diff options
| author | Thomas Gleixner <tglx@linutronix.de> | 2013-05-05 08:24:42 +0200 | 
|---|---|---|
| committer | Thomas Gleixner <tglx@linutronix.de> | 2013-05-05 08:27:03 +0200 | 
| commit | f99e44a7f3352d7131c7526207f153f13ec5acd4 (patch) | |
| tree | 0f448b21128c478053ee7f7765b865954c4eebe8 /net/8021q/vlan_core.c | |
| parent | fd29f424d458118f02e89596505c68a63dcb3007 (diff) | |
| parent | ce857229e0c3adc211944a13a5579ef84fd7b4af (diff) | |
Merge branch 'linus' into core/urgent
Update with Linus tree so fixes for the same can be applied.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'net/8021q/vlan_core.c')
| -rw-r--r-- | net/8021q/vlan_core.c | 80 | 
1 files changed, 50 insertions, 30 deletions
| diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c index f3b6f515eba6..8a15eaadc4bd 100644 --- a/net/8021q/vlan_core.c +++ b/net/8021q/vlan_core.c @@ -8,11 +8,12 @@  bool vlan_do_receive(struct sk_buff **skbp)  {  	struct sk_buff *skb = *skbp; +	__be16 vlan_proto = skb->vlan_proto;  	u16 vlan_id = skb->vlan_tci & VLAN_VID_MASK;  	struct net_device *vlan_dev;  	struct vlan_pcpu_stats *rx_stats; -	vlan_dev = vlan_find_dev(skb->dev, vlan_id); +	vlan_dev = vlan_find_dev(skb->dev, vlan_proto, vlan_id);  	if (!vlan_dev)  		return false; @@ -38,7 +39,8 @@ bool vlan_do_receive(struct sk_buff **skbp)  		 * original position later  		 */  		skb_push(skb, offset); -		skb = *skbp = vlan_insert_tag(skb, skb->vlan_tci); +		skb = *skbp = vlan_insert_tag(skb, skb->vlan_proto, +					      skb->vlan_tci);  		if (!skb)  			return false;  		skb_pull(skb, offset + VLAN_HLEN); @@ -62,12 +64,13 @@ bool vlan_do_receive(struct sk_buff **skbp)  /* Must be invoked with rcu_read_lock. */  struct net_device *__vlan_find_dev_deep(struct net_device *dev, -					u16 vlan_id) +					__be16 vlan_proto, u16 vlan_id)  {  	struct vlan_info *vlan_info = rcu_dereference(dev->vlan_info);  	if (vlan_info) { -		return vlan_group_get_device(&vlan_info->grp, vlan_id); +		return vlan_group_get_device(&vlan_info->grp, +					     vlan_proto, vlan_id);  	} else {  		/*  		 * Lower devices of master uppers (bonding, team) do not have @@ -78,7 +81,8 @@ struct net_device *__vlan_find_dev_deep(struct net_device *dev,  		upper_dev = netdev_master_upper_dev_get_rcu(dev);  		if (upper_dev) -			return __vlan_find_dev_deep(upper_dev, vlan_id); +			return __vlan_find_dev_deep(upper_dev, +						    vlan_proto, vlan_id);  	}  	return NULL; @@ -125,7 +129,7 @@ struct sk_buff *vlan_untag(struct sk_buff *skb)  	vhdr = (struct vlan_hdr *) skb->data;  	vlan_tci = ntohs(vhdr->h_vlan_TCI); -	__vlan_hwaccel_put_tag(skb, vlan_tci); +	__vlan_hwaccel_put_tag(skb, skb->protocol, vlan_tci);  	skb_pull_rcsum(skb, VLAN_HLEN);  	vlan_set_encap_proto(skb, vhdr); @@ -153,10 +157,11 @@ EXPORT_SYMBOL(vlan_untag);  static void vlan_group_free(struct vlan_group *grp)  { -	int i; +	int i, j; -	for (i = 0; i < VLAN_GROUP_ARRAY_SPLIT_PARTS; i++) -		kfree(grp->vlan_devices_arrays[i]); +	for (i = 0; i < VLAN_PROTO_NUM; i++) +		for (j = 0; j < VLAN_GROUP_ARRAY_SPLIT_PARTS; j++) +			kfree(grp->vlan_devices_arrays[i][j]);  }  static void vlan_info_free(struct vlan_info *vlan_info) @@ -185,35 +190,49 @@ static struct vlan_info *vlan_info_alloc(struct net_device *dev)  struct vlan_vid_info {  	struct list_head list; -	unsigned short vid; +	__be16 proto; +	u16 vid;  	int refcount;  }; +static bool vlan_hw_filter_capable(const struct net_device *dev, +				     const struct vlan_vid_info *vid_info) +{ +	if (vid_info->proto == htons(ETH_P_8021Q) && +	    dev->features & NETIF_F_HW_VLAN_CTAG_FILTER) +		return true; +	if (vid_info->proto == htons(ETH_P_8021AD) && +	    dev->features & NETIF_F_HW_VLAN_STAG_FILTER) +		return true; +	return false; +} +  static struct vlan_vid_info *vlan_vid_info_get(struct vlan_info *vlan_info, -					       unsigned short vid) +					       __be16 proto, u16 vid)  {  	struct vlan_vid_info *vid_info;  	list_for_each_entry(vid_info, &vlan_info->vid_list, list) { -		if (vid_info->vid == vid) +		if (vid_info->proto == proto && vid_info->vid == vid)  			return vid_info;  	}  	return NULL;  } -static struct vlan_vid_info *vlan_vid_info_alloc(unsigned short vid) +static struct vlan_vid_info *vlan_vid_info_alloc(__be16 proto, u16 vid)  {  	struct vlan_vid_info *vid_info;  	vid_info = kzalloc(sizeof(struct vlan_vid_info), GFP_KERNEL);  	if (!vid_info)  		return NULL; +	vid_info->proto = proto;  	vid_info->vid = vid;  	return vid_info;  } -static int __vlan_vid_add(struct vlan_info *vlan_info, unsigned short vid, +static int __vlan_vid_add(struct vlan_info *vlan_info, __be16 proto, u16 vid,  			  struct vlan_vid_info **pvid_info)  {  	struct net_device *dev = vlan_info->real_dev; @@ -221,12 +240,12 @@ static int __vlan_vid_add(struct vlan_info *vlan_info, unsigned short vid,  	struct vlan_vid_info *vid_info;  	int err; -	vid_info = vlan_vid_info_alloc(vid); +	vid_info = vlan_vid_info_alloc(proto, vid);  	if (!vid_info)  		return -ENOMEM; -	if (dev->features & NETIF_F_HW_VLAN_FILTER) { -		err =  ops->ndo_vlan_rx_add_vid(dev, vid); +	if (vlan_hw_filter_capable(dev, vid_info)) { +		err =  ops->ndo_vlan_rx_add_vid(dev, proto, vid);  		if (err) {  			kfree(vid_info);  			return err; @@ -238,7 +257,7 @@ static int __vlan_vid_add(struct vlan_info *vlan_info, unsigned short vid,  	return 0;  } -int vlan_vid_add(struct net_device *dev, unsigned short vid) +int vlan_vid_add(struct net_device *dev, __be16 proto, u16 vid)  {  	struct vlan_info *vlan_info;  	struct vlan_vid_info *vid_info; @@ -254,9 +273,9 @@ int vlan_vid_add(struct net_device *dev, unsigned short vid)  			return -ENOMEM;  		vlan_info_created = true;  	} -	vid_info = vlan_vid_info_get(vlan_info, vid); +	vid_info = vlan_vid_info_get(vlan_info, proto, vid);  	if (!vid_info) { -		err = __vlan_vid_add(vlan_info, vid, &vid_info); +		err = __vlan_vid_add(vlan_info, proto, vid, &vid_info);  		if (err)  			goto out_free_vlan_info;  	} @@ -279,14 +298,15 @@ static void __vlan_vid_del(struct vlan_info *vlan_info,  {  	struct net_device *dev = vlan_info->real_dev;  	const struct net_device_ops *ops = dev->netdev_ops; -	unsigned short vid = vid_info->vid; +	__be16 proto = vid_info->proto; +	u16 vid = vid_info->vid;  	int err; -	if (dev->features & NETIF_F_HW_VLAN_FILTER) { -		err = ops->ndo_vlan_rx_kill_vid(dev, vid); +	if (vlan_hw_filter_capable(dev, vid_info)) { +		err = ops->ndo_vlan_rx_kill_vid(dev, proto, vid);  		if (err) { -			pr_warn("failed to kill vid %d for device %s\n", -				vid, dev->name); +			pr_warn("failed to kill vid %04x/%d for device %s\n", +				proto, vid, dev->name);  		}  	}  	list_del(&vid_info->list); @@ -294,7 +314,7 @@ static void __vlan_vid_del(struct vlan_info *vlan_info,  	vlan_info->nr_vids--;  } -void vlan_vid_del(struct net_device *dev, unsigned short vid) +void vlan_vid_del(struct net_device *dev, __be16 proto, u16 vid)  {  	struct vlan_info *vlan_info;  	struct vlan_vid_info *vid_info; @@ -305,7 +325,7 @@ void vlan_vid_del(struct net_device *dev, unsigned short vid)  	if (!vlan_info)  		return; -	vid_info = vlan_vid_info_get(vlan_info, vid); +	vid_info = vlan_vid_info_get(vlan_info, proto, vid);  	if (!vid_info)  		return;  	vid_info->refcount--; @@ -333,7 +353,7 @@ int vlan_vids_add_by_dev(struct net_device *dev,  		return 0;  	list_for_each_entry(vid_info, &vlan_info->vid_list, list) { -		err = vlan_vid_add(dev, vid_info->vid); +		err = vlan_vid_add(dev, vid_info->proto, vid_info->vid);  		if (err)  			goto unwind;  	} @@ -343,7 +363,7 @@ unwind:  	list_for_each_entry_continue_reverse(vid_info,  					     &vlan_info->vid_list,  					     list) { -		vlan_vid_del(dev, vid_info->vid); +		vlan_vid_del(dev, vid_info->proto, vid_info->vid);  	}  	return err; @@ -363,7 +383,7 @@ void vlan_vids_del_by_dev(struct net_device *dev,  		return;  	list_for_each_entry(vid_info, &vlan_info->vid_list, list) -		vlan_vid_del(dev, vid_info->vid); +		vlan_vid_del(dev, vid_info->proto, vid_info->vid);  }  EXPORT_SYMBOL(vlan_vids_del_by_dev); | 
