if_vlan.h 12.7 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/*
 * VLAN		An implementation of 802.1Q VLAN tagging.
 *
 * Authors:	Ben Greear <greearb@candelatech.com>
 *
 *		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_

#include <linux/netdevice.h>
16
#include <linux/etherdevice.h>
17
#include <linux/rtnetlink.h>
18
#include <linux/bug.h>
19
#include <uapi/linux/if_vlan.h>
Linus Torvalds's avatar
Linus Torvalds committed
20

21
22
#define VLAN_HLEN	4		/* The additional bytes required by VLAN
					 * (in addition to the Ethernet header)
Linus Torvalds's avatar
Linus Torvalds committed
23
24
25
26
27
28
29
30
31
32
					 */
#define VLAN_ETH_HLEN	18		/* Total octets in header.	 */
#define VLAN_ETH_ZLEN	64		/* Min. octets in frame sans FCS */

/*
 * According to 802.3ac, the packet can be 4 bytes longer. --Klika Jan
 */
#define VLAN_ETH_DATA_LEN	1500	/* Max. octets in payload	 */
#define VLAN_ETH_FRAME_LEN	1518	/* Max. octets in frame sans FCS */

33
34
35
36
37
38
39
40
41
42
43
44
45
46
/*
 * 	struct vlan_hdr - vlan header
 * 	@h_vlan_TCI: priority and VLAN ID
 *	@h_vlan_encapsulated_proto: packet type ID or len
 */
struct vlan_hdr {
	__be16	h_vlan_TCI;
	__be16	h_vlan_encapsulated_proto;
};

/**
 *	struct vlan_ethhdr - vlan ethernet header (ethhdr + vlan_hdr)
 *	@h_dest: destination ethernet address
 *	@h_source: source ethernet address
47
 *	@h_vlan_proto: ethernet protocol
48
49
50
 *	@h_vlan_TCI: priority and VLAN ID
 *	@h_vlan_encapsulated_proto: packet type ID or len
 */
Linus Torvalds's avatar
Linus Torvalds committed
51
struct vlan_ethhdr {
52
53
54
55
56
	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;
Linus Torvalds's avatar
Linus Torvalds committed
57
58
59
60
61
62
};

#include <linux/skbuff.h>

static inline struct vlan_ethhdr *vlan_eth_hdr(const struct sk_buff *skb)
{
63
	return (struct vlan_ethhdr *)skb_mac_header(skb);
Linus Torvalds's avatar
Linus Torvalds committed
64
65
}

66
67
68
69
70
#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 */
71
#define VLAN_N_VID		4096
Linus Torvalds's avatar
Linus Torvalds committed
72
73

/* found in socket.c */
74
extern void vlan_ioctl_set(int (*hook)(struct net *, void __user *));
Linus Torvalds's avatar
Linus Torvalds committed
75

76
77
78
79
80
static inline int is_vlan_dev(struct net_device *dev)
{
        return dev->priv_flags & IFF_802_1Q_VLAN;
}

81
82
#define vlan_tx_tag_present(__skb)	((__skb)->vlan_tci & VLAN_TAG_PRESENT)
#define vlan_tx_tag_get(__skb)		((__skb)->vlan_tci & ~VLAN_TAG_PRESENT)
Eric Dumazet's avatar
Eric Dumazet committed
83
#define vlan_tx_tag_get_id(__skb)	((__skb)->vlan_tci & VLAN_VID_MASK)
Linus Torvalds's avatar
Linus Torvalds committed
84

85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
/**
 *	struct vlan_pcpu_stats - VLAN percpu rx/tx stats
 *	@rx_packets: number of received packets
 *	@rx_bytes: number of received bytes
 *	@rx_multicast: number of received multicast packets
 *	@tx_packets: number of transmitted packets
 *	@tx_bytes: number of transmitted bytes
 *	@syncp: synchronization point for 64bit counters
 *	@rx_errors: number of rx errors
 *	@tx_dropped: number of tx drops
 */
struct vlan_pcpu_stats {
	u64			rx_packets;
	u64			rx_bytes;
	u64			rx_multicast;
	u64			tx_packets;
	u64			tx_bytes;
	struct u64_stats_sync	syncp;
	u32			rx_errors;
	u32			tx_dropped;
};

107
108
109
110
111
112
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)

extern struct net_device *__vlan_find_dev_deep(struct net_device *real_dev,
					       __be16 vlan_proto, 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);
