forked from mirrors/linux
		
	vlan: allow null VLAN ID to be used
We currently use a 16 bit field (vlan_tci) to store VLAN ID/PRIO on a skb. Null value is used as a special value, meaning vlan tagging not enabled. This forbids use of null vlan ID. As pointed by David, some drivers use the 3 high order bits (PRIO) As VLAN ID is 12 bits, we can use the remaining bit (CFI) as a flag, and allow null VLAN ID. In case future code really wants to use VLAN_CFI_MASK, we'll have to use a bit outside of vlan_tci. #define VLAN_PRIO_MASK 0xe000 /* Priority Code Point */ #define VLAN_PRIO_SHIFT 13 #define VLAN_CFI_MASK 0x1000 /* Canonical Format Indicator */ #define VLAN_TAG_PRESENT VLAN_CFI_MASK #define VLAN_VID_MASK 0x0fff /* VLAN Identifier */ Reported-by: Gertjan Hofman <gertjan_hofman@yahoo.com> Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									9dbb58d867
								
							
						
					
					
						commit
						05423b2413
					
				
					 5 changed files with 15 additions and 10 deletions
				
			
		|  | @ -63,7 +63,11 @@ static inline struct vlan_ethhdr *vlan_eth_hdr(const struct sk_buff *skb) | ||||||
| 	return (struct vlan_ethhdr *)skb_mac_header(skb); | 	return (struct vlan_ethhdr *)skb_mac_header(skb); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #define VLAN_VID_MASK	0xfff | #define VLAN_PRIO_MASK		0xe000 /* Priority Code Point */ | ||||||
|  | #define VLAN_PRIO_SHIFT		13 | ||||||
|  | #define VLAN_CFI_MASK		0x1000 /* Canonical Format Indicator */ | ||||||
|  | #define VLAN_TAG_PRESENT	VLAN_CFI_MASK | ||||||
|  | #define VLAN_VID_MASK		0x0fff /* VLAN Identifier */ | ||||||
| 
 | 
 | ||||||
| /* found in socket.c */ | /* found in socket.c */ | ||||||
| extern void vlan_ioctl_set(int (*hook)(struct net *, void __user *)); | extern void vlan_ioctl_set(int (*hook)(struct net *, void __user *)); | ||||||
|  | @ -105,8 +109,8 @@ static inline void vlan_group_set_device(struct vlan_group *vg, | ||||||
| 	array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN] = dev; | 	array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN] = dev; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #define vlan_tx_tag_present(__skb)	((__skb)->vlan_tci) | #define vlan_tx_tag_present(__skb)	((__skb)->vlan_tci & VLAN_TAG_PRESENT) | ||||||
| #define vlan_tx_tag_get(__skb)		((__skb)->vlan_tci) | #define vlan_tx_tag_get(__skb)		((__skb)->vlan_tci & ~VLAN_TAG_PRESENT) | ||||||
| 
 | 
 | ||||||
