if_vlan.c revision 1.69.12.2 1 1.69.12.1 tls /* $NetBSD: if_vlan.c,v 1.69.12.2 2017/12/03 11:39:02 jdolecek Exp $ */
2 1.1 thorpej
3 1.1 thorpej /*-
4 1.31 thorpej * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
5 1.1 thorpej * All rights reserved.
6 1.1 thorpej *
7 1.1 thorpej * This code is derived from software contributed to The NetBSD Foundation
8 1.11 thorpej * by Andrew Doran, and by Jason R. Thorpe of Zembu Labs, Inc.
9 1.1 thorpej *
10 1.1 thorpej * Redistribution and use in source and binary forms, with or without
11 1.1 thorpej * modification, are permitted provided that the following conditions
12 1.1 thorpej * are met:
13 1.1 thorpej * 1. Redistributions of source code must retain the above copyright
14 1.1 thorpej * notice, this list of conditions and the following disclaimer.
15 1.1 thorpej * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 thorpej * notice, this list of conditions and the following disclaimer in the
17 1.1 thorpej * documentation and/or other materials provided with the distribution.
18 1.1 thorpej *
19 1.1 thorpej * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.1 thorpej * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.1 thorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.1 thorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.1 thorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.1 thorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.1 thorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.1 thorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.1 thorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.1 thorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.1 thorpej * POSSIBILITY OF SUCH DAMAGE.
30 1.1 thorpej */
31 1.1 thorpej
32 1.1 thorpej /*
33 1.1 thorpej * Copyright 1998 Massachusetts Institute of Technology
34 1.1 thorpej *
35 1.1 thorpej * Permission to use, copy, modify, and distribute this software and
36 1.1 thorpej * its documentation for any purpose and without fee is hereby
37 1.1 thorpej * granted, provided that both the above copyright notice and this
38 1.1 thorpej * permission notice appear in all copies, that both the above
39 1.1 thorpej * copyright notice and this permission notice appear in all
40 1.1 thorpej * supporting documentation, and that the name of M.I.T. not be used
41 1.1 thorpej * in advertising or publicity pertaining to distribution of the
42 1.1 thorpej * software without specific, written prior permission. M.I.T. makes
43 1.1 thorpej * no representations about the suitability of this software for any
44 1.1 thorpej * purpose. It is provided "as is" without express or implied
45 1.1 thorpej * warranty.
46 1.44 perry *
47 1.1 thorpej * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
48 1.1 thorpej * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
49 1.1 thorpej * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
50 1.1 thorpej * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
51 1.1 thorpej * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
52 1.1 thorpej * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
53 1.1 thorpej * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
54 1.1 thorpej * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
55 1.1 thorpej * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
56 1.1 thorpej * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
57 1.1 thorpej * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 1.1 thorpej * SUCH DAMAGE.
59 1.1 thorpej *
60 1.1 thorpej * from FreeBSD: if_vlan.c,v 1.16 2000/03/26 15:21:40 charnier Exp
61 1.1 thorpej * via OpenBSD: if_vlan.c,v 1.4 2000/05/15 19:15:00 chris Exp
62 1.1 thorpej */
63 1.1 thorpej
64 1.1 thorpej /*
65 1.1 thorpej * if_vlan.c - pseudo-device driver for IEEE 802.1Q virtual LANs. Might be
66 1.1 thorpej * extended some day to also handle IEEE 802.1P priority tagging. This is
67 1.1 thorpej * sort of sneaky in the implementation, since we need to pretend to be
68 1.1 thorpej * enough of an Ethernet implementation to make ARP work. The way we do
69 1.1 thorpej * this is by telling everyone that we are an Ethernet interface, and then
70 1.1 thorpej * catch the packets that ether_output() left on our output queue when it
71 1.1 thorpej * calls if_start(), rewrite them for use by the real outgoing interface,
72 1.1 thorpej * and ask it to send them.
73 1.1 thorpej *
74 1.1 thorpej * TODO:
75 1.1 thorpej *
76 1.1 thorpej * - Need some way to notify vlan interfaces when the parent
77 1.1 thorpej * interface changes MTU.
78 1.1 thorpej */
79 1.33 lukem
80 1.33 lukem #include <sys/cdefs.h>
81 1.69.12.1 tls __KERNEL_RCSID(0, "$NetBSD: if_vlan.c,v 1.69.12.2 2017/12/03 11:39:02 jdolecek Exp $");
82 1.1 thorpej
83 1.69.12.2 jdolecek #ifdef _KERNEL_OPT
84 1.1 thorpej #include "opt_inet.h"
85 1.69.12.2 jdolecek #endif
86 1.1 thorpej
87 1.1 thorpej #include <sys/param.h>
88 1.69.12.2 jdolecek #include <sys/systm.h>
89 1.1 thorpej #include <sys/kernel.h>
90 1.1 thorpej #include <sys/mbuf.h>
91 1.1 thorpej #include <sys/queue.h>
92 1.1 thorpej #include <sys/socket.h>
93 1.1 thorpej #include <sys/sockio.h>
94 1.1 thorpej #include <sys/systm.h>
95 1.1 thorpej #include <sys/proc.h>
96 1.48 elad #include <sys/kauth.h>
97 1.69.12.2 jdolecek #include <sys/mutex.h>
98 1.69.12.2 jdolecek #include <sys/kmem.h>
99 1.69.12.2 jdolecek #include <sys/cpu.h>
100 1.69.12.2 jdolecek #include <sys/pserialize.h>
101 1.69.12.2 jdolecek #include <sys/psref.h>
102 1.69.12.2 jdolecek #include <sys/pslist.h>
103 1.69.12.2 jdolecek #include <sys/atomic.h>
104 1.69.12.2 jdolecek #include <sys/device.h>
105 1.69.12.2 jdolecek #include <sys/module.h>
106 1.1 thorpej
107 1.1 thorpej #include <net/bpf.h>
108 1.1 thorpej #include <net/if.h>
109 1.1 thorpej #include <net/if_dl.h>
110 1.1 thorpej #include <net/if_types.h>
111 1.1 thorpej #include <net/if_ether.h>
112 1.1 thorpej #include <net/if_vlanvar.h>
113 1.1 thorpej
114 1.1 thorpej #ifdef INET
115 1.1 thorpej #include <netinet/in.h>
116 1.1 thorpej #include <netinet/if_inarp.h>
117 1.1 thorpej #endif
118 1.69.12.2 jdolecek #ifdef INET6
119 1.69.12.2 jdolecek #include <netinet6/in6_ifattach.h>
120 1.69.12.2 jdolecek #include <netinet6/in6_var.h>
121 1.69.12.2 jdolecek #endif
122 1.69.12.2 jdolecek
123 1.69.12.2 jdolecek #include "ioconf.h"
124 1.1 thorpej
125 1.10 thorpej struct vlan_mc_entry {
126 1.10 thorpej LIST_ENTRY(vlan_mc_entry) mc_entries;
127 1.10 thorpej /*
128 1.10 thorpej * A key to identify this entry. The mc_addr below can't be
129 1.10 thorpej * used since multiple sockaddr may mapped into the same
130 1.10 thorpej * ether_multi (e.g., AF_UNSPEC).
131 1.10 thorpej */
132 1.10 thorpej union {
133 1.10 thorpej struct ether_multi *mcu_enm;
134 1.10 thorpej } mc_u;
135 1.10 thorpej struct sockaddr_storage mc_addr;
136 1.10 thorpej };
137 1.10 thorpej
138 1.10 thorpej #define mc_enm mc_u.mcu_enm
139 1.10 thorpej
140 1.69.12.2 jdolecek
141 1.69.12.2 jdolecek struct ifvlan_linkmib {
142 1.69.12.2 jdolecek struct ifvlan *ifvm_ifvlan;
143 1.69.12.2 jdolecek const struct vlan_multisw *ifvm_msw;
144 1.69.12.2 jdolecek int ifvm_encaplen; /* encapsulation length */
145 1.69.12.2 jdolecek int ifvm_mtufudge; /* MTU fudged by this much */
146 1.69.12.2 jdolecek int ifvm_mintu; /* min transmission unit */
147 1.69.12.2 jdolecek uint16_t ifvm_proto; /* encapsulation ethertype */
148 1.69.12.2 jdolecek uint16_t ifvm_tag; /* tag to apply on packets */
149 1.69.12.2 jdolecek struct ifnet *ifvm_p; /* parent interface of this vlan */
150 1.69.12.2 jdolecek
151 1.69.12.2 jdolecek struct psref_target ifvm_psref;
152 1.69.12.2 jdolecek };
153 1.69.12.2 jdolecek
154 1.10 thorpej struct ifvlan {
155 1.10 thorpej union {
156 1.10 thorpej struct ethercom ifvu_ec;
157 1.10 thorpej } ifv_u;
158 1.69.12.2 jdolecek struct ifvlan_linkmib *ifv_mib; /*
159 1.69.12.2 jdolecek * reader must use vlan_getref_linkmib()
160 1.69.12.2 jdolecek * instead of direct dereference
161 1.69.12.2 jdolecek */
162 1.69.12.2 jdolecek kmutex_t ifv_lock; /* writer lock for ifv_mib */
163 1.69.12.2 jdolecek
164 1.10 thorpej LIST_HEAD(__vlan_mchead, vlan_mc_entry) ifv_mc_listhead;
165 1.10 thorpej LIST_ENTRY(ifvlan) ifv_list;
166 1.69.12.2 jdolecek struct pslist_entry ifv_hash;
167 1.17 thorpej int ifv_flags;
168 1.10 thorpej };
169 1.10 thorpej
170 1.17 thorpej #define IFVF_PROMISC 0x01 /* promiscuous mode enabled */
171 1.17 thorpej
172 1.10 thorpej #define ifv_ec ifv_u.ifvu_ec
173 1.10 thorpej
174 1.10 thorpej #define ifv_if ifv_ec.ec_if
175 1.10 thorpej
176 1.10 thorpej #define ifv_msw ifv_mib.ifvm_msw
177 1.10 thorpej #define ifv_encaplen ifv_mib.ifvm_encaplen
178 1.10 thorpej #define ifv_mtufudge ifv_mib.ifvm_mtufudge
179 1.10 thorpej #define ifv_mintu ifv_mib.ifvm_mintu
180 1.10 thorpej #define ifv_tag ifv_mib.ifvm_tag
181 1.10 thorpej
182 1.10 thorpej struct vlan_multisw {
183 1.10 thorpej int (*vmsw_addmulti)(struct ifvlan *, struct ifreq *);
184 1.10 thorpej int (*vmsw_delmulti)(struct ifvlan *, struct ifreq *);
185 1.10 thorpej void (*vmsw_purgemulti)(struct ifvlan *);
186 1.10 thorpej };
187 1.10 thorpej
188 1.10 thorpej static int vlan_ether_addmulti(struct ifvlan *, struct ifreq *);
189 1.10 thorpej static int vlan_ether_delmulti(struct ifvlan *, struct ifreq *);
190 1.10 thorpej static void vlan_ether_purgemulti(struct ifvlan *);
191 1.10 thorpej
192 1.10 thorpej const struct vlan_multisw vlan_ether_multisw = {
193 1.10 thorpej vlan_ether_addmulti,
194 1.10 thorpej vlan_ether_delmulti,
195 1.10 thorpej vlan_ether_purgemulti,
196 1.10 thorpej };
197 1.10 thorpej
198 1.1 thorpej static int vlan_clone_create(struct if_clone *, int);
199 1.42 peter static int vlan_clone_destroy(struct ifnet *);
200 1.69.12.2 jdolecek static int vlan_config(struct ifvlan *, struct ifnet *,
201 1.69.12.2 jdolecek uint16_t);
202 1.53 christos static int vlan_ioctl(struct ifnet *, u_long, void *);
203 1.1 thorpej static void vlan_start(struct ifnet *);
204 1.69.12.2 jdolecek static int vlan_transmit(struct ifnet *, struct mbuf *);
205 1.11 thorpej static void vlan_unconfig(struct ifnet *);
206 1.69.12.2 jdolecek static int vlan_unconfig_locked(struct ifvlan *,
207 1.69.12.2 jdolecek struct ifvlan_linkmib *);
208 1.69.12.2 jdolecek static void vlan_hash_init(void);
209 1.69.12.2 jdolecek static int vlan_hash_fini(void);
210 1.69.12.2 jdolecek static int vlan_tag_hash(uint16_t, u_long);
211 1.69.12.2 jdolecek static struct ifvlan_linkmib* vlan_getref_linkmib(struct ifvlan *,
212 1.69.12.2 jdolecek struct psref *);
213 1.69.12.2 jdolecek static void vlan_putref_linkmib(struct ifvlan_linkmib *,
214 1.69.12.2 jdolecek struct psref *);
215 1.69.12.2 jdolecek static void vlan_linkmib_update(struct ifvlan *,
216 1.69.12.2 jdolecek struct ifvlan_linkmib *);
217 1.69.12.2 jdolecek static struct ifvlan_linkmib* vlan_lookup_tag_psref(struct ifnet *,
218 1.69.12.2 jdolecek uint16_t, struct psref *);
219 1.69.12.2 jdolecek
220 1.69.12.2 jdolecek LIST_HEAD(vlan_ifvlist, ifvlan);
221 1.69.12.2 jdolecek static struct {
222 1.69.12.2 jdolecek kmutex_t lock;
223 1.69.12.2 jdolecek struct vlan_ifvlist list;
224 1.69.12.2 jdolecek } ifv_list __cacheline_aligned;
225 1.10 thorpej
226 1.1 thorpej
227 1.69.12.2 jdolecek #if !defined(VLAN_TAG_HASH_SIZE)
228 1.69.12.2 jdolecek #define VLAN_TAG_HASH_SIZE 32
229 1.69.12.2 jdolecek #endif
230 1.69.12.2 jdolecek static struct {
231 1.69.12.2 jdolecek kmutex_t lock;
232 1.69.12.2 jdolecek struct pslist_head *lists;
233 1.69.12.2 jdolecek u_long mask;
234 1.69.12.2 jdolecek } ifv_hash __cacheline_aligned = {
235 1.69.12.2 jdolecek .lists = NULL,
236 1.69.12.2 jdolecek .mask = 0,
237 1.69.12.2 jdolecek };
238 1.69.12.2 jdolecek
239 1.69.12.2 jdolecek pserialize_t vlan_psz __read_mostly;
240 1.69.12.2 jdolecek static struct psref_class *ifvm_psref_class __read_mostly;
241 1.1 thorpej
242 1.1 thorpej struct if_clone vlan_cloner =
243 1.1 thorpej IF_CLONE_INITIALIZER("vlan", vlan_clone_create, vlan_clone_destroy);
244 1.1 thorpej
245 1.38 scw /* Used to pad ethernet frames with < ETHER_MIN_LEN bytes */
246 1.38 scw static char vlan_zero_pad_buff[ETHER_MIN_LEN];
247 1.38 scw
248 1.69.12.2 jdolecek static inline int
249 1.69.12.2 jdolecek vlan_safe_ifpromisc(struct ifnet *ifp, int pswitch)
250 1.69.12.2 jdolecek {
251 1.69.12.2 jdolecek int e;
252 1.69.12.2 jdolecek KERNEL_LOCK_UNLESS_NET_MPSAFE();
253 1.69.12.2 jdolecek e = ifpromisc(ifp, pswitch);
254 1.69.12.2 jdolecek KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
255 1.69.12.2 jdolecek return e;
256 1.69.12.2 jdolecek }
257 1.69.12.2 jdolecek
258 1.1 thorpej void
259 1.52 christos vlanattach(int n)
260 1.1 thorpej {
261 1.1 thorpej
262 1.69.12.2 jdolecek /*
263 1.69.12.2 jdolecek * Nothing to do here, initialization is handled by the
264 1.69.12.2 jdolecek * module initialization code in vlaninit() below).
265 1.69.12.2 jdolecek */
266 1.69.12.2 jdolecek }
267 1.69.12.2 jdolecek
268 1.69.12.2 jdolecek static void
269 1.69.12.2 jdolecek vlaninit(void)
270 1.69.12.2 jdolecek {
271 1.69.12.2 jdolecek mutex_init(&ifv_list.lock, MUTEX_DEFAULT, IPL_NONE);
272 1.69.12.2 jdolecek LIST_INIT(&ifv_list.list);
273 1.69.12.2 jdolecek
274 1.69.12.2 jdolecek mutex_init(&ifv_hash.lock, MUTEX_DEFAULT, IPL_NONE);
275 1.69.12.2 jdolecek vlan_psz = pserialize_create();
276 1.69.12.2 jdolecek ifvm_psref_class = psref_class_create("vlanlinkmib", IPL_SOFTNET);
277 1.1 thorpej if_clone_attach(&vlan_cloner);
278 1.69.12.2 jdolecek
279 1.69.12.2 jdolecek vlan_hash_init();
280 1.69.12.2 jdolecek }
281 1.69.12.2 jdolecek
282 1.69.12.2 jdolecek static int
283 1.69.12.2 jdolecek vlandetach(void)
284 1.69.12.2 jdolecek {
285 1.69.12.2 jdolecek int error = 0;
286 1.69.12.2 jdolecek
287 1.69.12.2 jdolecek mutex_enter(&ifv_list.lock);
288 1.69.12.2 jdolecek if (!LIST_EMPTY(&ifv_list.list)) {
289 1.69.12.2 jdolecek mutex_exit(&ifv_list.lock);
290 1.69.12.2 jdolecek return EBUSY;
291 1.69.12.2 jdolecek }
292 1.69.12.2 jdolecek mutex_exit(&ifv_list.lock);
293 1.69.12.2 jdolecek
294 1.69.12.2 jdolecek error = vlan_hash_fini();
295 1.69.12.2 jdolecek if (error != 0)
296 1.69.12.2 jdolecek return error;
297 1.69.12.2 jdolecek
298 1.69.12.2 jdolecek if_clone_detach(&vlan_cloner);
299 1.69.12.2 jdolecek psref_class_destroy(ifvm_psref_class);
300 1.69.12.2 jdolecek pserialize_destroy(vlan_psz);
301 1.69.12.2 jdolecek mutex_destroy(&ifv_hash.lock);
302 1.69.12.2 jdolecek mutex_destroy(&ifv_list.lock);
303 1.69.12.2 jdolecek
304 1.69.12.2 jdolecek return 0;
305 1.1 thorpej }
306 1.1 thorpej
307 1.30 thorpej static void
308 1.30 thorpej vlan_reset_linkname(struct ifnet *ifp)
309 1.30 thorpej {
310 1.30 thorpej
311 1.30 thorpej /*
312 1.30 thorpej * We start out with a "802.1Q VLAN" type and zero-length
313 1.30 thorpej * addresses. When we attach to a parent interface, we
314 1.30 thorpej * inherit its type, address length, address, and data link
315 1.30 thorpej * type.
316 1.30 thorpej */
317 1.30 thorpej
318 1.30 thorpej ifp->if_type = IFT_L2VLAN;
319 1.30 thorpej ifp->if_addrlen = 0;
320 1.30 thorpej ifp->if_dlt = DLT_NULL;
321 1.30 thorpej if_alloc_sadl(ifp);
322 1.30 thorpej }
323 1.30 thorpej
324 1.1 thorpej static int
325 1.1 thorpej vlan_clone_create(struct if_clone *ifc, int unit)
326 1.1 thorpej {
327 1.1 thorpej struct ifvlan *ifv;
328 1.1 thorpej struct ifnet *ifp;
329 1.69.12.2 jdolecek struct ifvlan_linkmib *mib;
330 1.69.12.2 jdolecek int rv;
331 1.1 thorpej
332 1.59 christos ifv = malloc(sizeof(struct ifvlan), M_DEVBUF, M_WAITOK|M_ZERO);
333 1.69.12.2 jdolecek mib = kmem_zalloc(sizeof(struct ifvlan_linkmib), KM_SLEEP);
334 1.14 enami ifp = &ifv->ifv_if;
335 1.5 enami LIST_INIT(&ifv->ifv_mc_listhead);
336 1.11 thorpej
337 1.69.12.2 jdolecek mib->ifvm_ifvlan = ifv;
338 1.69.12.2 jdolecek mib->ifvm_p = NULL;
339 1.69.12.2 jdolecek psref_target_init(&mib->ifvm_psref, ifvm_psref_class);
340 1.69.12.2 jdolecek
341 1.69.12.2 jdolecek mutex_init(&ifv->ifv_lock, MUTEX_DEFAULT, IPL_NONE);
342 1.69.12.2 jdolecek ifv->ifv_mib = mib;
343 1.69.12.2 jdolecek
344 1.69.12.2 jdolecek mutex_enter(&ifv_list.lock);
345 1.69.12.2 jdolecek LIST_INSERT_HEAD(&ifv_list.list, ifv, ifv_list);
346 1.69.12.2 jdolecek mutex_exit(&ifv_list.lock);
347 1.1 thorpej
348 1.59 christos if_initname(ifp, ifc->ifc_name, unit);
349 1.1 thorpej ifp->if_softc = ifv;
350 1.1 thorpej ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
351 1.69.12.2 jdolecek ifp->if_extflags = IFEF_MPSAFE | IFEF_NO_LINK_STATE_CHANGE;
352 1.1 thorpej ifp->if_start = vlan_start;
353 1.69.12.2 jdolecek ifp->if_transmit = vlan_transmit;
354 1.1 thorpej ifp->if_ioctl = vlan_ioctl;
355 1.31 thorpej IFQ_SET_READY(&ifp->if_snd);
356 1.1 thorpej
357 1.69.12.2 jdolecek rv = if_initialize(ifp);
358 1.69.12.2 jdolecek if (rv != 0) {
359 1.69.12.2 jdolecek aprint_error("%s: if_initialize failed(%d)\n", ifp->if_xname,
360 1.69.12.2 jdolecek rv);
361 1.69.12.2 jdolecek goto fail;
362 1.69.12.2 jdolecek }
363 1.69.12.2 jdolecek
364 1.30 thorpej vlan_reset_linkname(ifp);
365 1.69.12.2 jdolecek if_register(ifp);
366 1.69.12.2 jdolecek return 0;
367 1.1 thorpej
368 1.69.12.2 jdolecek fail:
369 1.69.12.2 jdolecek mutex_enter(&ifv_list.lock);
370 1.69.12.2 jdolecek LIST_REMOVE(ifv, ifv_list);
371 1.69.12.2 jdolecek mutex_exit(&ifv_list.lock);
372 1.69.12.2 jdolecek
373 1.69.12.2 jdolecek mutex_destroy(&ifv->ifv_lock);
374 1.69.12.2 jdolecek psref_target_destroy(&ifv->ifv_mib->ifvm_psref, ifvm_psref_class);
375 1.69.12.2 jdolecek kmem_free(ifv->ifv_mib, sizeof(struct ifvlan_linkmib));
376 1.69.12.2 jdolecek free(ifv, M_DEVBUF);
377 1.69.12.2 jdolecek
378 1.69.12.2 jdolecek return rv;
379 1.1 thorpej }
380 1.1 thorpej
381 1.42 peter static int
382 1.1 thorpej vlan_clone_destroy(struct ifnet *ifp)
383 1.1 thorpej {
384 1.11 thorpej struct ifvlan *ifv = ifp->if_softc;
385 1.1 thorpej
386 1.69.12.2 jdolecek mutex_enter(&ifv_list.lock);
387 1.1 thorpej LIST_REMOVE(ifv, ifv_list);
388 1.69.12.2 jdolecek mutex_exit(&ifv_list.lock);
389 1.1 thorpej
390 1.69.12.2 jdolecek vlan_unconfig(ifp);
391 1.1 thorpej if_detach(ifp);
392 1.69.12.2 jdolecek
393 1.69.12.2 jdolecek psref_target_destroy(&ifv->ifv_mib->ifvm_psref, ifvm_psref_class);
394 1.69.12.2 jdolecek kmem_free(ifv->ifv_mib, sizeof(struct ifvlan_linkmib));
395 1.69.12.2 jdolecek mutex_destroy(&ifv->ifv_lock);
396 1.1 thorpej free(ifv, M_DEVBUF);
397 1.42 peter
398 1.42 peter return (0);
399 1.1 thorpej }
400 1.1 thorpej
401 1.11 thorpej /*
402 1.69.12.2 jdolecek * Configure a VLAN interface.
403 1.11 thorpej */
404 1.1 thorpej static int
405 1.69.12.2 jdolecek vlan_config(struct ifvlan *ifv, struct ifnet *p, uint16_t tag)
406 1.1 thorpej {
407 1.10 thorpej struct ifnet *ifp = &ifv->ifv_if;
408 1.69.12.2 jdolecek struct ifvlan_linkmib *nmib = NULL;
409 1.69.12.2 jdolecek struct ifvlan_linkmib *omib = NULL;
410 1.69.12.2 jdolecek struct ifvlan_linkmib *checkmib = NULL;
411 1.69.12.2 jdolecek struct psref_target *nmib_psref = NULL;
412 1.69.12.2 jdolecek uint16_t vid = EVL_VLANOFTAG(tag);
413 1.69.12.2 jdolecek int error = 0;
414 1.69.12.2 jdolecek int idx;
415 1.69.12.2 jdolecek bool omib_cleanup = false;
416 1.69.12.2 jdolecek struct psref psref;
417 1.69.12.2 jdolecek
418 1.69.12.2 jdolecek /* VLAN ID 0 and 4095 are reserved in the spec */
419 1.69.12.2 jdolecek if ((vid == 0) || (vid == 0xfff))
420 1.69.12.2 jdolecek return EINVAL;
421 1.69.12.2 jdolecek
422 1.69.12.2 jdolecek nmib = kmem_alloc(sizeof(*nmib), KM_SLEEP);
423 1.69.12.2 jdolecek
424 1.69.12.2 jdolecek mutex_enter(&ifv->ifv_lock);
425 1.69.12.2 jdolecek omib = ifv->ifv_mib;
426 1.69.12.2 jdolecek
427 1.69.12.2 jdolecek if (omib->ifvm_p != NULL) {
428 1.69.12.2 jdolecek error = EBUSY;
429 1.69.12.2 jdolecek goto done;
430 1.69.12.2 jdolecek }
431 1.69.12.2 jdolecek
432 1.69.12.2 jdolecek /* Duplicate check */
433 1.69.12.2 jdolecek checkmib = vlan_lookup_tag_psref(p, vid, &psref);
434 1.69.12.2 jdolecek if (checkmib != NULL) {
435 1.69.12.2 jdolecek vlan_putref_linkmib(checkmib, &psref);
436 1.69.12.2 jdolecek error = EEXIST;
437 1.69.12.2 jdolecek goto done;
438 1.69.12.2 jdolecek }
439 1.1 thorpej
440 1.69.12.2 jdolecek *nmib = *omib;
441 1.69.12.2 jdolecek nmib_psref = &nmib->ifvm_psref;
442 1.69.12.2 jdolecek
443 1.69.12.2 jdolecek psref_target_init(nmib_psref, ifvm_psref_class);
444 1.10 thorpej
445 1.10 thorpej switch (p->if_type) {
446 1.10 thorpej case IFT_ETHER:
447 1.10 thorpej {
448 1.10 thorpej struct ethercom *ec = (void *) p;
449 1.69.12.2 jdolecek nmib->ifvm_msw = &vlan_ether_multisw;
450 1.69.12.2 jdolecek nmib->ifvm_encaplen = ETHER_VLAN_ENCAP_LEN;
451 1.69.12.2 jdolecek nmib->ifvm_mintu = ETHERMIN;
452 1.10 thorpej
453 1.69.12.2 jdolecek if (ec->ec_nvlans++ == 0) {
454 1.69.12.2 jdolecek if ((error = ether_enable_vlan_mtu(p)) >= 0) {
455 1.10 thorpej if (error) {
456 1.69.12.2 jdolecek ec->ec_nvlans--;
457 1.69.12.2 jdolecek goto done;
458 1.10 thorpej }
459 1.69.12.2 jdolecek nmib->ifvm_mtufudge = 0;
460 1.69.12.2 jdolecek } else {
461 1.69.12.2 jdolecek /*
462 1.69.12.2 jdolecek * Fudge the MTU by the encapsulation size. This
463 1.69.12.2 jdolecek * makes us incompatible with strictly compliant
464 1.69.12.2 jdolecek * 802.1Q implementations, but allows us to use
465 1.69.12.2 jdolecek * the feature with other NetBSD
466 1.69.12.2 jdolecek * implementations, which might still be useful.
467 1.69.12.2 jdolecek */
468 1.69.12.2 jdolecek nmib->ifvm_mtufudge = nmib->ifvm_encaplen;
469 1.10 thorpej }
470 1.69.12.2 jdolecek error = 0;
471 1.10 thorpej }
472 1.10 thorpej
473 1.10 thorpej /*
474 1.32 thorpej * If the parent interface can do hardware-assisted
475 1.32 thorpej * VLAN encapsulation, then propagate its hardware-
476 1.63 darran * assisted checksumming flags and tcp segmentation
477 1.63 darran * offload.
478 1.32 thorpej */
479 1.67 sborrill if (ec->ec_capabilities & ETHERCAP_VLAN_HWTAGGING) {
480 1.67 sborrill ec->ec_capenable |= ETHERCAP_VLAN_HWTAGGING;
481 1.32 thorpej ifp->if_capabilities = p->if_capabilities &
482 1.65 darran (IFCAP_TSOv4 | IFCAP_TSOv6 |
483 1.63 darran IFCAP_CSUM_IPv4_Tx|IFCAP_CSUM_IPv4_Rx|
484 1.46 yamt IFCAP_CSUM_TCPv4_Tx|IFCAP_CSUM_TCPv4_Rx|
485 1.46 yamt IFCAP_CSUM_UDPv4_Tx|IFCAP_CSUM_UDPv4_Rx|
486 1.46 yamt IFCAP_CSUM_TCPv6_Tx|IFCAP_CSUM_TCPv6_Rx|
487 1.46 yamt IFCAP_CSUM_UDPv6_Tx|IFCAP_CSUM_UDPv6_Rx);
488 1.67 sborrill }
489 1.32 thorpej /*
490 1.10 thorpej * We inherit the parent's Ethernet address.
491 1.10 thorpej */
492 1.54 dyoung ether_ifattach(ifp, CLLADDR(p->if_sadl));
493 1.10 thorpej ifp->if_hdrlen = sizeof(struct ether_vlan_header); /* XXX? */
494 1.10 thorpej break;
495 1.10 thorpej }
496 1.10 thorpej
497 1.10 thorpej default:
498 1.69.12.2 jdolecek error = EPROTONOSUPPORT;
499 1.69.12.2 jdolecek goto done;
500 1.10 thorpej }
501 1.10 thorpej
502 1.69.12.2 jdolecek nmib->ifvm_p = p;
503 1.69.12.2 jdolecek nmib->ifvm_tag = vid;
504 1.69.12.2 jdolecek ifv->ifv_if.if_mtu = p->if_mtu - nmib->ifvm_mtufudge;
505 1.21 bouyer ifv->ifv_if.if_flags = p->if_flags &
506 1.23 bouyer (IFF_UP | IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
507 1.1 thorpej
508 1.1 thorpej /*
509 1.10 thorpej * Inherit the if_type from the parent. This allows us
510 1.10 thorpej * to participate in bridges of that type.
511 1.1 thorpej */
512 1.10 thorpej ifv->ifv_if.if_type = p->if_type;
513 1.10 thorpej
514 1.69.12.2 jdolecek PSLIST_ENTRY_INIT(ifv, ifv_hash);
515 1.69.12.2 jdolecek idx = vlan_tag_hash(vid, ifv_hash.mask);
516 1.69.12.2 jdolecek
517 1.69.12.2 jdolecek mutex_enter(&ifv_hash.lock);
518 1.69.12.2 jdolecek PSLIST_WRITER_INSERT_HEAD(&ifv_hash.lists[idx], ifv, ifv_hash);
519 1.69.12.2 jdolecek mutex_exit(&ifv_hash.lock);
520 1.69.12.2 jdolecek
521 1.69.12.2 jdolecek vlan_linkmib_update(ifv, nmib);
522 1.69.12.2 jdolecek nmib = NULL;
523 1.69.12.2 jdolecek nmib_psref = NULL;
524 1.69.12.2 jdolecek omib_cleanup = true;
525 1.69.12.2 jdolecek
526 1.69.12.2 jdolecek done:
527 1.69.12.2 jdolecek mutex_exit(&ifv->ifv_lock);
528 1.69.12.2 jdolecek
529 1.69.12.2 jdolecek if (nmib_psref)
530 1.69.12.2 jdolecek psref_target_destroy(nmib_psref, ifvm_psref_class);
531 1.69.12.2 jdolecek
532 1.69.12.2 jdolecek if (nmib)
533 1.69.12.2 jdolecek kmem_free(nmib, sizeof(*nmib));
534 1.69.12.2 jdolecek
535 1.69.12.2 jdolecek if (omib_cleanup)
536 1.69.12.2 jdolecek kmem_free(omib, sizeof(*omib));
537 1.69.12.2 jdolecek
538 1.69.12.2 jdolecek return error;
539 1.1 thorpej }
540 1.1 thorpej
541 1.11 thorpej /*
542 1.69.12.2 jdolecek * Unconfigure a VLAN interface.
543 1.11 thorpej */
544 1.11 thorpej static void
545 1.1 thorpej vlan_unconfig(struct ifnet *ifp)
546 1.1 thorpej {
547 1.10 thorpej struct ifvlan *ifv = ifp->if_softc;
548 1.69.12.2 jdolecek struct ifvlan_linkmib *nmib = NULL;
549 1.69.12.2 jdolecek int error;
550 1.1 thorpej
551 1.69.12.2 jdolecek nmib = kmem_alloc(sizeof(*nmib), KM_SLEEP);
552 1.69.12.2 jdolecek
553 1.69.12.2 jdolecek mutex_enter(&ifv->ifv_lock);
554 1.69.12.2 jdolecek error = vlan_unconfig_locked(ifv, nmib);
555 1.69.12.2 jdolecek mutex_exit(&ifv->ifv_lock);
556 1.69.12.2 jdolecek
557 1.69.12.2 jdolecek if (error)
558 1.69.12.2 jdolecek kmem_free(nmib, sizeof(*nmib));
559 1.69.12.2 jdolecek }
560 1.69.12.2 jdolecek static int
561 1.69.12.2 jdolecek vlan_unconfig_locked(struct ifvlan *ifv, struct ifvlan_linkmib *nmib)
562 1.69.12.2 jdolecek {
563 1.69.12.2 jdolecek struct ifnet *p;
564 1.69.12.2 jdolecek struct ifnet *ifp = &ifv->ifv_if;
565 1.69.12.2 jdolecek struct psref_target *nmib_psref = NULL;
566 1.69.12.2 jdolecek struct ifvlan_linkmib *omib;
567 1.69.12.2 jdolecek int error = 0;
568 1.69.12.2 jdolecek
569 1.69.12.2 jdolecek KASSERT(mutex_owned(&ifv->ifv_lock));
570 1.69.12.2 jdolecek
571 1.69.12.2 jdolecek omib = ifv->ifv_mib;
572 1.69.12.2 jdolecek p = omib->ifvm_p;
573 1.69.12.2 jdolecek
574 1.69.12.2 jdolecek if (p == NULL) {
575 1.69.12.2 jdolecek error = -1;
576 1.69.12.2 jdolecek goto done;
577 1.69.12.2 jdolecek }
578 1.69.12.2 jdolecek
579 1.69.12.2 jdolecek *nmib = *omib;
580 1.69.12.2 jdolecek nmib_psref = &nmib->ifvm_psref;
581 1.69.12.2 jdolecek psref_target_init(nmib_psref, ifvm_psref_class);
582 1.1 thorpej
583 1.1 thorpej /*
584 1.1 thorpej * Since the interface is being unconfigured, we need to empty the
585 1.1 thorpej * list of multicast groups that we may have joined while we were
586 1.1 thorpej * alive and remove them from the parent's list also.
587 1.1 thorpej */
588 1.69.12.2 jdolecek (*nmib->ifvm_msw->vmsw_purgemulti)(ifv);
589 1.1 thorpej
590 1.1 thorpej /* Disconnect from parent. */
591 1.69.12.2 jdolecek switch (p->if_type) {
592 1.10 thorpej case IFT_ETHER:
593 1.10 thorpej {
594 1.69.12.2 jdolecek struct ethercom *ec = (void *)p;
595 1.69.12.2 jdolecek if (--ec->ec_nvlans == 0)
596 1.69.12.2 jdolecek (void)ether_disable_vlan_mtu(p);
597 1.10 thorpej
598 1.10 thorpej ether_ifdetach(ifp);
599 1.69.12.2 jdolecek /* Restore vlan_ioctl overwritten by ether_ifdetach */
600 1.69.12.2 jdolecek ifp->if_ioctl = vlan_ioctl;
601 1.30 thorpej vlan_reset_linkname(ifp);
602 1.10 thorpej break;
603 1.10 thorpej }
604 1.10 thorpej
605 1.10 thorpej #ifdef DIAGNOSTIC
606 1.10 thorpej default:
607 1.10 thorpej panic("vlan_unconfig: impossible");
608 1.10 thorpej #endif
609 1.10 thorpej }
610 1.10 thorpej
611 1.69.12.2 jdolecek nmib->ifvm_p = NULL;
612 1.10 thorpej ifv->ifv_if.if_mtu = 0;
613 1.17 thorpej ifv->ifv_flags = 0;
614 1.1 thorpej
615 1.69.12.2 jdolecek mutex_enter(&ifv_hash.lock);
616 1.69.12.2 jdolecek PSLIST_WRITER_REMOVE(ifv, ifv_hash);
617 1.69.12.2 jdolecek pserialize_perform(vlan_psz);
618 1.69.12.2 jdolecek mutex_exit(&ifv_hash.lock);
619 1.69.12.2 jdolecek PSLIST_ENTRY_DESTROY(ifv, ifv_hash);
620 1.69.12.2 jdolecek
621 1.69.12.2 jdolecek vlan_linkmib_update(ifv, nmib);
622 1.69.12.2 jdolecek
623 1.69.12.2 jdolecek mutex_exit(&ifv->ifv_lock);
624 1.69.12.2 jdolecek
625 1.69.12.2 jdolecek nmib_psref = NULL;
626 1.69.12.2 jdolecek kmem_free(omib, sizeof(*omib));
627 1.69.12.2 jdolecek
628 1.69.12.2 jdolecek #ifdef INET6
629 1.69.12.2 jdolecek KERNEL_LOCK_UNLESS_NET_MPSAFE();
630 1.69.12.2 jdolecek /* To delete v6 link local addresses */
631 1.69.12.2 jdolecek if (in6_present)
632 1.69.12.2 jdolecek in6_ifdetach(ifp);
633 1.69.12.2 jdolecek KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
634 1.69.12.2 jdolecek #endif
635 1.69.12.2 jdolecek
636 1.69.12.2 jdolecek if ((ifp->if_flags & IFF_PROMISC) != 0)
637 1.69.12.2 jdolecek vlan_safe_ifpromisc(ifp, 0);
638 1.11 thorpej if_down(ifp);
639 1.11 thorpej ifp->if_flags &= ~(IFF_UP|IFF_RUNNING);
640 1.32 thorpej ifp->if_capabilities = 0;
641 1.69.12.2 jdolecek mutex_enter(&ifv->ifv_lock);
642 1.69.12.2 jdolecek done:
643 1.69.12.2 jdolecek
644 1.69.12.2 jdolecek if (nmib_psref)
645 1.69.12.2 jdolecek psref_target_destroy(nmib_psref, ifvm_psref_class);
646 1.69.12.2 jdolecek
647 1.69.12.2 jdolecek return error;
648 1.69.12.2 jdolecek }
649 1.69.12.2 jdolecek
650 1.69.12.2 jdolecek static void
651 1.69.12.2 jdolecek vlan_hash_init(void)
652 1.69.12.2 jdolecek {
653 1.69.12.2 jdolecek
654 1.69.12.2 jdolecek ifv_hash.lists = hashinit(VLAN_TAG_HASH_SIZE, HASH_PSLIST, true,
655 1.69.12.2 jdolecek &ifv_hash.mask);
656 1.69.12.2 jdolecek }
657 1.69.12.2 jdolecek
658 1.69.12.2 jdolecek static int
659 1.69.12.2 jdolecek vlan_hash_fini(void)
660 1.69.12.2 jdolecek {
661 1.69.12.2 jdolecek int i;
662 1.69.12.2 jdolecek
663 1.69.12.2 jdolecek mutex_enter(&ifv_hash.lock);
664 1.69.12.2 jdolecek
665 1.69.12.2 jdolecek for (i = 0; i < ifv_hash.mask + 1; i++) {
666 1.69.12.2 jdolecek if (PSLIST_WRITER_FIRST(&ifv_hash.lists[i], struct ifvlan,
667 1.69.12.2 jdolecek ifv_hash) != NULL) {
668 1.69.12.2 jdolecek mutex_exit(&ifv_hash.lock);
669 1.69.12.2 jdolecek return EBUSY;
670 1.69.12.2 jdolecek }
671 1.69.12.2 jdolecek }
672 1.69.12.2 jdolecek
673 1.69.12.2 jdolecek for (i = 0; i < ifv_hash.mask + 1; i++)
674 1.69.12.2 jdolecek PSLIST_DESTROY(&ifv_hash.lists[i]);
675 1.69.12.2 jdolecek
676 1.69.12.2 jdolecek mutex_exit(&ifv_hash.lock);
677 1.69.12.2 jdolecek
678 1.69.12.2 jdolecek hashdone(ifv_hash.lists, HASH_PSLIST, ifv_hash.mask);
679 1.69.12.2 jdolecek
680 1.69.12.2 jdolecek ifv_hash.lists = NULL;
681 1.69.12.2 jdolecek ifv_hash.mask = 0;
682 1.69.12.2 jdolecek
683 1.69.12.2 jdolecek return 0;
684 1.69.12.2 jdolecek }
685 1.69.12.2 jdolecek
686 1.69.12.2 jdolecek static int
687 1.69.12.2 jdolecek vlan_tag_hash(uint16_t tag, u_long mask)
688 1.69.12.2 jdolecek {
689 1.69.12.2 jdolecek uint32_t hash;
690 1.69.12.2 jdolecek
691 1.69.12.2 jdolecek hash = (tag >> 8) ^ tag;
692 1.69.12.2 jdolecek hash = (hash >> 2) ^ hash;
693 1.69.12.2 jdolecek
694 1.69.12.2 jdolecek return hash & mask;
695 1.69.12.2 jdolecek }
696 1.69.12.2 jdolecek
697 1.69.12.2 jdolecek static struct ifvlan_linkmib *
698 1.69.12.2 jdolecek vlan_getref_linkmib(struct ifvlan *sc, struct psref *psref)
699 1.69.12.2 jdolecek {
700 1.69.12.2 jdolecek struct ifvlan_linkmib *mib;
701 1.69.12.2 jdolecek int s;
702 1.69.12.2 jdolecek
703 1.69.12.2 jdolecek s = pserialize_read_enter();
704 1.69.12.2 jdolecek mib = sc->ifv_mib;
705 1.69.12.2 jdolecek if (mib == NULL) {
706 1.69.12.2 jdolecek pserialize_read_exit(s);
707 1.69.12.2 jdolecek return NULL;
708 1.69.12.2 jdolecek }
709 1.69.12.2 jdolecek membar_datadep_consumer();
710 1.69.12.2 jdolecek psref_acquire(psref, &mib->ifvm_psref, ifvm_psref_class);
711 1.69.12.2 jdolecek pserialize_read_exit(s);
712 1.69.12.2 jdolecek
713 1.69.12.2 jdolecek return mib;
714 1.69.12.2 jdolecek }
715 1.69.12.2 jdolecek
716 1.69.12.2 jdolecek static void
717 1.69.12.2 jdolecek vlan_putref_linkmib(struct ifvlan_linkmib *mib, struct psref *psref)
718 1.69.12.2 jdolecek {
719 1.69.12.2 jdolecek if (mib == NULL)
720 1.69.12.2 jdolecek return;
721 1.69.12.2 jdolecek psref_release(psref, &mib->ifvm_psref, ifvm_psref_class);
722 1.69.12.2 jdolecek }
723 1.69.12.2 jdolecek
724 1.69.12.2 jdolecek static struct ifvlan_linkmib *
725 1.69.12.2 jdolecek vlan_lookup_tag_psref(struct ifnet *ifp, uint16_t tag, struct psref *psref)
726 1.69.12.2 jdolecek {
727 1.69.12.2 jdolecek int idx;
728 1.69.12.2 jdolecek int s;
729 1.69.12.2 jdolecek struct ifvlan *sc;
730 1.69.12.2 jdolecek
731 1.69.12.2 jdolecek idx = vlan_tag_hash(tag, ifv_hash.mask);
732 1.69.12.2 jdolecek
733 1.69.12.2 jdolecek s = pserialize_read_enter();
734 1.69.12.2 jdolecek PSLIST_READER_FOREACH(sc, &ifv_hash.lists[idx], struct ifvlan,
735 1.69.12.2 jdolecek ifv_hash) {
736 1.69.12.2 jdolecek struct ifvlan_linkmib *mib = sc->ifv_mib;
737 1.69.12.2 jdolecek if (mib == NULL)
738 1.69.12.2 jdolecek continue;
739 1.69.12.2 jdolecek if (mib->ifvm_tag != tag)
740 1.69.12.2 jdolecek continue;
741 1.69.12.2 jdolecek if (mib->ifvm_p != ifp)
742 1.69.12.2 jdolecek continue;
743 1.69.12.2 jdolecek
744 1.69.12.2 jdolecek psref_acquire(psref, &mib->ifvm_psref, ifvm_psref_class);
745 1.69.12.2 jdolecek pserialize_read_exit(s);
746 1.69.12.2 jdolecek return mib;
747 1.69.12.2 jdolecek }
748 1.69.12.2 jdolecek pserialize_read_exit(s);
749 1.69.12.2 jdolecek return NULL;
750 1.69.12.2 jdolecek }
751 1.69.12.2 jdolecek
752 1.69.12.2 jdolecek static void
753 1.69.12.2 jdolecek vlan_linkmib_update(struct ifvlan *ifv, struct ifvlan_linkmib *nmib)
754 1.69.12.2 jdolecek {
755 1.69.12.2 jdolecek struct ifvlan_linkmib *omib = ifv->ifv_mib;
756 1.69.12.2 jdolecek
757 1.69.12.2 jdolecek KASSERT(mutex_owned(&ifv->ifv_lock));
758 1.69.12.2 jdolecek
759 1.69.12.2 jdolecek membar_producer();
760 1.69.12.2 jdolecek ifv->ifv_mib = nmib;
761 1.69.12.2 jdolecek
762 1.69.12.2 jdolecek pserialize_perform(vlan_psz);
763 1.69.12.2 jdolecek psref_target_destroy(&omib->ifvm_psref, ifvm_psref_class);
764 1.11 thorpej }
765 1.11 thorpej
766 1.11 thorpej /*
767 1.11 thorpej * Called when a parent interface is detaching; destroy any VLAN
768 1.11 thorpej * configuration for the parent interface.
769 1.11 thorpej */
770 1.11 thorpej void
771 1.11 thorpej vlan_ifdetach(struct ifnet *p)
772 1.11 thorpej {
773 1.11 thorpej struct ifvlan *ifv;
774 1.69.12.2 jdolecek struct ifvlan_linkmib *mib, **nmibs;
775 1.69.12.2 jdolecek struct psref psref;
776 1.69.12.2 jdolecek int error;
777 1.69.12.2 jdolecek int bound;
778 1.69.12.2 jdolecek int i, cnt = 0;
779 1.69.12.2 jdolecek
780 1.69.12.2 jdolecek bound = curlwp_bind();
781 1.69.12.2 jdolecek mutex_enter(&ifv_list.lock);
782 1.69.12.2 jdolecek LIST_FOREACH(ifv, &ifv_list.list, ifv_list) {
783 1.69.12.2 jdolecek mib = vlan_getref_linkmib(ifv, &psref);
784 1.69.12.2 jdolecek if (mib == NULL)
785 1.69.12.2 jdolecek continue;
786 1.11 thorpej
787 1.69.12.2 jdolecek if (mib->ifvm_p == p)
788 1.69.12.2 jdolecek cnt++;
789 1.69.12.2 jdolecek
790 1.69.12.2 jdolecek vlan_putref_linkmib(mib, &psref);
791 1.69.12.2 jdolecek }
792 1.69.12.2 jdolecek mutex_exit(&ifv_list.lock);
793 1.11 thorpej
794 1.69.12.2 jdolecek /*
795 1.69.12.2 jdolecek * The value of "cnt" does not increase while ifv_list.lock
796 1.69.12.2 jdolecek * and ifv->ifv_lock are released here, because the parent
797 1.69.12.2 jdolecek * interface is detaching.
798 1.69.12.2 jdolecek */
799 1.69.12.2 jdolecek nmibs = kmem_alloc(sizeof(*nmibs) * cnt, KM_SLEEP);
800 1.69.12.2 jdolecek for (i=0; i < cnt; i++) {
801 1.69.12.2 jdolecek nmibs[i] = kmem_alloc(sizeof(*nmibs[i]), KM_SLEEP);
802 1.11 thorpej }
803 1.11 thorpej
804 1.69.12.2 jdolecek mutex_enter(&ifv_list.lock);
805 1.69.12.2 jdolecek
806 1.69.12.2 jdolecek i = 0;
807 1.69.12.2 jdolecek LIST_FOREACH(ifv, &ifv_list.list, ifv_list) {
808 1.69.12.2 jdolecek mutex_enter(&ifv->ifv_lock);
809 1.69.12.2 jdolecek if (ifv->ifv_mib->ifvm_p == p) {
810 1.69.12.2 jdolecek KASSERTMSG(i < cnt, "no memory for unconfig, parent=%s",
811 1.69.12.2 jdolecek p->if_xname);
812 1.69.12.2 jdolecek error = vlan_unconfig_locked(ifv, nmibs[i]);
813 1.69.12.2 jdolecek if (!error) {
814 1.69.12.2 jdolecek nmibs[i] = NULL;
815 1.69.12.2 jdolecek i++;
816 1.69.12.2 jdolecek }
817 1.69.12.2 jdolecek
818 1.69.12.2 jdolecek }
819 1.69.12.2 jdolecek mutex_exit(&ifv->ifv_lock);
820 1.69.12.2 jdolecek }
821 1.69.12.2 jdolecek
822 1.69.12.2 jdolecek mutex_exit(&ifv_list.lock);
823 1.69.12.2 jdolecek curlwp_bindx(bound);
824 1.69.12.2 jdolecek
825 1.69.12.2 jdolecek for (i=0; i < cnt; i++) {
826 1.69.12.2 jdolecek if (nmibs[i])
827 1.69.12.2 jdolecek kmem_free(nmibs[i], sizeof(*nmibs[i]));
828 1.69.12.2 jdolecek }
829 1.69.12.2 jdolecek
830 1.69.12.2 jdolecek kmem_free(nmibs, sizeof(*nmibs) * cnt);
831 1.69.12.2 jdolecek
832 1.69.12.2 jdolecek return;
833 1.1 thorpej }
834 1.1 thorpej
835 1.1 thorpej static int
836 1.17 thorpej vlan_set_promisc(struct ifnet *ifp)
837 1.17 thorpej {
838 1.17 thorpej struct ifvlan *ifv = ifp->if_softc;
839 1.69.12.2 jdolecek struct ifvlan_linkmib *mib;
840 1.69.12.2 jdolecek struct psref psref;
841 1.20 enami int error = 0;
842 1.69.12.2 jdolecek int bound;
843 1.69.12.2 jdolecek
844 1.69.12.2 jdolecek bound = curlwp_bind();
845 1.69.12.2 jdolecek mib = vlan_getref_linkmib(ifv, &psref);
846 1.69.12.2 jdolecek if (mib == NULL) {
847 1.69.12.2 jdolecek curlwp_bindx(bound);
848 1.69.12.2 jdolecek return EBUSY;
849 1.69.12.2 jdolecek }
850 1.17 thorpej
851 1.17 thorpej if ((ifp->if_flags & IFF_PROMISC) != 0) {
852 1.17 thorpej if ((ifv->ifv_flags & IFVF_PROMISC) == 0) {
853 1.69.12.2 jdolecek error = vlan_safe_ifpromisc(mib->ifvm_p, 1);
854 1.17 thorpej if (error == 0)
855 1.17 thorpej ifv->ifv_flags |= IFVF_PROMISC;
856 1.17 thorpej }
857 1.17 thorpej } else {
858 1.17 thorpej if ((ifv->ifv_flags & IFVF_PROMISC) != 0) {
859 1.69.12.2 jdolecek error = vlan_safe_ifpromisc(mib->ifvm_p, 0);
860 1.17 thorpej if (error == 0)
861 1.17 thorpej ifv->ifv_flags &= ~IFVF_PROMISC;
862 1.17 thorpej }
863 1.17 thorpej }
864 1.69.12.2 jdolecek vlan_putref_linkmib(mib, &psref);
865 1.69.12.2 jdolecek curlwp_bindx(bound);
866 1.17 thorpej
867 1.17 thorpej return (error);
868 1.17 thorpej }
869 1.17 thorpej
870 1.17 thorpej static int
871 1.53 christos vlan_ioctl(struct ifnet *ifp, u_long cmd, void *data)
872 1.1 thorpej {
873 1.49 ad struct lwp *l = curlwp; /* XXX */
874 1.11 thorpej struct ifvlan *ifv = ifp->if_softc;
875 1.11 thorpej struct ifaddr *ifa = (struct ifaddr *) data;
876 1.11 thorpej struct ifreq *ifr = (struct ifreq *) data;
877 1.1 thorpej struct ifnet *pr;
878 1.60 bouyer struct ifcapreq *ifcr;
879 1.1 thorpej struct vlanreq vlr;
880 1.69.12.2 jdolecek struct ifvlan_linkmib *mib;
881 1.69.12.2 jdolecek struct psref psref;
882 1.69.12.2 jdolecek int error = 0;
883 1.69.12.2 jdolecek int bound;
884 1.1 thorpej
885 1.1 thorpej switch (cmd) {
886 1.1 thorpej case SIOCSIFMTU:
887 1.69.12.2 jdolecek bound = curlwp_bind();
888 1.69.12.2 jdolecek mib = vlan_getref_linkmib(ifv, &psref);
889 1.69.12.2 jdolecek if (mib == NULL) {
890 1.69.12.2 jdolecek curlwp_bindx(bound);
891 1.69.12.2 jdolecek error = EBUSY;
892 1.69.12.2 jdolecek break;
893 1.69.12.2 jdolecek }
894 1.69.12.2 jdolecek
895 1.69.12.2 jdolecek if (mib->ifvm_p == NULL) {
896 1.69.12.2 jdolecek vlan_putref_linkmib(mib, &psref);
897 1.69.12.2 jdolecek curlwp_bindx(bound);
898 1.56 dyoung error = EINVAL;
899 1.69.12.2 jdolecek } else if (
900 1.69.12.2 jdolecek ifr->ifr_mtu > (mib->ifvm_p->if_mtu - mib->ifvm_mtufudge) ||
901 1.69.12.2 jdolecek ifr->ifr_mtu < (mib->ifvm_mintu - mib->ifvm_mtufudge)) {
902 1.69.12.2 jdolecek vlan_putref_linkmib(mib, &psref);
903 1.69.12.2 jdolecek curlwp_bindx(bound);
904 1.1 thorpej error = EINVAL;
905 1.69.12.2 jdolecek } else {
906 1.69.12.2 jdolecek vlan_putref_linkmib(mib, &psref);
907 1.69.12.2 jdolecek curlwp_bindx(bound);
908 1.69.12.2 jdolecek
909 1.69.12.2 jdolecek error = ifioctl_common(ifp, cmd, data);
910 1.69.12.2 jdolecek if (error == ENETRESET)
911 1.69.12.2 jdolecek error = 0;
912 1.69.12.2 jdolecek }
913 1.69.12.2 jdolecek
914 1.1 thorpej break;
915 1.1 thorpej
916 1.1 thorpej case SIOCSETVLAN:
917 1.51 elad if ((error = kauth_authorize_network(l->l_cred,
918 1.51 elad KAUTH_NETWORK_INTERFACE,
919 1.51 elad KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, (void *)cmd,
920 1.51 elad NULL)) != 0)
921 1.1 thorpej break;
922 1.1 thorpej if ((error = copyin(ifr->ifr_data, &vlr, sizeof(vlr))) != 0)
923 1.1 thorpej break;
924 1.69.12.2 jdolecek
925 1.1 thorpej if (vlr.vlr_parent[0] == '\0') {
926 1.69.12.2 jdolecek bound = curlwp_bind();
927 1.69.12.2 jdolecek mib = vlan_getref_linkmib(ifv, &psref);
928 1.69.12.2 jdolecek if (mib == NULL) {
929 1.69.12.2 jdolecek curlwp_bindx(bound);
930 1.69.12.2 jdolecek error = EBUSY;
931 1.69.12.2 jdolecek break;
932 1.69.12.2 jdolecek }
933 1.69.12.2 jdolecek
934 1.69.12.2 jdolecek if (mib->ifvm_p != NULL &&
935 1.69.12.2 jdolecek (ifp->if_flags & IFF_PROMISC) != 0)
936 1.69.12.2 jdolecek error = vlan_safe_ifpromisc(mib->ifvm_p, 0);
937 1.69.12.2 jdolecek
938 1.69.12.2 jdolecek vlan_putref_linkmib(mib, &psref);
939 1.69.12.2 jdolecek curlwp_bindx(bound);
940 1.69.12.2 jdolecek
941 1.1 thorpej vlan_unconfig(ifp);
942 1.1 thorpej break;
943 1.1 thorpej }
944 1.1 thorpej if (vlr.vlr_tag != EVL_VLANOFTAG(vlr.vlr_tag)) {
945 1.1 thorpej error = EINVAL; /* check for valid tag */
946 1.1 thorpej break;
947 1.1 thorpej }
948 1.69.12.2 jdolecek if ((pr = ifunit(vlr.vlr_parent)) == NULL) {
949 1.1 thorpej error = ENOENT;
950 1.1 thorpej break;
951 1.1 thorpej }
952 1.69.12.2 jdolecek error = vlan_config(ifv, pr, vlr.vlr_tag);
953 1.69.12.2 jdolecek if (error != 0) {
954 1.1 thorpej break;
955 1.69.12.2 jdolecek }
956 1.1 thorpej ifp->if_flags |= IFF_RUNNING;
957 1.17 thorpej
958 1.17 thorpej /* Update promiscuous mode, if necessary. */
959 1.17 thorpej vlan_set_promisc(ifp);
960 1.1 thorpej break;
961 1.1 thorpej
962 1.1 thorpej case SIOCGETVLAN:
963 1.1 thorpej memset(&vlr, 0, sizeof(vlr));
964 1.69.12.2 jdolecek bound = curlwp_bind();
965 1.69.12.2 jdolecek mib = vlan_getref_linkmib(ifv, &psref);
966 1.69.12.2 jdolecek if (mib == NULL) {
967 1.69.12.2 jdolecek curlwp_bindx(bound);
968 1.69.12.2 jdolecek error = EBUSY;
969 1.69.12.2 jdolecek break;
970 1.69.12.2 jdolecek }
971 1.69.12.2 jdolecek if (mib->ifvm_p != NULL) {
972 1.1 thorpej snprintf(vlr.vlr_parent, sizeof(vlr.vlr_parent), "%s",
973 1.69.12.2 jdolecek mib->ifvm_p->if_xname);
974 1.69.12.2 jdolecek vlr.vlr_tag = mib->ifvm_tag;
975 1.1 thorpej }
976 1.69.12.2 jdolecek vlan_putref_linkmib(mib, &psref);
977 1.69.12.2 jdolecek curlwp_bindx(bound);
978 1.1 thorpej error = copyout(&vlr, ifr->ifr_data, sizeof(vlr));
979 1.1 thorpej break;
980 1.1 thorpej
981 1.1 thorpej case SIOCSIFFLAGS:
982 1.61 dyoung if ((error = ifioctl_common(ifp, cmd, data)) != 0)
983 1.61 dyoung break;
984 1.1 thorpej /*
985 1.17 thorpej * For promiscuous mode, we enable promiscuous mode on
986 1.17 thorpej * the parent if we need promiscuous on the VLAN interface.
987 1.1 thorpej */
988 1.69.12.2 jdolecek bound = curlwp_bind();
989 1.69.12.2 jdolecek mib = vlan_getref_linkmib(ifv, &psref);
990 1.69.12.2 jdolecek if (mib == NULL) {
991 1.69.12.2 jdolecek curlwp_bindx(bound);
992 1.69.12.2 jdolecek error = EBUSY;
993 1.69.12.2 jdolecek break;
994 1.69.12.2 jdolecek }
995 1.69.12.2 jdolecek
996 1.69.12.2 jdolecek if (mib->ifvm_p != NULL)
997 1.17 thorpej error = vlan_set_promisc(ifp);
998 1.69.12.2 jdolecek vlan_putref_linkmib(mib, &psref);
999 1.69.12.2 jdolecek curlwp_bindx(bound);
1000 1.1 thorpej break;
1001 1.1 thorpej
1002 1.1 thorpej case SIOCADDMULTI:
1003 1.69.12.2 jdolecek mutex_enter(&ifv->ifv_lock);
1004 1.69.12.2 jdolecek mib = ifv->ifv_mib;
1005 1.69.12.2 jdolecek if (mib == NULL) {
1006 1.69.12.2 jdolecek error = EBUSY;
1007 1.69.12.2 jdolecek mutex_exit(&ifv->ifv_lock);
1008 1.69.12.2 jdolecek break;
1009 1.69.12.2 jdolecek }
1010 1.69.12.2 jdolecek
1011 1.69.12.2 jdolecek error = (mib->ifvm_p != NULL) ?
1012 1.69.12.2 jdolecek (*mib->ifvm_msw->vmsw_addmulti)(ifv, ifr) : EINVAL;
1013 1.69.12.2 jdolecek mib = NULL;
1014 1.69.12.2 jdolecek mutex_exit(&ifv->ifv_lock);
1015 1.6 enami break;
1016 1.6 enami
1017 1.1 thorpej case SIOCDELMULTI:
1018 1.69.12.2 jdolecek mutex_enter(&ifv->ifv_lock);
1019 1.69.12.2 jdolecek mib = ifv->ifv_mib;
1020 1.69.12.2 jdolecek if (mib == NULL) {
1021 1.69.12.2 jdolecek error = EBUSY;
1022 1.69.12.2 jdolecek mutex_exit(&ifv->ifv_lock);
1023 1.69.12.2 jdolecek break;
1024 1.69.12.2 jdolecek }
1025 1.69.12.2 jdolecek error = (mib->ifvm_p != NULL) ?
1026 1.69.12.2 jdolecek (*mib->ifvm_msw->vmsw_delmulti)(ifv, ifr) : EINVAL;
1027 1.69.12.2 jdolecek mib = NULL;
1028 1.69.12.2 jdolecek mutex_exit(&ifv->ifv_lock);
1029 1.1 thorpej break;
1030 1.1 thorpej
1031 1.60 bouyer case SIOCSIFCAP:
1032 1.60 bouyer ifcr = data;
1033 1.60 bouyer /* make sure caps are enabled on parent */
1034 1.69.12.2 jdolecek bound = curlwp_bind();
1035 1.69.12.2 jdolecek mib = vlan_getref_linkmib(ifv, &psref);
1036 1.69.12.2 jdolecek if (mib == NULL) {
1037 1.69.12.2 jdolecek curlwp_bindx(bound);
1038 1.69.12.2 jdolecek error = EBUSY;
1039 1.69.12.2 jdolecek break;
1040 1.69.12.2 jdolecek }
1041 1.69.12.2 jdolecek
1042 1.69.12.2 jdolecek if (mib->ifvm_p == NULL) {
1043 1.69.12.2 jdolecek vlan_putref_linkmib(mib, &psref);
1044 1.69.12.2 jdolecek curlwp_bindx(bound);
1045 1.69.12.2 jdolecek error = EINVAL;
1046 1.69.12.2 jdolecek break;
1047 1.69.12.2 jdolecek }
1048 1.69.12.2 jdolecek if ((mib->ifvm_p->if_capenable & ifcr->ifcr_capenable) !=
1049 1.60 bouyer ifcr->ifcr_capenable) {
1050 1.69.12.2 jdolecek vlan_putref_linkmib(mib, &psref);
1051 1.69.12.2 jdolecek curlwp_bindx(bound);
1052 1.60 bouyer error = EINVAL;
1053 1.60 bouyer break;
1054 1.60 bouyer }
1055 1.69.12.2 jdolecek
1056 1.69.12.2 jdolecek vlan_putref_linkmib(mib, &psref);
1057 1.69.12.2 jdolecek curlwp_bindx(bound);
1058 1.69.12.2 jdolecek
1059 1.60 bouyer if ((error = ifioctl_common(ifp, cmd, data)) == ENETRESET)
1060 1.60 bouyer error = 0;
1061 1.60 bouyer break;
1062 1.68 dyoung case SIOCINITIFADDR:
1063 1.69.12.2 jdolecek bound = curlwp_bind();
1064 1.69.12.2 jdolecek mib = vlan_getref_linkmib(ifv, &psref);
1065 1.69.12.2 jdolecek if (mib == NULL) {
1066 1.69.12.2 jdolecek curlwp_bindx(bound);
1067 1.69.12.2 jdolecek error = EBUSY;
1068 1.69.12.2 jdolecek break;
1069 1.69.12.2 jdolecek }
1070 1.69.12.2 jdolecek
1071 1.69.12.2 jdolecek if (mib->ifvm_p == NULL) {
1072 1.68 dyoung error = EINVAL;
1073 1.69.12.2 jdolecek vlan_putref_linkmib(mib, &psref);
1074 1.69.12.2 jdolecek curlwp_bindx(bound);
1075 1.68 dyoung break;
1076 1.68 dyoung }
1077 1.69.12.2 jdolecek vlan_putref_linkmib(mib, &psref);
1078 1.69.12.2 jdolecek curlwp_bindx(bound);
1079 1.68 dyoung
1080 1.68 dyoung ifp->if_flags |= IFF_UP;
1081 1.68 dyoung #ifdef INET
1082 1.68 dyoung if (ifa->ifa_addr->sa_family == AF_INET)
1083 1.68 dyoung arp_ifinit(ifp, ifa);
1084 1.68 dyoung #endif
1085 1.68 dyoung break;
1086 1.68 dyoung
1087 1.1 thorpej default:
1088 1.61 dyoung error = ether_ioctl(ifp, cmd, data);
1089 1.1 thorpej }
1090 1.11 thorpej
1091 1.1 thorpej return (error);
1092 1.1 thorpej }
1093 1.1 thorpej
1094 1.1 thorpej static int
1095 1.10 thorpej vlan_ether_addmulti(struct ifvlan *ifv, struct ifreq *ifr)
1096 1.1 thorpej {
1097 1.55 dyoung const struct sockaddr *sa = ifreq_getaddr(SIOCADDMULTI, ifr);
1098 1.1 thorpej struct vlan_mc_entry *mc;
1099 1.57 matt uint8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN];
1100 1.69.12.2 jdolecek struct ifvlan_linkmib *mib;
1101 1.1 thorpej int error;
1102 1.1 thorpej
1103 1.69.12.2 jdolecek KASSERT(mutex_owned(&ifv->ifv_lock));
1104 1.69.12.2 jdolecek
1105 1.55 dyoung if (sa->sa_len > sizeof(struct sockaddr_storage))
1106 1.5 enami return (EINVAL);
1107 1.5 enami
1108 1.55 dyoung error = ether_addmulti(sa, &ifv->ifv_ec);
1109 1.5 enami if (error != ENETRESET)
1110 1.5 enami return (error);
1111 1.1 thorpej
1112 1.5 enami /*
1113 1.5 enami * This is new multicast address. We have to tell parent
1114 1.5 enami * about it. Also, remember this multicast address so that
1115 1.5 enami * we can delete them on unconfigure.
1116 1.5 enami */
1117 1.62 cegger mc = malloc(sizeof(struct vlan_mc_entry), M_DEVBUF, M_NOWAIT);
1118 1.5 enami if (mc == NULL) {
1119 1.5 enami error = ENOMEM;
1120 1.5 enami goto alloc_failed;
1121 1.1 thorpej }
1122 1.1 thorpej
1123 1.5 enami /*
1124 1.5 enami * As ether_addmulti() returns ENETRESET, following two
1125 1.5 enami * statement shouldn't fail.
1126 1.5 enami */
1127 1.55 dyoung (void)ether_multiaddr(sa, addrlo, addrhi);
1128 1.5 enami ETHER_LOOKUP_MULTI(addrlo, addrhi, &ifv->ifv_ec, mc->mc_enm);
1129 1.55 dyoung memcpy(&mc->mc_addr, sa, sa->sa_len);
1130 1.5 enami LIST_INSERT_HEAD(&ifv->ifv_mc_listhead, mc, mc_entries);
1131 1.5 enami
1132 1.69.12.2 jdolecek mib = ifv->ifv_mib;
1133 1.69.12.2 jdolecek
1134 1.69.12.2 jdolecek KERNEL_LOCK_UNLESS_IFP_MPSAFE(mib->ifvm_p);
1135 1.69.12.2 jdolecek error = if_mcast_op(mib->ifvm_p, SIOCADDMULTI, sa);
1136 1.69.12.2 jdolecek KERNEL_UNLOCK_UNLESS_IFP_MPSAFE(mib->ifvm_p);
1137 1.69.12.2 jdolecek
1138 1.5 enami if (error != 0)
1139 1.5 enami goto ioctl_failed;
1140 1.5 enami return (error);
1141 1.5 enami
1142 1.5 enami ioctl_failed:
1143 1.5 enami LIST_REMOVE(mc, mc_entries);
1144 1.62 cegger free(mc, M_DEVBUF);
1145 1.5 enami alloc_failed:
1146 1.55 dyoung (void)ether_delmulti(sa, &ifv->ifv_ec);
1147 1.5 enami return (error);
1148 1.5 enami }
1149 1.5 enami
1150 1.5 enami static int
1151 1.10 thorpej vlan_ether_delmulti(struct ifvlan *ifv, struct ifreq *ifr)
1152 1.5 enami {
1153 1.55 dyoung const struct sockaddr *sa = ifreq_getaddr(SIOCDELMULTI, ifr);
1154 1.5 enami struct ether_multi *enm;
1155 1.5 enami struct vlan_mc_entry *mc;
1156 1.69.12.2 jdolecek struct ifvlan_linkmib *mib;
1157 1.57 matt uint8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN];
1158 1.5 enami int error;
1159 1.5 enami
1160 1.69.12.2 jdolecek KASSERT(mutex_owned(&ifv->ifv_lock));
1161 1.69.12.2 jdolecek
1162 1.5 enami /*
1163 1.5 enami * Find a key to lookup vlan_mc_entry. We have to do this
1164 1.5 enami * before calling ether_delmulti for obvious reason.
1165 1.5 enami */
1166 1.55 dyoung if ((error = ether_multiaddr(sa, addrlo, addrhi)) != 0)
1167 1.5 enami return (error);
1168 1.5 enami ETHER_LOOKUP_MULTI(addrlo, addrhi, &ifv->ifv_ec, enm);
1169 1.5 enami
1170 1.55 dyoung error = ether_delmulti(sa, &ifv->ifv_ec);
1171 1.5 enami if (error != ENETRESET)
1172 1.5 enami return (error);
1173 1.5 enami
1174 1.5 enami /* We no longer use this multicast address. Tell parent so. */
1175 1.69.12.2 jdolecek mib = ifv->ifv_mib;
1176 1.69.12.2 jdolecek error = if_mcast_op(mib->ifvm_p, SIOCDELMULTI, sa);
1177 1.69.12.2 jdolecek
1178 1.5 enami if (error == 0) {
1179 1.5 enami /* And forget about this address. */
1180 1.5 enami for (mc = LIST_FIRST(&ifv->ifv_mc_listhead); mc != NULL;
1181 1.5 enami mc = LIST_NEXT(mc, mc_entries)) {
1182 1.5 enami if (mc->mc_enm == enm) {
1183 1.5 enami LIST_REMOVE(mc, mc_entries);
1184 1.62 cegger free(mc, M_DEVBUF);
1185 1.5 enami break;
1186 1.5 enami }
1187 1.5 enami }
1188 1.5 enami KASSERT(mc != NULL);
1189 1.5 enami } else
1190 1.55 dyoung (void)ether_addmulti(sa, &ifv->ifv_ec);
1191 1.5 enami return (error);
1192 1.5 enami }
1193 1.5 enami
1194 1.5 enami /*
1195 1.34 pooka * Delete any multicast address we have asked to add from parent
1196 1.5 enami * interface. Called when the vlan is being unconfigured.
1197 1.5 enami */
1198 1.5 enami static void
1199 1.10 thorpej vlan_ether_purgemulti(struct ifvlan *ifv)
1200 1.5 enami {
1201 1.5 enami struct vlan_mc_entry *mc;
1202 1.69.12.2 jdolecek struct ifvlan_linkmib *mib;
1203 1.69.12.2 jdolecek
1204 1.69.12.2 jdolecek KASSERT(mutex_owned(&ifv->ifv_lock));
1205 1.69.12.2 jdolecek mib = ifv->ifv_mib;
1206 1.69.12.2 jdolecek if (mib == NULL) {
1207 1.69.12.2 jdolecek return;
1208 1.69.12.2 jdolecek }
1209 1.5 enami
1210 1.5 enami while ((mc = LIST_FIRST(&ifv->ifv_mc_listhead)) != NULL) {
1211 1.69.12.2 jdolecek (void)if_mcast_op(mib->ifvm_p, SIOCDELMULTI,
1212 1.55 dyoung (const struct sockaddr *)&mc->mc_addr);
1213 1.5 enami LIST_REMOVE(mc, mc_entries);
1214 1.62 cegger free(mc, M_DEVBUF);
1215 1.1 thorpej }
1216 1.1 thorpej }
1217 1.1 thorpej
1218 1.1 thorpej static void
1219 1.1 thorpej vlan_start(struct ifnet *ifp)
1220 1.1 thorpej {
1221 1.14 enami struct ifvlan *ifv = ifp->if_softc;
1222 1.69.12.2 jdolecek struct ifnet *p;
1223 1.69.12.2 jdolecek struct ethercom *ec;
1224 1.1 thorpej struct mbuf *m;
1225 1.69.12.2 jdolecek struct ifvlan_linkmib *mib;
1226 1.69.12.2 jdolecek struct psref psref;
1227 1.31 thorpej int error;
1228 1.1 thorpej
1229 1.69.12.2 jdolecek mib = vlan_getref_linkmib(ifv, &psref);
1230 1.69.12.2 jdolecek if (mib == NULL)
1231 1.69.12.2 jdolecek return;
1232 1.69.12.2 jdolecek p = mib->ifvm_p;
1233 1.69.12.2 jdolecek ec = (void *)mib->ifvm_p;
1234 1.69.12.1 tls
1235 1.1 thorpej ifp->if_flags |= IFF_OACTIVE;
1236 1.1 thorpej
1237 1.1 thorpej for (;;) {
1238 1.31 thorpej IFQ_DEQUEUE(&ifp->if_snd, m);
1239 1.1 thorpej if (m == NULL)
1240 1.1 thorpej break;
1241 1.1 thorpej
1242 1.31 thorpej #ifdef ALTQ
1243 1.31 thorpej /*
1244 1.69.12.2 jdolecek * KERNEL_LOCK is required for ALTQ even if NET_MPSAFE is defined.
1245 1.69.12.2 jdolecek */
1246 1.69.12.2 jdolecek KERNEL_LOCK(1, NULL);
1247 1.69.12.2 jdolecek /*
1248 1.31 thorpej * If ALTQ is enabled on the parent interface, do
1249 1.31 thorpej * classification; the queueing discipline might
1250 1.31 thorpej * not require classification, but might require
1251 1.31 thorpej * the address family/header pointer in the pktattr.
1252 1.31 thorpej */
1253 1.31 thorpej if (ALTQ_IS_ENABLED(&p->if_snd)) {
1254 1.31 thorpej switch (p->if_type) {
1255 1.31 thorpej case IFT_ETHER:
1256 1.69.12.2 jdolecek altq_etherclassify(&p->if_snd, m);
1257 1.31 thorpej break;
1258 1.31 thorpej #ifdef DIAGNOSTIC
1259 1.31 thorpej default:
1260 1.31 thorpej panic("vlan_start: impossible (altq)");
1261 1.31 thorpej #endif
1262 1.31 thorpej }
1263 1.31 thorpej }
1264 1.69.12.2 jdolecek KERNEL_UNLOCK_ONE(NULL);
1265 1.31 thorpej #endif /* ALTQ */
1266 1.31 thorpej
1267 1.66 joerg bpf_mtap(ifp, m);
1268 1.1 thorpej /*
1269 1.24 bouyer * If the parent can insert the tag itself, just mark
1270 1.24 bouyer * the tag in the mbuf header.
1271 1.1 thorpej */
1272 1.24 bouyer if (ec->ec_capabilities & ETHERCAP_VLAN_HWTAGGING) {
1273 1.69.12.2 jdolecek vlan_set_tag(m, mib->ifvm_tag);
1274 1.24 bouyer } else {
1275 1.24 bouyer /*
1276 1.34 pooka * insert the tag ourselves
1277 1.24 bouyer */
1278 1.69.12.2 jdolecek M_PREPEND(m, mib->ifvm_encaplen, M_DONTWAIT);
1279 1.24 bouyer if (m == NULL) {
1280 1.24 bouyer printf("%s: unable to prepend encap header",
1281 1.69.12.2 jdolecek p->if_xname);
1282 1.10 thorpej ifp->if_oerrors++;
1283 1.10 thorpej continue;
1284 1.10 thorpej }
1285 1.10 thorpej
1286 1.24 bouyer switch (p->if_type) {
1287 1.24 bouyer case IFT_ETHER:
1288 1.24 bouyer {
1289 1.24 bouyer struct ether_vlan_header *evl;
1290 1.24 bouyer
1291 1.24 bouyer if (m->m_len < sizeof(struct ether_vlan_header))
1292 1.24 bouyer m = m_pullup(m,
1293 1.24 bouyer sizeof(struct ether_vlan_header));
1294 1.24 bouyer if (m == NULL) {
1295 1.24 bouyer printf("%s: unable to pullup encap "
1296 1.69.12.2 jdolecek "header", p->if_xname);
1297 1.24 bouyer ifp->if_oerrors++;
1298 1.24 bouyer continue;
1299 1.24 bouyer }
1300 1.24 bouyer
1301 1.24 bouyer /*
1302 1.24 bouyer * Transform the Ethernet header into an
1303 1.24 bouyer * Ethernet header with 802.1Q encapsulation.
1304 1.24 bouyer */
1305 1.53 christos memmove(mtod(m, void *),
1306 1.69.12.2 jdolecek mtod(m, char *) + mib->ifvm_encaplen,
1307 1.24 bouyer sizeof(struct ether_header));
1308 1.24 bouyer evl = mtod(m, struct ether_vlan_header *);
1309 1.24 bouyer evl->evl_proto = evl->evl_encap_proto;
1310 1.24 bouyer evl->evl_encap_proto = htons(ETHERTYPE_VLAN);
1311 1.69.12.2 jdolecek evl->evl_tag = htons(mib->ifvm_tag);
1312 1.38 scw
1313 1.38 scw /*
1314 1.38 scw * To cater for VLAN-aware layer 2 ethernet
1315 1.38 scw * switches which may need to strip the tag
1316 1.38 scw * before forwarding the packet, make sure
1317 1.38 scw * the packet+tag is at least 68 bytes long.
1318 1.38 scw * This is necessary because our parent will
1319 1.38 scw * only pad to 64 bytes (ETHER_MIN_LEN) and
1320 1.38 scw * some switches will not pad by themselves
1321 1.38 scw * after deleting a tag.
1322 1.38 scw */
1323 1.38 scw if (m->m_pkthdr.len <
1324 1.69.12.2 jdolecek (ETHER_MIN_LEN - ETHER_CRC_LEN +
1325 1.69.12.2 jdolecek ETHER_VLAN_ENCAP_LEN)) {
1326 1.38 scw m_copyback(m, m->m_pkthdr.len,
1327 1.69.12.2 jdolecek (ETHER_MIN_LEN - ETHER_CRC_LEN +
1328 1.38 scw ETHER_VLAN_ENCAP_LEN) -
1329 1.38 scw m->m_pkthdr.len,
1330 1.38 scw vlan_zero_pad_buff);
1331 1.38 scw }
1332 1.24 bouyer break;
1333 1.24 bouyer }
1334 1.10 thorpej
1335 1.10 thorpej #ifdef DIAGNOSTIC
1336 1.24 bouyer default:
1337 1.24 bouyer panic("vlan_start: impossible");
1338 1.10 thorpej #endif
1339 1.24 bouyer }
1340 1.1 thorpej }
1341 1.1 thorpej
1342 1.69.12.2 jdolecek if ((p->if_flags & IFF_RUNNING) == 0) {
1343 1.69.12.2 jdolecek m_freem(m);
1344 1.69.12.2 jdolecek continue;
1345 1.69.12.2 jdolecek }
1346 1.69.12.2 jdolecek
1347 1.69.12.2 jdolecek error = if_transmit_lock(p, m);
1348 1.31 thorpej if (error) {
1349 1.31 thorpej /* mbuf is already freed */
1350 1.1 thorpej ifp->if_oerrors++;
1351 1.1 thorpej continue;
1352 1.1 thorpej }
1353 1.23 bouyer ifp->if_opackets++;
1354 1.1 thorpej }
1355 1.1 thorpej
1356 1.1 thorpej ifp->if_flags &= ~IFF_OACTIVE;
1357 1.69.12.2 jdolecek
1358 1.69.12.2 jdolecek /* Remove reference to mib before release */
1359 1.69.12.2 jdolecek p = NULL;
1360 1.69.12.2 jdolecek ec = NULL;
1361 1.69.12.2 jdolecek
1362 1.69.12.2 jdolecek vlan_putref_linkmib(mib, &psref);
1363 1.69.12.2 jdolecek }
1364 1.69.12.2 jdolecek
1365 1.69.12.2 jdolecek static int
1366 1.69.12.2 jdolecek vlan_transmit(struct ifnet *ifp, struct mbuf *m)
1367 1.69.12.2 jdolecek {
1368 1.69.12.2 jdolecek struct ifvlan *ifv = ifp->if_softc;
1369 1.69.12.2 jdolecek struct ifnet *p;
1370 1.69.12.2 jdolecek struct ethercom *ec;
1371 1.69.12.2 jdolecek struct ifvlan_linkmib *mib;
1372 1.69.12.2 jdolecek struct psref psref;
1373 1.69.12.2 jdolecek int error;
1374 1.69.12.2 jdolecek size_t pktlen = m->m_pkthdr.len;
1375 1.69.12.2 jdolecek bool mcast = (m->m_flags & M_MCAST) != 0;
1376 1.69.12.2 jdolecek
1377 1.69.12.2 jdolecek mib = vlan_getref_linkmib(ifv, &psref);
1378 1.69.12.2 jdolecek if (mib == NULL) {
1379 1.69.12.2 jdolecek m_freem(m);
1380 1.69.12.2 jdolecek return ENETDOWN;
1381 1.69.12.2 jdolecek }
1382 1.69.12.2 jdolecek
1383 1.69.12.2 jdolecek p = mib->ifvm_p;
1384 1.69.12.2 jdolecek ec = (void *)mib->ifvm_p;
1385 1.69.12.2 jdolecek
1386 1.69.12.2 jdolecek bpf_mtap(ifp, m);
1387 1.69.12.2 jdolecek
1388 1.69.12.2 jdolecek if (pfil_run_hooks(ifp->if_pfil, &m, ifp, PFIL_OUT) != 0) {
1389 1.69.12.2 jdolecek if (m != NULL)
1390 1.69.12.2 jdolecek m_freem(m);
1391 1.69.12.2 jdolecek error = 0;
1392 1.69.12.2 jdolecek goto out;
1393 1.69.12.2 jdolecek }
1394 1.69.12.2 jdolecek
1395 1.69.12.2 jdolecek /*
1396 1.69.12.2 jdolecek * If the parent can insert the tag itself, just mark
1397 1.69.12.2 jdolecek * the tag in the mbuf header.
1398 1.69.12.2 jdolecek */
1399 1.69.12.2 jdolecek if (ec->ec_capabilities & ETHERCAP_VLAN_HWTAGGING) {
1400 1.69.12.2 jdolecek vlan_set_tag(m, mib->ifvm_tag);
1401 1.69.12.2 jdolecek } else {
1402 1.69.12.2 jdolecek /*
1403 1.69.12.2 jdolecek * insert the tag ourselves
1404 1.69.12.2 jdolecek */
1405 1.69.12.2 jdolecek M_PREPEND(m, mib->ifvm_encaplen, M_DONTWAIT);
1406 1.69.12.2 jdolecek if (m == NULL) {
1407 1.69.12.2 jdolecek printf("%s: unable to prepend encap header",
1408 1.69.12.2 jdolecek p->if_xname);
1409 1.69.12.2 jdolecek ifp->if_oerrors++;
1410 1.69.12.2 jdolecek error = ENOBUFS;
1411 1.69.12.2 jdolecek goto out;
1412 1.69.12.2 jdolecek }
1413 1.69.12.2 jdolecek
1414 1.69.12.2 jdolecek switch (p->if_type) {
1415 1.69.12.2 jdolecek case IFT_ETHER:
1416 1.69.12.2 jdolecek {
1417 1.69.12.2 jdolecek struct ether_vlan_header *evl;
1418 1.69.12.2 jdolecek
1419 1.69.12.2 jdolecek if (m->m_len < sizeof(struct ether_vlan_header))
1420 1.69.12.2 jdolecek m = m_pullup(m,
1421 1.69.12.2 jdolecek sizeof(struct ether_vlan_header));
1422 1.69.12.2 jdolecek if (m == NULL) {
1423 1.69.12.2 jdolecek printf("%s: unable to pullup encap "
1424 1.69.12.2 jdolecek "header", p->if_xname);
1425 1.69.12.2 jdolecek ifp->if_oerrors++;
1426 1.69.12.2 jdolecek error = ENOBUFS;
1427 1.69.12.2 jdolecek goto out;
1428 1.69.12.2 jdolecek }
1429 1.69.12.2 jdolecek
1430 1.69.12.2 jdolecek /*
1431 1.69.12.2 jdolecek * Transform the Ethernet header into an
1432 1.69.12.2 jdolecek * Ethernet header with 802.1Q encapsulation.
1433 1.69.12.2 jdolecek */
1434 1.69.12.2 jdolecek memmove(mtod(m, void *),
1435 1.69.12.2 jdolecek mtod(m, char *) + mib->ifvm_encaplen,
1436 1.69.12.2 jdolecek sizeof(struct ether_header));
1437 1.69.12.2 jdolecek evl = mtod(m, struct ether_vlan_header *);
1438 1.69.12.2 jdolecek evl->evl_proto = evl->evl_encap_proto;
1439 1.69.12.2 jdolecek evl->evl_encap_proto = htons(ETHERTYPE_VLAN);
1440 1.69.12.2 jdolecek evl->evl_tag = htons(mib->ifvm_tag);
1441 1.69.12.2 jdolecek
1442 1.69.12.2 jdolecek /*
1443 1.69.12.2 jdolecek * To cater for VLAN-aware layer 2 ethernet
1444 1.69.12.2 jdolecek * switches which may need to strip the tag
1445 1.69.12.2 jdolecek * before forwarding the packet, make sure
1446 1.69.12.2 jdolecek * the packet+tag is at least 68 bytes long.
1447 1.69.12.2 jdolecek * This is necessary because our parent will
1448 1.69.12.2 jdolecek * only pad to 64 bytes (ETHER_MIN_LEN) and
1449 1.69.12.2 jdolecek * some switches will not pad by themselves
1450 1.69.12.2 jdolecek * after deleting a tag.
1451 1.69.12.2 jdolecek */
1452 1.69.12.2 jdolecek if (m->m_pkthdr.len <
1453 1.69.12.2 jdolecek (ETHER_MIN_LEN - ETHER_CRC_LEN +
1454 1.69.12.2 jdolecek ETHER_VLAN_ENCAP_LEN)) {
1455 1.69.12.2 jdolecek m_copyback(m, m->m_pkthdr.len,
1456 1.69.12.2 jdolecek (ETHER_MIN_LEN - ETHER_CRC_LEN +
1457 1.69.12.2 jdolecek ETHER_VLAN_ENCAP_LEN) -
1458 1.69.12.2 jdolecek m->m_pkthdr.len,
1459 1.69.12.2 jdolecek vlan_zero_pad_buff);
1460 1.69.12.2 jdolecek }
1461 1.69.12.2 jdolecek break;
1462 1.69.12.2 jdolecek }
1463 1.69.12.2 jdolecek
1464 1.69.12.2 jdolecek #ifdef DIAGNOSTIC
1465 1.69.12.2 jdolecek default:
1466 1.69.12.2 jdolecek panic("vlan_transmit: impossible");
1467 1.69.12.2 jdolecek #endif
1468 1.69.12.2 jdolecek }
1469 1.69.12.2 jdolecek }
1470 1.69.12.2 jdolecek
1471 1.69.12.2 jdolecek if ((p->if_flags & IFF_RUNNING) == 0) {
1472 1.69.12.2 jdolecek m_freem(m);
1473 1.69.12.2 jdolecek error = ENETDOWN;
1474 1.69.12.2 jdolecek goto out;
1475 1.69.12.2 jdolecek }
1476 1.69.12.2 jdolecek
1477 1.69.12.2 jdolecek error = if_transmit_lock(p, m);
1478 1.69.12.2 jdolecek if (error) {
1479 1.69.12.2 jdolecek /* mbuf is already freed */
1480 1.69.12.2 jdolecek ifp->if_oerrors++;
1481 1.69.12.2 jdolecek } else {
1482 1.69.12.2 jdolecek
1483 1.69.12.2 jdolecek ifp->if_opackets++;
1484 1.69.12.2 jdolecek ifp->if_obytes += pktlen;
1485 1.69.12.2 jdolecek if (mcast)
1486 1.69.12.2 jdolecek ifp->if_omcasts++;
1487 1.69.12.2 jdolecek }
1488 1.69.12.2 jdolecek
1489 1.69.12.2 jdolecek out:
1490 1.69.12.2 jdolecek /* Remove reference to mib before release */
1491 1.69.12.2 jdolecek p = NULL;
1492 1.69.12.2 jdolecek ec = NULL;
1493 1.69.12.2 jdolecek
1494 1.69.12.2 jdolecek vlan_putref_linkmib(mib, &psref);
1495 1.69.12.2 jdolecek return error;
1496 1.1 thorpej }
1497 1.1 thorpej
1498 1.1 thorpej /*
1499 1.1 thorpej * Given an Ethernet frame, find a valid vlan interface corresponding to the
1500 1.44 perry * given source interface and tag, then run the real packet through the
1501 1.40 simonb * parent's input routine.
1502 1.1 thorpej */
1503 1.1 thorpej void
1504 1.1 thorpej vlan_input(struct ifnet *ifp, struct mbuf *m)
1505 1.1 thorpej {
1506 1.1 thorpej struct ifvlan *ifv;
1507 1.69.12.2 jdolecek uint16_t vid;
1508 1.69.12.2 jdolecek struct ifvlan_linkmib *mib;
1509 1.69.12.2 jdolecek struct psref psref;
1510 1.69.12.2 jdolecek bool have_vtag;
1511 1.69.12.2 jdolecek
1512 1.69.12.2 jdolecek have_vtag = vlan_has_tag(m);
1513 1.69.12.2 jdolecek if (have_vtag) {
1514 1.69.12.2 jdolecek vid = EVL_VLANOFTAG(vlan_get_tag(m));
1515 1.69.12.2 jdolecek m->m_flags &= ~M_VLANTAG;
1516 1.24 bouyer } else {
1517 1.24 bouyer switch (ifp->if_type) {
1518 1.24 bouyer case IFT_ETHER:
1519 1.24 bouyer {
1520 1.24 bouyer struct ether_vlan_header *evl;
1521 1.24 bouyer
1522 1.24 bouyer if (m->m_len < sizeof(struct ether_vlan_header) &&
1523 1.24 bouyer (m = m_pullup(m,
1524 1.24 bouyer sizeof(struct ether_vlan_header))) == NULL) {
1525 1.24 bouyer printf("%s: no memory for VLAN header, "
1526 1.24 bouyer "dropping packet.\n", ifp->if_xname);
1527 1.24 bouyer return;
1528 1.24 bouyer }
1529 1.24 bouyer evl = mtod(m, struct ether_vlan_header *);
1530 1.24 bouyer KASSERT(ntohs(evl->evl_encap_proto) == ETHERTYPE_VLAN);
1531 1.24 bouyer
1532 1.69.12.2 jdolecek vid = EVL_VLANOFTAG(ntohs(evl->evl_tag));
1533 1.1 thorpej
1534 1.24 bouyer /*
1535 1.24 bouyer * Restore the original ethertype. We'll remove
1536 1.24 bouyer * the encapsulation after we've found the vlan
1537 1.24 bouyer * interface corresponding to the tag.
1538 1.24 bouyer */
1539 1.24 bouyer evl->evl_encap_proto = evl->evl_proto;
1540 1.24 bouyer break;
1541 1.24 bouyer }
1542 1.10 thorpej
1543 1.24 bouyer default:
1544 1.69.12.2 jdolecek vid = (uint16_t) -1; /* XXX GCC */
1545 1.24 bouyer #ifdef DIAGNOSTIC
1546 1.24 bouyer panic("vlan_input: impossible");
1547 1.24 bouyer #endif
1548 1.10 thorpej }
1549 1.43 christos }
1550 1.10 thorpej
1551 1.69.12.2 jdolecek mib = vlan_lookup_tag_psref(ifp, vid, &psref);
1552 1.69.12.2 jdolecek if (mib == NULL) {
1553 1.37 itojun m_freem(m);
1554 1.14 enami ifp->if_noproto++;
1555 1.1 thorpej return;
1556 1.1 thorpej }
1557 1.43 christos
1558 1.69.12.2 jdolecek ifv = mib->ifvm_ifvlan;
1559 1.69.12.2 jdolecek if ((ifv->ifv_if.if_flags & (IFF_UP|IFF_RUNNING)) !=
1560 1.69.12.2 jdolecek (IFF_UP|IFF_RUNNING)) {
1561 1.69.12.2 jdolecek m_freem(m);
1562 1.69.12.2 jdolecek ifp->if_noproto++;
1563 1.69.12.2 jdolecek goto out;
1564 1.69.12.2 jdolecek }
1565 1.69.12.2 jdolecek
1566 1.43 christos /*
1567 1.43 christos * Now, remove the encapsulation header. The original
1568 1.43 christos * header has already been fixed up above.
1569 1.43 christos */
1570 1.69.12.2 jdolecek if (!have_vtag) {
1571 1.69.12.2 jdolecek memmove(mtod(m, char *) + mib->ifvm_encaplen,
1572 1.53 christos mtod(m, void *), sizeof(struct ether_header));
1573 1.69.12.2 jdolecek m_adj(m, mib->ifvm_encaplen);
1574 1.43 christos }
1575 1.43 christos
1576 1.69.12.2 jdolecek m_set_rcvif(m, &ifv->ifv_if);
1577 1.1 thorpej ifv->ifv_if.if_ipackets++;
1578 1.1 thorpej
1579 1.69.12.2 jdolecek if (pfil_run_hooks(ifp->if_pfil, &m, ifp, PFIL_IN) != 0) {
1580 1.69.12.2 jdolecek if (m != NULL)
1581 1.69.12.2 jdolecek m_freem(m);
1582 1.69.12.2 jdolecek goto out;
1583 1.69.12.2 jdolecek }
1584 1.1 thorpej
1585 1.69.12.2 jdolecek m->m_flags &= ~M_PROMISC;
1586 1.69.12.2 jdolecek if_input(&ifv->ifv_if, m);
1587 1.69.12.2 jdolecek out:
1588 1.69.12.2 jdolecek vlan_putref_linkmib(mib, &psref);
1589 1.1 thorpej }
1590 1.69.12.2 jdolecek
1591 1.69.12.2 jdolecek /*
1592 1.69.12.2 jdolecek * Module infrastructure
1593 1.69.12.2 jdolecek */
1594 1.69.12.2 jdolecek #include "if_module.h"
1595 1.69.12.2 jdolecek
1596 1.69.12.2 jdolecek IF_MODULE(MODULE_CLASS_DRIVER, vlan, "")
1597