diff options
| author | Mark Brown <[email protected]> | 2015-10-12 18:09:27 +0100 | 
|---|---|---|
| committer | Mark Brown <[email protected]> | 2015-10-12 18:09:27 +0100 | 
| commit | 79828b4fa835f73cdaf4bffa48696abdcbea9d02 (patch) | |
| tree | 5e0fa7156acb75ba603022bc807df8f2fedb97a8 /net/ipv4/arp.c | |
| parent | 721b51fcf91898299d96f4b72cb9434cda29dce6 (diff) | |
| parent | 8c1a9d6323abf0fb1e5dad96cf3f1c783505ea5a (diff) | |
Merge remote-tracking branch 'asoc/fix/rt5645' into asoc-fix-rt5645
Diffstat (limited to 'net/ipv4/arp.c')
| -rw-r--r-- | net/ipv4/arp.c | 96 | 
1 files changed, 55 insertions, 41 deletions
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 933a92820d26..30409b75e925 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -233,7 +233,7 @@ static int arp_constructor(struct neighbour *neigh)  		return -EINVAL;  	} -	neigh->type = inet_addr_type(dev_net(dev), addr); +	neigh->type = inet_addr_type_dev_table(dev_net(dev), dev, addr);  	parms = in_dev->arp_parms;  	__neigh_parms_put(neigh->parms); @@ -291,6 +291,40 @@ static void arp_error_report(struct neighbour *neigh, struct sk_buff *skb)  	kfree_skb(skb);  } +/* Create and send an arp packet. */ +static void arp_send_dst(int type, int ptype, __be32 dest_ip, +			 struct net_device *dev, __be32 src_ip, +			 const unsigned char *dest_hw, +			 const unsigned char *src_hw, +			 const unsigned char *target_hw, struct sk_buff *oskb) +{ +	struct sk_buff *skb; + +	/* arp on this interface. */ +	if (dev->flags & IFF_NOARP) +		return; + +	skb = arp_create(type, ptype, dest_ip, dev, src_ip, +			 dest_hw, src_hw, target_hw); +	if (!skb) +		return; + +	if (oskb) +		skb_dst_copy(skb, oskb); + +	arp_xmit(skb); +} + +void arp_send(int type, int ptype, __be32 dest_ip, +	      struct net_device *dev, __be32 src_ip, +	      const unsigned char *dest_hw, const unsigned char *src_hw, +	      const unsigned char *target_hw) +{ +	arp_send_dst(type, ptype, dest_ip, dev, src_ip, dest_hw, src_hw, +		     target_hw, NULL); +} +EXPORT_SYMBOL(arp_send); +  static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)  {  	__be32 saddr = 0; @@ -309,7 +343,7 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)  	switch (IN_DEV_ARP_ANNOUNCE(in_dev)) {  	default:  	case 0:		/* By default announce any local IP */ -		if (skb && inet_addr_type(dev_net(dev), +		if (skb && inet_addr_type_dev_table(dev_net(dev), dev,  					  ip_hdr(skb)->saddr) == RTN_LOCAL)  			saddr = ip_hdr(skb)->saddr;  		break; @@ -317,7 +351,8 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)  		if (!skb)  			break;  		saddr = ip_hdr(skb)->saddr; -		if (inet_addr_type(dev_net(dev), saddr) == RTN_LOCAL) { +		if (inet_addr_type_dev_table(dev_net(dev), dev, +					     saddr) == RTN_LOCAL) {  			/* saddr should be known to target */  			if (inet_addr_onlink(in_dev, target, saddr))  				break; @@ -346,8 +381,9 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)  		}  	} -	arp_send(ARPOP_REQUEST, ETH_P_ARP, target, dev, saddr, -		 dst_hw, dev->dev_addr, NULL); +	arp_send_dst(ARPOP_REQUEST, ETH_P_ARP, target, dev, saddr, +		     dst_hw, dev->dev_addr, NULL, +		     dev->priv_flags & IFF_XMIT_DST_RELEASE ? NULL : skb);  }  static int arp_ignore(struct in_device *in_dev, __be32 sip, __be32 tip) @@ -597,32 +633,6 @@ void arp_xmit(struct sk_buff *skb)  EXPORT_SYMBOL(arp_xmit);  /* - *	Create and send an arp packet. - */ -void arp_send(int type, int ptype, __be32 dest_ip, -	      struct net_device *dev, __be32 src_ip, -	      const unsigned char *dest_hw, const unsigned char *src_hw, -	      const unsigned char *target_hw) -{ -	struct sk_buff *skb; - -	/* -	 *	No arp on this interface. -	 */ - -	if (dev->flags&IFF_NOARP) -		return; - -	skb = arp_create(type, ptype, dest_ip, dev, src_ip, -			 dest_hw, src_hw, target_hw); -	if (!skb) -		return; - -	arp_xmit(skb); -} -EXPORT_SYMBOL(arp_send); - -/*   *	Process an arp request.   */ @@ -742,7 +752,7 @@ static int arp_process(struct sock *sk, struct sk_buff *skb)  	/* Special case: IPv4 duplicate address detection packet (RFC2131) */  	if (sip == 0) {  		if (arp->ar_op == htons(ARPOP_REQUEST) && -		    inet_addr_type(net, tip) == RTN_LOCAL && +		    inet_addr_type_dev_table(net, dev, tip) == RTN_LOCAL &&  		    !arp_ignore(in_dev, sip, tip))  			arp_send(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, sha,  				 dev->dev_addr, sha); @@ -802,16 +812,18 @@ static int arp_process(struct sock *sk, struct sk_buff *skb)  	n = __neigh_lookup(&arp_tbl, &sip, dev, 0);  	if (IN_DEV_ARP_ACCEPT(in_dev)) { +		unsigned int addr_type = inet_addr_type_dev_table(net, dev, sip); +  		/* Unsolicited ARP is not accepted by default.  		   It is possible, that this option should be enabled for some  		   devices (strip is candidate)  		 */  		is_garp = arp->ar_op == htons(ARPOP_REQUEST) && tip == sip && -			  inet_addr_type(net, sip) == RTN_UNICAST; +			  addr_type == RTN_UNICAST;  		if (!n &&  		    ((arp->ar_op == htons(ARPOP_REPLY)  && -		      inet_addr_type(net, sip) == RTN_UNICAST) || is_garp)) +				addr_type == RTN_UNICAST) || is_garp))  			n = __neigh_lookup(&arp_tbl, &sip, dev, 1);  	} @@ -1017,14 +1029,16 @@ static int arp_req_get(struct arpreq *r, struct net_device *dev)  	neigh = neigh_lookup(&arp_tbl, &ip, dev);  	if (neigh) { -		read_lock_bh(&neigh->lock); -		memcpy(r->arp_ha.sa_data, neigh->ha, dev->addr_len); -		r->arp_flags = arp_state_to_flags(neigh); -		read_unlock_bh(&neigh->lock); -		r->arp_ha.sa_family = dev->type; -		strlcpy(r->arp_dev, dev->name, sizeof(r->arp_dev)); +		if (!(neigh->nud_state & NUD_NOARP)) { +			read_lock_bh(&neigh->lock); +			memcpy(r->arp_ha.sa_data, neigh->ha, dev->addr_len); +			r->arp_flags = arp_state_to_flags(neigh); +			read_unlock_bh(&neigh->lock); +			r->arp_ha.sa_family = dev->type; +			strlcpy(r->arp_dev, dev->name, sizeof(r->arp_dev)); +			err = 0; +		}  		neigh_release(neigh); -		err = 0;  	}  	return err;  }  |