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 a1b0066..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,242 +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 *));
 
-#define VLAN_NAME "vlan"
-
-/* 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 {
-       int real_dev_ifindex; /* The ifindex of the ethernet(like) device the vlan is attached to. */
-       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[vlan_id % VLAN_GROUP_ARRAY_PART_LEN];
+        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. */
-       struct net_device_stats dev_stats; /* Device stats (rx-bytes, tx-pkts, etc...) */
-};
+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);
 
-#define VLAN_DEV_INFO(x) ((struct vlan_dev_info *)(x->priv))
+extern bool vlan_do_receive(struct sk_buff **skb, bool last_handler);
+extern struct sk_buff *vlan_untag(struct sk_buff *skb);
 
-/* inline functions */
+extern int vlan_vid_add(struct net_device *dev, unsigned short vid);
+extern void vlan_vid_del(struct net_device *dev, unsigned short vid);
 
-static inline struct net_device_stats *vlan_dev_get_stats(struct net_device *dev)
+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 &(VLAN_DEV_INFO(dev)->dev_stats);
+       return NULL;
 }
 
-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 = vlan_dev_get_stats(skb->dev);
-       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 = __constant_htons(ETH_P_8021Q);
+       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 = __constant_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;
 }
 
@@ -311,57 +227,54 @@ 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(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;
 
-       if (veth->h_vlan_proto != __constant_htons(ETH_P_8021Q)) {
+       if (veth->h_vlan_proto != htons(ETH_P_8021Q)) {
                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(struct sk_buff *skb, unsigned short *tag)
+static inline int __vlan_hwaccel_get_tag(const struct sk_buff *skb,
+                                        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;
        }
 }
@@ -371,19 +284,78 @@ static inline int __vlan_hwaccel_get_tag(struct sk_buff *skb, unsigned short *ta
 /**
  * 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(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 */
@@ -404,6 +376,8 @@ 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 {
@@ -424,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;