Deleted Added
full compact
if_vlan.c (152882) if_vlan.c (155051)
1/*-
2 * Copyright 1998 Massachusetts Institute of Technology
3 *
4 * Permission to use, copy, modify, and distribute this software and
5 * its documentation for any purpose and without fee is hereby
6 * granted, provided that both the above copyright notice and this
7 * permission notice appear in all copies, that both the above
8 * copyright notice and this permission notice appear in all

--- 12 unchanged lines hidden (view full) ---

21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
1/*-
2 * Copyright 1998 Massachusetts Institute of Technology
3 *
4 * Permission to use, copy, modify, and distribute this software and
5 * its documentation for any purpose and without fee is hereby
6 * granted, provided that both the above copyright notice and this
7 * permission notice appear in all copies, that both the above
8 * copyright notice and this permission notice appear in all

--- 12 unchanged lines hidden (view full) ---

21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $FreeBSD: head/sys/net/if_vlan.c 152882 2005-11-28 12:46:35Z glebius $
29 * $FreeBSD: head/sys/net/if_vlan.c 155051 2006-01-30 13:45:15Z glebius $
30 */
31
32/*
33 * if_vlan.c - pseudo-device driver for IEEE 802.1Q virtual LANs.
34 * Might be extended some day to also handle IEEE 802.1p priority
35 * tagging. This is sort of sneaky in the implementation, since
36 * we need to pretend to be enough of an Ethernet implementation
37 * to make arp work. The way we do this is by telling everyone
38 * that we are an Ethernet, and then catch the packets that
39 * ether_output() left on our output queue when it calls
40 * if_start(), rewrite them for use by the real outgoing interface,
41 * and ask it to send them.
42 */
43
44#include "opt_inet.h"
30 */
31
32/*
33 * if_vlan.c - pseudo-device driver for IEEE 802.1Q virtual LANs.
34 * Might be extended some day to also handle IEEE 802.1p priority
35 * tagging. This is sort of sneaky in the implementation, since
36 * we need to pretend to be enough of an Ethernet implementation
37 * to make arp work. The way we do this is by telling everyone
38 * that we are an Ethernet, and then catch the packets that
39 * ether_output() left on our output queue when it calls
40 * if_start(), rewrite them for use by the real outgoing interface,
41 * and ask it to send them.
42 */
43
44#include "opt_inet.h"
45#include "opt_vlan.h"
45
46#include <sys/param.h>
47#include <sys/kernel.h>
46
47#include <sys/param.h>
48#include <sys/kernel.h>
49#include <sys/lock.h>
48#include <sys/malloc.h>
49#include <sys/mbuf.h>
50#include <sys/module.h>
50#include <sys/malloc.h>
51#include <sys/mbuf.h>
52#include <sys/module.h>
53#include <sys/rwlock.h>
51#include <sys/queue.h>
52#include <sys/socket.h>
53#include <sys/sockio.h>
54#include <sys/sysctl.h>
55#include <sys/systm.h>
56
57#include <net/bpf.h>
58#include <net/ethernet.h>

--- 5 unchanged lines hidden (view full) ---

64#include <net/if_vlan_var.h>
65
66#ifdef INET
67#include <netinet/in.h>
68#include <netinet/if_ether.h>
69#endif
70
71#define VLANNAME "vlan"
54#include <sys/queue.h>
55#include <sys/socket.h>
56#include <sys/sockio.h>
57#include <sys/sysctl.h>
58#include <sys/systm.h>
59
60#include <net/bpf.h>
61#include <net/ethernet.h>

--- 5 unchanged lines hidden (view full) ---