113
extern __be16 vlan_dev_vlan_proto(const struct net_device *dev);
114
115
116
117
118
119
120
121
122
123
124
125
126

/**
 *	struct vlan_priority_tci_mapping - vlan egress priority mappings
 *	@priority: skb priority
 *	@vlan_qos: vlan priority: (skb->priority << 13) & 0xE000
 *	@next: pointer to next struct
 */
struct vlan_priority_tci_mapping {
	u32					priority;
	u16					vlan_qos;
	struct vlan_priority_tci_mapping	*next;
};

127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
struct proc_dir_entry;
struct netpoll;

/**
 *	struct vlan_dev_priv - VLAN private device data
 *	@nr_ingress_mappings: number of ingress priority mappings
 *	@ingress_priority_map: ingress priority mappings
 *	@nr_egress_mappings: number of egress priority mappings
 *	@egress_priority_map: hash of egress priority mappings
 *	@vlan_proto: VLAN encapsulation protocol
 *	@vlan_id: VLAN identifier
 *	@flags: device flags
 *	@real_dev: underlying netdevice
 *	@real_dev_addr: address of underlying netdevice
 *	@dent: proc dir entry
 *	@vlan_pcpu_stats: ptr to percpu rx stats
 */
struct vlan_dev_priv {
	unsigned int				nr_ingress_mappings;
	u32					ingress_priority_map[8];
	unsigned int				nr_egress_mappings;
	struct vlan_priority_tci_mapping	*egress_priority_map[16];

	__be16					vlan_proto;
	u16					vlan_id;
	u16					flags;

	struct net_device			*real_dev;
	unsigned char				real_dev_addr[ETH_ALEN];

	struct proc_dir_entry			*dent;
	struct vlan_pcpu_stats __percpu		*vlan_pcpu_stats;
#ifdef CONFIG_NET_POLL_CONTROLLER
	struct netpoll				*netpoll;
#endif
};

static inline struct vlan_dev_priv *vlan_dev_priv(const struct net_device *dev)
{
	return netdev_priv(dev);
}

static inline u16
vlan_dev_get_egress_qos_mask(struct net_device *dev, u32 skprio)
{
	struct vlan_priority_tci_mapping *mp;

	smp_rmb(); /* coupled with smp_wmb() in vlan_dev_set_egress_priority() */

	mp = vlan_dev_priv(dev)->egress_priority_map[(skprio & 0xF)];
	while (mp) {
		if (mp->priority == skprio) {
			return mp->vlan_qos; /* This should already be shifted
					      * to mask correctly with the
					      * VLAN's TCI */
		}
		mp = mp->next;
	}
	return 0;
}

188
extern bool vlan_do_receive(struct sk_buff **skb);
189
extern struct sk_buff *vlan_untag(struct sk_buff *skb);
190

191
192
extern int vlan_vid_add(struct net_device *dev, __be16 proto, u16 vid);
extern void vlan_vid_del(struct net_device *dev, __be16 proto, u16 vid);
193

194
195
196
197
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);
198
199

extern bool vlan_uses_dev(const struct net_device *dev);
200
#else
201
static inline struct net_device *
202
203
__vlan_find_dev_deep(struct net_device *real_dev,
		     __be16 vlan_proto, u16 vlan_id)
204
205
206
207
{
	return NULL;
}

208
209
210
211
212
213
214
215
216
217
218
219
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;
}

220
221
222
223
224
225
static inline __be16 vlan_dev_vlan_proto(const struct net_device *dev)
{
	BUG();
	return 0;
}

226
227
228
229
230
231
static inline u16 vlan_dev_get_egress_qos_mask(struct net_device *dev,
					       u32 skprio)
{
	return 0;
}

232
static inline bool vlan_do_receive(struct sk_buff **skb)
233
{
234
	return false;
235
}
Herbert Xu's avatar
Herbert Xu committed
236

237
static inline struct sk_buff *vlan_untag(struct sk_buff *skb)
238
239
240
{
	return skb;
}
241

242
static inline int vlan_vid_add(struct net_device *dev, __be16 proto, u16 vid)
243
244
245
246
{
	return 0;
}

247
static inline void vlan_vid_del(struct net_device *dev, __be16 proto, u16 vid)
248
249
{
}
250
251
252
253
254
255
256
257
258
259
260

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)
{
}
261
262
263
264
265

static inline bool vlan_uses_dev(const struct net_device *dev)
{
	return false;
}
266
#endif
Linus Torvalds's avatar
Linus Torvalds committed
267

