diff options
Diffstat (limited to 'net/ipv6')
39 files changed, 783 insertions, 501 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index cf88df82e2c..0ba0866230c 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -630,13 +630,13 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,  		goto out;  	} -	rt = addrconf_dst_alloc(idev, addr, 0); +	rt = addrconf_dst_alloc(idev, addr, false);  	if (IS_ERR(rt)) {  		err = PTR_ERR(rt);  		goto out;  	} -	ipv6_addr_copy(&ifa->addr, addr); +	ifa->addr = *addr;  	spin_lock_init(&ifa->lock);  	spin_lock_init(&ifa->state_lock); @@ -650,16 +650,6 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,  	ifa->rt = rt; -	/* -	 * part one of RFC 4429, section 3.3 -	 * We should not configure an address as -	 * optimistic if we do not yet know the link -	 * layer address of our nexhop router -	 */ - -	if (dst_get_neighbour_raw(&rt->dst) == NULL) -		ifa->flags &= ~IFA_F_OPTIMISTIC; -  	ifa->idev = idev;  	in6_dev_hold(idev);  	/* For caller */ @@ -807,7 +797,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)  				ip6_del_rt(rt);  				rt = NULL;  			} else if (!(rt->rt6i_flags & RTF_EXPIRES)) { -				rt->rt6i_expires = expires; +				rt->dst.expires = expires;  				rt->rt6i_flags |= RTF_EXPIRES;  			}  		} @@ -1228,7 +1218,7 @@ try_nextdev:  	if (!hiscore->ifa)  		return -EADDRNOTAVAIL; -	ipv6_addr_copy(saddr, &hiscore->ifa->addr); +	*saddr = hiscore->ifa->addr;  	in6_ifa_put(hiscore->ifa);  	return 0;  } @@ -1249,7 +1239,7 @@ int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr,  		list_for_each_entry(ifp, &idev->addr_list, if_list) {  			if (ifp->scope == IFA_LINK &&  			    !(ifp->flags & banned_flags)) { -				ipv6_addr_copy(addr, &ifp->addr); +				*addr = ifp->addr;  				err = 0;  				break;  			} @@ -1700,7 +1690,7 @@ addrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev,  		.fc_protocol = RTPROT_KERNEL,  	}; -	ipv6_addr_copy(&cfg.fc_dst, pfx); +	cfg.fc_dst = *pfx;  	/* Prevent useless cloning on PtP SIT.  	   This thing is done here expecting that the whole @@ -1733,7 +1723,7 @@ static struct rt6_info *addrconf_get_prefix_route(const struct in6_addr *pfx,  	if (!fn)  		goto out;  	for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) { -		if (rt->rt6i_dev->ifindex != dev->ifindex) +		if (rt->dst.dev->ifindex != dev->ifindex)  			continue;  		if ((rt->rt6i_flags & flags) != flags)  			continue; @@ -1805,14 +1795,15 @@ static struct inet6_dev *addrconf_add_dev(struct net_device *dev)  		return ERR_PTR(-EACCES);  	/* Add default multicast route */ -	addrconf_add_mroute(dev); +	if (!(dev->flags & IFF_LOOPBACK)) +		addrconf_add_mroute(dev);  	/* Add link local route */  	addrconf_add_lroute(dev);  	return idev;  } -void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len) +void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)  {  	struct prefix_info *pinfo;  	__u32 valid_lft; @@ -1890,11 +1881,11 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)  				rt = NULL;  			} else if (addrconf_finite_timeout(rt_expires)) {  				/* not infinity */ -				rt->rt6i_expires = jiffies + rt_expires; +				rt->dst.expires = jiffies + rt_expires;  				rt->rt6i_flags |= RTF_EXPIRES;  			} else {  				rt->rt6i_flags &= ~RTF_EXPIRES; -				rt->rt6i_expires = 0; +				rt->dst.expires = 0;  			}  		} else if (valid_lft) {  			clock_t expires = 0; @@ -1943,7 +1934,7 @@ ok:  #ifdef CONFIG_IPV6_OPTIMISTIC_DAD  			if (in6_dev->cnf.optimistic_dad && -			    !net->ipv6.devconf_all->forwarding) +			    !net->ipv6.devconf_all->forwarding && sllao)  				addr_flags = IFA_F_OPTIMISTIC;  #endif @@ -3077,20 +3068,39 @@ static void addrconf_dad_run(struct inet6_dev *idev)  struct if6_iter_state {  	struct seq_net_private p;  	int bucket; +	int offset;  }; -static struct inet6_ifaddr *if6_get_first(struct seq_file *seq) +static struct inet6_ifaddr *if6_get_first(struct seq_file *seq, loff_t pos)  {  	struct inet6_ifaddr *ifa = NULL;  	struct if6_iter_state *state = seq->private;  	struct net *net = seq_file_net(seq); +	int p = 0; + +	/* initial bucket if pos is 0 */ +	if (pos == 0) { +		state->bucket = 0; +		state->offset = 0; +	} -	for (state->bucket = 0; state->bucket < IN6_ADDR_HSIZE; ++state->bucket) { +	for (; state->bucket < IN6_ADDR_HSIZE; ++state->bucket) {  		struct hlist_node *n;  		hlist_for_each_entry_rcu_bh(ifa, n, &inet6_addr_lst[state->bucket], -					 addr_lst) +					 addr_lst) { +			/* sync with offset */ +			if (p < state->offset) { +				p++; +				continue; +			} +			state->offset++;  			if (net_eq(dev_net(ifa->idev->dev), net))  				return ifa; +		} + +		/* prepare for next bucket */ +		state->offset = 0; +		p = 0;  	}  	return NULL;  } @@ -3102,13 +3112,17 @@ static struct inet6_ifaddr *if6_get_next(struct seq_file *seq,  	struct net *net = seq_file_net(seq);  	struct hlist_node *n = &ifa->addr_lst; -	hlist_for_each_entry_continue_rcu_bh(ifa, n, addr_lst) +	hlist_for_each_entry_continue_rcu_bh(ifa, n, addr_lst) { +		state->offset++;  		if (net_eq(dev_net(ifa->idev->dev), net))  			return ifa; +	}  	while (++state->bucket < IN6_ADDR_HSIZE) { +		state->offset = 0;  		hlist_for_each_entry_rcu_bh(ifa, n,  				     &inet6_addr_lst[state->bucket], addr_lst) { +			state->offset++;  			if (net_eq(dev_net(ifa->idev->dev), net))  				return ifa;  		} @@ -3117,21 +3131,11 @@ static struct inet6_ifaddr *if6_get_next(struct seq_file *seq,  	return NULL;  } -static struct inet6_ifaddr *if6_get_idx(struct seq_file *seq, loff_t pos) -{ -	struct inet6_ifaddr *ifa = if6_get_first(seq); - -	if (ifa) -		while (pos && (ifa = if6_get_next(seq, ifa)) != NULL) -			--pos; -	return pos ? NULL : ifa; -} -  static void *if6_seq_start(struct seq_file *seq, loff_t *pos)  	__acquires(rcu_bh)  {  	rcu_read_lock_bh(); -	return if6_get_idx(seq, *pos); +	return if6_get_first(seq, *pos);  }  static void *if6_seq_next(struct seq_file *seq, void *v, loff_t *pos) diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index d27c797f9f0..273f48d1df2 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -347,7 +347,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)  			 */  			v4addr = LOOPBACK4_IPV6;  			if (!(addr_type & IPV6_ADDR_MULTICAST))	{ -				if (!inet->transparent && +				if (!(inet->freebind || inet->transparent) &&  				    !ipv6_chk_addr(net, &addr->sin6_addr,  						   dev, 0)) {  					err = -EADDRNOTAVAIL; @@ -361,10 +361,10 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)  	inet->inet_rcv_saddr = v4addr;  	inet->inet_saddr = v4addr; -	ipv6_addr_copy(&np->rcv_saddr, &addr->sin6_addr); +	np->rcv_saddr = addr->sin6_addr;  	if (!(addr_type & IPV6_ADDR_MULTICAST)) -		ipv6_addr_copy(&np->saddr, &addr->sin6_addr); +		np->saddr = addr->sin6_addr;  	/* Make sure we are allowed to bind here. */  	if (sk->sk_prot->get_port(sk, snum)) { @@ -458,14 +458,14 @@ int inet6_getname(struct socket *sock, struct sockaddr *uaddr,  		    peer == 1)  			return -ENOTCONN;  		sin->sin6_port = inet->inet_dport; -		ipv6_addr_copy(&sin->sin6_addr, &np->daddr); +		sin->sin6_addr = np->daddr;  		if (np->sndflow)  			sin->sin6_flowinfo = np->flow_label;  	} else {  		if (ipv6_addr_any(&np->rcv_saddr)) -			ipv6_addr_copy(&sin->sin6_addr, &np->saddr); +			sin->sin6_addr = np->saddr;  		else -			ipv6_addr_copy(&sin->sin6_addr, &np->rcv_saddr); +			sin->sin6_addr = np->rcv_saddr;  		sin->sin6_port = inet->inet_sport;  	} @@ -660,8 +660,8 @@ int inet6_sk_rebuild_header(struct sock *sk)  		memset(&fl6, 0, sizeof(fl6));  		fl6.flowi6_proto = sk->sk_protocol; -		ipv6_addr_copy(&fl6.daddr, &np->daddr); -		ipv6_addr_copy(&fl6.saddr, &np->saddr); +		fl6.daddr = np->daddr; +		fl6.saddr = np->saddr;  		fl6.flowlabel = np->flow_label;  		fl6.flowi6_oif = sk->sk_bound_dev_if;  		fl6.flowi6_mark = sk->sk_mark; @@ -769,7 +769,8 @@ out:  	return err;  } -static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, u32 features) +static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, +	netdev_features_t features)  {  	struct sk_buff *segs = ERR_PTR(-EINVAL);  	struct ipv6hdr *ipv6h; @@ -985,9 +986,9 @@ static int __net_init ipv6_init_mibs(struct net *net)  			  sizeof(struct icmpv6_mib),  			  __alignof__(struct icmpv6_mib)) < 0)  		goto err_icmp_mib; -	if (snmp_mib_init((void __percpu **)net->mib.icmpv6msg_statistics, -			  sizeof(struct icmpv6msg_mib), -			  __alignof__(struct icmpv6msg_mib)) < 0) +	net->mib.icmpv6msg_statistics = kzalloc(sizeof(struct icmpv6msg_mib), +						GFP_KERNEL); +	if (!net->mib.icmpv6msg_statistics)  		goto err_icmpmsg_mib;  	return 0; @@ -1008,7 +1009,7 @@ static void ipv6_cleanup_mibs(struct net *net)  	snmp_mib_free((void __percpu **)net->mib.udplite_stats_in6);  	snmp_mib_free((void __percpu **)net->mib.ipv6_statistics);  	snmp_mib_free((void __percpu **)net->mib.icmpv6_statistics); -	snmp_mib_free((void __percpu **)net->mib.icmpv6msg_statistics); +	kfree(net->mib.icmpv6msg_statistics);  }  static int __net_init inet6_net_init(struct net *net) @@ -1115,6 +1116,8 @@ static int __init inet6_init(void)  	if (err)  		goto static_sysctl_fail;  #endif +	tcpv6_prot.sysctl_mem = init_net.ipv4.sysctl_tcp_mem; +  	/*  	 *	ipngwg API draft makes clear that the correct semantics  	 *	for TCP and UDP is to consider one TCP and UDP instance diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index 4c0f894d084..2ae79dbeec2 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c @@ -193,9 +193,9 @@ static void ipv6_rearrange_destopt(struct ipv6hdr *iph, struct ipv6_opt_hdr *des  						printk(KERN_WARNING "destopt hao: invalid header length: %u\n", hao->length);  					goto bad;  				} -				ipv6_addr_copy(&final_addr, &hao->addr); -				ipv6_addr_copy(&hao->addr, &iph->saddr); -				ipv6_addr_copy(&iph->saddr, &final_addr); +				final_addr = hao->addr; +				hao->addr = iph->saddr; +				iph->saddr = final_addr;  			}  			break;  		} @@ -241,13 +241,13 @@ static void ipv6_rearrange_rthdr(struct ipv6hdr *iph, struct ipv6_rt_hdr *rthdr)  	segments = rthdr->hdrlen >> 1;  	addrs = ((struct rt0_hdr *)rthdr)->addr; -	ipv6_addr_copy(&final_addr, addrs + segments - 1); +	final_addr = addrs[segments - 1];  	addrs += segments - segments_left;  	memmove(addrs + 1, addrs, (segments_left - 1) * sizeof(*addrs)); -	ipv6_addr_copy(addrs, &iph->daddr); -	ipv6_addr_copy(&iph->daddr, &final_addr); +	addrs[0] = iph->daddr; +	iph->daddr = final_addr;  }  static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len, int dir) diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c index 674255f5e6b..59402b4637f 100644 --- a/net/ipv6/anycast.c +++ b/net/ipv6/anycast.c @@ -75,7 +75,7 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, const struct in6_addr *addr)  	if (pac == NULL)  		return -ENOMEM;  	pac->acl_next = NULL; -	ipv6_addr_copy(&pac->acl_addr, addr); +	pac->acl_addr = *addr;  	rcu_read_lock();  	if (ifindex == 0) { @@ -83,7 +83,7 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, const struct in6_addr *addr)  		rt = rt6_lookup(net, addr, NULL, 0, 0);  		if (rt) { -			dev = rt->rt6i_dev; +			dev = rt->dst.dev;  			dst_release(&rt->dst);  		} else if (ishost) {  			err = -EADDRNOTAVAIL; @@ -289,14 +289,14 @@ int ipv6_dev_ac_inc(struct net_device *dev, const struct in6_addr *addr)  		goto out;  	} -	rt = addrconf_dst_alloc(idev, addr, 1); +	rt = addrconf_dst_alloc(idev, addr, true);  	if (IS_ERR(rt)) {  		kfree(aca);  		err = PTR_ERR(rt);  		goto out;  	} -	ipv6_addr_copy(&aca->aca_addr, addr); +	aca->aca_addr = *addr;  	aca->aca_idev = idev;  	aca->aca_rt = rt;  	aca->aca_users = 1; diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index e2480691c22..ae08aee1773 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -71,7 +71,7 @@ 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; -			ipv6_addr_copy(&usin->sin6_addr, &flowlabel->dst); +			usin->sin6_addr = flowlabel->dst;  		}  	} @@ -143,7 +143,7 @@ ipv4_connected:  		}  	} -	ipv6_addr_copy(&np->daddr, daddr); +	np->daddr = *daddr;  	np->flow_label = fl6.flowlabel;  	inet->inet_dport = usin->sin6_port; @@ -154,8 +154,8 @@ ipv4_connected:  	 */  	fl6.flowi6_proto = sk->sk_protocol; -	ipv6_addr_copy(&fl6.daddr, &np->daddr); -	ipv6_addr_copy(&fl6.saddr, &np->saddr); +	fl6.daddr = np->daddr; +	fl6.saddr = np->saddr;  	fl6.flowi6_oif = sk->sk_bound_dev_if;  	fl6.flowi6_mark = sk->sk_mark;  	fl6.fl6_dport = inet->inet_dport; @@ -179,10 +179,10 @@ ipv4_connected:  	/* source address lookup done in ip6_dst_lookup */  	if (ipv6_addr_any(&np->saddr)) -		ipv6_addr_copy(&np->saddr, &fl6.saddr); +		np->saddr = fl6.saddr;  	if (ipv6_addr_any(&np->rcv_saddr)) { -		ipv6_addr_copy(&np->rcv_saddr, &fl6.saddr); +		np->rcv_saddr = fl6.saddr;  		inet->inet_rcv_saddr = LOOPBACK4_IPV6;  		if (sk->sk_prot->rehash)  			sk->sk_prot->rehash(sk); @@ -257,7 +257,7 @@ void ipv6_local_error(struct sock *sk, int err, struct flowi6 *fl6, u32 info)  	skb_put(skb, sizeof(struct ipv6hdr));  	skb_reset_network_header(skb);  	iph = ipv6_hdr(skb); -	ipv6_addr_copy(&iph->daddr, &fl6->daddr); +	iph->daddr = fl6->daddr;  	serr = SKB_EXT_ERR(skb);  	serr->ee.ee_errno = err; @@ -294,7 +294,7 @@ void ipv6_local_rxpmtu(struct sock *sk, struct flowi6 *fl6, u32 mtu)  	skb_put(skb, sizeof(struct ipv6hdr));  	skb_reset_network_header(skb);  	iph = ipv6_hdr(skb); -	ipv6_addr_copy(&iph->daddr, &fl6->daddr); +	iph->daddr = fl6->daddr;  	mtu_info = IP6CBMTU(skb); @@ -303,7 +303,7 @@ void ipv6_local_rxpmtu(struct sock *sk, struct flowi6 *fl6, u32 mtu)  	mtu_info->ip6m_addr.sin6_port = 0;  	mtu_info->ip6m_addr.sin6_flowinfo = 0;  	mtu_info->ip6m_addr.sin6_scope_id = fl6->flowi6_oif; -	ipv6_addr_copy(&mtu_info->ip6m_addr.sin6_addr, &ipv6_hdr(skb)->daddr); +	mtu_info->ip6m_addr.sin6_addr = ipv6_hdr(skb)->daddr;  	__skb_pull(skb, skb_tail_pointer(skb) - skb->data);  	skb_reset_transport_header(skb); @@ -354,8 +354,8 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len)  		sin->sin6_port = serr->port;  		sin->sin6_scope_id = 0;  		if (skb->protocol == htons(ETH_P_IPV6)) { -			ipv6_addr_copy(&sin->sin6_addr, -				  (struct in6_addr *)(nh + serr->addr_offset)); +			sin->sin6_addr = +				*(struct in6_addr *)(nh + serr->addr_offset);  			if (np->sndflow)  				sin->sin6_flowinfo =  					(*(__be32 *)(nh + serr->addr_offset - 24) & @@ -376,7 +376,7 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len)  		sin->sin6_flowinfo = 0;  		sin->sin6_scope_id = 0;  		if (skb->protocol == htons(ETH_P_IPV6)) { -			ipv6_addr_copy(&sin->sin6_addr, &ipv6_hdr(skb)->saddr); +			sin->sin6_addr = ipv6_hdr(skb)->saddr;  			if (np->rxopt.all)  				datagram_recv_ctl(sk, msg, skb);  			if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL) @@ -451,7 +451,7 @@ int ipv6_recv_rxpmtu(struct sock *sk, struct msghdr *msg, int len)  		sin->sin6_flowinfo = 0;  		sin->sin6_port = 0;  		sin->sin6_scope_id = mtu_info.ip6m_addr.sin6_scope_id; -		ipv6_addr_copy(&sin->sin6_addr, &mtu_info.ip6m_addr.sin6_addr); +		sin->sin6_addr = mtu_info.ip6m_addr.sin6_addr;  	}  	put_cmsg(msg, SOL_IPV6, IPV6_PATHMTU, sizeof(mtu_info), &mtu_info); @@ -475,7 +475,7 @@ int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)  		struct in6_pktinfo src_info;  		src_info.ipi6_ifindex = opt->iif; -		ipv6_addr_copy(&src_info.ipi6_addr, &ipv6_hdr(skb)->daddr); +		src_info.ipi6_addr = ipv6_hdr(skb)->daddr;  		put_cmsg(msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info);  	} @@ -550,7 +550,7 @@ int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)  		struct in6_pktinfo src_info;  		src_info.ipi6_ifindex = opt->iif; -		ipv6_addr_copy(&src_info.ipi6_addr, &ipv6_hdr(skb)->daddr); +		src_info.ipi6_addr = ipv6_hdr(skb)->daddr;  		put_cmsg(msg, SOL_IPV6, IPV6_2292PKTINFO, sizeof(src_info), &src_info);  	}  	if (np->rxopt.bits.rxohlim) { @@ -584,7 +584,7 @@ int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)  			 */  			sin6.sin6_family = AF_INET6; -			ipv6_addr_copy(&sin6.sin6_addr, &ipv6_hdr(skb)->daddr); +			sin6.sin6_addr = ipv6_hdr(skb)->daddr;  			sin6.sin6_port = ports[1];  			sin6.sin6_flowinfo = 0;  			sin6.sin6_scope_id = 0; @@ -654,12 +654,12 @@ int datagram_send_ctl(struct net *net, struct sock *sk,  			if (addr_type != IPV6_ADDR_ANY) {  				int strict = __ipv6_addr_src_scope(addr_type) <= IPV6_ADDR_SCOPE_LINKLOCAL; -				if (!inet_sk(sk)->transparent && +				if (!(inet_sk(sk)->freebind || inet_sk(sk)->transparent) &&  				    !ipv6_chk_addr(net, &src_info->ipi6_addr,  						   strict ? dev : NULL, 0))  					err = -EINVAL;  				else -					ipv6_addr_copy(&fl6->saddr, &src_info->ipi6_addr); +					fl6->saddr = src_info->ipi6_addr;  			}  			rcu_read_unlock(); diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index bf22a225f42..3d641b6e9b0 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c @@ -243,9 +243,9 @@ static int ipv6_dest_hao(struct sk_buff *skb, int optoff)  	if (skb->ip_summed == CHECKSUM_COMPLETE)  		skb->ip_summed = CHECKSUM_NONE; -	ipv6_addr_copy(&tmp_addr, &ipv6h->saddr); -	ipv6_addr_copy(&ipv6h->saddr, &hao->addr); -	ipv6_addr_copy(&hao->addr, &tmp_addr); +	tmp_addr = ipv6h->saddr; +	ipv6h->saddr = hao->addr; +	hao->addr = tmp_addr;  	if (skb->tstamp.tv64 == 0)  		__net_timestamp(skb); @@ -461,9 +461,9 @@ looped_back:  		return -1;  	} -	ipv6_addr_copy(&daddr, addr); -	ipv6_addr_copy(addr, &ipv6_hdr(skb)->daddr); -	ipv6_addr_copy(&ipv6_hdr(skb)->daddr, &daddr); +	daddr = *addr; +	*addr = ipv6_hdr(skb)->daddr; +	ipv6_hdr(skb)->daddr = daddr;  	skb_dst_drop(skb);  	ip6_route_input(skb); @@ -690,7 +690,7 @@ static void ipv6_push_rthdr(struct sk_buff *skb, u8 *proto,  		memcpy(phdr->addr, ihdr->addr + 1,  		       (hops - 1) * sizeof(struct in6_addr)); -	ipv6_addr_copy(phdr->addr + (hops - 1), *addr_p); +	phdr->addr[hops - 1] = **addr_p;  	*addr_p = ihdr->addr;  	phdr->rt_hdr.nexthdr = *proto; @@ -888,8 +888,8 @@ struct in6_addr *fl6_update_dst(struct flowi6 *fl6,  	if (!opt || !opt->srcrt)  		return NULL; -	ipv6_addr_copy(orig, &fl6->daddr); -	ipv6_addr_copy(&fl6->daddr, ((struct rt0_hdr *)opt->srcrt)->addr); +	*orig = fl6->daddr; +	fl6->daddr = *((struct rt0_hdr *)opt->srcrt)->addr;  	return orig;  } diff --git a/net/ipv6/exthdrs_core.c b/net/ipv6/exthdrs_core.c index 37f548b7f6d..72957f4a7c6 100644 --- a/net/ipv6/exthdrs_core.c +++ b/net/ipv6/exthdrs_core.c @@ -57,6 +57,9 @@ int ipv6_ext_hdr(u8 nexthdr)   *	    it returns NULL.   *	  - First fragment header is skipped, not-first ones   *	    are considered as unparsable. + *	  - Reports the offset field of the final fragment header so it is + *	    possible to tell whether this is a first fragment, later fragment, + *	    or not fragmented.   *	  - ESP is unparsable for now and considered like   *	    normal payload protocol.   *	  - Note also special handling of AUTH header. Thanks to IPsec wizards. @@ -64,10 +67,13 @@ int ipv6_ext_hdr(u8 nexthdr)   * --ANK (980726)   */ -int ipv6_skip_exthdr(const struct sk_buff *skb, int start, u8 *nexthdrp) +int ipv6_skip_exthdr(const struct sk_buff *skb, int start, u8 *nexthdrp, +		     __be16 *frag_offp)  {  	u8 nexthdr = *nexthdrp; +	*frag_offp = 0; +  	while (ipv6_ext_hdr(nexthdr)) {  		struct ipv6_opt_hdr _hdr, *hp;  		int hdrlen; @@ -87,7 +93,8 @@ int ipv6_skip_exthdr(const struct sk_buff *skb, int start, u8 *nexthdrp)  			if (fp == NULL)  				return -1; -			if (ntohs(*fp) & ~0x7) +			*frag_offp = *fp; +			if (ntohs(*frag_offp) & ~0x7)  				break;  			hdrlen = 8;  		} else if (nexthdr == NEXTHDR_AUTH) diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index 295571576f8..b6c57315206 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c @@ -96,7 +96,7 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp,  			if (!ipv6_prefix_equal(&saddr, &r->src.addr,  					       r->src.plen))  				goto again; -			ipv6_addr_copy(&flp6->saddr, &saddr); +			flp6->saddr = saddr;  		}  		goto out;  	} diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 90868fb4275..01d46bff63c 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -135,11 +135,12 @@ static int is_ineligible(struct sk_buff *skb)  	int ptr = (u8 *)(ipv6_hdr(skb) + 1) - skb->data;  	int len = skb->len - ptr;  	__u8 nexthdr = ipv6_hdr(skb)->nexthdr; +	__be16 frag_off;  	if (len < 0)  		return 1; -	ptr = ipv6_skip_exthdr(skb, ptr, &nexthdr); +	ptr = ipv6_skip_exthdr(skb, ptr, &nexthdr, &frag_off);  	if (ptr < 0)  		return 0;  	if (nexthdr == IPPROTO_ICMPV6) { @@ -290,9 +291,9 @@ static void mip6_addr_swap(struct sk_buff *skb)  		if (likely(off >= 0)) {  			hao = (struct ipv6_destopt_hao *)  					(skb_network_header(skb) + off); -			ipv6_addr_copy(&tmp, &iph->saddr); -			ipv6_addr_copy(&iph->saddr, &hao->addr); -			ipv6_addr_copy(&hao->addr, &tmp); +			tmp = iph->saddr; +			iph->saddr = hao->addr; +			hao->addr = tmp;  		}  	}  } @@ -444,9 +445,9 @@ void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)  	memset(&fl6, 0, sizeof(fl6));  	fl6.flowi6_proto = IPPROTO_ICMPV6; -	ipv6_addr_copy(&fl6.daddr, &hdr->saddr); +	fl6.daddr = hdr->saddr;  	if (saddr) -		ipv6_addr_copy(&fl6.saddr, saddr); +		fl6.saddr = *saddr;  	fl6.flowi6_oif = iif;  	fl6.fl6_icmp_type = type;  	fl6.fl6_icmp_code = code; @@ -538,9 +539,9 @@ static void icmpv6_echo_reply(struct sk_buff *skb)  	memset(&fl6, 0, sizeof(fl6));  	fl6.flowi6_proto = IPPROTO_ICMPV6; -	ipv6_addr_copy(&fl6.daddr, &ipv6_hdr(skb)->saddr); +	fl6.daddr = ipv6_hdr(skb)->saddr;  	if (saddr) -		ipv6_addr_copy(&fl6.saddr, saddr); +		fl6.saddr = *saddr;  	fl6.flowi6_oif = skb->dev->ifindex;  	fl6.fl6_icmp_type = ICMPV6_ECHO_REPLY;  	security_skb_classify_flow(skb, flowi6_to_flowi(&fl6)); @@ -596,6 +597,7 @@ static void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info)  	int inner_offset;  	int hash;  	u8 nexthdr; +	__be16 frag_off;  	if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))  		return; @@ -603,7 +605,8 @@ static void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info)  	nexthdr = ((struct ipv6hdr *)skb->data)->nexthdr;  	if (ipv6_ext_hdr(nexthdr)) {  		/* now skip over extension headers */ -		inner_offset = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr); +		inner_offset = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), +						&nexthdr, &frag_off);  		if (inner_offset<0)  			return;  	} else { @@ -786,8 +789,8 @@ void icmpv6_flow_init(struct sock *sk, struct flowi6 *fl6,  		      int oif)  {  	memset(fl6, 0, sizeof(*fl6)); -	ipv6_addr_copy(&fl6->saddr, saddr); -	ipv6_addr_copy(&fl6->daddr, daddr); +	fl6->saddr = *saddr; +	fl6->daddr = *daddr;  	fl6->flowi6_proto 	= IPPROTO_ICMPV6;  	fl6->fl6_icmp_type	= type;  	fl6->fl6_icmp_code	= 0; diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c index 1567fb12039..02dd203d9ea 100644 --- a/net/ipv6/inet6_connection_sock.c +++ b/net/ipv6/inet6_connection_sock.c @@ -65,9 +65,9 @@ struct dst_entry *inet6_csk_route_req(struct sock *sk,  	memset(&fl6, 0, sizeof(fl6));  	fl6.flowi6_proto = IPPROTO_TCP; -	ipv6_addr_copy(&fl6.daddr, &treq->rmt_addr); +	fl6.daddr = treq->rmt_addr;  	final_p = fl6_update_dst(&fl6, np->opt, &final); -	ipv6_addr_copy(&fl6.saddr, &treq->loc_addr); +	fl6.saddr = treq->loc_addr;  	fl6.flowi6_oif = sk->sk_bound_dev_if;  	fl6.flowi6_mark = sk->sk_mark;  	fl6.fl6_dport = inet_rsk(req)->rmt_port; @@ -157,7 +157,7 @@ void inet6_csk_addr2sockaddr(struct sock *sk, struct sockaddr * uaddr)  	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) uaddr;  	sin6->sin6_family = AF_INET6; -	ipv6_addr_copy(&sin6->sin6_addr, &np->daddr); +	sin6->sin6_addr = np->daddr;  	sin6->sin6_port	= inet_sk(sk)->inet_dport;  	/* We do not store received flowlabel for TCP */  	sin6->sin6_flowinfo = 0; @@ -215,8 +215,8 @@ int inet6_csk_xmit(struct sk_buff *skb, struct flowi *fl_unused)  	memset(&fl6, 0, sizeof(fl6));  	fl6.flowi6_proto = sk->sk_protocol; -	ipv6_addr_copy(&fl6.daddr, &np->daddr); -	ipv6_addr_copy(&fl6.saddr, &np->saddr); +	fl6.daddr = np->daddr; +	fl6.saddr = np->saddr;  	fl6.flowlabel = np->flow_label;  	IP6_ECN_flow_xmit(sk, fl6.flowlabel);  	fl6.flowi6_oif = sk->sk_bound_dev_if; @@ -246,7 +246,7 @@ int inet6_csk_xmit(struct sk_buff *skb, struct flowi *fl_unused)  	skb_dst_set_noref(skb, dst);  	/* Restore final destination back after routing done */ -	ipv6_addr_copy(&fl6.daddr, &np->daddr); +	fl6.daddr = np->daddr;  	res = ip6_xmit(sk, skb, &fl6, np->opt, np->tclass);  	rcu_read_unlock(); diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 93718f3db79..b82bcde53f7 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -190,7 +190,7 @@ static struct fib6_table *fib6_alloc_table(struct net *net, u32 id)  	struct fib6_table *table;  	table = kzalloc(sizeof(*table), GFP_ATOMIC); -	if (table != NULL) { +	if (table) {  		table->tb6_id = id;  		table->tb6_root.leaf = net->ipv6.ip6_null_entry;  		table->tb6_root.fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO; @@ -210,7 +210,7 @@ struct fib6_table *fib6_new_table(struct net *net, u32 id)  		return tb;  	tb = fib6_alloc_table(net, id); -	if (tb != NULL) +	if (tb)  		fib6_link_table(net, tb);  	return tb; @@ -367,7 +367,7 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)  	s_e = cb->args[1];  	w = (void *)cb->args[2]; -	if (w == NULL) { +	if (!w) {  		/* New dump:  		 *  		 * 1. hook callback destructor. @@ -379,7 +379,7 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)  		 * 2. allocate and initialize walker.  		 */  		w = kzalloc(sizeof(*w), GFP_ATOMIC); -		if (w == NULL) +		if (!w)  			return -ENOMEM;  		w->func = fib6_dump_node;  		cb->args[2] = (long)w; @@ -425,7 +425,8 @@ out:  static struct fib6_node * fib6_add_1(struct fib6_node *root, void *addr,  				     int addrlen, int plen, -				     int offset) +				     int offset, int allow_create, +				     int replace_required)  {  	struct fib6_node *fn, *in, *ln;  	struct fib6_node *pn = NULL; @@ -447,8 +448,18 @@ static struct fib6_node * fib6_add_1(struct fib6_node *root, void *addr,  		 *	Prefix match  		 */  		if (plen < fn->fn_bit || -		    !ipv6_prefix_equal(&key->addr, addr, fn->fn_bit)) +		    !ipv6_prefix_equal(&key->addr, addr, fn->fn_bit)) { +			if (!allow_create) { +				if (replace_required) { +					pr_warn("IPv6: Can't replace route, " +						"no match found\n"); +					return ERR_PTR(-ENOENT); +				} +				pr_warn("IPv6: NLM_F_CREATE should be set " +					"when creating new route\n"); +			}  			goto insert_above; +		}  		/*  		 *	Exact match ? @@ -456,7 +467,7 @@ static struct fib6_node * fib6_add_1(struct fib6_node *root, void *addr,  		if (plen == fn->fn_bit) {  			/* clean up an intermediate node */ -			if ((fn->fn_flags & RTN_RTINFO) == 0) { +			if (!(fn->fn_flags & RTN_RTINFO)) {  				rt6_release(fn->leaf);  				fn->leaf = NULL;  			} @@ -477,6 +488,23 @@ static struct fib6_node * fib6_add_1(struct fib6_node *root, void *addr,  		fn = dir ? fn->right: fn->left;  	} while (fn); +	if (!allow_create) { +		/* We should not create new node because +		 * NLM_F_REPLACE was specified without NLM_F_CREATE +		 * I assume it is safe to require NLM_F_CREATE when +		 * REPLACE flag is used! Later we may want to remove the +		 * check for replace_required, because according +		 * to netlink specification, NLM_F_CREATE +		 * MUST be specified if new route is created. +		 * That would keep IPv6 consistent with IPv4 +		 */ +		if (replace_required) { +			pr_warn("IPv6: Can't replace route, no match found\n"); +			return ERR_PTR(-ENOENT); +		} +		pr_warn("IPv6: NLM_F_CREATE should be set " +			"when creating new route\n"); +	}  	/*  	 *	We walked to the bottom of tree.  	 *	Create new leaf node without children. @@ -484,7 +512,7 @@ static struct fib6_node * fib6_add_1(struct fib6_node *root, void *addr,  	ln = node_alloc(); -	if (ln == NULL) +	if (!ln)  		return NULL;  	ln->fn_bit = plen; @@ -527,7 +555,7 @@ insert_above:  		in = node_alloc();  		ln = node_alloc(); -		if (in == NULL || ln == NULL) { +		if (!in || !ln) {  			if (in)  				node_free(in);  			if (ln) @@ -581,7 +609,7 @@ insert_above:  		ln = node_alloc(); -		if (ln == NULL) +		if (!ln)  			return NULL;  		ln->fn_bit = plen; @@ -614,10 +642,15 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,  {  	struct rt6_info *iter = NULL;  	struct rt6_info **ins; +	int replace = (info->nlh && +		       (info->nlh->nlmsg_flags & NLM_F_REPLACE)); +	int add = (!info->nlh || +		   (info->nlh->nlmsg_flags & NLM_F_CREATE)); +	int found = 0;  	ins = &fn->leaf; -	for (iter = fn->leaf; iter; iter=iter->dst.rt6_next) { +	for (iter = fn->leaf; iter; iter = iter->dst.rt6_next) {  		/*  		 *	Search for duplicates  		 */ @@ -626,17 +659,24 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,  			/*  			 *	Same priority level  			 */ +			if (info->nlh && +			    (info->nlh->nlmsg_flags & NLM_F_EXCL)) +				return -EEXIST; +			if (replace) { +				found++; +				break; +			} -			if (iter->rt6i_dev == rt->rt6i_dev && +			if (iter->dst.dev == rt->dst.dev &&  			    iter->rt6i_idev == rt->rt6i_idev &&  			    ipv6_addr_equal(&iter->rt6i_gateway,  					    &rt->rt6i_gateway)) { -				if (!(iter->rt6i_flags&RTF_EXPIRES)) +				if (!(iter->rt6i_flags & RTF_EXPIRES))  					return -EEXIST; -				iter->rt6i_expires = rt->rt6i_expires; -				if (!(rt->rt6i_flags&RTF_EXPIRES)) { +				iter->dst.expires = rt->dst.expires; +				if (!(rt->rt6i_flags & RTF_EXPIRES)) {  					iter->rt6i_flags &= ~RTF_EXPIRES; -					iter->rt6i_expires = 0; +					iter->dst.expires = 0;  				}  				return -EEXIST;  			} @@ -655,17 +695,40 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,  	/*  	 *	insert node  	 */ +	if (!replace) { +		if (!add) +			pr_warn("IPv6: NLM_F_CREATE should be set when creating new route\n"); -	rt->dst.rt6_next = iter; -	*ins = rt; -	rt->rt6i_node = fn; -	atomic_inc(&rt->rt6i_ref); -	inet6_rt_notify(RTM_NEWROUTE, rt, info); -	info->nl_net->ipv6.rt6_stats->fib_rt_entries++; +add: +		rt->dst.rt6_next = iter; +		*ins = rt; +		rt->rt6i_node = fn; +		atomic_inc(&rt->rt6i_ref); +		inet6_rt_notify(RTM_NEWROUTE, rt, info); +		info->nl_net->ipv6.rt6_stats->fib_rt_entries++; -	if ((fn->fn_flags & RTN_RTINFO) == 0) { -		info->nl_net->ipv6.rt6_stats->fib_route_nodes++; -		fn->fn_flags |= RTN_RTINFO; +		if (!(fn->fn_flags & RTN_RTINFO)) { +			info->nl_net->ipv6.rt6_stats->fib_route_nodes++; +			fn->fn_flags |= RTN_RTINFO; +		} + +	} else { +		if (!found) { +			if (add) +				goto add; +			pr_warn("IPv6: NLM_F_REPLACE set, but no existing node found!\n"); +			return -ENOENT; +		} +		*ins = rt; +		rt->rt6i_node = fn; +		rt->dst.rt6_next = iter->dst.rt6_next; +		atomic_inc(&rt->rt6i_ref); +		inet6_rt_notify(RTM_NEWROUTE, rt, info); +		rt6_release(iter); +		if (!(fn->fn_flags & RTN_RTINFO)) { +			info->nl_net->ipv6.rt6_stats->fib_route_nodes++; +			fn->fn_flags |= RTN_RTINFO; +		}  	}  	return 0; @@ -674,7 +737,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,  static __inline__ void fib6_start_gc(struct net *net, struct rt6_info *rt)  {  	if (!timer_pending(&net->ipv6.ip6_fib_timer) && -	    (rt->rt6i_flags & (RTF_EXPIRES|RTF_CACHE))) +	    (rt->rt6i_flags & (RTF_EXPIRES | RTF_CACHE)))  		mod_timer(&net->ipv6.ip6_fib_timer,  			  jiffies + net->ipv6.sysctl.ip6_rt_gc_interval);  } @@ -696,11 +759,28 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info)  {  	struct fib6_node *fn, *pn = NULL;  	int err = -ENOMEM; +	int allow_create = 1; +	int replace_required = 0; + +	if (info->nlh) { +		if (!(info->nlh->nlmsg_flags & NLM_F_CREATE)) +			allow_create = 0; +		if (info->nlh->nlmsg_flags & NLM_F_REPLACE) +			replace_required = 1; +	} +	if (!allow_create && !replace_required) +		pr_warn("IPv6: RTM_NEWROUTE with no NLM_F_CREATE or NLM_F_REPLACE\n");  	fn = fib6_add_1(root, &rt->rt6i_dst.addr, sizeof(struct in6_addr), -			rt->rt6i_dst.plen, offsetof(struct rt6_info, rt6i_dst)); +			rt->rt6i_dst.plen, offsetof(struct rt6_info, rt6i_dst), +			allow_create, replace_required); + +	if (IS_ERR(fn)) { +		err = PTR_ERR(fn); +		fn = NULL; +	} -	if (fn == NULL) +	if (!fn)  		goto out;  	pn = fn; @@ -709,7 +789,7 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info)  	if (rt->rt6i_src.plen) {  		struct fib6_node *sn; -		if (fn->subtree == NULL) { +		if (!fn->subtree) {  			struct fib6_node *sfn;  			/* @@ -724,7 +804,7 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info)  			/* Create subtree root node */  			sfn = node_alloc(); -			if (sfn == NULL) +			if (!sfn)  				goto st_failure;  			sfn->leaf = info->nl_net->ipv6.ip6_null_entry; @@ -736,9 +816,10 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info)  			sn = fib6_add_1(sfn, &rt->rt6i_src.addr,  					sizeof(struct in6_addr), rt->rt6i_src.plen, -					offsetof(struct rt6_info, rt6i_src)); +					offsetof(struct rt6_info, rt6i_src), +					allow_create, replace_required); -			if (sn == NULL) { +			if (!sn) {  				/* If it is failed, discard just allocated  				   root, and then (in st_failure) stale node  				   in main tree. @@ -753,13 +834,18 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info)  		} else {  			sn = fib6_add_1(fn->subtree, &rt->rt6i_src.addr,  					sizeof(struct in6_addr), rt->rt6i_src.plen, -					offsetof(struct rt6_info, rt6i_src)); +					offsetof(struct rt6_info, rt6i_src), +					allow_create, replace_required); -			if (sn == NULL) +			if (IS_ERR(sn)) { +				err = PTR_ERR(sn); +				sn = NULL; +			} +			if (!sn)  				goto st_failure;  		} -		if (fn->leaf == NULL) { +		if (!fn->leaf) {  			fn->leaf = rt;  			atomic_inc(&rt->rt6i_ref);  		} @@ -768,10 +854,9 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info)  #endif  	err = fib6_add_rt2node(fn, rt, info); - -	if (err == 0) { +	if (!err) {  		fib6_start_gc(info->nl_net, rt); -		if (!(rt->rt6i_flags&RTF_CACHE)) +		if (!(rt->rt6i_flags & RTF_CACHE))  			fib6_prune_clones(info->nl_net, pn, rt);  	} @@ -819,7 +904,7 @@ st_failure:   */  struct lookup_args { -	int		offset;		/* key offset on rt6_info	*/ +	int			offset;		/* key offset on rt6_info	*/  	const struct in6_addr	*addr;		/* search key			*/  }; @@ -849,11 +934,10 @@ static struct fib6_node * fib6_lookup_1(struct fib6_node *root,  			fn = next;  			continue;  		} -  		break;  	} -	while(fn) { +	while (fn) {  		if (FIB6_SUBTREE(fn) || fn->fn_flags & RTN_RTINFO) {  			struct rt6key *key; @@ -900,8 +984,7 @@ struct fib6_node * fib6_lookup(struct fib6_node *root, const struct in6_addr *da  	};  	fn = fib6_lookup_1(root, daddr ? args : args + 1); - -	if (fn == NULL || fn->fn_flags & RTN_TL_ROOT) +	if (!fn || fn->fn_flags & RTN_TL_ROOT)  		fn = root;  	return fn; @@ -961,7 +1044,7 @@ struct fib6_node * fib6_locate(struct fib6_node *root,  	}  #endif -	if (fn && fn->fn_flags&RTN_RTINFO) +	if (fn && fn->fn_flags & RTN_RTINFO)  		return fn;  	return NULL; @@ -975,14 +1058,13 @@ struct fib6_node * fib6_locate(struct fib6_node *root,  static struct rt6_info *fib6_find_prefix(struct net *net, struct fib6_node *fn)  { -	if (fn->fn_flags&RTN_ROOT) +	if (fn->fn_flags & RTN_ROOT)  		return net->ipv6.ip6_null_entry; -	while(fn) { -		if(fn->left) +	while (fn) { +		if (fn->left)  			return fn->left->leaf; - -		if(fn->right) +		if (fn->right)  			return fn->right->leaf;  		fn = FIB6_SUBTREE(fn); @@ -1020,12 +1102,12 @@ static struct fib6_node *fib6_repair_tree(struct net *net,  		if (children == 3 || FIB6_SUBTREE(fn)  #ifdef CONFIG_IPV6_SUBTREES  		    /* Subtree root (i.e. fn) may have one child */ -		    || (children && fn->fn_flags&RTN_ROOT) +		    || (children && fn->fn_flags & RTN_ROOT)  #endif  		    ) {  			fn->leaf = fib6_find_prefix(net, fn);  #if RT6_DEBUG >= 2 -			if (fn->leaf==NULL) { +			if (!fn->leaf) {  				WARN_ON(!fn->leaf);  				fn->leaf = net->ipv6.ip6_null_entry;  			} @@ -1058,7 +1140,7 @@ static struct fib6_node *fib6_repair_tree(struct net *net,  		read_lock(&fib6_walker_lock);  		FOR_WALKERS(w) { -			if (child == NULL) { +			if (!child) {  				if (w->root == fn) {  					w->root = w->node = NULL;  					RT6_TRACE("W %p adjusted by delroot 1\n", w); @@ -1087,7 +1169,7 @@ static struct fib6_node *fib6_repair_tree(struct net *net,  		read_unlock(&fib6_walker_lock);  		node_free(fn); -		if (pn->fn_flags&RTN_RTINFO || FIB6_SUBTREE(pn)) +		if (pn->fn_flags & RTN_RTINFO || FIB6_SUBTREE(pn))  			return pn;  		rt6_release(pn->leaf); @@ -1121,7 +1203,7 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp,  		if (w->state == FWS_C && w->leaf == rt) {  			RT6_TRACE("walker %p adjusted by delroute\n", w);  			w->leaf = rt->dst.rt6_next; -			if (w->leaf == NULL) +			if (!w->leaf)  				w->state = FWS_U;  		}  	} @@ -1130,7 +1212,7 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp,  	rt->dst.rt6_next = NULL;  	/* If it was last route, expunge its radix tree node */ -	if (fn->leaf == NULL) { +	if (!fn->leaf) {  		fn->fn_flags &= ~RTN_RTINFO;  		net->ipv6.rt6_stats->fib_route_nodes--;  		fn = fib6_repair_tree(net, fn); @@ -1144,7 +1226,7 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp,  		 * to still alive ones.  		 */  		while (fn) { -			if (!(fn->fn_flags&RTN_RTINFO) && fn->leaf == rt) { +			if (!(fn->fn_flags & RTN_RTINFO) && fn->leaf == rt) {  				fn->leaf = fib6_find_prefix(net, fn);  				atomic_inc(&fn->leaf->rt6i_ref);  				rt6_release(rt); @@ -1171,17 +1253,17 @@ int fib6_del(struct rt6_info *rt, struct nl_info *info)  		return -ENOENT;  	}  #endif -	if (fn == NULL || rt == net->ipv6.ip6_null_entry) +	if (!fn || rt == net->ipv6.ip6_null_entry)  		return -ENOENT;  	WARN_ON(!(fn->fn_flags & RTN_RTINFO)); -	if (!(rt->rt6i_flags&RTF_CACHE)) { +	if (!(rt->rt6i_flags & RTF_CACHE)) {  		struct fib6_node *pn = fn;  #ifdef CONFIG_IPV6_SUBTREES  		/* clones of this route might be in another subtree */  		if (rt->rt6i_src.plen) { -			while (!(pn->fn_flags&RTN_ROOT)) +			while (!(pn->fn_flags & RTN_ROOT))  				pn = pn->parent;  			pn = pn->parent;  		} @@ -1232,11 +1314,11 @@ static int fib6_walk_continue(struct fib6_walker_t *w)  	for (;;) {  		fn = w->node; -		if (fn == NULL) +		if (!fn)  			return 0;  		if (w->prune && fn != w->root && -		    fn->fn_flags&RTN_RTINFO && w->state < FWS_C) { +		    fn->fn_flags & RTN_RTINFO && w->state < FWS_C) {  			w->state = FWS_C;  			w->leaf = fn->leaf;  		} @@ -1265,7 +1347,7 @@ static int fib6_walk_continue(struct fib6_walker_t *w)  			w->state = FWS_C;  			w->leaf = fn->leaf;  		case FWS_C: -			if (w->leaf && fn->fn_flags&RTN_RTINFO) { +			if (w->leaf && fn->fn_flags & RTN_RTINFO) {  				int err;  				if (w->count < w->skip) { @@ -1380,6 +1462,26 @@ static void fib6_clean_tree(struct net *net, struct fib6_node *root,  	fib6_walk(&c.w);  } +void fib6_clean_all_ro(struct net *net, int (*func)(struct rt6_info *, void *arg), +		    int prune, void *arg) +{ +	struct fib6_table *table; +	struct hlist_node *node; +	struct hlist_head *head; +	unsigned int h; + +	rcu_read_lock(); +	for (h = 0; h < FIB6_TABLE_HASHSZ; h++) { +		head = &net->ipv6.fib_table_hash[h]; +		hlist_for_each_entry_rcu(table, node, head, tb6_hlist) { +			read_lock_bh(&table->tb6_lock); +			fib6_clean_tree(net, &table->tb6_root, +					func, prune, arg); +			read_unlock_bh(&table->tb6_lock); +		} +	} +	rcu_read_unlock(); +}  void fib6_clean_all(struct net *net, int (*func)(struct rt6_info *, void *arg),  		    int prune, void *arg)  { @@ -1439,8 +1541,8 @@ static int fib6_age(struct rt6_info *rt, void *arg)  	 *	only if they are not in use now.  	 */ -	if (rt->rt6i_flags&RTF_EXPIRES && rt->rt6i_expires) { -		if (time_after(now, rt->rt6i_expires)) { +	if (rt->rt6i_flags & RTF_EXPIRES && rt->dst.expires) { +		if (time_after(now, rt->dst.expires)) {  			RT6_TRACE("expiring %p\n", rt);  			return -1;  		} @@ -1451,7 +1553,7 @@ static int fib6_age(struct rt6_info *rt, void *arg)  			RT6_TRACE("aging clone %p\n", rt);  			return -1;  		} else if ((rt->rt6i_flags & RTF_GATEWAY) && -			   (!(dst_get_neighbour_raw(&rt->dst)->flags & NTF_ROUTER))) { +			   (!(dst_get_neighbour_noref_raw(&rt->dst)->flags & NTF_ROUTER))) {  			RT6_TRACE("purging route %p via non-router but gateway\n",  				  rt);  			return -1; diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index 4566dbd916d..b7867a1215b 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c @@ -386,7 +386,7 @@ fl_create(struct net *net, struct sock *sk, struct in6_flowlabel_req *freq,  		err = -EINVAL;  		goto done;  	} -	ipv6_addr_copy(&fl->dst, &freq->flr_dst); +	fl->dst = freq->flr_dst;  	atomic_set(&fl->users, 1);  	switch (fl->share) {  	case IPV6_FL_S_EXCL: diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index a46c64eb0a6..1ca5d45a12e 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c @@ -280,6 +280,7 @@ int ip6_mc_input(struct sk_buff *skb)  			u8 *ptr = skb_network_header(skb) + opt->ra;  			struct icmp6hdr *icmp6;  			u8 nexthdr = hdr->nexthdr; +			__be16 frag_off;  			int offset;  			/* Check if the value of Router Alert @@ -293,7 +294,7 @@ int ip6_mc_input(struct sk_buff *skb)  					goto out;  				}  				offset = ipv6_skip_exthdr(skb, sizeof(*hdr), -							  &nexthdr); +							  &nexthdr, &frag_off);  				if (offset < 0)  					goto out; diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 84d0bd5cac9..d97e07183ce 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -136,7 +136,7 @@ static int ip6_finish_output2(struct sk_buff *skb)  	}  	rcu_read_lock(); -	neigh = dst_get_neighbour(dst); +	neigh = dst_get_neighbour_noref(dst);  	if (neigh) {  		int res = neigh_output(neigh, skb); @@ -238,8 +238,8 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,  	hdr->nexthdr = proto;  	hdr->hop_limit = hlimit; -	ipv6_addr_copy(&hdr->saddr, &fl6->saddr); -	ipv6_addr_copy(&hdr->daddr, first_hop); +	hdr->saddr = fl6->saddr; +	hdr->daddr = *first_hop;  	skb->priority = sk->sk_priority;  	skb->mark = sk->sk_mark; @@ -290,8 +290,8 @@ int ip6_nd_hdr(struct sock *sk, struct sk_buff *skb, struct net_device *dev,  	hdr->nexthdr = proto;  	hdr->hop_limit = np->hop_limit; -	ipv6_addr_copy(&hdr->saddr, saddr); -	ipv6_addr_copy(&hdr->daddr, daddr); +	hdr->saddr = *saddr; +	hdr->daddr = *daddr;  	return 0;  } @@ -329,10 +329,11 @@ static int ip6_forward_proxy_check(struct sk_buff *skb)  {  	struct ipv6hdr *hdr = ipv6_hdr(skb);  	u8 nexthdr = hdr->nexthdr; +	__be16 frag_off;  	int offset;  	if (ipv6_ext_hdr(nexthdr)) { -		offset = ipv6_skip_exthdr(skb, sizeof(*hdr), &nexthdr); +		offset = ipv6_skip_exthdr(skb, sizeof(*hdr), &nexthdr, &frag_off);  		if (offset < 0)  			return 0;  	} else @@ -462,7 +463,7 @@ int ip6_forward(struct sk_buff *skb)  	   send redirects to source routed frames.  	   We don't send redirects to frames decapsulated from IPsec.  	 */ -	n = dst_get_neighbour(dst); +	n = dst_get_neighbour_noref(dst);  	if (skb->dev == dst->dev && n && opt->srcrt == 0 && !skb_sec_path(skb)) {  		struct in6_addr *target = NULL;  		struct rt6_info *rt; @@ -603,7 +604,7 @@ void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt)  	static atomic_t ipv6_fragmentation_id;  	int old, new; -	if (rt) { +	if (rt && !(rt->dst.flags & DST_NOPEER)) {  		struct inet_peer *peer;  		if (!rt->rt6i_peer) @@ -631,6 +632,7 @@ int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))  	struct ipv6hdr *tmp_hdr;  	struct frag_hdr *fh;  	unsigned int mtu, hlen, left, len; +	int hroom, troom;  	__be32 frag_id = 0;  	int ptr, offset = 0, err=0;  	u8 *prevhdr, nexthdr = 0; @@ -797,6 +799,8 @@ slow_path:  	 */  	*prevhdr = NEXTHDR_FRAGMENT; +	hroom = LL_RESERVED_SPACE(rt->dst.dev); +	troom = rt->dst.dev->needed_tailroom;  	/*  	 *	Keep copying data until we run out. @@ -815,7 +819,8 @@ slow_path:  		 *	Allocate buffer.  		 */ -		if ((frag = alloc_skb(len+hlen+sizeof(struct frag_hdr)+LL_ALLOCATED_SPACE(rt->dst.dev), GFP_ATOMIC)) == NULL) { +		if ((frag = alloc_skb(len + hlen + sizeof(struct frag_hdr) + +				      hroom + troom, GFP_ATOMIC)) == NULL) {  			NETDEBUG(KERN_INFO "IPv6: frag: no memory for new fragment!\n");  			IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),  				      IPSTATS_MIB_FRAGFAILS); @@ -828,7 +833,7 @@ slow_path:  		 */  		ip6_copy_metadata(frag, skb); -		skb_reserve(frag, LL_RESERVED_SPACE(rt->dst.dev)); +		skb_reserve(frag, hroom);  		skb_put(frag, len + hlen + sizeof(struct frag_hdr));  		skb_reset_network_header(frag);  		fh = (struct frag_hdr *)(skb_network_header(frag) + hlen); @@ -978,7 +983,7 @@ static int ip6_dst_lookup_tail(struct sock *sk,  	 * dst entry of the nexthop router  	 */  	rcu_read_lock(); -	n = dst_get_neighbour(*dst); +	n = dst_get_neighbour_noref(*dst);  	if (n && !(n->nud_state & NUD_VALID)) {  		struct inet6_ifaddr *ifp;  		struct flowi6 fl_gw6; @@ -1059,7 +1064,7 @@ struct dst_entry *ip6_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6,  	if (err)  		return ERR_PTR(err);  	if (final_dst) -		ipv6_addr_copy(&fl6->daddr, final_dst); +		fl6->daddr = *final_dst;  	if (can_sleep)  		fl6->flowi6_flags |= FLOWI_FLAG_CAN_SLEEP; @@ -1095,7 +1100,7 @@ struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6,  	if (err)  		return ERR_PTR(err);  	if (final_dst) -		ipv6_addr_copy(&fl6->daddr, final_dst); +		fl6->daddr = *final_dst;  	if (can_sleep)  		fl6->flowi6_flags |= FLOWI_FLAG_CAN_SLEEP; @@ -1588,7 +1593,7 @@ int ip6_push_pending_frames(struct sock *sk)  	if (np->pmtudisc < IPV6_PMTUDISC_DO)  		skb->local_df = 1; -	ipv6_addr_copy(final_dst, &fl6->daddr); +	*final_dst = fl6->daddr;  	__skb_pull(skb, skb_network_header_len(skb));  	if (opt && opt->opt_flen)  		ipv6_push_frag_opts(skb, opt, &proto); @@ -1604,8 +1609,8 @@ int ip6_push_pending_frames(struct sock *sk)  	hdr->hop_limit = np->cork.hop_limit;  	hdr->nexthdr = proto; -	ipv6_addr_copy(&hdr->saddr, &fl6->saddr); -	ipv6_addr_copy(&hdr->daddr, final_dst); +	hdr->saddr = fl6->saddr; +	hdr->daddr = *final_dst;  	skb->priority = sk->sk_priority;  	skb->mark = sk->sk_mark; diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 4e2e9ff67ef..e1f7761815f 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -93,7 +93,7 @@ struct pcpu_tstats {  	unsigned long	rx_bytes;  	unsigned long	tx_packets;  	unsigned long	tx_bytes; -}; +} __attribute__((aligned(4*sizeof(unsigned long))));  static struct net_device_stats *ip6_get_stats(struct net_device *dev)  { @@ -653,8 +653,8 @@ ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,  		rt = rt6_lookup(dev_net(skb->dev), &ipv6_hdr(skb2)->saddr,  				NULL, 0, 0); -		if (rt && rt->rt6i_dev) -			skb2->dev = rt->rt6i_dev; +		if (rt && rt->dst.dev) +			skb2->dev = rt->dst.dev;  		icmpv6_send(skb2, rel_type, rel_code, rel_info); @@ -979,8 +979,8 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,  	ipv6_change_dsfield(ipv6h, ~INET_ECN_MASK, dsfield);  	ipv6h->hop_limit = t->parms.hop_limit;  	ipv6h->nexthdr = proto; -	ipv6_addr_copy(&ipv6h->saddr, &fl6->saddr); -	ipv6_addr_copy(&ipv6h->daddr, &fl6->daddr); +	ipv6h->saddr = fl6->saddr; +	ipv6h->daddr = fl6->daddr;  	nf_reset(skb);  	pkt_len = skb->len;  	err = ip6_local_out(skb); @@ -1155,8 +1155,8 @@ static void ip6_tnl_link_config(struct ip6_tnl *t)  	memcpy(dev->broadcast, &p->raddr, sizeof(struct in6_addr));  	/* Set up flowi template */ -	ipv6_addr_copy(&fl6->saddr, &p->laddr); -	ipv6_addr_copy(&fl6->daddr, &p->raddr); +	fl6->saddr = p->laddr; +	fl6->daddr = p->raddr;  	fl6->flowi6_oif = p->link;  	fl6->flowlabel = 0; @@ -1185,11 +1185,11 @@ static void ip6_tnl_link_config(struct ip6_tnl *t)  		if (rt == NULL)  			return; -		if (rt->rt6i_dev) { -			dev->hard_header_len = rt->rt6i_dev->hard_header_len + +		if (rt->dst.dev) { +			dev->hard_header_len = rt->dst.dev->hard_header_len +  				sizeof (struct ipv6hdr); -			dev->mtu = rt->rt6i_dev->mtu - sizeof (struct ipv6hdr); +			dev->mtu = rt->dst.dev->mtu - sizeof (struct ipv6hdr);  			if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))  				dev->mtu-=8; @@ -1212,8 +1212,8 @@ static void ip6_tnl_link_config(struct ip6_tnl *t)  static int  ip6_tnl_change(struct ip6_tnl *t, struct ip6_tnl_parm *p)  { -	ipv6_addr_copy(&t->parms.laddr, &p->laddr); -	ipv6_addr_copy(&t->parms.raddr, &p->raddr); +	t->parms.laddr = p->laddr; +	t->parms.raddr = p->raddr;  	t->parms.flags = p->flags;  	t->parms.hop_limit = p->hop_limit;  	t->parms.encap_limit = p->encap_limit; diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 449a9185b8f..c7e95c8c579 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -1105,8 +1105,8 @@ static int ip6mr_cache_report(struct mr6_table *mrt, struct sk_buff *pkt,  		msg->im6_msgtype = MRT6MSG_WHOLEPKT;  		msg->im6_mif = mrt->mroute_reg_vif_num;  		msg->im6_pad = 0; -		ipv6_addr_copy(&msg->im6_src, &ipv6_hdr(pkt)->saddr); -		ipv6_addr_copy(&msg->im6_dst, &ipv6_hdr(pkt)->daddr); +		msg->im6_src = ipv6_hdr(pkt)->saddr; +		msg->im6_dst = ipv6_hdr(pkt)->daddr;  		skb->ip_summed = CHECKSUM_UNNECESSARY;  	} else @@ -1131,8 +1131,8 @@ static int ip6mr_cache_report(struct mr6_table *mrt, struct sk_buff *pkt,  	msg->im6_msgtype = assert;  	msg->im6_mif = mifi;  	msg->im6_pad = 0; -	ipv6_addr_copy(&msg->im6_src, &ipv6_hdr(pkt)->saddr); -	ipv6_addr_copy(&msg->im6_dst, &ipv6_hdr(pkt)->daddr); +	msg->im6_src = ipv6_hdr(pkt)->saddr; +	msg->im6_dst = ipv6_hdr(pkt)->daddr;  	skb_dst_set(skb, dst_clone(skb_dst(pkt)));  	skb->ip_summed = CHECKSUM_UNNECESSARY; @@ -2181,8 +2181,8 @@ int ip6mr_get_route(struct net *net,  		iph->payload_len = 0;  		iph->nexthdr = IPPROTO_NONE;  		iph->hop_limit = 0; -		ipv6_addr_copy(&iph->saddr, &rt->rt6i_src.addr); -		ipv6_addr_copy(&iph->daddr, &rt->rt6i_dst.addr); +		iph->saddr = rt->rt6i_src.addr; +		iph->daddr = rt->rt6i_dst.addr;  		err = ip6mr_cache_unresolved(mrt, vif, skb2);  		read_unlock(&mrt_lock); diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 26cb08c84b7..18a2719003c 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -435,7 +435,7 @@ sticky_done:  			goto e_inval;  		np->sticky_pktinfo.ipi6_ifindex = pkt.ipi6_ifindex; -		ipv6_addr_copy(&np->sticky_pktinfo.ipi6_addr, &pkt.ipi6_addr); +		np->sticky_pktinfo.ipi6_addr = pkt.ipi6_addr;  		retv = 0;  		break;  	} @@ -980,8 +980,7 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,  				struct in6_pktinfo src_info;  				src_info.ipi6_ifindex = np->mcast_oif ? np->mcast_oif :  					np->sticky_pktinfo.ipi6_ifindex; -				np->mcast_oif? ipv6_addr_copy(&src_info.ipi6_addr, &np->daddr) : -					ipv6_addr_copy(&src_info.ipi6_addr, &(np->sticky_pktinfo.ipi6_addr)); +				src_info.ipi6_addr = np->mcast_oif ? np->daddr : np->sticky_pktinfo.ipi6_addr;  				put_cmsg(&msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info);  			}  			if (np->rxopt.bits.rxhlim) { @@ -992,8 +991,7 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,  				struct in6_pktinfo src_info;  				src_info.ipi6_ifindex = np->mcast_oif ? np->mcast_oif :  					np->sticky_pktinfo.ipi6_ifindex; -				np->mcast_oif? ipv6_addr_copy(&src_info.ipi6_addr, &np->daddr) : -					ipv6_addr_copy(&src_info.ipi6_addr, &(np->sticky_pktinfo.ipi6_addr)); +				src_info.ipi6_addr = np->mcast_oif ? np->daddr : np->sticky_pktinfo.ipi6_addr;  				put_cmsg(&msg, SOL_IPV6, IPV6_2292PKTINFO, sizeof(src_info), &src_info);  			}  			if (np->rxopt.bits.rxohlim) { diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index ee7839f4d6e..b853f06cc14 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -155,14 +155,14 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)  		return -ENOMEM;  	mc_lst->next = NULL; -	ipv6_addr_copy(&mc_lst->addr, addr); +	mc_lst->addr = *addr;  	rcu_read_lock();  	if (ifindex == 0) {  		struct rt6_info *rt;  		rt = rt6_lookup(net, addr, NULL, 0, 0);  		if (rt) { -			dev = rt->rt6i_dev; +			dev = rt->dst.dev;  			dst_release(&rt->dst);  		}  	} else @@ -256,7 +256,7 @@ static struct inet6_dev *ip6_mc_find_dev_rcu(struct net *net,  		struct rt6_info *rt = rt6_lookup(net, group, NULL, 0, 0);  		if (rt) { -			dev = rt->rt6i_dev; +			dev = rt->dst.dev;  			dev_hold(dev);  			dst_release(&rt->dst);  		} @@ -858,7 +858,7 @@ int ipv6_dev_mc_inc(struct net_device *dev, const struct in6_addr *addr)  	setup_timer(&mc->mca_timer, igmp6_timer_handler, (unsigned long)mc); -	ipv6_addr_copy(&mc->mca_addr, addr); +	mc->mca_addr = *addr;  	mc->idev = idev; /* (reference taken) */  	mc->mca_users = 1;  	/* mca_stamp should be updated upon changes */ @@ -1343,13 +1343,15 @@ static struct sk_buff *mld_newpack(struct net_device *dev, int size)  	struct mld2_report *pmr;  	struct in6_addr addr_buf;  	const struct in6_addr *saddr; +	int hlen = LL_RESERVED_SPACE(dev); +	int tlen = dev->needed_tailroom;  	int err;  	u8 ra[8] = { IPPROTO_ICMPV6, 0,  		     IPV6_TLV_ROUTERALERT, 2, 0, 0,  		     IPV6_TLV_PADN, 0 };  	/* we assume size > sizeof(ra) here */ -	size += LL_ALLOCATED_SPACE(dev); +	size += hlen + tlen;  	/* limit our allocations to order-0 page */  	size = min_t(int, size, SKB_MAX_ORDER(0, 0));  	skb = sock_alloc_send_skb(sk, size, 1, &err); @@ -1357,7 +1359,7 @@ static struct sk_buff *mld_newpack(struct net_device *dev, int size)  	if (!skb)  		return NULL; -	skb_reserve(skb, LL_RESERVED_SPACE(dev)); +	skb_reserve(skb, hlen);  	if (ipv6_get_lladdr(dev, &addr_buf, IFA_F_TENTATIVE)) {  		/* <draft-ietf-magma-mld-source-05.txt>: @@ -1408,18 +1410,11 @@ static void mld_sendpack(struct sk_buff *skb)  					   csum_partial(skb_transport_header(skb),  							mldlen, 0)); -	dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr); - -	if (!dst) { -		err = -ENOMEM; -		goto err_out; -	} -  	icmpv6_flow_init(net->ipv6.igmp_sk, &fl6, ICMPV6_MLD2_REPORT,  			 &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,  			 skb->dev->ifindex); +	dst = icmp6_dst_alloc(skb->dev, NULL, &fl6); -	dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0);  	err = 0;  	if (IS_ERR(dst)) {  		err = PTR_ERR(dst); @@ -1723,6 +1718,8 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)  	struct mld_msg *hdr;  	const struct in6_addr *snd_addr, *saddr;  	struct in6_addr addr_buf; +	int hlen = LL_RESERVED_SPACE(dev); +	int tlen = dev->needed_tailroom;  	int err, len, payload_len, full_len;  	u8 ra[8] = { IPPROTO_ICMPV6, 0,  		     IPV6_TLV_ROUTERALERT, 2, 0, 0, @@ -1744,7 +1741,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)  		      IPSTATS_MIB_OUT, full_len);  	rcu_read_unlock(); -	skb = sock_alloc_send_skb(sk, LL_ALLOCATED_SPACE(dev) + full_len, 1, &err); +	skb = sock_alloc_send_skb(sk, hlen + tlen + full_len, 1, &err);  	if (skb == NULL) {  		rcu_read_lock(); @@ -1754,7 +1751,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)  		return;  	} -	skb_reserve(skb, LL_RESERVED_SPACE(dev)); +	skb_reserve(skb, hlen);  	if (ipv6_get_lladdr(dev, &addr_buf, IFA_F_TENTATIVE)) {  		/* <draft-ietf-magma-mld-source-05.txt>: @@ -1772,7 +1769,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)  	hdr = (struct mld_msg *) skb_put(skb, sizeof(struct mld_msg));  	memset(hdr, 0, sizeof(struct mld_msg));  	hdr->mld_type = type; -	ipv6_addr_copy(&hdr->mld_mca, addr); +	hdr->mld_mca = *addr;  	hdr->mld_cksum = csum_ipv6_magic(saddr, snd_addr, len,  					 IPPROTO_ICMPV6, @@ -1781,17 +1778,10 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)  	rcu_read_lock();  	idev = __in6_dev_get(skb->dev); -	dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr); -	if (!dst) { -		err = -ENOMEM; -		goto err_out; -	} -  	icmpv6_flow_init(sk, &fl6, type,  			 &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,  			 skb->dev->ifindex); - -	dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0); +	dst = icmp6_dst_alloc(skb->dev, NULL, &fl6);  	if (IS_ERR(dst)) {  		err = PTR_ERR(dst);  		goto err_out; @@ -1914,7 +1904,7 @@ static int ip6_mc_del_src(struct inet6_dev *idev, const struct in6_addr *pmca,   * Add multicast single-source filter to the interface list   */  static int ip6_mc_add1_src(struct ifmcaddr6 *pmc, int sfmode, -	const struct in6_addr *psfsrc, int delta) +	const struct in6_addr *psfsrc)  {  	struct ip6_sf_list *psf, *psf_prev; @@ -2045,7 +2035,7 @@ static int ip6_mc_add_src(struct inet6_dev *idev, const struct in6_addr *pmca,  		pmc->mca_sfcount[sfmode]++;  	err = 0;  	for (i=0; i<sfcount; i++) { -		err = ip6_mc_add1_src(pmc, sfmode, &psfsrc[i], delta); +		err = ip6_mc_add1_src(pmc, sfmode, &psfsrc[i]);  		if (err)  			break;  	} diff --git a/net/ipv6/mip6.c b/net/ipv6/mip6.c index 43242e6e610..7e1e0fbfef2 100644 --- a/net/ipv6/mip6.c +++ b/net/ipv6/mip6.c @@ -195,8 +195,8 @@ static inline int mip6_report_rl_allow(struct timeval *stamp,  		mip6_report_rl.stamp.tv_sec = stamp->tv_sec;  		mip6_report_rl.stamp.tv_usec = stamp->tv_usec;  		mip6_report_rl.iif = iif; -		ipv6_addr_copy(&mip6_report_rl.src, src); -		ipv6_addr_copy(&mip6_report_rl.dst, dst); +		mip6_report_rl.src = *src; +		mip6_report_rl.dst = *dst;  		allow = 1;  	}  	spin_unlock_bh(&mip6_report_rl.lock); diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 0cb78d7ddaf..d8f02ef88e5 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -93,7 +93,7 @@  static u32 ndisc_hash(const void *pkey,  		      const struct net_device *dev, -		      __u32 rnd); +		      __u32 *hash_rnd);  static int ndisc_constructor(struct neighbour *neigh);  static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb);  static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb); @@ -126,7 +126,6 @@ static const struct neigh_ops ndisc_direct_ops = {  struct neigh_table nd_tbl = {  	.family =	AF_INET6, -	.entry_size =	sizeof(struct neighbour) + sizeof(struct in6_addr),  	.key_len =	sizeof(struct in6_addr),  	.hash =		ndisc_hash,  	.constructor =	ndisc_constructor, @@ -141,7 +140,7 @@ struct neigh_table nd_tbl = {  		.gc_staletime		= 60 * HZ,  		.reachable_time		= ND_REACHABLE_TIME,  		.delay_probe_time	= 5 * HZ, -		.queue_len		= 3, +		.queue_len_bytes	= 64*1024,  		.ucast_probes		= 3,  		.mcast_probes		= 3,  		.anycast_delay		= 1 * HZ, @@ -350,16 +349,9 @@ EXPORT_SYMBOL(ndisc_mc_map);  static u32 ndisc_hash(const void *pkey,  		      const struct net_device *dev, -		      __u32 hash_rnd) +		      __u32 *hash_rnd)  { -	const u32 *p32 = pkey; -	u32 addr_hash, i; - -	addr_hash = 0; -	for (i = 0; i < (sizeof(struct in6_addr) / sizeof(u32)); i++) -		addr_hash ^= *p32++; - -	return jhash_2words(addr_hash, dev->ifindex, hash_rnd); +	return ndisc_hashfn(pkey, dev, hash_rnd);  }  static int ndisc_constructor(struct neighbour *neigh) @@ -446,6 +438,8 @@ struct sk_buff *ndisc_build_skb(struct net_device *dev,  	struct sock *sk = net->ipv6.ndisc_sk;  	struct sk_buff *skb;  	struct icmp6hdr *hdr; +	int hlen = LL_RESERVED_SPACE(dev); +	int tlen = dev->needed_tailroom;  	int len;  	int err;  	u8 *opt; @@ -459,7 +453,7 @@ struct sk_buff *ndisc_build_skb(struct net_device *dev,  	skb = sock_alloc_send_skb(sk,  				  (MAX_HEADER + sizeof(struct ipv6hdr) + -				   len + LL_ALLOCATED_SPACE(dev)), +				   len + hlen + tlen),  				  1, &err);  	if (!skb) {  		ND_PRINTK0(KERN_ERR @@ -468,7 +462,7 @@ struct sk_buff *ndisc_build_skb(struct net_device *dev,  		return NULL;  	} -	skb_reserve(skb, LL_RESERVED_SPACE(dev)); +	skb_reserve(skb, hlen);  	ip6_nd_hdr(sk, skb, dev, saddr, daddr, IPPROTO_ICMPV6, len);  	skb->transport_header = skb->tail; @@ -479,7 +473,7 @@ struct sk_buff *ndisc_build_skb(struct net_device *dev,  	opt = skb_transport_header(skb) + sizeof(struct icmp6hdr);  	if (target) { -		ipv6_addr_copy((struct in6_addr *)opt, target); +		*(struct in6_addr *)opt = *target;  		opt += sizeof(*target);  	} @@ -515,14 +509,7 @@ void ndisc_send_skb(struct sk_buff *skb,  	type = icmp6h->icmp6_type;  	icmpv6_flow_init(sk, &fl6, type, saddr, daddr, dev->ifindex); - -	dst = icmp6_dst_alloc(dev, neigh, daddr); -	if (!dst) { -		kfree_skb(skb); -		return; -	} - -	dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0); +	dst = icmp6_dst_alloc(dev, neigh, &fl6);  	if (IS_ERR(dst)) {  		kfree_skb(skb);  		return; @@ -1237,7 +1224,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)  	rt = rt6_get_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev);  	if (rt) -		neigh = dst_get_neighbour(&rt->dst); +		neigh = dst_get_neighbour_noref(&rt->dst);  	if (rt && lifetime == 0) {  		neigh_clone(neigh); @@ -1257,7 +1244,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)  			return;  		} -		neigh = dst_get_neighbour(&rt->dst); +		neigh = dst_get_neighbour_noref(&rt->dst);  		if (neigh == NULL) {  			ND_PRINTK0(KERN_ERR  				   "ICMPv6 RA: %s() got default router without neighbour.\n", @@ -1271,7 +1258,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)  	}  	if (rt) -		rt->rt6i_expires = jiffies + (HZ * lifetime); +		rt->dst.expires = jiffies + (HZ * lifetime);  	if (ra_msg->icmph.icmp6_hop_limit) {  		in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit; @@ -1381,7 +1368,9 @@ skip_routeinfo:  		for (p = ndopts.nd_opts_pi;  		     p;  		     p = ndisc_next_option(p, ndopts.nd_opts_pi_end)) { -			addrconf_prefix_rcv(skb->dev, (u8*)p, (p->nd_opt_len) << 3); +			addrconf_prefix_rcv(skb->dev, (u8 *)p, +					    (p->nd_opt_len) << 3, +					    ndopts.nd_opts_src_lladdr != NULL);  		}  	} @@ -1533,6 +1522,7 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,  	struct inet6_dev *idev;  	struct flowi6 fl6;  	u8 *opt; +	int hlen, tlen;  	int rd_len;  	int err;  	u8 ha_buf[MAX_ADDR_LEN], *ha = NULL; @@ -1590,9 +1580,11 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,  	rd_len &= ~0x7;  	len += rd_len; +	hlen = LL_RESERVED_SPACE(dev); +	tlen = dev->needed_tailroom;  	buff = sock_alloc_send_skb(sk,  				   (MAX_HEADER + sizeof(struct ipv6hdr) + -				    len + LL_ALLOCATED_SPACE(dev)), +				    len + hlen + tlen),  				   1, &err);  	if (buff == NULL) {  		ND_PRINTK0(KERN_ERR @@ -1601,7 +1593,7 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,  		goto release;  	} -	skb_reserve(buff, LL_RESERVED_SPACE(dev)); +	skb_reserve(buff, hlen);  	ip6_nd_hdr(sk, buff, dev, &saddr_buf, &ipv6_hdr(skb)->saddr,  		   IPPROTO_ICMPV6, len); @@ -1617,9 +1609,9 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,  	 */  	addrp = (struct in6_addr *)(icmph + 1); -	ipv6_addr_copy(addrp, target); +	*addrp = *target;  	addrp++; -	ipv6_addr_copy(addrp, &ipv6_hdr(skb)->daddr); +	*addrp = ipv6_hdr(skb)->daddr;  	opt = (u8*) (addrp + 1); diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig index f792b34cbe9..9a68fb5b9e7 100644 --- a/net/ipv6/netfilter/Kconfig +++ b/net/ipv6/netfilter/Kconfig @@ -125,6 +125,16 @@ config IP6_NF_MATCH_MH  	  To compile it as a module, choose M here.  If unsure, say N. +config IP6_NF_MATCH_RPFILTER +	tristate '"rpfilter" reverse path filter match support' +	depends on NETFILTER_ADVANCED +	---help--- +	  This option allows you to match packets whose replies would +	  go out via the interface the packet came in. + +	  To compile it as a module, choose M here.  If unsure, say N. +	  The module will be called ip6t_rpfilter. +  config IP6_NF_MATCH_RT  	tristate '"rt" Routing header match support'  	depends on NETFILTER_ADVANCED diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile index abfee91ce81..2eaed96db02 100644 --- a/net/ipv6/netfilter/Makefile +++ b/net/ipv6/netfilter/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_IP6_NF_MATCH_FRAG) += ip6t_frag.o  obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o  obj-$(CONFIG_IP6_NF_MATCH_MH) += ip6t_mh.o  obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o +obj-$(CONFIG_IP6_NF_MATCH_RPFILTER) += ip6t_rpfilter.o  obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o  # targets diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index e63c3972a73..fb80a23c664 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c @@ -405,6 +405,7 @@ __ipq_rcv_skb(struct sk_buff *skb)  	int status, type, pid, flags;  	unsigned int nlmsglen, skblen;  	struct nlmsghdr *nlh; +	bool enable_timestamp = false;  	skblen = skb->len;  	if (skblen < sizeof(*nlh)) @@ -442,11 +443,13 @@ __ipq_rcv_skb(struct sk_buff *skb)  			RCV_SKB_FAIL(-EBUSY);  		}  	} else { -		net_enable_timestamp(); +		enable_timestamp = true;  		peer_pid = pid;  	}  	spin_unlock_bh(&queue_lock); +	if (enable_timestamp) +		net_enable_timestamp();  	status = ipq_receive_peer(NLMSG_DATA(nlh), type,  				  nlmsglen - NLMSG_LENGTH(0)); diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c index a5a4c5dd539..aad2fa41cf4 100644 --- a/net/ipv6/netfilter/ip6t_REJECT.c +++ b/net/ipv6/netfilter/ip6t_REJECT.c @@ -49,6 +49,7 @@ static void send_reset(struct net *net, struct sk_buff *oldskb)  	const __u8 tclass = DEFAULT_TOS_VALUE;  	struct dst_entry *dst = NULL;  	u8 proto; +	__be16 frag_off;  	struct flowi6 fl6;  	if ((!(ipv6_addr_type(&oip6h->saddr) & IPV6_ADDR_UNICAST)) || @@ -58,7 +59,7 @@ static void send_reset(struct net *net, struct sk_buff *oldskb)  	}  	proto = oip6h->nexthdr; -	tcphoff = ipv6_skip_exthdr(oldskb, ((u8*)(oip6h+1) - oldskb->data), &proto); +	tcphoff = ipv6_skip_exthdr(oldskb, ((u8*)(oip6h+1) - oldskb->data), &proto, &frag_off);  	if ((tcphoff < 0) || (tcphoff > oldskb->len)) {  		pr_debug("Cannot get TCP header.\n"); @@ -93,8 +94,8 @@ static void send_reset(struct net *net, struct sk_buff *oldskb)  	memset(&fl6, 0, sizeof(fl6));  	fl6.flowi6_proto = IPPROTO_TCP; -	ipv6_addr_copy(&fl6.saddr, &oip6h->daddr); -	ipv6_addr_copy(&fl6.daddr, &oip6h->saddr); +	fl6.saddr = oip6h->daddr; +	fl6.daddr = oip6h->saddr;  	fl6.fl6_sport = otcph.dest;  	fl6.fl6_dport = otcph.source;  	security_skb_classify_flow(oldskb, flowi6_to_flowi(&fl6)); @@ -129,8 +130,8 @@ static void send_reset(struct net *net, struct sk_buff *oldskb)  	*(__be32 *)ip6h =  htonl(0x60000000 | (tclass << 20));  	ip6h->hop_limit = ip6_dst_hoplimit(dst);  	ip6h->nexthdr = IPPROTO_TCP; -	ipv6_addr_copy(&ip6h->saddr, &oip6h->daddr); -	ipv6_addr_copy(&ip6h->daddr, &oip6h->saddr); +	ip6h->saddr = oip6h->daddr; +	ip6h->daddr = oip6h->saddr;  	tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr));  	/* Truncate to length (no data) */ diff --git a/net/ipv6/netfilter/ip6t_rpfilter.c b/net/ipv6/netfilter/ip6t_rpfilter.c new file mode 100644 index 00000000000..5d1d8b04d69 --- /dev/null +++ b/net/ipv6/netfilter/ip6t_rpfilter.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2011 Florian Westphal <fw@strlen.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/module.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> +#include <linux/route.h> +#include <net/ip6_fib.h> +#include <net/ip6_route.h> + +#include <linux/netfilter/xt_rpfilter.h> +#include <linux/netfilter/x_tables.h> + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Florian Westphal <fw@strlen.de>"); +MODULE_DESCRIPTION("Xtables: IPv6 reverse path filter match"); + +static bool rpfilter_addr_unicast(const struct in6_addr *addr) +{ +	int addr_type = ipv6_addr_type(addr); +	return addr_type & IPV6_ADDR_UNICAST; +} + +static bool rpfilter_lookup_reverse6(const struct sk_buff *skb, +				     const struct net_device *dev, u8 flags) +{ +	struct rt6_info *rt; +	struct ipv6hdr *iph = ipv6_hdr(skb); +	bool ret = false; +	struct flowi6 fl6 = { +		.flowlabel = (* (__be32 *) iph) & IPV6_FLOWINFO_MASK, +		.flowi6_proto = iph->nexthdr, +		.daddr = iph->saddr, +	}; +	int lookup_flags; + +	if (rpfilter_addr_unicast(&iph->daddr)) { +		memcpy(&fl6.saddr, &iph->daddr, sizeof(struct in6_addr)); +		lookup_flags = RT6_LOOKUP_F_HAS_SADDR; +	} else { +		lookup_flags = 0; +	} + +	fl6.flowi6_mark = flags & XT_RPFILTER_VALID_MARK ? skb->mark : 0; +	if ((flags & XT_RPFILTER_LOOSE) == 0) { +		fl6.flowi6_oif = dev->ifindex; +		lookup_flags |= RT6_LOOKUP_F_IFACE; +	} + +	rt = (void *) ip6_route_lookup(dev_net(dev), &fl6, lookup_flags); +	if (rt->dst.error) +		goto out; + +	if (rt->rt6i_flags & (RTF_REJECT|RTF_ANYCAST)) +		goto out; + +	if (rt->rt6i_flags & RTF_LOCAL) { +		ret = flags & XT_RPFILTER_ACCEPT_LOCAL; +		goto out; +	} + +	if (rt->rt6i_idev->dev == dev || (flags & XT_RPFILTER_LOOSE)) +		ret = true; + out: +	dst_release(&rt->dst); +	return ret; +} + +static bool rpfilter_mt(const struct sk_buff *skb, struct xt_action_param *par) +{ +	const struct xt_rpfilter_info *info = par->matchinfo; +	int saddrtype; +	struct ipv6hdr *iph; +	bool invert = info->flags & XT_RPFILTER_INVERT; + +	if (par->in->flags & IFF_LOOPBACK) +		return true ^ invert; + +	iph = ipv6_hdr(skb); +	saddrtype = ipv6_addr_type(&iph->saddr); +	if (unlikely(saddrtype == IPV6_ADDR_ANY)) +		return true ^ invert; /* not routable: forward path will drop it */ + +	return rpfilter_lookup_reverse6(skb, par->in, info->flags) ^ invert; +} + +static int rpfilter_check(const struct xt_mtchk_param *par) +{ +	const struct xt_rpfilter_info *info = par->matchinfo; +	unsigned int options = ~XT_RPFILTER_OPTION_MASK; + +	if (info->flags & options) { +		pr_info("unknown options encountered"); +		return -EINVAL; +	} + +	if (strcmp(par->table, "mangle") != 0 && +	    strcmp(par->table, "raw") != 0) { +		pr_info("match only valid in the \'raw\' " +			"or \'mangle\' tables, not \'%s\'.\n", par->table); +		return -EINVAL; +	} + +	return 0; +} + +static struct xt_match rpfilter_mt_reg __read_mostly = { +	.name		= "rpfilter", +	.family		= NFPROTO_IPV6, +	.checkentry	= rpfilter_check, +	.match		= rpfilter_mt, +	.matchsize	= sizeof(struct xt_rpfilter_info), +	.hooks		= (1 << NF_INET_PRE_ROUTING), +	.me		= THIS_MODULE +}; + +static int __init rpfilter_mt_init(void) +{ +	return xt_register_match(&rpfilter_mt_reg); +} + +static void __exit rpfilter_mt_exit(void) +{ +	xt_unregister_match(&rpfilter_mt_reg); +} + +module_init(rpfilter_mt_init); +module_exit(rpfilter_mt_exit); diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c index c9e37c8fd62..a8f6da97e3b 100644 --- a/net/ipv6/netfilter/ip6table_filter.c +++ b/net/ipv6/netfilter/ip6table_filter.c @@ -44,7 +44,7 @@ ip6table_filter_hook(unsigned int hook, struct sk_buff *skb,  static struct nf_hook_ops *filter_ops __read_mostly;  /* Default to forward because I got too much mail already. */ -static int forward = NF_ACCEPT; +static bool forward = NF_ACCEPT;  module_param(forward, bool, 0000);  static int __net_init ip6table_filter_net_init(struct net *net) diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index 1008ce94bc3..fdeb6d03da8 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -142,11 +142,7 @@ static const struct snmp_mib snmp6_udplite6_list[] = {  	SNMP_MIB_SENTINEL  }; -/* can be called either with percpu mib (pcpumib != NULL), - * or shared one (smib != NULL) - */ -static void snmp6_seq_show_icmpv6msg(struct seq_file *seq, void __percpu **pcpumib, -				     atomic_long_t *smib) +static void snmp6_seq_show_icmpv6msg(struct seq_file *seq, atomic_long_t *smib)  {  	char name[32];  	int i; @@ -163,14 +159,14 @@ static void snmp6_seq_show_icmpv6msg(struct seq_file *seq, void __percpu **pcpum  		snprintf(name, sizeof(name), "Icmp6%s%s",  			i & 0x100 ? "Out" : "In", p);  		seq_printf(seq, "%-32s\t%lu\n", name, -			pcpumib ? snmp_fold_field(pcpumib, i) : atomic_long_read(smib + i)); +			   atomic_long_read(smib + i));  	}  	/* print by number (nonzero only) - ICMPMsgStat format */  	for (i = 0; i < ICMP6MSG_MIB_MAX; i++) {  		unsigned long val; -		val = pcpumib ? snmp_fold_field(pcpumib, i) : atomic_long_read(smib + i); +		val = atomic_long_read(smib + i);  		if (!val)  			continue;  		snprintf(name, sizeof(name), "Icmp6%sType%u", @@ -215,8 +211,7 @@ static int snmp6_seq_show(struct seq_file *seq, void *v)  			    snmp6_ipstats_list, offsetof(struct ipstats_mib, syncp));  	snmp6_seq_show_item(seq, (void __percpu **)net->mib.icmpv6_statistics,  			    NULL, snmp6_icmp6_list); -	snmp6_seq_show_icmpv6msg(seq, -			    (void __percpu **)net->mib.icmpv6msg_statistics, NULL); +	snmp6_seq_show_icmpv6msg(seq, net->mib.icmpv6msg_statistics->mibs);  	snmp6_seq_show_item(seq, (void __percpu **)net->mib.udp_stats_in6,  			    NULL, snmp6_udp6_list);  	snmp6_seq_show_item(seq, (void __percpu **)net->mib.udplite_stats_in6, @@ -246,7 +241,7 @@ static int snmp6_dev_seq_show(struct seq_file *seq, void *v)  			    snmp6_ipstats_list);  	snmp6_seq_show_item(seq, NULL, idev->stats.icmpv6dev->mibs,  			    snmp6_icmp6_list); -	snmp6_seq_show_icmpv6msg(seq, NULL, idev->stats.icmpv6msgdev->mibs); +	snmp6_seq_show_icmpv6msg(seq, idev->stats.icmpv6msgdev->mibs);  	return 0;  } diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 331af3b882a..a4894f4f194 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -299,9 +299,9 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)  	}  	inet->inet_rcv_saddr = inet->inet_saddr = v4addr; -	ipv6_addr_copy(&np->rcv_saddr, &addr->sin6_addr); +	np->rcv_saddr = addr->sin6_addr;  	if (!(addr_type & IPV6_ADDR_MULTICAST)) -		ipv6_addr_copy(&np->saddr, &addr->sin6_addr); +		np->saddr = addr->sin6_addr;  	err = 0;  out_unlock:  	rcu_read_unlock(); @@ -383,7 +383,8 @@ static inline int rawv6_rcv_skb(struct sock *sk, struct sk_buff *skb)  	}  	/* Charge it to the socket. */ -	if (ip_queue_rcv_skb(sk, skb) < 0) { +	skb_dst_drop(skb); +	if (sock_queue_rcv_skb(sk, skb) < 0) {  		kfree_skb(skb);  		return NET_RX_DROP;  	} @@ -494,7 +495,7 @@ static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk,  	if (sin6) {  		sin6->sin6_family = AF_INET6;  		sin6->sin6_port = 0; -		ipv6_addr_copy(&sin6->sin6_addr, &ipv6_hdr(skb)->saddr); +		sin6->sin6_addr = ipv6_hdr(skb)->saddr;  		sin6->sin6_flowinfo = 0;  		sin6->sin6_scope_id = 0;  		if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) @@ -610,6 +611,8 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length,  	struct sk_buff *skb;  	int err;  	struct rt6_info *rt = (struct rt6_info *)*dstp; +	int hlen = LL_RESERVED_SPACE(rt->dst.dev); +	int tlen = rt->dst.dev->needed_tailroom;  	if (length > rt->dst.dev->mtu) {  		ipv6_local_error(sk, EMSGSIZE, fl6, rt->dst.dev->mtu); @@ -619,11 +622,11 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length,  		goto out;  	skb = sock_alloc_send_skb(sk, -				  length + LL_ALLOCATED_SPACE(rt->dst.dev) + 15, +				  length + hlen + tlen + 15,  				  flags & MSG_DONTWAIT, &err);  	if (skb == NULL)  		goto error; -	skb_reserve(skb, LL_RESERVED_SPACE(rt->dst.dev)); +	skb_reserve(skb, hlen);  	skb->priority = sk->sk_priority;  	skb->mark = sk->sk_mark; @@ -843,11 +846,11 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,  		goto out;  	if (!ipv6_addr_any(daddr)) -		ipv6_addr_copy(&fl6.daddr, 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)) -		ipv6_addr_copy(&fl6.saddr, &np->saddr); +		fl6.saddr = np->saddr;  	final_p = fl6_update_dst(&fl6, opt, &final); diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index dfb164e9051..b69fae76a6f 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -153,8 +153,8 @@ void ip6_frag_init(struct inet_frag_queue *q, void *a)  	fq->id = arg->id;  	fq->user = arg->user; -	ipv6_addr_copy(&fq->saddr, arg->src); -	ipv6_addr_copy(&fq->daddr, arg->dst); +	fq->saddr = *arg->src; +	fq->daddr = *arg->dst;  }  EXPORT_SYMBOL(ip6_frag_init); diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 3399dd32628..07361dfa808 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -62,17 +62,6 @@  #include <linux/sysctl.h>  #endif -/* Set to 3 to get tracing. */ -#define RT6_DEBUG 2 - -#if RT6_DEBUG >= 3 -#define RDBG(x) printk x -#define RT6_TRACE(x...) printk(KERN_DEBUG x) -#else -#define RDBG(x) -#define RT6_TRACE(x...) do { ; } while (0) -#endif -  static struct rt6_info *ip6_rt_copy(const struct rt6_info *ort,  				    const struct in6_addr *dest);  static struct dst_entry	*ip6_dst_check(struct dst_entry *dst, u32 cookie); @@ -134,7 +123,23 @@ static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old)  static struct neighbour *ip6_neigh_lookup(const struct dst_entry *dst, const void *daddr)  { -	return __neigh_lookup_errno(&nd_tbl, daddr, dst->dev); +	struct neighbour *n = __ipv6_neigh_lookup(&nd_tbl, dst->dev, daddr); +	if (n) +		return n; +	return neigh_create(&nd_tbl, daddr, dst->dev); +} + +static int rt6_bind_neighbour(struct rt6_info *rt, struct net_device *dev) +{ +	struct neighbour *n = __ipv6_neigh_lookup(&nd_tbl, dev, &rt->rt6i_gateway); +	if (!n) { +		n = neigh_create(&nd_tbl, &rt->rt6i_gateway, dev); +		if (IS_ERR(n)) +			return PTR_ERR(n); +	} +	dst_set_neighbour(&rt->dst, n); + +	return 0;  }  static struct dst_ops ip6_dst_ops_template = { @@ -247,9 +252,9 @@ static inline struct rt6_info *ip6_dst_alloc(struct dst_ops *ops,  {  	struct rt6_info *rt = dst_alloc(ops, dev, 0, 0, flags); -	if (rt != NULL) +	if (rt)  		memset(&rt->rt6i_table, 0, -			sizeof(*rt) - sizeof(struct dst_entry)); +		       sizeof(*rt) - sizeof(struct dst_entry));  	return rt;  } @@ -263,7 +268,7 @@ static void ip6_dst_destroy(struct dst_entry *dst)  	if (!(rt->dst.flags & DST_HOST))  		dst_destroy_metrics_generic(dst); -	if (idev != NULL) { +	if (idev) {  		rt->rt6i_idev = NULL;  		in6_dev_put(idev);  	} @@ -299,10 +304,10 @@ static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,  	struct net_device *loopback_dev =  		dev_net(dev)->loopback_dev; -	if (dev != loopback_dev && idev != NULL && idev->dev == dev) { +	if (dev != loopback_dev && idev && idev->dev == dev) {  		struct inet6_dev *loopback_idev =  			in6_dev_get(loopback_dev); -		if (loopback_idev != NULL) { +		if (loopback_idev) {  			rt->rt6i_idev = loopback_idev;  			in6_dev_put(idev);  		} @@ -312,7 +317,7 @@ static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,  static __inline__ int rt6_check_expired(const struct rt6_info *rt)  {  	return (rt->rt6i_flags & RTF_EXPIRES) && -		time_after(jiffies, rt->rt6i_expires); +		time_after(jiffies, rt->dst.expires);  }  static inline int rt6_need_strict(const struct in6_addr *daddr) @@ -338,13 +343,13 @@ static inline struct rt6_info *rt6_device_match(struct net *net,  		goto out;  	for (sprt = rt; sprt; sprt = sprt->dst.rt6_next) { -		struct net_device *dev = sprt->rt6i_dev; +		struct net_device *dev = sprt->dst.dev;  		if (oif) {  			if (dev->ifindex == oif)  				return sprt;  			if (dev->flags & IFF_LOOPBACK) { -				if (sprt->rt6i_idev == NULL || +				if (!sprt->rt6i_idev ||  				    sprt->rt6i_idev->dev->ifindex != oif) {  					if (flags & RT6_LOOKUP_F_IFACE && oif)  						continue; @@ -385,7 +390,7 @@ static void rt6_probe(struct rt6_info *rt)  	 * to no more than one per minute.  	 */  	rcu_read_lock(); -	neigh = rt ? dst_get_neighbour(&rt->dst) : NULL; +	neigh = rt ? dst_get_neighbour_noref(&rt->dst) : NULL;  	if (!neigh || (neigh->nud_state & NUD_VALID))  		goto out;  	read_lock_bh(&neigh->lock); @@ -399,7 +404,7 @@ static void rt6_probe(struct rt6_info *rt)  		target = (struct in6_addr *)&neigh->primary_key;  		addrconf_addr_solict_mult(target, &mcaddr); -		ndisc_send_ns(rt->rt6i_dev, NULL, target, &mcaddr, NULL); +		ndisc_send_ns(rt->dst.dev, NULL, target, &mcaddr, NULL);  	} else {  		read_unlock_bh(&neigh->lock);  	} @@ -417,7 +422,7 @@ static inline void rt6_probe(struct rt6_info *rt)   */  static inline int rt6_check_dev(struct rt6_info *rt, int oif)  { -	struct net_device *dev = rt->rt6i_dev; +	struct net_device *dev = rt->dst.dev;  	if (!oif || dev->ifindex == oif)  		return 2;  	if ((dev->flags & IFF_LOOPBACK) && @@ -432,7 +437,7 @@ static inline int rt6_check_neigh(struct rt6_info *rt)  	int m;  	rcu_read_lock(); -	neigh = dst_get_neighbour(&rt->dst); +	neigh = dst_get_neighbour_noref(&rt->dst);  	if (rt->rt6i_flags & RTF_NONEXTHOP ||  	    !(rt->rt6i_flags & RTF_GATEWAY))  		m = 1; @@ -518,9 +523,6 @@ static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict)  	struct rt6_info *match, *rt0;  	struct net *net; -	RT6_TRACE("%s(fn->leaf=%p, oif=%d)\n", -		  __func__, fn->leaf, oif); -  	rt0 = fn->rr_ptr;  	if (!rt0)  		fn->rr_ptr = rt0 = fn->leaf; @@ -539,10 +541,7 @@ static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict)  			fn->rr_ptr = next;  	} -	RT6_TRACE("%s() => %p\n", -		  __func__, match); - -	net = dev_net(rt0->rt6i_dev); +	net = dev_net(rt0->dst.dev);  	return match ? match : net->ipv6.ip6_null_entry;  } @@ -611,7 +610,7 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,  		if (!addrconf_finite_timeout(lifetime)) {  			rt->rt6i_flags &= ~RTF_EXPIRES;  		} else { -			rt->rt6i_expires = jiffies + HZ * lifetime; +			rt->dst.expires = jiffies + HZ * lifetime;  			rt->rt6i_flags |= RTF_EXPIRES;  		}  		dst_release(&rt->dst); @@ -636,7 +635,7 @@ do { \  				goto restart; \  		} \  	} \ -} while(0) +} while (0)  static struct rt6_info *ip6_pol_route_lookup(struct net *net,  					     struct fib6_table *table, @@ -658,6 +657,13 @@ out:  } +struct dst_entry * ip6_route_lookup(struct net *net, struct flowi6 *fl6, +				    int flags) +{ +	return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_lookup); +} +EXPORT_SYMBOL_GPL(ip6_route_lookup); +  struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr,  			    const struct in6_addr *saddr, int oif, int strict)  { @@ -706,7 +712,7 @@ static int __ip6_ins_rt(struct rt6_info *rt, struct nl_info *info)  int ip6_ins_rt(struct rt6_info *rt)  {  	struct nl_info info = { -		.nl_net = dev_net(rt->rt6i_dev), +		.nl_net = dev_net(rt->dst.dev),  	};  	return __ip6_ins_rt(rt, &info);  } @@ -724,29 +730,27 @@ static struct rt6_info *rt6_alloc_cow(const struct rt6_info *ort,  	rt = ip6_rt_copy(ort, daddr);  	if (rt) { -		struct neighbour *neigh;  		int attempts = !in_softirq(); -		if (!(rt->rt6i_flags&RTF_GATEWAY)) { -			if (rt->rt6i_dst.plen != 128 && +		if (!(rt->rt6i_flags & RTF_GATEWAY)) { +			if (ort->rt6i_dst.plen != 128 &&  			    ipv6_addr_equal(&ort->rt6i_dst.addr, daddr))  				rt->rt6i_flags |= RTF_ANYCAST; -			ipv6_addr_copy(&rt->rt6i_gateway, daddr); +			rt->rt6i_gateway = *daddr;  		}  		rt->rt6i_flags |= RTF_CACHE;  #ifdef CONFIG_IPV6_SUBTREES  		if (rt->rt6i_src.plen && saddr) { -			ipv6_addr_copy(&rt->rt6i_src.addr, saddr); +			rt->rt6i_src.addr = *saddr;  			rt->rt6i_src.plen = 128;  		}  #endif  	retry: -		neigh = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_gateway); -		if (IS_ERR(neigh)) { -			struct net *net = dev_net(rt->rt6i_dev); +		if (rt6_bind_neighbour(rt, rt->dst.dev)) { +			struct net *net = dev_net(rt->dst.dev);  			int saved_rt_min_interval =  				net->ipv6.sysctl.ip6_rt_gc_min_interval;  			int saved_rt_elasticity = @@ -771,8 +775,6 @@ static struct rt6_info *rt6_alloc_cow(const struct rt6_info *ort,  			dst_free(&rt->dst);  			return NULL;  		} -		dst_set_neighbour(&rt->dst, neigh); -  	}  	return rt; @@ -785,7 +787,7 @@ static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort,  	if (rt) {  		rt->rt6i_flags |= RTF_CACHE; -		dst_set_neighbour(&rt->dst, neigh_clone(dst_get_neighbour_raw(&ort->dst))); +		dst_set_neighbour(&rt->dst, neigh_clone(dst_get_neighbour_noref_raw(&ort->dst)));  	}  	return rt;  } @@ -819,7 +821,7 @@ restart:  	dst_hold(&rt->dst);  	read_unlock_bh(&table->tb6_lock); -	if (!dst_get_neighbour_raw(&rt->dst) && !(rt->rt6i_flags & RTF_NONEXTHOP)) +	if (!dst_get_neighbour_noref_raw(&rt->dst) && !(rt->rt6i_flags & RTF_NONEXTHOP))  		nrt = rt6_alloc_cow(rt, &fl6->daddr, &fl6->saddr);  	else if (!(rt->dst.flags & DST_HOST))  		nrt = rt6_alloc_clone(rt, &fl6->daddr); @@ -875,7 +877,7 @@ void ip6_route_input(struct sk_buff *skb)  		.flowi6_iif = skb->dev->ifindex,  		.daddr = iph->daddr,  		.saddr = iph->saddr, -		.flowlabel = (* (__be32 *) iph)&IPV6_FLOWINFO_MASK, +		.flowlabel = (* (__be32 *) iph) & IPV6_FLOWINFO_MASK,  		.flowi6_mark = skb->mark,  		.flowi6_proto = iph->nexthdr,  	}; @@ -932,9 +934,9 @@ struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_ori  		rt->rt6i_idev = ort->rt6i_idev;  		if (rt->rt6i_idev)  			in6_dev_hold(rt->rt6i_idev); -		rt->rt6i_expires = 0; +		rt->dst.expires = 0; -		ipv6_addr_copy(&rt->rt6i_gateway, &ort->rt6i_gateway); +		rt->rt6i_gateway = ort->rt6i_gateway;  		rt->rt6i_flags = ort->rt6i_flags & ~RTF_EXPIRES;  		rt->rt6i_metric = 0; @@ -997,7 +999,7 @@ static void ip6_link_failure(struct sk_buff *skb)  	rt = (struct rt6_info *) skb_dst(skb);  	if (rt) { -		if (rt->rt6i_flags&RTF_CACHE) { +		if (rt->rt6i_flags & RTF_CACHE) {  			dst_set_expires(&rt->dst, 0);  			rt->rt6i_flags |= RTF_EXPIRES;  		} else if (rt->rt6i_node && (rt->rt6i_flags & RTF_DEFAULT)) @@ -1067,34 +1069,38 @@ static DEFINE_SPINLOCK(icmp6_dst_lock);  struct dst_entry *icmp6_dst_alloc(struct net_device *dev,  				  struct neighbour *neigh, -				  const struct in6_addr *addr) +				  struct flowi6 *fl6)  { +	struct dst_entry *dst;  	struct rt6_info *rt;  	struct inet6_dev *idev = in6_dev_get(dev);  	struct net *net = dev_net(dev); -	if (unlikely(idev == NULL)) +	if (unlikely(!idev))  		return NULL;  	rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops, dev, 0); -	if (unlikely(rt == NULL)) { +	if (unlikely(!rt)) {  		in6_dev_put(idev); +		dst = ERR_PTR(-ENOMEM);  		goto out;  	}  	if (neigh)  		neigh_hold(neigh);  	else { -		neigh = ndisc_get_neigh(dev, addr); -		if (IS_ERR(neigh)) -			neigh = NULL; +		neigh = ip6_neigh_lookup(&rt->dst, &fl6->daddr); +		if (IS_ERR(neigh)) { +			dst_free(&rt->dst); +			return ERR_CAST(neigh); +		}  	}  	rt->dst.flags |= DST_HOST;  	rt->dst.output  = ip6_output;  	dst_set_neighbour(&rt->dst, neigh);  	atomic_set(&rt->dst.__refcnt, 1); -	ipv6_addr_copy(&rt->rt6i_dst.addr, addr); +	rt->rt6i_dst.addr = fl6->daddr;  	rt->rt6i_dst.plen = 128;  	rt->rt6i_idev     = idev;  	dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 255); @@ -1106,8 +1112,10 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev,  	fib6_force_start_gc(net); +	dst = xfrm_lookup(net, &rt->dst, flowi6_to_flowi(fl6), NULL, 0); +  out: -	return &rt->dst; +	return dst;  }  int icmp6_dst_gc(void) @@ -1237,21 +1245,30 @@ int ip6_route_add(struct fib6_config *cfg)  	if (cfg->fc_metric == 0)  		cfg->fc_metric = IP6_RT_PRIO_USER; -	table = fib6_new_table(net, cfg->fc_table); -	if (table == NULL) { -		err = -ENOBUFS; -		goto out; +	err = -ENOBUFS; +	if (cfg->fc_nlinfo.nlh && +	    !(cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_CREATE)) { +		table = fib6_get_table(net, cfg->fc_table); +		if (!table) { +			printk(KERN_WARNING "IPv6: NLM_F_CREATE should be specified when creating new route\n"); +			table = fib6_new_table(net, cfg->fc_table); +		} +	} else { +		table = fib6_new_table(net, cfg->fc_table);  	} +	if (!table) +		goto out; +  	rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops, NULL, DST_NOCOUNT); -	if (rt == NULL) { +	if (!rt) {  		err = -ENOMEM;  		goto out;  	}  	rt->dst.obsolete = -1; -	rt->rt6i_expires = (cfg->fc_flags & RTF_EXPIRES) ? +	rt->dst.expires = (cfg->fc_flags & RTF_EXPIRES) ?  				jiffies + clock_t_to_jiffies(cfg->fc_expires) :  				0; @@ -1294,8 +1311,9 @@ int ip6_route_add(struct fib6_config *cfg)  	   they would result in kernel looping; promote them to reject routes  	 */  	if ((cfg->fc_flags & RTF_REJECT) || -	    (dev && (dev->flags&IFF_LOOPBACK) && !(addr_type&IPV6_ADDR_LOOPBACK) -					      && !(cfg->fc_flags&RTF_LOCAL))) { +	    (dev && (dev->flags & IFF_LOOPBACK) && +	     !(addr_type & IPV6_ADDR_LOOPBACK) && +	     !(cfg->fc_flags & RTF_LOCAL))) {  		/* hold loopback dev/idev if we haven't done so. */  		if (dev != net->loopback_dev) {  			if (dev) { @@ -1322,7 +1340,7 @@ int ip6_route_add(struct fib6_config *cfg)  		int gwa_type;  		gw_addr = &cfg->fc_gateway; -		ipv6_addr_copy(&rt->rt6i_gateway, gw_addr); +		rt->rt6i_gateway = *gw_addr;  		gwa_type = ipv6_addr_type(gw_addr);  		if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) { @@ -1336,26 +1354,26 @@ int ip6_route_add(struct fib6_config *cfg)  			   some exceptions. --ANK  			 */  			err = -EINVAL; -			if (!(gwa_type&IPV6_ADDR_UNICAST)) +			if (!(gwa_type & IPV6_ADDR_UNICAST))  				goto out;  			grt = rt6_lookup(net, gw_addr, NULL, cfg->fc_ifindex, 1);  			err = -EHOSTUNREACH; -			if (grt == NULL) +			if (!grt)  				goto out;  			if (dev) { -				if (dev != grt->rt6i_dev) { +				if (dev != grt->dst.dev) {  					dst_release(&grt->dst);  					goto out;  				}  			} else { -				dev = grt->rt6i_dev; +				dev = grt->dst.dev;  				idev = grt->rt6i_idev;  				dev_hold(dev);  				in6_dev_hold(grt->rt6i_idev);  			} -			if (!(grt->rt6i_flags&RTF_GATEWAY)) +			if (!(grt->rt6i_flags & RTF_GATEWAY))  				err = 0;  			dst_release(&grt->dst); @@ -1363,12 +1381,12 @@ int ip6_route_add(struct fib6_config *cfg)  				goto out;  		}  		err = -EINVAL; -		if (dev == NULL || (dev->flags&IFF_LOOPBACK)) +		if (!dev || (dev->flags & IFF_LOOPBACK))  			goto out;  	}  	err = -ENODEV; -	if (dev == NULL) +	if (!dev)  		goto out;  	if (!ipv6_addr_any(&cfg->fc_prefsrc)) { @@ -1376,18 +1394,15 @@ int ip6_route_add(struct fib6_config *cfg)  			err = -EINVAL;  			goto out;  		} -		ipv6_addr_copy(&rt->rt6i_prefsrc.addr, &cfg->fc_prefsrc); +		rt->rt6i_prefsrc.addr = cfg->fc_prefsrc;  		rt->rt6i_prefsrc.plen = 128;  	} else  		rt->rt6i_prefsrc.plen = 0;  	if (cfg->fc_flags & (RTF_GATEWAY | RTF_NONEXTHOP)) { -		struct neighbour *n = __neigh_lookup_errno(&nd_tbl, &rt->rt6i_gateway, dev); -		if (IS_ERR(n)) { -			err = PTR_ERR(n); +		err = rt6_bind_neighbour(rt, dev); +		if (err)  			goto out; -		} -		dst_set_neighbour(&rt->dst, n);  	}  	rt->rt6i_flags = cfg->fc_flags; @@ -1433,7 +1448,7 @@ static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info)  {  	int err;  	struct fib6_table *table; -	struct net *net = dev_net(rt->rt6i_dev); +	struct net *net = dev_net(rt->dst.dev);  	if (rt == net->ipv6.ip6_null_entry)  		return -ENOENT; @@ -1452,7 +1467,7 @@ static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info)  int ip6_del_rt(struct rt6_info *rt)  {  	struct nl_info info = { -		.nl_net = dev_net(rt->rt6i_dev), +		.nl_net = dev_net(rt->dst.dev),  	};  	return __ip6_del_rt(rt, &info);  } @@ -1465,7 +1480,7 @@ static int ip6_route_del(struct fib6_config *cfg)  	int err = -ESRCH;  	table = fib6_get_table(cfg->fc_nlinfo.nl_net, cfg->fc_table); -	if (table == NULL) +	if (!table)  		return err;  	read_lock_bh(&table->tb6_lock); @@ -1477,8 +1492,8 @@ static int ip6_route_del(struct fib6_config *cfg)  	if (fn) {  		for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {  			if (cfg->fc_ifindex && -			    (rt->rt6i_dev == NULL || -			     rt->rt6i_dev->ifindex != cfg->fc_ifindex)) +			    (!rt->dst.dev || +			     rt->dst.dev->ifindex != cfg->fc_ifindex))  				continue;  			if (cfg->fc_flags & RTF_GATEWAY &&  			    !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway)) @@ -1540,7 +1555,7 @@ restart:  			continue;  		if (!(rt->rt6i_flags & RTF_GATEWAY))  			continue; -		if (fl6->flowi6_oif != rt->rt6i_dev->ifindex) +		if (fl6->flowi6_oif != rt->dst.dev->ifindex)  			continue;  		if (!ipv6_addr_equal(&rdfl->gateway, &rt->rt6i_gateway))  			continue; @@ -1573,7 +1588,7 @@ static struct rt6_info *ip6_route_redirect(const struct in6_addr *dest,  		},  	}; -	ipv6_addr_copy(&rdfl.gateway, gateway); +	rdfl.gateway = *gateway;  	if (rt6_need_strict(dest))  		flags |= RT6_LOOKUP_F_IFACE; @@ -1618,18 +1633,18 @@ void rt6_redirect(const struct in6_addr *dest, const struct in6_addr *src,  	dst_confirm(&rt->dst);  	/* Duplicate redirect: silently ignore. */ -	if (neigh == dst_get_neighbour_raw(&rt->dst)) +	if (neigh == dst_get_neighbour_noref_raw(&rt->dst))  		goto out;  	nrt = ip6_rt_copy(rt, dest); -	if (nrt == NULL) +	if (!nrt)  		goto out;  	nrt->rt6i_flags = RTF_GATEWAY|RTF_UP|RTF_DYNAMIC|RTF_CACHE;  	if (on_link)  		nrt->rt6i_flags &= ~RTF_GATEWAY; -	ipv6_addr_copy(&nrt->rt6i_gateway, (struct in6_addr*)neigh->primary_key); +	nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key;  	dst_set_neighbour(&nrt->dst, neigh_clone(neigh));  	if (ip6_ins_rt(nrt)) @@ -1639,7 +1654,7 @@ void rt6_redirect(const struct in6_addr *dest, const struct in6_addr *src,  	netevent.new = &nrt->dst;  	call_netevent_notifiers(NETEVENT_REDIRECT, &netevent); -	if (rt->rt6i_flags&RTF_CACHE) { +	if (rt->rt6i_flags & RTF_CACHE) {  		ip6_del_rt(rt);  		return;  	} @@ -1660,7 +1675,7 @@ static void rt6_do_pmtu_disc(const struct in6_addr *daddr, const struct in6_addr  	int allfrag = 0;  again:  	rt = rt6_lookup(net, daddr, saddr, ifindex, 0); -	if (rt == NULL) +	if (!rt)  		return;  	if (rt6_check_expired(rt)) { @@ -1710,7 +1725,7 @@ again:  	   1. It is connected route. Action: COW  	   2. It is gatewayed route or NONEXTHOP route. Action: clone it.  	 */ -	if (!dst_get_neighbour_raw(&rt->dst) && !(rt->rt6i_flags & RTF_NONEXTHOP)) +	if (!dst_get_neighbour_noref_raw(&rt->dst) && !(rt->rt6i_flags & RTF_NONEXTHOP))  		nrt = rt6_alloc_cow(rt, daddr, saddr);  	else  		nrt = rt6_alloc_clone(rt, daddr); @@ -1766,7 +1781,7 @@ void rt6_pmtu_discovery(const struct in6_addr *daddr, const struct in6_addr *sad  static struct rt6_info *ip6_rt_copy(const struct rt6_info *ort,  				    const struct in6_addr *dest)  { -	struct net *net = dev_net(ort->rt6i_dev); +	struct net *net = dev_net(ort->dst.dev);  	struct rt6_info *rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops,  					    ort->dst.dev, 0); @@ -1775,7 +1790,7 @@ static struct rt6_info *ip6_rt_copy(const struct rt6_info *ort,  		rt->dst.output = ort->dst.output;  		rt->dst.flags |= DST_HOST; -		ipv6_addr_copy(&rt->rt6i_dst.addr, dest); +		rt->rt6i_dst.addr = *dest;  		rt->rt6i_dst.plen = 128;  		dst_copy_metrics(&rt->dst, &ort->dst);  		rt->dst.error = ort->dst.error; @@ -1783,9 +1798,9 @@ static struct rt6_info *ip6_rt_copy(const struct rt6_info *ort,  		if (rt->rt6i_idev)  			in6_dev_hold(rt->rt6i_idev);  		rt->dst.lastuse = jiffies; -		rt->rt6i_expires = 0; +		rt->dst.expires = 0; -		ipv6_addr_copy(&rt->rt6i_gateway, &ort->rt6i_gateway); +		rt->rt6i_gateway = ort->rt6i_gateway;  		rt->rt6i_flags = ort->rt6i_flags & ~RTF_EXPIRES;  		rt->rt6i_metric = 0; @@ -1808,7 +1823,7 @@ static struct rt6_info *rt6_get_route_info(struct net *net,  	struct fib6_table *table;  	table = fib6_get_table(net, RT6_TABLE_INFO); -	if (table == NULL) +	if (!table)  		return NULL;  	write_lock_bh(&table->tb6_lock); @@ -1817,7 +1832,7 @@ static struct rt6_info *rt6_get_route_info(struct net *net,  		goto out;  	for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) { -		if (rt->rt6i_dev->ifindex != ifindex) +		if (rt->dst.dev->ifindex != ifindex)  			continue;  		if ((rt->rt6i_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY))  			continue; @@ -1848,8 +1863,8 @@ static struct rt6_info *rt6_add_route_info(struct net *net,  		.fc_nlinfo.nl_net = net,  	}; -	ipv6_addr_copy(&cfg.fc_dst, prefix); -	ipv6_addr_copy(&cfg.fc_gateway, gwaddr); +	cfg.fc_dst = *prefix; +	cfg.fc_gateway = *gwaddr;  	/* We should treat it as a default route if prefix length is 0. */  	if (!prefixlen) @@ -1867,12 +1882,12 @@ struct rt6_info *rt6_get_dflt_router(const struct in6_addr *addr, struct net_dev  	struct fib6_table *table;  	table = fib6_get_table(dev_net(dev), RT6_TABLE_DFLT); -	if (table == NULL) +	if (!table)  		return NULL;  	write_lock_bh(&table->tb6_lock);  	for (rt = table->tb6_root.leaf; rt; rt=rt->dst.rt6_next) { -		if (dev == rt->rt6i_dev && +		if (dev == rt->dst.dev &&  		    ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) &&  		    ipv6_addr_equal(&rt->rt6i_gateway, addr))  			break; @@ -1898,7 +1913,7 @@ struct rt6_info *rt6_add_dflt_router(const struct in6_addr *gwaddr,  		.fc_nlinfo.nl_net = dev_net(dev),  	}; -	ipv6_addr_copy(&cfg.fc_gateway, gwaddr); +	cfg.fc_gateway = *gwaddr;  	ip6_route_add(&cfg); @@ -1912,7 +1927,7 @@ void rt6_purge_dflt_routers(struct net *net)  	/* NOTE: Keep consistent with rt6_get_dflt_router */  	table = fib6_get_table(net, RT6_TABLE_DFLT); -	if (table == NULL) +	if (!table)  		return;  restart: @@ -1944,9 +1959,9 @@ static void rtmsg_to_fib6_config(struct net *net,  	cfg->fc_nlinfo.nl_net = net; -	ipv6_addr_copy(&cfg->fc_dst, &rtmsg->rtmsg_dst); -	ipv6_addr_copy(&cfg->fc_src, &rtmsg->rtmsg_src); -	ipv6_addr_copy(&cfg->fc_gateway, &rtmsg->rtmsg_gateway); +	cfg->fc_dst = rtmsg->rtmsg_dst; +	cfg->fc_src = rtmsg->rtmsg_src; +	cfg->fc_gateway = rtmsg->rtmsg_gateway;  }  int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg) @@ -2045,14 +2060,14 @@ static int ip6_pkt_prohibit_out(struct sk_buff *skb)  struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,  				    const struct in6_addr *addr, -				    int anycast) +				    bool anycast)  {  	struct net *net = dev_net(idev->dev);  	struct rt6_info *rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops,  					    net->loopback_dev, 0); -	struct neighbour *neigh; +	int err; -	if (rt == NULL) { +	if (!rt) {  		if (net_ratelimit())  			pr_warning("IPv6:  Maximum number of routes reached,"  				   " consider increasing route/max_size.\n"); @@ -2072,15 +2087,13 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,  		rt->rt6i_flags |= RTF_ANYCAST;  	else  		rt->rt6i_flags |= RTF_LOCAL; -	neigh = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_gateway); -	if (IS_ERR(neigh)) { +	err = rt6_bind_neighbour(rt, rt->dst.dev); +	if (err) {  		dst_free(&rt->dst); - -		return ERR_CAST(neigh); +		return ERR_PTR(err);  	} -	dst_set_neighbour(&rt->dst, neigh); -	ipv6_addr_copy(&rt->rt6i_dst.addr, addr); +	rt->rt6i_dst.addr = *addr;  	rt->rt6i_dst.plen = 128;  	rt->rt6i_table = fib6_get_table(net, RT6_TABLE_LOCAL); @@ -2098,7 +2111,7 @@ int ip6_route_get_saddr(struct net *net,  	struct inet6_dev *idev = ip6_dst_idev((struct dst_entry*)rt);  	int err = 0;  	if (rt->rt6i_prefsrc.plen) -		ipv6_addr_copy(saddr, &rt->rt6i_prefsrc.addr); +		*saddr = rt->rt6i_prefsrc.addr;  	else  		err = ipv6_dev_get_saddr(net, idev ? idev->dev : NULL,  					 daddr, prefs, saddr); @@ -2118,7 +2131,7 @@ static int fib6_remove_prefsrc(struct rt6_info *rt, void *arg)  	struct net *net = ((struct arg_dev_net_ip *)arg)->net;  	struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr; -	if (((void *)rt->rt6i_dev == dev || dev == NULL) && +	if (((void *)rt->dst.dev == dev || !dev) &&  	    rt != net->ipv6.ip6_null_entry &&  	    ipv6_addr_equal(addr, &rt->rt6i_prefsrc.addr)) {  		/* remove prefsrc entry */ @@ -2148,11 +2161,10 @@ static int fib6_ifdown(struct rt6_info *rt, void *arg)  	const struct arg_dev_net *adn = arg;  	const struct net_device *dev = adn->dev; -	if ((rt->rt6i_dev == dev || dev == NULL) && -	    rt != adn->net->ipv6.ip6_null_entry) { -		RT6_TRACE("deleted by ifdown %p\n", rt); +	if ((rt->dst.dev == dev || !dev) && +	    rt != adn->net->ipv6.ip6_null_entry)  		return -1; -	} +  	return 0;  } @@ -2185,7 +2197,7 @@ static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg)  	*/  	idev = __in6_dev_get(arg->dev); -	if (idev == NULL) +	if (!idev)  		return 0;  	/* For administrative MTU increase, there is no way to discover @@ -2202,7 +2214,7 @@ static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg)  	   also have the lowest MTU, TOO BIG MESSAGE will be lead to  	   PMTU discouvery.  	 */ -	if (rt->rt6i_dev == arg->dev && +	if (rt->dst.dev == arg->dev &&  	    !dst_metric_locked(&rt->dst, RTAX_MTU) &&  	    (dst_mtu(&rt->dst) >= arg->mtu ||  	     (dst_mtu(&rt->dst) < arg->mtu && @@ -2351,11 +2363,13 @@ static int rt6_fill_node(struct net *net,  			 int iif, int type, u32 pid, u32 seq,  			 int prefix, int nowait, unsigned int flags)  { +	const struct inet_peer *peer;  	struct rtmsg *rtm;  	struct nlmsghdr *nlh;  	long expires;  	u32 table;  	struct neighbour *n; +	u32 ts, tsage;  	if (prefix) {	/* user wants prefix routes only */  		if (!(rt->rt6i_flags & RTF_PREFIX_RT)) { @@ -2365,7 +2379,7 @@ static int rt6_fill_node(struct net *net,  	}  	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*rtm), flags); -	if (nlh == NULL) +	if (!nlh)  		return -EMSGSIZE;  	rtm = nlmsg_data(nlh); @@ -2379,25 +2393,25 @@ static int rt6_fill_node(struct net *net,  		table = RT6_TABLE_UNSPEC;  	rtm->rtm_table = table;  	NLA_PUT_U32(skb, RTA_TABLE, table); -	if (rt->rt6i_flags&RTF_REJECT) +	if (rt->rt6i_flags & RTF_REJECT)  		rtm->rtm_type = RTN_UNREACHABLE; -	else if (rt->rt6i_flags&RTF_LOCAL) +	else if (rt->rt6i_flags & RTF_LOCAL)  		rtm->rtm_type = RTN_LOCAL; -	else if (rt->rt6i_dev && (rt->rt6i_dev->flags&IFF_LOOPBACK)) +	else if (rt->dst.dev && (rt->dst.dev->flags & IFF_LOOPBACK))  		rtm->rtm_type = RTN_LOCAL;  	else  		rtm->rtm_type = RTN_UNICAST;  	rtm->rtm_flags = 0;  	rtm->rtm_scope = RT_SCOPE_UNIVERSE;  	rtm->rtm_protocol = rt->rt6i_protocol; -	if (rt->rt6i_flags&RTF_DYNAMIC) +	if (rt->rt6i_flags & RTF_DYNAMIC)  		rtm->rtm_protocol = RTPROT_REDIRECT;  	else if (rt->rt6i_flags & RTF_ADDRCONF)  		rtm->rtm_protocol = RTPROT_KERNEL; -	else if (rt->rt6i_flags&RTF_DEFAULT) +	else if (rt->rt6i_flags & RTF_DEFAULT)  		rtm->rtm_protocol = RTPROT_RA; -	if (rt->rt6i_flags&RTF_CACHE) +	if (rt->rt6i_flags & RTF_CACHE)  		rtm->rtm_flags |= RTM_F_CLONED;  	if (dst) { @@ -2437,7 +2451,7 @@ static int rt6_fill_node(struct net *net,  	if (rt->rt6i_prefsrc.plen) {  		struct in6_addr saddr_buf; -		ipv6_addr_copy(&saddr_buf, &rt->rt6i_prefsrc.addr); +		saddr_buf = rt->rt6i_prefsrc.addr;  		NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf);  	} @@ -2445,24 +2459,31 @@ static int rt6_fill_node(struct net *net,  		goto nla_put_failure;  	rcu_read_lock(); -	n = dst_get_neighbour(&rt->dst); +	n = dst_get_neighbour_noref(&rt->dst);  	if (n)  		NLA_PUT(skb, RTA_GATEWAY, 16, &n->primary_key);  	rcu_read_unlock();  	if (rt->dst.dev) -		NLA_PUT_U32(skb, RTA_OIF, rt->rt6i_dev->ifindex); +		NLA_PUT_U32(skb, RTA_OIF, rt->dst.dev->ifindex);  	NLA_PUT_U32(skb, RTA_PRIORITY, rt->rt6i_metric);  	if (!(rt->rt6i_flags & RTF_EXPIRES))  		expires = 0; -	else if (rt->rt6i_expires - jiffies < INT_MAX) -		expires = rt->rt6i_expires - jiffies; +	else if (rt->dst.expires - jiffies < INT_MAX) +		expires = rt->dst.expires - jiffies;  	else  		expires = INT_MAX; -	if (rtnl_put_cacheinfo(skb, &rt->dst, 0, 0, 0, +	peer = rt->rt6i_peer; +	ts = tsage = 0; +	if (peer && peer->tcp_ts_stamp) { +		ts = peer->tcp_ts; +		tsage = get_seconds() - peer->tcp_ts_stamp; +	} + +	if (rtnl_put_cacheinfo(skb, &rt->dst, 0, ts, tsage,  			       expires, rt->dst.error) < 0)  		goto nla_put_failure; @@ -2511,14 +2532,14 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void  		if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr))  			goto errout; -		ipv6_addr_copy(&fl6.saddr, nla_data(tb[RTA_SRC])); +		fl6.saddr = *(struct in6_addr *)nla_data(tb[RTA_SRC]);  	}  	if (tb[RTA_DST]) {  		if (nla_len(tb[RTA_DST]) < sizeof(struct in6_addr))  			goto errout; -		ipv6_addr_copy(&fl6.daddr, nla_data(tb[RTA_DST])); +		fl6.daddr = *(struct in6_addr *)nla_data(tb[RTA_DST]);  	}  	if (tb[RTA_IIF]) @@ -2537,7 +2558,7 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void  	}  	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); -	if (skb == NULL) { +	if (!skb) {  		err = -ENOBUFS;  		goto errout;  	} @@ -2572,10 +2593,10 @@ void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info)  	int err;  	err = -ENOBUFS; -	seq = info->nlh != NULL ? info->nlh->nlmsg_seq : 0; +	seq = info->nlh ? info->nlh->nlmsg_seq : 0;  	skb = nlmsg_new(rt6_nlmsg_size(), gfp_any()); -	if (skb == NULL) +	if (!skb)  		goto errout;  	err = rt6_fill_node(net, skb, rt, NULL, NULL, 0, @@ -2642,7 +2663,7 @@ static int rt6_info_route(struct rt6_info *rt, void *p_arg)  	seq_puts(m, "00000000000000000000000000000000 00 ");  #endif  	rcu_read_lock(); -	n = dst_get_neighbour(&rt->dst); +	n = dst_get_neighbour_noref(&rt->dst);  	if (n) {  		seq_printf(m, "%pi6", n->primary_key);  	} else { @@ -2652,14 +2673,14 @@ static int rt6_info_route(struct rt6_info *rt, void *p_arg)  	seq_printf(m, " %08x %08x %08x %08x %8s\n",  		   rt->rt6i_metric, atomic_read(&rt->dst.__refcnt),  		   rt->dst.__use, rt->rt6i_flags, -		   rt->rt6i_dev ? rt->rt6i_dev->name : ""); +		   rt->dst.dev ? rt->dst.dev->name : "");  	return 0;  }  static int ipv6_route_show(struct seq_file *m, void *v)  {  	struct net *net = (struct net *)m->private; -	fib6_clean_all(net, rt6_info_route, 0, m); +	fib6_clean_all_ro(net, rt6_info_route, 0, m);  	return 0;  } diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index a7a18602a04..3b6dac956bb 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -91,7 +91,7 @@ struct pcpu_tstats {  	unsigned long	rx_bytes;  	unsigned long	tx_packets;  	unsigned long	tx_bytes; -}; +} __attribute__((aligned(4*sizeof(unsigned long))));  static struct net_device_stats *ipip6_get_stats(struct net_device *dev)  { @@ -263,6 +263,8 @@ static struct ip_tunnel *ipip6_tunnel_locate(struct net *net,  	if (register_netdevice(dev) < 0)  		goto failed_free; +	strcpy(nt->parms.name, dev->name); +  	dev_hold(dev);  	ipip6_tunnel_link(sitn, nt); @@ -680,7 +682,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,  		struct neighbour *neigh = NULL;  		if (skb_dst(skb)) -			neigh = dst_get_neighbour(skb_dst(skb)); +			neigh = dst_get_neighbour_noref(skb_dst(skb));  		if (neigh == NULL) {  			if (net_ratelimit()) @@ -705,7 +707,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,  		struct neighbour *neigh = NULL;  		if (skb_dst(skb)) -			neigh = dst_get_neighbour(skb_dst(skb)); +			neigh = dst_get_neighbour_noref(skb_dst(skb));  		if (neigh == NULL) {  			if (net_ratelimit()) @@ -914,7 +916,7 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)  				goto done;  #ifdef CONFIG_IPV6_SIT_6RD  		} else { -			ipv6_addr_copy(&ip6rd.prefix, &t->ip6rd.prefix); +			ip6rd.prefix = t->ip6rd.prefix;  			ip6rd.relay_prefix = t->ip6rd.relay_prefix;  			ip6rd.prefixlen = t->ip6rd.prefixlen;  			ip6rd.relay_prefixlen = t->ip6rd.relay_prefixlen; @@ -1082,7 +1084,7 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)  			if (relay_prefix != ip6rd.relay_prefix)  				goto done; -			ipv6_addr_copy(&t->ip6rd.prefix, &prefix); +			t->ip6rd.prefix = prefix;  			t->ip6rd.relay_prefix = relay_prefix;  			t->ip6rd.prefixlen = ip6rd.prefixlen;  			t->ip6rd.relay_prefixlen = ip6rd.relay_prefixlen; @@ -1144,7 +1146,6 @@ static int ipip6_tunnel_init(struct net_device *dev)  	struct ip_tunnel *tunnel = netdev_priv(dev);  	tunnel->dev = dev; -	strcpy(tunnel->parms.name, dev->name);  	memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4);  	memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4); @@ -1207,6 +1208,7 @@ static void __net_exit sit_destroy_tunnels(struct sit_net *sitn, struct list_hea  static int __net_init sit_init_net(struct net *net)  {  	struct sit_net *sitn = net_generic(net, sit_net_id); +	struct ip_tunnel *t;  	int err;  	sitn->tunnels[0] = sitn->tunnels_wc; @@ -1231,6 +1233,9 @@ static int __net_init sit_init_net(struct net *net)  	if ((err = register_netdev(sitn->fb_tunnel_dev)))  		goto err_reg_dev; +	t = netdev_priv(sitn->fb_tunnel_dev); + +	strcpy(t->parms.name, sitn->fb_tunnel_dev->name);  	return 0;  err_reg_dev: diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index 5a0d6648bbb..8e951d8d3b8 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c @@ -200,8 +200,8 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)  	req->mss = mss;  	ireq->rmt_port = th->source;  	ireq->loc_port = th->dest; -	ipv6_addr_copy(&ireq6->rmt_addr, &ipv6_hdr(skb)->saddr); -	ipv6_addr_copy(&ireq6->loc_addr, &ipv6_hdr(skb)->daddr); +	ireq6->rmt_addr = ipv6_hdr(skb)->saddr; +	ireq6->loc_addr = ipv6_hdr(skb)->daddr;  	if (ipv6_opt_accepted(sk, skb) ||  	    np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||  	    np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) { @@ -237,9 +237,9 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)  		struct flowi6 fl6;  		memset(&fl6, 0, sizeof(fl6));  		fl6.flowi6_proto = IPPROTO_TCP; -		ipv6_addr_copy(&fl6.daddr, &ireq6->rmt_addr); +		fl6.daddr = ireq6->rmt_addr;  		final_p = fl6_update_dst(&fl6, np->opt, &final); -		ipv6_addr_copy(&fl6.saddr, &ireq6->loc_addr); +		fl6.saddr = ireq6->loc_addr;  		fl6.flowi6_oif = sk->sk_bound_dev_if;  		fl6.flowi6_mark = sk->sk_mark;  		fl6.fl6_dport = inet_rsk(req)->rmt_port; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 2dea4bb7b54..906c7ca4354 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -62,6 +62,7 @@  #include <net/netdma.h>  #include <net/inet_common.h>  #include <net/secure_seq.h> +#include <net/tcp_memcontrol.h>  #include <asm/uaccess.h> @@ -153,7 +154,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,  			flowlabel = fl6_sock_lookup(sk, fl6.flowlabel);  			if (flowlabel == NULL)  				return -EINVAL; -			ipv6_addr_copy(&usin->sin6_addr, &flowlabel->dst); +			usin->sin6_addr = flowlabel->dst;  			fl6_sock_release(flowlabel);  		}  	} @@ -195,7 +196,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,  		tp->write_seq = 0;  	} -	ipv6_addr_copy(&np->daddr, &usin->sin6_addr); +	np->daddr = usin->sin6_addr;  	np->flow_label = fl6.flowlabel;  	/* @@ -244,9 +245,8 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,  		saddr = &np->rcv_saddr;  	fl6.flowi6_proto = IPPROTO_TCP; -	ipv6_addr_copy(&fl6.daddr, &np->daddr); -	ipv6_addr_copy(&fl6.saddr, -		       (saddr ? saddr : &np->saddr)); +	fl6.daddr = np->daddr; +	fl6.saddr = saddr ? *saddr : np->saddr;  	fl6.flowi6_oif = sk->sk_bound_dev_if;  	fl6.flowi6_mark = sk->sk_mark;  	fl6.fl6_dport = usin->sin6_port; @@ -264,11 +264,11 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,  	if (saddr == NULL) {  		saddr = &fl6.saddr; -		ipv6_addr_copy(&np->rcv_saddr, saddr); +		np->rcv_saddr = *saddr;  	}  	/* set the source address */ -	ipv6_addr_copy(&np->saddr, saddr); +	np->saddr = *saddr;  	inet->inet_rcv_saddr = LOOPBACK4_IPV6;  	sk->sk_gso_type = SKB_GSO_TCPV6; @@ -398,8 +398,8 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,  			 */  			memset(&fl6, 0, sizeof(fl6));  			fl6.flowi6_proto = IPPROTO_TCP; -			ipv6_addr_copy(&fl6.daddr, &np->daddr); -			ipv6_addr_copy(&fl6.saddr, &np->saddr); +			fl6.daddr = np->daddr; +			fl6.saddr = np->saddr;  			fl6.flowi6_oif = sk->sk_bound_dev_if;  			fl6.flowi6_mark = sk->sk_mark;  			fl6.fl6_dport = inet->inet_dport; @@ -489,8 +489,8 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,  	memset(&fl6, 0, sizeof(fl6));  	fl6.flowi6_proto = IPPROTO_TCP; -	ipv6_addr_copy(&fl6.daddr, &treq->rmt_addr); -	ipv6_addr_copy(&fl6.saddr, &treq->loc_addr); +	fl6.daddr = treq->rmt_addr; +	fl6.saddr = treq->loc_addr;  	fl6.flowlabel = 0;  	fl6.flowi6_oif = treq->iif;  	fl6.flowi6_mark = sk->sk_mark; @@ -512,7 +512,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,  	if (skb) {  		__tcp_v6_send_check(skb, &treq->loc_addr, &treq->rmt_addr); -		ipv6_addr_copy(&fl6.daddr, &treq->rmt_addr); +		fl6.daddr = treq->rmt_addr;  		err = ip6_xmit(sk, skb, &fl6, opt, np->tclass);  		err = net_xmit_eval(err);  	} @@ -617,8 +617,7 @@ static int tcp_v6_md5_do_add(struct sock *sk, const struct in6_addr *peer,  			tp->md5sig_info->alloced6++;  		} -		ipv6_addr_copy(&tp->md5sig_info->keys6[tp->md5sig_info->entries6].addr, -			       peer); +		tp->md5sig_info->keys6[tp->md5sig_info->entries6].addr = *peer;  		tp->md5sig_info->keys6[tp->md5sig_info->entries6].base.key = newkey;  		tp->md5sig_info->keys6[tp->md5sig_info->entries6].base.keylen = newkeylen; @@ -750,8 +749,8 @@ static int tcp_v6_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp,  	bp = &hp->md5_blk.ip6;  	/* 1. TCP pseudo-header (RFC2460) */ -	ipv6_addr_copy(&bp->saddr, saddr); -	ipv6_addr_copy(&bp->daddr, daddr); +	bp->saddr = *saddr; +	bp->daddr = *daddr;  	bp->protocol = cpu_to_be32(IPPROTO_TCP);  	bp->len = cpu_to_be32(nbytes); @@ -1039,8 +1038,8 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win,  #endif  	memset(&fl6, 0, sizeof(fl6)); -	ipv6_addr_copy(&fl6.daddr, &ipv6_hdr(skb)->saddr); -	ipv6_addr_copy(&fl6.saddr, &ipv6_hdr(skb)->daddr); +	fl6.daddr = ipv6_hdr(skb)->saddr; +	fl6.saddr = ipv6_hdr(skb)->daddr;  	buff->ip_summed = CHECKSUM_PARTIAL;  	buff->csum = 0; @@ -1250,8 +1249,8 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)  	tcp_openreq_init(req, &tmp_opt, skb);  	treq = inet6_rsk(req); -	ipv6_addr_copy(&treq->rmt_addr, &ipv6_hdr(skb)->saddr); -	ipv6_addr_copy(&treq->loc_addr, &ipv6_hdr(skb)->daddr); +	treq->rmt_addr = ipv6_hdr(skb)->saddr; +	treq->loc_addr = ipv6_hdr(skb)->daddr;  	if (!want_cookie || tmp_opt.tstamp_ok)  		TCP_ECN_create_request(req, tcp_hdr(skb)); @@ -1381,7 +1380,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,  		ipv6_addr_set_v4mapped(newinet->inet_saddr, &newnp->saddr); -		ipv6_addr_copy(&newnp->rcv_saddr, &newnp->saddr); +		newnp->rcv_saddr = newnp->saddr;  		inet_csk(newsk)->icsk_af_ops = &ipv6_mapped;  		newsk->sk_backlog_rcv = tcp_v4_do_rcv; @@ -1445,9 +1444,9 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,  	memcpy(newnp, np, sizeof(struct ipv6_pinfo)); -	ipv6_addr_copy(&newnp->daddr, &treq->rmt_addr); -	ipv6_addr_copy(&newnp->saddr, &treq->loc_addr); -	ipv6_addr_copy(&newnp->rcv_saddr, &treq->loc_addr); +	newnp->daddr = treq->rmt_addr; +	newnp->saddr = treq->loc_addr; +	newnp->rcv_saddr = treq->loc_addr;  	newsk->sk_bound_dev_if = treq->iif;  	/* Now IPv6 options... @@ -1996,7 +1995,8 @@ static int tcp_v6_init_sock(struct sock *sk)  	sk->sk_rcvbuf = sysctl_tcp_rmem[1];  	local_bh_disable(); -	percpu_counter_inc(&tcp_sockets_allocated); +	sock_update_memcg(sk); +	sk_sockets_allocated_inc(sk);  	local_bh_enable();  	return 0; @@ -2215,7 +2215,6 @@ struct proto tcpv6_prot = {  	.memory_allocated	= &tcp_memory_allocated,  	.memory_pressure	= &tcp_memory_pressure,  	.orphan_count		= &tcp_orphan_count, -	.sysctl_mem		= sysctl_tcp_mem,  	.sysctl_wmem		= sysctl_tcp_wmem,  	.sysctl_rmem		= sysctl_tcp_rmem,  	.max_header		= MAX_TCP_HEADER, @@ -2229,6 +2228,9 @@ struct proto tcpv6_prot = {  	.compat_setsockopt	= compat_tcp_setsockopt,  	.compat_getsockopt	= compat_tcp_getsockopt,  #endif +#ifdef CONFIG_CGROUP_MEM_RES_CTLR_KMEM +	.proto_cgroup		= tcp_proto_cgroup, +#endif  };  static const struct inet6_protocol tcpv6_protocol = { diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 8c254191518..4f96b5c6368 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -238,7 +238,7 @@ exact_match:  	return result;  } -static struct sock *__udp6_lib_lookup(struct net *net, +struct sock *__udp6_lib_lookup(struct net *net,  				      const struct in6_addr *saddr, __be16 sport,  				      const struct in6_addr *daddr, __be16 dport,  				      int dif, struct udp_table *udptable) @@ -305,6 +305,7 @@ begin:  	rcu_read_unlock();  	return result;  } +EXPORT_SYMBOL_GPL(__udp6_lib_lookup);  static struct sock *__udp6_lib_lookup_skb(struct sk_buff *skb,  					  __be16 sport, __be16 dport, @@ -418,8 +419,7 @@ try_again:  			ipv6_addr_set_v4mapped(ip_hdr(skb)->saddr,  					       &sin6->sin6_addr);  		else { -			ipv6_addr_copy(&sin6->sin6_addr, -				       &ipv6_hdr(skb)->saddr); +			sin6->sin6_addr = ipv6_hdr(skb)->saddr;  			if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)  				sin6->sin6_scope_id = IP6CB(skb)->iif;  		} @@ -539,7 +539,9 @@ int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)  			goto drop;  	} -	if ((rc = ip_queue_rcv_skb(sk, skb)) < 0) { +	skb_dst_drop(skb); +	rc = sock_queue_rcv_skb(sk, skb); +	if (rc < 0) {  		/* Note that an ENOMEM error is charged twice */  		if (rc == -ENOMEM)  			UDP6_INC_STATS_BH(sock_net(sk), @@ -1114,11 +1116,11 @@ do_udp_sendmsg:  	fl6.flowi6_proto = sk->sk_protocol;  	if (!ipv6_addr_any(daddr)) -		ipv6_addr_copy(&fl6.daddr, 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)) -		ipv6_addr_copy(&fl6.saddr, &np->saddr); +		fl6.saddr = np->saddr;  	fl6.fl6_sport = inet->inet_sport;  	final_p = fl6_update_dst(&fl6, opt, &final); @@ -1299,7 +1301,8 @@ static int udp6_ufo_send_check(struct sk_buff *skb)  	return 0;  } -static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, u32 features) +static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, +	netdev_features_t features)  {  	struct sk_buff *segs = ERR_PTR(-EINVAL);  	unsigned int mss; diff --git a/net/ipv6/xfrm6_mode_beet.c b/net/ipv6/xfrm6_mode_beet.c index 3437d7d4eed..a81ce945075 100644 --- a/net/ipv6/xfrm6_mode_beet.c +++ b/net/ipv6/xfrm6_mode_beet.c @@ -72,8 +72,8 @@ static int xfrm6_beet_output(struct xfrm_state *x, struct sk_buff *skb)  		top_iph->nexthdr = IPPROTO_BEETPH;  	} -	ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr); -	ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr); +	top_iph->saddr = *(struct in6_addr *)&x->props.saddr; +	top_iph->daddr = *(struct in6_addr *)&x->id.daddr;  	return 0;  } @@ -99,8 +99,8 @@ static int xfrm6_beet_input(struct xfrm_state *x, struct sk_buff *skb)  	ip6h = ipv6_hdr(skb);  	ip6h->payload_len = htons(skb->len - size); -	ipv6_addr_copy(&ip6h->daddr, (struct in6_addr *) &x->sel.daddr.a6); -	ipv6_addr_copy(&ip6h->saddr, (struct in6_addr *) &x->sel.saddr.a6); +	ip6h->daddr = *(struct in6_addr *)&x->sel.daddr.a6; +	ip6h->saddr = *(struct in6_addr *)&x->sel.saddr.a6;  	err = 0;  out:  	return err; diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c index 4d6edff0498..261e6e6f487 100644 --- a/net/ipv6/xfrm6_mode_tunnel.c +++ b/net/ipv6/xfrm6_mode_tunnel.c @@ -55,8 +55,8 @@ static int xfrm6_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)  		dsfield &= ~INET_ECN_MASK;  	ipv6_change_dsfield(top_iph, 0, dsfield);  	top_iph->hop_limit = ip6_dst_hoplimit(dst->child); -	ipv6_addr_copy(&top_iph->saddr, (const struct in6_addr *)&x->props.saddr); -	ipv6_addr_copy(&top_iph->daddr, (const struct in6_addr *)&x->id.daddr); +	top_iph->saddr = *(struct in6_addr *)&x->props.saddr; +	top_iph->daddr = *(struct in6_addr *)&x->id.daddr;  	return 0;  } diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c index faae41737fc..4eeff89c1aa 100644 --- a/net/ipv6/xfrm6_output.c +++ b/net/ipv6/xfrm6_output.c @@ -49,7 +49,7 @@ static void xfrm6_local_rxpmtu(struct sk_buff *skb, u32 mtu)  	struct sock *sk = skb->sk;  	fl6.flowi6_oif = sk->sk_bound_dev_if; -	ipv6_addr_copy(&fl6.daddr, &ipv6_hdr(skb)->daddr); +	fl6.daddr = ipv6_hdr(skb)->daddr;  	ipv6_local_rxpmtu(sk, &fl6, mtu);  } @@ -60,7 +60,7 @@ static void xfrm6_local_error(struct sk_buff *skb, u32 mtu)  	struct sock *sk = skb->sk;  	fl6.fl6_dport = inet_sk(sk)->inet_dport; -	ipv6_addr_copy(&fl6.daddr, &ipv6_hdr(skb)->daddr); +	fl6.daddr = ipv6_hdr(skb)->daddr;  	ipv6_local_error(sk, EMSGSIZE, &fl6, mtu);  } diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index d879f7efbd1..8ea65e03273 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c @@ -132,8 +132,8 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse)  	memset(fl6, 0, sizeof(struct flowi6));  	fl6->flowi6_mark = skb->mark; -	ipv6_addr_copy(&fl6->daddr, reverse ? &hdr->saddr : &hdr->daddr); -	ipv6_addr_copy(&fl6->saddr, reverse ? &hdr->daddr : &hdr->saddr); +	fl6->daddr = reverse ? hdr->saddr : hdr->daddr; +	fl6->saddr = reverse ? hdr->daddr : hdr->saddr;  	while (nh + offset + 1 < skb->data ||  	       pskb_may_pull(skb, nh + offset + 1 - skb->data)) { diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c index f2d72b8a3fa..3f2f7c4ab72 100644 --- a/net/ipv6/xfrm6_state.c +++ b/net/ipv6/xfrm6_state.c @@ -27,8 +27,8 @@ __xfrm6_init_tempsel(struct xfrm_selector *sel, const struct flowi *fl)  	/* Initialize temporary selector matching only  	 * to current session. */ -	ipv6_addr_copy((struct in6_addr *)&sel->daddr, &fl6->daddr); -	ipv6_addr_copy((struct in6_addr *)&sel->saddr, &fl6->saddr); +	*(struct in6_addr *)&sel->daddr = fl6->daddr; +	*(struct in6_addr *)&sel->saddr = fl6->saddr;  	sel->dport = xfrm_flowi_dport(fl, &fl6->uli);  	sel->dport_mask = htons(0xffff);  	sel->sport = xfrm_flowi_sport(fl, &fl6->uli);  |