67#include <net/if_vlan_var.h>
68
69#ifdef INET
70#include <netinet/in.h>
71#include <netinet/if_ether.h>
72#endif
73
74#define VLANNAME "vlan"
75#define VLAN_DEF_HWIDTH 4
72
76
77LIST_HEAD(ifvlanhead, ifvlan);
78
79struct ifvlantrunk {
80 struct ifnet *parent; /* parent interface of this trunk */
81 struct rwlock rw;
82#ifdef VLAN_ARRAY
83 struct ifvlan *vlans[EVL_VLID_MASK+1]; /* static table */
84#else
85 struct ifvlanhead *hash; /* dynamic hash-list table */
86 uint16_t hmask;
87 uint16_t hwidth;
88#endif
89 int refcnt;
90 LIST_ENTRY(ifvlantrunk) trunk_entry;
91};
92static LIST_HEAD(, ifvlantrunk) trunk_list;
93
73struct vlan_mc_entry {
74 struct ether_addr mc_addr;
75 SLIST_ENTRY(vlan_mc_entry) mc_entries;
76};
77
78struct ifvlan {
94struct vlan_mc_entry {
95 struct ether_addr mc_addr;
96 SLIST_ENTRY(vlan_mc_entry) mc_entries;
97};
98
99struct ifvlan {
100 struct ifvlantrunk *ifv_trunk;
79 struct ifnet *ifv_ifp;
101 struct ifnet *ifv_ifp;
80 struct ifnet *ifv_p; /* parent inteface of this vlan */
102#define TRUNK(ifv) ((ifv)->ifv_trunk)
103#define PARENT(ifv) ((ifv)->ifv_trunk->parent)
81 int ifv_pflags; /* special flags we have set on parent */
82 struct ifv_linkmib {
83 int ifvm_parent;
84 int ifvm_encaplen; /* encapsulation length */
85 int ifvm_mtufudge; /* MTU fudged by this much */
86 int ifvm_mintu; /* min transmission unit */
104 int ifv_pflags; /* special flags we have set on parent */
105 struct ifv_linkmib {
106 int ifvm_parent;
107 int ifvm_encaplen; /* encapsulation length */
108 int ifvm_mtufudge; /* MTU fudged by this much */
109 int ifvm_mintu; /* min transmission unit */
87 u_int16_t ifvm_proto; /* encapsulation ethertype */
88 u_int16_t ifvm_tag; /* tag to apply on packets leaving if */
110 uint16_t ifvm_proto; /* encapsulation ethertype */
111 uint16_t ifvm_tag; /* tag to apply on packets leaving if */
89 } ifv_mib;
112 } ifv_mib;
90 SLIST_HEAD(__vlan_mchead, vlan_mc_entry) vlan_mc_listhead;
113 SLIST_HEAD(__vlan_mchead, vlan_mc_entry) vlan_mc_listhead;
91 LIST_ENTRY(ifvlan) ifv_list;
92};
93#define ifv_tag ifv_mib.ifvm_tag
94#define ifv_encaplen ifv_mib.ifvm_encaplen
95#define ifv_mtufudge ifv_mib.ifvm_mtufudge
96#define ifv_mintu ifv_mib.ifvm_mintu
97
114 LIST_ENTRY(ifvlan) ifv_list;
115};
116#define ifv_tag ifv_mib.ifvm_tag
117#define ifv_encaplen ifv_mib.ifvm_encaplen
118#define ifv_mtufudge ifv_mib.ifvm_mtufudge
119#define ifv_mintu ifv_mib.ifvm_mintu
120
98/* Special flags we should propagate to parent */
121/* Special flags we should propagate to parent. */
99static struct {
100 int flag;
101 int (*func)(struct ifnet *, int);
102} vlan_pflags[] = {
103 {IFF_PROMISC, ifpromisc},
104 {IFF_ALLMULTI, if_allmulti},
105 {0, NULL}
106};
107
108SYSCTL_DECL(_net_link);
109SYSCTL_NODE(_net_link, IFT_L2VLAN, vlan, CTLFLAG_RW, 0, "IEEE 802.1Q VLAN");
110SYSCTL_NODE(_net_link_vlan, PF_LINK, link, CTLFLAG_RW, 0, "for consistency");
111
112static MALLOC_DEFINE(M_VLAN, VLANNAME, "802.1Q Virtual LAN Interface");
122static struct {
123 int flag;
124 int (*func)(struct ifnet *, int);
125} vlan_pflags[] = {
126 {IFF_PROMISC, ifpromisc},
127 {IFF_ALLMULTI, if_allmulti},
128 {0, NULL}
129};
130
131SYSCTL_DECL(_net_link);
132SYSCTL_NODE(_net_link, IFT_L2VLAN, vlan, CTLFLAG_RW, 0, "IEEE 802.1Q VLAN");
133SYSCTL_NODE(_net_link_vlan, PF_LINK, link, CTLFLAG_RW, 0, "for consistency");
134
135static MALLOC_DEFINE(M_VLAN, VLANNAME, "802.1Q Virtual LAN Interface");
113static LIST_HEAD(, ifvlan) ifv_list;
114
115/*
136
137/*
116 * Locking: one lock is used to guard both the ifv_list and modification
117 * to vlan data structures. We are rather conservative here; probably
118 * more than necessary.
138 * We have a global mutex, that is used to serialize configuration
139 * changes and isn't used in normal packet delivery.
140 *
141 * We also have a per-trunk rwlock, that is locked shared on packet
142 * processing and exclusive when configuration is changed.
143 *
144 * The VLAN_ARRAY substitutes the dynamic hash with a static array
145 * with 4096 entries. In theory this can give a boots in processing,
146 * however on practice it does not. Probably this is because array
147 * is too big to fit into CPU cache.
119 */
120static struct mtx ifv_mtx;
148 */
149static struct mtx ifv_mtx;
121#define VLAN_LOCK_INIT() mtx_init(&ifv_mtx, VLANNAME, NULL, MTX_DEF)
150#define VLAN_LOCK_INIT() mtx_init(&ifv_mtx, "vlan_global", NULL, MTX_DEF)
122#define VLAN_LOCK_DESTROY() mtx_destroy(&ifv_mtx)
123#define VLAN_LOCK_ASSERT() mtx_assert(&ifv_mtx, MA_OWNED)
151#define VLAN_LOCK_DESTROY() mtx_destroy(&ifv_mtx)
152#define VLAN_LOCK_ASSERT() mtx_assert(&ifv_mtx, MA_OWNED)
124#define VLAN_LOCK() mtx_lock(&ifv_mtx)
125#define VLAN_UNLOCK() mtx_unlock(&ifv_mtx)
153#define VLAN_LOCK() mtx_lock(&ifv_mtx)
154#define VLAN_UNLOCK() mtx_unlock(&ifv_mtx)
155#define TRUNK_LOCK_INIT(trunk) rw_init(&(trunk)->rw, VLANNAME)
156#define TRUNK_LOCK_DESTROY(trunk) rw_destroy(&(trunk)->rw)
157#define TRUNK_LOCK(trunk) rw_wlock(&(trunk)->rw)
158#define TRUNK_UNLOCK(trunk) rw_wunlock(&(trunk)->rw)
159#define TRUNK_LOCK_ASSERT(trunk) rw_assert(&(trunk)->rw, RA_WLOCKED)
160#define TRUNK_RLOCK(trunk) rw_rlock(&(trunk)->rw)
161#define TRUNK_RUNLOCK(trunk) rw_runlock(&(trunk)->rw)
162#define TRUNK_LOCK_RASSERT(trunk) rw_assert(&(trunk)->rw, RA_RLOCKED)
126
163
164#ifndef VLAN_ARRAY
165static void vlan_inithash(struct ifvlantrunk *trunk);
166static void vlan_freehash(struct ifvlantrunk *trunk);
167static int vlan_inshash(struct ifvlantrunk *trunk, struct ifvlan *ifv);
168static int vlan_remhash(struct ifvlantrunk *trunk, struct ifvlan *ifv);
169static void vlan_growhash(struct ifvlantrunk *trunk, int howmuch);
170static __inline struct ifvlan * vlan_gethash(struct ifvlantrunk *trunk,
171 uint16_t tag);
172#endif
173static void trunk_destroy(struct ifvlantrunk *trunk);
174
127static void vlan_start(struct ifnet *ifp);
128static void vlan_ifinit(void *foo);
129static void vlan_input(struct ifnet *ifp, struct mbuf *m);
130static int vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr);
131static int vlan_setflag(struct ifnet *ifp, int flag, int status,
132 int (*func)(struct ifnet *, int));
133static int vlan_setflags(struct ifnet *ifp, int status);
134static int vlan_setmulti(struct ifnet *ifp);
135static int vlan_unconfig(struct ifnet *ifp);
175static void vlan_start(struct ifnet *ifp);
176static void vlan_ifinit(void *foo);
177static void vlan_input(struct ifnet *ifp, struct mbuf *m);
178static int vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr);
179static int vlan_setflag(struct ifnet *ifp, int flag, int status,
180 int (*func)(struct ifnet *, int));
181static int vlan_setflags(struct ifnet *ifp, int status);
182static int vlan_setmulti(struct ifnet *ifp);
183static int vlan_unconfig(struct ifnet *ifp);
136static int vlan_config(struct ifvlan *ifv, struct ifnet *p);
184static int vlan_config(struct ifvlan *ifv, struct ifnet *p, uint16_t tag);
137static void vlan_link_state(struct ifnet *ifp, int link);
185static void vlan_link_state(struct ifnet *ifp, int link);
186static void vlan_capabilities(struct ifvlan *ifv);
187static void vlan_trunk_capabilities(struct ifnet *ifp);
138
139static struct ifnet *vlan_clone_match_ethertag(struct if_clone *,
140 const char *, int *);
141static int vlan_clone_match(struct if_clone *, const char *);
142static int vlan_clone_create(struct if_clone *, char *, size_t);
143static int vlan_clone_destroy(struct if_clone *, struct ifnet *);
144
145static struct if_clone vlan_cloner = IFC_CLONE_INITIALIZER(VLANNAME, NULL,
146 IF_MAXUNIT, NULL, vlan_clone_match, vlan_clone_create, vlan_clone_destroy);
147
188
189static struct ifnet *vlan_clone_match_ethertag(struct if_clone *,
190 const char *, int *);
191static int vlan_clone_match(struct if_clone *, const char *);
192static int vlan_clone_create(struct if_clone *, char *, size_t);
193static int vlan_clone_destroy(struct if_clone *, struct ifnet *);
194
195static struct if_clone vlan_cloner = IFC_CLONE_INITIALIZER(VLANNAME, NULL,
196 IF_MAXUNIT, NULL, vlan_clone_match, vlan_clone_create, vlan_clone_destroy);
197
198#ifndef VLAN_ARRAY
199#define HASH(n, m) ((((n) >> 8) ^ ((n) >> 4) ^ (n)) & (m))
200static void
201vlan_inithash(struct ifvlantrunk *trunk)
202{
203 int i, n;
204
205 /*
206 * The trunk must not be locked here since we call malloc(M_WAITOK).
207 * It is OK in case this function is called before the trunk struct
208 * gets hooked up and becomes visible from other threads.
209 */
210
211 KASSERT(trunk->hwidth == 0 && trunk->hash == NULL,
212 ("%s: hash already initialized", __func__));
213
214 trunk->hwidth = VLAN_DEF_HWIDTH;
215 n = 1 << trunk->hwidth;
216 trunk->hmask = n - 1;
217 trunk->hash = malloc(sizeof(struct ifvlanhead) * n, M_VLAN, M_WAITOK);
218 for (i = 0; i < n; i++)
219 LIST_INIT(&trunk->hash[i]);
220}
221
222static void
223vlan_freehash(struct ifvlantrunk *trunk)
224{
225#ifdef INVARIANTS
226 int i;
227
228 TRUNK_LOCK_ASSERT(trunk); /* XXX just unhook trunk first? */
229 KASSERT(trunk->hwidth > 0, ("%s: hwidth not positive", __func__));
230 for (i = 0; i < (1 << trunk->hwidth); i++)
231 KASSERT(LIST_EMPTY(&trunk->hash[i]),
232 ("%s: hash table not empty", __func__));
233#endif
234 free(trunk->hash, M_VLAN);
235 trunk->hash = NULL;
236 trunk->hwidth = trunk->hmask = 0;
237}
238
239static int
240vlan_inshash(struct ifvlantrunk *trunk, struct ifvlan *ifv)
241{
242 int i, b;
243 struct ifvlan *ifv2;
244
245 TRUNK_LOCK_ASSERT(trunk);
246 KASSERT(trunk->hwidth > 0, ("%s: hwidth not positive", __func__));
247
248 b = 1 << trunk->hwidth;
249 i = HASH(ifv->ifv_tag, trunk->hmask);
250 LIST_FOREACH(ifv2, &trunk->hash[i], ifv_list)
251 if (ifv->ifv_tag == ifv2->ifv_tag)
252 return (EEXIST);
253
254 /*
255 * Grow the hash when the number of vlans exceeds half of the number of
256 * hash buckets squared. This will make the average linked-list length
257 * buckets/2.
258 */
259 if (trunk->refcnt > (b * b) / 2) {
260 vlan_growhash(trunk, 1);
261 i = HASH(ifv->ifv_tag, trunk->hmask);
262 }
263 LIST_INSERT_HEAD(&trunk->hash[i], ifv, ifv_list);
264 trunk->refcnt++;
265
266 return (0);
267}
268
269static int
270vlan_remhash(struct ifvlantrunk *trunk, struct ifvlan *ifv)
271{
272 int i, b;
273 struct ifvlan *ifv2;
274
275 TRUNK_LOCK_ASSERT(trunk);
276 KASSERT(trunk->hwidth > 0, ("%s: hwidth not positive", __func__));
277
278 b = 1 << trunk->hwidth;
279 i = HASH(ifv->ifv_tag, trunk->hmask);
280 LIST_FOREACH(ifv2, &trunk->hash[i], ifv_list)
281 if (ifv2 == ifv) {
282 trunk->refcnt--;
283 LIST_REMOVE(ifv2, ifv_list);
284 if (trunk->refcnt < (b * b) / 2)
285 vlan_growhash(trunk, -1);
286 return (0);
287 }
288
289 panic("%s: vlan not found\n", __func__);
290 return (ENOENT); /*NOTREACHED*/
291}
292
148/*
293/*
294 * Grow the hash larger or smaller if memory permits.
295 */
296static void
297vlan_growhash(struct ifvlantrunk *trunk, int howmuch)
298{
299
300 struct ifvlan *ifv;
301 struct ifvlanhead *hash2;
302 int hwidth2, i, j, n, n2;
303
304 TRUNK_LOCK_ASSERT(trunk);
305 KASSERT(trunk->hwidth > 0, ("%s: hwidth not positive", __func__));
306
307 if (howmuch == 0) {
308 /* Harmless yet obvious coding error */
309 printf("%s: howmuch is 0\n", __func__);
310 return;
311 }
312
313 hwidth2 = trunk->hwidth + howmuch;
314 n = 1 << trunk->hwidth;
315 n2 = 1 << hwidth2;
316 /* Do not shrink the table below the default */
317 if (hwidth2 < VLAN_DEF_HWIDTH)
318 return;
319
320 /* M_NOWAIT because we're called with trunk mutex held */
321 hash2 = malloc(sizeof(struct ifvlanhead) * n2, M_VLAN, M_NOWAIT);
322 if (hash2 == NULL) {
323 printf("%s: out of memory -- hash size not changed\n",
324 __func__);
325 return; /* We can live with the old hash table */
326 }
327 for (j = 0; j < n2; j++)
328 LIST_INIT(&hash2[j]);
329 for (i = 0; i < n; i++)
330 while (!LIST_EMPTY(&trunk->hash[i])) {
331 ifv = LIST_FIRST(&trunk->hash[i]);
332 LIST_REMOVE(ifv, ifv_list);
333 j = HASH(ifv->ifv_tag, n2 - 1);
334 LIST_INSERT_HEAD(&hash2[j], ifv, ifv_list);
335 }
336 free(trunk->hash, M_VLAN);
337 trunk->hash = hash2;
338 trunk->hwidth = hwidth2;
339 trunk->hmask = n2 - 1;
340}
341
342static __inline struct ifvlan *
343vlan_gethash(struct ifvlantrunk *trunk, uint16_t tag)
344{
345 struct ifvlan *ifv;
346
347 TRUNK_LOCK_RASSERT(trunk);
348
349 LIST_FOREACH(ifv, &trunk->hash[HASH(tag, trunk->hmask)], ifv_list)
350 if (ifv->ifv_tag == tag)
351 return (ifv);
352 return (NULL);
353}
354
355#if 0
356/* Debugging code to view the hashtables. */
357static void
358vlan_dumphash(struct ifvlantrunk *trunk)
359{
360 int i;
361 struct ifvlan *ifv;
362
363 for (i = 0; i < (1 << trunk->hwidth); i++) {
364 printf("%d: ", i);
365 LIST_FOREACH(ifv, &trunk->hash[i], ifv_list)
366 printf("%s ", ifv->ifv_ifp->if_xname);
367 printf("\n");
368 }
369}
370#endif /* 0 */
371#endif /* !VLAN_ARRAY */
372
373static void
374trunk_destroy(struct ifvlantrunk *trunk)
375{
376 VLAN_LOCK_ASSERT();
377
378 TRUNK_LOCK(trunk);
379#ifndef VLAN_ARRAY
380 vlan_freehash(trunk);
381#endif
382 TRUNK_LOCK_DESTROY(trunk);
383 LIST_REMOVE(trunk, trunk_entry);
384 trunk->parent->if_vlantrunk = NULL;
385 free(trunk, M_VLAN);
386}
387
388/*
149 * Program our multicast filter. What we're actually doing is
150 * programming the multicast filter of the parent. This has the
151 * side effect of causing the parent interface to receive multicast
152 * traffic that it doesn't really want, which ends up being discarded
153 * later by the upper protocol layers. Unfortunately, there's no way
154 * to avoid this: there really is only one physical interface.
155 *
156 * XXX: There is a possible race here if more than one thread is

--- 8 unchanged lines hidden (view full) ---

165 struct vlan_mc_entry *mc = NULL;
166 struct sockaddr_dl sdl;
167 int error;
168
169 /*VLAN_LOCK_ASSERT();*/
170
171 /* Find the parent. */
172 sc = ifp->if_softc;
389 * Program our multicast filter. What we're actually doing is
390 * programming the multicast filter of the parent. This has the
391 * side effect of causing the parent interface to receive multicast
392 * traffic that it doesn't really want, which ends up being discarded
393 * later by the upper protocol layers. Unfortunately, there's no way
394 * to avoid this: there really is only one physical interface.
395 *
396 * XXX: There is a possible race here if more than one thread is

