diff options
Diffstat (limited to 'net/ipv6')
| -rw-r--r-- | net/ipv6/addrconf.c | 51 | ||||
| -rw-r--r-- | net/ipv6/addrconf_core.c | 19 | ||||
| -rw-r--r-- | net/ipv6/ip6_input.c | 12 | ||||
| -rw-r--r-- | net/ipv6/netfilter/ip6t_NPT.c | 2 | ||||
| -rw-r--r-- | net/ipv6/netfilter/ip6t_rpfilter.c | 8 | ||||
| -rw-r--r-- | net/ipv6/reassembly.c | 12 | ||||
| -rw-r--r-- | net/ipv6/tcp_ipv6.c | 1 | 
7 files changed, 80 insertions, 25 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 26512250e09..dae802c0af7 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -168,8 +168,6 @@ static void inet6_prefix_notify(int event, struct inet6_dev *idev,  static bool ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr,  			       struct net_device *dev); -static ATOMIC_NOTIFIER_HEAD(inet6addr_chain); -  static struct ipv6_devconf ipv6_devconf __read_mostly = {  	.forwarding		= 0,  	.hop_limit		= IPV6_DEFAULT_HOPLIMIT, @@ -837,7 +835,7 @@ out2:  	rcu_read_unlock_bh();  	if (likely(err == 0)) -		atomic_notifier_call_chain(&inet6addr_chain, NETDEV_UP, ifa); +		inet6addr_notifier_call_chain(NETDEV_UP, ifa);  	else {  		kfree(ifa);  		ifa = ERR_PTR(err); @@ -927,7 +925,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)  	ipv6_ifa_notify(RTM_DELADDR, ifp); -	atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifp); +	inet6addr_notifier_call_chain(NETDEV_DOWN, ifp);  	/*  	 * Purge or update corresponding prefix @@ -2529,6 +2527,9 @@ static void sit_add_v4_addrs(struct inet6_dev *idev)  static void init_loopback(struct net_device *dev)  {  	struct inet6_dev  *idev; +	struct net_device *sp_dev; +	struct inet6_ifaddr *sp_ifa; +	struct rt6_info *sp_rt;  	/* ::1 */ @@ -2540,6 +2541,30 @@ static void init_loopback(struct net_device *dev)  	}  	add_addr(idev, &in6addr_loopback, 128, IFA_HOST); + +	/* Add routes to other interface's IPv6 addresses */ +	for_each_netdev(dev_net(dev), sp_dev) { +		if (!strcmp(sp_dev->name, dev->name)) +			continue; + +		idev = __in6_dev_get(sp_dev); +		if (!idev) +			continue; + +		read_lock_bh(&idev->lock); +		list_for_each_entry(sp_ifa, &idev->addr_list, if_list) { + +			if (sp_ifa->flags & (IFA_F_DADFAILED | IFA_F_TENTATIVE)) +				continue; + +			sp_rt = addrconf_dst_alloc(idev, &sp_ifa->addr, 0); + +			/* Failure cases are ignored */ +			if (!IS_ERR(sp_rt)) +				ip6_ins_rt(sp_rt); +		} +		read_unlock_bh(&idev->lock); +	}  }  static void addrconf_add_linklocal(struct inet6_dev *idev, const struct in6_addr *addr) @@ -2961,7 +2986,7 @@ static int addrconf_ifdown(struct net_device *dev, int how)  		if (state != INET6_IFADDR_STATE_DEAD) {  			__ipv6_ifa_notify(RTM_DELADDR, ifa); -			atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa); +			inet6addr_notifier_call_chain(NETDEV_DOWN, ifa);  		}  		in6_ifa_put(ifa); @@ -4842,22 +4867,6 @@ static struct pernet_operations addrconf_ops = {  	.exit = addrconf_exit_net,  }; -/* - *      Device notifier - */ - -int register_inet6addr_notifier(struct notifier_block *nb) -{ -	return atomic_notifier_chain_register(&inet6addr_chain, nb); -} -EXPORT_SYMBOL(register_inet6addr_notifier); - -int unregister_inet6addr_notifier(struct notifier_block *nb) -{ -	return atomic_notifier_chain_unregister(&inet6addr_chain, nb); -} -EXPORT_SYMBOL(unregister_inet6addr_notifier); -  static struct rtnl_af_ops inet6_ops = {  	.family		  = AF_INET6,  	.fill_link_af	  = inet6_fill_link_af, diff --git a/net/ipv6/addrconf_core.c b/net/ipv6/addrconf_core.c index d051e5f4bf3..72104562c86 100644 --- a/net/ipv6/addrconf_core.c +++ b/net/ipv6/addrconf_core.c @@ -78,3 +78,22 @@ int __ipv6_addr_type(const struct in6_addr *addr)  }  EXPORT_SYMBOL(__ipv6_addr_type); +static ATOMIC_NOTIFIER_HEAD(inet6addr_chain); + +int register_inet6addr_notifier(struct notifier_block *nb) +{ +	return atomic_notifier_chain_register(&inet6addr_chain, nb); +} +EXPORT_SYMBOL(register_inet6addr_notifier); + +int unregister_inet6addr_notifier(struct notifier_block *nb) +{ +	return atomic_notifier_chain_unregister(&inet6addr_chain, nb); +} +EXPORT_SYMBOL(unregister_inet6addr_notifier); + +int inet6addr_notifier_call_chain(unsigned long val, void *v) +{ +	return atomic_notifier_call_chain(&inet6addr_chain, val, v); +} +EXPORT_SYMBOL(inet6addr_notifier_call_chain); diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index e33fe0ab256..2bab2aa5974 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c @@ -118,6 +118,18 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt  	    ipv6_addr_loopback(&hdr->daddr))  		goto err; +	/* RFC4291 Errata ID: 3480 +	 * Interface-Local scope spans only a single interface on a +	 * node and is useful only for loopback transmission of +	 * multicast.  Packets with interface-local scope received +	 * from another node must be discarded. +	 */ +	if (!(skb->pkt_type == PACKET_LOOPBACK || +	      dev->flags & IFF_LOOPBACK) && +	    ipv6_addr_is_multicast(&hdr->daddr) && +	    IPV6_ADDR_MC_SCOPE(&hdr->daddr) == 1) +		goto err; +  	/* RFC4291 2.7  	 * Nodes must not originate a packet to a multicast address whose scope  	 * field contains the reserved value 0; if such a packet is received, it diff --git a/net/ipv6/netfilter/ip6t_NPT.c b/net/ipv6/netfilter/ip6t_NPT.c index 33608c61027..cb631143721 100644 --- a/net/ipv6/netfilter/ip6t_NPT.c +++ b/net/ipv6/netfilter/ip6t_NPT.c @@ -57,7 +57,7 @@ static bool ip6t_npt_map_pfx(const struct ip6t_npt_tginfo *npt,  		if (pfx_len - i >= 32)  			mask = 0;  		else -			mask = htonl(~((1 << (pfx_len - i)) - 1)); +			mask = htonl((1 << (i - pfx_len + 32)) - 1);  		idx = i / 32;  		addr->s6_addr32[idx] &= mask; diff --git a/net/ipv6/netfilter/ip6t_rpfilter.c b/net/ipv6/netfilter/ip6t_rpfilter.c index 5060d54199a..e0983f3648a 100644 --- a/net/ipv6/netfilter/ip6t_rpfilter.c +++ b/net/ipv6/netfilter/ip6t_rpfilter.c @@ -71,6 +71,12 @@ static bool rpfilter_lookup_reverse6(const struct sk_buff *skb,  	return ret;  } +static bool rpfilter_is_local(const struct sk_buff *skb) +{ +	const struct rt6_info *rt = (const void *) skb_dst(skb); +	return rt && (rt->rt6i_flags & RTF_LOCAL); +} +  static bool rpfilter_mt(const struct sk_buff *skb, struct xt_action_param *par)  {  	const struct xt_rpfilter_info *info = par->matchinfo; @@ -78,7 +84,7 @@ static bool rpfilter_mt(const struct sk_buff *skb, struct xt_action_param *par)  	struct ipv6hdr *iph;  	bool invert = info->flags & XT_RPFILTER_INVERT; -	if (par->in->flags & IFF_LOOPBACK) +	if (rpfilter_is_local(skb))  		return true ^ invert;  	iph = ipv6_hdr(skb); diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 196ab9347ad..0ba10e53a62 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -330,9 +330,17 @@ found:  	}  	if (fq->q.last_in == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) && -	    fq->q.meat == fq->q.len) -		return ip6_frag_reasm(fq, prev, dev); +	    fq->q.meat == fq->q.len) { +		int res; +		unsigned long orefdst = skb->_skb_refdst; +		skb->_skb_refdst = 0UL; +		res = ip6_frag_reasm(fq, prev, dev); +		skb->_skb_refdst = orefdst; +		return res; +	} + +	skb_dst_drop(skb);  	inet_frag_lru_move(&fq->q);  	return -1; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index f6d629fd6ae..46a5be85be8 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -386,6 +386,7 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,  		if (dst)  			dst->ops->redirect(dst, sk, skb); +		goto out;  	}  	if (type == ICMPV6_PKT_TOOBIG) {  |