Merge tag 'bug-for-3.4' of git://git.kernel.org/pub/scm/linux/kernel/git/paulg/linux
[linux-2.6.git] / include / linux / if_vlan.h
index 594cd35..a810987 100644 (file)
 #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 */
 
@@ -67,189 +64,161 @@ static inline struct vlan_ethhdr *vlan_eth_hdr(const struct sk_buff *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 */
+#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)
+#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)
 {
-       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;
+       return NULL;
 }
 
-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;
-};
+static inline struct net_device *vlan_dev_real_dev(const struct net_device *dev)
+{
+       BUG();
+       return NULL;
+}
 
-/* 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. */
-};
+static inline u16 vlan_dev_vlan_id(const struct net_device *dev)
+{
+       BUG();
+       return 0;
+}
 
-static inline struct vlan_dev_info *vlan_dev_info(const struct net_device *dev)
+static inline bool vlan_do_receive(struct sk_buff **skb, bool last_handler)
 {
-       return netdev_priv(dev);
+       if (((*skb)->vlan_tci & VLAN_VID_MASK) && last_handler)
+               (*skb)->pkt_type = PACKET_OTHERHOST;
+       return false;
 }
 
-/* VLAN tx hw acceleration helpers. */
-struct vlan_skb_tx_cookie {
-       u32     magic;
-       u32     vlan_tag;
-};
+static inline struct sk_buff *vlan_untag(struct sk_buff *skb)
+{
+       return skb;
+}
 
-#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)
+static inline int vlan_vid_add(struct net_device *dev, unsigned short vid)
+{
+       return 0;
+}
 
-#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
-extern int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp,
-                            unsigned short vlan_tag, int polling);
-#else
-static inline int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp,
-                                   unsigned short vlan_tag, int polling)
+static inline void vlan_vid_del(struct net_device *dev, unsigned short vid)
 {
-       BUG();
-       return NET_XMIT_SUCCESS;
 }
-#endif
 
-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);
+       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;
 }
 
@@ -258,28 +227,28 @@ static inline struct sk_buff *__vlan_hwaccel_put_tag(struct sk_buff *skb, unsign
 /**
  * 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;
 
@@ -287,29 +256,25 @@ static inline int __vlan_get_tag(const struct sk_buff *skb, unsigned short *tag)
                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;
        }
 }
@@ -319,19 +284,78 @@ static inline int __vlan_hwaccel_get_tag(const struct sk_buff *skb,
 /**
  * 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 */
@@ -353,6 +377,7 @@ enum vlan_ioctl_cmds {
 enum vlan_flags {
        VLAN_FLAG_REORDER_HDR   = 0x1,
        VLAN_FLAG_GVRP          = 0x2,
+       VLAN_FLAG_LOOSE_BINDING = 0x4,
 };
 
 enum vlan_name_types {
@@ -373,7 +398,7 @@ struct vlan_ioctl_args {
                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;