--- 8 unchanged lines hidden (view full) ---

405 struct vlan_mc_entry *mc = NULL;
406 struct sockaddr_dl sdl;
407 int error;
408
409 /*VLAN_LOCK_ASSERT();*/
410
411 /* Find the parent. */
412 sc = ifp->if_softc;
173 ifp_p = sc->ifv_p;
413 ifp_p = PARENT(sc);
174
414
175 /*
176 * If we don't have a parent, just remember the membership for
177 * when we do.
178 */
179 if (ifp_p == NULL)
180 return (0);
181
182 bzero((char *)&sdl, sizeof(sdl));
183 sdl.sdl_len = sizeof(sdl);
184 sdl.sdl_family = AF_LINK;
185 sdl.sdl_index = ifp_p->if_index;
186 sdl.sdl_type = IFT_ETHER;
187 sdl.sdl_alen = ETHER_ADDR_LEN;
188
189 /* First, remove any existing filter entries. */

--- 28 unchanged lines hidden (view full) ---

218}
219
220/*
221 * VLAN support can be loaded as a module. The only place in the
222 * system that's intimately aware of this is ether_input. We hook
223 * into this code through vlan_input_p which is defined there and
224 * set here. Noone else in the system should be aware of this so
225 * we use an explicit reference here.
415 bzero((char *)&sdl, sizeof(sdl));
416 sdl.sdl_len = sizeof(sdl);
417 sdl.sdl_family = AF_LINK;
418 sdl.sdl_index = ifp_p->if_index;
419 sdl.sdl_type = IFT_ETHER;
420 sdl.sdl_alen = ETHER_ADDR_LEN;
421
422 /* First, remove any existing filter entries. */

--- 28 unchanged lines hidden (view full) ---

