--- zzzz-none-000/linux-2.6.39.4/net/l2tp/l2tp_ip.c 2011-08-03 19:43:28.000000000 +0000 +++ puma6-atom-6490-729/linux-2.6.39.4/net/l2tp/l2tp_ip.c 2021-11-10 13:38:18.000000000 +0000 @@ -9,6 +9,8 @@ * 2 of the License, or (at your option) any later version. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -32,15 +34,8 @@ /* inet_sock has to be the first member of l2tp_ip_sock */ struct inet_sock inet; - __u32 conn_id; - __u32 peer_conn_id; - - __u64 tx_packets; - __u64 tx_bytes; - __u64 tx_errors; - __u64 rx_packets; - __u64 rx_bytes; - __u64 rx_errors; + u32 conn_id; + u32 peer_conn_id; }; static DEFINE_RWLOCK(l2tp_ip_lock); @@ -120,14 +115,15 @@ */ static int l2tp_ip_recv(struct sk_buff *skb) { + struct net *net = dev_net(skb->dev); struct sock *sk; u32 session_id; u32 tunnel_id; unsigned char *ptr, *optr; struct l2tp_session *session; struct l2tp_tunnel *tunnel = NULL; + struct iphdr *iph; int length; - int offset; /* Point to L2TP header */ optr = ptr = skb->data; @@ -148,7 +144,7 @@ } /* Ok, this is a data packet. Lookup the session. */ - session = l2tp_session_find(&init_net, NULL, session_id); + session = l2tp_session_find(net, NULL, session_id); if (session == NULL) goto discard; @@ -162,14 +158,8 @@ if (!pskb_may_pull(skb, length)) goto discard; - printk(KERN_DEBUG "%s: ip recv: ", tunnel->name); - - offset = 0; - do { - printk(" %02X", ptr[offset]); - } while (++offset < length); - - printk("\n"); + pr_debug("%s: ip recv\n", tunnel->name); + print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, ptr, length); } l2tp_recv_common(session, skb, ptr, optr, 0, skb->len, tunnel->recv_payload_hook); @@ -185,21 +175,16 @@ goto discard; tunnel_id = ntohl(*(__be32 *) &skb->data[4]); - tunnel = l2tp_tunnel_find(&init_net, tunnel_id); - if (tunnel != NULL) - sk = tunnel->sock; - else { - struct iphdr *iph = (struct iphdr *) skb_network_header(skb); + iph = (struct iphdr *)skb_network_header(skb); - read_lock_bh(&l2tp_ip_lock); - sk = __l2tp_ip_bind_lookup(&init_net, iph->daddr, 0, tunnel_id); + read_lock_bh(&l2tp_ip_lock); + sk = __l2tp_ip_bind_lookup(net, iph->daddr, 0, tunnel_id); + if (!sk || sock_flag(sk, SOCK_DEAD)) { read_unlock_bh(&l2tp_ip_lock); - } - - if (sk == NULL) goto discard; - + } sock_hold(sk); + read_unlock_bh(&l2tp_ip_lock); if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) goto discard_put; @@ -232,7 +217,7 @@ { write_lock_bh(&l2tp_ip_lock); hlist_del_init(&sk->sk_bind_node); - hlist_del_init(&sk->sk_node); + sk_del_node_init(sk); write_unlock_bh(&l2tp_ip_lock); sk_common_release(sk); } @@ -240,10 +225,16 @@ static void l2tp_ip_destroy_sock(struct sock *sk) { struct sk_buff *skb; + struct l2tp_tunnel *tunnel = l2tp_sock_to_tunnel(sk); while ((skb = __skb_dequeue_tail(&sk->sk_write_queue)) != NULL) kfree_skb(skb); + if (tunnel) { + l2tp_tunnel_closeall(tunnel); + sock_put(sk); + } + sk_refcnt_debug_dec(sk); } @@ -251,12 +242,21 @@ { struct inet_sock *inet = inet_sk(sk); struct sockaddr_l2tpip *addr = (struct sockaddr_l2tpip *) uaddr; - int ret = -EINVAL; + struct net *net = sock_net(sk); + int ret; int chk_addr_ret; + if (!sock_flag(sk, SOCK_ZAPPED)) + return -EINVAL; + if (addr_len < sizeof(struct sockaddr_l2tpip)) + return -EINVAL; + if (addr->l2tp_family != AF_INET) + return -EINVAL; + ret = -EADDRINUSE; read_lock_bh(&l2tp_ip_lock); - if (__l2tp_ip_bind_lookup(&init_net, addr->l2tp_addr.s_addr, sk->sk_bound_dev_if, addr->l2tp_conn_id)) + if (__l2tp_ip_bind_lookup(net, addr->l2tp_addr.s_addr, + sk->sk_bound_dev_if, addr->l2tp_conn_id)) goto out_in_use; read_unlock_bh(&l2tp_ip_lock); @@ -265,13 +265,14 @@ if (sk->sk_state != TCP_CLOSE || addr_len < sizeof(struct sockaddr_l2tpip)) goto out; - chk_addr_ret = inet_addr_type(&init_net, addr->l2tp_addr.s_addr); + chk_addr_ret = inet_addr_type(net, addr->l2tp_addr.s_addr); ret = -EADDRNOTAVAIL; if (addr->l2tp_addr.s_addr && chk_addr_ret != RTN_LOCAL && chk_addr_ret != RTN_MULTICAST && chk_addr_ret != RTN_BROADCAST) goto out; - inet->inet_rcv_saddr = inet->inet_saddr = addr->l2tp_addr.s_addr; + if (addr->l2tp_addr.s_addr) + inet->inet_rcv_saddr = inet->inet_saddr = addr->l2tp_addr.s_addr; if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST) inet->inet_saddr = 0; /* Use device */ sk_dst_reset(sk); @@ -283,6 +284,8 @@ sk_del_node_init(sk); write_unlock_bh(&l2tp_ip_lock); ret = 0; + sock_reset_flag(sk, SOCK_ZAPPED); + out: release_sock(sk); @@ -296,69 +299,43 @@ static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) { - int rc; - struct inet_sock *inet = inet_sk(sk); struct sockaddr_l2tpip *lsa = (struct sockaddr_l2tpip *) uaddr; - struct rtable *rt; - __be32 saddr; - int oif; - - rc = -EINVAL; - if (addr_len < sizeof(*lsa)) - goto out; - - rc = -EAFNOSUPPORT; - if (lsa->l2tp_family != AF_INET) - goto out; + int rc; - sk_dst_reset(sk); + if (sock_flag(sk, SOCK_ZAPPED)) /* Must bind first - autobinding does not work */ + return -EINVAL; - oif = sk->sk_bound_dev_if; - saddr = inet->inet_saddr; + if (addr_len < sizeof(*lsa)) + return -EINVAL; - rc = -EINVAL; if (ipv4_is_multicast(lsa->l2tp_addr.s_addr)) - goto out; + return -EINVAL; - rt = ip_route_connect(lsa->l2tp_addr.s_addr, saddr, - RT_CONN_FLAGS(sk), oif, - IPPROTO_L2TP, - 0, 0, sk, true); - if (IS_ERR(rt)) { - rc = PTR_ERR(rt); - if (rc == -ENETUNREACH) - IP_INC_STATS_BH(&init_net, IPSTATS_MIB_OUTNOROUTES); - goto out; - } + rc = ip4_datagram_connect(sk, uaddr, addr_len); + if (rc < 0) + return rc; - rc = -ENETUNREACH; - if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) { - ip_rt_put(rt); - goto out; - } + lock_sock(sk); l2tp_ip_sk(sk)->peer_conn_id = lsa->l2tp_conn_id; - if (!inet->inet_saddr) - inet->inet_saddr = rt->rt_src; - if (!inet->inet_rcv_saddr) - inet->inet_rcv_saddr = rt->rt_src; - inet->inet_daddr = rt->rt_dst; - sk->sk_state = TCP_ESTABLISHED; - inet->inet_id = jiffies; - - sk_dst_set(sk, &rt->dst); - write_lock_bh(&l2tp_ip_lock); hlist_del_init(&sk->sk_bind_node); sk_add_bind_node(sk, &l2tp_ip_bind_table); write_unlock_bh(&l2tp_ip_lock); - rc = 0; -out: + release_sock(sk); return rc; } +static int l2tp_ip_disconnect(struct sock *sk, int flags) +{ + if (sock_flag(sk, SOCK_ZAPPED)) + return 0; + + return udp_disconnect(sk, flags); +} + static int l2tp_ip_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer) { @@ -389,22 +366,17 @@ { int rc; - if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) - goto drop; - - nf_reset(skb); - /* Charge it to the socket, dropping if the queue is full. */ rc = sock_queue_rcv_skb(sk, skb); if (rc < 0) goto drop; - return 0; + return NET_RX_SUCCESS; drop: - IP_INC_STATS(&init_net, IPSTATS_MIB_INDISCARDS); + IP_INC_STATS(sock_net(sk), IPSTATS_MIB_INDISCARDS); kfree_skb(skb); - return -1; + return NET_RX_DROP; } /* Userspace will call sendmsg() on the tunnel socket to send L2TP @@ -414,45 +386,55 @@ { struct sk_buff *skb; int rc; - struct l2tp_ip_sock *lsa = l2tp_ip_sk(sk); struct inet_sock *inet = inet_sk(sk); - struct ip_options *opt = inet->opt; struct rtable *rt = NULL; int connected = 0; __be32 daddr; + lock_sock(sk); + + rc = -ENOTCONN; if (sock_flag(sk, SOCK_DEAD)) - return -ENOTCONN; + goto out; /* Get and verify the address. */ if (msg->msg_name) { struct sockaddr_l2tpip *lip = (struct sockaddr_l2tpip *) msg->msg_name; + rc = -EINVAL; if (msg->msg_namelen < sizeof(*lip)) - return -EINVAL; + goto out; if (lip->l2tp_family != AF_INET) { + rc = -EAFNOSUPPORT; if (lip->l2tp_family != AF_UNSPEC) - return -EAFNOSUPPORT; + goto out; } daddr = lip->l2tp_addr.s_addr; } else { + rc = -EDESTADDRREQ; if (sk->sk_state != TCP_ESTABLISHED) - return -EDESTADDRREQ; + goto out; daddr = inet->inet_daddr; connected = 1; } + /* + * s/2 + NET_SKB_PAD/NET_SKB_PAD/" in call to sock_wmalloc and skb_reserve + * to get the right alignment. + * 2014-07-10 c.paeth@avm.de + */ + /* Allocate a socket buffer */ rc = -ENOMEM; - skb = sock_wmalloc(sk, 2 + NET_SKB_PAD + sizeof(struct iphdr) + + skb = sock_wmalloc(sk, NET_SKB_PAD + sizeof(struct iphdr) + 4 + len, 0, GFP_KERNEL); if (!skb) goto error; /* Reserve space for headers, putting IP header on 4-byte boundary. */ - skb_reserve(skb, 2 + NET_SKB_PAD); + skb_reserve(skb, NET_SKB_PAD); skb_reset_network_header(skb); skb_reserve(skb, sizeof(struct iphdr)); skb_reset_transport_header(skb); @@ -470,10 +452,15 @@ if (connected) rt = (struct rtable *) __sk_dst_check(sk, 0); + rcu_read_lock(); if (rt == NULL) { + const struct ip_options *inet_opt; + + inet_opt = rcu_dereference(inet->opt); + /* Use correct destination address if we have options. */ - if (opt && opt->srr) - daddr = opt->faddr; + if (inet_opt && inet_opt->srr) + daddr = inet_opt->faddr; /* If this fails, retransmit mechanism of transport layer will * keep trying until route appears or the connection times @@ -486,36 +473,44 @@ sk->sk_bound_dev_if); if (IS_ERR(rt)) goto no_route; - sk_setup_caps(sk, &rt->dst); + if (connected) { + sk_setup_caps(sk, &rt->dst); + } else { + skb_dst_set(skb, &rt->dst); + goto xmit; + } } - skb_dst_set(skb, dst_clone(&rt->dst)); + /* We dont need to clone dst here, it is guaranteed to not disappear. + * __dev_xmit_skb() might force a refcount if needed. + */ + skb_dst_set_noref(skb, &rt->dst); + +xmit: /* Queue the packet to IP for output */ rc = ip_queue_xmit(skb); + rcu_read_unlock(); error: - /* Update stats */ - if (rc >= 0) { - lsa->tx_packets++; - lsa->tx_bytes += len; + if (rc >= 0) rc = len; - } else { - lsa->tx_errors++; - } +out: + release_sock(sk); return rc; no_route: + rcu_read_unlock(); IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); kfree_skb(skb); - return -EHOSTUNREACH; + rc = -EHOSTUNREACH; + goto out; } static int l2tp_ip_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, size_t len, int noblock, int flags, int *addr_len) { struct inet_sock *inet = inet_sk(sk); - struct l2tp_ip_sock *lsk = l2tp_ip_sk(sk); size_t copied = 0; int err = -EOPNOTSUPP; struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name; @@ -557,15 +552,7 @@ done: skb_free_datagram(sk, skb); out: - if (err) { - lsk->rx_errors++; - return err; - } - - lsk->rx_packets++; - lsk->rx_bytes += copied; - - return copied; + return err ? err : copied; } static struct proto l2tp_ip_prot = { @@ -575,7 +562,7 @@ .close = l2tp_ip_close, .bind = l2tp_ip_bind, .connect = l2tp_ip_connect, - .disconnect = udp_disconnect, + .disconnect = l2tp_ip_disconnect, .ioctl = udp_ioctl, .destroy = l2tp_ip_destroy_sock, .setsockopt = ip_setsockopt, @@ -627,13 +614,14 @@ static struct net_protocol l2tp_ip_protocol __read_mostly = { .handler = l2tp_ip_recv, + .netns_ok = 1, }; static int __init l2tp_ip_init(void) { int err; - printk(KERN_INFO "L2TP IP encapsulation support (L2TPv3)\n"); + pr_info("L2TP IP encapsulation support (L2TPv3)\n"); err = proto_register(&l2tp_ip_prot, 1); if (err != 0)