diff options
Diffstat (limited to 'net/l2tp')
| -rw-r--r-- | net/l2tp/Kconfig | 5 | ||||
| -rw-r--r-- | net/l2tp/Makefile | 3 | ||||
| -rw-r--r-- | net/l2tp/l2tp_core.c | 987 | ||||
| -rw-r--r-- | net/l2tp/l2tp_core.h | 143 | ||||
| -rw-r--r-- | net/l2tp/l2tp_debugfs.c | 45 | ||||
| -rw-r--r-- | net/l2tp/l2tp_eth.c | 79 | ||||
| -rw-r--r-- | net/l2tp/l2tp_ip.c | 250 | ||||
| -rw-r--r-- | net/l2tp/l2tp_ip6.c | 805 | ||||
| -rw-r--r-- | net/l2tp/l2tp_netlink.c | 250 | ||||
| -rw-r--r-- | net/l2tp/l2tp_ppp.c | 386 | 
10 files changed, 2087 insertions, 866 deletions
diff --git a/net/l2tp/Kconfig b/net/l2tp/Kconfig index 4b1e71751e1..adb9843dd7c 100644 --- a/net/l2tp/Kconfig +++ b/net/l2tp/Kconfig @@ -4,6 +4,7 @@  menuconfig L2TP  	tristate "Layer Two Tunneling Protocol (L2TP)" +	depends on (IPV6 || IPV6=n)  	depends on INET  	---help---  	  Layer Two Tunneling Protocol @@ -45,8 +46,8 @@ config L2TP_DEBUGFS  	  will be called l2tp_debugfs.  config L2TP_V3 -	bool "L2TPv3 support (EXPERIMENTAL)" -	depends on EXPERIMENTAL && L2TP +	bool "L2TPv3 support" +	depends on L2TP  	help  	  Layer Two Tunneling Protocol Version 3 diff --git a/net/l2tp/Makefile b/net/l2tp/Makefile index 110e7bc2de5..2870f41ea44 100644 --- a/net/l2tp/Makefile +++ b/net/l2tp/Makefile @@ -10,3 +10,6 @@ obj-$(subst y,$(CONFIG_L2TP),$(CONFIG_L2TP_IP)) += l2tp_ip.o  obj-$(subst y,$(CONFIG_L2TP),$(CONFIG_L2TP_V3)) += l2tp_netlink.o  obj-$(subst y,$(CONFIG_L2TP),$(CONFIG_L2TP_ETH)) += l2tp_eth.o  obj-$(subst y,$(CONFIG_L2TP),$(CONFIG_L2TP_DEBUGFS)) += l2tp_debugfs.o +ifneq ($(CONFIG_IPV6),) +obj-$(subst y,$(CONFIG_L2TP),$(CONFIG_L2TP_IP)) += l2tp_ip6.o +endif diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index c64ce0a0bb0..bea25904320 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -18,6 +18,8 @@   * published by the Free Software Foundation.   */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +  #include <linux/module.h>  #include <linux/string.h>  #include <linux/list.h> @@ -53,9 +55,13 @@  #include <net/inet_common.h>  #include <net/xfrm.h>  #include <net/protocol.h> +#include <net/inet6_connection_sock.h> +#include <net/inet_ecn.h> +#include <net/ip6_route.h> +#include <net/ip6_checksum.h>  #include <asm/byteorder.h> -#include <asm/atomic.h> +#include <linux/atomic.h>  #include "l2tp_core.h" @@ -82,12 +88,6 @@  /* Default trace flags */  #define L2TP_DEFAULT_DEBUG_FLAGS	0 -#define PRINTK(_mask, _type, _lvl, _fmt, args...)			\ -	do {								\ -		if ((_mask) & (_type))					\ -			printk(_lvl "L2TP: " _fmt, ##args);		\ -	} while (0) -  /* Private data stored for received packets in the skb.   */  struct l2tp_skb_cb { @@ -101,6 +101,7 @@ struct l2tp_skb_cb {  static atomic_t l2tp_tunnel_count;  static atomic_t l2tp_session_count; +static struct workqueue_struct *l2tp_wq;  /* per-net private data for this module */  static unsigned int l2tp_net_id; @@ -111,9 +112,12 @@ struct l2tp_net {  	spinlock_t l2tp_session_hlist_lock;  }; -static void l2tp_session_set_header_len(struct l2tp_session *session, int version);  static void l2tp_tunnel_free(struct l2tp_tunnel *tunnel); -static void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel); + +static inline struct l2tp_tunnel *l2tp_tunnel(struct sock *sk) +{ +	return sk->sk_user_data; +}  static inline struct l2tp_net *l2tp_pernet(struct net *net)  { @@ -122,7 +126,6 @@ static inline struct l2tp_net *l2tp_pernet(struct net *net)  	return net_generic(net, l2tp_net_id);  } -  /* Tunnel reference counts. Incremented per session that is added to   * the tunnel.   */ @@ -137,14 +140,20 @@ static inline void l2tp_tunnel_dec_refcount_1(struct l2tp_tunnel *tunnel)  		l2tp_tunnel_free(tunnel);  }  #ifdef L2TP_REFCNT_DEBUG -#define l2tp_tunnel_inc_refcount(_t) do { \ -		printk(KERN_DEBUG "l2tp_tunnel_inc_refcount: %s:%d %s: cnt=%d\n", __func__, __LINE__, (_t)->name, atomic_read(&_t->ref_count)); \ -		l2tp_tunnel_inc_refcount_1(_t);				\ -	} while (0) -#define l2tp_tunnel_dec_refcount(_t) do { \ -		printk(KERN_DEBUG "l2tp_tunnel_dec_refcount: %s:%d %s: cnt=%d\n", __func__, __LINE__, (_t)->name, atomic_read(&_t->ref_count)); \ -		l2tp_tunnel_dec_refcount_1(_t);				\ -	} while (0) +#define l2tp_tunnel_inc_refcount(_t)					\ +do {									\ +	pr_debug("l2tp_tunnel_inc_refcount: %s:%d %s: cnt=%d\n",	\ +		 __func__, __LINE__, (_t)->name,			\ +		 atomic_read(&_t->ref_count));				\ +	l2tp_tunnel_inc_refcount_1(_t);					\ +} while (0) +#define l2tp_tunnel_dec_refcount(_t) +do {									\ +	pr_debug("l2tp_tunnel_dec_refcount: %s:%d %s: cnt=%d\n",	\ +		 __func__, __LINE__, (_t)->name,			\ +		 atomic_read(&_t->ref_count));				\ +	l2tp_tunnel_dec_refcount_1(_t);					\ +} while (0)  #else  #define l2tp_tunnel_inc_refcount(t) l2tp_tunnel_inc_refcount_1(t)  #define l2tp_tunnel_dec_refcount(t) l2tp_tunnel_dec_refcount_1(t) @@ -162,6 +171,51 @@ l2tp_session_id_hash_2(struct l2tp_net *pn, u32 session_id)  } +/* Lookup the tunnel socket, possibly involving the fs code if the socket is + * owned by userspace.  A struct sock returned from this function must be + * released using l2tp_tunnel_sock_put once you're done with it. + */ +static struct sock *l2tp_tunnel_sock_lookup(struct l2tp_tunnel *tunnel) +{ +	int err = 0; +	struct socket *sock = NULL; +	struct sock *sk = NULL; + +	if (!tunnel) +		goto out; + +	if (tunnel->fd >= 0) { +		/* Socket is owned by userspace, who might be in the process +		 * of closing it.  Look the socket up using the fd to ensure +		 * consistency. +		 */ +		sock = sockfd_lookup(tunnel->fd, &err); +		if (sock) +			sk = sock->sk; +	} else { +		/* Socket is owned by kernelspace */ +		sk = tunnel->sock; +		sock_hold(sk); +	} + +out: +	return sk; +} + +/* Drop a reference to a tunnel socket obtained via. l2tp_tunnel_sock_put */ +static void l2tp_tunnel_sock_put(struct sock *sk) +{ +	struct l2tp_tunnel *tunnel = l2tp_sock_to_tunnel(sk); +	if (tunnel) { +		if (tunnel->fd >= 0) { +			/* Socket is owned by userspace */ +			sockfd_put(sk->sk_socket); +		} +		sock_put(sk); +	} +	sock_put(sk); +} +  /* Lookup a session by id in the global session list   */  static struct l2tp_session *l2tp_session_find_2(struct net *net, u32 session_id) @@ -170,10 +224,9 @@ static struct l2tp_session *l2tp_session_find_2(struct net *net, u32 session_id)  	struct hlist_head *session_list =  		l2tp_session_id_hash_2(pn, session_id);  	struct l2tp_session *session; -	struct hlist_node *walk;  	rcu_read_lock_bh(); -	hlist_for_each_entry_rcu(session, walk, session_list, global_hlist) { +	hlist_for_each_entry_rcu(session, session_list, global_hlist) {  		if (session->session_id == session_id) {  			rcu_read_unlock_bh();  			return session; @@ -202,7 +255,6 @@ struct l2tp_session *l2tp_session_find(struct net *net, struct l2tp_tunnel *tunn  {  	struct hlist_head *session_list;  	struct l2tp_session *session; -	struct hlist_node *walk;  	/* In L2TPv3, session_ids are unique over all tunnels and we  	 * sometimes need to look them up before we know the @@ -213,7 +265,7 @@ struct l2tp_session *l2tp_session_find(struct net *net, struct l2tp_tunnel *tunn  	session_list = l2tp_session_id_hash(tunnel, session_id);  	read_lock_bh(&tunnel->hlist_lock); -	hlist_for_each_entry(session, walk, session_list, hlist) { +	hlist_for_each_entry(session, session_list, hlist) {  		if (session->session_id == session_id) {  			read_unlock_bh(&tunnel->hlist_lock);  			return session; @@ -228,13 +280,12 @@ EXPORT_SYMBOL_GPL(l2tp_session_find);  struct l2tp_session *l2tp_session_find_nth(struct l2tp_tunnel *tunnel, int nth)  {  	int hash; -	struct hlist_node *walk;  	struct l2tp_session *session;  	int count = 0;  	read_lock_bh(&tunnel->hlist_lock);  	for (hash = 0; hash < L2TP_HASH_SIZE; hash++) { -		hlist_for_each_entry(session, walk, &tunnel->session_hlist[hash], hlist) { +		hlist_for_each_entry(session, &tunnel->session_hlist[hash], hlist) {  			if (++count > nth) {  				read_unlock_bh(&tunnel->hlist_lock);  				return session; @@ -255,12 +306,11 @@ struct l2tp_session *l2tp_session_find_by_ifname(struct net *net, char *ifname)  {  	struct l2tp_net *pn = l2tp_pernet(net);  	int hash; -	struct hlist_node *walk;  	struct l2tp_session *session;  	rcu_read_lock_bh();  	for (hash = 0; hash < L2TP_HASH_SIZE_2; hash++) { -		hlist_for_each_entry_rcu(session, walk, &pn->l2tp_session_hlist[hash], global_hlist) { +		hlist_for_each_entry_rcu(session, &pn->l2tp_session_hlist[hash], global_hlist) {  			if (!strcmp(session->ifname, ifname)) {  				rcu_read_unlock_bh();  				return session; @@ -331,11 +381,11 @@ static void l2tp_recv_queue_skb(struct l2tp_session *session, struct sk_buff *sk  	skb_queue_walk_safe(&session->reorder_q, skbp, tmp) {  		if (L2TP_SKB_CB(skbp)->ns > ns) {  			__skb_queue_before(&session->reorder_q, skbp, skb); -			PRINTK(session->debug, L2TP_MSG_SEQ, KERN_DEBUG, -			       "%s: pkt %hu, inserted before %hu, reorder_q len=%d\n", -			       session->name, ns, L2TP_SKB_CB(skbp)->ns, -			       skb_queue_len(&session->reorder_q)); -			session->stats.rx_oos_packets++; +			l2tp_dbg(session, L2TP_MSG_SEQ, +				 "%s: pkt %hu, inserted before %hu, reorder_q len=%d\n", +				 session->name, ns, L2TP_SKB_CB(skbp)->ns, +				 skb_queue_len(&session->reorder_q)); +			atomic_long_inc(&session->stats.rx_oos_packets);  			goto out;  		}  	} @@ -358,21 +408,18 @@ static void l2tp_recv_dequeue_skb(struct l2tp_session *session, struct sk_buff *  	 */  	skb_orphan(skb); -	tunnel->stats.rx_packets++; -	tunnel->stats.rx_bytes += length; -	session->stats.rx_packets++; -	session->stats.rx_bytes += length; +	atomic_long_inc(&tunnel->stats.rx_packets); +	atomic_long_add(length, &tunnel->stats.rx_bytes); +	atomic_long_inc(&session->stats.rx_packets); +	atomic_long_add(length, &session->stats.rx_bytes);  	if (L2TP_SKB_CB(skb)->has_seq) {  		/* Bump our Nr */  		session->nr++; -		if (tunnel->version == L2TP_HDR_VER_2) -			session->nr &= 0xffff; -		else -			session->nr &= 0xffffff; +		session->nr &= session->nr_max; -		PRINTK(session->debug, L2TP_MSG_SEQ, KERN_DEBUG, -		       "%s: updated nr to %hu\n", session->name, session->nr); +		l2tp_dbg(session, L2TP_MSG_SEQ, "%s: updated nr to %hu\n", +			 session->name, session->nr);  	}  	/* call private receive handler */ @@ -397,17 +444,18 @@ static void l2tp_recv_dequeue(struct l2tp_session *session)  	 * expect to send up next, dequeue it and any other  	 * in-sequence packets behind it.  	 */ +start:  	spin_lock_bh(&session->reorder_q.lock);  	skb_queue_walk_safe(&session->reorder_q, skb, tmp) {  		if (time_after(jiffies, L2TP_SKB_CB(skb)->expires)) { -			session->stats.rx_seq_discards++; -			session->stats.rx_errors++; -			PRINTK(session->debug, L2TP_MSG_SEQ, KERN_DEBUG, -			       "%s: oos pkt %u len %d discarded (too old), " -			       "waiting for %u, reorder_q_len=%d\n", -			       session->name, L2TP_SKB_CB(skb)->ns, -			       L2TP_SKB_CB(skb)->length, session->nr, -			       skb_queue_len(&session->reorder_q)); +			atomic_long_inc(&session->stats.rx_seq_discards); +			atomic_long_inc(&session->stats.rx_errors); +			l2tp_dbg(session, L2TP_MSG_SEQ, +				 "%s: oos pkt %u len %d discarded (too old), waiting for %u, reorder_q_len=%d\n", +				 session->name, L2TP_SKB_CB(skb)->ns, +				 L2TP_SKB_CB(skb)->length, session->nr, +				 skb_queue_len(&session->reorder_q)); +			session->reorder_skip = 1;  			__skb_unlink(skb, &session->reorder_q);  			kfree_skb(skb);  			if (session->deref) @@ -416,13 +464,20 @@ static void l2tp_recv_dequeue(struct l2tp_session *session)  		}  		if (L2TP_SKB_CB(skb)->has_seq) { +			if (session->reorder_skip) { +				l2tp_dbg(session, L2TP_MSG_SEQ, +					 "%s: advancing nr to next pkt: %u -> %u", +					 session->name, session->nr, +					 L2TP_SKB_CB(skb)->ns); +				session->reorder_skip = 0; +				session->nr = L2TP_SKB_CB(skb)->ns; +			}  			if (L2TP_SKB_CB(skb)->ns != session->nr) { -				PRINTK(session->debug, L2TP_MSG_SEQ, KERN_DEBUG, -				       "%s: holding oos pkt %u len %d, " -				       "waiting for %u, reorder_q_len=%d\n", -				       session->name, L2TP_SKB_CB(skb)->ns, -				       L2TP_SKB_CB(skb)->length, session->nr, -				       skb_queue_len(&session->reorder_q)); +				l2tp_dbg(session, L2TP_MSG_SEQ, +					 "%s: holding oos pkt %u len %d, waiting for %u, reorder_q_len=%d\n", +					 session->name, L2TP_SKB_CB(skb)->ns, +					 L2TP_SKB_CB(skb)->length, session->nr, +					 skb_queue_len(&session->reorder_q));  				goto out;  			}  		} @@ -433,35 +488,89 @@ static void l2tp_recv_dequeue(struct l2tp_session *session)  		 */  		spin_unlock_bh(&session->reorder_q.lock);  		l2tp_recv_dequeue_skb(session, skb); -		spin_lock_bh(&session->reorder_q.lock); +		goto start;  	}  out:  	spin_unlock_bh(&session->reorder_q.lock);  } -static inline int l2tp_verify_udp_checksum(struct sock *sk, -					   struct sk_buff *skb) +static int l2tp_seq_check_rx_window(struct l2tp_session *session, u32 nr)  { -	struct udphdr *uh = udp_hdr(skb); -	u16 ulen = ntohs(uh->len); -	struct inet_sock *inet; -	__wsum psum; +	u32 nws; -	if (sk->sk_no_check || skb_csum_unnecessary(skb) || !uh->check) -		return 0; +	if (nr >= session->nr) +		nws = nr - session->nr; +	else +		nws = (session->nr_max + 1) - (session->nr - nr); -	inet = inet_sk(sk); -	psum = csum_tcpudp_nofold(inet->inet_saddr, inet->inet_daddr, ulen, -				  IPPROTO_UDP, 0); +	return nws < session->nr_window_size; +} + +/* If packet has sequence numbers, queue it if acceptable. Returns 0 if + * acceptable, else non-zero. + */ +static int l2tp_recv_data_seq(struct l2tp_session *session, struct sk_buff *skb) +{ +	if (!l2tp_seq_check_rx_window(session, L2TP_SKB_CB(skb)->ns)) { +		/* Packet sequence number is outside allowed window. +		 * Discard it. +		 */ +		l2tp_dbg(session, L2TP_MSG_SEQ, +			 "%s: pkt %u len %d discarded, outside window, nr=%u\n", +			 session->name, L2TP_SKB_CB(skb)->ns, +			 L2TP_SKB_CB(skb)->length, session->nr); +		goto discard; +	} -	if ((skb->ip_summed == CHECKSUM_COMPLETE) && -	    !csum_fold(csum_add(psum, skb->csum))) -		return 0; +	if (session->reorder_timeout != 0) { +		/* Packet reordering enabled. Add skb to session's +		 * reorder queue, in order of ns. +		 */ +		l2tp_recv_queue_skb(session, skb); +		goto out; +	} -	skb->csum = psum; +	/* Packet reordering disabled. Discard out-of-sequence packets, while +	 * tracking the number if in-sequence packets after the first OOS packet +	 * is seen. After nr_oos_count_max in-sequence packets, reset the +	 * sequence number to re-enable packet reception. +	 */ +	if (L2TP_SKB_CB(skb)->ns == session->nr) { +		skb_queue_tail(&session->reorder_q, skb); +	} else { +		u32 nr_oos = L2TP_SKB_CB(skb)->ns; +		u32 nr_next = (session->nr_oos + 1) & session->nr_max; -	return __skb_checksum_complete(skb); +		if (nr_oos == nr_next) +			session->nr_oos_count++; +		else +			session->nr_oos_count = 0; + +		session->nr_oos = nr_oos; +		if (session->nr_oos_count > session->nr_oos_count_max) { +			session->reorder_skip = 1; +			l2tp_dbg(session, L2TP_MSG_SEQ, +				 "%s: %d oos packets received. Resetting sequence numbers\n", +				 session->name, session->nr_oos_count); +		} +		if (!session->reorder_skip) { +			atomic_long_inc(&session->stats.rx_seq_discards); +			l2tp_dbg(session, L2TP_MSG_SEQ, +				 "%s: oos pkt %u len %d discarded, waiting for %u, reorder_q_len=%d\n", +				 session->name, L2TP_SKB_CB(skb)->ns, +				 L2TP_SKB_CB(skb)->length, session->nr, +				 skb_queue_len(&session->reorder_q)); +			goto discard; +		} +		skb_queue_tail(&session->reorder_q, skb); +	} + +out: +	return 0; + +discard: +	return 1;  }  /* Do receive processing of L2TP data frames. We handle both L2TPv2 @@ -543,10 +652,11 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb,  	/* Parse and check optional cookie */  	if (session->peer_cookie_len > 0) {  		if (memcmp(ptr, &session->peer_cookie[0], session->peer_cookie_len)) { -			PRINTK(tunnel->debug, L2TP_MSG_DATA, KERN_INFO, -			       "%s: cookie mismatch (%u/%u). Discarding.\n", -			       tunnel->name, tunnel->tunnel_id, session->session_id); -			session->stats.rx_cookie_discards++; +			l2tp_info(tunnel, L2TP_MSG_DATA, +				  "%s: cookie mismatch (%u/%u). Discarding.\n", +				  tunnel->name, tunnel->tunnel_id, +				  session->session_id); +			atomic_long_inc(&session->stats.rx_cookie_discards);  			goto discard;  		}  		ptr += session->peer_cookie_len; @@ -572,9 +682,9 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb,  			L2TP_SKB_CB(skb)->ns = ns;  			L2TP_SKB_CB(skb)->has_seq = 1; -			PRINTK(session->debug, L2TP_MSG_SEQ, KERN_DEBUG, -			       "%s: recv data ns=%u, nr=%u, session nr=%u\n", -			       session->name, ns, nr, session->nr); +			l2tp_dbg(session, L2TP_MSG_SEQ, +				 "%s: recv data ns=%u, nr=%u, session nr=%u\n", +				 session->name, ns, nr, session->nr);  		}  	} else if (session->l2specific_type == L2TP_L2SPECTYPE_DEFAULT) {  		u32 l2h = ntohl(*(__be32 *) ptr); @@ -586,9 +696,9 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb,  			L2TP_SKB_CB(skb)->ns = ns;  			L2TP_SKB_CB(skb)->has_seq = 1; -			PRINTK(session->debug, L2TP_MSG_SEQ, KERN_DEBUG, -			       "%s: recv data ns=%u, session nr=%u\n", -			       session->name, ns, session->nr); +			l2tp_dbg(session, L2TP_MSG_SEQ, +				 "%s: recv data ns=%u, session nr=%u\n", +				 session->name, ns, session->nr);  		}  	} @@ -601,9 +711,9 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb,  		 * configure it so.  		 */  		if ((!session->lns_mode) && (!session->send_seq)) { -			PRINTK(session->debug, L2TP_MSG_SEQ, KERN_INFO, -			       "%s: requested to enable seq numbers by LNS\n", -			       session->name); +			l2tp_info(session, L2TP_MSG_SEQ, +				  "%s: requested to enable seq numbers by LNS\n", +				  session->name);  			session->send_seq = -1;  			l2tp_session_set_header_len(session, tunnel->version);  		} @@ -612,10 +722,10 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb,  		 * If user has configured mandatory sequence numbers, discard.  		 */  		if (session->recv_seq) { -			PRINTK(session->debug, L2TP_MSG_SEQ, KERN_WARNING, -			       "%s: recv data has no seq numbers when required. " -			       "Discarding\n", session->name); -			session->stats.rx_seq_discards++; +			l2tp_warn(session, L2TP_MSG_SEQ, +				  "%s: recv data has no seq numbers when required. Discarding.\n", +				  session->name); +			atomic_long_inc(&session->stats.rx_seq_discards);  			goto discard;  		} @@ -625,16 +735,16 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb,  		 * LAC is broken. Discard the frame.  		 */  		if ((!session->lns_mode) && (session->send_seq)) { -			PRINTK(session->debug, L2TP_MSG_SEQ, KERN_INFO, -			       "%s: requested to disable seq numbers by LNS\n", -			       session->name); +			l2tp_info(session, L2TP_MSG_SEQ, +				  "%s: requested to disable seq numbers by LNS\n", +				  session->name);  			session->send_seq = 0;  			l2tp_session_set_header_len(session, tunnel->version);  		} else if (session->send_seq) { -			PRINTK(session->debug, L2TP_MSG_SEQ, KERN_WARNING, -			       "%s: recv data has no seq numbers when required. " -			       "Discarding\n", session->name); -			session->stats.rx_seq_discards++; +			l2tp_warn(session, L2TP_MSG_SEQ, +				  "%s: recv data has no seq numbers when required. Discarding.\n", +				  session->name); +			atomic_long_inc(&session->stats.rx_seq_discards);  			goto discard;  		}  	} @@ -678,27 +788,8 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb,  	 * enabled. Saved L2TP protocol info is stored in skb->sb[].  	 */  	if (L2TP_SKB_CB(skb)->has_seq) { -		if (session->reorder_timeout != 0) { -			/* Packet reordering enabled. Add skb to session's -			 * reorder queue, in order of ns. -			 */ -			l2tp_recv_queue_skb(session, skb); -		} else { -			/* Packet reordering disabled. Discard out-of-sequence -			 * packets -			 */ -			if (L2TP_SKB_CB(skb)->ns != session->nr) { -				session->stats.rx_seq_discards++; -				PRINTK(session->debug, L2TP_MSG_SEQ, KERN_DEBUG, -				       "%s: oos pkt %u len %d discarded, " -				       "waiting for %u, reorder_q_len=%d\n", -				       session->name, L2TP_SKB_CB(skb)->ns, -				       L2TP_SKB_CB(skb)->length, session->nr, -				       skb_queue_len(&session->reorder_q)); -				goto discard; -			} -			skb_queue_tail(&session->reorder_q, skb); -		} +		if (l2tp_recv_data_seq(session, skb)) +			goto discard;  	} else {  		/* No sequence numbers. Add the skb to the tail of the  		 * reorder queue. This ensures that it will be @@ -715,7 +806,7 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb,  	return;  discard: -	session->stats.rx_errors++; +	atomic_long_inc(&session->stats.rx_errors);  	kfree_skb(skb);  	if (session->deref) @@ -725,6 +816,23 @@ discard:  }  EXPORT_SYMBOL(l2tp_recv_common); +/* Drop skbs from the session's reorder_q + */ +int l2tp_session_queue_purge(struct l2tp_session *session) +{ +	struct sk_buff *skb = NULL; +	BUG_ON(!session); +	BUG_ON(session->magic != L2TP_SESSION_MAGIC); +	while ((skb = skb_dequeue(&session->reorder_q))) { +		atomic_long_inc(&session->stats.rx_errors); +		kfree_skb(skb); +		if (session->deref) +			(*session->deref)(session); +	} +	return 0; +} +EXPORT_SYMBOL_GPL(l2tp_session_queue_purge); +  /* Internal UDP receive frame. Do the real work of receiving an L2TP data frame   * here. The skb is not on a list when we get here.   * Returns 0 if the packet was a data packet and was successfully passed on. @@ -738,51 +846,44 @@ static int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb,  	unsigned char *ptr, *optr;  	u16 hdrflags;  	u32 tunnel_id, session_id; -	int offset;  	u16 version;  	int length; -	if (tunnel->sock && l2tp_verify_udp_checksum(tunnel->sock, skb)) -		goto discard_bad_csum; +	/* UDP has verifed checksum */  	/* UDP always verifies the packet length. */  	__skb_pull(skb, sizeof(struct udphdr));  	/* Short packet? */  	if (!pskb_may_pull(skb, L2TP_HDR_SIZE_SEQ)) { -		PRINTK(tunnel->debug, L2TP_MSG_DATA, KERN_INFO, -		       "%s: recv short packet (len=%d)\n", tunnel->name, skb->len); +		l2tp_info(tunnel, L2TP_MSG_DATA, +			  "%s: recv short packet (len=%d)\n", +			  tunnel->name, skb->len);  		goto error;  	} -	/* Point to L2TP header */ -	optr = ptr = skb->data; -  	/* Trace packet contents, if enabled */  	if (tunnel->debug & L2TP_MSG_DATA) {  		length = min(32u, skb->len);  		if (!pskb_may_pull(skb, length))  			goto error; -		printk(KERN_DEBUG "%s: recv: ", tunnel->name); - -		offset = 0; -		do { -			printk(" %02X", ptr[offset]); -		} while (++offset < length); - -		printk("\n"); +		pr_debug("%s: recv\n", tunnel->name); +		print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, skb->data, length);  	} +	/* Point to L2TP header */ +	optr = ptr = skb->data; +  	/* Get L2TP header flags */  	hdrflags = ntohs(*(__be16 *) ptr);  	/* Check protocol version */  	version = hdrflags & L2TP_HDR_VER_MASK;  	if (version != tunnel->version) { -		PRINTK(tunnel->debug, L2TP_MSG_DATA, KERN_INFO, -		       "%s: recv protocol version mismatch: got %d expected %d\n", -		       tunnel->name, version, tunnel->version); +		l2tp_info(tunnel, L2TP_MSG_DATA, +			  "%s: recv protocol version mismatch: got %d expected %d\n", +			  tunnel->name, version, tunnel->version);  		goto error;  	} @@ -791,8 +892,9 @@ static int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb,  	/* If type is control packet, it is handled by userspace. */  	if (hdrflags & L2TP_HDRFLAG_T) { -		PRINTK(tunnel->debug, L2TP_MSG_DATA, KERN_DEBUG, -		       "%s: recv control packet, len=%d\n", tunnel->name, length); +		l2tp_dbg(tunnel, L2TP_MSG_DATA, +			 "%s: recv control packet, len=%d\n", +			 tunnel->name, length);  		goto error;  	} @@ -820,9 +922,9 @@ static int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb,  	session = l2tp_session_find(tunnel->l2tp_net, tunnel, session_id);  	if (!session || !session->recv_skb) {  		/* Not found? Pass to userspace to deal with */ -		PRINTK(tunnel->debug, L2TP_MSG_DATA, KERN_INFO, -		       "%s: no session found (%u/%u). Passing up.\n", -		       tunnel->name, tunnel_id, session_id); +		l2tp_info(tunnel, L2TP_MSG_DATA, +			  "%s: no session found (%u/%u). Passing up.\n", +			  tunnel->name, tunnel_id, session_id);  		goto error;  	} @@ -830,14 +932,6 @@ static int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb,  	return 0; -discard_bad_csum: -	LIMIT_NETDEBUG("%s: UDP: bad checksum\n", tunnel->name); -	UDP_INC_STATS_USER(tunnel->l2tp_net, UDP_MIB_INERRORS, 0); -	tunnel->stats.rx_errors++; -	kfree_skb(skb); - -	return 0; -  error:  	/* Put UDP header back */  	__skb_push(skb, sizeof(struct udphdr)); @@ -859,8 +953,8 @@ int l2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb)  	if (tunnel == NULL)  		goto pass_up; -	PRINTK(tunnel->debug, L2TP_MSG_DATA, KERN_DEBUG, -	       "%s: received %d bytes\n", tunnel->name, skb->len); +	l2tp_dbg(tunnel, L2TP_MSG_DATA, "%s: received %d bytes\n", +		 tunnel->name, skb->len);  	if (l2tp_udp_recv_core(tunnel, skb, tunnel->recv_payload_hook))  		goto pass_up_put; @@ -902,8 +996,8 @@ static int l2tp_build_l2tpv2_header(struct l2tp_session *session, void *buf)  		*bufp++ = 0;  		session->ns++;  		session->ns &= 0xffff; -		PRINTK(session->debug, L2TP_MSG_SEQ, KERN_DEBUG, -		       "%s: updated ns to %u\n", session->name, session->ns); +		l2tp_dbg(session, L2TP_MSG_SEQ, "%s: updated ns to %u\n", +			 session->name, session->ns);  	}  	return bufp - optr; @@ -939,8 +1033,9 @@ static int l2tp_build_l2tpv3_header(struct l2tp_session *session, void *buf)  				l2h = 0x40000000 | session->ns;  				session->ns++;  				session->ns &= 0xffffff; -				PRINTK(session->debug, L2TP_MSG_SEQ, KERN_DEBUG, -				       "%s: updated ns to %u\n", session->name, session->ns); +				l2tp_dbg(session, L2TP_MSG_SEQ, +					 "%s: updated ns to %u\n", +					 session->name, session->ns);  			}  			*((__be32 *) bufp) = htonl(l2h); @@ -954,7 +1049,7 @@ static int l2tp_build_l2tpv3_header(struct l2tp_session *session, void *buf)  }  static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, -			  size_t data_len) +			  struct flowi *fl, size_t data_len)  {  	struct l2tp_tunnel *tunnel = session->tunnel;  	unsigned int len = skb->len; @@ -962,64 +1057,44 @@ static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb,  	/* Debug */  	if (session->send_seq) -		PRINTK(session->debug, L2TP_MSG_DATA, KERN_DEBUG, -		       "%s: send %Zd bytes, ns=%u\n", session->name, -		       data_len, session->ns - 1); +		l2tp_dbg(session, L2TP_MSG_DATA, "%s: send %Zd bytes, ns=%u\n", +			 session->name, data_len, session->ns - 1);  	else -		PRINTK(session->debug, L2TP_MSG_DATA, KERN_DEBUG, -		       "%s: send %Zd bytes\n", session->name, data_len); +		l2tp_dbg(session, L2TP_MSG_DATA, "%s: send %Zd bytes\n", +			 session->name, data_len);  	if (session->debug & L2TP_MSG_DATA) { -		int i;  		int uhlen = (tunnel->encap == L2TP_ENCAPTYPE_UDP) ? sizeof(struct udphdr) : 0;  		unsigned char *datap = skb->data + uhlen; -		printk(KERN_DEBUG "%s: xmit:", session->name); -		for (i = 0; i < (len - uhlen); i++) { -			printk(" %02X", *datap++); -			if (i == 31) { -				printk(" ..."); -				break; -			} -		} -		printk("\n"); +		pr_debug("%s: xmit\n", session->name); +		print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, +				     datap, min_t(size_t, 32, len - uhlen));  	}  	/* Queue the packet to IP for output */ -	skb->local_df = 1; -	error = ip_queue_xmit(skb); +	skb->ignore_df = 1; +#if IS_ENABLED(CONFIG_IPV6) +	if (tunnel->sock->sk_family == PF_INET6 && !tunnel->v4mapped) +		error = inet6_csk_xmit(tunnel->sock, skb, NULL); +	else +#endif +		error = ip_queue_xmit(tunnel->sock, skb, fl);  	/* Update stats */  	if (error >= 0) { -		tunnel->stats.tx_packets++; -		tunnel->stats.tx_bytes += len; -		session->stats.tx_packets++; -		session->stats.tx_bytes += len; +		atomic_long_inc(&tunnel->stats.tx_packets); +		atomic_long_add(len, &tunnel->stats.tx_bytes); +		atomic_long_inc(&session->stats.tx_packets); +		atomic_long_add(len, &session->stats.tx_bytes);  	} else { -		tunnel->stats.tx_errors++; -		session->stats.tx_errors++; +		atomic_long_inc(&tunnel->stats.tx_errors); +		atomic_long_inc(&session->stats.tx_errors);  	}  	return 0;  } -/* Automatically called when the skb is freed. - */ -static void l2tp_sock_wfree(struct sk_buff *skb) -{ -	sock_put(skb->sk); -} - -/* For data skbs that we transmit, we associate with the tunnel socket - * but don't do accounting. - */ -static inline void l2tp_skb_set_owner_w(struct sk_buff *skb, struct sock *sk) -{ -	sock_hold(sk); -	skb->sk = sk; -	skb->destructor = l2tp_sock_wfree; -} -  /* If caller requires the skb to have a ppp header, the header must be   * inserted in the skb data before calling this function.   */ @@ -1028,14 +1103,13 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len  	int data_len = skb->len;  	struct l2tp_tunnel *tunnel = session->tunnel;  	struct sock *sk = tunnel->sock; +	struct flowi *fl;  	struct udphdr *uh;  	struct inet_sock *inet; -	__wsum csum; -	int old_headroom; -	int new_headroom;  	int headroom;  	int uhlen = (tunnel->encap == L2TP_ENCAPTYPE_UDP) ? sizeof(struct udphdr) : 0;  	int udp_len; +	int ret = NET_XMIT_SUCCESS;  	/* Check that there's enough headroom in the skb to insert IP,  	 * UDP and L2TP headers. If not enough, expand it to @@ -1043,13 +1117,10 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len  	 */  	headroom = NET_SKB_PAD + sizeof(struct iphdr) +  		uhlen + hdr_len; -	old_headroom = skb_headroom(skb); -	if (skb_cow_head(skb, headroom)) -		goto abort; - -	new_headroom = skb_headroom(skb); -	skb_orphan(skb); -	skb->truesize += new_headroom - old_headroom; +	if (skb_cow_head(skb, headroom)) { +		kfree_skb(skb); +		return NET_XMIT_DROP; +	}  	/* Setup L2TP header */  	session->build_header(session, __skb_push(skb, hdr_len)); @@ -1060,14 +1131,22 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len  			      IPSKB_REROUTED);  	nf_reset(skb); +	bh_lock_sock(sk); +	if (sock_owned_by_user(sk)) { +		kfree_skb(skb); +		ret = NET_XMIT_DROP; +		goto out_unlock; +	} +  	/* Get routing info from the tunnel socket */  	skb_dst_drop(skb); -	skb_dst_set(skb, dst_clone(__sk_dst_get(sk))); +	skb_dst_set(skb, dst_clone(__sk_dst_check(sk, 0))); +	inet = inet_sk(sk); +	fl = &inet->cork.fl;  	switch (tunnel->encap) {  	case L2TP_ENCAPTYPE_UDP:  		/* Setup UDP header */ -		inet = inet_sk(sk);  		__skb_push(skb, sizeof(*uh));  		skb_reset_transport_header(skb);  		uh = udp_hdr(skb); @@ -1075,40 +1154,28 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len  		uh->dest = inet->inet_dport;  		udp_len = uhlen + hdr_len + data_len;  		uh->len = htons(udp_len); -		uh->check = 0;  		/* Calculate UDP checksum if configured to do so */ -		if (sk->sk_no_check == UDP_CSUM_NOXMIT) -			skb->ip_summed = CHECKSUM_NONE; -		else if ((skb_dst(skb) && skb_dst(skb)->dev) && -			 (!(skb_dst(skb)->dev->features & NETIF_F_V4_CSUM))) { -			skb->ip_summed = CHECKSUM_COMPLETE; -			csum = skb_checksum(skb, 0, udp_len, 0); -			uh->check = csum_tcpudp_magic(inet->inet_saddr, -						      inet->inet_daddr, -						      udp_len, IPPROTO_UDP, csum); -			if (uh->check == 0) -				uh->check = CSUM_MANGLED_0; -		} else { -			skb->ip_summed = CHECKSUM_PARTIAL; -			skb->csum_start = skb_transport_header(skb) - skb->head; -			skb->csum_offset = offsetof(struct udphdr, check); -			uh->check = ~csum_tcpudp_magic(inet->inet_saddr, -						       inet->inet_daddr, -						       udp_len, IPPROTO_UDP, 0); -		} +#if IS_ENABLED(CONFIG_IPV6) +		if (sk->sk_family == PF_INET6 && !tunnel->v4mapped) +			udp6_set_csum(udp_get_no_check6_tx(sk), +				      skb, &inet6_sk(sk)->saddr, +				      &sk->sk_v6_daddr, udp_len); +		else +#endif +		udp_set_csum(sk->sk_no_check_tx, skb, inet->inet_saddr, +			     inet->inet_daddr, udp_len);  		break;  	case L2TP_ENCAPTYPE_IP:  		break;  	} -	l2tp_skb_set_owner_w(skb, sk); - -	l2tp_xmit_core(session, skb, data_len); +	l2tp_xmit_core(session, skb, fl, data_len); +out_unlock: +	bh_unlock_sock(sk); -abort: -	return 0; +	return ret;  }  EXPORT_SYMBOL_GPL(l2tp_xmit_skb); @@ -1122,47 +1189,52 @@ EXPORT_SYMBOL_GPL(l2tp_xmit_skb);   */  static void l2tp_tunnel_destruct(struct sock *sk)  { -	struct l2tp_tunnel *tunnel; +	struct l2tp_tunnel *tunnel = l2tp_tunnel(sk); +	struct l2tp_net *pn; -	tunnel = sk->sk_user_data;  	if (tunnel == NULL)  		goto end; -	PRINTK(tunnel->debug, L2TP_MSG_CONTROL, KERN_INFO, -	       "%s: closing...\n", tunnel->name); +	l2tp_info(tunnel, L2TP_MSG_CONTROL, "%s: closing...\n", tunnel->name); -	/* Close all sessions */ -	l2tp_tunnel_closeall(tunnel); +	/* Disable udp encapsulation */  	switch (tunnel->encap) {  	case L2TP_ENCAPTYPE_UDP:  		/* No longer an encapsulation socket. See net/ipv4/udp.c */  		(udp_sk(sk))->encap_type = 0;  		(udp_sk(sk))->encap_rcv = NULL; +		(udp_sk(sk))->encap_destroy = NULL;  		break;  	case L2TP_ENCAPTYPE_IP:  		break;  	}  	/* Remove hooks into tunnel socket */ -	tunnel->sock = NULL;  	sk->sk_destruct = tunnel->old_sk_destruct;  	sk->sk_user_data = NULL; +	tunnel->sock = NULL; -	/* Call the original destructor */ -	if (sk->sk_destruct) -		(*sk->sk_destruct)(sk); +	/* Remove the tunnel struct from the tunnel list */ +	pn = l2tp_pernet(tunnel->l2tp_net); +	spin_lock_bh(&pn->l2tp_tunnel_list_lock); +	list_del_rcu(&tunnel->list); +	spin_unlock_bh(&pn->l2tp_tunnel_list_lock); +	atomic_dec(&l2tp_tunnel_count); -	/* We're finished with the socket */ +	l2tp_tunnel_closeall(tunnel);  	l2tp_tunnel_dec_refcount(tunnel); +	/* Call the original destructor */ +	if (sk->sk_destruct) +		(*sk->sk_destruct)(sk);  end:  	return;  }  /* When the tunnel is closed, all the attached sessions need to go too.   */ -static void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel) +void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel)  {  	int hash;  	struct hlist_node *walk; @@ -1171,8 +1243,8 @@ static void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel)  	BUG_ON(tunnel == NULL); -	PRINTK(tunnel->debug, L2TP_MSG_CONTROL, KERN_INFO, -	       "%s: closing all sessions...\n", tunnel->name); +	l2tp_info(tunnel, L2TP_MSG_CONTROL, "%s: closing all sessions...\n", +		  tunnel->name);  	write_lock_bh(&tunnel->hlist_lock);  	for (hash = 0; hash < L2TP_HASH_SIZE; hash++) { @@ -1180,30 +1252,18 @@ again:  		hlist_for_each_safe(walk, tmp, &tunnel->session_hlist[hash]) {  			session = hlist_entry(walk, struct l2tp_session, hlist); -			PRINTK(session->debug, L2TP_MSG_CONTROL, KERN_INFO, -			       "%s: closing session\n", session->name); +			l2tp_info(session, L2TP_MSG_CONTROL, +				  "%s: closing session\n", session->name);  			hlist_del_init(&session->hlist); -			/* Since we should hold the sock lock while -			 * doing any unbinding, we need to release the -			 * lock we're holding before taking that lock. -			 * Hold a reference to the sock so it doesn't -			 * disappear as we're jumping between locks. -			 */  			if (session->ref != NULL)  				(*session->ref)(session);  			write_unlock_bh(&tunnel->hlist_lock); -			if (tunnel->version != L2TP_HDR_VER_2) { -				struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net); - -				spin_lock_bh(&pn->l2tp_session_hlist_lock); -				hlist_del_init_rcu(&session->global_hlist); -				spin_unlock_bh(&pn->l2tp_session_hlist_lock); -				synchronize_rcu(); -			} +			__l2tp_session_unhash(session); +			l2tp_session_queue_purge(session);  			if (session->session_close != NULL)  				(*session->session_close)(session); @@ -1211,6 +1271,8 @@ again:  			if (session->deref != NULL)  				(*session->deref)(session); +			l2tp_session_dec_refcount(session); +  			write_lock_bh(&tunnel->hlist_lock);  			/* Now restart from the beginning of this hash @@ -1223,91 +1285,205 @@ again:  	}  	write_unlock_bh(&tunnel->hlist_lock);  } +EXPORT_SYMBOL_GPL(l2tp_tunnel_closeall); + +/* Tunnel socket destroy hook for UDP encapsulation */ +static void l2tp_udp_encap_destroy(struct sock *sk) +{ +	struct l2tp_tunnel *tunnel = l2tp_sock_to_tunnel(sk); +	if (tunnel) { +		l2tp_tunnel_closeall(tunnel); +		sock_put(sk); +	} +}  /* Really kill the tunnel.   * Come here only when all sessions have been cleared from the tunnel.   */  static void l2tp_tunnel_free(struct l2tp_tunnel *tunnel)  { -	struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net); -  	BUG_ON(atomic_read(&tunnel->ref_count) != 0);  	BUG_ON(tunnel->sock != NULL); +	l2tp_info(tunnel, L2TP_MSG_CONTROL, "%s: free...\n", tunnel->name); +	kfree_rcu(tunnel, rcu); +} -	PRINTK(tunnel->debug, L2TP_MSG_CONTROL, KERN_INFO, -	       "%s: free...\n", tunnel->name); +/* Workqueue tunnel deletion function */ +static void l2tp_tunnel_del_work(struct work_struct *work) +{ +	struct l2tp_tunnel *tunnel = NULL; +	struct socket *sock = NULL; +	struct sock *sk = NULL; -	/* Remove from tunnel list */ -	spin_lock_bh(&pn->l2tp_tunnel_list_lock); -	list_del_rcu(&tunnel->list); -	spin_unlock_bh(&pn->l2tp_tunnel_list_lock); -	synchronize_rcu(); +	tunnel = container_of(work, struct l2tp_tunnel, del_work); +	sk = l2tp_tunnel_sock_lookup(tunnel); +	if (!sk) +		return; -	atomic_dec(&l2tp_tunnel_count); -	kfree(tunnel); +	sock = sk->sk_socket; + +	/* If the tunnel socket was created by userspace, then go through the +	 * inet layer to shut the socket down, and let userspace close it. +	 * Otherwise, if we created the socket directly within the kernel, use +	 * the sk API to release it here. +	 * In either case the tunnel resources are freed in the socket +	 * destructor when the tunnel socket goes away. +	 */ +	if (tunnel->fd >= 0) { +		if (sock) +			inet_shutdown(sock, 2); +	} else { +		if (sock) +			kernel_sock_shutdown(sock, SHUT_RDWR); +		sk_release_kernel(sk); +	} + +	l2tp_tunnel_sock_put(sk);  }  /* Create a socket for the tunnel, if one isn't set up by   * userspace. This is used for static tunnels where there is no   * managing L2TP daemon. + * + * Since we don't want these sockets to keep a namespace alive by + * themselves, we drop the socket's namespace refcount after creation. + * These sockets are freed when the namespace exits using the pernet + * exit hook.   */ -static int l2tp_tunnel_sock_create(u32 tunnel_id, u32 peer_tunnel_id, struct l2tp_tunnel_cfg *cfg, struct socket **sockp) +static int l2tp_tunnel_sock_create(struct net *net, +				u32 tunnel_id, +				u32 peer_tunnel_id, +				struct l2tp_tunnel_cfg *cfg, +				struct socket **sockp)  {  	int err = -EINVAL; -	struct sockaddr_in udp_addr; -	struct sockaddr_l2tpip ip_addr;  	struct socket *sock = NULL; +	struct sockaddr_in udp_addr = {0}; +	struct sockaddr_l2tpip ip_addr = {0}; +#if IS_ENABLED(CONFIG_IPV6) +	struct sockaddr_in6 udp6_addr = {0}; +	struct sockaddr_l2tpip6 ip6_addr = {0}; +#endif  	switch (cfg->encap) {  	case L2TP_ENCAPTYPE_UDP: -		err = sock_create(AF_INET, SOCK_DGRAM, 0, sockp); -		if (err < 0) -			goto out; +#if IS_ENABLED(CONFIG_IPV6) +		if (cfg->local_ip6 && cfg->peer_ip6) { +			err = sock_create_kern(AF_INET6, SOCK_DGRAM, 0, &sock); +			if (err < 0) +				goto out; -		sock = *sockp; +			sk_change_net(sock->sk, net); -		memset(&udp_addr, 0, sizeof(udp_addr)); -		udp_addr.sin_family = AF_INET; -		udp_addr.sin_addr = cfg->local_ip; -		udp_addr.sin_port = htons(cfg->local_udp_port); -		err = kernel_bind(sock, (struct sockaddr *) &udp_addr, sizeof(udp_addr)); -		if (err < 0) -			goto out; +			udp6_addr.sin6_family = AF_INET6; +			memcpy(&udp6_addr.sin6_addr, cfg->local_ip6, +			       sizeof(udp6_addr.sin6_addr)); +			udp6_addr.sin6_port = htons(cfg->local_udp_port); +			err = kernel_bind(sock, (struct sockaddr *) &udp6_addr, +					  sizeof(udp6_addr)); +			if (err < 0) +				goto out; -		udp_addr.sin_family = AF_INET; -		udp_addr.sin_addr = cfg->peer_ip; -		udp_addr.sin_port = htons(cfg->peer_udp_port); -		err = kernel_connect(sock, (struct sockaddr *) &udp_addr, sizeof(udp_addr), 0); -		if (err < 0) -			goto out; +			udp6_addr.sin6_family = AF_INET6; +			memcpy(&udp6_addr.sin6_addr, cfg->peer_ip6, +			       sizeof(udp6_addr.sin6_addr)); +			udp6_addr.sin6_port = htons(cfg->peer_udp_port); +			err = kernel_connect(sock, +					     (struct sockaddr *) &udp6_addr, +					     sizeof(udp6_addr), 0); +			if (err < 0) +				goto out; + +			if (cfg->udp6_zero_tx_checksums) +				udp_set_no_check6_tx(sock->sk, true); +			if (cfg->udp6_zero_rx_checksums) +				udp_set_no_check6_rx(sock->sk, true); +		} else +#endif +		{ +			err = sock_create_kern(AF_INET, SOCK_DGRAM, 0, &sock); +			if (err < 0) +				goto out; + +			sk_change_net(sock->sk, net); + +			udp_addr.sin_family = AF_INET; +			udp_addr.sin_addr = cfg->local_ip; +			udp_addr.sin_port = htons(cfg->local_udp_port); +			err = kernel_bind(sock, (struct sockaddr *) &udp_addr, +					  sizeof(udp_addr)); +			if (err < 0) +				goto out; + +			udp_addr.sin_family = AF_INET; +			udp_addr.sin_addr = cfg->peer_ip; +			udp_addr.sin_port = htons(cfg->peer_udp_port); +			err = kernel_connect(sock, +					     (struct sockaddr *) &udp_addr, +					     sizeof(udp_addr), 0); +			if (err < 0) +				goto out; +		}  		if (!cfg->use_udp_checksums) -			sock->sk->sk_no_check = UDP_CSUM_NOXMIT; +			sock->sk->sk_no_check_tx = 1;  		break;  	case L2TP_ENCAPTYPE_IP: -		err = sock_create(AF_INET, SOCK_DGRAM, IPPROTO_L2TP, sockp); -		if (err < 0) -			goto out; +#if IS_ENABLED(CONFIG_IPV6) +		if (cfg->local_ip6 && cfg->peer_ip6) { +			err = sock_create_kern(AF_INET6, SOCK_DGRAM, +					  IPPROTO_L2TP, &sock); +			if (err < 0) +				goto out; -		sock = *sockp; +			sk_change_net(sock->sk, net); -		memset(&ip_addr, 0, sizeof(ip_addr)); -		ip_addr.l2tp_family = AF_INET; -		ip_addr.l2tp_addr = cfg->local_ip; -		ip_addr.l2tp_conn_id = tunnel_id; -		err = kernel_bind(sock, (struct sockaddr *) &ip_addr, sizeof(ip_addr)); -		if (err < 0) -			goto out; +			ip6_addr.l2tp_family = AF_INET6; +			memcpy(&ip6_addr.l2tp_addr, cfg->local_ip6, +			       sizeof(ip6_addr.l2tp_addr)); +			ip6_addr.l2tp_conn_id = tunnel_id; +			err = kernel_bind(sock, (struct sockaddr *) &ip6_addr, +					  sizeof(ip6_addr)); +			if (err < 0) +				goto out; -		ip_addr.l2tp_family = AF_INET; -		ip_addr.l2tp_addr = cfg->peer_ip; -		ip_addr.l2tp_conn_id = peer_tunnel_id; -		err = kernel_connect(sock, (struct sockaddr *) &ip_addr, sizeof(ip_addr), 0); -		if (err < 0) -			goto out; +			ip6_addr.l2tp_family = AF_INET6; +			memcpy(&ip6_addr.l2tp_addr, cfg->peer_ip6, +			       sizeof(ip6_addr.l2tp_addr)); +			ip6_addr.l2tp_conn_id = peer_tunnel_id; +			err = kernel_connect(sock, +					     (struct sockaddr *) &ip6_addr, +					     sizeof(ip6_addr), 0); +			if (err < 0) +				goto out; +		} else +#endif +		{ +			err = sock_create_kern(AF_INET, SOCK_DGRAM, +					  IPPROTO_L2TP, &sock); +			if (err < 0) +				goto out; + +			sk_change_net(sock->sk, net); + +			ip_addr.l2tp_family = AF_INET; +			ip_addr.l2tp_addr = cfg->local_ip; +			ip_addr.l2tp_conn_id = tunnel_id; +			err = kernel_bind(sock, (struct sockaddr *) &ip_addr, +					  sizeof(ip_addr)); +			if (err < 0) +				goto out; +			ip_addr.l2tp_family = AF_INET; +			ip_addr.l2tp_addr = cfg->peer_ip; +			ip_addr.l2tp_conn_id = peer_tunnel_id; +			err = kernel_connect(sock, (struct sockaddr *) &ip_addr, +					     sizeof(ip_addr), 0); +			if (err < 0) +				goto out; +		}  		break;  	default: @@ -1315,14 +1491,18 @@ static int l2tp_tunnel_sock_create(u32 tunnel_id, u32 peer_tunnel_id, struct l2t  	}  out: +	*sockp = sock;  	if ((err < 0) && sock) { -		sock_release(sock); +		kernel_sock_shutdown(sock, SHUT_RDWR); +		sk_release_kernel(sock->sk);  		*sockp = NULL;  	}  	return err;  } +static struct lock_class_key l2tp_socket_class; +  int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32 peer_tunnel_id, struct l2tp_tunnel_cfg *cfg, struct l2tp_tunnel **tunnelp)  {  	struct l2tp_tunnel *tunnel = NULL; @@ -1337,15 +1517,23 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32  	 * kernel socket.  	 */  	if (fd < 0) { -		err = l2tp_tunnel_sock_create(tunnel_id, peer_tunnel_id, cfg, &sock); +		err = l2tp_tunnel_sock_create(net, tunnel_id, peer_tunnel_id, +				cfg, &sock);  		if (err < 0)  			goto err;  	} else { -		err = -EBADF;  		sock = sockfd_lookup(fd, &err);  		if (!sock) { -			printk(KERN_ERR "tunl %hu: sockfd_lookup(fd=%d) returned %d\n", +			pr_err("tunl %u: sockfd_lookup(fd=%d) returned %d\n",  			       tunnel_id, fd, err); +			err = -EBADF; +			goto err; +		} + +		/* Reject namespace mismatches */ +		if (!net_eq(sock_net(sock->sk), net)) { +			pr_err("tunl %u: netns mismatch\n", tunnel_id); +			err = -EINVAL;  			goto err;  		}  	} @@ -1360,7 +1548,7 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32  	case L2TP_ENCAPTYPE_UDP:  		err = -EPROTONOSUPPORT;  		if (sk->sk_protocol != IPPROTO_UDP) { -			printk(KERN_ERR "tunl %hu: fd %d wrong protocol, got %d, expected %d\n", +			pr_err("tunl %hu: fd %d wrong protocol, got %d, expected %d\n",  			       tunnel_id, fd, sk->sk_protocol, IPPROTO_UDP);  			goto err;  		} @@ -1368,7 +1556,7 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32  	case L2TP_ENCAPTYPE_IP:  		err = -EPROTONOSUPPORT;  		if (sk->sk_protocol != IPPROTO_L2TP) { -			printk(KERN_ERR "tunl %hu: fd %d wrong protocol, got %d, expected %d\n", +			pr_err("tunl %hu: fd %d wrong protocol, got %d, expected %d\n",  			       tunnel_id, fd, sk->sk_protocol, IPPROTO_L2TP);  			goto err;  		} @@ -1376,7 +1564,7 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32  	}  	/* Check if this socket has already been prepped */ -	tunnel = (struct l2tp_tunnel *)sk->sk_user_data; +	tunnel = l2tp_tunnel(sk);  	if (tunnel != NULL) {  		/* This socket has already been prepped */  		err = -EBUSY; @@ -1405,12 +1593,37 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32  	if (cfg != NULL)  		tunnel->debug = cfg->debug; +#if IS_ENABLED(CONFIG_IPV6) +	if (sk->sk_family == PF_INET6) { +		struct ipv6_pinfo *np = inet6_sk(sk); + +		if (ipv6_addr_v4mapped(&np->saddr) && +		    ipv6_addr_v4mapped(&sk->sk_v6_daddr)) { +			struct inet_sock *inet = inet_sk(sk); + +			tunnel->v4mapped = true; +			inet->inet_saddr = np->saddr.s6_addr32[3]; +			inet->inet_rcv_saddr = sk->sk_v6_rcv_saddr.s6_addr32[3]; +			inet->inet_daddr = sk->sk_v6_daddr.s6_addr32[3]; +		} else { +			tunnel->v4mapped = false; +		} +	} +#endif +  	/* Mark socket as an encapsulation socket. See net/ipv4/udp.c */  	tunnel->encap = encap;  	if (encap == L2TP_ENCAPTYPE_UDP) {  		/* Mark socket as an encapsulation socket. See net/ipv4/udp.c */  		udp_sk(sk)->encap_type = UDP_ENCAP_L2TPINUDP;  		udp_sk(sk)->encap_rcv = l2tp_udp_encap_recv; +		udp_sk(sk)->encap_destroy = l2tp_udp_encap_destroy; +#if IS_ENABLED(CONFIG_IPV6) +		if (sk->sk_family == PF_INET6 && !tunnel->v4mapped) +			udpv6_encap_enable(); +		else +#endif +		udp_encap_enable();  	}  	sk->sk_user_data = tunnel; @@ -1421,20 +1634,25 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32  	tunnel->old_sk_destruct = sk->sk_destruct;  	sk->sk_destruct = &l2tp_tunnel_destruct;  	tunnel->sock = sk; +	tunnel->fd = fd; +	lockdep_set_class_and_name(&sk->sk_lock.slock, &l2tp_socket_class, "l2tp_sock"); +  	sk->sk_allocation = GFP_ATOMIC; +	/* Init delete workqueue struct */ +	INIT_WORK(&tunnel->del_work, l2tp_tunnel_del_work); +  	/* Add tunnel to our list */  	INIT_LIST_HEAD(&tunnel->list); -	spin_lock_bh(&pn->l2tp_tunnel_list_lock); -	list_add_rcu(&tunnel->list, &pn->l2tp_tunnel_list); -	spin_unlock_bh(&pn->l2tp_tunnel_list_lock); -	synchronize_rcu();  	atomic_inc(&l2tp_tunnel_count);  	/* Bump the reference count. The tunnel context is deleted -	 * only when this drops to zero. +	 * only when this drops to zero. Must be done before list insertion  	 */  	l2tp_tunnel_inc_refcount(tunnel); +	spin_lock_bh(&pn->l2tp_tunnel_list_lock); +	list_add_rcu(&tunnel->list, &pn->l2tp_tunnel_list); +	spin_unlock_bh(&pn->l2tp_tunnel_list_lock);  	err = 0;  err: @@ -1455,25 +1673,8 @@ EXPORT_SYMBOL_GPL(l2tp_tunnel_create);   */  int l2tp_tunnel_delete(struct l2tp_tunnel *tunnel)  { -	int err = 0; -	struct socket *sock = tunnel->sock ? tunnel->sock->sk_socket : NULL; - -	/* Force the tunnel socket to close. This will eventually -	 * cause the tunnel to be deleted via the normal socket close -	 * mechanisms when userspace closes the tunnel socket. -	 */ -	if (sock != NULL) { -		err = inet_shutdown(sock, 2); - -		/* If the tunnel's socket was created by the kernel, -		 * close the socket here since the socket was not -		 * created by userspace. -		 */ -		if (sock->file == NULL) -			err = inet_release(sock); -	} - -	return err; +	l2tp_tunnel_closeall(tunnel); +	return (false == queue_work(l2tp_wq, &tunnel->del_work));  }  EXPORT_SYMBOL_GPL(l2tp_tunnel_delete); @@ -1481,66 +1682,73 @@ EXPORT_SYMBOL_GPL(l2tp_tunnel_delete);   */  void l2tp_session_free(struct l2tp_session *session)  { -	struct l2tp_tunnel *tunnel; +	struct l2tp_tunnel *tunnel = session->tunnel;  	BUG_ON(atomic_read(&session->ref_count) != 0); -	tunnel = session->tunnel; -	if (tunnel != NULL) { +	if (tunnel) {  		BUG_ON(tunnel->magic != L2TP_TUNNEL_MAGIC); +		if (session->session_id != 0) +			atomic_dec(&l2tp_session_count); +		sock_put(tunnel->sock); +		session->tunnel = NULL; +		l2tp_tunnel_dec_refcount(tunnel); +	} -		/* Delete the session from the hash */ +	kfree(session); +} +EXPORT_SYMBOL_GPL(l2tp_session_free); + +/* Remove an l2tp session from l2tp_core's hash lists. + * Provides a tidyup interface for pseudowire code which can't just route all + * shutdown via. l2tp_session_delete and a pseudowire-specific session_close + * callback. + */ +void __l2tp_session_unhash(struct l2tp_session *session) +{ +	struct l2tp_tunnel *tunnel = session->tunnel; + +	/* Remove the session from core hashes */ +	if (tunnel) { +		/* Remove from the per-tunnel hash */  		write_lock_bh(&tunnel->hlist_lock);  		hlist_del_init(&session->hlist);  		write_unlock_bh(&tunnel->hlist_lock); -		/* Unlink from the global hash if not L2TPv2 */ +		/* For L2TPv3 we have a per-net hash: remove from there, too */  		if (tunnel->version != L2TP_HDR_VER_2) {  			struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net); -  			spin_lock_bh(&pn->l2tp_session_hlist_lock);  			hlist_del_init_rcu(&session->global_hlist);  			spin_unlock_bh(&pn->l2tp_session_hlist_lock);  			synchronize_rcu();  		} - -		if (session->session_id != 0) -			atomic_dec(&l2tp_session_count); - -		sock_put(tunnel->sock); - -		/* This will delete the tunnel context if this -		 * is the last session on the tunnel. -		 */ -		session->tunnel = NULL; -		l2tp_tunnel_dec_refcount(tunnel);  	} - -	kfree(session); - -	return;  } -EXPORT_SYMBOL_GPL(l2tp_session_free); +EXPORT_SYMBOL_GPL(__l2tp_session_unhash);  /* This function is used by the netlink SESSION_DELETE command and by     pseudowire modules.   */  int l2tp_session_delete(struct l2tp_session *session)  { +	if (session->ref) +		(*session->ref)(session); +	__l2tp_session_unhash(session); +	l2tp_session_queue_purge(session);  	if (session->session_close != NULL)  		(*session->session_close)(session); - +	if (session->deref) +		(*session->deref)(session);  	l2tp_session_dec_refcount(session); -  	return 0;  }  EXPORT_SYMBOL_GPL(l2tp_session_delete); -  /* We come here whenever a session's send_seq, cookie_len or   * l2specific_len parameters are set.   */ -static void l2tp_session_set_header_len(struct l2tp_session *session, int version) +void l2tp_session_set_header_len(struct l2tp_session *session, int version)  {  	if (version == L2TP_HDR_VER_2) {  		session->hdr_len = 6; @@ -1553,6 +1761,7 @@ static void l2tp_session_set_header_len(struct l2tp_session *session, int versio  	}  } +EXPORT_SYMBOL_GPL(l2tp_session_set_header_len);  struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg)  { @@ -1565,7 +1774,16 @@ struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunn  		session->session_id = session_id;  		session->peer_session_id = peer_session_id; -		session->nr = 1; +		session->nr = 0; +		if (tunnel->version == L2TP_HDR_VER_2) +			session->nr_max = 0xffff; +		else +			session->nr_max = 0xffffff; +		session->nr_window_size = session->nr_max / 2; +		session->nr_oos_count_max = 4; + +		/* Use NR of first received packet */ +		session->reorder_skip = 1;  		sprintf(&session->name[0], "sess %u/%u",  			tunnel->tunnel_id, session->session_id); @@ -1626,7 +1844,6 @@ struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunn  			hlist_add_head_rcu(&session->global_hlist,  					   l2tp_session_id_hash_2(pn, session_id));  			spin_unlock_bh(&pn->l2tp_session_hlist_lock); -			synchronize_rcu();  		}  		/* Ignore management session in session count value */ @@ -1658,8 +1875,21 @@ static __net_init int l2tp_init_net(struct net *net)  	return 0;  } +static __net_exit void l2tp_exit_net(struct net *net) +{ +	struct l2tp_net *pn = l2tp_pernet(net); +	struct l2tp_tunnel *tunnel = NULL; + +	rcu_read_lock_bh(); +	list_for_each_entry_rcu(tunnel, &pn->l2tp_tunnel_list, list) { +		(void)l2tp_tunnel_delete(tunnel); +	} +	rcu_read_unlock_bh(); +} +  static struct pernet_operations l2tp_net_ops = {  	.init = l2tp_init_net, +	.exit = l2tp_exit_net,  	.id   = &l2tp_net_id,  	.size = sizeof(struct l2tp_net),  }; @@ -1672,7 +1902,14 @@ static int __init l2tp_init(void)  	if (rc)  		goto out; -	printk(KERN_INFO "L2TP core driver, %s\n", L2TP_DRV_VERSION); +	l2tp_wq = alloc_workqueue("l2tp", WQ_UNBOUND, 0); +	if (!l2tp_wq) { +		pr_err("alloc_workqueue failed\n"); +		rc = -ENOMEM; +		goto out; +	} + +	pr_info("L2TP core driver, %s\n", L2TP_DRV_VERSION);  out:  	return rc; @@ -1681,6 +1918,10 @@ out:  static void __exit l2tp_exit(void)  {  	unregister_pernet_device(&l2tp_net_ops); +	if (l2tp_wq) { +		destroy_workqueue(l2tp_wq); +		l2tp_wq = NULL; +	}  }  module_init(l2tp_init); diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h index a16a48e79fa..68aa9ffd4ae 100644 --- a/net/l2tp/l2tp_core.h +++ b/net/l2tp/l2tp_core.h @@ -36,15 +36,15 @@ enum {  struct sk_buff;  struct l2tp_stats { -	u64			tx_packets; -	u64			tx_bytes; -	u64			tx_errors; -	u64			rx_packets; -	u64			rx_bytes; -	u64			rx_seq_discards; -	u64			rx_oos_packets; -	u64			rx_errors; -	u64			rx_cookie_discards; +	atomic_long_t		tx_packets; +	atomic_long_t		tx_bytes; +	atomic_long_t		tx_errors; +	atomic_long_t		rx_packets; +	atomic_long_t		rx_bytes; +	atomic_long_t		rx_seq_discards; +	atomic_long_t		rx_oos_packets; +	atomic_long_t		rx_errors; +	atomic_long_t		rx_cookie_discards;  };  struct l2tp_tunnel; @@ -54,15 +54,15 @@ struct l2tp_tunnel;   */  struct l2tp_session_cfg {  	enum l2tp_pwtype	pw_type; -	unsigned		data_seq:2;	/* data sequencing level +	unsigned int		data_seq:2;	/* data sequencing level  						 * 0 => none, 1 => IP only,  						 * 2 => all  						 */ -	unsigned		recv_seq:1;	/* expect receive packets with +	unsigned int		recv_seq:1;	/* expect receive packets with  						 * sequence numbers? */ -	unsigned		send_seq:1;	/* send packets with sequence +	unsigned int		send_seq:1;	/* send packets with sequence  						 * numbers? */ -	unsigned		lns_mode:1;	/* behave as LNS? LAC enables +	unsigned int		lns_mode:1;	/* behave as LNS? LAC enables  						 * sequence numbers under  						 * control of LNS. */  	int			debug;		/* bitmask of debug message @@ -102,26 +102,32 @@ struct l2tp_session {  	u32			nr;		/* session NR state (receive) */  	u32			ns;		/* session NR state (send) */  	struct sk_buff_head	reorder_q;	/* receive reorder queue */ +	u32			nr_max;		/* max NR. Depends on tunnel */ +	u32			nr_window_size;	/* NR window size */ +	u32			nr_oos;		/* NR of last OOS packet */ +	int			nr_oos_count;	/* For OOS recovery */ +	int			nr_oos_count_max;  	struct hlist_node	hlist;		/* Hash list node */  	atomic_t		ref_count;  	char			name[32];	/* for logging */  	char			ifname[IFNAMSIZ]; -	unsigned		data_seq:2;	/* data sequencing level +	unsigned int		data_seq:2;	/* data sequencing level  						 * 0 => none, 1 => IP only,  						 * 2 => all  						 */ -	unsigned		recv_seq:1;	/* expect receive packets with +	unsigned int		recv_seq:1;	/* expect receive packets with  						 * sequence numbers? */ -	unsigned		send_seq:1;	/* send packets with sequence +	unsigned int		send_seq:1;	/* send packets with sequence  						 * numbers? */ -	unsigned		lns_mode:1;	/* behave as LNS? LAC enables +	unsigned int		lns_mode:1;	/* behave as LNS? LAC enables  						 * sequence numbers under  						 * control of LNS. */  	int			debug;		/* bitmask of debug message  						 * categories */  	int			reorder_timeout; /* configured reorder timeout  						  * (in jiffies) */ +	int			reorder_skip;	/* set if skip to next nr */  	int			mtu;  	int			mru;  	enum l2tp_pwtype	pwtype; @@ -150,13 +156,20 @@ struct l2tp_tunnel_cfg {  	/* Used only for kernel-created sockets */  	struct in_addr		local_ip;  	struct in_addr		peer_ip; +#if IS_ENABLED(CONFIG_IPV6) +	struct in6_addr		*local_ip6; +	struct in6_addr		*peer_ip6; +#endif  	u16			local_udp_port;  	u16			peer_udp_port; -	unsigned int		use_udp_checksums:1; +	unsigned int		use_udp_checksums:1, +				udp6_zero_tx_checksums:1, +				udp6_zero_rx_checksums:1;  };  struct l2tp_tunnel {  	int			magic;		/* Should be L2TP_TUNNEL_MAGIC */ +	struct rcu_head rcu;  	rwlock_t		hlist_lock;	/* protect session_hlist */  	struct hlist_head	session_hlist[L2TP_HASH_SIZE];  						/* hashed list of sessions, @@ -181,7 +194,13 @@ struct l2tp_tunnel {  	int (*recv_payload_hook)(struct sk_buff *skb);  	void (*old_sk_destruct)(struct sock *);  	struct sock		*sock;		/* Parent socket */ -	int			fd; +	int			fd;		/* Parent fd, if tunnel socket +						 * was created by userspace */ +#if IS_ENABLED(CONFIG_IPV6) +	bool			v4mapped; +#endif + +	struct work_struct	del_work;  	uint8_t			priv[0];	/* private data */  }; @@ -221,24 +240,39 @@ out:  	return tunnel;  } -extern struct l2tp_session *l2tp_session_find(struct net *net, struct l2tp_tunnel *tunnel, u32 session_id); -extern struct l2tp_session *l2tp_session_find_nth(struct l2tp_tunnel *tunnel, int nth); -extern struct l2tp_session *l2tp_session_find_by_ifname(struct net *net, char *ifname); -extern struct l2tp_tunnel *l2tp_tunnel_find(struct net *net, u32 tunnel_id); -extern struct l2tp_tunnel *l2tp_tunnel_find_nth(struct net *net, int nth); - -extern int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32 peer_tunnel_id, struct l2tp_tunnel_cfg *cfg, struct l2tp_tunnel **tunnelp); -extern int l2tp_tunnel_delete(struct l2tp_tunnel *tunnel); -extern struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg); -extern int l2tp_session_delete(struct l2tp_session *session); -extern void l2tp_session_free(struct l2tp_session *session); -extern void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, unsigned char *ptr, unsigned char *optr, u16 hdrflags, int length, int (*payload_hook)(struct sk_buff *skb)); -extern int l2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb); - -extern int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len); - -extern int l2tp_nl_register_ops(enum l2tp_pwtype pw_type, const struct l2tp_nl_cmd_ops *ops); -extern void l2tp_nl_unregister_ops(enum l2tp_pwtype pw_type); +struct l2tp_session *l2tp_session_find(struct net *net, +				       struct l2tp_tunnel *tunnel, +				       u32 session_id); +struct l2tp_session *l2tp_session_find_nth(struct l2tp_tunnel *tunnel, int nth); +struct l2tp_session *l2tp_session_find_by_ifname(struct net *net, char *ifname); +struct l2tp_tunnel *l2tp_tunnel_find(struct net *net, u32 tunnel_id); +struct l2tp_tunnel *l2tp_tunnel_find_nth(struct net *net, int nth); + +int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, +		       u32 peer_tunnel_id, struct l2tp_tunnel_cfg *cfg, +		       struct l2tp_tunnel **tunnelp); +void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel); +int l2tp_tunnel_delete(struct l2tp_tunnel *tunnel); +struct l2tp_session *l2tp_session_create(int priv_size, +					 struct l2tp_tunnel *tunnel, +					 u32 session_id, u32 peer_session_id, +					 struct l2tp_session_cfg *cfg); +void __l2tp_session_unhash(struct l2tp_session *session); +int l2tp_session_delete(struct l2tp_session *session); +void l2tp_session_free(struct l2tp_session *session); +void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, +		      unsigned char *ptr, unsigned char *optr, u16 hdrflags, +		      int length, int (*payload_hook)(struct sk_buff *skb)); +int l2tp_session_queue_purge(struct l2tp_session *session); +int l2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb); +void l2tp_session_set_header_len(struct l2tp_session *session, int version); + +int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, +		  int hdr_len); + +int l2tp_nl_register_ops(enum l2tp_pwtype pw_type, +			 const struct l2tp_nl_cmd_ops *ops); +void l2tp_nl_unregister_ops(enum l2tp_pwtype pw_type);  /* Session reference counts. Incremented when code obtains a reference   * to a session. @@ -255,17 +289,36 @@ static inline void l2tp_session_dec_refcount_1(struct l2tp_session *session)  }  #ifdef L2TP_REFCNT_DEBUG -#define l2tp_session_inc_refcount(_s) do { \ -		printk(KERN_DEBUG "l2tp_session_inc_refcount: %s:%d %s: cnt=%d\n", __func__, __LINE__, (_s)->name, atomic_read(&_s->ref_count)); \ -		l2tp_session_inc_refcount_1(_s);				\ -	} while (0) -#define l2tp_session_dec_refcount(_s) do { \ -		printk(KERN_DEBUG "l2tp_session_dec_refcount: %s:%d %s: cnt=%d\n", __func__, __LINE__, (_s)->name, atomic_read(&_s->ref_count)); \ -		l2tp_session_dec_refcount_1(_s);				\ -	} while (0) +#define l2tp_session_inc_refcount(_s)					\ +do {									\ +	pr_debug("l2tp_session_inc_refcount: %s:%d %s: cnt=%d\n",	\ +		 __func__, __LINE__, (_s)->name,			\ +		 atomic_read(&_s->ref_count));				\ +	l2tp_session_inc_refcount_1(_s);				\ +} while (0) +#define l2tp_session_dec_refcount(_s)					\ +do {									\ +	pr_debug("l2tp_session_dec_refcount: %s:%d %s: cnt=%d\n",	\ +		 __func__, __LINE__, (_s)->name,			\ +		 atomic_read(&_s->ref_count));				\ +	l2tp_session_dec_refcount_1(_s);				\ +} while (0)  #else  #define l2tp_session_inc_refcount(s) l2tp_session_inc_refcount_1(s)  #define l2tp_session_dec_refcount(s) l2tp_session_dec_refcount_1(s)  #endif +#define l2tp_printk(ptr, type, func, fmt, ...)				\ +do {									\ +	if (((ptr)->debug) & (type))					\ +		func(fmt, ##__VA_ARGS__);				\ +} while (0) + +#define l2tp_warn(ptr, type, fmt, ...)					\ +	l2tp_printk(ptr, type, pr_warn, fmt, ##__VA_ARGS__) +#define l2tp_info(ptr, type, fmt, ...)					\ +	l2tp_printk(ptr, type, pr_info, fmt, ##__VA_ARGS__) +#define l2tp_dbg(ptr, type, fmt, ...)					\ +	l2tp_printk(ptr, type, pr_debug, fmt, ##__VA_ARGS__) +  #endif /* _L2TP_CORE_H_ */ diff --git a/net/l2tp/l2tp_debugfs.c b/net/l2tp/l2tp_debugfs.c index b8dbae82fab..2d6760a2ae3 100644 --- a/net/l2tp/l2tp_debugfs.c +++ b/net/l2tp/l2tp_debugfs.c @@ -9,6 +9,8 @@   *	2 of the License, or (at your option) any later version.   */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +  #include <linux/module.h>  #include <linux/skbuff.h>  #include <linux/socket.h> @@ -122,6 +124,15 @@ static void l2tp_dfs_seq_tunnel_show(struct seq_file *m, void *v)  	seq_printf(m, "\nTUNNEL %u peer %u", tunnel->tunnel_id, tunnel->peer_tunnel_id);  	if (tunnel->sock) {  		struct inet_sock *inet = inet_sk(tunnel->sock); + +#if IS_ENABLED(CONFIG_IPV6) +		if (tunnel->sock->sk_family == AF_INET6) { +			const struct ipv6_pinfo *np = inet6_sk(tunnel->sock); + +			seq_printf(m, " from %pI6c to %pI6c\n", +				&np->saddr, &tunnel->sock->sk_v6_daddr); +		} else +#endif  		seq_printf(m, " from %pI4 to %pI4\n",  			   &inet->inet_saddr, &inet->inet_daddr);  		if (tunnel->encap == L2TP_ENCAPTYPE_UDP) @@ -136,14 +147,14 @@ static void l2tp_dfs_seq_tunnel_show(struct seq_file *m, void *v)  		   tunnel->sock ? atomic_read(&tunnel->sock->sk_refcnt) : 0,  		   atomic_read(&tunnel->ref_count)); -	seq_printf(m, " %08x rx %llu/%llu/%llu rx %llu/%llu/%llu\n", +	seq_printf(m, " %08x rx %ld/%ld/%ld rx %ld/%ld/%ld\n",  		   tunnel->debug, -		   (unsigned long long)tunnel->stats.tx_packets, -		   (unsigned long long)tunnel->stats.tx_bytes, -		   (unsigned long long)tunnel->stats.tx_errors, -		   (unsigned long long)tunnel->stats.rx_packets, -		   (unsigned long long)tunnel->stats.rx_bytes, -		   (unsigned long long)tunnel->stats.rx_errors); +		   atomic_long_read(&tunnel->stats.tx_packets), +		   atomic_long_read(&tunnel->stats.tx_bytes), +		   atomic_long_read(&tunnel->stats.tx_errors), +		   atomic_long_read(&tunnel->stats.rx_packets), +		   atomic_long_read(&tunnel->stats.rx_bytes), +		   atomic_long_read(&tunnel->stats.rx_errors));  	if (tunnel->show != NULL)  		tunnel->show(m, tunnel); @@ -193,14 +204,14 @@ static void l2tp_dfs_seq_session_show(struct seq_file *m, void *v)  		seq_printf(m, "\n");  	} -	seq_printf(m, "   %hu/%hu tx %llu/%llu/%llu rx %llu/%llu/%llu\n", +	seq_printf(m, "   %hu/%hu tx %ld/%ld/%ld rx %ld/%ld/%ld\n",  		   session->nr, session->ns, -		   (unsigned long long)session->stats.tx_packets, -		   (unsigned long long)session->stats.tx_bytes, -		   (unsigned long long)session->stats.tx_errors, -		   (unsigned long long)session->stats.rx_packets, -		   (unsigned long long)session->stats.rx_bytes, -		   (unsigned long long)session->stats.rx_errors); +		   atomic_long_read(&session->stats.tx_packets), +		   atomic_long_read(&session->stats.tx_bytes), +		   atomic_long_read(&session->stats.tx_errors), +		   atomic_long_read(&session->stats.rx_packets), +		   atomic_long_read(&session->stats.rx_bytes), +		   atomic_long_read(&session->stats.rx_errors));  	if (session->show != NULL)  		session->show(m, session); @@ -258,7 +269,7 @@ static int l2tp_dfs_seq_open(struct inode *inode, struct file *file)  	 */  	pd->net = get_net_ns_by_pid(current->pid);  	if (IS_ERR(pd->net)) { -		rc = -PTR_ERR(pd->net); +		rc = PTR_ERR(pd->net);  		goto err_free_pd;  	} @@ -317,11 +328,11 @@ static int __init l2tp_debugfs_init(void)  	if (tunnels == NULL)  		rc = -EIO; -	printk(KERN_INFO "L2TP debugfs support\n"); +	pr_info("L2TP debugfs support\n");  out:  	if (rc) -		printk(KERN_WARNING "l2tp debugfs: unable to init\n"); +		pr_warn("unable to init\n");  	return rc;  } diff --git a/net/l2tp/l2tp_eth.c b/net/l2tp/l2tp_eth.c index 8d9ce0accc9..76125c57ee6 100644 --- a/net/l2tp/l2tp_eth.c +++ b/net/l2tp/l2tp_eth.c @@ -9,6 +9,8 @@   *	2 of the License, or (at your option) any later version.   */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +  #include <linux/module.h>  #include <linux/skbuff.h>  #include <linux/socket.h> @@ -40,6 +42,12 @@ struct l2tp_eth {  	struct sock		*tunnel_sock;  	struct l2tp_session	*session;  	struct list_head	list; +	atomic_long_t		tx_bytes; +	atomic_long_t		tx_packets; +	atomic_long_t		tx_dropped; +	atomic_long_t		rx_bytes; +	atomic_long_t		rx_packets; +	atomic_long_t		rx_errors;  };  /* via l2tp_session_priv() */ @@ -59,14 +67,15 @@ static inline struct l2tp_eth_net *l2tp_eth_pernet(struct net *net)  	return net_generic(net, l2tp_eth_net_id);  } +static struct lock_class_key l2tp_eth_tx_busylock;  static int l2tp_eth_dev_init(struct net_device *dev)  {  	struct l2tp_eth *priv = netdev_priv(dev);  	priv->dev = dev; -	random_ether_addr(dev->dev_addr); +	eth_hw_addr_random(dev);  	memset(&dev->broadcast[0], 0xff, 6); - +	dev->qdisc_tx_busylock = &l2tp_eth_tx_busylock;  	return 0;  } @@ -85,25 +94,45 @@ static int l2tp_eth_dev_xmit(struct sk_buff *skb, struct net_device *dev)  {  	struct l2tp_eth *priv = netdev_priv(dev);  	struct l2tp_session *session = priv->session; +	unsigned int len = skb->len; +	int ret = l2tp_xmit_skb(session, skb, session->hdr_len); + +	if (likely(ret == NET_XMIT_SUCCESS)) { +		atomic_long_add(len, &priv->tx_bytes); +		atomic_long_inc(&priv->tx_packets); +	} else { +		atomic_long_inc(&priv->tx_dropped); +	} +	return NETDEV_TX_OK; +} -	l2tp_xmit_skb(session, skb, session->hdr_len); - -	dev->stats.tx_bytes += skb->len; -	dev->stats.tx_packets++; +static struct rtnl_link_stats64 *l2tp_eth_get_stats64(struct net_device *dev, +						      struct rtnl_link_stats64 *stats) +{ +	struct l2tp_eth *priv = netdev_priv(dev); -	return 0; +	stats->tx_bytes   = atomic_long_read(&priv->tx_bytes); +	stats->tx_packets = atomic_long_read(&priv->tx_packets); +	stats->tx_dropped = atomic_long_read(&priv->tx_dropped); +	stats->rx_bytes   = atomic_long_read(&priv->rx_bytes); +	stats->rx_packets = atomic_long_read(&priv->rx_packets); +	stats->rx_errors  = atomic_long_read(&priv->rx_errors); +	return stats;  } +  static struct net_device_ops l2tp_eth_netdev_ops = {  	.ndo_init		= l2tp_eth_dev_init,  	.ndo_uninit		= l2tp_eth_dev_uninit,  	.ndo_start_xmit		= l2tp_eth_dev_xmit, +	.ndo_get_stats64	= l2tp_eth_get_stats64,  };  static void l2tp_eth_dev_setup(struct net_device *dev)  {  	ether_setup(dev); - +	dev->priv_flags		&= ~IFF_TX_SKB_SHARING; +	dev->features		|= NETIF_F_LLTX;  	dev->netdev_ops		= &l2tp_eth_netdev_ops;  	dev->destructor		= free_netdev;  } @@ -112,27 +141,20 @@ static void l2tp_eth_dev_recv(struct l2tp_session *session, struct sk_buff *skb,  {  	struct l2tp_eth_sess *spriv = l2tp_session_priv(session);  	struct net_device *dev = spriv->dev; +	struct l2tp_eth *priv = netdev_priv(dev);  	if (session->debug & L2TP_MSG_DATA) {  		unsigned int length; -		int offset; -		u8 *ptr = skb->data;  		length = min(32u, skb->len);  		if (!pskb_may_pull(skb, length))  			goto error; -		printk(KERN_DEBUG "%s: eth recv: ", session->name); - -		offset = 0; -		do { -			printk(" %02X", ptr[offset]); -		} while (++offset < length); - -		printk("\n"); +		pr_debug("%s: eth recv\n", session->name); +		print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, skb->data, length);  	} -	if (!pskb_may_pull(skb, sizeof(ETH_HLEN))) +	if (!pskb_may_pull(skb, ETH_HLEN))  		goto error;  	secpath_reset(skb); @@ -144,15 +166,15 @@ static void l2tp_eth_dev_recv(struct l2tp_session *session, struct sk_buff *skb,  	nf_reset(skb);  	if (dev_forward_skb(dev, skb) == NET_RX_SUCCESS) { -		dev->stats.rx_packets++; -		dev->stats.rx_bytes += data_len; -	} else -		dev->stats.rx_errors++; - +		atomic_long_inc(&priv->rx_packets); +		atomic_long_add(data_len, &priv->rx_bytes); +	} else { +		atomic_long_inc(&priv->rx_errors); +	}  	return;  error: -	dev->stats.rx_errors++; +	atomic_long_inc(&priv->rx_errors);  	kfree_skb(skb);  } @@ -167,6 +189,7 @@ static void l2tp_eth_delete(struct l2tp_session *session)  		if (dev) {  			unregister_netdev(dev);  			spriv->dev = NULL; +			module_put(THIS_MODULE);  		}  	}  } @@ -254,6 +277,7 @@ static int l2tp_eth_create(struct net *net, u32 tunnel_id, u32 session_id, u32 p  	if (rc < 0)  		goto out_del_dev; +	__module_get(THIS_MODULE);  	/* Must be done after register_netdev() */  	strlcpy(session->ifname, dev->name, IFNAMSIZ); @@ -267,6 +291,7 @@ static int l2tp_eth_create(struct net *net, u32 tunnel_id, u32 session_id, u32 p  out_del_dev:  	free_netdev(dev); +	spriv->dev = NULL;  out_del_session:  	l2tp_session_delete(session);  out: @@ -283,7 +308,7 @@ static __net_init int l2tp_eth_init_net(struct net *net)  	return 0;  } -static __net_initdata struct pernet_operations l2tp_eth_net_ops = { +static struct pernet_operations l2tp_eth_net_ops = {  	.init = l2tp_eth_init_net,  	.id   = &l2tp_eth_net_id,  	.size = sizeof(struct l2tp_eth_net), @@ -308,7 +333,7 @@ static int __init l2tp_eth_init(void)  	if (err)  		goto out_unreg; -	printk(KERN_INFO "L2TP ethernet pseudowire support (L2TPv3)\n"); +	pr_info("L2TP ethernet pseudowire support (L2TPv3)\n");  	return 0; diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c index 04635e88e8e..369a9822488 100644 --- a/net/l2tp/l2tp_ip.c +++ b/net/l2tp/l2tp_ip.c @@ -9,6 +9,8 @@   *	2 of the License, or (at your option) any later version.   */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +  #include <linux/icmp.h>  #include <linux/module.h>  #include <linux/skbuff.h> @@ -32,15 +34,8 @@ struct l2tp_ip_sock {  	/* 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); @@ -54,10 +49,9 @@ static inline struct l2tp_ip_sock *l2tp_ip_sk(const struct sock *sk)  static struct sock *__l2tp_ip_bind_lookup(struct net *net, __be32 laddr, int dif, u32 tunnel_id)  { -	struct hlist_node *node;  	struct sock *sk; -	sk_for_each_bound(sk, node, &l2tp_ip_bind_table) { +	sk_for_each_bound(sk, &l2tp_ip_bind_table) {  		struct inet_sock *inet = inet_sk(sk);  		struct l2tp_ip_sock *l2tp = l2tp_ip_sk(sk); @@ -120,6 +114,7 @@ static inline struct sock *l2tp_ip_bind_lookup(struct net *net, __be32 laddr, in   */  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; @@ -127,7 +122,6 @@ static int l2tp_ip_recv(struct sk_buff *skb)  	struct l2tp_session *session;  	struct l2tp_tunnel *tunnel = NULL;  	int length; -	int offset;  	/* Point to L2TP header */  	optr = ptr = skb->data; @@ -148,7 +142,7 @@ static int l2tp_ip_recv(struct sk_buff *skb)  	}  	/* 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 +156,8 @@ static int l2tp_ip_recv(struct sk_buff *skb)  		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,14 +173,14 @@ pass_up:  		goto discard;  	tunnel_id = ntohl(*(__be32 *) &skb->data[4]); -	tunnel = l2tp_tunnel_find(&init_net, tunnel_id); +	tunnel = l2tp_tunnel_find(net, tunnel_id);  	if (tunnel != NULL)  		sk = tunnel->sock;  	else {  		struct iphdr *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); +		sk = __l2tp_ip_bind_lookup(net, iph->daddr, 0, tunnel_id);  		read_unlock_bh(&l2tp_ip_lock);  	} @@ -232,7 +220,7 @@ static void l2tp_ip_close(struct sock *sk, long timeout)  {  	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 +228,16 @@ static void l2tp_ip_close(struct sock *sk, long timeout)  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 +245,21 @@ static int l2tp_ip_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)  {  	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 +268,14 @@ static int l2tp_ip_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)  	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 +287,8 @@ static int l2tp_ip_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)  	sk_del_node_init(sk);  	write_unlock_bh(&l2tp_ip_lock);  	ret = 0; +	sock_reset_flag(sk, SOCK_ZAPPED); +  out:  	release_sock(sk); @@ -296,68 +302,43 @@ out_in_use:  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; -	rc = ip_route_connect(&rt, lsa->l2tp_addr.s_addr, saddr, -			      RT_CONN_FLAGS(sk), oif, -			      IPPROTO_L2TP, -			      0, 0, sk, 1); -	if (rc) { -		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)  { @@ -388,11 +369,6 @@ static int l2tp_ip_backlog_recv(struct sock *sk, struct sk_buff *skb)  {  	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) @@ -401,7 +377,7 @@ static int l2tp_ip_backlog_recv(struct sock *sk, struct sk_buff *skb)  	return 0;  drop: -	IP_INC_STATS(&init_net, IPSTATS_MIB_INDISCARDS); +	IP_INC_STATS(sock_net(sk), IPSTATS_MIB_INDISCARDS);  	kfree_skb(skb);  	return -1;  } @@ -413,31 +389,36 @@ static int l2tp_ip_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m  {  	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; +	struct flowi4 *fl4;  	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; +		DECLARE_SOCKADDR(struct sockaddr_l2tpip *, lip, 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; @@ -466,73 +447,77 @@ static int l2tp_ip_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m  		goto error;  	} +	fl4 = &inet->cork.fl.u.ip4;  	if (connected)  		rt = (struct rtable *) __sk_dst_check(sk, 0); +	rcu_read_lock();  	if (rt == NULL) { +		const struct ip_options_rcu *inet_opt; + +		inet_opt = rcu_dereference(inet->inet_opt); +  		/* Use correct destination address if we have options. */ -		if (opt && opt->srr) -			daddr = opt->faddr; - -		{ -			struct flowi fl = { .oif = sk->sk_bound_dev_if, -					    .fl4_dst = daddr, -					    .fl4_src = inet->inet_saddr, -					    .fl4_tos = RT_CONN_FLAGS(sk), -					    .proto = sk->sk_protocol, -					    .flags = inet_sk_flowi_flags(sk), -					    .fl_ip_sport = inet->inet_sport, -					    .fl_ip_dport = inet->inet_dport }; - -			/* If this fails, retransmit mechanism of transport layer will -			 * keep trying until route appears or the connection times -			 * itself out. -			 */ -			security_sk_classify_flow(sk, &fl); -			if (ip_route_output_flow(sock_net(sk), &rt, &fl, sk, 0)) -				goto no_route; +		if (inet_opt && inet_opt->opt.srr) +			daddr = inet_opt->opt.faddr; + +		/* If this fails, retransmit mechanism of transport layer will +		 * keep trying until route appears or the connection times +		 * itself out. +		 */ +		rt = ip_route_output_ports(sock_net(sk), fl4, sk, +					   daddr, inet->inet_saddr, +					   inet->inet_dport, inet->inet_sport, +					   sk->sk_protocol, RT_CONN_FLAGS(sk), +					   sk->sk_bound_dev_if); +		if (IS_ERR(rt)) +			goto no_route; +		if (connected) { +			sk_setup_caps(sk, &rt->dst); +		} else { +			skb_dst_set(skb, &rt->dst); +			goto xmit;  		} -		sk_setup_caps(sk, &rt->dst);  	} -	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); +	rc = ip_queue_xmit(sk, skb, &inet->cork.fl); +	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; +	DECLARE_SOCKADDR(struct sockaddr_in *, sin, msg->msg_name);  	struct sk_buff *skb;  	if (flags & MSG_OOB)  		goto out; -	if (addr_len) -		*addr_len = sizeof(*sin); -  	skb = skb_recv_datagram(sk, flags, noblock, &err);  	if (!skb)  		goto out; @@ -555,6 +540,7 @@ static int l2tp_ip_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m  		sin->sin_addr.s_addr = ip_hdr(skb)->saddr;  		sin->sin_port = 0;  		memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); +		*addr_len = sizeof(*sin);  	}  	if (inet->cmsg_flags)  		ip_cmsg_recv(msg, skb); @@ -563,15 +549,7 @@ static int l2tp_ip_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m  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 = { @@ -581,7 +559,7 @@ static struct proto l2tp_ip_prot = {  	.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, @@ -628,18 +606,18 @@ static struct inet_protosw l2tp_ip_protosw = {  	.protocol	= IPPROTO_L2TP,  	.prot		= &l2tp_ip_prot,  	.ops		= &l2tp_ip_ops, -	.no_check	= 0,  };  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) @@ -672,4 +650,8 @@ MODULE_LICENSE("GPL");  MODULE_AUTHOR("James Chapman <jchapman@katalix.com>");  MODULE_DESCRIPTION("L2TP over IP");  MODULE_VERSION("1.0"); -MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET, SOCK_DGRAM, IPPROTO_L2TP); + +/* Use the value of SOCK_DGRAM (2) directory, because __stringify doesn't like + * enums + */ +MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET, 2, IPPROTO_L2TP); diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c new file mode 100644 index 00000000000..f3f98a156ce --- /dev/null +++ b/net/l2tp/l2tp_ip6.c @@ -0,0 +1,805 @@ +/* + * L2TPv3 IP encapsulation support for IPv6 + * + * Copyright (c) 2012 Katalix Systems Ltd + * + *	This program is free software; you can redistribute it and/or + *	modify it under the terms of the GNU General Public License + *	as published by the Free Software Foundation; either version + *	2 of the License, or (at your option) any later version. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/icmp.h> +#include <linux/module.h> +#include <linux/skbuff.h> +#include <linux/random.h> +#include <linux/socket.h> +#include <linux/l2tp.h> +#include <linux/in.h> +#include <linux/in6.h> +#include <net/sock.h> +#include <net/ip.h> +#include <net/icmp.h> +#include <net/udp.h> +#include <net/inet_common.h> +#include <net/inet_hashtables.h> +#include <net/tcp_states.h> +#include <net/protocol.h> +#include <net/xfrm.h> + +#include <net/transp_v6.h> +#include <net/addrconf.h> +#include <net/ip6_route.h> + +#include "l2tp_core.h" + +struct l2tp_ip6_sock { +	/* inet_sock has to be the first member of l2tp_ip6_sock */ +	struct inet_sock	inet; + +	u32			conn_id; +	u32			peer_conn_id; + +	/* ipv6_pinfo has to be the last member of l2tp_ip6_sock, see +	   inet6_sk_generic */ +	struct ipv6_pinfo	inet6; +}; + +static DEFINE_RWLOCK(l2tp_ip6_lock); +static struct hlist_head l2tp_ip6_table; +static struct hlist_head l2tp_ip6_bind_table; + +static inline struct l2tp_ip6_sock *l2tp_ip6_sk(const struct sock *sk) +{ +	return (struct l2tp_ip6_sock *)sk; +} + +static struct sock *__l2tp_ip6_bind_lookup(struct net *net, +					   struct in6_addr *laddr, +					   int dif, u32 tunnel_id) +{ +	struct sock *sk; + +	sk_for_each_bound(sk, &l2tp_ip6_bind_table) { +		const struct in6_addr *addr = inet6_rcv_saddr(sk); +		struct l2tp_ip6_sock *l2tp = l2tp_ip6_sk(sk); + +		if (l2tp == NULL) +			continue; + +		if ((l2tp->conn_id == tunnel_id) && +		    net_eq(sock_net(sk), net) && +		    !(addr && ipv6_addr_equal(addr, laddr)) && +		    !(sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif)) +			goto found; +	} + +	sk = NULL; +found: +	return sk; +} + +static inline struct sock *l2tp_ip6_bind_lookup(struct net *net, +						struct in6_addr *laddr, +						int dif, u32 tunnel_id) +{ +	struct sock *sk = __l2tp_ip6_bind_lookup(net, laddr, dif, tunnel_id); +	if (sk) +		sock_hold(sk); + +	return sk; +} + +/* When processing receive frames, there are two cases to + * consider. Data frames consist of a non-zero session-id and an + * optional cookie. Control frames consist of a regular L2TP header + * preceded by 32-bits of zeros. + * + * L2TPv3 Session Header Over IP + * + *  0                   1                   2                   3 + *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |                           Session ID                          | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |               Cookie (optional, maximum 64 bits)... + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + *                                                                 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * L2TPv3 Control Message Header Over IP + * + *  0                   1                   2                   3 + *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |                      (32 bits of zeros)                       | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |T|L|x|x|S|x|x|x|x|x|x|x|  Ver  |             Length            | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |                     Control Connection ID                     | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |               Ns              |               Nr              | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * All control frames are passed to userspace. + */ +static int l2tp_ip6_recv(struct sk_buff *skb) +{ +	struct sock *sk; +	u32 session_id; +	u32 tunnel_id; +	unsigned char *ptr, *optr; +	struct l2tp_session *session; +	struct l2tp_tunnel *tunnel = NULL; +	int length; + +	/* Point to L2TP header */ +	optr = ptr = skb->data; + +	if (!pskb_may_pull(skb, 4)) +		goto discard; + +	session_id = ntohl(*((__be32 *) ptr)); +	ptr += 4; + +	/* RFC3931: L2TP/IP packets have the first 4 bytes containing +	 * the session_id. If it is 0, the packet is a L2TP control +	 * frame and the session_id value can be discarded. +	 */ +	if (session_id == 0) { +		__skb_pull(skb, 4); +		goto pass_up; +	} + +	/* Ok, this is a data packet. Lookup the session. */ +	session = l2tp_session_find(&init_net, NULL, session_id); +	if (session == NULL) +		goto discard; + +	tunnel = session->tunnel; +	if (tunnel == NULL) +		goto discard; + +	/* Trace packet contents, if enabled */ +	if (tunnel->debug & L2TP_MSG_DATA) { +		length = min(32u, skb->len); +		if (!pskb_may_pull(skb, length)) +			goto discard; + +		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); +	return 0; + +pass_up: +	/* Get the tunnel_id from the L2TP header */ +	if (!pskb_may_pull(skb, 12)) +		goto discard; + +	if ((skb->data[0] & 0xc0) != 0xc0) +		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 ipv6hdr *iph = ipv6_hdr(skb); + +		read_lock_bh(&l2tp_ip6_lock); +		sk = __l2tp_ip6_bind_lookup(&init_net, &iph->daddr, +					    0, tunnel_id); +		read_unlock_bh(&l2tp_ip6_lock); +	} + +	if (sk == NULL) +		goto discard; + +	sock_hold(sk); + +	if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) +		goto discard_put; + +	nf_reset(skb); + +	return sk_receive_skb(sk, skb, 1); + +discard_put: +	sock_put(sk); + +discard: +	kfree_skb(skb); +	return 0; +} + +static int l2tp_ip6_open(struct sock *sk) +{ +	/* Prevent autobind. We don't have ports. */ +	inet_sk(sk)->inet_num = IPPROTO_L2TP; + +	write_lock_bh(&l2tp_ip6_lock); +	sk_add_node(sk, &l2tp_ip6_table); +	write_unlock_bh(&l2tp_ip6_lock); + +	return 0; +} + +static void l2tp_ip6_close(struct sock *sk, long timeout) +{ +	write_lock_bh(&l2tp_ip6_lock); +	hlist_del_init(&sk->sk_bind_node); +	sk_del_node_init(sk); +	write_unlock_bh(&l2tp_ip6_lock); + +	sk_common_release(sk); +} + +static void l2tp_ip6_destroy_sock(struct sock *sk) +{ +	struct l2tp_tunnel *tunnel = l2tp_sock_to_tunnel(sk); + +	lock_sock(sk); +	ip6_flush_pending_frames(sk); +	release_sock(sk); + +	if (tunnel) { +		l2tp_tunnel_closeall(tunnel); +		sock_put(sk); +	} + +	inet6_destroy_sock(sk); +} + +static int l2tp_ip6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) +{ +	struct inet_sock *inet = inet_sk(sk); +	struct ipv6_pinfo *np = inet6_sk(sk); +	struct sockaddr_l2tpip6 *addr = (struct sockaddr_l2tpip6 *) uaddr; +	__be32 v4addr = 0; +	int addr_type; +	int err; + +	if (!sock_flag(sk, SOCK_ZAPPED)) +		return -EINVAL; +	if (addr->l2tp_family != AF_INET6) +		return -EINVAL; +	if (addr_len < sizeof(*addr)) +		return -EINVAL; + +	addr_type = ipv6_addr_type(&addr->l2tp_addr); + +	/* l2tp_ip6 sockets are IPv6 only */ +	if (addr_type == IPV6_ADDR_MAPPED) +		return -EADDRNOTAVAIL; + +	/* L2TP is point-point, not multicast */ +	if (addr_type & IPV6_ADDR_MULTICAST) +		return -EADDRNOTAVAIL; + +	err = -EADDRINUSE; +	read_lock_bh(&l2tp_ip6_lock); +	if (__l2tp_ip6_bind_lookup(&init_net, &addr->l2tp_addr, +				   sk->sk_bound_dev_if, addr->l2tp_conn_id)) +		goto out_in_use; +	read_unlock_bh(&l2tp_ip6_lock); + +	lock_sock(sk); + +	err = -EINVAL; +	if (sk->sk_state != TCP_CLOSE) +		goto out_unlock; + +	/* Check if the address belongs to the host. */ +	rcu_read_lock(); +	if (addr_type != IPV6_ADDR_ANY) { +		struct net_device *dev = NULL; + +		if (addr_type & IPV6_ADDR_LINKLOCAL) { +			if (addr_len >= sizeof(struct sockaddr_in6) && +			    addr->l2tp_scope_id) { +				/* Override any existing binding, if another +				 * one is supplied by user. +				 */ +				sk->sk_bound_dev_if = addr->l2tp_scope_id; +			} + +			/* Binding to link-local address requires an +			   interface */ +			if (!sk->sk_bound_dev_if) +				goto out_unlock_rcu; + +			err = -ENODEV; +			dev = dev_get_by_index_rcu(sock_net(sk), +						   sk->sk_bound_dev_if); +			if (!dev) +				goto out_unlock_rcu; +		} + +		/* ipv4 addr of the socket is invalid.  Only the +		 * unspecified and mapped address have a v4 equivalent. +		 */ +		v4addr = LOOPBACK4_IPV6; +		err = -EADDRNOTAVAIL; +		if (!ipv6_chk_addr(sock_net(sk), &addr->l2tp_addr, dev, 0)) +			goto out_unlock_rcu; +	} +	rcu_read_unlock(); + +	inet->inet_rcv_saddr = inet->inet_saddr = v4addr; +	sk->sk_v6_rcv_saddr = addr->l2tp_addr; +	np->saddr = addr->l2tp_addr; + +	l2tp_ip6_sk(sk)->conn_id = addr->l2tp_conn_id; + +	write_lock_bh(&l2tp_ip6_lock); +	sk_add_bind_node(sk, &l2tp_ip6_bind_table); +	sk_del_node_init(sk); +	write_unlock_bh(&l2tp_ip6_lock); + +	sock_reset_flag(sk, SOCK_ZAPPED); +	release_sock(sk); +	return 0; + +out_unlock_rcu: +	rcu_read_unlock(); +out_unlock: +	release_sock(sk); +	return err; + +out_in_use: +	read_unlock_bh(&l2tp_ip6_lock); +	return err; +} + +static int l2tp_ip6_connect(struct sock *sk, struct sockaddr *uaddr, +			    int addr_len) +{ +	struct sockaddr_l2tpip6 *lsa = (struct sockaddr_l2tpip6 *) uaddr; +	struct sockaddr_in6	*usin = (struct sockaddr_in6 *) uaddr; +	struct in6_addr	*daddr; +	int	addr_type; +	int rc; + +	if (sock_flag(sk, SOCK_ZAPPED)) /* Must bind first - autobinding does not work */ +		return -EINVAL; + +	if (addr_len < sizeof(*lsa)) +		return -EINVAL; + +	if (usin->sin6_family != AF_INET6) +		return -EINVAL; + +	addr_type = ipv6_addr_type(&usin->sin6_addr); +	if (addr_type & IPV6_ADDR_MULTICAST) +		return -EINVAL; + +	if (addr_type & IPV6_ADDR_MAPPED) { +		daddr = &usin->sin6_addr; +		if (ipv4_is_multicast(daddr->s6_addr32[3])) +			return -EINVAL; +	} + +	rc = ip6_datagram_connect(sk, uaddr, addr_len); + +	lock_sock(sk); + +	l2tp_ip6_sk(sk)->peer_conn_id = lsa->l2tp_conn_id; + +	write_lock_bh(&l2tp_ip6_lock); +	hlist_del_init(&sk->sk_bind_node); +	sk_add_bind_node(sk, &l2tp_ip6_bind_table); +	write_unlock_bh(&l2tp_ip6_lock); + +	release_sock(sk); + +	return rc; +} + +static int l2tp_ip6_disconnect(struct sock *sk, int flags) +{ +	if (sock_flag(sk, SOCK_ZAPPED)) +		return 0; + +	return udp_disconnect(sk, flags); +} + +static int l2tp_ip6_getname(struct socket *sock, struct sockaddr *uaddr, +			    int *uaddr_len, int peer) +{ +	struct sockaddr_l2tpip6 *lsa = (struct sockaddr_l2tpip6 *)uaddr; +	struct sock *sk = sock->sk; +	struct ipv6_pinfo *np = inet6_sk(sk); +	struct l2tp_ip6_sock *lsk = l2tp_ip6_sk(sk); + +	lsa->l2tp_family = AF_INET6; +	lsa->l2tp_flowinfo = 0; +	lsa->l2tp_scope_id = 0; +	lsa->l2tp_unused = 0; +	if (peer) { +		if (!lsk->peer_conn_id) +			return -ENOTCONN; +		lsa->l2tp_conn_id = lsk->peer_conn_id; +		lsa->l2tp_addr = sk->sk_v6_daddr; +		if (np->sndflow) +			lsa->l2tp_flowinfo = np->flow_label; +	} else { +		if (ipv6_addr_any(&sk->sk_v6_rcv_saddr)) +			lsa->l2tp_addr = np->saddr; +		else +			lsa->l2tp_addr = sk->sk_v6_rcv_saddr; + +		lsa->l2tp_conn_id = lsk->conn_id; +	} +	if (ipv6_addr_type(&lsa->l2tp_addr) & IPV6_ADDR_LINKLOCAL) +		lsa->l2tp_scope_id = sk->sk_bound_dev_if; +	*uaddr_len = sizeof(*lsa); +	return 0; +} + +static int l2tp_ip6_backlog_recv(struct sock *sk, struct sk_buff *skb) +{ +	int rc; + +	/* 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; + +drop: +	IP_INC_STATS(&init_net, IPSTATS_MIB_INDISCARDS); +	kfree_skb(skb); +	return -1; +} + +static int l2tp_ip6_push_pending_frames(struct sock *sk) +{ +	struct sk_buff *skb; +	__be32 *transhdr = NULL; +	int err = 0; + +	skb = skb_peek(&sk->sk_write_queue); +	if (skb == NULL) +		goto out; + +	transhdr = (__be32 *)skb_transport_header(skb); +	*transhdr = 0; + +	err = ip6_push_pending_frames(sk); + +out: +	return err; +} + +/* Userspace will call sendmsg() on the tunnel socket to send L2TP + * control frames. + */ +static int l2tp_ip6_sendmsg(struct kiocb *iocb, struct sock *sk, +			    struct msghdr *msg, size_t len) +{ +	struct ipv6_txoptions opt_space; +	DECLARE_SOCKADDR(struct sockaddr_l2tpip6 *, lsa, msg->msg_name); +	struct in6_addr *daddr, *final_p, final; +	struct ipv6_pinfo *np = inet6_sk(sk); +	struct ipv6_txoptions *opt = NULL; +	struct ip6_flowlabel *flowlabel = NULL; +	struct dst_entry *dst = NULL; +	struct flowi6 fl6; +	int addr_len = msg->msg_namelen; +	int hlimit = -1; +	int tclass = -1; +	int dontfrag = -1; +	int transhdrlen = 4; /* zero session-id */ +	int ulen = len + transhdrlen; +	int err; + +	/* Rough check on arithmetic overflow, +	   better check is made in ip6_append_data(). +	 */ +	if (len > INT_MAX) +		return -EMSGSIZE; + +	/* Mirror BSD error message compatibility */ +	if (msg->msg_flags & MSG_OOB) +		return -EOPNOTSUPP; + +	/* +	 *	Get and verify the address. +	 */ +	memset(&fl6, 0, sizeof(fl6)); + +	fl6.flowi6_mark = sk->sk_mark; + +	if (lsa) { +		if (addr_len < SIN6_LEN_RFC2133) +			return -EINVAL; + +		if (lsa->l2tp_family && lsa->l2tp_family != AF_INET6) +			return -EAFNOSUPPORT; + +		daddr = &lsa->l2tp_addr; +		if (np->sndflow) { +			fl6.flowlabel = lsa->l2tp_flowinfo & IPV6_FLOWINFO_MASK; +			if (fl6.flowlabel&IPV6_FLOWLABEL_MASK) { +				flowlabel = fl6_sock_lookup(sk, fl6.flowlabel); +				if (flowlabel == NULL) +					return -EINVAL; +			} +		} + +		/* +		 * Otherwise it will be difficult to maintain +		 * sk->sk_dst_cache. +		 */ +		if (sk->sk_state == TCP_ESTABLISHED && +		    ipv6_addr_equal(daddr, &sk->sk_v6_daddr)) +			daddr = &sk->sk_v6_daddr; + +		if (addr_len >= sizeof(struct sockaddr_in6) && +		    lsa->l2tp_scope_id && +		    ipv6_addr_type(daddr) & IPV6_ADDR_LINKLOCAL) +			fl6.flowi6_oif = lsa->l2tp_scope_id; +	} else { +		if (sk->sk_state != TCP_ESTABLISHED) +			return -EDESTADDRREQ; + +		daddr = &sk->sk_v6_daddr; +		fl6.flowlabel = np->flow_label; +	} + +	if (fl6.flowi6_oif == 0) +		fl6.flowi6_oif = sk->sk_bound_dev_if; + +	if (msg->msg_controllen) { +		opt = &opt_space; +		memset(opt, 0, sizeof(struct ipv6_txoptions)); +		opt->tot_len = sizeof(struct ipv6_txoptions); + +		err = ip6_datagram_send_ctl(sock_net(sk), sk, msg, &fl6, opt, +					    &hlimit, &tclass, &dontfrag); +		if (err < 0) { +			fl6_sock_release(flowlabel); +			return err; +		} +		if ((fl6.flowlabel & IPV6_FLOWLABEL_MASK) && !flowlabel) { +			flowlabel = fl6_sock_lookup(sk, fl6.flowlabel); +			if (flowlabel == NULL) +				return -EINVAL; +		} +		if (!(opt->opt_nflen|opt->opt_flen)) +			opt = NULL; +	} + +	if (opt == NULL) +		opt = np->opt; +	if (flowlabel) +		opt = fl6_merge_options(&opt_space, flowlabel, opt); +	opt = ipv6_fixup_options(&opt_space, opt); + +	fl6.flowi6_proto = sk->sk_protocol; +	if (!ipv6_addr_any(daddr)) +		fl6.daddr = *daddr; +	else +		fl6.daddr.s6_addr[15] = 0x1; /* :: means loopback (BSD'ism) */ +	if (ipv6_addr_any(&fl6.saddr) && !ipv6_addr_any(&np->saddr)) +		fl6.saddr = np->saddr; + +	final_p = fl6_update_dst(&fl6, opt, &final); + +	if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) +		fl6.flowi6_oif = np->mcast_oif; +	else if (!fl6.flowi6_oif) +		fl6.flowi6_oif = np->ucast_oif; + +	security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); + +	dst = ip6_dst_lookup_flow(sk, &fl6, final_p); +	if (IS_ERR(dst)) { +		err = PTR_ERR(dst); +		goto out; +	} + +	if (hlimit < 0) +		hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst); + +	if (tclass < 0) +		tclass = np->tclass; + +	if (dontfrag < 0) +		dontfrag = np->dontfrag; + +	if (msg->msg_flags & MSG_CONFIRM) +		goto do_confirm; + +back_from_confirm: +	lock_sock(sk); +	err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, +			      ulen, transhdrlen, hlimit, tclass, opt, +			      &fl6, (struct rt6_info *)dst, +			      msg->msg_flags, dontfrag); +	if (err) +		ip6_flush_pending_frames(sk); +	else if (!(msg->msg_flags & MSG_MORE)) +		err = l2tp_ip6_push_pending_frames(sk); +	release_sock(sk); +done: +	dst_release(dst); +out: +	fl6_sock_release(flowlabel); + +	return err < 0 ? err : len; + +do_confirm: +	dst_confirm(dst); +	if (!(msg->msg_flags & MSG_PROBE) || len) +		goto back_from_confirm; +	err = 0; +	goto done; +} + +static int l2tp_ip6_recvmsg(struct kiocb *iocb, struct sock *sk, +			    struct msghdr *msg, size_t len, int noblock, +			    int flags, int *addr_len) +{ +	struct ipv6_pinfo *np = inet6_sk(sk); +	DECLARE_SOCKADDR(struct sockaddr_l2tpip6 *, lsa, msg->msg_name); +	size_t copied = 0; +	int err = -EOPNOTSUPP; +	struct sk_buff *skb; + +	if (flags & MSG_OOB) +		goto out; + +	if (addr_len) +		*addr_len = sizeof(*lsa); + +	if (flags & MSG_ERRQUEUE) +		return ipv6_recv_error(sk, msg, len, addr_len); + +	skb = skb_recv_datagram(sk, flags, noblock, &err); +	if (!skb) +		goto out; + +	copied = skb->len; +	if (len < copied) { +		msg->msg_flags |= MSG_TRUNC; +		copied = len; +	} + +	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); +	if (err) +		goto done; + +	sock_recv_timestamp(msg, sk, skb); + +	/* Copy the address. */ +	if (lsa) { +		lsa->l2tp_family = AF_INET6; +		lsa->l2tp_unused = 0; +		lsa->l2tp_addr = ipv6_hdr(skb)->saddr; +		lsa->l2tp_flowinfo = 0; +		lsa->l2tp_scope_id = 0; +		lsa->l2tp_conn_id = 0; +		if (ipv6_addr_type(&lsa->l2tp_addr) & IPV6_ADDR_LINKLOCAL) +			lsa->l2tp_scope_id = IP6CB(skb)->iif; +	} + +	if (np->rxopt.all) +		ip6_datagram_recv_ctl(sk, msg, skb); + +	if (flags & MSG_TRUNC) +		copied = skb->len; +done: +	skb_free_datagram(sk, skb); +out: +	return err ? err : copied; +} + +static struct proto l2tp_ip6_prot = { +	.name		   = "L2TP/IPv6", +	.owner		   = THIS_MODULE, +	.init		   = l2tp_ip6_open, +	.close		   = l2tp_ip6_close, +	.bind		   = l2tp_ip6_bind, +	.connect	   = l2tp_ip6_connect, +	.disconnect	   = l2tp_ip6_disconnect, +	.ioctl		   = udp_ioctl, +	.destroy	   = l2tp_ip6_destroy_sock, +	.setsockopt	   = ipv6_setsockopt, +	.getsockopt	   = ipv6_getsockopt, +	.sendmsg	   = l2tp_ip6_sendmsg, +	.recvmsg	   = l2tp_ip6_recvmsg, +	.backlog_rcv	   = l2tp_ip6_backlog_recv, +	.hash		   = inet_hash, +	.unhash		   = inet_unhash, +	.obj_size	   = sizeof(struct l2tp_ip6_sock), +#ifdef CONFIG_COMPAT +	.compat_setsockopt = compat_ipv6_setsockopt, +	.compat_getsockopt = compat_ipv6_getsockopt, +#endif +}; + +static const struct proto_ops l2tp_ip6_ops = { +	.family		   = PF_INET6, +	.owner		   = THIS_MODULE, +	.release	   = inet6_release, +	.bind		   = inet6_bind, +	.connect	   = inet_dgram_connect, +	.socketpair	   = sock_no_socketpair, +	.accept		   = sock_no_accept, +	.getname	   = l2tp_ip6_getname, +	.poll		   = datagram_poll, +	.ioctl		   = inet6_ioctl, +	.listen		   = sock_no_listen, +	.shutdown	   = inet_shutdown, +	.setsockopt	   = sock_common_setsockopt, +	.getsockopt	   = sock_common_getsockopt, +	.sendmsg	   = inet_sendmsg, +	.recvmsg	   = sock_common_recvmsg, +	.mmap		   = sock_no_mmap, +	.sendpage	   = sock_no_sendpage, +#ifdef CONFIG_COMPAT +	.compat_setsockopt = compat_sock_common_setsockopt, +	.compat_getsockopt = compat_sock_common_getsockopt, +#endif +}; + +static struct inet_protosw l2tp_ip6_protosw = { +	.type		= SOCK_DGRAM, +	.protocol	= IPPROTO_L2TP, +	.prot		= &l2tp_ip6_prot, +	.ops		= &l2tp_ip6_ops, +}; + +static struct inet6_protocol l2tp_ip6_protocol __read_mostly = { +	.handler	= l2tp_ip6_recv, +}; + +static int __init l2tp_ip6_init(void) +{ +	int err; + +	pr_info("L2TP IP encapsulation support for IPv6 (L2TPv3)\n"); + +	err = proto_register(&l2tp_ip6_prot, 1); +	if (err != 0) +		goto out; + +	err = inet6_add_protocol(&l2tp_ip6_protocol, IPPROTO_L2TP); +	if (err) +		goto out1; + +	inet6_register_protosw(&l2tp_ip6_protosw); +	return 0; + +out1: +	proto_unregister(&l2tp_ip6_prot); +out: +	return err; +} + +static void __exit l2tp_ip6_exit(void) +{ +	inet6_unregister_protosw(&l2tp_ip6_protosw); +	inet6_del_protocol(&l2tp_ip6_protocol, IPPROTO_L2TP); +	proto_unregister(&l2tp_ip6_prot); +} + +module_init(l2tp_ip6_init); +module_exit(l2tp_ip6_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Chris Elston <celston@katalix.com>"); +MODULE_DESCRIPTION("L2TP IP encapsulation for IPv6"); +MODULE_VERSION("1.0"); + +/* Use the value of SOCK_DGRAM (2) directory, because __stringify doesn't like + * enums + */ +MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 2, IPPROTO_L2TP); diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c index 4c1e540732d..0ac907adb2f 100644 --- a/net/l2tp/l2tp_netlink.c +++ b/net/l2tp/l2tp_netlink.c @@ -14,6 +14,8 @@   * published by the Free Software Foundation.   */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +  #include <net/sock.h>  #include <net/genetlink.h>  #include <net/udp.h> @@ -35,6 +37,7 @@ static struct genl_family l2tp_nl_family = {  	.version	= L2TP_GENL_VERSION,  	.hdrsize	= 0,  	.maxattr	= L2TP_ATTR_MAX, +	.netnsok	= true,  };  /* Accessed under genl lock */ @@ -70,22 +73,22 @@ static int l2tp_nl_cmd_noop(struct sk_buff *skb, struct genl_info *info)  	void *hdr;  	int ret = -ENOBUFS; -	msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); +	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);  	if (!msg) {  		ret = -ENOMEM;  		goto out;  	} -	hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, +	hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq,  			  &l2tp_nl_family, 0, L2TP_CMD_NOOP); -	if (IS_ERR(hdr)) { -		ret = PTR_ERR(hdr); +	if (!hdr) { +		ret = -EMSGSIZE;  		goto err_out;  	}  	genlmsg_end(msg, hdr); -	return genlmsg_unicast(genl_info_net(info), msg, info->snd_pid); +	return genlmsg_unicast(genl_info_net(info), msg, info->snd_portid);  err_out:  	nlmsg_free(msg); @@ -133,16 +136,38 @@ static int l2tp_nl_cmd_tunnel_create(struct sk_buff *skb, struct genl_info *info  	if (info->attrs[L2TP_ATTR_FD]) {  		fd = nla_get_u32(info->attrs[L2TP_ATTR_FD]);  	} else { -		if (info->attrs[L2TP_ATTR_IP_SADDR]) -			cfg.local_ip.s_addr = nla_get_be32(info->attrs[L2TP_ATTR_IP_SADDR]); -		if (info->attrs[L2TP_ATTR_IP_DADDR]) -			cfg.peer_ip.s_addr = nla_get_be32(info->attrs[L2TP_ATTR_IP_DADDR]); +#if IS_ENABLED(CONFIG_IPV6) +		if (info->attrs[L2TP_ATTR_IP6_SADDR] && +		    info->attrs[L2TP_ATTR_IP6_DADDR]) { +			cfg.local_ip6 = nla_data( +				info->attrs[L2TP_ATTR_IP6_SADDR]); +			cfg.peer_ip6 = nla_data( +				info->attrs[L2TP_ATTR_IP6_DADDR]); +		} else +#endif +		if (info->attrs[L2TP_ATTR_IP_SADDR] && +		    info->attrs[L2TP_ATTR_IP_DADDR]) { +			cfg.local_ip.s_addr = nla_get_be32( +				info->attrs[L2TP_ATTR_IP_SADDR]); +			cfg.peer_ip.s_addr = nla_get_be32( +				info->attrs[L2TP_ATTR_IP_DADDR]); +		} else { +			ret = -EINVAL; +			goto out; +		}  		if (info->attrs[L2TP_ATTR_UDP_SPORT])  			cfg.local_udp_port = nla_get_u16(info->attrs[L2TP_ATTR_UDP_SPORT]);  		if (info->attrs[L2TP_ATTR_UDP_DPORT])  			cfg.peer_udp_port = nla_get_u16(info->attrs[L2TP_ATTR_UDP_DPORT]);  		if (info->attrs[L2TP_ATTR_UDP_CSUM])  			cfg.use_udp_checksums = nla_get_flag(info->attrs[L2TP_ATTR_UDP_CSUM]); + +#if IS_ENABLED(CONFIG_IPV6) +		if (info->attrs[L2TP_ATTR_UDP_ZERO_CSUM6_TX]) +			cfg.udp6_zero_tx_checksums = nla_get_flag(info->attrs[L2TP_ATTR_UDP_ZERO_CSUM6_TX]); +		if (info->attrs[L2TP_ATTR_UDP_ZERO_CSUM6_RX]) +			cfg.udp6_zero_rx_checksums = nla_get_flag(info->attrs[L2TP_ATTR_UDP_ZERO_CSUM6_RX]); +#endif  	}  	if (info->attrs[L2TP_ATTR_DEBUG]) @@ -218,54 +243,83 @@ out:  	return ret;  } -static int l2tp_nl_tunnel_send(struct sk_buff *skb, u32 pid, u32 seq, int flags, +static int l2tp_nl_tunnel_send(struct sk_buff *skb, u32 portid, u32 seq, int flags,  			       struct l2tp_tunnel *tunnel)  {  	void *hdr;  	struct nlattr *nest;  	struct sock *sk = NULL;  	struct inet_sock *inet; +#if IS_ENABLED(CONFIG_IPV6) +	struct ipv6_pinfo *np = NULL; +#endif -	hdr = genlmsg_put(skb, pid, seq, &l2tp_nl_family, flags, +	hdr = genlmsg_put(skb, portid, seq, &l2tp_nl_family, flags,  			  L2TP_CMD_TUNNEL_GET); -	if (IS_ERR(hdr)) -		return PTR_ERR(hdr); - -	NLA_PUT_U8(skb, L2TP_ATTR_PROTO_VERSION, tunnel->version); -	NLA_PUT_U32(skb, L2TP_ATTR_CONN_ID, tunnel->tunnel_id); -	NLA_PUT_U32(skb, L2TP_ATTR_PEER_CONN_ID, tunnel->peer_tunnel_id); -	NLA_PUT_U32(skb, L2TP_ATTR_DEBUG, tunnel->debug); -	NLA_PUT_U16(skb, L2TP_ATTR_ENCAP_TYPE, tunnel->encap); +	if (!hdr) +		return -EMSGSIZE; + +	if (nla_put_u8(skb, L2TP_ATTR_PROTO_VERSION, tunnel->version) || +	    nla_put_u32(skb, L2TP_ATTR_CONN_ID, tunnel->tunnel_id) || +	    nla_put_u32(skb, L2TP_ATTR_PEER_CONN_ID, tunnel->peer_tunnel_id) || +	    nla_put_u32(skb, L2TP_ATTR_DEBUG, tunnel->debug) || +	    nla_put_u16(skb, L2TP_ATTR_ENCAP_TYPE, tunnel->encap)) +		goto nla_put_failure;  	nest = nla_nest_start(skb, L2TP_ATTR_STATS);  	if (nest == NULL)  		goto nla_put_failure; -	NLA_PUT_U64(skb, L2TP_ATTR_TX_PACKETS, tunnel->stats.tx_packets); -	NLA_PUT_U64(skb, L2TP_ATTR_TX_BYTES, tunnel->stats.tx_bytes); -	NLA_PUT_U64(skb, L2TP_ATTR_TX_ERRORS, tunnel->stats.tx_errors); -	NLA_PUT_U64(skb, L2TP_ATTR_RX_PACKETS, tunnel->stats.rx_packets); -	NLA_PUT_U64(skb, L2TP_ATTR_RX_BYTES, tunnel->stats.rx_bytes); -	NLA_PUT_U64(skb, L2TP_ATTR_RX_SEQ_DISCARDS, tunnel->stats.rx_seq_discards); -	NLA_PUT_U64(skb, L2TP_ATTR_RX_OOS_PACKETS, tunnel->stats.rx_oos_packets); -	NLA_PUT_U64(skb, L2TP_ATTR_RX_ERRORS, tunnel->stats.rx_errors); +	if (nla_put_u64(skb, L2TP_ATTR_TX_PACKETS, +		    atomic_long_read(&tunnel->stats.tx_packets)) || +	    nla_put_u64(skb, L2TP_ATTR_TX_BYTES, +		    atomic_long_read(&tunnel->stats.tx_bytes)) || +	    nla_put_u64(skb, L2TP_ATTR_TX_ERRORS, +		    atomic_long_read(&tunnel->stats.tx_errors)) || +	    nla_put_u64(skb, L2TP_ATTR_RX_PACKETS, +		    atomic_long_read(&tunnel->stats.rx_packets)) || +	    nla_put_u64(skb, L2TP_ATTR_RX_BYTES, +		    atomic_long_read(&tunnel->stats.rx_bytes)) || +	    nla_put_u64(skb, L2TP_ATTR_RX_SEQ_DISCARDS, +		    atomic_long_read(&tunnel->stats.rx_seq_discards)) || +	    nla_put_u64(skb, L2TP_ATTR_RX_OOS_PACKETS, +		    atomic_long_read(&tunnel->stats.rx_oos_packets)) || +	    nla_put_u64(skb, L2TP_ATTR_RX_ERRORS, +		    atomic_long_read(&tunnel->stats.rx_errors))) +		goto nla_put_failure;  	nla_nest_end(skb, nest);  	sk = tunnel->sock;  	if (!sk)  		goto out; +#if IS_ENABLED(CONFIG_IPV6) +	if (sk->sk_family == AF_INET6) +		np = inet6_sk(sk); +#endif +  	inet = inet_sk(sk);  	switch (tunnel->encap) {  	case L2TP_ENCAPTYPE_UDP: -		NLA_PUT_U16(skb, L2TP_ATTR_UDP_SPORT, ntohs(inet->inet_sport)); -		NLA_PUT_U16(skb, L2TP_ATTR_UDP_DPORT, ntohs(inet->inet_dport)); -		NLA_PUT_U8(skb, L2TP_ATTR_UDP_CSUM, (sk->sk_no_check != UDP_CSUM_NOXMIT)); +		if (nla_put_u16(skb, L2TP_ATTR_UDP_SPORT, ntohs(inet->inet_sport)) || +		    nla_put_u16(skb, L2TP_ATTR_UDP_DPORT, ntohs(inet->inet_dport)) || +		    nla_put_u8(skb, L2TP_ATTR_UDP_CSUM, !sk->sk_no_check_tx)) +			goto nla_put_failure;  		/* NOBREAK */  	case L2TP_ENCAPTYPE_IP: -		NLA_PUT_BE32(skb, L2TP_ATTR_IP_SADDR, inet->inet_saddr); -		NLA_PUT_BE32(skb, L2TP_ATTR_IP_DADDR, inet->inet_daddr); +#if IS_ENABLED(CONFIG_IPV6) +		if (np) { +			if (nla_put(skb, L2TP_ATTR_IP6_SADDR, sizeof(np->saddr), +				    &np->saddr) || +			    nla_put(skb, L2TP_ATTR_IP6_DADDR, sizeof(sk->sk_v6_daddr), +				    &sk->sk_v6_daddr)) +				goto nla_put_failure; +		} else +#endif +		if (nla_put_be32(skb, L2TP_ATTR_IP_SADDR, inet->inet_saddr) || +		    nla_put_be32(skb, L2TP_ATTR_IP_DADDR, inet->inet_daddr)) +			goto nla_put_failure;  		break;  	} @@ -298,18 +352,18 @@ static int l2tp_nl_cmd_tunnel_get(struct sk_buff *skb, struct genl_info *info)  		goto out;  	} -	msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); +	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);  	if (!msg) {  		ret = -ENOMEM;  		goto out;  	} -	ret = l2tp_nl_tunnel_send(msg, info->snd_pid, info->snd_seq, +	ret = l2tp_nl_tunnel_send(msg, info->snd_portid, info->snd_seq,  				  NLM_F_ACK, tunnel);  	if (ret < 0)  		goto err_out; -	return genlmsg_unicast(net, msg, info->snd_pid); +	return genlmsg_unicast(net, msg, info->snd_portid);  err_out:  	nlmsg_free(msg); @@ -329,7 +383,7 @@ static int l2tp_nl_cmd_tunnel_dump(struct sk_buff *skb, struct netlink_callback  		if (tunnel == NULL)  			goto out; -		if (l2tp_nl_tunnel_send(skb, NETLINK_CB(cb->skb).pid, +		if (l2tp_nl_tunnel_send(skb, NETLINK_CB(cb->skb).portid,  					cb->nlh->nlmsg_seq, NLM_F_MULTI,  					tunnel) <= 0)  			goto out; @@ -530,8 +584,10 @@ static int l2tp_nl_cmd_session_modify(struct sk_buff *skb, struct genl_info *inf  	if (info->attrs[L2TP_ATTR_RECV_SEQ])  		session->recv_seq = nla_get_u8(info->attrs[L2TP_ATTR_RECV_SEQ]); -	if (info->attrs[L2TP_ATTR_SEND_SEQ]) +	if (info->attrs[L2TP_ATTR_SEND_SEQ]) {  		session->send_seq = nla_get_u8(info->attrs[L2TP_ATTR_SEND_SEQ]); +		l2tp_session_set_header_len(session, session->tunnel->version); +	}  	if (info->attrs[L2TP_ATTR_LNS_MODE])  		session->lns_mode = nla_get_u8(info->attrs[L2TP_ATTR_LNS_MODE]); @@ -549,7 +605,7 @@ out:  	return ret;  } -static int l2tp_nl_session_send(struct sk_buff *skb, u32 pid, u32 seq, int flags, +static int l2tp_nl_session_send(struct sk_buff *skb, u32 portid, u32 seq, int flags,  				struct l2tp_session *session)  {  	void *hdr; @@ -559,47 +615,62 @@ static int l2tp_nl_session_send(struct sk_buff *skb, u32 pid, u32 seq, int flags  	sk = tunnel->sock; -	hdr = genlmsg_put(skb, pid, seq, &l2tp_nl_family, flags, L2TP_CMD_SESSION_GET); -	if (IS_ERR(hdr)) -		return PTR_ERR(hdr); - -	NLA_PUT_U32(skb, L2TP_ATTR_CONN_ID, tunnel->tunnel_id); -	NLA_PUT_U32(skb, L2TP_ATTR_SESSION_ID, session->session_id); -	NLA_PUT_U32(skb, L2TP_ATTR_PEER_CONN_ID, tunnel->peer_tunnel_id); -	NLA_PUT_U32(skb, L2TP_ATTR_PEER_SESSION_ID, session->peer_session_id); -	NLA_PUT_U32(skb, L2TP_ATTR_DEBUG, session->debug); -	NLA_PUT_U16(skb, L2TP_ATTR_PW_TYPE, session->pwtype); -	NLA_PUT_U16(skb, L2TP_ATTR_MTU, session->mtu); -	if (session->mru) -		NLA_PUT_U16(skb, L2TP_ATTR_MRU, session->mru); - -	if (session->ifname && session->ifname[0]) -		NLA_PUT_STRING(skb, L2TP_ATTR_IFNAME, session->ifname); -	if (session->cookie_len) -		NLA_PUT(skb, L2TP_ATTR_COOKIE, session->cookie_len, &session->cookie[0]); -	if (session->peer_cookie_len) -		NLA_PUT(skb, L2TP_ATTR_PEER_COOKIE, session->peer_cookie_len, &session->peer_cookie[0]); -	NLA_PUT_U8(skb, L2TP_ATTR_RECV_SEQ, session->recv_seq); -	NLA_PUT_U8(skb, L2TP_ATTR_SEND_SEQ, session->send_seq); -	NLA_PUT_U8(skb, L2TP_ATTR_LNS_MODE, session->lns_mode); +	hdr = genlmsg_put(skb, portid, seq, &l2tp_nl_family, flags, L2TP_CMD_SESSION_GET); +	if (!hdr) +		return -EMSGSIZE; + +	if (nla_put_u32(skb, L2TP_ATTR_CONN_ID, tunnel->tunnel_id) || +	    nla_put_u32(skb, L2TP_ATTR_SESSION_ID, session->session_id) || +	    nla_put_u32(skb, L2TP_ATTR_PEER_CONN_ID, tunnel->peer_tunnel_id) || +	    nla_put_u32(skb, L2TP_ATTR_PEER_SESSION_ID, +			session->peer_session_id) || +	    nla_put_u32(skb, L2TP_ATTR_DEBUG, session->debug) || +	    nla_put_u16(skb, L2TP_ATTR_PW_TYPE, session->pwtype) || +	    nla_put_u16(skb, L2TP_ATTR_MTU, session->mtu) || +	    (session->mru && +	     nla_put_u16(skb, L2TP_ATTR_MRU, session->mru))) +		goto nla_put_failure; + +	if ((session->ifname[0] && +	     nla_put_string(skb, L2TP_ATTR_IFNAME, session->ifname)) || +	    (session->cookie_len && +	     nla_put(skb, L2TP_ATTR_COOKIE, session->cookie_len, +		     &session->cookie[0])) || +	    (session->peer_cookie_len && +	     nla_put(skb, L2TP_ATTR_PEER_COOKIE, session->peer_cookie_len, +		     &session->peer_cookie[0])) || +	    nla_put_u8(skb, L2TP_ATTR_RECV_SEQ, session->recv_seq) || +	    nla_put_u8(skb, L2TP_ATTR_SEND_SEQ, session->send_seq) || +	    nla_put_u8(skb, L2TP_ATTR_LNS_MODE, session->lns_mode) ||  #ifdef CONFIG_XFRM -	if ((sk) && (sk->sk_policy[0] || sk->sk_policy[1])) -		NLA_PUT_U8(skb, L2TP_ATTR_USING_IPSEC, 1); +	    (((sk) && (sk->sk_policy[0] || sk->sk_policy[1])) && +	     nla_put_u8(skb, L2TP_ATTR_USING_IPSEC, 1)) ||  #endif -	if (session->reorder_timeout) -		NLA_PUT_MSECS(skb, L2TP_ATTR_RECV_TIMEOUT, session->reorder_timeout); +	    (session->reorder_timeout && +	     nla_put_msecs(skb, L2TP_ATTR_RECV_TIMEOUT, session->reorder_timeout))) +		goto nla_put_failure;  	nest = nla_nest_start(skb, L2TP_ATTR_STATS);  	if (nest == NULL)  		goto nla_put_failure; -	NLA_PUT_U64(skb, L2TP_ATTR_TX_PACKETS, session->stats.tx_packets); -	NLA_PUT_U64(skb, L2TP_ATTR_TX_BYTES, session->stats.tx_bytes); -	NLA_PUT_U64(skb, L2TP_ATTR_TX_ERRORS, session->stats.tx_errors); -	NLA_PUT_U64(skb, L2TP_ATTR_RX_PACKETS, session->stats.rx_packets); -	NLA_PUT_U64(skb, L2TP_ATTR_RX_BYTES, session->stats.rx_bytes); -	NLA_PUT_U64(skb, L2TP_ATTR_RX_SEQ_DISCARDS, session->stats.rx_seq_discards); -	NLA_PUT_U64(skb, L2TP_ATTR_RX_OOS_PACKETS, session->stats.rx_oos_packets); -	NLA_PUT_U64(skb, L2TP_ATTR_RX_ERRORS, session->stats.rx_errors); + +	if (nla_put_u64(skb, L2TP_ATTR_TX_PACKETS, +		atomic_long_read(&session->stats.tx_packets)) || +	    nla_put_u64(skb, L2TP_ATTR_TX_BYTES, +		atomic_long_read(&session->stats.tx_bytes)) || +	    nla_put_u64(skb, L2TP_ATTR_TX_ERRORS, +		atomic_long_read(&session->stats.tx_errors)) || +	    nla_put_u64(skb, L2TP_ATTR_RX_PACKETS, +		atomic_long_read(&session->stats.rx_packets)) || +	    nla_put_u64(skb, L2TP_ATTR_RX_BYTES, +		atomic_long_read(&session->stats.rx_bytes)) || +	    nla_put_u64(skb, L2TP_ATTR_RX_SEQ_DISCARDS, +		atomic_long_read(&session->stats.rx_seq_discards)) || +	    nla_put_u64(skb, L2TP_ATTR_RX_OOS_PACKETS, +		atomic_long_read(&session->stats.rx_oos_packets)) || +	    nla_put_u64(skb, L2TP_ATTR_RX_ERRORS, +		atomic_long_read(&session->stats.rx_errors))) +		goto nla_put_failure;  	nla_nest_end(skb, nest);  	return genlmsg_end(skb, hdr); @@ -621,18 +692,18 @@ static int l2tp_nl_cmd_session_get(struct sk_buff *skb, struct genl_info *info)  		goto out;  	} -	msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); +	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);  	if (!msg) {  		ret = -ENOMEM;  		goto out;  	} -	ret = l2tp_nl_session_send(msg, info->snd_pid, info->snd_seq, +	ret = l2tp_nl_session_send(msg, info->snd_portid, info->snd_seq,  				   0, session);  	if (ret < 0)  		goto err_out; -	return genlmsg_unicast(genl_info_net(info), msg, info->snd_pid); +	return genlmsg_unicast(genl_info_net(info), msg, info->snd_portid);  err_out:  	nlmsg_free(msg); @@ -664,7 +735,7 @@ static int l2tp_nl_cmd_session_dump(struct sk_buff *skb, struct netlink_callback  			continue;  		} -		if (l2tp_nl_session_send(skb, NETLINK_CB(cb->skb).pid, +		if (l2tp_nl_session_send(skb, NETLINK_CB(cb->skb).portid,  					 cb->nlh->nlmsg_seq, NLM_F_MULTI,  					 session) <= 0)  			break; @@ -708,6 +779,14 @@ static struct nla_policy l2tp_nl_policy[L2TP_ATTR_MAX + 1] = {  	[L2TP_ATTR_MTU]			= { .type = NLA_U16, },  	[L2TP_ATTR_MRU]			= { .type = NLA_U16, },  	[L2TP_ATTR_STATS]		= { .type = NLA_NESTED, }, +	[L2TP_ATTR_IP6_SADDR] = { +		.type = NLA_BINARY, +		.len = sizeof(struct in6_addr), +	}, +	[L2TP_ATTR_IP6_DADDR] = { +		.type = NLA_BINARY, +		.len = sizeof(struct in6_addr), +	},  	[L2TP_ATTR_IFNAME] = {  		.type = NLA_NUL_STRING,  		.len = IFNAMSIZ - 1, @@ -722,7 +801,7 @@ static struct nla_policy l2tp_nl_policy[L2TP_ATTR_MAX + 1] = {  	},  }; -static struct genl_ops l2tp_nl_ops[] = { +static const struct genl_ops l2tp_nl_ops[] = {  	{  		.cmd = L2TP_CMD_NOOP,  		.doit = l2tp_nl_cmd_noop, @@ -795,11 +874,12 @@ int l2tp_nl_register_ops(enum l2tp_pwtype pw_type, const struct l2tp_nl_cmd_ops  		goto out;  	l2tp_nl_cmd_ops[pw_type] = ops; +	ret = 0;  out:  	genl_unlock();  err: -	return 0; +	return ret;  }  EXPORT_SYMBOL_GPL(l2tp_nl_register_ops); @@ -815,13 +895,8 @@ EXPORT_SYMBOL_GPL(l2tp_nl_unregister_ops);  static int l2tp_nl_init(void)  { -	int err; - -	printk(KERN_INFO "L2TP netlink interface\n"); -	err = genl_register_family_with_ops(&l2tp_nl_family, l2tp_nl_ops, -					    ARRAY_SIZE(l2tp_nl_ops)); - -	return err; +	pr_info("L2TP netlink interface\n"); +	return genl_register_family_with_ops(&l2tp_nl_family, l2tp_nl_ops);  }  static void l2tp_nl_cleanup(void) @@ -836,5 +911,4 @@ MODULE_AUTHOR("James Chapman <jchapman@katalix.com>");  MODULE_DESCRIPTION("L2TP netlink");  MODULE_LICENSE("GPL");  MODULE_VERSION("1.0"); -MODULE_ALIAS("net-pf-" __stringify(PF_NETLINK) "-proto-" \ -	     __stringify(NETLINK_GENERIC) "-type-" "l2tp"); +MODULE_ALIAS_GENL_FAMILY("l2tp"); diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c index 39a21d0c61c..13752d96275 100644 --- a/net/l2tp/l2tp_ppp.c +++ b/net/l2tp/l2tp_ppp.c @@ -57,6 +57,8 @@   * http://openl2tp.sourceforge.net.   */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +  #include <linux/module.h>  #include <linux/string.h>  #include <linux/list.h> @@ -82,7 +84,7 @@  #include <net/sock.h>  #include <linux/ppp_channel.h>  #include <linux/ppp_defs.h> -#include <linux/if_ppp.h> +#include <linux/ppp-ioctl.h>  #include <linux/file.h>  #include <linux/hash.h>  #include <linux/sort.h> @@ -95,9 +97,10 @@  #include <net/ip.h>  #include <net/udp.h>  #include <net/xfrm.h> +#include <net/inet_common.h>  #include <asm/byteorder.h> -#include <asm/atomic.h> +#include <linux/atomic.h>  #include "l2tp_core.h" @@ -106,12 +109,6 @@  /* Space for UDP, L2TP and PPP headers */  #define PPPOL2TP_HEADER_OVERHEAD	40 -#define PRINTK(_mask, _type, _lvl, _fmt, args...)			\ -	do {								\ -		if ((_mask) & (_type))					\ -			printk(_lvl "PPPOL2TP: " _fmt, ##args);		\ -	} while (0) -  /* Number of bytes to build transmit L2TP headers.   * Unfortunately the size is different depending on whether sequence numbers   * are enabled. @@ -200,8 +197,6 @@ static int pppol2tp_recvmsg(struct kiocb *iocb, struct socket *sock,  	if (sk->sk_state & PPPOX_BOUND)  		goto end; -	msg->msg_namelen = 0; -  	err = 0;  	skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,  				flags & MSG_DONTWAIT, &err); @@ -236,9 +231,9 @@ static void pppol2tp_recv(struct l2tp_session *session, struct sk_buff *skb, int  	if (sk->sk_state & PPPOX_BOUND) {  		struct pppox_sock *po; -		PRINTK(session->debug, PPPOL2TP_MSG_DATA, KERN_DEBUG, -		       "%s: recv %d byte data frame, passing to ppp\n", -		       session->name, data_len); +		l2tp_dbg(session, PPPOL2TP_MSG_DATA, +			 "%s: recv %d byte data frame, passing to ppp\n", +			 session->name, data_len);  		/* We need to forget all info related to the L2TP packet  		 * gathered in the skb as we are going to reuse the same @@ -259,19 +254,20 @@ static void pppol2tp_recv(struct l2tp_session *session, struct sk_buff *skb, int  		po = pppox_sk(sk);  		ppp_input(&po->chan, skb);  	} else { -		PRINTK(session->debug, PPPOL2TP_MSG_DATA, KERN_INFO, -		       "%s: socket not bound\n", session->name); +		l2tp_dbg(session, PPPOL2TP_MSG_DATA, +			 "%s: recv %d byte data frame, passing to L2TP socket\n", +			 session->name, data_len); -		/* Not bound. Nothing we can do, so discard. */ -		session->stats.rx_errors++; -		kfree_skb(skb); +		if (sock_queue_rcv_skb(sk, skb) < 0) { +			atomic_long_inc(&session->stats.rx_errors); +			kfree_skb(skb); +		}  	}  	return;  no_sock: -	PRINTK(session->debug, PPPOL2TP_MSG_DATA, KERN_INFO, -	       "%s: no socket\n", session->name); +	l2tp_info(session, PPPOL2TP_MSG_DATA, "%s: no socket\n", session->name);  	kfree_skb(skb);  } @@ -350,18 +346,21 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh  	skb_put(skb, 2);  	/* Copy user data into skb */ -	error = memcpy_fromiovec(skb->data, m->msg_iov, total_len); +	error = memcpy_fromiovec(skb_put(skb, total_len), m->msg_iov, +				 total_len);  	if (error < 0) {  		kfree_skb(skb);  		goto error_put_sess_tun;  	} -	skb_put(skb, total_len); +	local_bh_disable();  	l2tp_xmit_skb(session, skb, session->hdr_len); +	local_bh_enable();  	sock_put(ps->tunnel_sock); +	sock_put(sk); -	return error; +	return total_len;  error_put_sess_tun:  	sock_put(ps->tunnel_sock); @@ -393,8 +392,7 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)  	struct l2tp_session *session;  	struct l2tp_tunnel *tunnel;  	struct pppol2tp_session *ps; -	int old_headroom; -	int new_headroom; +	int uhlen, headroom;  	if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED))  		goto abort; @@ -412,19 +410,23 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)  	if (tunnel == NULL)  		goto abort_put_sess; -	old_headroom = skb_headroom(skb); -	if (skb_cow_head(skb, sizeof(ppph))) +	uhlen = (tunnel->encap == L2TP_ENCAPTYPE_UDP) ? sizeof(struct udphdr) : 0; +	headroom = NET_SKB_PAD + +		   sizeof(struct iphdr) + /* IP header */ +		   uhlen +		/* UDP header (if L2TP_ENCAPTYPE_UDP) */ +		   session->hdr_len +	/* L2TP header */ +		   sizeof(ppph);	/* PPP header */ +	if (skb_cow_head(skb, headroom))  		goto abort_put_sess_tun; -	new_headroom = skb_headroom(skb); -	skb->truesize += new_headroom - old_headroom; -  	/* Setup PPP header */  	__skb_push(skb, sizeof(ppph));  	skb->data[0] = ppph[0];  	skb->data[1] = ppph[1]; +	local_bh_disable();  	l2tp_xmit_skb(session, skb, session->hdr_len); +	local_bh_enable();  	sock_put(sk_tun);  	sock_put(sk); @@ -450,35 +452,15 @@ static void pppol2tp_session_close(struct l2tp_session *session)  {  	struct pppol2tp_session *ps = l2tp_session_priv(session);  	struct sock *sk = ps->sock; -	struct sk_buff *skb; +	struct socket *sock = sk->sk_socket;  	BUG_ON(session->magic != L2TP_SESSION_MAGIC); -	if (session->session_id == 0) -		goto out; - -	if (sk != NULL) { -		lock_sock(sk); - -		if (sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND)) { -			pppox_unbind_sock(sk); -			sk->sk_state = PPPOX_DEAD; -			sk->sk_state_change(sk); -		} - -		/* Purge any queued data */ -		skb_queue_purge(&sk->sk_receive_queue); -		skb_queue_purge(&sk->sk_write_queue); -		while ((skb = skb_dequeue(&session->reorder_q))) { -			kfree_skb(skb); -			sock_put(sk); -		} - -		release_sock(sk); +	if (sock) { +		inet_shutdown(sock, 2); +		/* Don't let the session go away before our socket does */ +		l2tp_session_inc_refcount(session);  	} - -out: -	return;  }  /* Really kill the session socket. (Called from sock_put() if @@ -486,20 +468,12 @@ out:   */  static void pppol2tp_session_destruct(struct sock *sk)  { -	struct l2tp_session *session; - -	if (sk->sk_user_data != NULL) { -		session = sk->sk_user_data; -		if (session == NULL) -			goto out; - +	struct l2tp_session *session = sk->sk_user_data; +	if (session) {  		sk->sk_user_data = NULL;  		BUG_ON(session->magic != L2TP_SESSION_MAGIC);  		l2tp_session_dec_refcount(session);  	} - -out: -	return;  }  /* Called when the PPPoX socket (session) is closed. @@ -528,16 +502,13 @@ static int pppol2tp_release(struct socket *sock)  	session = pppol2tp_sock_to_session(sk);  	/* Purge any queued data */ -	skb_queue_purge(&sk->sk_receive_queue); -	skb_queue_purge(&sk->sk_write_queue);  	if (session != NULL) { -		struct sk_buff *skb; -		while ((skb = skb_dequeue(&session->reorder_q))) { -			kfree_skb(skb); -			sock_put(sk); -		} +		__l2tp_session_unhash(session); +		l2tp_session_queue_purge(session);  		sock_put(sk);  	} +	skb_queue_purge(&sk->sk_receive_queue); +	skb_queue_purge(&sk->sk_write_queue);  	release_sock(sk); @@ -621,7 +592,6 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,  {  	struct sock *sk = sock->sk;  	struct sockaddr_pppol2tp *sp = (struct sockaddr_pppol2tp *) uservaddr; -	struct sockaddr_pppol2tpv3 *sp3 = (struct sockaddr_pppol2tpv3 *) uservaddr;  	struct pppox_sock *po = pppox_sk(sk);  	struct l2tp_session *session = NULL;  	struct l2tp_tunnel *tunnel; @@ -650,7 +620,13 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,  	if (sk->sk_user_data)  		goto end; /* socket is already attached */ -	/* Get params from socket address. Handle L2TPv2 and L2TPv3 */ +	/* Get params from socket address. Handle L2TPv2 and L2TPv3. +	 * This is nasty because there are different sockaddr_pppol2tp +	 * structs for L2TPv2, L2TPv3, over IPv4 and IPv6. We use +	 * the sockaddr size to determine which structure the caller +	 * is using. +	 */ +	peer_tunnel_id = 0;  	if (sockaddr_len == sizeof(struct sockaddr_pppol2tp)) {  		fd = sp->pppol2tp.fd;  		tunnel_id = sp->pppol2tp.s_tunnel; @@ -658,12 +634,31 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,  		session_id = sp->pppol2tp.s_session;  		peer_session_id = sp->pppol2tp.d_session;  	} else if (sockaddr_len == sizeof(struct sockaddr_pppol2tpv3)) { +		struct sockaddr_pppol2tpv3 *sp3 = +			(struct sockaddr_pppol2tpv3 *) sp;  		ver = 3;  		fd = sp3->pppol2tp.fd;  		tunnel_id = sp3->pppol2tp.s_tunnel;  		peer_tunnel_id = sp3->pppol2tp.d_tunnel;  		session_id = sp3->pppol2tp.s_session;  		peer_session_id = sp3->pppol2tp.d_session; +	} else if (sockaddr_len == sizeof(struct sockaddr_pppol2tpin6)) { +		struct sockaddr_pppol2tpin6 *sp6 = +			(struct sockaddr_pppol2tpin6 *) sp; +		fd = sp6->pppol2tp.fd; +		tunnel_id = sp6->pppol2tp.s_tunnel; +		peer_tunnel_id = sp6->pppol2tp.d_tunnel; +		session_id = sp6->pppol2tp.s_session; +		peer_session_id = sp6->pppol2tp.d_session; +	} else if (sockaddr_len == sizeof(struct sockaddr_pppol2tpv3in6)) { +		struct sockaddr_pppol2tpv3in6 *sp6 = +			(struct sockaddr_pppol2tpv3in6 *) sp; +		ver = 3; +		fd = sp6->pppol2tp.fd; +		tunnel_id = sp6->pppol2tp.s_tunnel; +		peer_tunnel_id = sp6->pppol2tp.d_tunnel; +		session_id = sp6->pppol2tp.s_session; +		peer_session_id = sp6->pppol2tp.d_session;  	} else {  		error = -EINVAL;  		goto end; /* bad socket address */ @@ -704,12 +699,8 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,  	if (tunnel->recv_payload_hook == NULL)  		tunnel->recv_payload_hook = pppol2tp_recv_payload_hook; -	if (tunnel->peer_tunnel_id == 0) { -		if (ver == 2) -			tunnel->peer_tunnel_id = sp->pppol2tp.d_tunnel; -		else -			tunnel->peer_tunnel_id = sp3->pppol2tp.d_tunnel; -	} +	if (tunnel->peer_tunnel_id == 0) +		tunnel->peer_tunnel_id = peer_tunnel_id;  	/* Create session if it doesn't already exist. We handle the  	 * case where a session was previously created by the netlink @@ -762,9 +753,9 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,  	session->deref = pppol2tp_session_sock_put;  	/* If PMTU discovery was enabled, use the MTU that was discovered */ -	dst = sk_dst_get(sk); +	dst = sk_dst_get(tunnel->sock);  	if (dst != NULL) { -		u32 pmtu = dst_mtu(__sk_dst_get(sk)); +		u32 pmtu = dst_mtu(__sk_dst_get(tunnel->sock));  		if (pmtu != 0)  			session->mtu = session->mru = pmtu -  				PPPOL2TP_HEADER_OVERHEAD; @@ -800,8 +791,8 @@ out_no_ppp:  	/* This is how we get the session context from the socket. */  	sk->sk_user_data = session;  	sk->sk_state = PPPOX_CONNECTED; -	PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, -	       "%s: created\n", session->name); +	l2tp_info(session, PPPOL2TP_MSG_CONTROL, "%s: created\n", +		  session->name);  end:  	release_sock(sk); @@ -854,8 +845,8 @@ static int pppol2tp_session_create(struct net *net, u32 tunnel_id, u32 session_i  	ps = l2tp_session_priv(session);  	ps->tunnel_sock = tunnel->sock; -	PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, -	       "%s: created\n", session->name); +	l2tp_info(session, PPPOL2TP_MSG_CONTROL, "%s: created\n", +		  session->name);  	error = 0; @@ -863,18 +854,6 @@ out:  	return error;  } -/* Called when deleting sessions via the netlink interface. - */ -static int pppol2tp_session_delete(struct l2tp_session *session) -{ -	struct pppol2tp_session *ps = l2tp_session_priv(session); - -	if (ps->sock == NULL) -		l2tp_session_dec_refcount(session); - -	return 0; -} -  #endif /* CONFIG_L2TP_V3 */  /* getname() support. @@ -908,8 +887,8 @@ static int pppol2tp_getname(struct socket *sock, struct sockaddr *uaddr,  		goto end_put_sess;  	} -	inet = inet_sk(sk); -	if (tunnel->version == 2) { +	inet = inet_sk(tunnel->sock); +	if ((tunnel->version == 2) && (tunnel->sock->sk_family == AF_INET)) {  		struct sockaddr_pppol2tp sp;  		len = sizeof(sp);  		memset(&sp, 0, len); @@ -925,6 +904,46 @@ static int pppol2tp_getname(struct socket *sock, struct sockaddr *uaddr,  		sp.pppol2tp.addr.sin_port = inet->inet_dport;  		sp.pppol2tp.addr.sin_addr.s_addr = inet->inet_daddr;  		memcpy(uaddr, &sp, len); +#if IS_ENABLED(CONFIG_IPV6) +	} else if ((tunnel->version == 2) && +		   (tunnel->sock->sk_family == AF_INET6)) { +		struct sockaddr_pppol2tpin6 sp; + +		len = sizeof(sp); +		memset(&sp, 0, len); +		sp.sa_family	= AF_PPPOX; +		sp.sa_protocol	= PX_PROTO_OL2TP; +		sp.pppol2tp.fd  = tunnel->fd; +		sp.pppol2tp.pid = pls->owner; +		sp.pppol2tp.s_tunnel = tunnel->tunnel_id; +		sp.pppol2tp.d_tunnel = tunnel->peer_tunnel_id; +		sp.pppol2tp.s_session = session->session_id; +		sp.pppol2tp.d_session = session->peer_session_id; +		sp.pppol2tp.addr.sin6_family = AF_INET6; +		sp.pppol2tp.addr.sin6_port = inet->inet_dport; +		memcpy(&sp.pppol2tp.addr.sin6_addr, &tunnel->sock->sk_v6_daddr, +		       sizeof(tunnel->sock->sk_v6_daddr)); +		memcpy(uaddr, &sp, len); +	} else if ((tunnel->version == 3) && +		   (tunnel->sock->sk_family == AF_INET6)) { +		struct sockaddr_pppol2tpv3in6 sp; + +		len = sizeof(sp); +		memset(&sp, 0, len); +		sp.sa_family	= AF_PPPOX; +		sp.sa_protocol	= PX_PROTO_OL2TP; +		sp.pppol2tp.fd  = tunnel->fd; +		sp.pppol2tp.pid = pls->owner; +		sp.pppol2tp.s_tunnel = tunnel->tunnel_id; +		sp.pppol2tp.d_tunnel = tunnel->peer_tunnel_id; +		sp.pppol2tp.s_session = session->session_id; +		sp.pppol2tp.d_session = session->peer_session_id; +		sp.pppol2tp.addr.sin6_family = AF_INET6; +		sp.pppol2tp.addr.sin6_port = inet->inet_dport; +		memcpy(&sp.pppol2tp.addr.sin6_addr, &tunnel->sock->sk_v6_daddr, +		       sizeof(tunnel->sock->sk_v6_daddr)); +		memcpy(uaddr, &sp, len); +#endif  	} else if (tunnel->version == 3) {  		struct sockaddr_pppol2tpv3 sp;  		len = sizeof(sp); @@ -968,14 +987,14 @@ end:  static void pppol2tp_copy_stats(struct pppol2tp_ioc_stats *dest,  				struct l2tp_stats *stats)  { -	dest->tx_packets = stats->tx_packets; -	dest->tx_bytes = stats->tx_bytes; -	dest->tx_errors = stats->tx_errors; -	dest->rx_packets = stats->rx_packets; -	dest->rx_bytes = stats->rx_bytes; -	dest->rx_seq_discards = stats->rx_seq_discards; -	dest->rx_oos_packets = stats->rx_oos_packets; -	dest->rx_errors = stats->rx_errors; +	dest->tx_packets = atomic_long_read(&stats->tx_packets); +	dest->tx_bytes = atomic_long_read(&stats->tx_bytes); +	dest->tx_errors = atomic_long_read(&stats->tx_errors); +	dest->rx_packets = atomic_long_read(&stats->rx_packets); +	dest->rx_bytes = atomic_long_read(&stats->rx_bytes); +	dest->rx_seq_discards = atomic_long_read(&stats->rx_seq_discards); +	dest->rx_oos_packets = atomic_long_read(&stats->rx_oos_packets); +	dest->rx_errors = atomic_long_read(&stats->rx_errors);  }  /* Session ioctl helper. @@ -991,9 +1010,9 @@ static int pppol2tp_session_ioctl(struct l2tp_session *session,  	struct l2tp_tunnel *tunnel = session->tunnel;  	struct pppol2tp_ioc_stats stats; -	PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_DEBUG, -	       "%s: pppol2tp_session_ioctl(cmd=%#x, arg=%#lx)\n", -	       session->name, cmd, arg); +	l2tp_dbg(session, PPPOL2TP_MSG_CONTROL, +		 "%s: pppol2tp_session_ioctl(cmd=%#x, arg=%#lx)\n", +		 session->name, cmd, arg);  	sk = ps->sock;  	sock_hold(sk); @@ -1011,8 +1030,8 @@ static int pppol2tp_session_ioctl(struct l2tp_session *session,  		if (copy_to_user((void __user *) arg, &ifr, sizeof(struct ifreq)))  			break; -		PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, -		       "%s: get mtu=%d\n", session->name, session->mtu); +		l2tp_info(session, PPPOL2TP_MSG_CONTROL, "%s: get mtu=%d\n", +			  session->name, session->mtu);  		err = 0;  		break; @@ -1027,8 +1046,8 @@ static int pppol2tp_session_ioctl(struct l2tp_session *session,  		session->mtu = ifr.ifr_mtu; -		PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, -		       "%s: set mtu=%d\n", session->name, session->mtu); +		l2tp_info(session, PPPOL2TP_MSG_CONTROL, "%s: set mtu=%d\n", +			  session->name, session->mtu);  		err = 0;  		break; @@ -1041,8 +1060,8 @@ static int pppol2tp_session_ioctl(struct l2tp_session *session,  		if (put_user(session->mru, (int __user *) arg))  			break; -		PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, -		       "%s: get mru=%d\n", session->name, session->mru); +		l2tp_info(session, PPPOL2TP_MSG_CONTROL, "%s: get mru=%d\n", +			  session->name, session->mru);  		err = 0;  		break; @@ -1056,8 +1075,8 @@ static int pppol2tp_session_ioctl(struct l2tp_session *session,  			break;  		session->mru = val; -		PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, -		       "%s: set mru=%d\n", session->name, session->mru); +		l2tp_info(session, PPPOL2TP_MSG_CONTROL, "%s: set mru=%d\n", +			  session->name, session->mru);  		err = 0;  		break; @@ -1066,8 +1085,8 @@ static int pppol2tp_session_ioctl(struct l2tp_session *session,  		if (put_user(ps->flags, (int __user *) arg))  			break; -		PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, -		       "%s: get flags=%d\n", session->name, ps->flags); +		l2tp_info(session, PPPOL2TP_MSG_CONTROL, "%s: get flags=%d\n", +			  session->name, ps->flags);  		err = 0;  		break; @@ -1076,8 +1095,8 @@ static int pppol2tp_session_ioctl(struct l2tp_session *session,  		if (get_user(val, (int __user *) arg))  			break;  		ps->flags = val; -		PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, -		       "%s: set flags=%d\n", session->name, ps->flags); +		l2tp_info(session, PPPOL2TP_MSG_CONTROL, "%s: set flags=%d\n", +			  session->name, ps->flags);  		err = 0;  		break; @@ -1093,8 +1112,8 @@ static int pppol2tp_session_ioctl(struct l2tp_session *session,  		if (copy_to_user((void __user *) arg, &stats,  				 sizeof(stats)))  			break; -		PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, -		       "%s: get L2TP stats\n", session->name); +		l2tp_info(session, PPPOL2TP_MSG_CONTROL, "%s: get L2TP stats\n", +			  session->name);  		err = 0;  		break; @@ -1121,9 +1140,9 @@ static int pppol2tp_tunnel_ioctl(struct l2tp_tunnel *tunnel,  	struct sock *sk;  	struct pppol2tp_ioc_stats stats; -	PRINTK(tunnel->debug, PPPOL2TP_MSG_CONTROL, KERN_DEBUG, -	       "%s: pppol2tp_tunnel_ioctl(cmd=%#x, arg=%#lx)\n", -	       tunnel->name, cmd, arg); +	l2tp_dbg(tunnel, PPPOL2TP_MSG_CONTROL, +		 "%s: pppol2tp_tunnel_ioctl(cmd=%#x, arg=%#lx)\n", +		 tunnel->name, cmd, arg);  	sk = tunnel->sock;  	sock_hold(sk); @@ -1157,8 +1176,8 @@ static int pppol2tp_tunnel_ioctl(struct l2tp_tunnel *tunnel,  			err = -EFAULT;  			break;  		} -		PRINTK(tunnel->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, -		       "%s: get L2TP stats\n", tunnel->name); +		l2tp_info(tunnel, PPPOL2TP_MSG_CONTROL, "%s: get L2TP stats\n", +			  tunnel->name);  		err = 0;  		break; @@ -1247,8 +1266,8 @@ static int pppol2tp_tunnel_setsockopt(struct sock *sk,  	switch (optname) {  	case PPPOL2TP_SO_DEBUG:  		tunnel->debug = val; -		PRINTK(tunnel->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, -		       "%s: set debug=%x\n", tunnel->name, tunnel->debug); +		l2tp_info(tunnel, PPPOL2TP_MSG_CONTROL, "%s: set debug=%x\n", +			  tunnel->name, tunnel->debug);  		break;  	default: @@ -1275,8 +1294,9 @@ static int pppol2tp_session_setsockopt(struct sock *sk,  			break;  		}  		session->recv_seq = val ? -1 : 0; -		PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, -		       "%s: set recv_seq=%d\n", session->name, session->recv_seq); +		l2tp_info(session, PPPOL2TP_MSG_CONTROL, +			  "%s: set recv_seq=%d\n", +			  session->name, session->recv_seq);  		break;  	case PPPOL2TP_SO_SENDSEQ: @@ -1291,8 +1311,10 @@ static int pppol2tp_session_setsockopt(struct sock *sk,  			po->chan.hdrlen = val ? PPPOL2TP_L2TP_HDR_SIZE_SEQ :  				PPPOL2TP_L2TP_HDR_SIZE_NOSEQ;  		} -		PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, -		       "%s: set send_seq=%d\n", session->name, session->send_seq); +		l2tp_session_set_header_len(session, session->tunnel->version); +		l2tp_info(session, PPPOL2TP_MSG_CONTROL, +			  "%s: set send_seq=%d\n", +			  session->name, session->send_seq);  		break;  	case PPPOL2TP_SO_LNSMODE: @@ -1301,20 +1323,22 @@ static int pppol2tp_session_setsockopt(struct sock *sk,  			break;  		}  		session->lns_mode = val ? -1 : 0; -		PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, -		       "%s: set lns_mode=%d\n", session->name, session->lns_mode); +		l2tp_info(session, PPPOL2TP_MSG_CONTROL, +			  "%s: set lns_mode=%d\n", +			  session->name, session->lns_mode);  		break;  	case PPPOL2TP_SO_DEBUG:  		session->debug = val; -		PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, -		       "%s: set debug=%x\n", session->name, session->debug); +		l2tp_info(session, PPPOL2TP_MSG_CONTROL, "%s: set debug=%x\n", +			  session->name, session->debug);  		break;  	case PPPOL2TP_SO_REORDERTO:  		session->reorder_timeout = msecs_to_jiffies(val); -		PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, -		       "%s: set reorder_timeout=%d\n", session->name, session->reorder_timeout); +		l2tp_info(session, PPPOL2TP_MSG_CONTROL, +			  "%s: set reorder_timeout=%d\n", +			  session->name, session->reorder_timeout);  		break;  	default: @@ -1341,7 +1365,7 @@ static int pppol2tp_setsockopt(struct socket *sock, int level, int optname,  	int err;  	if (level != SOL_PPPOL2TP) -		return udp_prot.setsockopt(sk, level, optname, optval, optlen); +		return -EINVAL;  	if (optlen < sizeof(int))  		return -EINVAL; @@ -1393,8 +1417,8 @@ static int pppol2tp_tunnel_getsockopt(struct sock *sk,  	switch (optname) {  	case PPPOL2TP_SO_DEBUG:  		*val = tunnel->debug; -		PRINTK(tunnel->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, -		       "%s: get debug=%x\n", tunnel->name, tunnel->debug); +		l2tp_info(tunnel, PPPOL2TP_MSG_CONTROL, "%s: get debug=%x\n", +			  tunnel->name, tunnel->debug);  		break;  	default: @@ -1416,32 +1440,32 @@ static int pppol2tp_session_getsockopt(struct sock *sk,  	switch (optname) {  	case PPPOL2TP_SO_RECVSEQ:  		*val = session->recv_seq; -		PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, -		       "%s: get recv_seq=%d\n", session->name, *val); +		l2tp_info(session, PPPOL2TP_MSG_CONTROL, +			  "%s: get recv_seq=%d\n", session->name, *val);  		break;  	case PPPOL2TP_SO_SENDSEQ:  		*val = session->send_seq; -		PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, -		       "%s: get send_seq=%d\n", session->name, *val); +		l2tp_info(session, PPPOL2TP_MSG_CONTROL, +			  "%s: get send_seq=%d\n", session->name, *val);  		break;  	case PPPOL2TP_SO_LNSMODE:  		*val = session->lns_mode; -		PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, -		       "%s: get lns_mode=%d\n", session->name, *val); +		l2tp_info(session, PPPOL2TP_MSG_CONTROL, +			  "%s: get lns_mode=%d\n", session->name, *val);  		break;  	case PPPOL2TP_SO_DEBUG:  		*val = session->debug; -		PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, -		       "%s: get debug=%d\n", session->name, *val); +		l2tp_info(session, PPPOL2TP_MSG_CONTROL, "%s: get debug=%d\n", +			  session->name, *val);  		break;  	case PPPOL2TP_SO_REORDERTO:  		*val = (int) jiffies_to_msecs(session->reorder_timeout); -		PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, -		       "%s: get reorder_timeout=%d\n", session->name, *val); +		l2tp_info(session, PPPOL2TP_MSG_CONTROL, +			  "%s: get reorder_timeout=%d\n", session->name, *val);  		break;  	default: @@ -1456,8 +1480,8 @@ static int pppol2tp_session_getsockopt(struct sock *sk,   * handler, according to whether the PPPoX socket is a for a regular session   * or the special tunnel type.   */ -static int pppol2tp_getsockopt(struct socket *sock, int level, -			       int optname, char __user *optval, int __user *optlen) +static int pppol2tp_getsockopt(struct socket *sock, int level, int optname, +			       char __user *optval, int __user *optlen)  {  	struct sock *sk = sock->sk;  	struct l2tp_session *session; @@ -1467,9 +1491,9 @@ static int pppol2tp_getsockopt(struct socket *sock, int level,  	struct pppol2tp_session *ps;  	if (level != SOL_PPPOL2TP) -		return udp_prot.getsockopt(sk, level, optname, optval, optlen); +		return -EINVAL; -	if (get_user(len, (int __user *) optlen)) +	if (get_user(len, optlen))  		return -EFAULT;  	len = min_t(unsigned int, len, sizeof(int)); @@ -1502,7 +1526,7 @@ static int pppol2tp_getsockopt(struct socket *sock, int level,  		err = pppol2tp_session_getsockopt(sk, session, optname, &val);  	err = -EFAULT; -	if (put_user(len, (int __user *) optlen)) +	if (put_user(len, optlen))  		goto end_put_sess;  	if (copy_to_user((void __user *) optval, &val, len)) @@ -1605,14 +1629,14 @@ static void pppol2tp_seq_tunnel_show(struct seq_file *m, void *v)  		   tunnel->name,  		   (tunnel == tunnel->sock->sk_user_data) ? 'Y' : 'N',  		   atomic_read(&tunnel->ref_count) - 1); -	seq_printf(m, " %08x %llu/%llu/%llu %llu/%llu/%llu\n", +	seq_printf(m, " %08x %ld/%ld/%ld %ld/%ld/%ld\n",  		   tunnel->debug, -		   (unsigned long long)tunnel->stats.tx_packets, -		   (unsigned long long)tunnel->stats.tx_bytes, -		   (unsigned long long)tunnel->stats.tx_errors, -		   (unsigned long long)tunnel->stats.rx_packets, -		   (unsigned long long)tunnel->stats.rx_bytes, -		   (unsigned long long)tunnel->stats.rx_errors); +		   atomic_long_read(&tunnel->stats.tx_packets), +		   atomic_long_read(&tunnel->stats.tx_bytes), +		   atomic_long_read(&tunnel->stats.tx_errors), +		   atomic_long_read(&tunnel->stats.rx_packets), +		   atomic_long_read(&tunnel->stats.rx_bytes), +		   atomic_long_read(&tunnel->stats.rx_errors));  }  static void pppol2tp_seq_session_show(struct seq_file *m, void *v) @@ -1647,14 +1671,14 @@ static void pppol2tp_seq_session_show(struct seq_file *m, void *v)  		   session->lns_mode ? "LNS" : "LAC",  		   session->debug,  		   jiffies_to_msecs(session->reorder_timeout)); -	seq_printf(m, "   %hu/%hu %llu/%llu/%llu %llu/%llu/%llu\n", +	seq_printf(m, "   %hu/%hu %ld/%ld/%ld %ld/%ld/%ld\n",  		   session->nr, session->ns, -		   (unsigned long long)session->stats.tx_packets, -		   (unsigned long long)session->stats.tx_bytes, -		   (unsigned long long)session->stats.tx_errors, -		   (unsigned long long)session->stats.rx_packets, -		   (unsigned long long)session->stats.rx_bytes, -		   (unsigned long long)session->stats.rx_errors); +		   atomic_long_read(&session->stats.tx_packets), +		   atomic_long_read(&session->stats.tx_bytes), +		   atomic_long_read(&session->stats.tx_errors), +		   atomic_long_read(&session->stats.rx_packets), +		   atomic_long_read(&session->stats.rx_bytes), +		   atomic_long_read(&session->stats.rx_errors));  	if (po)  		seq_printf(m, "   interface %s\n", ppp_dev_name(&po->chan)); @@ -1723,7 +1747,8 @@ static __net_init int pppol2tp_init_net(struct net *net)  	struct proc_dir_entry *pde;  	int err = 0; -	pde = proc_net_fops_create(net, "pppol2tp", S_IRUGO, &pppol2tp_proc_fops); +	pde = proc_create("pppol2tp", S_IRUGO, net->proc_net, +			  &pppol2tp_proc_fops);  	if (!pde) {  		err = -ENOMEM;  		goto out; @@ -1735,7 +1760,7 @@ out:  static __net_exit void pppol2tp_exit_net(struct net *net)  { -	proc_net_remove(net, "pppol2tp"); +	remove_proc_entry("pppol2tp", net->proc_net);  }  static struct pernet_operations pppol2tp_net_ops = { @@ -1770,14 +1795,15 @@ static const struct proto_ops pppol2tp_ops = {  static const struct pppox_proto pppol2tp_proto = {  	.create		= pppol2tp_create, -	.ioctl		= pppol2tp_ioctl +	.ioctl		= pppol2tp_ioctl, +	.owner		= THIS_MODULE,  };  #ifdef CONFIG_L2TP_V3  static const struct l2tp_nl_cmd_ops pppol2tp_nl_cmd_ops = {  	.session_create	= pppol2tp_session_create, -	.session_delete	= pppol2tp_session_delete, +	.session_delete	= l2tp_session_delete,  };  #endif /* CONFIG_L2TP_V3 */ @@ -1804,8 +1830,7 @@ static int __init pppol2tp_init(void)  		goto out_unregister_pppox;  #endif -	printk(KERN_INFO "PPPoL2TP kernel driver, %s\n", -	       PPPOL2TP_DRV_VERSION); +	pr_info("PPPoL2TP kernel driver, %s\n", PPPOL2TP_DRV_VERSION);  out:  	return err; @@ -1838,3 +1863,4 @@ MODULE_AUTHOR("James Chapman <jchapman@katalix.com>");  MODULE_DESCRIPTION("PPP over L2TP over UDP");  MODULE_LICENSE("GPL");  MODULE_VERSION(PPPOL2TP_DRV_VERSION); +MODULE_ALIAS("pppox-proto-" __stringify(PX_PROTO_OL2TP));  | 
