#define _LINUX_IF_VLAN_H_
#ifdef __KERNEL__
-
-/* externally defined structs */
-struct hlist_node;
-
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/bug.h>
-#define VLAN_HLEN 4 /* The additional bytes (on top of the Ethernet header)
- * that VLAN requires.
+#define VLAN_HLEN 4 /* The additional bytes required by VLAN
+ * (in addition to the Ethernet header)
*/
-#define VLAN_ETH_ALEN 6 /* Octets in one ethernet addr */
#define VLAN_ETH_HLEN 18 /* Total octets in header. */
#define VLAN_ETH_ZLEN 64 /* Min. octets in frame sans FCS */
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 */
+#define VLAN_N_VID 4096
/* found in socket.c */
extern void vlan_ioctl_set(int (*hook)(struct net *, void __user *));
-/* if this changes, algorithm will have to be reworked because this
- * depends on completely exhausting the VLAN identifier space. Thus
- * it gives constant time look-up, but in many cases it wastes memory.
- */
-#define VLAN_GROUP_ARRAY_LEN 4096
-#define VLAN_GROUP_ARRAY_SPLIT_PARTS 8
-#define VLAN_GROUP_ARRAY_PART_LEN (VLAN_GROUP_ARRAY_LEN/VLAN_GROUP_ARRAY_SPLIT_PARTS)
-
-struct vlan_group {
- struct net_device *real_dev; /* The ethernet(like) device
- * the vlan is attached to.
- */
- unsigned int nr_vlans;
- struct hlist_node hlist; /* linked list */
- struct net_device **vlan_devices_arrays[VLAN_GROUP_ARRAY_SPLIT_PARTS];
- struct rcu_head rcu;
-};
+struct vlan_info;
-static inline struct net_device *vlan_group_get_device(struct vlan_group *vg,
- unsigned int vlan_id)
+static inline int is_vlan_dev(struct net_device *dev)
{
- struct net_device **array;
- array = vg->vlan_devices_arrays[vlan_id / VLAN_GROUP_ARRAY_PART_LEN];
- return array ? array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN] : NULL;
+ return dev->priv_flags & IFF_802_1Q_VLAN;
}
-static inline void vlan_group_set_device(struct vlan_group *vg,
- unsigned int vlan_id,
- struct net_device *dev)
-{
- struct net_device **array;
- if (!vg)
- return;
- array = vg->vlan_devices_arrays[vlan_id / VLAN_GROUP_ARRAY_PART_LEN];
- array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN] = dev;
-}
+#define vlan_tx_tag_present(__skb) ((__skb)->vlan_tci & VLAN_TAG_PRESENT)
+#define vlan_tx_tag_get(__skb) ((__skb)->vlan_tci & ~VLAN_TAG_PRESENT)
-struct vlan_priority_tci_mapping {
- u32 priority;
- unsigned short vlan_qos; /* This should be shifted when first set, so we only do it
- * at provisioning time.
- * ((skb->priority << 13) & 0xE000)
- */
- struct vlan_priority_tci_mapping *next;
-};
+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
-/* Holds information that makes sense if this device is a VLAN device. */
-struct vlan_dev_info {
- /** This will be the mapping that correlates skb->priority to
- * 3 bits of VLAN QOS tags...
- */
- unsigned int nr_ingress_mappings;
- u32 ingress_priority_map[8];
-
- unsigned int nr_egress_mappings;
- struct vlan_priority_tci_mapping *egress_priority_map[16]; /* hash table */
-
- unsigned short vlan_id; /* The VLAN Identifier for this interface. */
- unsigned short flags; /* (1 << 0) re_order_header This option will cause the
- * VLAN code to move around the ethernet header on
- * ingress to make the skb look **exactly** like it
- * came in from an ethernet port. This destroys some of
- * the VLAN information in the skb, but it fixes programs
- * like DHCP that use packet-filtering and don't understand
- * 802.1Q
- */
- struct net_device *real_dev; /* the underlying device/interface */
- unsigned char real_dev_addr[ETH_ALEN];
- struct proc_dir_entry *dent; /* Holds the proc data */
- unsigned long cnt_inc_headroom_on_tx; /* How many times did we have to grow the skb on TX. */
- unsigned long cnt_encap_on_xmit; /* How many times did we have to encapsulate the skb on TX. */
-};
+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);
-static inline struct vlan_dev_info *vlan_dev_info(const struct net_device *dev)
+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 netdev_priv(dev);
+ return NULL;
}
-/* inline functions */
-static inline __u32 vlan_get_ingress_priority(struct net_device *dev,
- unsigned short vlan_tag)
+static inline struct net_device *vlan_dev_real_dev(const struct net_device *dev)
{
- struct vlan_dev_info *vip = vlan_dev_info(dev);
-
- return vip->ingress_priority_map[(vlan_tag >> 13) & 0x7];
+ BUG();
+ return NULL;
}
-/* VLAN tx hw acceleration helpers. */
-struct vlan_skb_tx_cookie {
- u32 magic;
- u32 vlan_tag;
-};
-
-#define VLAN_TX_COOKIE_MAGIC 0x564c414e /* "VLAN" in ascii. */
-#define VLAN_TX_SKB_CB(__skb) ((struct vlan_skb_tx_cookie *)&((__skb)->cb[0]))
-#define vlan_tx_tag_present(__skb) \
- (VLAN_TX_SKB_CB(__skb)->magic == VLAN_TX_COOKIE_MAGIC)
-#define vlan_tx_tag_get(__skb) (VLAN_TX_SKB_CB(__skb)->vlan_tag)
-
-/* VLAN rx hw acceleration helper. This acts like netif_{rx,receive_skb}(). */
-static inline int __vlan_hwaccel_rx(struct sk_buff *skb,
- struct vlan_group *grp,
- unsigned short vlan_tag, int polling)
+static inline u16 vlan_dev_vlan_id(const struct net_device *dev)
{
- struct net_device_stats *stats;
-
- if (skb_bond_should_drop(skb)) {
- dev_kfree_skb_any(skb);
- return NET_RX_DROP;
- }
-
- skb->dev = vlan_group_get_device(grp, vlan_tag & VLAN_VID_MASK);
- if (skb->dev == NULL) {
- dev_kfree_skb_any(skb);
-
- /* Not NET_RX_DROP, this is not being dropped
- * due to congestion.
- */
- return 0;
- }
-
- skb->dev->last_rx = jiffies;
-
- stats = &skb->dev->stats;
- stats->rx_packets++;
- stats->rx_bytes += skb->len;
+ BUG();
+ return 0;
+}
- skb->priority = vlan_get_ingress_priority(skb->dev, vlan_tag);
- switch (skb->pkt_type) {
- case PACKET_BROADCAST:
- break;
+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;
+}
- case PACKET_MULTICAST:
- stats->multicast++;
- break;
+static inline struct sk_buff *vlan_untag(struct sk_buff *skb)
+{
+ return skb;
+}
- case PACKET_OTHERHOST:
- /* Our lower layer thinks this is not local, let's make sure.
- * This allows the VLAN to have a different MAC than the underlying
- * device, and still route correctly.
- */
- if (!compare_ether_addr(eth_hdr(skb)->h_dest,
- skb->dev->dev_addr))
- skb->pkt_type = PACKET_HOST;
- break;
- };
+static inline int vlan_vid_add(struct net_device *dev, unsigned short vid)
+{
+ return 0;
+}
- return (polling ? netif_receive_skb(skb) : netif_rx(skb));
+static inline void vlan_vid_del(struct net_device *dev, unsigned short vid)
+{
}
-static inline int vlan_hwaccel_rx(struct sk_buff *skb,
- struct vlan_group *grp,
- unsigned short vlan_tag)
+static inline int vlan_vids_add_by_dev(struct net_device *dev,
+ const struct net_device *by_dev)
{
- return __vlan_hwaccel_rx(skb, grp, vlan_tag, 0);
+ return 0;
}
-static inline int vlan_hwaccel_receive_skb(struct sk_buff *skb,
- struct vlan_group *grp,
- unsigned short vlan_tag)
+static inline void vlan_vids_del_by_dev(struct net_device *dev,
+ const struct net_device *by_dev)
{
- return __vlan_hwaccel_rx(skb, grp, vlan_tag, 1);
}
+#endif
/**
- * __vlan_put_tag - regular VLAN tag inserting
+ * vlan_insert_tag - regular VLAN tag inserting
* @skb: skbuff to tag
- * @tag: VLAN tag to insert
+ * @vlan_tci: VLAN TCI 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.
+ *
+ * Does not change skb->protocol so this function can be used during receive.
*/
-static inline struct sk_buff *__vlan_put_tag(struct sk_buff *skb, unsigned short tag)
+static inline struct sk_buff *vlan_insert_tag(struct sk_buff *skb, u16 vlan_tci)
{
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;
- }
+ if (skb_cow_head(skb, VLAN_HLEN) < 0) {
+ kfree_skb(skb);
+ 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);
+ memmove(skb->data, skb->data + VLAN_HLEN, 2 * ETH_ALEN);
+ skb->mac_header -= VLAN_HLEN;
/* first, the ethernet type */
veth->h_vlan_proto = htons(ETH_P_8021Q);
- /* now, the tag */
- veth->h_vlan_TCI = htons(tag);
+ /* now, the TCI */
+ veth->h_vlan_TCI = htons(vlan_tci);
- skb->protocol = htons(ETH_P_8021Q);
- skb->mac_header -= VLAN_HLEN;
- skb->network_header -= VLAN_HLEN;
+ return skb;
+}
+/**
+ * __vlan_put_tag - regular VLAN tag inserting
+ * @skb: skbuff to tag
+ * @vlan_tci: VLAN TCI 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, u16 vlan_tci)
+{
+ skb = vlan_insert_tag(skb, vlan_tci);
+ if (skb)
+ skb->protocol = htons(ETH_P_8021Q);
return skb;
}
/**
* __vlan_hwaccel_put_tag - hardware accelerated VLAN inserting
* @skb: skbuff to tag
- * @tag: VLAN tag to insert
+ * @vlan_tci: VLAN TCI to insert
*
- * Puts the VLAN tag in @skb->cb[] and lets the device do the rest
+ * Puts the VLAN TCI in @skb->vlan_tci and lets the device do the rest
*/
-static inline struct sk_buff *__vlan_hwaccel_put_tag(struct sk_buff *skb, unsigned short tag)
+static inline struct sk_buff *__vlan_hwaccel_put_tag(struct sk_buff *skb,
+ u16 vlan_tci)
{
- struct vlan_skb_tx_cookie *cookie;
-
- cookie = VLAN_TX_SKB_CB(skb);
- cookie->magic = VLAN_TX_COOKIE_MAGIC;
- cookie->vlan_tag = tag;
-
+ skb->vlan_tci = VLAN_TAG_PRESENT | vlan_tci;
return skb;
}
/**
* vlan_put_tag - inserts VLAN tag according to device features
* @skb: skbuff to tag
- * @tag: VLAN tag to insert
+ * @vlan_tci: VLAN TCI 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)
+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, tag);
+ return __vlan_hwaccel_put_tag(skb, vlan_tci);
} else {
- return __vlan_put_tag(skb, tag);
+ return __vlan_put_tag(skb, vlan_tci);
}
}
/**
* __vlan_get_tag - get the VLAN ID that is part of the payload
* @skb: skbuff to query
- * @tag: buffer to store vlaue
- *
+ * @vlan_tci: buffer to store vlaue
+ *
* Returns error if the skb is not of VLAN type
*/
-static inline int __vlan_get_tag(const struct sk_buff *skb, unsigned short *tag)
+static inline int __vlan_get_tag(const struct sk_buff *skb, u16 *vlan_tci)
{
struct vlan_ethhdr *veth = (struct vlan_ethhdr *)skb->data;
return -EINVAL;
}
- *tag = ntohs(veth->h_vlan_TCI);
-
+ *vlan_tci = 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
+ * @vlan_tci: buffer to store vlaue
+ *
+ * Returns error if @skb->vlan_tci is not set correctly
*/
static inline int __vlan_hwaccel_get_tag(const struct sk_buff *skb,
- unsigned short *tag)
+ u16 *vlan_tci)
{
- struct vlan_skb_tx_cookie *cookie;
-
- cookie = VLAN_TX_SKB_CB(skb);
- if (cookie->magic == VLAN_TX_COOKIE_MAGIC) {
- *tag = cookie->vlan_tag;
+ if (vlan_tx_tag_present(skb)) {
+ *vlan_tci = vlan_tx_tag_get(skb);
return 0;
} else {
- *tag = 0;
+ *vlan_tci = 0;
return -EINVAL;
}
}
/**
* vlan_get_tag - get the VLAN ID from the skb
* @skb: skbuff to query
- * @tag: buffer to store vlaue
- *
+ * @vlan_tci: buffer to store vlaue
+ *
* Returns error if the skb is not VLAN tagged
*/
-static inline int vlan_get_tag(const struct sk_buff *skb, unsigned short *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, tag);
+ return __vlan_hwaccel_get_tag(skb, vlan_tci);
} else {
- return __vlan_get_tag(skb, tag);
+ return __vlan_get_tag(skb, vlan_tci);
}
}
+/**
+ * vlan_get_protocol - get protocol EtherType.
+ * @skb: skbuff to query
+ *
+ * Returns the EtherType of the packet, regardless of whether it is
+ * vlan encapsulated (normal or hardware accelerated) or not.
+ */
+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;
+
+ /*
+ * Was a VLAN packet, grab the encapsulated protocol, which the layer
+ * three protocols care about.
+ */
+
+ proto = vhdr->h_vlan_encapsulated_proto;
+ if (ntohs(proto) >= 1536) {
+ skb->protocol = proto;
+ return;
+ }
+
+ rawp = skb->data;
+ if (*(unsigned short *) rawp == 0xFFFF)
+ /*
+ * This is a magic hack to spot IPX packets. Older Novell
+ * breaks the protocol design and runs IPX over 802.3 without
+ * an 802.2 LLC layer. We look for FFFF which isn't a used
+ * 802.2 SSAP/DSAP. This won't work for fault tolerant netware
+ * but does for the rest.
+ */
+ skb->protocol = htons(ETH_P_802_3);
+ else
+ /*
+ * Real 802.2 LLC
+ */
+ skb->protocol = htons(ETH_P_802_2);
+}
#endif /* __KERNEL__ */
/* VLAN IOCTLs are found in sockios.h */
enum vlan_flags {
VLAN_FLAG_REORDER_HDR = 0x1,
+ VLAN_FLAG_GVRP = 0x2,
+ VLAN_FLAG_LOOSE_BINDING = 0x4,
};
enum vlan_name_types {
unsigned int skb_priority;
unsigned int name_type;
unsigned int bind_type;
- unsigned int flag; /* Matches vlan_dev_info flags */
+ unsigned int flag; /* Matches vlan_dev_priv flags */
} u;
short vlan_qos;