diff options
| author | Shmulik Hen <shmulik.hen@intel.com> | 2004-02-06 00:20:43 -0800 |
|---|---|---|
| committer | Hideaki Yoshifuji <yoshfuji@linux-ipv6.org> | 2004-02-06 00:20:43 -0800 |
| commit | cdea4568af5eecf3446de415c55a9751822d757d (patch) | |
| tree | bbd15b8c58ae9c3571d2f988d32d3e1f43e55fff /include | |
| parent | 6d7c32165fa2483419d6d4a0e82a7dd0830613e8 (diff) | |
[VLAN]: Export VLAN tag get/set functionality.
Enable intermediate network drivers like bonding to get or set a
VLAN tag in an skb without a need to know about how tagging is done
according to a network adapter's capabilities.
Diffstat (limited to 'include')
| -rw-r--r-- | include/linux/if_vlan.h | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h index 6cb10ed07188..104df1877778 100644 --- a/include/linux/if_vlan.h +++ b/include/linux/if_vlan.h @@ -200,6 +200,152 @@ static inline int vlan_hwaccel_receive_skb(struct sk_buff *skb, { return __vlan_hwaccel_rx(skb, grp, vlan_tag, 1); } + +/** + * __vlan_put_tag - regular VLAN tag inserting + * @skb: skbuff to tag + * @tag: VLAN tag to insert + * + * Inserts the VLAN tag into @skb as part of the payload + * Returns a VLAN tagged skb. If a new skb is created, @skb is freed. + * + * Following the skb_unshare() example, in case of error, the calling function + * doesn't have to worry about freeing the original skb. + */ +static inline struct sk_buff *__vlan_put_tag(struct sk_buff *skb, unsigned short tag) +{ + struct vlan_ethhdr *veth; + + if (skb_headroom(skb) < VLAN_HLEN) { + struct sk_buff *sk_tmp = skb; + skb = skb_realloc_headroom(sk_tmp, VLAN_HLEN); + kfree_skb(sk_tmp); + if (!skb) { + printk(KERN_ERR "vlan: failed to realloc headroom\n"); + return NULL; + } + } else { + skb = skb_unshare(skb, GFP_ATOMIC); + if (!skb) { + printk(KERN_ERR "vlan: failed to unshare skbuff\n"); + return NULL; + } + } + + veth = (struct vlan_ethhdr *)skb_push(skb, VLAN_HLEN); + + /* Move the mac addresses to the beginning of the new header. */ + memmove(skb->data, skb->data + VLAN_HLEN, 2 * VLAN_ETH_ALEN); + + /* first, the ethernet type */ + veth->h_vlan_proto = __constant_htons(ETH_P_8021Q); + + /* now, the tag */ + veth->h_vlan_TCI = htons(tag); + + skb->protocol = __constant_htons(ETH_P_8021Q); + skb->mac.raw -= VLAN_HLEN; + skb->nh.raw -= VLAN_HLEN; + + return skb; +} + +/** + * __vlan_hwaccel_put_tag - hardware accelerated VLAN inserting + * @skb: skbuff to tag + * @tag: VLAN tag to insert + * + * Puts the VLAN tag in @skb->cb[] and lets the device do the rest + */ +static inline struct sk_buff *__vlan_hwaccel_put_tag(struct sk_buff *skb, unsigned short tag) +{ + struct vlan_skb_tx_cookie *cookie; + + cookie = VLAN_TX_SKB_CB(skb); + cookie->magic = VLAN_TX_COOKIE_MAGIC; + cookie->vlan_tag = tag; + + return skb; +} + +#define HAVE_VLAN_PUT_TAG + +/** + * vlan_put_tag - inserts VLAN tag according to device features + * @skb: skbuff to tag + * @tag: VLAN tag to insert + * + * Assumes skb->dev is the target that will xmit this frame. + * Returns a VLAN tagged skb. + */ +static inline struct sk_buff *vlan_put_tag(struct sk_buff *skb, unsigned short tag) +{ + if (skb->dev->features & NETIF_F_HW_VLAN_TX) { + return __vlan_hwaccel_put_tag(skb, tag); + } else { + return __vlan_put_tag(skb, tag); + } +} + +/** + * __vlan_get_tag - get the VLAN ID that is part of the payload + * @skb: skbuff to query + * @tag: buffer to store vlaue + * + * Returns error if the skb is not of VLAN type + */ +static inline int __vlan_get_tag(struct sk_buff *skb, unsigned short *tag) +{ + struct vlan_ethhdr *veth = (struct vlan_ethhdr *)skb->data; + + if (veth->h_vlan_proto != __constant_htons(ETH_P_8021Q)) { + return -EINVAL; + } + + *tag = ntohs(veth->h_vlan_TCI); + + return 0; +} + +/** + * __vlan_hwaccel_get_tag - get the VLAN ID that is in @skb->cb[] + * @skb: skbuff to query + * @tag: buffer to store vlaue + * + * Returns error if @skb->cb[] is not set correctly + */ +static inline int __vlan_hwaccel_get_tag(struct sk_buff *skb, unsigned short *tag) +{ + struct vlan_skb_tx_cookie *cookie; + + cookie = VLAN_TX_SKB_CB(skb); + if (cookie->magic == VLAN_TX_COOKIE_MAGIC) { + *tag = cookie->vlan_tag; + return 0; + } else { + *tag = 0; + return -EINVAL; + } +} + +#define HAVE_VLAN_GET_TAG + +/** + * vlan_get_tag - get the VLAN ID from the skb + * @skb: skbuff to query + * @tag: buffer to store vlaue + * + * Returns error if the skb is not VLAN tagged + */ +static inline int vlan_get_tag(struct sk_buff *skb, unsigned short *tag) +{ + if (skb->dev->features & NETIF_F_HW_VLAN_TX) { + return __vlan_hwaccel_get_tag(skb, tag); + } else { + return __vlan_get_tag(skb, tag); + } +} + #endif /* __KERNEL__ */ /* VLAN IOCTLs are found in sockios.h */ |