451}
452
453/*
454 * VLAN support can be loaded as a module. The only place in the
455 * system that's intimately aware of this is ether_input. We hook
456 * into this code through vlan_input_p which is defined there and
457 * set here. Noone else in the system should be aware of this so
458 * we use an explicit reference here.
226 *
227 * NB: Noone should ever need to check if vlan_input_p is null or
228 * not. This is because interfaces have a count of the number
229 * of active vlans (if_nvlans) and this should never be bumped
230 * except by vlan_config--which is in this module so therefore
231 * the module must be loaded and vlan_input_p must be non-NULL.
232 */
233extern void (*vlan_input_p)(struct ifnet *, struct mbuf *);
234
235/* For if_link_state_change() eyes only... */
236extern void (*vlan_link_state_p)(struct ifnet *, int);
237
238static int
239vlan_modevent(module_t mod, int type, void *data)
240{
241
242 switch (type) {
243 case MOD_LOAD:
459 */
460extern void (*vlan_input_p)(struct ifnet *, struct mbuf *);
461
462/* For if_link_state_change() eyes only... */
463extern void (*vlan_link_state_p)(struct ifnet *, int);
464
465static int
466vlan_modevent(module_t mod, int type, void *data)
467{
468
469 switch (type) {
470 case MOD_LOAD:
244 LIST_INIT(&ifv_list);
471 LIST_INIT(&trunk_list);
245 VLAN_LOCK_INIT();
246 vlan_input_p = vlan_input;
247 vlan_link_state_p = vlan_link_state;
472 VLAN_LOCK_INIT();
473 vlan_input_p = vlan_input;
474 vlan_link_state_p = vlan_link_state;
475 vlan_trunk_cap_p = vlan_trunk_capabilities;
248 if_clone_attach(&vlan_cloner);
249 break;
250 case MOD_UNLOAD:
476 if_clone_attach(&vlan_cloner);
477 break;
478 case MOD_UNLOAD:
479 {
480 struct ifvlantrunk *trunk, *trunk1;
481
251 if_clone_detach(&vlan_cloner);
252 vlan_input_p = NULL;
253 vlan_link_state_p = NULL;
482 if_clone_detach(&vlan_cloner);
483 vlan_input_p = NULL;
484 vlan_link_state_p = NULL;
485 vlan_trunk_cap_p = NULL;
486 VLAN_LOCK();
487 LIST_FOREACH_SAFE(trunk, &trunk_list, trunk_entry, trunk1)
488 trunk_destroy(trunk);
489 VLAN_UNLOCK();
254 VLAN_LOCK_DESTROY();
255 break;
490 VLAN_LOCK_DESTROY();
491 break;
492 }
256 default:
257 return (EOPNOTSUPP);
258 }
259 return (0);
260}
261
262static moduledata_t vlan_mod = {
263 "if_vlan",

--- 128 unchanged lines hidden (view full) ---

392 ifp->if_ioctl = vlan_ioctl;
393 ifp->if_snd.ifq_maxlen = ifqmaxlen;
394 ether_ifattach(ifp, eaddr);
395 /* Now undo some of the damage... */
396 ifp->if_baudrate = 0;
397 ifp->if_type = IFT_L2VLAN;
398 ifp->if_hdrlen = ETHER_VLAN_ENCAP_LEN;
399
493 default:
494 return (EOPNOTSUPP);
495 }
496 return (0);
497}
498
499static moduledata_t vlan_mod = {
500 "if_vlan",

--- 128 unchanged lines hidden (view full) ---

629 ifp->if_ioctl = vlan_ioctl;
630 ifp->if_snd.ifq_maxlen = ifqmaxlen;
631 ether_ifattach(ifp, eaddr);
632 /* Now undo some of the damage... */
633 ifp->if_baudrate = 0;
634 ifp->if_type = IFT_L2VLAN;
635 ifp->if_hdrlen = ETHER_VLAN_ENCAP_LEN;
636
400 VLAN_LOCK();
401 LIST_INSERT_HEAD(&ifv_list, ifv, ifv_list);
402 VLAN_UNLOCK();
403
404 if (ethertag) {
637 if (ethertag) {
405 VLAN_LOCK();
406 error = vlan_config(ifv, p);
638 error = vlan_config(ifv, p, tag);
407 if (error != 0) {
408 /*
409 * Since we've partialy failed, we need to back
410 * out all the way, otherwise userland could get
411 * confused. Thus, we destroy the interface.
412 */
639 if (error != 0) {
640 /*
641 * Since we've partialy failed, we need to back
642 * out all the way, otherwise userland could get
643 * confused. Thus, we destroy the interface.
644 */
413 LIST_REMOVE(ifv, ifv_list);
414 vlan_unconfig(ifp);
645 vlan_unconfig(ifp);
415 VLAN_UNLOCK();
416 ether_ifdetach(ifp);
417 if_free_type(ifp, IFT_ETHER);
418 free(ifv, M_VLAN);
419
420 return (error);
421 }
646 ether_ifdetach(ifp);
647 if_free_type(ifp, IFT_ETHER);
648 free(ifv, M_VLAN);
649
650 return (error);
651 }
422 ifv->ifv_tag = tag;
423 ifp->if_drv_flags |= IFF_DRV_RUNNING;
652 ifp->if_drv_flags |= IFF_DRV_RUNNING;
424 VLAN_UNLOCK();
425
426 /* Update flags on the parent, if necessary. */
427 vlan_setflags(ifp, 1);
428 }
429
430 return (0);
431}
432
433static int
434vlan_clone_destroy(struct if_clone *ifc, struct ifnet *ifp)
435{
436 int unit;
437 struct ifvlan *ifv = ifp->if_softc;
438
439 unit = ifp->if_dunit;
440
653
654 /* Update flags on the parent, if necessary. */
655 vlan_setflags(ifp, 1);
656 }
657
658 return (0);
659}
660
661static int
662vlan_clone_destroy(struct if_clone *ifc, struct ifnet *ifp)
663{
664 int unit;
665 struct ifvlan *ifv = ifp->if_softc;
666
667 unit = ifp->if_dunit;
668
441 VLAN_LOCK();
442 LIST_REMOVE(ifv, ifv_list);
443 vlan_unconfig(ifp);
669 vlan_unconfig(ifp);
444 VLAN_UNLOCK();
445
446 ether_ifdetach(ifp);
447 if_free_type(ifp, IFT_ETHER);
448
449 free(ifv, M_VLAN);
450
451 ifc_free_unit(ifc, unit);
452

--- 17 unchanged lines hidden (view full) ---

470 * not called, the queue would never get emptied and
471 * interface would stall forever.
472 */
473static void
474vlan_start(struct ifnet *ifp)
475{
476 struct ifvlan *ifv;
477 struct ifnet *p;
670
671 ether_ifdetach(ifp);
672 if_free_type(ifp, IFT_ETHER);
673
674 free(ifv, M_VLAN);
675
676 ifc_free_unit(ifc, unit);
677

--- 17 unchanged lines hidden (view full) ---

695 * not called, the queue would never get emptied and
696 * interface would stall forever.
697 */
698static void
699vlan_start(struct ifnet *ifp)
700{
701 struct ifvlan *ifv;
702 struct ifnet *p;
478 struct ether_vlan_header *evl;
479 struct mbuf *m;
480 int error;
481
482 ifv = ifp->if_softc;
703 struct mbuf *m;
704 int error;
705
706 ifv = ifp->if_softc;
483 p = ifv->ifv_p;
707 p = PARENT(ifv);
484
485 for (;;) {
486 IF_DEQUEUE(&ifp->if_snd, m);
487 if (m == 0)
488 break;
489 BPF_MTAP(ifp, m);
490
491 /*

--- 10 unchanged lines hidden (view full) ---

502 /*
503 * If underlying interface can do VLAN tag insertion itself,
504 * just pass the packet along. However, we need some way to
505 * tell the interface where the packet came from so that it
506 * knows how to find the VLAN tag to use, so we attach a
507 * packet tag that holds it.
508 */
509 if (p->if_capenable & IFCAP_VLAN_HWTAGGING) {
708
709 for (;;) {
710 IF_DEQUEUE(&ifp->if_snd, m);
711 if (m == 0)
712 break;
713 BPF_MTAP(ifp, m);
714
715 /*

--- 10 unchanged lines hidden (view full) ---

726 /*
727 * If underlying interface can do VLAN tag insertion itself,
728 * just pass the packet along. However, we need some way to
729 * tell the interface where the packet came from so that it
730 * knows how to find the VLAN tag to use, so we attach a
731 * packet tag that holds it.
732 */
733 if (p->if_capenable & IFCAP_VLAN_HWTAGGING) {
510 struct m_tag *mtag = m_tag_alloc(MTAG_VLAN,
511 MTAG_VLAN_TAG,
512 sizeof(u_int),
513 M_NOWAIT);
734 struct m_tag *mtag = (struct m_tag *)
735 uma_zalloc(zone_mtag_vlan, M_NOWAIT);
514 if (mtag == NULL) {
515 ifp->if_oerrors++;
516 m_freem(m);
517 continue;
518 }
519 VLAN_TAG_VALUE(mtag) = ifv->ifv_tag;
520 m_tag_prepend(m, mtag);
521 m->m_flags |= M_VLANTAG;
522 } else {
736 if (mtag == NULL) {
737 ifp->if_oerrors++;
738 m_freem(m);
739 continue;
740 }
741 VLAN_TAG_VALUE(mtag) = ifv->ifv_tag;
742 m_tag_prepend(m, mtag);
743 m->m_flags |= M_VLANTAG;
744 } else {
745 struct ether_vlan_header *evl;
746
523 M_PREPEND(m, ifv->ifv_encaplen, M_DONTWAIT);
524 if (m == NULL) {
525 if_printf(ifp,
526 "unable to prepend VLAN header\n");
527 ifp->if_oerrors++;
528 continue;
529 }
530 /* M_PREPEND takes care of m_len, m_pkthdr.len for us */

--- 34 unchanged lines hidden (view full) ---

565 else
566 ifp->if_oerrors++;
567 }
568}
569
570static void
571vlan_input(struct ifnet *ifp, struct mbuf *m)
572{
747 M_PREPEND(m, ifv->ifv_encaplen, M_DONTWAIT);
748 if (m == NULL) {
749 if_printf(ifp,
750 "unable to prepend VLAN header\n");
751 ifp->if_oerrors++;
752 continue;
753 }
754 /* M_PREPEND takes care of m_len, m_pkthdr.len for us */

--- 34 unchanged lines hidden (view full) ---

789 else
790 ifp->if_oerrors++;
791 }
792}
793
794static void
795vlan_input(struct ifnet *ifp, struct mbuf *m)
796{
573 struct ether_vlan_header *evl;
797 struct ifvlantrunk *trunk = ifp->if_vlantrunk;
574 struct ifvlan *ifv;
575 struct m_tag *mtag;
798 struct ifvlan *ifv;
799 struct m_tag *mtag;
576 u_int tag;
800 uint16_t tag;
577
801
802 KASSERT(trunk != NULL, ("%s: no trunk", __func__));
803
578 if (m->m_flags & M_VLANTAG) {
579 /*
580 * Packet is tagged, but m contains a normal
581 * Ethernet frame; the tag is stored out-of-band.
582 */
583 mtag = m_tag_locate(m, MTAG_VLAN, MTAG_VLAN_TAG, NULL);
584 KASSERT(mtag != NULL,
585 ("%s: M_VLANTAG without m_tag", __func__));
586 tag = EVL_VLANOFTAG(VLAN_TAG_VALUE(mtag));
587 m_tag_delete(m, mtag);
588 m->m_flags &= ~M_VLANTAG;
589 } else {
804 if (m->m_flags & M_VLANTAG) {
805 /*
806 * Packet is tagged, but m contains a normal
807 * Ethernet frame; the tag is stored out-of-band.
808 */
809 mtag = m_tag_locate(m, MTAG_VLAN, MTAG_VLAN_TAG, NULL);
810 KASSERT(mtag != NULL,
811 ("%s: M_VLANTAG without m_tag", __func__));
812 tag = EVL_VLANOFTAG(VLAN_TAG_VALUE(mtag));
813 m_tag_delete(m, mtag);
814 m->m_flags &= ~M_VLANTAG;
815 } else {
816 struct ether_vlan_header *evl;
817
590 /*
591 * Packet is tagged in-band as specified by 802.1q.
592 */
593 mtag = NULL;
594 switch (ifp->if_type) {
595 case IFT_ETHER:
596 if (m->m_len < sizeof(*evl) &&
597 (m = m_pullup(m, sizeof(*evl))) == NULL) {

--- 10 unchanged lines hidden (view full) ---

608 /*
609 * Restore the original ethertype. We'll remove
610 * the encapsulation after we've found the vlan
611 * interface corresponding to the tag.
612 */
613 evl->evl_encap_proto = evl->evl_proto;
614 break;
615 default:
818 /*
819 * Packet is tagged in-band as specified by 802.1q.
820 */
821 mtag = NULL;
822 switch (ifp->if_type) {
823 case IFT_ETHER:
824 if (m->m_len < sizeof(*evl) &&
825 (m = m_pullup(m, sizeof(*evl))) == NULL) {

--- 10 unchanged lines hidden (view full) ---

836 /*
837 * Restore the original ethertype. We'll remove
838 * the encapsulation after we've found the vlan
839 * interface corresponding to the tag.
840 */
841 evl->evl_encap_proto = evl->evl_proto;
842 break;
843 default:
616 tag = (u_int) -1;
844 tag = (uint16_t) -1;
617#ifdef INVARIANTS
618 panic("%s: unsupported if_type (%u)",
619 __func__, ifp->if_type);
620#endif
621 break;
622 }
623 }
624
845#ifdef INVARIANTS
846 panic("%s: unsupported if_type (%u)",
847 __func__, ifp->if_type);
848#endif
849 break;
850 }
851 }
852
625 VLAN_LOCK();
626 LIST_FOREACH(ifv, &ifv_list, ifv_list)
627 if (ifp == ifv->ifv_p && tag == ifv->ifv_tag)
628 break;
629
853 /*
854 * In VLAN_ARRAY case we proceed completely lockless.
855 */
856#ifdef VLAN_ARRAY
857 ifv = trunk->vlans[tag];
630 if (ifv == NULL || (ifv->ifv_ifp->if_flags & IFF_UP) == 0) {
858 if (ifv == NULL || (ifv->ifv_ifp->if_flags & IFF_UP) == 0) {
631 VLAN_UNLOCK();
632 m_freem(m);
633 ifp->if_noproto++;
859 m_freem(m);
860 ifp->if_noproto++;
634#ifdef DEBUG
635 printf("%s: tag %d, no interface\n", __func__, tag);
636#endif
637 return;
638 }
861 return;
862 }
639 VLAN_UNLOCK(); /* XXX extend below? */
640#ifdef DEBUG
641 printf("%s: tag %d, parent %s\n", __func__, tag, ifv->ifv_p->if_xname);
863#else
864 TRUNK_RLOCK(trunk);
865 ifv = vlan_gethash(trunk, tag);
866 if (ifv == NULL || (ifv->ifv_ifp->if_flags & IFF_UP) == 0) {
867 TRUNK_RUNLOCK(trunk);
868 m_freem(m);
869 ifp->if_noproto++;
870 return;
871 }
872 TRUNK_RUNLOCK(trunk);
642#endif
643
644 if (mtag == NULL) {
645 /*
646 * Packet had an in-line encapsulation header;
647 * remove it. The original header has already
648 * been fixed up above.
649 */

--- 6 unchanged lines hidden (view full) ---

656 m->m_pkthdr.rcvif = ifv->ifv_ifp;
657 ifv->ifv_ifp->if_ipackets++;
658
659 /* Pass it back through the parent's input routine. */
660 (*ifp->if_input)(ifv->ifv_ifp, m);
661}
662
663static int
873#endif
874
875 if (mtag == NULL) {
876 /*
877 * Packet had an in-line encapsulation header;
878 * remove it. The original header has already
879 * been fixed up above.
880 */

--- 6 unchanged lines hidden (view full) ---

887 m->m_pkthdr.rcvif = ifv->ifv_ifp;
888 ifv->ifv_ifp->if_ipackets++;
889
890 /* Pass it back through the parent's input routine. */
891 (*ifp->if_input)(ifv->ifv_ifp, m);
892}
893
894static int
664vlan_config(struct ifvlan *ifv, struct ifnet *p)
895vlan_config(struct ifvlan *ifv, struct ifnet *p, uint16_t tag)
665{
896{
897 struct ifvlantrunk *trunk;
666 struct ifnet *ifp;
898 struct ifnet *ifp;
899 int error = 0;
667
900
668 VLAN_LOCK_ASSERT();
669
901 /* VID numbers 0x0 and 0xFFF are reserved */
902 if (tag == 0 || tag == 0xFFF)
903 return (EINVAL);
670 if (p->if_type != IFT_ETHER)
671 return (EPROTONOSUPPORT);
904 if (p->if_type != IFT_ETHER)
905 return (EPROTONOSUPPORT);
672 if (ifv->ifv_p)
906 if (ifv->ifv_trunk)
673 return (EBUSY);
674
907 return (EBUSY);
908
909 if (p->if_vlantrunk == NULL) {
910 trunk = malloc(sizeof(struct ifvlantrunk),
911 M_VLAN, M_WAITOK | M_ZERO);
912 VLAN_LOCK();
913 if (p->if_vlantrunk != NULL) {
914 /* A race that that is very unlikely to be hit. */
915 free(trunk, M_VLAN);
916 goto exists;
917 }
918#ifndef VLAN_ARRAY
919 vlan_inithash(trunk);
920#endif
921 TRUNK_LOCK_INIT(trunk);
922 LIST_INSERT_HEAD(&trunk_list, trunk, trunk_entry);
923 TRUNK_LOCK(trunk);
924 p->if_vlantrunk = trunk;
925 trunk->parent = p;
926 } else {
927 VLAN_LOCK();
928exists:
929 trunk = p->if_vlantrunk;
930 TRUNK_LOCK(trunk);
931 }
932
933 ifv->ifv_tag = tag;
934#ifdef VLAN_ARRAY
935 if (trunk->vlans[tag] != NULL)
936 error = EEXIST;
937#else
938 error = vlan_inshash(trunk, ifv);
939#endif
940 if (error)
941 goto done;
942
675 ifv->ifv_encaplen = ETHER_VLAN_ENCAP_LEN;
676 ifv->ifv_mintu = ETHERMIN;
677 ifv->ifv_pflags = 0;
678
679 /*
943 ifv->ifv_encaplen = ETHER_VLAN_ENCAP_LEN;
944 ifv->ifv_mintu = ETHERMIN;
945 ifv->ifv_pflags = 0;
946
947 /*
680 * The active VLAN counter on the parent is used
681 * at various places to see if there is a vlan(4)
682 * attached to this physical interface.
683 */
684 p->if_nvlans++;
685
686 /*
687 * If the parent supports the VLAN_MTU capability,
688 * i.e. can Tx/Rx larger than ETHER_MAX_LEN frames,
689 * use it.
690 */
691 if (p->if_capenable & IFCAP_VLAN_MTU) {
692 /*
693 * No need to fudge the MTU since the parent can
694 * handle extended frames.

--- 5 unchanged lines hidden (view full) ---

700 * makes us incompatible with strictly compliant
701 * 802.1Q implementations, but allows us to use
702 * the feature with other NetBSD implementations,
703 * which might still be useful.
704 */
705 ifv->ifv_mtufudge = ifv->ifv_encaplen;
706 }
707
948 * If the parent supports the VLAN_MTU capability,
949 * i.e. can Tx/Rx larger than ETHER_MAX_LEN frames,
950 * use it.
951 */
952 if (p->if_capenable & IFCAP_VLAN_MTU) {
953 /*
954 * No need to fudge the MTU since the parent can
955 * handle extended frames.

--- 5 unchanged lines hidden (view full) ---

961 * makes us incompatible with strictly compliant
962 * 802.1Q implementations, but allows us to use
963 * the feature with other NetBSD implementations,
964 * which might still be useful.
965 */
966 ifv->ifv_mtufudge = ifv->ifv_encaplen;
967 }
968
708 ifv->ifv_p = p;
969 ifv->ifv_trunk = trunk;
709 ifp = ifv->ifv_ifp;
710 ifp->if_mtu = p->if_mtu - ifv->ifv_mtufudge;
970 ifp = ifv->ifv_ifp;
971 ifp->if_mtu = p->if_mtu - ifv->ifv_mtufudge;
711 ifv->ifv_ifp->if_baudrate = p->if_baudrate;
972 ifp->if_baudrate = p->if_baudrate;
712 /*
713 * Copy only a selected subset of flags from the parent.
714 * Other flags are none of our business.
715 */
716#define VLAN_COPY_FLAGS \
717 (IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX | IFF_POINTOPOINT)
718 ifp->if_flags &= ~VLAN_COPY_FLAGS;
719 ifp->if_flags |= p->if_flags & VLAN_COPY_FLAGS;
720#undef VLAN_COPY_FLAGS
721
722 ifp->if_link_state = p->if_link_state;
723
973 /*
974 * Copy only a selected subset of flags from the parent.
975 * Other flags are none of our business.
976 */
977#define VLAN_COPY_FLAGS \
978 (IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX | IFF_POINTOPOINT)
979 ifp->if_flags &= ~VLAN_COPY_FLAGS;
980 ifp->if_flags |= p->if_flags & VLAN_COPY_FLAGS;
981#undef VLAN_COPY_FLAGS
982
983 ifp->if_link_state = p->if_link_state;
984
724#if 0
725 /*
726 * Not ready yet. We need notification from the parent
727 * when hw checksumming flags in its if_capenable change.
728 * Flags set in if_capabilities only are useless.
729 */
730 /*
731 * If the parent interface can do hardware-assisted
732 * VLAN encapsulation, then propagate its hardware-
733 * assisted checksumming flags.
734 */
735 if (p->if_capabilities & IFCAP_VLAN_HWTAGGING)
736 ifp->if_capabilities |= p->if_capabilities & IFCAP_HWCSUM;
737#endif
985 vlan_capabilities(ifv);
738
739 /*
740 * Set up our ``Ethernet address'' to reflect the underlying
741 * physical interface's.
742 */
743 bcopy(IF_LLADDR(p), IF_LLADDR(ifp), ETHER_ADDR_LEN);
744
745 /*
746 * Configure multicast addresses that may already be
747 * joined on the vlan device.
748 */
749 (void)vlan_setmulti(ifp); /* XXX: VLAN lock held */
750
986
987 /*
988 * Set up our ``Ethernet address'' to reflect the underlying
989 * physical interface's.
990 */
991 bcopy(IF_LLADDR(p), IF_LLADDR(ifp), ETHER_ADDR_LEN);
992
993 /*
994 * Configure multicast addresses that may already be
995 * joined on the vlan device.
996 */
997 (void)vlan_setmulti(ifp); /* XXX: VLAN lock held */
998
751 return (0);
999#ifdef VLAN_ARRAY
1000 atomic_store_rel_ptr((uintptr_t *)&trunk->vlans[tag], (uintptr_t)ifv);
1001 trunk->refcnt++;
1002#endif
1003done:
1004 TRUNK_UNLOCK(trunk);
1005 VLAN_UNLOCK();
1006
1007 return (error);
752}
753
754static int
755vlan_unconfig(struct ifnet *ifp)
756{
1008}
1009
1010static int
1011vlan_unconfig(struct ifnet *ifp)
1012{
1013 struct ifvlantrunk *trunk;
757 struct vlan_mc_entry *mc;
758 struct ifvlan *ifv;
1014 struct vlan_mc_entry *mc;
1015 struct ifvlan *ifv;
759 struct ifnet *p;
760 int error;
761
1016 int error;
1017
762 VLAN_LOCK_ASSERT();
1018 VLAN_LOCK();
763
764 ifv = ifp->if_softc;
1019
1020 ifv = ifp->if_softc;
765 p = ifv->ifv_p;
1021 trunk = ifv->ifv_trunk;
766
1022
767 if (p) {
1023 if (trunk) {
768 struct sockaddr_dl sdl;
1024 struct sockaddr_dl sdl;
1025 struct ifnet *p = trunk->parent;
769
1026
1027 TRUNK_LOCK(trunk);
1028#ifdef VLAN_ARRAY
1029 atomic_store_rel_ptr((uintptr_t *)&trunk->vlans[ifv->ifv_tag],
1030 (uintptr_t)NULL);
1031 trunk->refcnt--;
1032#endif
1033
770 /*
771 * Since the interface is being unconfigured, we need to
772 * empty the list of multicast groups that we may have joined
773 * while we were alive from the parent's list.
774 */
775 bzero((char *)&sdl, sizeof(sdl));
776 sdl.sdl_len = sizeof(sdl);
777 sdl.sdl_family = AF_LINK;

--- 8 unchanged lines hidden (view full) ---

786 error = if_delmulti(p, (struct sockaddr *)&sdl);
787 if (error)
788 return (error);
789 SLIST_REMOVE_HEAD(&ifv->vlan_mc_listhead, mc_entries);
790 free(mc, M_VLAN);
791 }
792
793 vlan_setflags(ifp, 0); /* clear special flags on parent */
1034 /*
1035 * Since the interface is being unconfigured, we need to
1036 * empty the list of multicast groups that we may have joined
1037 * while we were alive from the parent's list.
1038 */
1039 bzero((char *)&sdl, sizeof(sdl));
1040 sdl.sdl_len = sizeof(sdl);
1041 sdl.sdl_family = AF_LINK;

--- 8 unchanged lines hidden (view full) ---

1050 error = if_delmulti(p, (struct sockaddr *)&sdl);
1051 if (error)
1052 return (error);
1053 SLIST_REMOVE_HEAD(&ifv->vlan_mc_listhead, mc_entries);
1054 free(mc, M_VLAN);
1055 }
1056
1057 vlan_setflags(ifp, 0); /* clear special flags on parent */
794 p->if_nvlans--;
1058#ifndef VLAN_ARRAY
1059 vlan_remhash(trunk, ifv);
1060#endif
1061 ifv->ifv_trunk = NULL;
1062
1063 /*
1064 * Check if we were the last.
1065 */
1066 if (trunk->refcnt == 0) {
1067 atomic_store_rel_ptr((uintptr_t *)
1068 &trunk->parent->if_vlantrunk,
1069 (uintptr_t)NULL);
1070 /*
1071 * XXXGL: If some ithread has already entered
1072 * vlan_input() and is now blocked on the trunk
1073 * lock, then it should preempt us right after
1074 * unlock and finish its work. Then we will acquire
1075 * lock again in trunk_destroy().
1076 * XXX: not true in case of VLAN_ARRAY
1077 */
1078 TRUNK_UNLOCK(trunk);
1079 trunk_destroy(trunk);
1080 } else
1081 TRUNK_UNLOCK(trunk);
795 }
796
797 /* Disconnect from parent. */
798 if (ifv->ifv_pflags)
799 if_printf(ifp, "%s: ifv_pflags unclean\n", __func__);
1082 }
1083
1084 /* Disconnect from parent. */
1085 if (ifv->ifv_pflags)
1086 if_printf(ifp, "%s: ifv_pflags unclean\n", __func__);
800 ifv->ifv_p = NULL;
801 ifv->ifv_ifp->if_mtu = ETHERMTU; /* XXX why not 0? */
802 ifv->ifv_ifp->if_link_state = LINK_STATE_UNKNOWN;
803
804 /* Clear our MAC address. */
805 bzero(IF_LLADDR(ifv->ifv_ifp), ETHER_ADDR_LEN);
806
1087 ifv->ifv_ifp->if_mtu = ETHERMTU; /* XXX why not 0? */
1088 ifv->ifv_ifp->if_link_state = LINK_STATE_UNKNOWN;
1089
1090 /* Clear our MAC address. */
1091 bzero(IF_LLADDR(ifv->ifv_ifp), ETHER_ADDR_LEN);
1092
1093 VLAN_UNLOCK();
1094
807 return (0);
808}
809
810/* Handle a reference counted flag that should be set on the parent as well */
811static int
812vlan_setflag(struct ifnet *ifp, int flag, int status,
813 int (*func)(struct ifnet *, int))
814{

--- 11 unchanged lines hidden (view full) ---

826 * we want it to be. If it is, flip it. We record parent's
827 * status in ifv_pflags so that we won't clear parent's flag
828 * we haven't set. In fact, we don't clear or set parent's
829 * flags directly, but get or release references to them.
830 * That's why we can be sure that recorded flags still are
831 * in accord with actual parent's flags.
832 */
833 if (status != (ifv->ifv_pflags & flag)) {
1095 return (0);
1096}
1097
1098/* Handle a reference counted flag that should be set on the parent as well */
1099static int
1100vlan_setflag(struct ifnet *ifp, int flag, int status,
1101 int (*func)(struct ifnet *, int))
1102{

--- 11 unchanged lines hidden (view full) ---

1114 * we want it to be. If it is, flip it. We record parent's
1115 * status in ifv_pflags so that we won't clear parent's flag
1116 * we haven't set. In fact, we don't clear or set parent's
1117 * flags directly, but get or release references to them.
1118 * That's why we can be sure that recorded flags still are
1119 * in accord with actual parent's flags.
1120 */
1121 if (status != (ifv->ifv_pflags & flag)) {
834 error = (*func)(ifv->ifv_p, status);
1122 error = (*func)(PARENT(ifv), status);
835 if (error)
836 return (error);
837 ifv->ifv_pflags &= ~flag;
838 ifv->ifv_pflags |= status;
839 }
840 return (0);
841}
842

--- 15 unchanged lines hidden (view full) ---

858 }
859 return (0);
860}
861
862/* Inform all vlans that their parent has changed link state */
863static void
864vlan_link_state(struct ifnet *ifp, int link)
865{
1123 if (error)
1124 return (error);
1125 ifv->ifv_pflags &= ~flag;
1126 ifv->ifv_pflags |= status;
1127 }
1128 return (0);
1129}
1130

--- 15 unchanged lines hidden (view full) ---

1146 }
1147 return (0);
1148}
1149
1150/* Inform all vlans that their parent has changed link state */
1151static void
1152vlan_link_state(struct ifnet *ifp, int link)
1153{
1154 struct ifvlantrunk *trunk = ifp->if_vlantrunk;
866 struct ifvlan *ifv;
1155 struct ifvlan *ifv;
1156 int i;
867
1157
868 VLAN_LOCK();
869 LIST_FOREACH(ifv, &ifv_list, ifv_list) {
870 if (ifv->ifv_p == ifp)
1158 TRUNK_LOCK(trunk);
1159#ifdef VLAN_ARRAY
1160 for (i = 0; i < EVL_VLID_MASK+1; i++)
1161 if (trunk->vlans[i] != NULL) {
1162 ifv = trunk->vlans[i];
1163#else
1164 for (i = 0; i < (1 << trunk->hwidth); i++) {
1165 LIST_FOREACH(ifv, &trunk->hash[i], ifv_list)
1166#endif
871 if_link_state_change(ifv->ifv_ifp,
1167 if_link_state_change(ifv->ifv_ifp,
872 ifv->ifv_p->if_link_state);
1168 trunk->parent->if_link_state);
873 }
1169 }
874 VLAN_UNLOCK();
1170 TRUNK_UNLOCK(trunk);
875}
876
1171}
1172
1173static void
1174vlan_capabilities(struct ifvlan *ifv)
1175{
1176 struct ifnet *p = PARENT(ifv);
1177 struct ifnet *ifp = ifv->ifv_ifp;
1178
1179 TRUNK_LOCK_ASSERT(TRUNK(ifv));
1180
1181 /*
1182 * If the parent interface can do checksum offloading
1183 * on VLANs, then propagate its hardware-assisted
1184 * checksumming flags. Also assert that checksum
1185 * offloading requires hardware VLAN tagging.
1186 */
1187 if (p->if_capabilities & IFCAP_VLAN_HWCSUM)
1188 ifp->if_capabilities = p->if_capabilities & IFCAP_HWCSUM;
1189
1190 if (p->if_capenable & IFCAP_VLAN_HWCSUM &&
1191 p->if_capenable & IFCAP_VLAN_HWTAGGING) {
1192 ifp->if_capenable = p->if_capenable & IFCAP_HWCSUM;
1193 ifp->if_hwassist = p->if_hwassist;
1194 } else {
1195 ifp->if_capenable = 0;
1196 ifp->if_hwassist = 0;
1197 }
1198}
1199
1200static void
1201vlan_trunk_capabilities(struct ifnet *ifp)
1202{
1203 struct ifvlantrunk *trunk = ifp->if_vlantrunk;
1204 struct ifvlan *ifv;
1205 int i;
1206
1207 TRUNK_LOCK(trunk);
1208#ifdef VLAN_ARRAY
1209 for (i = 0; i < EVL_VLID_MASK+1; i++)
1210 if (trunk->vlans[i] != NULL) {
1211 ifv = trunk->vlans[i];
1212#else
1213 for (i = 0; i < (1 << trunk->hwidth); i++) {
1214 LIST_FOREACH(ifv, &trunk->hash[i], ifv_list)
1215#endif
1216 vlan_capabilities(ifv);
1217 }
1218 TRUNK_UNLOCK(trunk);
1219}
1220
877static int
878vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
879{
880 struct ifaddr *ifa;
881 struct ifnet *p;
882 struct ifreq *ifr;
883 struct ifvlan *ifv;
884 struct vlanreq vlr;

--- 25 unchanged lines hidden (view full) ---

910 sa = (struct sockaddr *) &ifr->ifr_data;
911 bcopy(IF_LLADDR(ifp), (caddr_t)sa->sa_data,
912 ETHER_ADDR_LEN);
913 }
914 break;
915
916 case SIOCGIFMEDIA:
917 VLAN_LOCK();
1221static int
1222vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1223{
1224 struct ifaddr *ifa;
1225 struct ifnet *p;
1226 struct ifreq *ifr;
1227 struct ifvlan *ifv;
1228 struct vlanreq vlr;

--- 25 unchanged lines hidden (view full) ---

1254 sa = (struct sockaddr *) &ifr->ifr_data;
1255 bcopy(IF_LLADDR(ifp), (caddr_t)sa->sa_data,
1256 ETHER_ADDR_LEN);
1257 }
1258 break;
1259
1260 case SIOCGIFMEDIA:
1261 VLAN_LOCK();
918 if (ifv->ifv_p != NULL) {
919 error = (*ifv->ifv_p->if_ioctl)(ifv->ifv_p,
1262 if (TRUNK(ifv) != NULL) {
1263 error = (*PARENT(ifv)->if_ioctl)(PARENT(ifv),
920 SIOCGIFMEDIA, data);
921 VLAN_UNLOCK();
922 /* Limit the result to the parent's current config. */
923 if (error == 0) {
924 struct ifmediareq *ifmr;
925
926 ifmr = (struct ifmediareq *)data;
927 if (ifmr->ifm_count >= 1 && ifmr->ifm_ulist) {

--- 13 unchanged lines hidden (view full) ---

941 error = EINVAL;
942 break;
943
944 case SIOCSIFMTU:
945 /*
946 * Set the interface MTU.
947 */
948 VLAN_LOCK();
1264 SIOCGIFMEDIA, data);
1265 VLAN_UNLOCK();
1266 /* Limit the result to the parent's current config. */
1267 if (error == 0) {
1268 struct ifmediareq *ifmr;
1269
1270 ifmr = (struct ifmediareq *)data;
1271 if (ifmr->ifm_count >= 1 && ifmr->ifm_ulist) {

--- 13 unchanged lines hidden (view full) ---

1285 error = EINVAL;
1286 break;
1287
1288 case SIOCSIFMTU:
1289 /*
1290 * Set the interface MTU.
1291 */
1292 VLAN_LOCK();
949 if (ifv->ifv_p != NULL) {
1293 if (TRUNK(ifv) != NULL) {
950 if (ifr->ifr_mtu >
1294 if (ifr->ifr_mtu >
951 (ifv->ifv_p->if_mtu - ifv->ifv_mtufudge) ||
1295 (PARENT(ifv)->if_mtu - ifv->ifv_mtufudge) ||
952 ifr->ifr_mtu <
953 (ifv->ifv_mintu - ifv->ifv_mtufudge))
954 error = EINVAL;
955 else
956 ifp->if_mtu = ifr->ifr_mtu;
957 } else
958 error = EINVAL;
959 VLAN_UNLOCK();

--- 20 unchanged lines hidden (view full) ---

980 /*
981 * Don't let the caller set up a VLAN tag with
982 * anything except VLID bits.
983 */
984 if (vlr.vlr_tag & ~EVL_VLID_MASK) {
985 error = EINVAL;
986 break;
987 }
1296 ifr->ifr_mtu <
1297 (ifv->ifv_mintu - ifv->ifv_mtufudge))
1298 error = EINVAL;
1299 else
1300 ifp->if_mtu = ifr->ifr_mtu;
1301 } else
1302 error = EINVAL;
1303 VLAN_UNLOCK();

--- 20 unchanged lines hidden (view full) ---

1324 /*
1325 * Don't let the caller set up a VLAN tag with
1326 * anything except VLID bits.
1327 */
1328 if (vlr.vlr_tag & ~EVL_VLID_MASK) {
1329 error = EINVAL;
1330 break;
1331 }
988 VLAN_LOCK();
989 error = vlan_config(ifv, p);
990 if (error) {
991 VLAN_UNLOCK();
1332 error = vlan_config(ifv, p, vlr.vlr_tag);
1333 if (error)
992 break;
1334 break;
993 }
994 ifv->ifv_tag = vlr.vlr_tag;
995 ifp->if_drv_flags |= IFF_DRV_RUNNING;
1335 ifp->if_drv_flags |= IFF_DRV_RUNNING;
996 VLAN_UNLOCK();
997
998 /* Update flags on the parent, if necessary. */
999 vlan_setflags(ifp, 1);
1000 break;
1001
1002 case SIOCGETVLAN:
1003 bzero(&vlr, sizeof(vlr));
1004 VLAN_LOCK();
1336
1337 /* Update flags on the parent, if necessary. */
1338 vlan_setflags(ifp, 1);
1339 break;
1340
1341 case SIOCGETVLAN:
1342 bzero(&vlr, sizeof(vlr));
1343 VLAN_LOCK();
1005 if (ifv->ifv_p) {
1006 strlcpy(vlr.vlr_parent, ifv->ifv_p->if_xname,
1344 if (TRUNK(ifv) != NULL) {
1345 strlcpy(vlr.vlr_parent, PARENT(ifv)->if_xname,
1007 sizeof(vlr.vlr_parent));
1008 vlr.vlr_tag = ifv->ifv_tag;
1009 }
1010 VLAN_UNLOCK();
1011 error = copyout(&vlr, ifr->ifr_data, sizeof(vlr));
1012 break;
1013
1014 case SIOCSIFFLAGS:
1015 /*
1016 * We should propagate selected flags to the parent,
1017 * e.g., promiscuous mode.
1018 */
1346 sizeof(vlr.vlr_parent));
1347 vlr.vlr_tag = ifv->ifv_tag;
1348 }
1349 VLAN_UNLOCK();
1350 error = copyout(&vlr, ifr->ifr_data, sizeof(vlr));
1351 break;
1352
1353 case SIOCSIFFLAGS:
1354 /*
1355 * We should propagate selected flags to the parent,
1356 * e.g., promiscuous mode.
1357 */
1019 if (ifv->ifv_p != NULL)
1358 if (TRUNK(ifv) != NULL)
1020 error = vlan_setflags(ifp, 1);
1021 break;
1022
1023 case SIOCADDMULTI:
1024 case SIOCDELMULTI:
1359 error = vlan_setflags(ifp, 1);
1360 break;
1361
1362 case SIOCADDMULTI:
1363 case SIOCDELMULTI:
1025 /*VLAN_LOCK();*/
1026 error = vlan_setmulti(ifp);
1027 /*VLAN_UNLOCK();*/
1364 /*
1365 * If we don't have a parent, just remember the membership for
1366 * when we do.
1367 */
1368 if (TRUNK(ifv) != NULL)
1369 error = vlan_setmulti(ifp);
1028 break;
1370 break;
1371
1029 default:
1030 error = EINVAL;
1031 }
1032
1033 return (error);
1034}
1372 default:
1373 error = EINVAL;
1374 }
1375
1376 return (error);
1377}