diff options
Diffstat (limited to 'net/core')
| -rw-r--r-- | net/core/datagram.c | 26 | ||||
| -rw-r--r-- | net/core/dev.c | 139 | ||||
| -rw-r--r-- | net/core/dev_addr_lists.c | 210 | ||||
| -rw-r--r-- | net/core/dst.c | 9 | ||||
| -rw-r--r-- | net/core/ethtool.c | 29 | ||||
| -rw-r--r-- | net/core/fib_rules.c | 4 | ||||
| -rw-r--r-- | net/core/filter.c | 5 | ||||
| -rw-r--r-- | net/core/flow.c | 44 | ||||
| -rw-r--r-- | net/core/flow_dissector.c | 70 | ||||
| -rw-r--r-- | net/core/neighbour.c | 57 | ||||
| -rw-r--r-- | net/core/net-procfs.c | 2 | ||||
| -rw-r--r-- | net/core/net_namespace.c | 7 | ||||
| -rw-r--r-- | net/core/netpoll.c | 22 | ||||
| -rw-r--r-- | net/core/pktgen.c | 54 | ||||
| -rw-r--r-- | net/core/rtnetlink.c | 187 | ||||
| -rw-r--r-- | net/core/scm.c | 24 | ||||
| -rw-r--r-- | net/core/secure_seq.c | 4 | ||||
| -rw-r--r-- | net/core/skbuff.c | 93 | ||||
| -rw-r--r-- | net/core/sock.c | 22 | ||||
| -rw-r--r-- | net/core/sock_diag.c | 33 | ||||
| -rw-r--r-- | net/core/utils.c | 5 | 
21 files changed, 691 insertions, 355 deletions
| diff --git a/net/core/datagram.c b/net/core/datagram.c index 368f9c3f9dc6..b71423db7785 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c @@ -78,9 +78,10 @@ static int receiver_wake_function(wait_queue_t *wait, unsigned int mode, int syn  	return autoremove_wake_function(wait, mode, sync, key);  }  /* - * Wait for a packet.. + * Wait for the last received packet to be different from skb   */ -static int wait_for_packet(struct sock *sk, int *err, long *timeo_p) +static int wait_for_more_packets(struct sock *sk, int *err, long *timeo_p, +				 const struct sk_buff *skb)  {  	int error;  	DEFINE_WAIT_FUNC(wait, receiver_wake_function); @@ -92,7 +93,7 @@ static int wait_for_packet(struct sock *sk, int *err, long *timeo_p)  	if (error)  		goto out_err; -	if (!skb_queue_empty(&sk->sk_receive_queue)) +	if (sk->sk_receive_queue.prev != skb)  		goto out;  	/* Socket shut down? */ @@ -131,9 +132,9 @@ out_noerr:   *	__skb_recv_datagram - Receive a datagram skbuff   *	@sk: socket   *	@flags: MSG_ flags + *	@peeked: returns non-zero if this packet has been seen before   *	@off: an offset in bytes to peek skb from. Returns an offset   *	      within an skb where data actually starts - *	@peeked: returns non-zero if this packet has been seen before   *	@err: error code returned   *   *	Get a datagram skbuff, understands the peeking, nonblocking wakeups @@ -161,7 +162,7 @@ out_noerr:  struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags,  				    int *peeked, int *off, int *err)  { -	struct sk_buff *skb; +	struct sk_buff *skb, *last;  	long timeo;  	/*  	 * Caller is allowed not to check sk->sk_err before skb_recv_datagram() @@ -182,13 +183,17 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags,  		 */  		unsigned long cpu_flags;  		struct sk_buff_head *queue = &sk->sk_receive_queue; +		int _off = *off; +		last = (struct sk_buff *)queue;  		spin_lock_irqsave(&queue->lock, cpu_flags);  		skb_queue_walk(queue, skb) { +			last = skb;  			*peeked = skb->peeked;  			if (flags & MSG_PEEK) { -				if (*off >= skb->len && skb->len) { -					*off -= skb->len; +				if (_off >= skb->len && (skb->len || _off || +							 skb->peeked)) { +					_off -= skb->len;  					continue;  				}  				skb->peeked = 1; @@ -197,6 +202,7 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags,  				__skb_unlink(skb, queue);  			spin_unlock_irqrestore(&queue->lock, cpu_flags); +			*off = _off;  			return skb;  		}  		spin_unlock_irqrestore(&queue->lock, cpu_flags); @@ -206,7 +212,7 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags,  		if (!timeo)  			goto no_packet; -	} while (!wait_for_packet(sk, err, &timeo)); +	} while (!wait_for_more_packets(sk, err, &timeo, last));  	return NULL; @@ -749,7 +755,9 @@ unsigned int datagram_poll(struct file *file, struct socket *sock,  	/* exceptional events? */  	if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue)) -		mask |= POLLERR; +		mask |= POLLERR | +			(sock_flag(sk, SOCK_SELECT_ERR_QUEUE) ? POLLPRI : 0); +  	if (sk->sk_shutdown & RCV_SHUTDOWN)  		mask |= POLLRDHUP | POLLIN | POLLRDNORM;  	if (sk->sk_shutdown == SHUTDOWN_MASK) diff --git a/net/core/dev.c b/net/core/dev.c index a06a7a58dd11..4040673f806a 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -200,7 +200,7 @@ static inline void rps_unlock(struct softnet_data *sd)  }  /* Device list insertion */ -static int list_netdevice(struct net_device *dev) +static void list_netdevice(struct net_device *dev)  {  	struct net *net = dev_net(dev); @@ -214,8 +214,6 @@ static int list_netdevice(struct net_device *dev)  	write_unlock_bh(&dev_base_lock);  	dev_base_seq_inc(net); - -	return 0;  }  /* Device list removal @@ -1545,7 +1543,6 @@ void net_enable_timestamp(void)  		return;  	}  #endif -	WARN_ON(in_interrupt());  	static_key_slow_inc(&netstamp_needed);  }  EXPORT_SYMBOL(net_enable_timestamp); @@ -1625,7 +1622,6 @@ int dev_forward_skb(struct net_device *dev, struct sk_buff *skb)  	}  	skb_orphan(skb); -	nf_reset(skb);  	if (unlikely(!is_skb_forwardable(dev, skb))) {  		atomic_long_inc(&dev->rx_dropped); @@ -1641,6 +1637,7 @@ int dev_forward_skb(struct net_device *dev, struct sk_buff *skb)  	skb->mark = 0;  	secpath_reset(skb);  	nf_reset(skb); +	nf_reset_trace(skb);  	return netif_rx(skb);  }  EXPORT_SYMBOL_GPL(dev_forward_skb); @@ -2149,6 +2146,9 @@ static void skb_warn_bad_offload(const struct sk_buff *skb)  	struct net_device *dev = skb->dev;  	const char *driver = ""; +	if (!net_ratelimit()) +		return; +  	if (dev && dev->dev.parent)  		driver = dev_driver_string(dev->dev.parent); @@ -2208,30 +2208,40 @@ out:  }  EXPORT_SYMBOL(skb_checksum_help); -/** - *	skb_mac_gso_segment - mac layer segmentation handler. - *	@skb: buffer to segment - *	@features: features for the output path (see dev->features) - */ -struct sk_buff *skb_mac_gso_segment(struct sk_buff *skb, -				    netdev_features_t features) +__be16 skb_network_protocol(struct sk_buff *skb)  { -	struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT); -	struct packet_offload *ptype;  	__be16 type = skb->protocol; +	int vlan_depth = ETH_HLEN; -	while (type == htons(ETH_P_8021Q)) { -		int vlan_depth = ETH_HLEN; +	while (type == htons(ETH_P_8021Q) || type == htons(ETH_P_8021AD)) {  		struct vlan_hdr *vh;  		if (unlikely(!pskb_may_pull(skb, vlan_depth + VLAN_HLEN))) -			return ERR_PTR(-EINVAL); +			return 0;  		vh = (struct vlan_hdr *)(skb->data + vlan_depth);  		type = vh->h_vlan_encapsulated_proto;  		vlan_depth += VLAN_HLEN;  	} +	return type; +} + +/** + *	skb_mac_gso_segment - mac layer segmentation handler. + *	@skb: buffer to segment + *	@features: features for the output path (see dev->features) + */ +struct sk_buff *skb_mac_gso_segment(struct sk_buff *skb, +				    netdev_features_t features) +{ +	struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT); +	struct packet_offload *ptype; +	__be16 type = skb_network_protocol(skb); + +	if (unlikely(!type)) +		return ERR_PTR(-EINVAL); +  	__skb_pull(skb, skb->mac_len);  	rcu_read_lock(); @@ -2398,24 +2408,12 @@ static int dev_gso_segment(struct sk_buff *skb, netdev_features_t features)  	return 0;  } -static bool can_checksum_protocol(netdev_features_t features, __be16 protocol) -{ -	return ((features & NETIF_F_GEN_CSUM) || -		((features & NETIF_F_V4_CSUM) && -		 protocol == htons(ETH_P_IP)) || -		((features & NETIF_F_V6_CSUM) && -		 protocol == htons(ETH_P_IPV6)) || -		((features & NETIF_F_FCOE_CRC) && -		 protocol == htons(ETH_P_FCOE))); -} -  static netdev_features_t harmonize_features(struct sk_buff *skb,  	__be16 protocol, netdev_features_t features)  {  	if (skb->ip_summed != CHECKSUM_NONE &&  	    !can_checksum_protocol(features, protocol)) {  		features &= ~NETIF_F_ALL_CSUM; -		features &= ~NETIF_F_SG;  	} else if (illegal_highdma(skb->dev, skb)) {  		features &= ~NETIF_F_SG;  	} @@ -2431,20 +2429,22 @@ netdev_features_t netif_skb_features(struct sk_buff *skb)  	if (skb_shinfo(skb)->gso_segs > skb->dev->gso_max_segs)  		features &= ~NETIF_F_GSO_MASK; -	if (protocol == htons(ETH_P_8021Q)) { +	if (protocol == htons(ETH_P_8021Q) || protocol == htons(ETH_P_8021AD)) {  		struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data;  		protocol = veh->h_vlan_encapsulated_proto;  	} else if (!vlan_tx_tag_present(skb)) {  		return harmonize_features(skb, protocol, features);  	} -	features &= (skb->dev->vlan_features | NETIF_F_HW_VLAN_TX); +	features &= (skb->dev->vlan_features | NETIF_F_HW_VLAN_CTAG_TX | +					       NETIF_F_HW_VLAN_STAG_TX); -	if (protocol != htons(ETH_P_8021Q)) { +	if (protocol != htons(ETH_P_8021Q) && protocol != htons(ETH_P_8021AD)) {  		return harmonize_features(skb, protocol, features);  	} else {  		features &= NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | -				NETIF_F_GEN_CSUM | NETIF_F_HW_VLAN_TX; +				NETIF_F_GEN_CSUM | NETIF_F_HW_VLAN_CTAG_TX | +				NETIF_F_HW_VLAN_STAG_TX;  		return harmonize_features(skb, protocol, features);  	}  } @@ -2485,8 +2485,9 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,  		features = netif_skb_features(skb);  		if (vlan_tx_tag_present(skb) && -		    !(features & NETIF_F_HW_VLAN_TX)) { -			skb = __vlan_put_tag(skb, vlan_tx_tag_get(skb)); +		    !vlan_hw_offload_capable(features, skb->vlan_proto)) { +			skb = __vlan_put_tag(skb, skb->vlan_proto, +					     vlan_tx_tag_get(skb));  			if (unlikely(!skb))  				goto out; @@ -2545,13 +2546,6 @@ gso:  		skb->next = nskb->next;  		nskb->next = NULL; -		/* -		 * If device doesn't need nskb->dst, release it right now while -		 * its hot in this cpu cache -		 */ -		if (dev->priv_flags & IFF_XMIT_DST_RELEASE) -			skb_dst_drop(nskb); -  		if (!list_empty(&ptype_all))  			dev_queue_xmit_nit(nskb, dev); @@ -2571,8 +2565,11 @@ gso:  	} while (skb->next);  out_kfree_gso_skb: -	if (likely(skb->next == NULL)) +	if (likely(skb->next == NULL)) {  		skb->destructor = DEV_GSO_CB(skb)->destructor; +		consume_skb(skb); +		return rc; +	}  out_kfree_skb:  	kfree_skb(skb);  out: @@ -2590,6 +2587,7 @@ static void qdisc_pkt_len_init(struct sk_buff *skb)  	 */  	if (shinfo->gso_size)  {  		unsigned int hdr_len; +		u16 gso_segs = shinfo->gso_segs;  		/* mac layer + network layer */  		hdr_len = skb_transport_header(skb) - skb_mac_header(skb); @@ -2599,7 +2597,12 @@ static void qdisc_pkt_len_init(struct sk_buff *skb)  			hdr_len += tcp_hdrlen(skb);  		else  			hdr_len += sizeof(struct udphdr); -		qdisc_skb_cb(skb)->pkt_len += (shinfo->gso_segs - 1) * hdr_len; + +		if (shinfo->gso_type & SKB_GSO_DODGY) +			gso_segs = DIV_ROUND_UP(skb->len - hdr_len, +						shinfo->gso_size); + +		qdisc_skb_cb(skb)->pkt_len += (gso_segs - 1) * hdr_len;  	}  } @@ -3315,6 +3318,7 @@ int netdev_rx_handler_register(struct net_device *dev,  	if (dev->rx_handler)  		return -EBUSY; +	/* Note: rx_handler_data must be set before rx_handler */  	rcu_assign_pointer(dev->rx_handler_data, rx_handler_data);  	rcu_assign_pointer(dev->rx_handler, rx_handler); @@ -3326,7 +3330,7 @@ EXPORT_SYMBOL_GPL(netdev_rx_handler_register);   *	netdev_rx_handler_unregister - unregister receive handler   *	@dev: device to unregister a handler from   * - *	Unregister a receive hander from a device. + *	Unregister a receive handler from a device.   *   *	The caller must hold the rtnl_mutex.   */ @@ -3335,6 +3339,11 @@ void netdev_rx_handler_unregister(struct net_device *dev)  	ASSERT_RTNL();  	RCU_INIT_POINTER(dev->rx_handler, NULL); +	/* a reader seeing a non NULL rx_handler in a rcu_read_lock() +	 * section has a guarantee to see a non NULL rx_handler_data +	 * as well. +	 */ +	synchronize_net();  	RCU_INIT_POINTER(dev->rx_handler_data, NULL);  }  EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister); @@ -3350,6 +3359,7 @@ static bool skb_pfmemalloc_protocol(struct sk_buff *skb)  	case __constant_htons(ETH_P_IP):  	case __constant_htons(ETH_P_IPV6):  	case __constant_htons(ETH_P_8021Q): +	case __constant_htons(ETH_P_8021AD):  		return true;  	default:  		return false; @@ -3390,7 +3400,8 @@ another_round:  	__this_cpu_inc(softnet_data.processed); -	if (skb->protocol == cpu_to_be16(ETH_P_8021Q)) { +	if (skb->protocol == cpu_to_be16(ETH_P_8021Q) || +	    skb->protocol == cpu_to_be16(ETH_P_8021AD)) {  		skb = vlan_untag(skb);  		if (unlikely(!skb))  			goto unlock; @@ -3444,6 +3455,7 @@ ncls:  		}  		switch (rx_handler(&skb)) {  		case RX_HANDLER_CONSUMED: +			ret = NET_RX_SUCCESS;  			goto unlock;  		case RX_HANDLER_ANOTHER:  			goto another_round; @@ -4057,6 +4069,9 @@ void netif_napi_add(struct net_device *dev, struct napi_struct *napi,  	napi->gro_list = NULL;  	napi->skb = NULL;  	napi->poll = poll; +	if (weight > NAPI_POLL_WEIGHT) +		pr_err_once("netif_napi_add() called with weight %d on device %s\n", +			    weight, dev->name);  	napi->weight = weight;  	list_add(&napi->dev_list, &dev->napi_list);  	napi->dev = dev; @@ -4103,7 +4118,7 @@ static void net_rx_action(struct softirq_action *h)  		 * Allow this to run for 2 jiffies since which will allow  		 * an average latency of 1.5/HZ.  		 */ -		if (unlikely(budget <= 0 || time_after(jiffies, time_limit))) +		if (unlikely(budget <= 0 || time_after_eq(jiffies, time_limit)))  			goto softnet_break;  		local_irq_enable(); @@ -4780,7 +4795,7 @@ EXPORT_SYMBOL(dev_set_mac_address);  /**   *	dev_change_carrier - Change device carrier   *	@dev: device - *	@new_carries: new value + *	@new_carrier: new value   *   *	Change device carrier   */ @@ -4918,20 +4933,25 @@ static netdev_features_t netdev_fix_features(struct net_device *dev,  		features &= ~(NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM);  	} -	/* Fix illegal SG+CSUM combinations. */ -	if ((features & NETIF_F_SG) && -	    !(features & NETIF_F_ALL_CSUM)) { -		netdev_dbg(dev, -			"Dropping NETIF_F_SG since no checksum feature.\n"); -		features &= ~NETIF_F_SG; -	} -  	/* TSO requires that SG is present as well. */  	if ((features & NETIF_F_ALL_TSO) && !(features & NETIF_F_SG)) {  		netdev_dbg(dev, "Dropping TSO features since no SG feature.\n");  		features &= ~NETIF_F_ALL_TSO;  	} +	if ((features & NETIF_F_TSO) && !(features & NETIF_F_HW_CSUM) && +					!(features & NETIF_F_IP_CSUM)) { +		netdev_dbg(dev, "Dropping TSO features since no CSUM feature.\n"); +		features &= ~NETIF_F_TSO; +		features &= ~NETIF_F_TSO_ECN; +	} + +	if ((features & NETIF_F_TSO6) && !(features & NETIF_F_HW_CSUM) && +					 !(features & NETIF_F_IPV6_CSUM)) { +		netdev_dbg(dev, "Dropping TSO6 features since no CSUM feature.\n"); +		features &= ~NETIF_F_TSO6; +	} +  	/* TSO ECN requires that TSO is present as well. */  	if ((features & NETIF_F_ALL_TSO) == NETIF_F_TSO_ECN)  		features &= ~NETIF_F_TSO_ECN; @@ -5162,7 +5182,8 @@ int register_netdevice(struct net_device *dev)  		}  	} -	if (((dev->hw_features | dev->features) & NETIF_F_HW_VLAN_FILTER) && +	if (((dev->hw_features | dev->features) & +	     NETIF_F_HW_VLAN_CTAG_FILTER) &&  	    (!dev->netdev_ops->ndo_vlan_rx_add_vid ||  	     !dev->netdev_ops->ndo_vlan_rx_kill_vid)) {  		netdev_WARN(dev, "Buggy VLAN acceleration in driver!\n"); @@ -5199,6 +5220,10 @@ int register_netdevice(struct net_device *dev)  	 */  	dev->vlan_features |= NETIF_F_HIGHDMA; +	/* Make NETIF_F_SG inheritable to tunnel devices. +	 */ +	dev->hw_enc_features |= NETIF_F_SG; +  	ret = call_netdevice_notifiers(NETDEV_POST_INIT, dev);  	ret = notifier_to_errno(ret);  	if (ret) diff --git a/net/core/dev_addr_lists.c b/net/core/dev_addr_lists.c index bd2eb9d3e369..c013f38482a1 100644 --- a/net/core/dev_addr_lists.c +++ b/net/core/dev_addr_lists.c @@ -22,7 +22,8 @@  static int __hw_addr_create_ex(struct netdev_hw_addr_list *list,  			       const unsigned char *addr, int addr_len, -			       unsigned char addr_type, bool global) +			       unsigned char addr_type, bool global, +			       bool sync)  {  	struct netdev_hw_addr *ha;  	int alloc_size; @@ -37,7 +38,7 @@ static int __hw_addr_create_ex(struct netdev_hw_addr_list *list,  	ha->type = addr_type;  	ha->refcount = 1;  	ha->global_use = global; -	ha->synced = false; +	ha->synced = sync;  	list_add_tail_rcu(&ha->list, &list->list);  	list->count++; @@ -46,7 +47,7 @@ static int __hw_addr_create_ex(struct netdev_hw_addr_list *list,  static int __hw_addr_add_ex(struct netdev_hw_addr_list *list,  			    const unsigned char *addr, int addr_len, -			    unsigned char addr_type, bool global) +			    unsigned char addr_type, bool global, bool sync)  {  	struct netdev_hw_addr *ha; @@ -63,43 +64,62 @@ static int __hw_addr_add_ex(struct netdev_hw_addr_list *list,  				else  					ha->global_use = true;  			} +			if (sync) { +				if (ha->synced) +					return 0; +				else +					ha->synced = true; +			}  			ha->refcount++;  			return 0;  		}  	} -	return __hw_addr_create_ex(list, addr, addr_len, addr_type, global); +	return __hw_addr_create_ex(list, addr, addr_len, addr_type, global, +				   sync);  }  static int __hw_addr_add(struct netdev_hw_addr_list *list,  			 const unsigned char *addr, int addr_len,  			 unsigned char addr_type)  { -	return __hw_addr_add_ex(list, addr, addr_len, addr_type, false); +	return __hw_addr_add_ex(list, addr, addr_len, addr_type, false, false); +} + +static int __hw_addr_del_entry(struct netdev_hw_addr_list *list, +			       struct netdev_hw_addr *ha, bool global, +			       bool sync) +{ +	if (global && !ha->global_use) +		return -ENOENT; + +	if (sync && !ha->synced) +		return -ENOENT; + +	if (global) +		ha->global_use = false; + +	if (sync) +		ha->synced = false; + +	if (--ha->refcount) +		return 0; +	list_del_rcu(&ha->list); +	kfree_rcu(ha, rcu_head); +	list->count--; +	return 0;  }  static int __hw_addr_del_ex(struct netdev_hw_addr_list *list,  			    const unsigned char *addr, int addr_len, -			    unsigned char addr_type, bool global) +			    unsigned char addr_type, bool global, bool sync)  {  	struct netdev_hw_addr *ha;  	list_for_each_entry(ha, &list->list, list) {  		if (!memcmp(ha->addr, addr, addr_len) && -		    (ha->type == addr_type || !addr_type)) { -			if (global) { -				if (!ha->global_use) -					break; -				else -					ha->global_use = false; -			} -			if (--ha->refcount) -				return 0; -			list_del_rcu(&ha->list); -			kfree_rcu(ha, rcu_head); -			list->count--; -			return 0; -		} +		    (ha->type == addr_type || !addr_type)) +			return __hw_addr_del_entry(list, ha, global, sync);  	}  	return -ENOENT;  } @@ -108,7 +128,57 @@ static int __hw_addr_del(struct netdev_hw_addr_list *list,  			 const unsigned char *addr, int addr_len,  			 unsigned char addr_type)  { -	return __hw_addr_del_ex(list, addr, addr_len, addr_type, false); +	return __hw_addr_del_ex(list, addr, addr_len, addr_type, false, false); +} + +static int __hw_addr_sync_one(struct netdev_hw_addr_list *to_list, +			       struct netdev_hw_addr *ha, +			       int addr_len) +{ +	int err; + +	err = __hw_addr_add_ex(to_list, ha->addr, addr_len, ha->type, +			       false, true); +	if (err) +		return err; +	ha->sync_cnt++; +	ha->refcount++; + +	return 0; +} + +static void __hw_addr_unsync_one(struct netdev_hw_addr_list *to_list, +				 struct netdev_hw_addr_list *from_list, +				 struct netdev_hw_addr *ha, +				 int addr_len) +{ +	int err; + +	err = __hw_addr_del_ex(to_list, ha->addr, addr_len, ha->type, +			       false, true); +	if (err) +		return; +	ha->sync_cnt--; +	__hw_addr_del_entry(from_list, ha, false, true); +} + +static int __hw_addr_sync_multiple(struct netdev_hw_addr_list *to_list, +				   struct netdev_hw_addr_list *from_list, +				   int addr_len) +{ +	int err = 0; +	struct netdev_hw_addr *ha, *tmp; + +	list_for_each_entry_safe(ha, tmp, &from_list->list, list) { +		if (ha->sync_cnt == ha->refcount) { +			__hw_addr_unsync_one(to_list, from_list, ha, addr_len); +		} else { +			err = __hw_addr_sync_one(to_list, ha, addr_len); +			if (err) +				break; +		} +	} +	return err;  }  int __hw_addr_add_multiple(struct netdev_hw_addr_list *to_list, @@ -152,6 +222,11 @@ void __hw_addr_del_multiple(struct netdev_hw_addr_list *to_list,  }  EXPORT_SYMBOL(__hw_addr_del_multiple); +/* This function only works where there is a strict 1-1 relationship + * between source and destionation of they synch. If you ever need to + * sync addresses to more then 1 destination, you need to use + * __hw_addr_sync_multiple(). + */  int __hw_addr_sync(struct netdev_hw_addr_list *to_list,  		   struct netdev_hw_addr_list *from_list,  		   int addr_len) @@ -160,17 +235,12 @@ int __hw_addr_sync(struct netdev_hw_addr_list *to_list,  	struct netdev_hw_addr *ha, *tmp;  	list_for_each_entry_safe(ha, tmp, &from_list->list, list) { -		if (!ha->synced) { -			err = __hw_addr_add(to_list, ha->addr, -					    addr_len, ha->type); +		if (!ha->sync_cnt) { +			err = __hw_addr_sync_one(to_list, ha, addr_len);  			if (err)  				break; -			ha->synced = true; -			ha->refcount++; -		} else if (ha->refcount == 1) { -			__hw_addr_del(to_list, ha->addr, addr_len, ha->type); -			__hw_addr_del(from_list, ha->addr, addr_len, ha->type); -		} +		} else if (ha->refcount == 1) +			__hw_addr_unsync_one(to_list, from_list, ha, addr_len);  	}  	return err;  } @@ -183,13 +253,8 @@ void __hw_addr_unsync(struct netdev_hw_addr_list *to_list,  	struct netdev_hw_addr *ha, *tmp;  	list_for_each_entry_safe(ha, tmp, &from_list->list, list) { -		if (ha->synced) { -			__hw_addr_del(to_list, ha->addr, -				      addr_len, ha->type); -			ha->synced = false; -			__hw_addr_del(from_list, ha->addr, -				      addr_len, ha->type); -		} +		if (ha->sync_cnt) +			__hw_addr_unsync_one(to_list, from_list, ha, addr_len);  	}  }  EXPORT_SYMBOL(__hw_addr_unsync); @@ -406,7 +471,7 @@ int dev_uc_add_excl(struct net_device *dev, const unsigned char *addr)  		}  	}  	err = __hw_addr_create_ex(&dev->uc, addr, dev->addr_len, -				  NETDEV_HW_ADDR_T_UNICAST, true); +				  NETDEV_HW_ADDR_T_UNICAST, true, false);  	if (!err)  		__dev_set_rx_mode(dev);  out: @@ -469,7 +534,8 @@ EXPORT_SYMBOL(dev_uc_del);   *	locked by netif_addr_lock_bh.   *   *	This function is intended to be called from the dev->set_rx_mode - *	function of layered software devices. + *	function of layered software devices.  This function assumes that + *	addresses will only ever be synced to the @to devices and no other.   */  int dev_uc_sync(struct net_device *to, struct net_device *from)  { @@ -488,6 +554,36 @@ int dev_uc_sync(struct net_device *to, struct net_device *from)  EXPORT_SYMBOL(dev_uc_sync);  /** + *	dev_uc_sync_multiple - Synchronize device's unicast list to another + *	device, but allow for multiple calls to sync to multiple devices. + *	@to: destination device + *	@from: source device + * + *	Add newly added addresses to the destination device and release + *	addresses that have been deleted from the source. The source device + *	must be locked by netif_addr_lock_bh. + * + *	This function is intended to be called from the dev->set_rx_mode + *	function of layered software devices.  It allows for a single source + *	device to be synced to multiple destination devices. + */ +int dev_uc_sync_multiple(struct net_device *to, struct net_device *from) +{ +	int err = 0; + +	if (to->addr_len != from->addr_len) +		return -EINVAL; + +	netif_addr_lock_nested(to); +	err = __hw_addr_sync_multiple(&to->uc, &from->uc, to->addr_len); +	if (!err) +		__dev_set_rx_mode(to); +	netif_addr_unlock(to); +	return err; +} +EXPORT_SYMBOL(dev_uc_sync_multiple); + +/**   *	dev_uc_unsync - Remove synchronized addresses from the destination device   *	@to: destination device   *	@from: source device @@ -559,7 +655,7 @@ int dev_mc_add_excl(struct net_device *dev, const unsigned char *addr)  		}  	}  	err = __hw_addr_create_ex(&dev->mc, addr, dev->addr_len, -				  NETDEV_HW_ADDR_T_MULTICAST, true); +				  NETDEV_HW_ADDR_T_MULTICAST, true, false);  	if (!err)  		__dev_set_rx_mode(dev);  out: @@ -575,7 +671,7 @@ static int __dev_mc_add(struct net_device *dev, const unsigned char *addr,  	netif_addr_lock_bh(dev);  	err = __hw_addr_add_ex(&dev->mc, addr, dev->addr_len, -			       NETDEV_HW_ADDR_T_MULTICAST, global); +			       NETDEV_HW_ADDR_T_MULTICAST, global, false);  	if (!err)  		__dev_set_rx_mode(dev);  	netif_addr_unlock_bh(dev); @@ -615,7 +711,7 @@ static int __dev_mc_del(struct net_device *dev, const unsigned char *addr,  	netif_addr_lock_bh(dev);  	err = __hw_addr_del_ex(&dev->mc, addr, dev->addr_len, -			       NETDEV_HW_ADDR_T_MULTICAST, global); +			       NETDEV_HW_ADDR_T_MULTICAST, global, false);  	if (!err)  		__dev_set_rx_mode(dev);  	netif_addr_unlock_bh(dev); @@ -679,6 +775,36 @@ int dev_mc_sync(struct net_device *to, struct net_device *from)  EXPORT_SYMBOL(dev_mc_sync);  /** + *	dev_mc_sync_multiple - Synchronize device's unicast list to another + *	device, but allow for multiple calls to sync to multiple devices. + *	@to: destination device + *	@from: source device + * + *	Add newly added addresses to the destination device and release + *	addresses that have no users left. The source device must be + *	locked by netif_addr_lock_bh. + * + *	This function is intended to be called from the ndo_set_rx_mode + *	function of layered software devices.  It allows for a single + *	source device to be synced to multiple destination devices. + */ +int dev_mc_sync_multiple(struct net_device *to, struct net_device *from) +{ +	int err = 0; + +	if (to->addr_len != from->addr_len) +		return -EINVAL; + +	netif_addr_lock_nested(to); +	err = __hw_addr_sync(&to->mc, &from->mc, to->addr_len); +	if (!err) +		__dev_set_rx_mode(to); +	netif_addr_unlock(to); +	return err; +} +EXPORT_SYMBOL(dev_mc_sync_multiple); + +/**   *	dev_mc_unsync - Remove synchronized addresses from the destination device   *	@to: destination device   *	@from: source device diff --git a/net/core/dst.c b/net/core/dst.c index 35fd12f1a69c..df9cc810ec8e 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -320,27 +320,28 @@ void __dst_destroy_metrics_generic(struct dst_entry *dst, unsigned long old)  EXPORT_SYMBOL(__dst_destroy_metrics_generic);  /** - * skb_dst_set_noref - sets skb dst, without a reference + * __skb_dst_set_noref - sets skb dst, without a reference   * @skb: buffer   * @dst: dst entry + * @force: if force is set, use noref version even for DST_NOCACHE entries   *   * Sets skb dst, assuming a reference was not taken on dst   * skb_dst_drop() should not dst_release() this dst   */ -void skb_dst_set_noref(struct sk_buff *skb, struct dst_entry *dst) +void __skb_dst_set_noref(struct sk_buff *skb, struct dst_entry *dst, bool force)  {  	WARN_ON(!rcu_read_lock_held() && !rcu_read_lock_bh_held());  	/* If dst not in cache, we must take a reference, because  	 * dst_release() will destroy dst as soon as its refcount becomes zero  	 */ -	if (unlikely(dst->flags & DST_NOCACHE)) { +	if (unlikely((dst->flags & DST_NOCACHE) && !force)) {  		dst_hold(dst);  		skb_dst_set(skb, dst);  	} else {  		skb->_skb_refdst = (unsigned long)dst | SKB_DST_NOREF;  	}  } -EXPORT_SYMBOL(skb_dst_set_noref); +EXPORT_SYMBOL(__skb_dst_set_noref);  /* Dirty hack. We did it in 2.2 (in __dst_free),   * we have _very_ good reasons not to repeat diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 3e9b2c3e30f0..5a934ef90f8b 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -60,10 +60,13 @@ static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN]  	[NETIF_F_IPV6_CSUM_BIT] =        "tx-checksum-ipv6",  	[NETIF_F_HIGHDMA_BIT] =          "highdma",  	[NETIF_F_FRAGLIST_BIT] =         "tx-scatter-gather-fraglist", -	[NETIF_F_HW_VLAN_TX_BIT] =       "tx-vlan-hw-insert", +	[NETIF_F_HW_VLAN_CTAG_TX_BIT] =  "tx-vlan-ctag-hw-insert", -	[NETIF_F_HW_VLAN_RX_BIT] =       "rx-vlan-hw-parse", -	[NETIF_F_HW_VLAN_FILTER_BIT] =   "rx-vlan-filter", +	[NETIF_F_HW_VLAN_CTAG_RX_BIT] =  "rx-vlan-ctag-hw-parse", +	[NETIF_F_HW_VLAN_CTAG_FILTER_BIT] = "rx-vlan-ctag-filter", +	[NETIF_F_HW_VLAN_STAG_TX_BIT] =  "tx-vlan-stag-hw-insert", +	[NETIF_F_HW_VLAN_STAG_RX_BIT] =  "rx-vlan-stag-hw-parse", +	[NETIF_F_HW_VLAN_STAG_FILTER_BIT] = "rx-vlan-stag-filter",  	[NETIF_F_VLAN_CHALLENGED_BIT] =  "vlan-challenged",  	[NETIF_F_GSO_BIT] =              "tx-generic-segmentation",  	[NETIF_F_LLTX_BIT] =             "tx-lockless", @@ -78,6 +81,7 @@ static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN]  	[NETIF_F_TSO6_BIT] =             "tx-tcp6-segmentation",  	[NETIF_F_FSO_BIT] =              "tx-fcoe-segmentation",  	[NETIF_F_GSO_GRE_BIT] =		 "tx-gre-segmentation", +	[NETIF_F_GSO_UDP_TUNNEL_BIT] =	 "tx-udp_tnl-segmentation",  	[NETIF_F_FCOE_CRC_BIT] =         "tx-checksum-fcoe-crc",  	[NETIF_F_SCTP_CSUM_BIT] =        "tx-checksum-sctp", @@ -266,18 +270,19 @@ static int ethtool_set_one_feature(struct net_device *dev,  #define ETH_ALL_FLAGS    (ETH_FLAG_LRO | ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN | \  			  ETH_FLAG_NTUPLE | ETH_FLAG_RXHASH) -#define ETH_ALL_FEATURES (NETIF_F_LRO | NETIF_F_HW_VLAN_RX | \ -			  NETIF_F_HW_VLAN_TX | NETIF_F_NTUPLE | NETIF_F_RXHASH) +#define ETH_ALL_FEATURES (NETIF_F_LRO | NETIF_F_HW_VLAN_CTAG_RX | \ +			  NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_NTUPLE | \ +			  NETIF_F_RXHASH)  static u32 __ethtool_get_flags(struct net_device *dev)  {  	u32 flags = 0; -	if (dev->features & NETIF_F_LRO)	flags |= ETH_FLAG_LRO; -	if (dev->features & NETIF_F_HW_VLAN_RX)	flags |= ETH_FLAG_RXVLAN; -	if (dev->features & NETIF_F_HW_VLAN_TX)	flags |= ETH_FLAG_TXVLAN; -	if (dev->features & NETIF_F_NTUPLE)	flags |= ETH_FLAG_NTUPLE; -	if (dev->features & NETIF_F_RXHASH)	flags |= ETH_FLAG_RXHASH; +	if (dev->features & NETIF_F_LRO)	     flags |= ETH_FLAG_LRO; +	if (dev->features & NETIF_F_HW_VLAN_CTAG_RX) flags |= ETH_FLAG_RXVLAN; +	if (dev->features & NETIF_F_HW_VLAN_CTAG_TX) flags |= ETH_FLAG_TXVLAN; +	if (dev->features & NETIF_F_NTUPLE)	     flags |= ETH_FLAG_NTUPLE; +	if (dev->features & NETIF_F_RXHASH)	     flags |= ETH_FLAG_RXHASH;  	return flags;  } @@ -290,8 +295,8 @@ static int __ethtool_set_flags(struct net_device *dev, u32 data)  		return -EINVAL;  	if (data & ETH_FLAG_LRO)	features |= NETIF_F_LRO; -	if (data & ETH_FLAG_RXVLAN)	features |= NETIF_F_HW_VLAN_RX; -	if (data & ETH_FLAG_TXVLAN)	features |= NETIF_F_HW_VLAN_TX; +	if (data & ETH_FLAG_RXVLAN)	features |= NETIF_F_HW_VLAN_CTAG_RX; +	if (data & ETH_FLAG_TXVLAN)	features |= NETIF_F_HW_VLAN_CTAG_TX;  	if (data & ETH_FLAG_NTUPLE)	features |= NETIF_F_NTUPLE;  	if (data & ETH_FLAG_RXHASH)	features |= NETIF_F_RXHASH; diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 58a4ba27dfe3..d5a9f8ead0d8 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -266,7 +266,7 @@ errout:  	return err;  } -static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) +static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh)  {  	struct net *net = sock_net(skb->sk);  	struct fib_rule_hdr *frh = nlmsg_data(nlh); @@ -415,7 +415,7 @@ errout:  	return err;  } -static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) +static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh)  {  	struct net *net = sock_net(skb->sk);  	struct fib_rule_hdr *frh = nlmsg_data(nlh); diff --git a/net/core/filter.c b/net/core/filter.c index 2e20b55a7830..dad2a178f9f8 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -348,6 +348,9 @@ load_b:  		case BPF_S_ANC_VLAN_TAG_PRESENT:  			A = !!vlan_tx_tag_present(skb);  			continue; +		case BPF_S_ANC_PAY_OFFSET: +			A = __skb_get_poff(skb); +			continue;  		case BPF_S_ANC_NLATTR: {  			struct nlattr *nla; @@ -612,6 +615,7 @@ int sk_chk_filter(struct sock_filter *filter, unsigned int flen)  			ANCILLARY(ALU_XOR_X);  			ANCILLARY(VLAN_TAG);  			ANCILLARY(VLAN_TAG_PRESENT); +			ANCILLARY(PAY_OFFSET);  			}  			/* ancillary operation unknown or unsupported */ @@ -814,6 +818,7 @@ static void sk_decode_filter(struct sock_filter *filt, struct sock_filter *to)  		[BPF_S_ANC_SECCOMP_LD_W] = BPF_LD|BPF_B|BPF_ABS,  		[BPF_S_ANC_VLAN_TAG]	= BPF_LD|BPF_B|BPF_ABS,  		[BPF_S_ANC_VLAN_TAG_PRESENT] = BPF_LD|BPF_B|BPF_ABS, +		[BPF_S_ANC_PAY_OFFSET]	= BPF_LD|BPF_B|BPF_ABS,  		[BPF_S_LD_W_LEN]	= BPF_LD|BPF_W|BPF_LEN,  		[BPF_S_LD_W_IND]	= BPF_LD|BPF_W|BPF_IND,  		[BPF_S_LD_H_IND]	= BPF_LD|BPF_H|BPF_IND, diff --git a/net/core/flow.c b/net/core/flow.c index c56ea6f7f6c7..7102f166482d 100644 --- a/net/core/flow.c +++ b/net/core/flow.c @@ -323,12 +323,30 @@ static void flow_cache_flush_tasklet(unsigned long data)  		complete(&info->completion);  } +/* + * Return whether a cpu needs flushing.  Conservatively, we assume + * the presence of any entries means the core may require flushing, + * since the flow_cache_ops.check() function may assume it's running + * on the same core as the per-cpu cache component. + */ +static int flow_cache_percpu_empty(struct flow_cache *fc, int cpu) +{ +	struct flow_cache_percpu *fcp; +	int i; + +	fcp = per_cpu_ptr(fc->percpu, cpu); +	for (i = 0; i < flow_cache_hash_size(fc); i++) +		if (!hlist_empty(&fcp->hash_table[i])) +			return 0; +	return 1; +} +  static void flow_cache_flush_per_cpu(void *data)  {  	struct flow_flush_info *info = data;  	struct tasklet_struct *tasklet; -	tasklet = this_cpu_ptr(&info->cache->percpu->flush_tasklet); +	tasklet = &this_cpu_ptr(info->cache->percpu)->flush_tasklet;  	tasklet->data = (unsigned long)info;  	tasklet_schedule(tasklet);  } @@ -337,22 +355,40 @@ void flow_cache_flush(void)  {  	struct flow_flush_info info;  	static DEFINE_MUTEX(flow_flush_sem); +	cpumask_var_t mask; +	int i, self; + +	/* Track which cpus need flushing to avoid disturbing all cores. */ +	if (!alloc_cpumask_var(&mask, GFP_KERNEL)) +		return; +	cpumask_clear(mask);  	/* Don't want cpus going down or up during this. */  	get_online_cpus();  	mutex_lock(&flow_flush_sem);  	info.cache = &flow_cache_global; -	atomic_set(&info.cpuleft, num_online_cpus()); +	for_each_online_cpu(i) +		if (!flow_cache_percpu_empty(info.cache, i)) +			cpumask_set_cpu(i, mask); +	atomic_set(&info.cpuleft, cpumask_weight(mask)); +	if (atomic_read(&info.cpuleft) == 0) +		goto done; +  	init_completion(&info.completion);  	local_bh_disable(); -	smp_call_function(flow_cache_flush_per_cpu, &info, 0); -	flow_cache_flush_tasklet((unsigned long)&info); +	self = cpumask_test_and_clear_cpu(smp_processor_id(), mask); +	on_each_cpu_mask(mask, flow_cache_flush_per_cpu, &info, 0); +	if (self) +		flow_cache_flush_tasklet((unsigned long)&info);  	local_bh_enable();  	wait_for_completion(&info.completion); + +done:  	mutex_unlock(&flow_flush_sem);  	put_online_cpus(); +	free_cpumask_var(mask);  }  static void flow_cache_flush_task(struct work_struct *work) diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 9d4c7201400d..00ee068efc1c 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -5,6 +5,10 @@  #include <linux/if_vlan.h>  #include <net/ip.h>  #include <net/ipv6.h> +#include <linux/igmp.h> +#include <linux/icmp.h> +#include <linux/sctp.h> +#include <linux/dccp.h>  #include <linux/if_tunnel.h>  #include <linux/if_pppox.h>  #include <linux/ppp_defs.h> @@ -119,6 +123,17 @@ ipv6:  				nhoff += 4;  			if (hdr->flags & GRE_SEQ)  				nhoff += 4; +			if (proto == htons(ETH_P_TEB)) { +				const struct ethhdr *eth; +				struct ethhdr _eth; + +				eth = skb_header_pointer(skb, nhoff, +							 sizeof(_eth), &_eth); +				if (!eth) +					return false; +				proto = eth->h_proto; +				nhoff += sizeof(*eth); +			}  			goto again;  		}  		break; @@ -140,6 +155,8 @@ ipv6:  			flow->ports = *ports;  	} +	flow->thoff = (u16) nhoff; +  	return true;  }  EXPORT_SYMBOL(skb_flow_dissect); @@ -215,6 +232,59 @@ u16 __skb_tx_hash(const struct net_device *dev, const struct sk_buff *skb,  }  EXPORT_SYMBOL(__skb_tx_hash); +/* __skb_get_poff() returns the offset to the payload as far as it could + * be dissected. The main user is currently BPF, so that we can dynamically + * truncate packets without needing to push actual payload to the user + * space and can analyze headers only, instead. + */ +u32 __skb_get_poff(const struct sk_buff *skb) +{ +	struct flow_keys keys; +	u32 poff = 0; + +	if (!skb_flow_dissect(skb, &keys)) +		return 0; + +	poff += keys.thoff; +	switch (keys.ip_proto) { +	case IPPROTO_TCP: { +		const struct tcphdr *tcph; +		struct tcphdr _tcph; + +		tcph = skb_header_pointer(skb, poff, sizeof(_tcph), &_tcph); +		if (!tcph) +			return poff; + +		poff += max_t(u32, sizeof(struct tcphdr), tcph->doff * 4); +		break; +	} +	case IPPROTO_UDP: +	case IPPROTO_UDPLITE: +		poff += sizeof(struct udphdr); +		break; +	/* For the rest, we do not really care about header +	 * extensions at this point for now. +	 */ +	case IPPROTO_ICMP: +		poff += sizeof(struct icmphdr); +		break; +	case IPPROTO_ICMPV6: +		poff += sizeof(struct icmp6hdr); +		break; +	case IPPROTO_IGMP: +		poff += sizeof(struct igmphdr); +		break; +	case IPPROTO_DCCP: +		poff += sizeof(struct dccp_hdr); +		break; +	case IPPROTO_SCTP: +		poff += sizeof(struct sctphdr); +		break; +	} + +	return poff; +} +  static inline u16 dev_cap_txqueue(struct net_device *dev, u16 queue_index)  {  	if (unlikely(queue_index >= dev->real_num_tx_queues)) { diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 3863b8f639c5..5c56b217b999 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -39,21 +39,13 @@  #include <linux/string.h>  #include <linux/log2.h> +#define DEBUG  #define NEIGH_DEBUG 1 - -#define NEIGH_PRINTK(x...) printk(x) -#define NEIGH_NOPRINTK(x...) do { ; } while(0) -#define NEIGH_PRINTK1 NEIGH_NOPRINTK -#define NEIGH_PRINTK2 NEIGH_NOPRINTK - -#if NEIGH_DEBUG >= 1 -#undef NEIGH_PRINTK1 -#define NEIGH_PRINTK1 NEIGH_PRINTK -#endif -#if NEIGH_DEBUG >= 2 -#undef NEIGH_PRINTK2 -#define NEIGH_PRINTK2 NEIGH_PRINTK -#endif +#define neigh_dbg(level, fmt, ...)		\ +do {						\ +	if (level <= NEIGH_DEBUG)		\ +		pr_debug(fmt, ##__VA_ARGS__);	\ +} while (0)  #define PNEIGH_HASHMASK		0xF @@ -246,7 +238,7 @@ static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev)  					n->nud_state = NUD_NOARP;  				else  					n->nud_state = NUD_NONE; -				NEIGH_PRINTK2("neigh %p is stray.\n", n); +				neigh_dbg(2, "neigh %p is stray\n", n);  			}  			write_unlock(&n->lock);  			neigh_cleanup_and_release(n); @@ -542,7 +534,7 @@ struct neighbour *__neigh_create(struct neigh_table *tbl, const void *pkey,  						     lockdep_is_held(&tbl->lock)));  	rcu_assign_pointer(nht->hash_buckets[hash_val], n);  	write_unlock_bh(&tbl->lock); -	NEIGH_PRINTK2("neigh %p is created.\n", n); +	neigh_dbg(2, "neigh %p is created\n", n);  	rc = n;  out:  	return rc; @@ -725,7 +717,7 @@ void neigh_destroy(struct neighbour *neigh)  	dev_put(dev);  	neigh_parms_put(neigh->parms); -	NEIGH_PRINTK2("neigh %p is destroyed.\n", neigh); +	neigh_dbg(2, "neigh %p is destroyed\n", neigh);  	atomic_dec(&neigh->tbl->entries);  	kfree_rcu(neigh, rcu); @@ -739,7 +731,7 @@ EXPORT_SYMBOL(neigh_destroy);   */  static void neigh_suspect(struct neighbour *neigh)  { -	NEIGH_PRINTK2("neigh %p is suspected.\n", neigh); +	neigh_dbg(2, "neigh %p is suspected\n", neigh);  	neigh->output = neigh->ops->output;  } @@ -751,7 +743,7 @@ static void neigh_suspect(struct neighbour *neigh)   */  static void neigh_connect(struct neighbour *neigh)  { -	NEIGH_PRINTK2("neigh %p is connected.\n", neigh); +	neigh_dbg(2, "neigh %p is connected\n", neigh);  	neigh->output = neigh->ops->connected_output;  } @@ -852,7 +844,7 @@ static void neigh_invalidate(struct neighbour *neigh)  	struct sk_buff *skb;  	NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed); -	NEIGH_PRINTK2("neigh %p is failed.\n", neigh); +	neigh_dbg(2, "neigh %p is failed\n", neigh);  	neigh->updated = jiffies;  	/* It is very thin place. report_unreachable is very complicated @@ -904,17 +896,17 @@ static void neigh_timer_handler(unsigned long arg)  	if (state & NUD_REACHABLE) {  		if (time_before_eq(now,  				   neigh->confirmed + neigh->parms->reachable_time)) { -			NEIGH_PRINTK2("neigh %p is still alive.\n", neigh); +			neigh_dbg(2, "neigh %p is still alive\n", neigh);  			next = neigh->confirmed + neigh->parms->reachable_time;  		} else if (time_before_eq(now,  					  neigh->used + neigh->parms->delay_probe_time)) { -			NEIGH_PRINTK2("neigh %p is delayed.\n", neigh); +			neigh_dbg(2, "neigh %p is delayed\n", neigh);  			neigh->nud_state = NUD_DELAY;  			neigh->updated = jiffies;  			neigh_suspect(neigh);  			next = now + neigh->parms->delay_probe_time;  		} else { -			NEIGH_PRINTK2("neigh %p is suspected.\n", neigh); +			neigh_dbg(2, "neigh %p is suspected\n", neigh);  			neigh->nud_state = NUD_STALE;  			neigh->updated = jiffies;  			neigh_suspect(neigh); @@ -923,14 +915,14 @@ static void neigh_timer_handler(unsigned long arg)  	} else if (state & NUD_DELAY) {  		if (time_before_eq(now,  				   neigh->confirmed + neigh->parms->delay_probe_time)) { -			NEIGH_PRINTK2("neigh %p is now reachable.\n", neigh); +			neigh_dbg(2, "neigh %p is now reachable\n", neigh);  			neigh->nud_state = NUD_REACHABLE;  			neigh->updated = jiffies;  			neigh_connect(neigh);  			notify = 1;  			next = neigh->confirmed + neigh->parms->reachable_time;  		} else { -			NEIGH_PRINTK2("neigh %p is probed.\n", neigh); +			neigh_dbg(2, "neigh %p is probed\n", neigh);  			neigh->nud_state = NUD_PROBE;  			neigh->updated = jiffies;  			atomic_set(&neigh->probes, 0); @@ -997,7 +989,7 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)  			return 1;  		}  	} else if (neigh->nud_state & NUD_STALE) { -		NEIGH_PRINTK2("neigh %p is delayed.\n", neigh); +		neigh_dbg(2, "neigh %p is delayed\n", neigh);  		neigh->nud_state = NUD_DELAY;  		neigh->updated = jiffies;  		neigh_add_timer(neigh, @@ -1320,8 +1312,7 @@ int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb)  out:  	return rc;  discard: -	NEIGH_PRINTK1("neigh_resolve_output: dst=%p neigh=%p\n", -		      dst, neigh); +	neigh_dbg(1, "%s: dst=%p neigh=%p\n", __func__, dst, neigh);  out_kfree_skb:  	rc = -EINVAL;  	kfree_skb(skb); @@ -1498,7 +1489,7 @@ void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms)  		}  	}  	write_unlock_bh(&tbl->lock); -	NEIGH_PRINTK1("neigh_parms_release: not found\n"); +	neigh_dbg(1, "%s: not found\n", __func__);  }  EXPORT_SYMBOL(neigh_parms_release); @@ -1613,7 +1604,7 @@ int neigh_table_clear(struct neigh_table *tbl)  }  EXPORT_SYMBOL(neigh_table_clear); -static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) +static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh)  {  	struct net *net = sock_net(skb->sk);  	struct ndmsg *ndm; @@ -1677,7 +1668,7 @@ out:  	return err;  } -static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) +static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh)  {  	struct net *net = sock_net(skb->sk);  	struct ndmsg *ndm; @@ -1955,7 +1946,7 @@ static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = {  	[NDTPA_LOCKTIME]		= { .type = NLA_U64 },  }; -static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) +static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh)  {  	struct net *net = sock_net(skb->sk);  	struct neigh_table *tbl; @@ -2714,7 +2705,7 @@ static int neigh_stat_seq_open(struct inode *inode, struct file *file)  	if (!ret) {  		struct seq_file *sf = file->private_data; -		sf->private = PDE(inode)->data; +		sf->private = PDE_DATA(inode);  	}  	return ret;  }; diff --git a/net/core/net-procfs.c b/net/core/net-procfs.c index 3174f1998ee6..569d355fec3e 100644 --- a/net/core/net-procfs.c +++ b/net/core/net-procfs.c @@ -271,7 +271,7 @@ static int ptype_seq_show(struct seq_file *seq, void *v)  		else  			seq_printf(seq, "%04x", ntohs(pt->type)); -		seq_printf(seq, " %-8s %pF\n", +		seq_printf(seq, " %-8s %pf\n",  			   pt->dev ? pt->dev->name : "", pt->func);  	} diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 80e271d9e64b..f97652036754 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -10,7 +10,8 @@  #include <linux/idr.h>  #include <linux/rculist.h>  #include <linux/nsproxy.h> -#include <linux/proc_fs.h> +#include <linux/fs.h> +#include <linux/proc_ns.h>  #include <linux/file.h>  #include <linux/export.h>  #include <linux/user_namespace.h> @@ -336,7 +337,7 @@ EXPORT_SYMBOL_GPL(__put_net);  struct net *get_net_ns_by_fd(int fd)  { -	struct proc_inode *ei; +	struct proc_ns *ei;  	struct file *file;  	struct net *net; @@ -344,7 +345,7 @@ struct net *get_net_ns_by_fd(int fd)  	if (IS_ERR(file))  		return ERR_CAST(file); -	ei = PROC_I(file_inode(file)); +	ei = get_proc_ns(file_inode(file));  	if (ei->ns_ops == &netns_operations)  		net = get_net(ei->ns);  	else diff --git a/net/core/netpoll.c b/net/core/netpoll.c index fa32899006a2..a5802a8b652f 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -47,7 +47,7 @@ static struct sk_buff_head skb_pool;  static atomic_t trapped; -static struct srcu_struct netpoll_srcu; +DEFINE_STATIC_SRCU(netpoll_srcu);  #define USEC_PER_POLL	50  #define NETPOLL_RX_ENABLED  1 @@ -206,17 +206,17 @@ static void netpoll_poll_dev(struct net_device *dev)  	 * the dev_open/close paths use this to block netpoll activity  	 * while changing device state  	 */ -	if (!mutex_trylock(&ni->dev_lock)) +	if (!down_trylock(&ni->dev_lock))  		return;  	if (!netif_running(dev)) { -		mutex_unlock(&ni->dev_lock); +		up(&ni->dev_lock);  		return;  	}  	ops = dev->netdev_ops;  	if (!ops->ndo_poll_controller) { -		mutex_unlock(&ni->dev_lock); +		up(&ni->dev_lock);  		return;  	} @@ -225,7 +225,7 @@ static void netpoll_poll_dev(struct net_device *dev)  	poll_napi(dev); -	mutex_unlock(&ni->dev_lock); +	up(&ni->dev_lock);  	if (dev->flags & IFF_SLAVE) {  		if (ni) { @@ -255,7 +255,7 @@ int netpoll_rx_disable(struct net_device *dev)  	idx = srcu_read_lock(&netpoll_srcu);  	ni = srcu_dereference(dev->npinfo, &netpoll_srcu);  	if (ni) -		mutex_lock(&ni->dev_lock); +		down(&ni->dev_lock);  	srcu_read_unlock(&netpoll_srcu, idx);  	return 0;  } @@ -267,7 +267,7 @@ void netpoll_rx_enable(struct net_device *dev)  	rcu_read_lock();  	ni = rcu_dereference(dev->npinfo);  	if (ni) -		mutex_unlock(&ni->dev_lock); +		up(&ni->dev_lock);  	rcu_read_unlock();  }  EXPORT_SYMBOL(netpoll_rx_enable); @@ -383,8 +383,9 @@ void netpoll_send_skb_on_dev(struct netpoll *np, struct sk_buff *skb,  			if (__netif_tx_trylock(txq)) {  				if (!netif_xmit_stopped(txq)) {  					if (vlan_tx_tag_present(skb) && -					    !(netif_skb_features(skb) & NETIF_F_HW_VLAN_TX)) { -						skb = __vlan_put_tag(skb, vlan_tx_tag_get(skb)); +					    !vlan_hw_offload_capable(netif_skb_features(skb), +								     skb->vlan_proto)) { +						skb = __vlan_put_tag(skb, skb->vlan_proto, vlan_tx_tag_get(skb));  						if (unlikely(!skb))  							break;  						skb->vlan_tci = 0; @@ -1046,7 +1047,7 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev, gfp_t gfp)  		INIT_LIST_HEAD(&npinfo->rx_np);  		spin_lock_init(&npinfo->rx_lock); -		mutex_init(&npinfo->dev_lock); +		sema_init(&npinfo->dev_lock, 1);  		skb_queue_head_init(&npinfo->neigh_tx);  		skb_queue_head_init(&npinfo->txq);  		INIT_DELAYED_WORK(&npinfo->tx_work, queue_process); @@ -1212,7 +1213,6 @@ EXPORT_SYMBOL(netpoll_setup);  static int __init netpoll_init(void)  {  	skb_queue_head_init(&skb_pool); -	init_srcu_struct(&netpoll_srcu);  	return 0;  }  core_initcall(netpoll_init); diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 6048fc1da1c2..11f2704c3810 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -508,7 +508,7 @@ out:  static int pgctrl_open(struct inode *inode, struct file *file)  { -	return single_open(file, pgctrl_show, PDE(inode)->data); +	return single_open(file, pgctrl_show, PDE_DATA(inode));  }  static const struct file_operations pktgen_fops = { @@ -1685,7 +1685,7 @@ static ssize_t pktgen_if_write(struct file *file,  static int pktgen_if_open(struct inode *inode, struct file *file)  { -	return single_open(file, pktgen_if_show, PDE(inode)->data); +	return single_open(file, pktgen_if_show, PDE_DATA(inode));  }  static const struct file_operations pktgen_if_fops = { @@ -1823,7 +1823,7 @@ out:  static int pktgen_thread_open(struct inode *inode, struct file *file)  { -	return single_open(file, pktgen_thread_show, PDE(inode)->data); +	return single_open(file, pktgen_thread_show, PDE_DATA(inode));  }  static const struct file_operations pktgen_thread_fops = { @@ -1904,7 +1904,7 @@ static void pktgen_change_name(const struct pktgen_net *pn, struct net_device *d  			if (pkt_dev->odev != dev)  				continue; -			remove_proc_entry(pkt_dev->entry->name, pn->proc_dir); +			proc_remove(pkt_dev->entry);  			pkt_dev->entry = proc_create_data(dev->name, 0600,  							  pn->proc_dir, @@ -2198,7 +2198,7 @@ static inline int f_pick(struct pktgen_dev *pkt_dev)  				pkt_dev->curfl = 0; /*reset */  		}  	} else { -		flow = random32() % pkt_dev->cflows; +		flow = prandom_u32() % pkt_dev->cflows;  		pkt_dev->curfl = flow;  		if (pkt_dev->flows[flow].count > pkt_dev->lflow) { @@ -2246,7 +2246,7 @@ static void set_cur_queue_map(struct pktgen_dev *pkt_dev)  	else if (pkt_dev->queue_map_min <= pkt_dev->queue_map_max) {  		__u16 t;  		if (pkt_dev->flags & F_QUEUE_MAP_RND) { -			t = random32() % +			t = prandom_u32() %  				(pkt_dev->queue_map_max -  				 pkt_dev->queue_map_min + 1)  				+ pkt_dev->queue_map_min; @@ -2278,7 +2278,7 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)  		__u32 tmp;  		if (pkt_dev->flags & F_MACSRC_RND) -			mc = random32() % pkt_dev->src_mac_count; +			mc = prandom_u32() % pkt_dev->src_mac_count;  		else {  			mc = pkt_dev->cur_src_mac_offset++;  			if (pkt_dev->cur_src_mac_offset >= @@ -2304,7 +2304,7 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)  		__u32 tmp;  		if (pkt_dev->flags & F_MACDST_RND) -			mc = random32() % pkt_dev->dst_mac_count; +			mc = prandom_u32() % pkt_dev->dst_mac_count;  		else {  			mc = pkt_dev->cur_dst_mac_offset++; @@ -2331,21 +2331,21 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)  		for (i = 0; i < pkt_dev->nr_labels; i++)  			if (pkt_dev->labels[i] & MPLS_STACK_BOTTOM)  				pkt_dev->labels[i] = MPLS_STACK_BOTTOM | -					     ((__force __be32)random32() & +					     ((__force __be32)prandom_u32() &  						      htonl(0x000fffff));  	}  	if ((pkt_dev->flags & F_VID_RND) && (pkt_dev->vlan_id != 0xffff)) { -		pkt_dev->vlan_id = random32() & (4096-1); +		pkt_dev->vlan_id = prandom_u32() & (4096 - 1);  	}  	if ((pkt_dev->flags & F_SVID_RND) && (pkt_dev->svlan_id != 0xffff)) { -		pkt_dev->svlan_id = random32() & (4096 - 1); +		pkt_dev->svlan_id = prandom_u32() & (4096 - 1);  	}  	if (pkt_dev->udp_src_min < pkt_dev->udp_src_max) {  		if (pkt_dev->flags & F_UDPSRC_RND) -			pkt_dev->cur_udp_src = random32() % +			pkt_dev->cur_udp_src = prandom_u32() %  				(pkt_dev->udp_src_max - pkt_dev->udp_src_min)  				+ pkt_dev->udp_src_min; @@ -2358,7 +2358,7 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)  	if (pkt_dev->udp_dst_min < pkt_dev->udp_dst_max) {  		if (pkt_dev->flags & F_UDPDST_RND) { -			pkt_dev->cur_udp_dst = random32() % +			pkt_dev->cur_udp_dst = prandom_u32() %  				(pkt_dev->udp_dst_max - pkt_dev->udp_dst_min)  				+ pkt_dev->udp_dst_min;  		} else { @@ -2375,7 +2375,7 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)  		if (imn < imx) {  			__u32 t;  			if (pkt_dev->flags & F_IPSRC_RND) -				t = random32() % (imx - imn) + imn; +				t = prandom_u32() % (imx - imn) + imn;  			else {  				t = ntohl(pkt_dev->cur_saddr);  				t++; @@ -2396,17 +2396,15 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)  				__be32 s;  				if (pkt_dev->flags & F_IPDST_RND) { -					t = random32() % (imx - imn) + imn; -					s = htonl(t); - -					while (ipv4_is_loopback(s) || -					       ipv4_is_multicast(s) || -					       ipv4_is_lbcast(s) || -					       ipv4_is_zeronet(s) || -					       ipv4_is_local_multicast(s)) { -						t = random32() % (imx - imn) + imn; +					do { +						t = prandom_u32() % +							(imx - imn) + imn;  						s = htonl(t); -					} +					} while (ipv4_is_loopback(s) || +						ipv4_is_multicast(s) || +						ipv4_is_lbcast(s) || +						ipv4_is_zeronet(s) || +						ipv4_is_local_multicast(s));  					pkt_dev->cur_daddr = s;  				} else {  					t = ntohl(pkt_dev->cur_daddr); @@ -2437,7 +2435,7 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)  			for (i = 0; i < 4; i++) {  				pkt_dev->cur_in6_daddr.s6_addr32[i] = -				    (((__force __be32)random32() | +				    (((__force __be32)prandom_u32() |  				      pkt_dev->min_in6_daddr.s6_addr32[i]) &  				     pkt_dev->max_in6_daddr.s6_addr32[i]);  			} @@ -2447,7 +2445,7 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)  	if (pkt_dev->min_pkt_size < pkt_dev->max_pkt_size) {  		__u32 t;  		if (pkt_dev->flags & F_TXSIZE_RND) { -			t = random32() % +			t = prandom_u32() %  				(pkt_dev->max_pkt_size - pkt_dev->min_pkt_size)  				+ pkt_dev->min_pkt_size;  		} else { @@ -3576,8 +3574,6 @@ static void _rem_dev_from_if_list(struct pktgen_thread *t,  static int pktgen_remove_device(struct pktgen_thread *t,  				struct pktgen_dev *pkt_dev)  { -	struct pktgen_net *pn = t->net; -  	pr_debug("remove_device pkt_dev=%p\n", pkt_dev);  	if (pkt_dev->running) { @@ -3597,7 +3593,7 @@ static int pktgen_remove_device(struct pktgen_thread *t,  	_rem_dev_from_if_list(t, pkt_dev);  	if (pkt_dev->entry) -		remove_proc_entry(pkt_dev->entry->name, pn->proc_dir); +		proc_remove(pkt_dev->entry);  #ifdef CONFIG_XFRM  	free_SAs(pkt_dev); diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index b376410ff259..a08bd2b7fe3f 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -496,8 +496,10 @@ static int rtnl_link_fill(struct sk_buff *skb, const struct net_device *dev)  	}  	if (ops->fill_info) {  		data = nla_nest_start(skb, IFLA_INFO_DATA); -		if (data == NULL) +		if (data == NULL) { +			err = -EMSGSIZE;  			goto err_cancel_link; +		}  		err = ops->fill_info(skb, dev);  		if (err < 0)  			goto err_cancel_data; @@ -515,32 +517,6 @@ out:  	return err;  } -static const int rtm_min[RTM_NR_FAMILIES] = -{ -	[RTM_FAM(RTM_NEWLINK)]      = NLMSG_LENGTH(sizeof(struct ifinfomsg)), -	[RTM_FAM(RTM_NEWADDR)]      = NLMSG_LENGTH(sizeof(struct ifaddrmsg)), -	[RTM_FAM(RTM_NEWROUTE)]     = NLMSG_LENGTH(sizeof(struct rtmsg)), -	[RTM_FAM(RTM_NEWRULE)]      = NLMSG_LENGTH(sizeof(struct fib_rule_hdr)), -	[RTM_FAM(RTM_NEWQDISC)]     = NLMSG_LENGTH(sizeof(struct tcmsg)), -	[RTM_FAM(RTM_NEWTCLASS)]    = NLMSG_LENGTH(sizeof(struct tcmsg)), -	[RTM_FAM(RTM_NEWTFILTER)]   = NLMSG_LENGTH(sizeof(struct tcmsg)), -	[RTM_FAM(RTM_NEWACTION)]    = NLMSG_LENGTH(sizeof(struct tcamsg)), -	[RTM_FAM(RTM_GETMULTICAST)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)), -	[RTM_FAM(RTM_GETANYCAST)]   = NLMSG_LENGTH(sizeof(struct rtgenmsg)), -}; - -static const int rta_max[RTM_NR_FAMILIES] = -{ -	[RTM_FAM(RTM_NEWLINK)]      = IFLA_MAX, -	[RTM_FAM(RTM_NEWADDR)]      = IFA_MAX, -	[RTM_FAM(RTM_NEWROUTE)]     = RTA_MAX, -	[RTM_FAM(RTM_NEWRULE)]      = FRA_MAX, -	[RTM_FAM(RTM_NEWQDISC)]     = TCA_MAX, -	[RTM_FAM(RTM_NEWTCLASS)]    = TCA_MAX, -	[RTM_FAM(RTM_NEWTFILTER)]   = TCA_MAX, -	[RTM_FAM(RTM_NEWACTION)]    = TCAA_MAX, -}; -  int rtnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, unsigned int group, int echo)  {  	struct sock *rtnl = net->rtnl; @@ -979,6 +955,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,  			 * report anything.  			 */  			ivi.spoofchk = -1; +			memset(ivi.mac, 0, sizeof(ivi.mac));  			if (dev->netdev_ops->ndo_get_vf_config(dev, i, &ivi))  				break;  			vf_mac.vf = @@ -1069,7 +1046,7 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)  	rcu_read_lock();  	cb->seq = net->dev_base_seq; -	if (nlmsg_parse(cb->nlh, sizeof(struct rtgenmsg), tb, IFLA_MAX, +	if (nlmsg_parse(cb->nlh, sizeof(struct ifinfomsg), tb, IFLA_MAX,  			ifla_policy) >= 0) {  		if (tb[IFLA_EXT_MASK]) @@ -1536,7 +1513,7 @@ errout:  	return err;  } -static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) +static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh)  {  	struct net *net = sock_net(skb->sk);  	struct ifinfomsg *ifm; @@ -1577,7 +1554,7 @@ errout:  	return err;  } -static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) +static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh)  {  	struct net *net = sock_net(skb->sk);  	const struct rtnl_link_ops *ops; @@ -1708,7 +1685,7 @@ static int rtnl_group_changelink(struct net *net, int group,  	return 0;  } -static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) +static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh)  {  	struct net *net = sock_net(skb->sk);  	const struct rtnl_link_ops *ops; @@ -1863,7 +1840,7 @@ out:  	}  } -static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) +static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh)  {  	struct net *net = sock_net(skb->sk);  	struct ifinfomsg *ifm; @@ -1919,7 +1896,7 @@ static u16 rtnl_calcit(struct sk_buff *skb, struct nlmsghdr *nlh)  	u32 ext_filter_mask = 0;  	u16 min_ifinfo_dump_size = 0; -	if (nlmsg_parse(nlh, sizeof(struct rtgenmsg), tb, IFLA_MAX, +	if (nlmsg_parse(nlh, sizeof(struct ifinfomsg), tb, IFLA_MAX,  			ifla_policy) >= 0) {  		if (tb[IFLA_EXT_MASK])  			ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]); @@ -1954,8 +1931,11 @@ static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb)  		if (rtnl_msg_handlers[idx] == NULL ||  		    rtnl_msg_handlers[idx][type].dumpit == NULL)  			continue; -		if (idx > s_idx) +		if (idx > s_idx) {  			memset(&cb->args[0], 0, sizeof(cb->args)); +			cb->prev_seq = 0; +			cb->seq = 0; +		}  		if (rtnl_msg_handlers[idx][type].dumpit(skb, cb))  			break;  	} @@ -2048,7 +2028,39 @@ errout:  	rtnl_set_sk_err(net, RTNLGRP_NEIGH, err);  } -static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) +/** + * ndo_dflt_fdb_add - default netdevice operation to add an FDB entry + */ +int ndo_dflt_fdb_add(struct ndmsg *ndm, +		     struct nlattr *tb[], +		     struct net_device *dev, +		     const unsigned char *addr, +		     u16 flags) +{ +	int err = -EINVAL; + +	/* If aging addresses are supported device will need to +	 * implement its own handler for this. +	 */ +	if (ndm->ndm_state && !(ndm->ndm_state & NUD_PERMANENT)) { +		pr_info("%s: FDB only supports static addresses\n", dev->name); +		return err; +	} + +	if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr)) +		err = dev_uc_add_excl(dev, addr); +	else if (is_multicast_ether_addr(addr)) +		err = dev_mc_add_excl(dev, addr); + +	/* Only return duplicate errors if NLM_F_EXCL is set */ +	if (err == -EEXIST && !(flags & NLM_F_EXCL)) +		err = 0; + +	return err; +} +EXPORT_SYMBOL(ndo_dflt_fdb_add); + +static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh)  {  	struct net *net = sock_net(skb->sk);  	struct ndmsg *ndm; @@ -2079,7 +2091,7 @@ static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)  	}  	addr = nla_data(tb[NDA_LLADDR]); -	if (!is_valid_ether_addr(addr)) { +	if (is_zero_ether_addr(addr)) {  		pr_info("PF_BRIDGE: RTM_NEWNEIGH with invalid ether address\n");  		return -EINVAL;  	} @@ -2100,10 +2112,13 @@ static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)  	}  	/* Embedded bridge, macvlan, and any other device support */ -	if ((ndm->ndm_flags & NTF_SELF) && dev->netdev_ops->ndo_fdb_add) { -		err = dev->netdev_ops->ndo_fdb_add(ndm, tb, -						   dev, addr, -						   nlh->nlmsg_flags); +	if ((ndm->ndm_flags & NTF_SELF)) { +		if (dev->netdev_ops->ndo_fdb_add) +			err = dev->netdev_ops->ndo_fdb_add(ndm, tb, dev, addr, +							   nlh->nlmsg_flags); +		else +			err = ndo_dflt_fdb_add(ndm, tb, dev, addr, +					       nlh->nlmsg_flags);  		if (!err) {  			rtnl_fdb_notify(dev, addr, RTM_NEWNEIGH); @@ -2114,7 +2129,36 @@ out:  	return err;  } -static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) +/** + * ndo_dflt_fdb_del - default netdevice operation to delete an FDB entry + */ +int ndo_dflt_fdb_del(struct ndmsg *ndm, +		     struct nlattr *tb[], +		     struct net_device *dev, +		     const unsigned char *addr) +{ +	int err = -EOPNOTSUPP; + +	/* If aging addresses are supported device will need to +	 * implement its own handler for this. +	 */ +	if (ndm->ndm_state & NUD_PERMANENT) { +		pr_info("%s: FDB only supports static addresses\n", dev->name); +		return -EINVAL; +	} + +	if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr)) +		err = dev_uc_del(dev, addr); +	else if (is_multicast_ether_addr(addr)) +		err = dev_mc_del(dev, addr); +	else +		err = -EINVAL; + +	return err; +} +EXPORT_SYMBOL(ndo_dflt_fdb_del); + +static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh)  {  	struct net *net = sock_net(skb->sk);  	struct ndmsg *ndm; @@ -2148,7 +2192,7 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)  	}  	addr = nla_data(tb[NDA_LLADDR]); -	if (!is_valid_ether_addr(addr)) { +	if (is_zero_ether_addr(addr)) {  		pr_info("PF_BRIDGE: RTM_DELNEIGH with invalid ether address\n");  		return -EINVAL;  	} @@ -2171,8 +2215,11 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)  	}  	/* Embedded bridge, macvlan, and any other device support */ -	if ((ndm->ndm_flags & NTF_SELF) && dev->netdev_ops->ndo_fdb_del) { -		err = dev->netdev_ops->ndo_fdb_del(ndm, tb, dev, addr); +	if (ndm->ndm_flags & NTF_SELF) { +		if (dev->netdev_ops->ndo_fdb_del) +			err = dev->netdev_ops->ndo_fdb_del(ndm, tb, dev, addr); +		else +			err = ndo_dflt_fdb_del(ndm, tb, dev, addr);  		if (!err) {  			rtnl_fdb_notify(dev, addr, RTM_DELNEIGH); @@ -2217,7 +2264,7 @@ skip:   * @dev: netdevice   *   * Default netdevice operation to dump the existing unicast address list. - * Returns zero on success. + * Returns number of addresses from list put in skb.   */  int ndo_dflt_fdb_dump(struct sk_buff *skb,  		      struct netlink_callback *cb, @@ -2257,6 +2304,8 @@ static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb)  		if (dev->netdev_ops->ndo_fdb_dump)  			idx = dev->netdev_ops->ndo_fdb_dump(skb, cb, dev, idx); +		else +			idx = ndo_dflt_fdb_dump(skb, cb, dev, idx);  	}  	rcu_read_unlock(); @@ -2408,8 +2457,7 @@ errout:  	return err;  } -static int rtnl_bridge_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, -			       void *arg) +static int rtnl_bridge_setlink(struct sk_buff *skb, struct nlmsghdr *nlh)  {  	struct net *net = sock_net(skb->sk);  	struct ifinfomsg *ifm; @@ -2479,8 +2527,7 @@ out:  	return err;  } -static int rtnl_bridge_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, -			       void *arg) +static int rtnl_bridge_dellink(struct sk_buff *skb, struct nlmsghdr *nlh)  {  	struct net *net = sock_net(skb->sk);  	struct ifinfomsg *ifm; @@ -2550,10 +2597,6 @@ out:  	return err;  } -/* Protected by RTNL sempahore.  */ -static struct rtattr **rta_buf; -static int rtattr_max; -  /* Process one rtnetlink message. */  static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) @@ -2561,7 +2604,6 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)  	struct net *net = sock_net(skb->sk);  	rtnl_doit_func doit;  	int sz_idx, kind; -	int min_len;  	int family;  	int type;  	int err; @@ -2573,10 +2615,10 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)  	type -= RTM_BASE;  	/* All the messages must have at least 1 byte length */ -	if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtgenmsg))) +	if (nlmsg_len(nlh) < sizeof(struct rtgenmsg))  		return 0; -	family = ((struct rtgenmsg *)NLMSG_DATA(nlh))->rtgen_family; +	family = ((struct rtgenmsg *)nlmsg_data(nlh))->rtgen_family;  	sz_idx = type>>2;  	kind = type&3; @@ -2609,32 +2651,11 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)  		return err;  	} -	memset(rta_buf, 0, (rtattr_max * sizeof(struct rtattr *))); - -	min_len = rtm_min[sz_idx]; -	if (nlh->nlmsg_len < min_len) -		return -EINVAL; - -	if (nlh->nlmsg_len > min_len) { -		int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); -		struct rtattr *attr = (void *)nlh + NLMSG_ALIGN(min_len); - -		while (RTA_OK(attr, attrlen)) { -			unsigned int flavor = attr->rta_type; -			if (flavor) { -				if (flavor > rta_max[sz_idx]) -					return -EINVAL; -				rta_buf[flavor-1] = attr; -			} -			attr = RTA_NEXT(attr, attrlen); -		} -	} -  	doit = rtnl_get_doit(family, type);  	if (doit == NULL)  		return -EOPNOTSUPP; -	return doit(skb, nlh, (void *)&rta_buf[0]); +	return doit(skb, nlh);  }  static void rtnetlink_rcv(struct sk_buff *skb) @@ -2704,16 +2725,6 @@ static struct pernet_operations rtnetlink_net_ops = {  void __init rtnetlink_init(void)  { -	int i; - -	rtattr_max = 0; -	for (i = 0; i < ARRAY_SIZE(rta_max); i++) -		if (rta_max[i] > rtattr_max) -			rtattr_max = rta_max[i]; -	rta_buf = kmalloc(rtattr_max * sizeof(struct rtattr *), GFP_KERNEL); -	if (!rta_buf) -		panic("rtnetlink_init: cannot allocate rta_buf\n"); -  	if (register_pernet_subsys(&rtnetlink_net_ops))  		panic("rtnetlink_init: cannot initialize rtnetlink\n"); diff --git a/net/core/scm.c b/net/core/scm.c index 905dcc6ad1e3..03795d0147f2 100644 --- a/net/core/scm.c +++ b/net/core/scm.c @@ -24,6 +24,7 @@  #include <linux/interrupt.h>  #include <linux/netdevice.h>  #include <linux/security.h> +#include <linux/pid_namespace.h>  #include <linux/pid.h>  #include <linux/nsproxy.h>  #include <linux/slab.h> @@ -52,7 +53,8 @@ static __inline__ int scm_check_creds(struct ucred *creds)  	if (!uid_valid(uid) || !gid_valid(gid))  		return -EINVAL; -	if ((creds->pid == task_tgid_vnr(current) || nsown_capable(CAP_SYS_ADMIN)) && +	if ((creds->pid == task_tgid_vnr(current) || +	     ns_capable(current->nsproxy->pid_ns->user_ns, CAP_SYS_ADMIN)) &&  	    ((uid_eq(uid, cred->uid)   || uid_eq(uid, cred->euid) ||  	      uid_eq(uid, cred->suid)) || nsown_capable(CAP_SETUID)) &&  	    ((gid_eq(gid, cred->gid)   || gid_eq(gid, cred->egid) || @@ -185,22 +187,6 @@ int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p)  			p->creds.uid = uid;  			p->creds.gid = gid; - -			if (!p->cred || -			    !uid_eq(p->cred->euid, uid) || -			    !gid_eq(p->cred->egid, gid)) { -				struct cred *cred; -				err = -ENOMEM; -				cred = prepare_creds(); -				if (!cred) -					goto error; - -				cred->uid = cred->euid = uid; -				cred->gid = cred->egid = gid; -				if (p->cred) -					put_cred(p->cred); -				p->cred = cred; -			}  			break;  		}  		default: @@ -304,8 +290,8 @@ void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm)  		/* Bump the usage count and install the file. */  		sock = sock_from_file(fp[i], &err);  		if (sock) { -			sock_update_netprioidx(sock->sk, current); -			sock_update_classid(sock->sk, current); +			sock_update_netprioidx(sock->sk); +			sock_update_classid(sock->sk);  		}  		fd_install(new_fd, get_file(fp[i]));  	} diff --git a/net/core/secure_seq.c b/net/core/secure_seq.c index e61a8bb7fce7..6a2f13cee86a 100644 --- a/net/core/secure_seq.c +++ b/net/core/secure_seq.c @@ -12,12 +12,10 @@  static u32 net_secret[MD5_MESSAGE_BYTES / 4] ____cacheline_aligned; -static int __init net_secret_init(void) +void net_secret_init(void)  {  	get_random_bytes(net_secret, sizeof(net_secret)); -	return 0;  } -late_initcall(net_secret_init);  #ifdef CONFIG_INET  static u32 seq_scale(u32 seq) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 33245ef54c3b..af9185d0be6a 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -179,6 +179,33 @@ out:   *   */ +struct sk_buff *__alloc_skb_head(gfp_t gfp_mask, int node) +{ +	struct sk_buff *skb; + +	/* Get the HEAD */ +	skb = kmem_cache_alloc_node(skbuff_head_cache, +				    gfp_mask & ~__GFP_DMA, node); +	if (!skb) +		goto out; + +	/* +	 * Only clear those fields we need to clear, not those that we will +	 * actually initialise below. Hence, don't put any more fields after +	 * the tail pointer in struct sk_buff! +	 */ +	memset(skb, 0, offsetof(struct sk_buff, tail)); +	skb->data = NULL; +	skb->truesize = sizeof(struct sk_buff); +	atomic_set(&skb->users, 1); + +#ifdef NET_SKBUFF_DATA_USES_OFFSET +	skb->mac_header = ~0U; +#endif +out: +	return skb; +} +  /**   *	__alloc_skb	-	allocate a network buffer   *	@size: size to allocate @@ -584,7 +611,8 @@ static void skb_release_head_state(struct sk_buff *skb)  static void skb_release_all(struct sk_buff *skb)  {  	skb_release_head_state(skb); -	skb_release_data(skb); +	if (likely(skb->data)) +		skb_release_data(skb);  }  /** @@ -673,6 +701,7 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)  	new->mac_header		= old->mac_header;  	new->inner_transport_header = old->inner_transport_header;  	new->inner_network_header = old->inner_network_header; +	new->inner_mac_header = old->inner_mac_header;  	skb_dst_copy(new, old);  	new->rxhash		= old->rxhash;  	new->ooo_okay		= old->ooo_okay; @@ -706,6 +735,7 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)  	new->tc_verd		= old->tc_verd;  #endif  #endif +	new->vlan_proto		= old->vlan_proto;  	new->vlan_tci		= old->vlan_tci;  	skb_copy_secmark(new, old); @@ -867,6 +897,18 @@ struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask)  }  EXPORT_SYMBOL(skb_clone); +static void skb_headers_offset_update(struct sk_buff *skb, int off) +{ +	/* {transport,network,mac}_header and tail are relative to skb->head */ +	skb->transport_header += off; +	skb->network_header   += off; +	if (skb_mac_header_was_set(skb)) +		skb->mac_header += off; +	skb->inner_transport_header += off; +	skb->inner_network_header += off; +	skb->inner_mac_header += off; +} +  static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)  {  #ifndef NET_SKBUFF_DATA_USES_OFFSET @@ -879,13 +921,7 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)  	__copy_skb_header(new, old);  #ifndef NET_SKBUFF_DATA_USES_OFFSET -	/* {transport,network,mac}_header are relative to skb->head */ -	new->transport_header += offset; -	new->network_header   += offset; -	if (skb_mac_header_was_set(new)) -		new->mac_header	      += offset; -	new->inner_transport_header += offset; -	new->inner_network_header   += offset; +	skb_headers_offset_update(new, offset);  #endif  	skb_shinfo(new)->gso_size = skb_shinfo(old)->gso_size;  	skb_shinfo(new)->gso_segs = skb_shinfo(old)->gso_segs; @@ -1077,14 +1113,8 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,  #else  	skb->end      = skb->head + size;  #endif -	/* {transport,network,mac}_header and tail are relative to skb->head */  	skb->tail	      += off; -	skb->transport_header += off; -	skb->network_header   += off; -	if (skb_mac_header_was_set(skb)) -		skb->mac_header += off; -	skb->inner_transport_header += off; -	skb->inner_network_header += off; +	skb_headers_offset_update(skb, off);  	/* Only adjust this if it actually is csum_start rather than csum */  	if (skb->ip_summed == CHECKSUM_PARTIAL)  		skb->csum_start += nhead; @@ -1180,12 +1210,7 @@ struct sk_buff *skb_copy_expand(const struct sk_buff *skb,  	if (n->ip_summed == CHECKSUM_PARTIAL)  		n->csum_start += off;  #ifdef NET_SKBUFF_DATA_USES_OFFSET -	n->transport_header += off; -	n->network_header   += off; -	if (skb_mac_header_was_set(skb)) -		n->mac_header += off; -	n->inner_transport_header += off; -	n->inner_network_header	   += off; +	skb_headers_offset_update(n, off);  #endif  	return n; @@ -2741,12 +2766,19 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)  	unsigned int tnl_hlen = skb_tnl_header_len(skb);  	unsigned int headroom;  	unsigned int len; +	__be16 proto; +	bool csum;  	int sg = !!(features & NETIF_F_SG);  	int nfrags = skb_shinfo(skb)->nr_frags;  	int err = -ENOMEM;  	int i = 0;  	int pos; +	proto = skb_network_protocol(skb); +	if (unlikely(!proto)) +		return ERR_PTR(-EINVAL); + +	csum = !!can_checksum_protocol(features, proto);  	__skb_push(skb, doffset);  	headroom = skb_headroom(skb);  	pos = skb_headlen(skb); @@ -2884,6 +2916,12 @@ skip_fraglist:  		nskb->data_len = len - hsize;  		nskb->len += nskb->data_len;  		nskb->truesize += nskb->data_len; + +		if (!csum) { +			nskb->csum = skb_checksum(nskb, doffset, +						  nskb->len - doffset, 0); +			nskb->ip_summed = CHECKSUM_NONE; +		}  	} while ((offset += len) < skb->len);  	return segs; @@ -3289,12 +3327,8 @@ void skb_tstamp_tx(struct sk_buff *orig_skb,  	if (!sk)  		return; -	skb = skb_clone(orig_skb, GFP_ATOMIC); -	if (!skb) -		return; -  	if (hwtstamps) { -		*skb_hwtstamps(skb) = +		*skb_hwtstamps(orig_skb) =  			*hwtstamps;  	} else {  		/* @@ -3302,9 +3336,13 @@ void skb_tstamp_tx(struct sk_buff *orig_skb,  		 * so keep the shared tx_flags and only  		 * store software time stamp  		 */ -		skb->tstamp = ktime_get_real(); +		orig_skb->tstamp = ktime_get_real();  	} +	skb = skb_clone(orig_skb, GFP_ATOMIC); +	if (!skb) +		return; +  	serr = SKB_EXT_ERR(skb);  	memset(serr, 0, sizeof(*serr));  	serr->ee.ee_errno = ENOMSG; @@ -3361,6 +3399,7 @@ bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off)  	skb->ip_summed = CHECKSUM_PARTIAL;  	skb->csum_start = skb_headroom(skb) + start;  	skb->csum_offset = off; +	skb_set_transport_header(skb, start);  	return true;  }  EXPORT_SYMBOL_GPL(skb_partial_csum_set); diff --git a/net/core/sock.c b/net/core/sock.c index b261a7977746..d4f4cea726e7 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -907,6 +907,10 @@ set_rcvbuf:  		sock_valbool_flag(sk, SOCK_NOFCS, valbool);  		break; +	case SO_SELECT_ERR_QUEUE: +		sock_valbool_flag(sk, SOCK_SELECT_ERR_QUEUE, valbool); +		break; +  	default:  		ret = -ENOPROTOOPT;  		break; @@ -1160,6 +1164,10 @@ int sock_getsockopt(struct socket *sock, int level, int optname,  		v.val = sock_flag(sk, SOCK_FILTER_LOCKED);  		break; +	case SO_SELECT_ERR_QUEUE: +		v.val = sock_flag(sk, SOCK_SELECT_ERR_QUEUE); +		break; +  	default:  		return -ENOPROTOOPT;  	} @@ -1298,13 +1306,12 @@ static void sk_prot_free(struct proto *prot, struct sock *sk)  	module_put(owner);  } -#ifdef CONFIG_CGROUPS  #if IS_ENABLED(CONFIG_NET_CLS_CGROUP) -void sock_update_classid(struct sock *sk, struct task_struct *task) +void sock_update_classid(struct sock *sk)  {  	u32 classid; -	classid = task_cls_classid(task); +	classid = task_cls_classid(current);  	if (classid != sk->sk_classid)  		sk->sk_classid = classid;  } @@ -1312,16 +1319,15 @@ EXPORT_SYMBOL(sock_update_classid);  #endif  #if IS_ENABLED(CONFIG_NETPRIO_CGROUP) -void sock_update_netprioidx(struct sock *sk, struct task_struct *task) +void sock_update_netprioidx(struct sock *sk)  {  	if (in_interrupt())  		return; -	sk->sk_cgrp_prioidx = task_netprioidx(task); +	sk->sk_cgrp_prioidx = task_netprioidx(current);  }  EXPORT_SYMBOL_GPL(sock_update_netprioidx);  #endif -#endif  /**   *	sk_alloc - All socket objects are allocated here @@ -1347,8 +1353,8 @@ struct sock *sk_alloc(struct net *net, int family, gfp_t priority,  		sock_net_set(sk, get_net(net));  		atomic_set(&sk->sk_wmem_alloc, 1); -		sock_update_classid(sk, current); -		sock_update_netprioidx(sk, current); +		sock_update_classid(sk); +		sock_update_netprioidx(sk);  	}  	return sk; diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c index a29e90cf36b7..d5bef0b0f639 100644 --- a/net/core/sock_diag.c +++ b/net/core/sock_diag.c @@ -49,6 +49,39 @@ int sock_diag_put_meminfo(struct sock *sk, struct sk_buff *skb, int attrtype)  }  EXPORT_SYMBOL_GPL(sock_diag_put_meminfo); +int sock_diag_put_filterinfo(struct user_namespace *user_ns, struct sock *sk, +			     struct sk_buff *skb, int attrtype) +{ +	struct nlattr *attr; +	struct sk_filter *filter; +	unsigned int len; +	int err = 0; + +	if (!ns_capable(user_ns, CAP_NET_ADMIN)) { +		nla_reserve(skb, attrtype, 0); +		return 0; +	} + +	rcu_read_lock(); + +	filter = rcu_dereference(sk->sk_filter); +	len = filter ? filter->len * sizeof(struct sock_filter) : 0; + +	attr = nla_reserve(skb, attrtype, len); +	if (attr == NULL) { +		err = -EMSGSIZE; +		goto out; +	} + +	if (filter) +		memcpy(nla_data(attr), filter->insns, len); + +out: +	rcu_read_unlock(); +	return err; +} +EXPORT_SYMBOL(sock_diag_put_filterinfo); +  void sock_diag_register_inet_compat(int (*fn)(struct sk_buff *skb, struct nlmsghdr *nlh))  {  	mutex_lock(&sock_diag_table_mutex); diff --git a/net/core/utils.c b/net/core/utils.c index e3487e461939..3c7f5b51b979 100644 --- a/net/core/utils.c +++ b/net/core/utils.c @@ -17,6 +17,7 @@  #include <linux/module.h>  #include <linux/jiffies.h>  #include <linux/kernel.h> +#include <linux/ctype.h>  #include <linux/inet.h>  #include <linux/mm.h>  #include <linux/net.h> @@ -348,9 +349,7 @@ int mac_pton(const char *s, u8 *mac)  	/* Don't dirty result unless string is valid MAC. */  	for (i = 0; i < ETH_ALEN; i++) { -		if (!strchr("0123456789abcdefABCDEF", s[i * 3])) -			return 0; -		if (!strchr("0123456789abcdefABCDEF", s[i * 3 + 1])) +		if (!isxdigit(s[i * 3]) || !isxdigit(s[i * 3 + 1]))  			return 0;  		if (i != ETH_ALEN - 1 && s[i * 3 + 2] != ':')  			return 0; | 