268
269
270
271
272
static inline bool vlan_hw_offload_capable(netdev_features_t features,
					   __be16 proto)
{
	if (proto == htons(ETH_P_8021Q) && features & NETIF_F_HW_VLAN_CTAG_TX)
		return true;
273
274
	if (proto == htons(ETH_P_8021AD) && features & NETIF_F_HW_VLAN_STAG_TX)
		return true;
275
276
277
	return false;
}

Linus Torvalds's avatar
Linus Torvalds committed
278
/**
279
 * vlan_insert_tag - regular VLAN tag inserting
Linus Torvalds's avatar
Linus Torvalds committed
280
 * @skb: skbuff to tag
281
 * @vlan_proto: VLAN encapsulation protocol
282
 * @vlan_tci: VLAN TCI to insert
Linus Torvalds's avatar
Linus Torvalds committed
283
284
285
 *
 * 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.
286
 *
Linus Torvalds's avatar
Linus Torvalds committed
287
288
 * Following the skb_unshare() example, in case of error, the calling function
 * doesn't have to worry about freeing the original skb.
289
290
 *
 * Does not change skb->protocol so this function can be used during receive.
Linus Torvalds's avatar
Linus Torvalds committed
291
 */
292
293
static inline struct sk_buff *vlan_insert_tag(struct sk_buff *skb,
					      __be16 vlan_proto, u16 vlan_tci)
Linus Torvalds's avatar
Linus Torvalds committed
294
295
296
{
	struct vlan_ethhdr *veth;

297
	if (skb_cow_head(skb, VLAN_HLEN) < 0) {
298
		dev_kfree_skb_any(skb);
299
		return NULL;
Linus Torvalds's avatar
Linus Torvalds committed
300
301
302
303
	}
	veth = (struct vlan_ethhdr *)skb_push(skb, VLAN_HLEN);

	/* Move the mac addresses to the beginning of the new header. */
304
	memmove(skb->data, skb->data + VLAN_HLEN, 2 * ETH_ALEN);
305
	skb->mac_header -= VLAN_HLEN;
Linus Torvalds's avatar
Linus Torvalds committed
306
307

	/* first, the ethernet type */
308
	veth->h_vlan_proto = vlan_proto;
Linus Torvalds's avatar
Linus Torvalds committed
309

310
311
	/* now, the TCI */
	veth->h_vlan_TCI = htons(vlan_tci);
Linus Torvalds's avatar
Linus Torvalds committed
312

313
314
	return skb;
}
Linus Torvalds's avatar
Linus Torvalds committed
315

316
317
318
319
320
321
322
323
324
325
326
/**
 * __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.
 */
327
328
static inline struct sk_buff *__vlan_put_tag(struct sk_buff *skb,
					     __be16 vlan_proto, u16 vlan_tci)
329
{
330
	skb = vlan_insert_tag(skb, vlan_proto, vlan_tci);
331
	if (skb)
332
		skb->protocol = vlan_proto;
Linus Torvalds's avatar
Linus Torvalds committed
333
334
335
336
337
338
	return skb;
}

/**
 * __vlan_hwaccel_put_tag - hardware accelerated VLAN inserting
 * @skb: skbuff to tag
339
 * @vlan_proto: VLAN encapsulation protocol
340
 * @vlan_tci: VLAN TCI to insert
Linus Torvalds's avatar
Linus Torvalds committed
341
 *
342
 * Puts the VLAN TCI in @skb->vlan_tci and lets the device do the rest
Linus Torvalds's avatar
Linus Torvalds committed
343
 */
344
static inline struct sk_buff *__vlan_hwaccel_put_tag(struct sk_buff *skb,
345
						     __be16 vlan_proto,
346
						     u16 vlan_tci)
Linus Torvalds's avatar
Linus Torvalds committed
347
{
348
	skb->vlan_proto = vlan_proto;
349
	skb->vlan_tci = VLAN_TAG_PRESENT | vlan_tci;
Linus Torvalds's avatar
Linus Torvalds committed
350
351
352
353
354
355
	return skb;
}

/**
 * vlan_put_tag - inserts VLAN tag according to device features
 * @skb: skbuff to tag
356
 * @vlan_tci: VLAN TCI to insert
Linus Torvalds's avatar
Linus Torvalds committed
357
358
359
360
 *
 * Assumes skb->dev is the target that will xmit this frame.
 * Returns a VLAN tagged skb.
 */
361
362
static inline struct sk_buff *vlan_put_tag(struct sk_buff *skb,
					   __be16 vlan_proto, u16 vlan_tci)
