/* * VLAN An implementation of 802.1Q VLAN tagging. * * Authors: Ben Greear * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * */ #ifndef _LINUX_IF_VLAN_H_ #define _LINUX_IF_VLAN_H_ #ifdef __KERNEL__ #include #include #include #include #define VLAN_HLEN 4 #define VLAN_ETH_HLEN 18 #define VLAN_ETH_ZLEN 64 #define VLAN_ETH_DATA_LEN 1500 #define VLAN_ETH_FRAME_LEN 1518 struct vlan_hdr { __be16 h_vlan_TCI; __be16 h_vlan_encapsulated_proto; }; struct vlan_ethhdr { unsigned char h_dest[ETH_ALEN]; unsigned char h_source[ETH_ALEN]; __be16 h_vlan_proto; __be16 h_vlan_TCI; __be16 h_vlan_encapsulated_proto; }; #include static inline struct vlan_ethhdr *vlan_eth_hdr(const struct sk_buff *skb) { return (struct vlan_ethhdr *)skb_mac_header(skb); } #define VLAN_PRIO_MASK 0xe000 #define VLAN_PRIO_SHIFT 13 #define VLAN_CFI_MASK 0x1000 #define VLAN_TAG_PRESENT VLAN_CFI_MASK #define VLAN_VID_MASK 0x0fff #define VLAN_N_VID 4096 extern void vlan_ioctl_set(int (*hook)(struct net *, void __user *)); struct vlan_info; static inline int is_vlan_dev(struct net_device *dev) { return dev->priv_flags & IFF_802_1Q_VLAN; } #define vlan_tx_tag_present(__skb) ((__skb)->vlan_tci & VLAN_TAG_PRESENT) #define vlan_tx_tag_get(__skb) ((__skb)->vlan_tci & ~VLAN_TAG_PRESENT) #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) extern struct net_device *__vlan_find_dev_deep(struct net_device *real_dev, u16 vlan_id); extern struct net_device *vlan_dev_real_dev(const struct net_device *dev); extern u16 vlan_dev_vlan_id(const struct net_device *dev); extern bool vlan_do_receive(struct sk_buff **skb, bool last_handler); extern struct sk_buff *vlan_untag(struct sk_buff *skb); extern int vlan_vid_add(struct net_device *dev, unsigned short vid); extern void vlan_vid_del(struct net_device *dev, unsigned short vid); extern int vlan_vids_add_by_dev(struct net_device *dev, const struct net_device *by_dev); extern void vlan_vids_del_by_dev(struct net_device *dev, const struct net_device *by_dev); #else static inline struct net_device * __vlan_find_dev_deep(struct net_device *real_dev, u16 vlan_id) { return NULL; } static inline struct net_device *vlan_dev_real_dev(const struct net_device *dev) { BUG(); return NULL; } static inline u16 vlan_dev_vlan_id(const struct net_device *dev) { BUG(); return 0; } static inline bool vlan_do_receive(struct sk_buff **skb, bool last_handler) { if (((*skb)->vlan_tci & VLAN_VID_MASK) && last_handler) (*skb)->pkt_type = PACKET_OTHERHOST; return false; } static inline struct sk_buff *vlan_untag(struct sk_buff *skb) { return skb; } static inline int vlan_vid_add(struct net_device *dev, unsigned short vid) { return 0; } static inline void vlan_vid_del(struct net_device *dev, unsigned short vid) { } static inline int vlan_vids_add_by_dev(struct net_device *dev, const struct net_device *by_dev) { return 0; } static inline void vlan_vids_del_by_dev(struct net_device *dev, const struct net_device *by_dev) { } #endif static inline struct sk_buff *vlan_insert_tag(struct sk_buff *skb, u16 vlan_tci) { struct vlan_ethhdr *veth; if (skb_cow_head(skb, VLAN_HLEN) < 0) { kfree_skb(skb); return NULL; } veth = (struct vlan_ethhdr *)skb_push(skb, VLAN_HLEN); memmove(skb->data, skb->data + VLAN_HLEN, 2 * ETH_ALEN); skb->mac_header -= VLAN_HLEN; veth->h_vlan_proto = htons(ETH_P_8021Q); veth->h_vlan_TCI = htons(vlan_tci); return skb; } static inline struct sk_buff *__vlan_put_tag(struct sk_buff *skb, u16 vlan_tci) { skb = vlan_insert_tag(skb, vlan_tci); if (skb) skb->protocol = htons(ETH_P_8021Q); return skb; } static inline struct sk_buff *__vlan_hwaccel_put_tag(struct sk_buff *skb, u16 vlan_tci) { skb->vlan_tci = VLAN_TAG_PRESENT | vlan_tci; return skb; } #define HAVE_VLAN_PUT_TAG static inline struct sk_buff *vlan_put_tag(struct sk_buff *skb, u16 vlan_tci) { if (skb->dev->features & NETIF_F_HW_VLAN_TX) { return __vlan_hwaccel_put_tag(skb, vlan_tci); } else { return __vlan_put_tag(skb, vlan_tci); } } static inline int __vlan_get_tag(const struct sk_buff *skb, u16 *vlan_tci) { struct vlan_ethhdr *veth = (struct vlan_ethhdr *)skb->data; if (veth->h_vlan_proto != htons(ETH_P_8021Q)) { return -EINVAL; } *vlan_tci = ntohs(veth->h_vlan_TCI); return 0; } static inline int __vlan_hwaccel_get_tag(const struct sk_buff *skb, u16 *vlan_tci) { if (vlan_tx_tag_present(skb)) { *vlan_tci = vlan_tx_tag_get(skb); return 0; } else { *vlan_tci = 0; return -EINVAL; } } #define HAVE_VLAN_GET_TAG static inline int vlan_get_tag(const struct sk_buff *skb, u16 *vlan_tci) { if (skb->dev->features & NETIF_F_HW_VLAN_TX) { return __vlan_hwaccel_get_tag(skb, vlan_tci); } else { return __vlan_get_tag(skb, vlan_tci); } } static inline __be16 vlan_get_protocol(const struct sk_buff *skb) { __be16 protocol = 0; if (vlan_tx_tag_present(skb) || skb->protocol != cpu_to_be16(ETH_P_8021Q)) protocol = skb->protocol; else { __be16 proto, *protop; protop = skb_header_pointer(skb, offsetof(struct vlan_ethhdr, h_vlan_encapsulated_proto), sizeof(proto), &proto); if (likely(protop)) protocol = *protop; } return protocol; } static inline void vlan_set_encap_proto(struct sk_buff *skb, struct vlan_hdr *vhdr) { __be16 proto; unsigned char *rawp; proto = vhdr->h_vlan_encapsulated_proto; if (ntohs(proto) >= 1536) { skb->protocol = proto; return; } rawp = skb->data; if (*(unsigned short *) rawp == 0xFFFF) skb->protocol = htons(ETH_P_802_3); else skb->protocol = htons(ETH_P_802_2); } #endif enum vlan_ioctl_cmds { ADD_VLAN_CMD, DEL_VLAN_CMD, SET_VLAN_INGRESS_PRIORITY_CMD, SET_VLAN_EGRESS_PRIORITY_CMD, GET_VLAN_INGRESS_PRIORITY_CMD, GET_VLAN_EGRESS_PRIORITY_CMD, SET_VLAN_NAME_TYPE_CMD, SET_VLAN_FLAG_CMD, GET_VLAN_REALDEV_NAME_CMD, GET_VLAN_VID_CMD }; enum vlan_flags { VLAN_FLAG_REORDER_HDR = 0x1, VLAN_FLAG_GVRP = 0x2, VLAN_FLAG_LOOSE_BINDING = 0x4, }; enum vlan_name_types { VLAN_NAME_TYPE_PLUS_VID, VLAN_NAME_TYPE_RAW_PLUS_VID, VLAN_NAME_TYPE_PLUS_VID_NO_PAD, VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD, VLAN_NAME_TYPE_HIGHEST }; struct vlan_ioctl_args { int cmd; char device1[24]; union { char device2[24]; int VID; unsigned int skb_priority; unsigned int name_type; unsigned int bind_type; unsigned int flag; } u; short vlan_qos; }; #endif