| #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) | #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) | ||||||
| extern struct net_device *vlan_dev_real_dev(const struct net_device *dev); | extern struct net_device *vlan_dev_real_dev(const struct net_device *dev); | ||||||
|  | @ -231,7 +235,7 @@ static inline struct sk_buff *__vlan_put_tag(struct sk_buff *skb, u16 vlan_tci) | ||||||
| static inline struct sk_buff *__vlan_hwaccel_put_tag(struct sk_buff *skb, | static inline struct sk_buff *__vlan_hwaccel_put_tag(struct sk_buff *skb, | ||||||
| 						     u16 vlan_tci) | 						     u16 vlan_tci) | ||||||
| { | { | ||||||
| 	skb->vlan_tci = vlan_tci; | 	skb->vlan_tci = VLAN_TAG_PRESENT | vlan_tci; | ||||||
| 	return skb; | 	return skb; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -284,7 +288,7 @@ static inline int __vlan_hwaccel_get_tag(const struct sk_buff *skb, | ||||||
| 					 u16 *vlan_tci) | 					 u16 *vlan_tci) | ||||||
| { | { | ||||||
| 	if (vlan_tx_tag_present(skb)) { | 	if (vlan_tx_tag_present(skb)) { | ||||||
| 		*vlan_tci = skb->vlan_tci; | 		*vlan_tci = vlan_tx_tag_get(skb); | ||||||
| 		return 0; | 		return 0; | ||||||
| 	} else { | 	} else { | ||||||
| 		*vlan_tci = 0; | 		*vlan_tci = 0; | ||||||
|  |  | ||||||
|  | @ -89,7 +89,7 @@ static inline u32 vlan_get_ingress_priority(struct net_device *dev, | ||||||
| { | { | ||||||
| 	struct vlan_dev_info *vip = vlan_dev_info(dev); | 	struct vlan_dev_info *vip = vlan_dev_info(dev); | ||||||
| 
 | 
 | ||||||
| 	return vip->ingress_priority_map[(vlan_tci >> 13) & 0x7]; | 	return vip->ingress_priority_map[(vlan_tci >> VLAN_PRIO_SHIFT) & 0x7]; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #ifdef CONFIG_VLAN_8021Q_GVRP | #ifdef CONFIG_VLAN_8021Q_GVRP | ||||||
|  |  | ||||||
|  | @ -393,7 +393,7 @@ int vlan_dev_set_egress_priority(const struct net_device *dev, | ||||||
| 	struct vlan_dev_info *vlan = vlan_dev_info(dev); | 	struct vlan_dev_info *vlan = vlan_dev_info(dev); | ||||||
| 	struct vlan_priority_tci_mapping *mp = NULL; | 	struct vlan_priority_tci_mapping *mp = NULL; | ||||||
| 	struct vlan_priority_tci_mapping *np; | 	struct vlan_priority_tci_mapping *np; | ||||||
| 	u32 vlan_qos = (vlan_prio << 13) & 0xE000; | 	u32 vlan_qos = (vlan_prio << VLAN_PRIO_SHIFT) & VLAN_PRIO_MASK; | ||||||
| 
 | 
 | ||||||
| 	/* See if a priority mapping exists.. */ | 	/* See if a priority mapping exists.. */ | ||||||
| 	mp = vlan->egress_priority_map[skb_prio & 0xF]; | 	mp = vlan->egress_priority_map[skb_prio & 0xF]; | ||||||
|  |  | ||||||
|  | @ -2300,7 +2300,7 @@ int netif_receive_skb(struct sk_buff *skb) | ||||||
| 	if (!skb->tstamp.tv64) | 	if (!skb->tstamp.tv64) | ||||||
| 		net_timestamp(skb); | 		net_timestamp(skb); | ||||||
| 
 | 
 | ||||||
| 	if (skb->vlan_tci && vlan_hwaccel_do_receive(skb)) | 	if (vlan_tx_tag_present(skb) && vlan_hwaccel_do_receive(skb)) | ||||||
| 		return NET_RX_SUCCESS; | 		return NET_RX_SUCCESS; | ||||||
| 
 | 
 | ||||||
| 	/* if we've gotten here through NAPI, check netpoll */ | 	/* if we've gotten here through NAPI, check netpoll */ | ||||||
|  |  | ||||||
|  | @ -79,6 +79,7 @@ | ||||||
| #include <linux/module.h> | #include <linux/module.h> | ||||||
| #include <linux/init.h> | #include <linux/init.h> | ||||||
| #include <linux/mutex.h> | #include <linux/mutex.h> | ||||||
|  | #include <linux/if_vlan.h> | ||||||
| 
 | 
 | ||||||
| #ifdef CONFIG_INET | #ifdef CONFIG_INET | ||||||
| #include <net/inet_common.h> | #include <net/inet_common.h> | ||||||
|  | @ -766,7 +767,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, | ||||||
| 			getnstimeofday(&ts); | 			getnstimeofday(&ts); | ||||||
| 		h.h2->tp_sec = ts.tv_sec; | 		h.h2->tp_sec = ts.tv_sec; | ||||||
| 		h.h2->tp_nsec = ts.tv_nsec; | 		h.h2->tp_nsec = ts.tv_nsec; | ||||||
| 		h.h2->tp_vlan_tci = skb->vlan_tci; | 		h.h2->tp_vlan_tci = vlan_tx_tag_get(skb); | ||||||
| 		hdrlen = sizeof(*h.h2); | 		hdrlen = sizeof(*h.h2); | ||||||
| 		break; | 		break; | ||||||
| 	default: | 	default: | ||||||
|  | @ -1493,7 +1494,7 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, | ||||||
| 		aux.tp_snaplen = skb->len; | 		aux.tp_snaplen = skb->len; | ||||||
| 		aux.tp_mac = 0; | 		aux.tp_mac = 0; | ||||||
| 		aux.tp_net = skb_network_offset(skb); | 		aux.tp_net = skb_network_offset(skb); | ||||||
| 		aux.tp_vlan_tci = skb->vlan_tci; | 		aux.tp_vlan_tci = vlan_tx_tag_get(skb); | ||||||
| 
 | 
 | ||||||
| 		put_cmsg(msg, SOL_PACKET, PACKET_AUXDATA, sizeof(aux), &aux); | 		put_cmsg(msg, SOL_PACKET, PACKET_AUXDATA, sizeof(aux), &aux); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Eric Dumazet
						Eric Dumazet