datapath: Add __vlan_insert_tag() compat helper if not available
[cascardo/ovs.git] / datapath / linux / compat / include / linux / if_vlan.h
1 #ifndef __LINUX_IF_VLAN_WRAPPER_H
2 #define __LINUX_IF_VLAN_WRAPPER_H 1
3
4 #include <linux/skbuff.h>
5 #include <linux/version.h>
6 #include_next <linux/if_vlan.h>
7
8 #ifndef HAVE_VLAN_INSERT_TAG_SET_PROTO
9 /*
10  * The behavior of __vlan_put_tag()/vlan_insert_tag_set_proto() has changed
11  * over time:
12  *
13  *      - In 2.6.26 and earlier, it adjusted both MAC and network header
14  *        pointers.  (The latter didn't make any sense.)
15  *
16  *      - In 2.6.27 and 2.6.28, it did not adjust any header pointers at all.
17  *
18  *      - In 2.6.29 and later, it adjusts the MAC header pointer only.
19  *
20  *      - In 3.19 and later, it was renamed to vlan_insert_tag_set_proto()
21  *
22  * This is the version from 2.6.33.  We unconditionally substitute this version
23  * to avoid the need to guess whether the version in the kernel tree is
24  * acceptable.
25  */
26 #define vlan_insert_tag_set_proto(skb, proto, vlan_tci) \
27         rpl_vlan_insert_tag_set_proto(skb, vlan_tci)
28 static inline struct sk_buff *rpl_vlan_insert_tag_set_proto(struct sk_buff *skb,
29                                                             u16 vlan_tci)
30 {
31         struct vlan_ethhdr *veth;
32
33         if (skb_cow_head(skb, VLAN_HLEN) < 0) {
34                 kfree_skb(skb);
35                 return NULL;
36         }
37         veth = (struct vlan_ethhdr *)skb_push(skb, VLAN_HLEN);
38
39         /* Move the mac addresses to the beginning of the new header. */
40         memmove(skb->data, skb->data + VLAN_HLEN, 2 * ETH_ALEN);
41         skb->mac_header -= VLAN_HLEN;
42
43         /* first, the ethernet type */
44         veth->h_vlan_proto = htons(ETH_P_8021Q);
45
46         /* now, the TCI */
47         veth->h_vlan_TCI = htons(vlan_tci);
48
49         skb->protocol = htons(ETH_P_8021Q);
50
51         return skb;
52 }
53 #endif
54
55 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0)
56 static inline struct sk_buff *rpl___vlan_hwaccel_put_tag(struct sk_buff *skb,
57                                                      __be16 vlan_proto,
58                                                      u16 vlan_tci)
59 {
60         return __vlan_hwaccel_put_tag(skb, vlan_tci);
61 }
62
63 #define __vlan_hwaccel_put_tag rpl___vlan_hwaccel_put_tag
64 #endif
65
66 /* All of these were introduced in a single commit preceding 2.6.33, so
67  * presumably all of them or none of them are present. */
68 #ifndef VLAN_PRIO_MASK
69 #define VLAN_PRIO_MASK          0xe000 /* Priority Code Point */
70 #define VLAN_PRIO_SHIFT         13
71 #define VLAN_CFI_MASK           0x1000 /* Canonical Format Indicator */
72 #define VLAN_TAG_PRESENT        VLAN_CFI_MASK
73 #endif
74
75 #ifndef HAVE_VLAN_SET_ENCAP_PROTO
76 static inline void vlan_set_encap_proto(struct sk_buff *skb, struct vlan_hdr *vhdr)
77 {
78         __be16 proto;
79         unsigned char *rawp;
80
81         /*
82          * Was a VLAN packet, grab the encapsulated protocol, which the layer
83          * three protocols care about.
84          */
85
86         proto = vhdr->h_vlan_encapsulated_proto;
87         if (ntohs(proto) >= 1536) {
88                 skb->protocol = proto;
89                 return;
90         }
91
92         rawp = skb->data;
93         if (*(unsigned short *) rawp == 0xFFFF)
94                 /*
95                  * This is a magic hack to spot IPX packets. Older Novell
96                  * breaks the protocol design and runs IPX over 802.3 without
97                  * an 802.2 LLC layer. We look for FFFF which isn't a used
98                  * 802.2 SSAP/DSAP. This won't work for fault tolerant netware
99                  * but does for the rest.
100                  */
101                 skb->protocol = htons(ETH_P_802_3);
102         else
103                 /*
104                  * Real 802.2 LLC
105                  */
106                 skb->protocol = htons(ETH_P_802_2);
107 }
108 #endif
109
110 #ifndef HAVE___VLAN_INSERT_TAG
111 /* Kernels which don't have __vlan_insert_tag() also don't have skb->vlan_proto
112  * so ignore the proto paramter.
113  */
114 #define __vlan_insert_tag(skb, proto, tci) rpl_vlan_insert_tag(skb, tci)
115 static inline int rpl_vlan_insert_tag(struct sk_buff *skb, u16 vlan_tci)
116 {
117         struct vlan_ethhdr *veth;
118
119         if (skb_cow_head(skb, VLAN_HLEN) < 0)
120                 return -ENOMEM;
121
122         veth = (struct vlan_ethhdr *)skb_push(skb, VLAN_HLEN);
123
124         /* Move the mac addresses to the beginning of the new header. */
125         memmove(skb->data, skb->data + VLAN_HLEN, 2 * ETH_ALEN);
126         skb->mac_header -= VLAN_HLEN;
127
128         /* first, the ethernet type */
129         veth->h_vlan_proto = htons(ETH_P_8021Q);
130
131         /* now, the TCI */
132         veth->h_vlan_TCI = htons(ETH_P_8021Q);
133
134         return 0;
135 }
136 #endif
137
138 #endif  /* linux/if_vlan.h wrapper */