diff options
Diffstat (limited to 'net/l2tp')
| -rw-r--r-- | net/l2tp/l2tp_core.c | 190 | ||||
| -rw-r--r-- | net/l2tp/l2tp_core.h | 63 | ||||
| -rw-r--r-- | net/l2tp/l2tp_debugfs.c | 5 | ||||
| -rw-r--r-- | net/l2tp/l2tp_ip.c | 11 | ||||
| -rw-r--r-- | net/l2tp/l2tp_ip6.c | 40 | ||||
| -rw-r--r-- | net/l2tp/l2tp_netlink.c | 27 | ||||
| -rw-r--r-- | net/l2tp/l2tp_ppp.c | 42 | 
7 files changed, 148 insertions, 230 deletions
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index feae495a0a3..bea25904320 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -112,9 +112,13 @@ 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 inline struct l2tp_tunnel *l2tp_tunnel(struct sock *sk) +{ +	return sk->sk_user_data; +} +  static inline struct l2tp_net *l2tp_pernet(struct net *net)  {  	BUG_ON(!net); @@ -171,7 +175,7 @@ l2tp_session_id_hash_2(struct l2tp_net *pn, u32 session_id)   * owned by userspace.  A struct sock returned from this function must be   * released using l2tp_tunnel_sock_put once you're done with it.   */ -struct sock *l2tp_tunnel_sock_lookup(struct l2tp_tunnel *tunnel) +static struct sock *l2tp_tunnel_sock_lookup(struct l2tp_tunnel *tunnel)  {  	int err = 0;  	struct socket *sock = NULL; @@ -197,10 +201,9 @@ struct sock *l2tp_tunnel_sock_lookup(struct l2tp_tunnel *tunnel)  out:  	return sk;  } -EXPORT_SYMBOL_GPL(l2tp_tunnel_sock_lookup);  /* Drop a reference to a tunnel socket obtained via. l2tp_tunnel_sock_put */ -void l2tp_tunnel_sock_put(struct sock *sk) +static void l2tp_tunnel_sock_put(struct sock *sk)  {  	struct l2tp_tunnel *tunnel = l2tp_sock_to_tunnel(sk);  	if (tunnel) { @@ -212,7 +215,6 @@ void l2tp_tunnel_sock_put(struct sock *sk)  	}  	sock_put(sk);  } -EXPORT_SYMBOL_GPL(l2tp_tunnel_sock_put);  /* Lookup a session by id in the global session list   */ @@ -493,52 +495,6 @@ out:  	spin_unlock_bh(&session->reorder_q.lock);  } -static inline int l2tp_verify_udp_checksum(struct sock *sk, -					   struct sk_buff *skb) -{ -	struct udphdr *uh = udp_hdr(skb); -	u16 ulen = ntohs(uh->len); -	__wsum psum; - -	if (sk->sk_no_check || skb_csum_unnecessary(skb)) -		return 0; - -#if IS_ENABLED(CONFIG_IPV6) -	if (sk->sk_family == PF_INET6) { -		if (!uh->check) { -			LIMIT_NETDEBUG(KERN_INFO "L2TP: IPv6: checksum is 0\n"); -			return 1; -		} -		if ((skb->ip_summed == CHECKSUM_COMPLETE) && -		    !csum_ipv6_magic(&ipv6_hdr(skb)->saddr, -				     &ipv6_hdr(skb)->daddr, ulen, -				     IPPROTO_UDP, skb->csum)) { -			skb->ip_summed = CHECKSUM_UNNECESSARY; -			return 0; -		} -		skb->csum = ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr, -							 &ipv6_hdr(skb)->daddr, -							 skb->len, IPPROTO_UDP, -							 0)); -	} else -#endif -	{ -		struct inet_sock *inet; -		if (!uh->check) -			return 0; -		inet = inet_sk(sk); -		psum = csum_tcpudp_nofold(inet->inet_saddr, inet->inet_daddr, -					  ulen, IPPROTO_UDP, 0); - -		if ((skb->ip_summed == CHECKSUM_COMPLETE) && -		    !csum_fold(csum_add(psum, skb->csum))) -			return 0; -		skb->csum = psum; -	} - -	return __skb_checksum_complete(skb); -} -  static int l2tp_seq_check_rx_window(struct l2tp_session *session, u32 nr)  {  	u32 nws; @@ -893,8 +849,7 @@ static int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb,  	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)); @@ -977,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); -	atomic_long_inc(&tunnel->stats.rx_errors); -	kfree_skb(skb); - -	return 0; -  error:  	/* Put UDP header back */  	__skb_push(skb, sizeof(struct udphdr)); @@ -1126,13 +1073,13 @@ static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb,  	}  	/* Queue the packet to IP for output */ -	skb->local_df = 1; +	skb->ignore_df = 1;  #if IS_ENABLED(CONFIG_IPV6) -	if (skb->sk->sk_family == PF_INET6) -		error = inet6_csk_xmit(skb, NULL); +	if (tunnel->sock->sk_family == PF_INET6 && !tunnel->v4mapped) +		error = inet6_csk_xmit(tunnel->sock, skb, NULL);  	else  #endif -		error = ip_queue_xmit(skb, fl); +		error = ip_queue_xmit(tunnel->sock, skb, fl);  	/* Update stats */  	if (error >= 0) { @@ -1148,48 +1095,6 @@ static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb,  	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 IS_ENABLED(CONFIG_IPV6) -static void l2tp_xmit_ipv6_csum(struct sock *sk, struct sk_buff *skb, -				int udp_len) -{ -	struct ipv6_pinfo *np = inet6_sk(sk); -	struct udphdr *uh = udp_hdr(skb); - -	if (!skb_dst(skb) || !skb_dst(skb)->dev || -	    !(skb_dst(skb)->dev->features & NETIF_F_IPV6_CSUM)) { -		__wsum csum = skb_checksum(skb, 0, udp_len, 0); -		skb->ip_summed = CHECKSUM_UNNECESSARY; -		uh->check = csum_ipv6_magic(&np->saddr, &np->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_ipv6_magic(&np->saddr, &np->daddr, -					     udp_len, IPPROTO_UDP, 0); -	} -} -#endif -  /* If caller requires the skb to have a ppp header, the header must be   * inserted in the skb data before calling this function.   */ @@ -1201,7 +1106,6 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len  	struct flowi *fl;  	struct udphdr *uh;  	struct inet_sock *inet; -	__wsum csum;  	int headroom;  	int uhlen = (tunnel->encap == L2TP_ENCAPTYPE_UDP) ? sizeof(struct udphdr) : 0;  	int udp_len; @@ -1218,7 +1122,6 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len  		return NET_XMIT_DROP;  	} -	skb_orphan(skb);  	/* Setup L2TP header */  	session->build_header(session, __skb_push(skb, hdr_len)); @@ -1251,41 +1154,23 @@ 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 IS_ENABLED(CONFIG_IPV6) -		if (sk->sk_family == PF_INET6) -			l2tp_xmit_ipv6_csum(sk, skb, udp_len); +		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 -		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); -		} +		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, fl, data_len);  out_unlock:  	bh_unlock_sock(sk); @@ -1304,10 +1189,9 @@ 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; @@ -1509,6 +1393,11 @@ static int l2tp_tunnel_sock_create(struct net *net,  					     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  		{ @@ -1537,7 +1426,7 @@ static int l2tp_tunnel_sock_create(struct net *net,  		}  		if (!cfg->use_udp_checksums) -			sock->sk->sk_no_check = UDP_CSUM_NOXMIT; +			sock->sk->sk_no_check_tx = 1;  		break; @@ -1675,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; @@ -1704,6 +1593,24 @@ 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) { @@ -1712,7 +1619,7 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32  		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) +		if (sk->sk_family == PF_INET6 && !tunnel->v4mapped)  			udpv6_encap_enable();  		else  #endif @@ -1789,8 +1696,6 @@ void l2tp_session_free(struct l2tp_session *session)  	}  	kfree(session); - -	return;  }  EXPORT_SYMBOL_GPL(l2tp_session_free); @@ -1843,7 +1748,7 @@ 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; @@ -1856,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)  { @@ -1996,7 +1902,7 @@ static int __init l2tp_init(void)  	if (rc)  		goto out; -	l2tp_wq = alloc_workqueue("l2tp", WQ_NON_REENTRANT | WQ_UNBOUND, 0); +	l2tp_wq = alloc_workqueue("l2tp", WQ_UNBOUND, 0);  	if (!l2tp_wq) {  		pr_err("alloc_workqueue failed\n");  		rc = -ENOMEM; diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h index 66a559b104b..68aa9ffd4ae 100644 --- a/net/l2tp/l2tp_core.h +++ b/net/l2tp/l2tp_core.h @@ -162,7 +162,9 @@ struct l2tp_tunnel_cfg {  #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 { @@ -194,6 +196,9 @@ struct l2tp_tunnel {  	struct sock		*sock;		/* Parent socket */  	int			fd;		/* Parent fd, if tunnel socket  						 * was created by userspace */ +#if IS_ENABLED(CONFIG_IPV6) +	bool			v4mapped; +#endif  	struct work_struct	del_work; @@ -235,29 +240,39 @@ out:  	return tunnel;  } -extern struct sock *l2tp_tunnel_sock_lookup(struct l2tp_tunnel *tunnel); -extern void l2tp_tunnel_sock_put(struct sock *sk); -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 void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel); -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 void __l2tp_session_unhash(struct l2tp_session *session); -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_session_queue_purge(struct l2tp_session *session); -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. diff --git a/net/l2tp/l2tp_debugfs.c b/net/l2tp/l2tp_debugfs.c index 072d7202e18..2d6760a2ae3 100644 --- a/net/l2tp/l2tp_debugfs.c +++ b/net/l2tp/l2tp_debugfs.c @@ -127,9 +127,10 @@ static void l2tp_dfs_seq_tunnel_show(struct seq_file *m, void *v)  #if IS_ENABLED(CONFIG_IPV6)  		if (tunnel->sock->sk_family == AF_INET6) { -			struct ipv6_pinfo *np = inet6_sk(tunnel->sock); +			const struct ipv6_pinfo *np = inet6_sk(tunnel->sock); +  			seq_printf(m, " from %pI6c to %pI6c\n", -				&np->saddr, &np->daddr); +				&np->saddr, &tunnel->sock->sk_v6_daddr);  		} else  #endif  		seq_printf(m, " from %pI4 to %pI4\n", diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c index 571db8dd229..369a9822488 100644 --- a/net/l2tp/l2tp_ip.c +++ b/net/l2tp/l2tp_ip.c @@ -403,7 +403,7 @@ static int l2tp_ip_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m  	/* 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))  			goto out; @@ -487,7 +487,7 @@ static int l2tp_ip_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m  xmit:  	/* Queue the packet to IP for output */ -	rc = ip_queue_xmit(skb, &inet->cork.fl); +	rc = ip_queue_xmit(sk, skb, &inet->cork.fl);  	rcu_read_unlock();  error: @@ -512,15 +512,12 @@ static int l2tp_ip_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m  	struct inet_sock *inet = inet_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; @@ -543,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); @@ -608,7 +606,6 @@ 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 = { diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c index b8a6039314e..f3f98a156ce 100644 --- a/net/l2tp/l2tp_ip6.c +++ b/net/l2tp/l2tp_ip6.c @@ -63,7 +63,7 @@ static struct sock *__l2tp_ip6_bind_lookup(struct net *net,  	struct sock *sk;  	sk_for_each_bound(sk, &l2tp_ip6_bind_table) { -		struct in6_addr *addr = inet6_rcv_saddr(sk); +		const struct in6_addr *addr = inet6_rcv_saddr(sk);  		struct l2tp_ip6_sock *l2tp = l2tp_ip6_sk(sk);  		if (l2tp == NULL) @@ -331,7 +331,7 @@ static int l2tp_ip6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)  	rcu_read_unlock();  	inet->inet_rcv_saddr = inet->inet_saddr = v4addr; -	np->rcv_saddr = addr->l2tp_addr; +	sk->sk_v6_rcv_saddr = addr->l2tp_addr;  	np->saddr = addr->l2tp_addr;  	l2tp_ip6_sk(sk)->conn_id = addr->l2tp_conn_id; @@ -371,6 +371,9 @@ static int l2tp_ip6_connect(struct sock *sk, struct sockaddr *uaddr,  	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; @@ -421,14 +424,14 @@ static int l2tp_ip6_getname(struct socket *sock, struct sockaddr *uaddr,  		if (!lsk->peer_conn_id)  			return -ENOTCONN;  		lsa->l2tp_conn_id = lsk->peer_conn_id; -		lsa->l2tp_addr = np->daddr; +		lsa->l2tp_addr = sk->sk_v6_daddr;  		if (np->sndflow)  			lsa->l2tp_flowinfo = np->flow_label;  	} else { -		if (ipv6_addr_any(&np->rcv_saddr)) +		if (ipv6_addr_any(&sk->sk_v6_rcv_saddr))  			lsa->l2tp_addr = np->saddr;  		else -			lsa->l2tp_addr = np->rcv_saddr; +			lsa->l2tp_addr = sk->sk_v6_rcv_saddr;  		lsa->l2tp_conn_id = lsk->conn_id;  	} @@ -481,8 +484,7 @@ static int l2tp_ip6_sendmsg(struct kiocb *iocb, struct sock *sk,  			    struct msghdr *msg, size_t len)  {  	struct ipv6_txoptions opt_space; -	struct sockaddr_l2tpip6 *lsa = -		(struct sockaddr_l2tpip6 *) msg->msg_name; +	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; @@ -528,7 +530,6 @@ static int l2tp_ip6_sendmsg(struct kiocb *iocb, struct sock *sk,  				flowlabel = fl6_sock_lookup(sk, fl6.flowlabel);  				if (flowlabel == NULL)  					return -EINVAL; -				daddr = &flowlabel->dst;  			}  		} @@ -537,8 +538,8 @@ static int l2tp_ip6_sendmsg(struct kiocb *iocb, struct sock *sk,  		 * sk->sk_dst_cache.  		 */  		if (sk->sk_state == TCP_ESTABLISHED && -		    ipv6_addr_equal(daddr, &np->daddr)) -			daddr = &np->daddr; +		    ipv6_addr_equal(daddr, &sk->sk_v6_daddr)) +			daddr = &sk->sk_v6_daddr;  		if (addr_len >= sizeof(struct sockaddr_in6) &&  		    lsa->l2tp_scope_id && @@ -548,7 +549,7 @@ static int l2tp_ip6_sendmsg(struct kiocb *iocb, struct sock *sk,  		if (sk->sk_state != TCP_ESTABLISHED)  			return -EDESTADDRREQ; -		daddr = &np->daddr; +		daddr = &sk->sk_v6_daddr;  		fl6.flowlabel = np->flow_label;  	} @@ -598,20 +599,14 @@ static int l2tp_ip6_sendmsg(struct kiocb *iocb, struct sock *sk,  	security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); -	dst = ip6_dst_lookup_flow(sk, &fl6, final_p, true); +	dst = ip6_dst_lookup_flow(sk, &fl6, final_p);  	if (IS_ERR(dst)) {  		err = PTR_ERR(dst);  		goto out;  	} -	if (hlimit < 0) { -		if (ipv6_addr_is_multicast(&fl6.daddr)) -			hlimit = np->mcast_hops; -		else -			hlimit = np->hop_limit; -		if (hlimit < 0) -			hlimit = ip6_dst_hoplimit(dst); -	} +	if (hlimit < 0) +		hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);  	if (tclass < 0)  		tclass = np->tclass; @@ -653,7 +648,7 @@ static int l2tp_ip6_recvmsg(struct kiocb *iocb, struct sock *sk,  			    int flags, int *addr_len)  {  	struct ipv6_pinfo *np = inet6_sk(sk); -	struct sockaddr_l2tpip6 *lsa = (struct sockaddr_l2tpip6 *)msg->msg_name; +	DECLARE_SOCKADDR(struct sockaddr_l2tpip6 *, lsa, msg->msg_name);  	size_t copied = 0;  	int err = -EOPNOTSUPP;  	struct sk_buff *skb; @@ -665,7 +660,7 @@ static int l2tp_ip6_recvmsg(struct kiocb *iocb, struct sock *sk,  		*addr_len = sizeof(*lsa);  	if (flags & MSG_ERRQUEUE) -		return ipv6_recv_error(sk, msg, len); +		return ipv6_recv_error(sk, msg, len, addr_len);  	skb = skb_recv_datagram(sk, flags, noblock, &err);  	if (!skb) @@ -760,7 +755,6 @@ static struct inet_protosw l2tp_ip6_protosw = {  	.protocol	= IPPROTO_L2TP,  	.prot		= &l2tp_ip6_prot,  	.ops		= &l2tp_ip6_ops, -	.no_check	= 0,  };  static struct inet6_protocol l2tp_ip6_protocol __read_mostly = { diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c index 0825ff26e11..0ac907adb2f 100644 --- a/net/l2tp/l2tp_netlink.c +++ b/net/l2tp/l2tp_netlink.c @@ -161,6 +161,13 @@ static int l2tp_nl_cmd_tunnel_create(struct sk_buff *skb, struct genl_info *info  			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]) @@ -297,8 +304,7 @@ static int l2tp_nl_tunnel_send(struct sk_buff *skb, u32 portid, u32 seq, int fla  	case L2TP_ENCAPTYPE_UDP:  		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 != UDP_CSUM_NOXMIT))) +		    nla_put_u8(skb, L2TP_ATTR_UDP_CSUM, !sk->sk_no_check_tx))  			goto nla_put_failure;  		/* NOBREAK */  	case L2TP_ENCAPTYPE_IP: @@ -306,8 +312,8 @@ static int l2tp_nl_tunnel_send(struct sk_buff *skb, u32 portid, u32 seq, int fla  		if (np) {  			if (nla_put(skb, L2TP_ATTR_IP6_SADDR, sizeof(np->saddr),  				    &np->saddr) || -			    nla_put(skb, L2TP_ATTR_IP6_DADDR, sizeof(np->daddr), -				    &np->daddr)) +			    nla_put(skb, L2TP_ATTR_IP6_DADDR, sizeof(sk->sk_v6_daddr), +				    &sk->sk_v6_daddr))  				goto nla_put_failure;  		} else  #endif @@ -578,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]); @@ -793,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, @@ -887,13 +895,8 @@ EXPORT_SYMBOL_GPL(l2tp_nl_unregister_ops);  static int l2tp_nl_init(void)  { -	int err; -  	pr_info("L2TP netlink interface\n"); -	err = genl_register_family_with_ops(&l2tp_nl_family, l2tp_nl_ops, -					    ARRAY_SIZE(l2tp_nl_ops)); - -	return err; +	return genl_register_family_with_ops(&l2tp_nl_family, l2tp_nl_ops);  }  static void l2tp_nl_cleanup(void) diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c index 5ebee2ded9e..13752d96275 100644 --- a/net/l2tp/l2tp_ppp.c +++ b/net/l2tp/l2tp_ppp.c @@ -197,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); @@ -256,12 +254,14 @@ static void pppol2tp_recv(struct l2tp_session *session, struct sk_buff *skb, int  		po = pppox_sk(sk);  		ppp_input(&po->chan, skb);  	} else { -		l2tp_info(session, PPPOL2TP_MSG_DATA, "%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. */ -		atomic_long_inc(&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; @@ -353,7 +353,9 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh  		goto error_put_sess_tun;  	} +	local_bh_disable();  	l2tp_xmit_skb(session, skb, session->hdr_len); +	local_bh_enable();  	sock_put(ps->tunnel_sock);  	sock_put(sk); @@ -422,7 +424,9 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)  	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); @@ -452,13 +456,11 @@ static void pppol2tp_session_close(struct l2tp_session *session)  	BUG_ON(session->magic != L2TP_SESSION_MAGIC); -  	if (sock) {  		inet_shutdown(sock, 2);  		/* Don't let the session go away before our socket does */  		l2tp_session_inc_refcount(session);  	} -	return;  }  /* Really kill the session socket. (Called from sock_put() if @@ -472,7 +474,6 @@ static void pppol2tp_session_destruct(struct sock *sk)  		BUG_ON(session->magic != L2TP_SESSION_MAGIC);  		l2tp_session_dec_refcount(session);  	} -	return;  }  /* Called when the PPPoX socket (session) is closed. @@ -752,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; @@ -906,8 +907,8 @@ static int pppol2tp_getname(struct socket *sock, struct sockaddr *uaddr,  #if IS_ENABLED(CONFIG_IPV6)  	} else if ((tunnel->version == 2) &&  		   (tunnel->sock->sk_family == AF_INET6)) { -		struct ipv6_pinfo *np = inet6_sk(tunnel->sock);  		struct sockaddr_pppol2tpin6 sp; +  		len = sizeof(sp);  		memset(&sp, 0, len);  		sp.sa_family	= AF_PPPOX; @@ -920,13 +921,13 @@ static int pppol2tp_getname(struct socket *sock, struct sockaddr *uaddr,  		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, &np->daddr, -		       sizeof(np->daddr)); +		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 ipv6_pinfo *np = inet6_sk(tunnel->sock);  		struct sockaddr_pppol2tpv3in6 sp; +  		len = sizeof(sp);  		memset(&sp, 0, len);  		sp.sa_family	= AF_PPPOX; @@ -939,8 +940,8 @@ static int pppol2tp_getname(struct socket *sock, struct sockaddr *uaddr,  		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, &np->daddr, -		       sizeof(np->daddr)); +		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) { @@ -1310,6 +1311,7 @@ static int pppol2tp_session_setsockopt(struct sock *sk,  			po->chan.hdrlen = val ? PPPOL2TP_L2TP_HDR_SIZE_SEQ :  				PPPOL2TP_L2TP_HDR_SIZE_NOSEQ;  		} +		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); @@ -1363,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; @@ -1489,7 +1491,7 @@ static int pppol2tp_getsockopt(struct socket *sock, int level, int optname,  	struct pppol2tp_session *ps;  	if (level != SOL_PPPOL2TP) -		return udp_prot.getsockopt(sk, level, optname, optval, optlen); +		return -EINVAL;  	if (get_user(len, optlen))  		return -EFAULT;  | 