Linus Torvalds's avatar
Linus Torvalds committed
363
{
364
365
	if (vlan_hw_offload_capable(skb->dev->features, vlan_proto)) {
		return __vlan_hwaccel_put_tag(skb, vlan_proto, vlan_tci);
Linus Torvalds's avatar
Linus Torvalds committed
366
	} else {
367
		return __vlan_put_tag(skb, vlan_proto, vlan_tci);
Linus Torvalds's avatar
Linus Torvalds committed
368
369
370
371
372
373
	}
}

/**
 * __vlan_get_tag - get the VLAN ID that is part of the payload
 * @skb: skbuff to query
374
375
 * @vlan_tci: buffer to store vlaue
 *
Linus Torvalds's avatar
Linus Torvalds committed
376
377
 * Returns error if the skb is not of VLAN type
 */
378
static inline int __vlan_get_tag(const struct sk_buff *skb, u16 *vlan_tci)
Linus Torvalds's avatar
Linus Torvalds committed
379
380
381
{
	struct vlan_ethhdr *veth = (struct vlan_ethhdr *)skb->data;

382
383
	if (veth->h_vlan_proto != htons(ETH_P_8021Q) &&
	    veth->h_vlan_proto != htons(ETH_P_8021AD))
Linus Torvalds's avatar
Linus Torvalds committed
384
385
		return -EINVAL;

386
	*vlan_tci = ntohs(veth->h_vlan_TCI);
Linus Torvalds's avatar
Linus Torvalds committed
387
388
389
390
391
392
	return 0;
}

/**
 * __vlan_hwaccel_get_tag - get the VLAN ID that is in @skb->cb[]
 * @skb: skbuff to query
393
394
 * @vlan_tci: buffer to store vlaue
 *
395
 * Returns error if @skb->vlan_tci is not set correctly
Linus Torvalds's avatar
Linus Torvalds committed
396
 */
397
static inline int __vlan_hwaccel_get_tag(const struct sk_buff *skb,
398
					 u16 *vlan_tci)
Linus Torvalds's avatar
Linus Torvalds committed
399
{
400
	if (vlan_tx_tag_present(skb)) {
401
		*vlan_tci = vlan_tx_tag_get(skb);
Linus Torvalds's avatar
Linus Torvalds committed
402
403
		return 0;
	} else {
404
		*vlan_tci = 0;
Linus Torvalds's avatar
Linus Torvalds committed
405
406
407
408
409
410
411
412
413
		return -EINVAL;
	}
}

#define HAVE_VLAN_GET_TAG

/**
 * vlan_get_tag - get the VLAN ID from the skb
 * @skb: skbuff to query
414
415
 * @vlan_tci: buffer to store vlaue
 *
Linus Torvalds's avatar
Linus Torvalds committed
416
417
 * Returns error if the skb is not VLAN tagged
 */
418
static inline int vlan_get_tag(const struct sk_buff *skb, u16 *vlan_tci)
Linus Torvalds's avatar
Linus Torvalds committed
419
{
420
	if (skb->dev->features & NETIF_F_HW_VLAN_CTAG_TX) {
421
		return __vlan_hwaccel_get_tag(skb, vlan_tci);
Linus Torvalds's avatar
Linus Torvalds committed
422
	} else {
423
		return __vlan_get_tag(skb, vlan_tci);
Linus Torvalds's avatar
Linus Torvalds committed
424
425
426
	}
}

427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
/**
 * 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;
}
452
453
454
455
456

static inline void vlan_set_encap_proto(struct sk_buff *skb,
					struct vlan_hdr *vhdr)
{
	__be16 proto;
457
	unsigned short *rawp;
458
459
460
461
462
463
464

	/*
	 * Was a VLAN packet, grab the encapsulated protocol, which the layer
	 * three protocols care about.
	 */

	proto = vhdr->h_vlan_encapsulated_proto;
Simon Horman's avatar
Simon Horman committed
465
	if (ntohs(proto) >= ETH_P_802_3_MIN) {
466
467
468
469
		skb->protocol = proto;
		return;
	}

470
471
	rawp = (unsigned short *)(vhdr + 1);
	if (*rawp == 0xFFFF)
472
473
474
475
476
477
478
479
480
481
482
483
484
485
		/*
		 * 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);
}
Linus Torvalds's avatar
Linus Torvalds committed
486
#endif /* !(_LINUX_IF_VLAN_H_) */