diff options
Diffstat (limited to 'net/ipv6/datagram.c')
| -rw-r--r-- | net/ipv6/datagram.c | 94 | 
1 files changed, 64 insertions, 30 deletions
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 48b6bd2a9a1..c3bf2d2e519 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -73,7 +73,6 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)  			flowlabel = fl6_sock_lookup(sk, fl6.flowlabel);  			if (flowlabel == NULL)  				return -EINVAL; -			usin->sin6_addr = flowlabel->dst;  		}  	} @@ -107,16 +106,16 @@ ipv4_connected:  		if (err)  			goto out; -		ipv6_addr_set_v4mapped(inet->inet_daddr, &np->daddr); +		ipv6_addr_set_v4mapped(inet->inet_daddr, &sk->sk_v6_daddr);  		if (ipv6_addr_any(&np->saddr) ||  		    ipv6_mapped_addr_any(&np->saddr))  			ipv6_addr_set_v4mapped(inet->inet_saddr, &np->saddr); -		if (ipv6_addr_any(&np->rcv_saddr) || -		    ipv6_mapped_addr_any(&np->rcv_saddr)) { +		if (ipv6_addr_any(&sk->sk_v6_rcv_saddr) || +		    ipv6_mapped_addr_any(&sk->sk_v6_rcv_saddr)) {  			ipv6_addr_set_v4mapped(inet->inet_rcv_saddr, -					       &np->rcv_saddr); +					       &sk->sk_v6_rcv_saddr);  			if (sk->sk_prot->rehash)  				sk->sk_prot->rehash(sk);  		} @@ -145,7 +144,7 @@ ipv4_connected:  		}  	} -	np->daddr = *daddr; +	sk->sk_v6_daddr = *daddr;  	np->flow_label = fl6.flowlabel;  	inet->inet_dport = usin->sin6_port; @@ -156,7 +155,7 @@ ipv4_connected:  	 */  	fl6.flowi6_proto = sk->sk_protocol; -	fl6.daddr = np->daddr; +	fl6.daddr = sk->sk_v6_daddr;  	fl6.saddr = np->saddr;  	fl6.flowi6_oif = sk->sk_bound_dev_if;  	fl6.flowi6_mark = sk->sk_mark; @@ -171,7 +170,7 @@ ipv4_connected:  	opt = flowlabel ? flowlabel->opt : np->opt;  	final_p = fl6_update_dst(&fl6, opt, &final); -	dst = ip6_dst_lookup_flow(sk, &fl6, final_p, true); +	dst = ip6_dst_lookup_flow(sk, &fl6, final_p);  	err = 0;  	if (IS_ERR(dst)) {  		err = PTR_ERR(dst); @@ -183,16 +182,16 @@ ipv4_connected:  	if (ipv6_addr_any(&np->saddr))  		np->saddr = fl6.saddr; -	if (ipv6_addr_any(&np->rcv_saddr)) { -		np->rcv_saddr = fl6.saddr; +	if (ipv6_addr_any(&sk->sk_v6_rcv_saddr)) { +		sk->sk_v6_rcv_saddr = fl6.saddr;  		inet->inet_rcv_saddr = LOOPBACK4_IPV6;  		if (sk->sk_prot->rehash)  			sk->sk_prot->rehash(sk);  	}  	ip6_dst_store(sk, dst, -		      ipv6_addr_equal(&fl6.daddr, &np->daddr) ? -		      &np->daddr : NULL, +		      ipv6_addr_equal(&fl6.daddr, &sk->sk_v6_daddr) ? +		      &sk->sk_v6_daddr : NULL,  #ifdef CONFIG_IPV6_SUBTREES  		      ipv6_addr_equal(&fl6.saddr, &np->saddr) ?  		      &np->saddr : @@ -206,6 +205,16 @@ out:  }  EXPORT_SYMBOL_GPL(ip6_datagram_connect); +int ip6_datagram_connect_v6_only(struct sock *sk, struct sockaddr *uaddr, +				 int addr_len) +{ +	DECLARE_SOCKADDR(struct sockaddr_in6 *, sin6, uaddr); +	if (sin6->sin6_family != AF_INET6) +		return -EAFNOSUPPORT; +	return ip6_datagram_connect(sk, uaddr, addr_len); +} +EXPORT_SYMBOL_GPL(ip6_datagram_connect_v6_only); +  void ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err,  		     __be16 port, u32 info, u8 *payload)  { @@ -318,12 +327,12 @@ void ipv6_local_rxpmtu(struct sock *sk, struct flowi6 *fl6, u32 mtu)  /*   *	Handle MSG_ERRQUEUE   */ -int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len) +int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)  {  	struct ipv6_pinfo *np = inet6_sk(sk);  	struct sock_exterr_skb *serr;  	struct sk_buff *skb, *skb2; -	struct sockaddr_in6 *sin; +	DECLARE_SOCKADDR(struct sockaddr_in6 *, sin, msg->msg_name);  	struct {  		struct sock_extended_err ee;  		struct sockaddr_in6	 offender; @@ -349,7 +358,6 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len)  	serr = SKB_EXT_ERR(skb); -	sin = (struct sockaddr_in6 *)msg->msg_name;  	if (sin) {  		const unsigned char *nh = skb_network_header(skb);  		sin->sin6_family = AF_INET6; @@ -369,6 +377,7 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len)  					       &sin->sin6_addr);  			sin->sin6_scope_id = 0;  		} +		*addr_len = sizeof(*sin);  	}  	memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err)); @@ -377,10 +386,13 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len)  	if (serr->ee.ee_origin != SO_EE_ORIGIN_LOCAL) {  		sin->sin6_family = AF_INET6;  		sin->sin6_flowinfo = 0; +		sin->sin6_port = 0; +		if (np->rxopt.all) +			ip6_datagram_recv_common_ctl(sk, msg, skb);  		if (skb->protocol == htons(ETH_P_IPV6)) {  			sin->sin6_addr = ipv6_hdr(skb)->saddr;  			if (np->rxopt.all) -				ip6_datagram_recv_ctl(sk, msg, skb); +				ip6_datagram_recv_specific_ctl(sk, msg, skb);  			sin->sin6_scope_id =  				ipv6_iface_scope_id(&sin->sin6_addr,  						    IP6CB(skb)->iif); @@ -423,12 +435,13 @@ EXPORT_SYMBOL_GPL(ipv6_recv_error);  /*   *	Handle IPV6_RECVPATHMTU   */ -int ipv6_recv_rxpmtu(struct sock *sk, struct msghdr *msg, int len) +int ipv6_recv_rxpmtu(struct sock *sk, struct msghdr *msg, int len, +		     int *addr_len)  {  	struct ipv6_pinfo *np = inet6_sk(sk);  	struct sk_buff *skb; -	struct sockaddr_in6 *sin;  	struct ip6_mtuinfo mtu_info; +	DECLARE_SOCKADDR(struct sockaddr_in6 *, sin, msg->msg_name);  	int err;  	int copied; @@ -450,13 +463,13 @@ int ipv6_recv_rxpmtu(struct sock *sk, struct msghdr *msg, int len)  	memcpy(&mtu_info, IP6CBMTU(skb), sizeof(mtu_info)); -	sin = (struct sockaddr_in6 *)msg->msg_name;  	if (sin) {  		sin->sin6_family = AF_INET6;  		sin->sin6_flowinfo = 0;  		sin->sin6_port = 0;  		sin->sin6_scope_id = mtu_info.ip6m_addr.sin6_scope_id;  		sin->sin6_addr = mtu_info.ip6m_addr.sin6_addr; +		*addr_len = sizeof(*sin);  	}  	put_cmsg(msg, SOL_IPV6, IPV6_PATHMTU, sizeof(mtu_info), &mtu_info); @@ -470,20 +483,34 @@ out:  } -int ip6_datagram_recv_ctl(struct sock *sk, struct msghdr *msg, -			  struct sk_buff *skb) +void ip6_datagram_recv_common_ctl(struct sock *sk, struct msghdr *msg, +				 struct sk_buff *skb)  {  	struct ipv6_pinfo *np = inet6_sk(sk); -	struct inet6_skb_parm *opt = IP6CB(skb); -	unsigned char *nh = skb_network_header(skb); +	bool is_ipv6 = skb->protocol == htons(ETH_P_IPV6);  	if (np->rxopt.bits.rxinfo) {  		struct in6_pktinfo src_info; -		src_info.ipi6_ifindex = opt->iif; -		src_info.ipi6_addr = ipv6_hdr(skb)->daddr; +		if (is_ipv6) { +			src_info.ipi6_ifindex = IP6CB(skb)->iif; +			src_info.ipi6_addr = ipv6_hdr(skb)->daddr; +		} else { +			src_info.ipi6_ifindex = +				PKTINFO_SKB_CB(skb)->ipi_ifindex; +			ipv6_addr_set_v4mapped(ip_hdr(skb)->daddr, +					       &src_info.ipi6_addr); +		}  		put_cmsg(msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info);  	} +} + +void ip6_datagram_recv_specific_ctl(struct sock *sk, struct msghdr *msg, +				    struct sk_buff *skb) +{ +	struct ipv6_pinfo *np = inet6_sk(sk); +	struct inet6_skb_parm *opt = IP6CB(skb); +	unsigned char *nh = skb_network_header(skb);  	if (np->rxopt.bits.rxhlim) {  		int hlim = ipv6_hdr(skb)->hop_limit; @@ -601,7 +628,13 @@ int ip6_datagram_recv_ctl(struct sock *sk, struct msghdr *msg,  			put_cmsg(msg, SOL_IPV6, IPV6_ORIGDSTADDR, sizeof(sin6), &sin6);  		}  	} -	return 0; +} + +void ip6_datagram_recv_ctl(struct sock *sk, struct msghdr *msg, +			  struct sk_buff *skb) +{ +	ip6_datagram_recv_common_ctl(sk, msg, skb); +	ip6_datagram_recv_specific_ctl(sk, msg, skb);  }  EXPORT_SYMBOL_GPL(ip6_datagram_recv_ctl); @@ -666,7 +699,9 @@ int ip6_datagram_send_ctl(struct net *net, struct sock *sk,  				int strict = __ipv6_addr_src_scope(addr_type) <= IPV6_ADDR_SCOPE_LINKLOCAL;  				if (!(inet_sk(sk)->freebind || inet_sk(sk)->transparent) &&  				    !ipv6_chk_addr(net, &src_info->ipi6_addr, -						   strict ? dev : NULL, 0)) +						   strict ? dev : NULL, 0) && +				    !ipv6_chk_acast_addr_src(net, dev, +							     &src_info->ipi6_addr))  					err = -EINVAL;  				else  					fl6->saddr = src_info->ipi6_addr; @@ -883,11 +918,10 @@ EXPORT_SYMBOL_GPL(ip6_datagram_send_ctl);  void ip6_dgram_sock_seq_show(struct seq_file *seq, struct sock *sp,  			     __u16 srcp, __u16 destp, int bucket)  { -	struct ipv6_pinfo *np = inet6_sk(sp);  	const struct in6_addr *dest, *src; -	dest  = &np->daddr; -	src   = &np->rcv_saddr; +	dest  = &sp->sk_v6_daddr; +	src   = &sp->sk_v6_rcv_saddr;  	seq_printf(seq,  		   "%5d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "  		   "%02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %d\n",  | 
