if_vlan.c revision 1.26.2.2 1 1.26.2.2 jhawk /* $NetBSD: if_vlan.c,v 1.26.2.2 2000/12/31 20:14:32 jhawk Exp $ */
2 1.26.2.2 jhawk
3 1.26.2.2 jhawk /*-
4 1.26.2.2 jhawk * Copyright (c) 2000 The NetBSD Foundation, Inc.
5 1.26.2.2 jhawk * All rights reserved.
6 1.26.2.2 jhawk *
7 1.26.2.2 jhawk * This code is derived from software contributed to The NetBSD Foundation
8 1.26.2.2 jhawk * by Andrew Doran, and by Jason R. Thorpe of Zembu Labs, Inc.
9 1.26.2.2 jhawk *
10 1.26.2.2 jhawk * Redistribution and use in source and binary forms, with or without
11 1.26.2.2 jhawk * modification, are permitted provided that the following conditions
12 1.26.2.2 jhawk * are met:
13 1.26.2.2 jhawk * 1. Redistributions of source code must retain the above copyright
14 1.26.2.2 jhawk * notice, this list of conditions and the following disclaimer.
15 1.26.2.2 jhawk * 2. Redistributions in binary form must reproduce the above copyright
16 1.26.2.2 jhawk * notice, this list of conditions and the following disclaimer in the
17 1.26.2.2 jhawk * documentation and/or other materials provided with the distribution.
18 1.26.2.2 jhawk * 3. All advertising materials mentioning features or use of this software
19 1.26.2.2 jhawk * must display the following acknowledgement:
20 1.26.2.2 jhawk * This product includes software developed by the NetBSD
21 1.26.2.2 jhawk * Foundation, Inc. and its contributors.
22 1.26.2.2 jhawk * 4. Neither the name of The NetBSD Foundation nor the names of its
23 1.26.2.2 jhawk * contributors may be used to endorse or promote products derived
24 1.26.2.2 jhawk * from this software without specific prior written permission.
25 1.26.2.2 jhawk *
26 1.26.2.2 jhawk * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 1.26.2.2 jhawk * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 1.26.2.2 jhawk * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 1.26.2.2 jhawk * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 1.26.2.2 jhawk * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 1.26.2.2 jhawk * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 1.26.2.2 jhawk * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 1.26.2.2 jhawk * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 1.26.2.2 jhawk * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 1.26.2.2 jhawk * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 1.26.2.2 jhawk * POSSIBILITY OF SUCH DAMAGE.
37 1.26.2.2 jhawk */
38 1.26.2.2 jhawk
39 1.26.2.2 jhawk /*
40 1.26.2.2 jhawk * Copyright 1998 Massachusetts Institute of Technology
41 1.26.2.2 jhawk *
42 1.26.2.2 jhawk * Permission to use, copy, modify, and distribute this software and
43 1.26.2.2 jhawk * its documentation for any purpose and without fee is hereby
44 1.26.2.2 jhawk * granted, provided that both the above copyright notice and this
45 1.26.2.2 jhawk * permission notice appear in all copies, that both the above
46 1.26.2.2 jhawk * copyright notice and this permission notice appear in all
47 1.26.2.2 jhawk * supporting documentation, and that the name of M.I.T. not be used
48 1.26.2.2 jhawk * in advertising or publicity pertaining to distribution of the
49 1.26.2.2 jhawk * software without specific, written prior permission. M.I.T. makes
50 1.26.2.2 jhawk * no representations about the suitability of this software for any
51 1.26.2.2 jhawk * purpose. It is provided "as is" without express or implied
52 1.26.2.2 jhawk * warranty.
53 1.26.2.2 jhawk *
54 1.26.2.2 jhawk * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
55 1.26.2.2 jhawk * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
56 1.26.2.2 jhawk * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
57 1.26.2.2 jhawk * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
58 1.26.2.2 jhawk * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
59 1.26.2.2 jhawk * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
60 1.26.2.2 jhawk * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
61 1.26.2.2 jhawk * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
62 1.26.2.2 jhawk * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
63 1.26.2.2 jhawk * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
64 1.26.2.2 jhawk * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
65 1.26.2.2 jhawk * SUCH DAMAGE.
66 1.26.2.2 jhawk *
67 1.26.2.2 jhawk * from FreeBSD: if_vlan.c,v 1.16 2000/03/26 15:21:40 charnier Exp
68 1.26.2.2 jhawk * via OpenBSD: if_vlan.c,v 1.4 2000/05/15 19:15:00 chris Exp
69 1.26.2.2 jhawk */
70 1.26.2.2 jhawk
71 1.26.2.2 jhawk /*
72 1.26.2.2 jhawk * if_vlan.c - pseudo-device driver for IEEE 802.1Q virtual LANs. Might be
73 1.26.2.2 jhawk * extended some day to also handle IEEE 802.1P priority tagging. This is
74 1.26.2.2 jhawk * sort of sneaky in the implementation, since we need to pretend to be
75 1.26.2.2 jhawk * enough of an Ethernet implementation to make ARP work. The way we do
76 1.26.2.2 jhawk * this is by telling everyone that we are an Ethernet interface, and then
77 1.26.2.2 jhawk * catch the packets that ether_output() left on our output queue when it
78 1.26.2.2 jhawk * calls if_start(), rewrite them for use by the real outgoing interface,
79 1.26.2.2 jhawk * and ask it to send them.
80 1.26.2.2 jhawk *
81 1.26.2.2 jhawk * TODO:
82 1.26.2.2 jhawk *
83 1.26.2.2 jhawk * - Need some way to notify vlan interfaces when the parent
84 1.26.2.2 jhawk * interface changes MTU.
85 1.26.2.2 jhawk */
86 1.26.2.2 jhawk
87 1.26.2.2 jhawk #include "opt_inet.h"
88 1.26.2.2 jhawk #include "bpfilter.h"
89 1.26.2.2 jhawk
90 1.26.2.2 jhawk #include <sys/param.h>
91 1.26.2.2 jhawk #include <sys/kernel.h>
92 1.26.2.2 jhawk #include <sys/mbuf.h>
93 1.26.2.2 jhawk #include <sys/queue.h>
94 1.26.2.2 jhawk #include <sys/socket.h>
95 1.26.2.2 jhawk #include <sys/sockio.h>
96 1.26.2.2 jhawk #include <sys/systm.h>
97 1.26.2.2 jhawk #include <sys/proc.h>
98 1.26.2.2 jhawk
99 1.26.2.2 jhawk #if NBPFILTER > 0
100 1.26.2.2 jhawk #include <net/bpf.h>
101 1.26.2.2 jhawk #endif
102 1.26.2.2 jhawk #include <net/if.h>
103 1.26.2.2 jhawk #include <net/if_dl.h>
104 1.26.2.2 jhawk #include <net/if_types.h>
105 1.26.2.2 jhawk #include <net/if_ether.h>
106 1.26.2.2 jhawk #include <net/if_vlanvar.h>
107 1.26.2.2 jhawk
108 1.26.2.2 jhawk #ifdef INET
109 1.26.2.2 jhawk #include <netinet/in.h>
110 1.26.2.2 jhawk #include <netinet/if_inarp.h>
111 1.26.2.2 jhawk #endif
112 1.26.2.2 jhawk
113 1.26.2.2 jhawk extern struct ifaddr **ifnet_addrs; /* XXX if.c */
114 1.26.2.2 jhawk
115 1.26.2.2 jhawk struct vlan_mc_entry {
116 1.26.2.2 jhawk LIST_ENTRY(vlan_mc_entry) mc_entries;
117 1.26.2.2 jhawk /*
118 1.26.2.2 jhawk * A key to identify this entry. The mc_addr below can't be
119 1.26.2.2 jhawk * used since multiple sockaddr may mapped into the same
120 1.26.2.2 jhawk * ether_multi (e.g., AF_UNSPEC).
121 1.26.2.2 jhawk */
122 1.26.2.2 jhawk union {
123 1.26.2.2 jhawk struct ether_multi *mcu_enm;
124 1.26.2.2 jhawk } mc_u;
125 1.26.2.2 jhawk struct sockaddr_storage mc_addr;
126 1.26.2.2 jhawk };
127 1.26.2.2 jhawk
128 1.26.2.2 jhawk #define mc_enm mc_u.mcu_enm
129 1.26.2.2 jhawk
130 1.26.2.2 jhawk struct ifvlan {
131 1.26.2.2 jhawk union {
132 1.26.2.2 jhawk struct ethercom ifvu_ec;
133 1.26.2.2 jhawk } ifv_u;
134 1.26.2.2 jhawk struct ifnet *ifv_p; /* parent interface of this vlan */
135 1.26.2.2 jhawk struct ifv_linkmib {
136 1.26.2.2 jhawk const struct vlan_multisw *ifvm_msw;
137 1.26.2.2 jhawk int ifvm_encaplen; /* encapsulation length */
138 1.26.2.2 jhawk int ifvm_mtufudge; /* MTU fudged by this much */
139 1.26.2.2 jhawk int ifvm_mintu; /* min transmission unit */
140 1.26.2.2 jhawk u_int16_t ifvm_proto; /* encapsulation ethertype */
141 1.26.2.2 jhawk u_int16_t ifvm_tag; /* tag to apply on packets */
142 1.26.2.2 jhawk } ifv_mib;
143 1.26.2.2 jhawk LIST_HEAD(__vlan_mchead, vlan_mc_entry) ifv_mc_listhead;
144 1.26.2.2 jhawk LIST_ENTRY(ifvlan) ifv_list;
145 1.26.2.2 jhawk int ifv_flags;
146 1.26.2.2 jhawk };
147 1.26.2.2 jhawk
148 1.26.2.2 jhawk #define IFVF_PROMISC 0x01 /* promiscuous mode enabled */
149 1.26.2.2 jhawk
150 1.26.2.2 jhawk #define ifv_ec ifv_u.ifvu_ec
151 1.26.2.2 jhawk
152 1.26.2.2 jhawk #define ifv_if ifv_ec.ec_if
153 1.26.2.2 jhawk
154 1.26.2.2 jhawk #define ifv_msw ifv_mib.ifvm_msw
155 1.26.2.2 jhawk #define ifv_encaplen ifv_mib.ifvm_encaplen
156 1.26.2.2 jhawk #define ifv_mtufudge ifv_mib.ifvm_mtufudge
157 1.26.2.2 jhawk #define ifv_mintu ifv_mib.ifvm_mintu
158 1.26.2.2 jhawk #define ifv_tag ifv_mib.ifvm_tag
159 1.26.2.2 jhawk
160 1.26.2.2 jhawk struct vlan_multisw {
161 1.26.2.2 jhawk int (*vmsw_addmulti)(struct ifvlan *, struct ifreq *);
162 1.26.2.2 jhawk int (*vmsw_delmulti)(struct ifvlan *, struct ifreq *);
163 1.26.2.2 jhawk void (*vmsw_purgemulti)(struct ifvlan *);
164 1.26.2.2 jhawk };
165 1.26.2.2 jhawk
166 1.26.2.2 jhawk static int vlan_ether_addmulti(struct ifvlan *, struct ifreq *);
167 1.26.2.2 jhawk static int vlan_ether_delmulti(struct ifvlan *, struct ifreq *);
168 1.26.2.2 jhawk static void vlan_ether_purgemulti(struct ifvlan *);
169 1.26.2.2 jhawk
170 1.26.2.2 jhawk const struct vlan_multisw vlan_ether_multisw = {
171 1.26.2.2 jhawk vlan_ether_addmulti,
172 1.26.2.2 jhawk vlan_ether_delmulti,
173 1.26.2.2 jhawk vlan_ether_purgemulti,
174 1.26.2.2 jhawk };
175 1.26.2.2 jhawk
176 1.26.2.2 jhawk static int vlan_clone_create(struct if_clone *, int);
177 1.26.2.2 jhawk static void vlan_clone_destroy(struct ifnet *);
178 1.26.2.2 jhawk static int vlan_config(struct ifvlan *, struct ifnet *);
179 1.26.2.2 jhawk static int vlan_ioctl(struct ifnet *, u_long, caddr_t);
180 1.26.2.2 jhawk static void vlan_start(struct ifnet *);
181 1.26.2.2 jhawk static void vlan_unconfig(struct ifnet *);
182 1.26.2.2 jhawk
183 1.26.2.2 jhawk void vlanattach(int);
184 1.26.2.2 jhawk
185 1.26.2.2 jhawk /* XXX This should be a hash table with the tag as the basis of the key. */
186 1.26.2.2 jhawk static LIST_HEAD(, ifvlan) ifv_list;
187 1.26.2.2 jhawk
188 1.26.2.2 jhawk struct if_clone vlan_cloner =
189 1.26.2.2 jhawk IF_CLONE_INITIALIZER("vlan", vlan_clone_create, vlan_clone_destroy);
190 1.26.2.2 jhawk
191 1.26.2.2 jhawk void
192 1.26.2.2 jhawk vlanattach(int n)
193 1.26.2.2 jhawk {
194 1.26.2.2 jhawk
195 1.26.2.2 jhawk LIST_INIT(&ifv_list);
196 1.26.2.2 jhawk if_clone_attach(&vlan_cloner);
197 1.26.2.2 jhawk }
198 1.26.2.2 jhawk
199 1.26.2.2 jhawk static int
200 1.26.2.2 jhawk vlan_clone_create(struct if_clone *ifc, int unit)
201 1.26.2.2 jhawk {
202 1.26.2.2 jhawk struct ifvlan *ifv;
203 1.26.2.2 jhawk struct ifnet *ifp;
204 1.26.2.2 jhawk int s;
205 1.26.2.2 jhawk
206 1.26.2.2 jhawk ifv = malloc(sizeof(struct ifvlan), M_DEVBUF, M_WAITOK);
207 1.26.2.2 jhawk memset(ifv, 0, sizeof(struct ifvlan));
208 1.26.2.2 jhawk ifp = &ifv->ifv_if;
209 1.26.2.2 jhawk LIST_INIT(&ifv->ifv_mc_listhead);
210 1.26.2.2 jhawk
211 1.26.2.2 jhawk s = splnet();
212 1.26.2.2 jhawk LIST_INSERT_HEAD(&ifv_list, ifv, ifv_list);
213 1.26.2.2 jhawk splx(s);
214 1.26.2.2 jhawk
215 1.26.2.2 jhawk sprintf(ifp->if_xname, "%s%d", ifc->ifc_name, unit);
216 1.26.2.2 jhawk ifp->if_softc = ifv;
217 1.26.2.2 jhawk ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
218 1.26.2.2 jhawk ifp->if_start = vlan_start;
219 1.26.2.2 jhawk ifp->if_ioctl = vlan_ioctl;
220 1.26.2.2 jhawk
221 1.26.2.2 jhawk if_attach(ifp);
222 1.26.2.2 jhawk
223 1.26.2.2 jhawk return (0);
224 1.26.2.2 jhawk }
225 1.26.2.2 jhawk
226 1.26.2.2 jhawk static void
227 1.26.2.2 jhawk vlan_clone_destroy(struct ifnet *ifp)
228 1.26.2.2 jhawk {
229 1.26.2.2 jhawk struct ifvlan *ifv = ifp->if_softc;
230 1.26.2.2 jhawk int s;
231 1.26.2.2 jhawk
232 1.26.2.2 jhawk s = splnet();
233 1.26.2.2 jhawk LIST_REMOVE(ifv, ifv_list);
234 1.26.2.2 jhawk vlan_unconfig(ifp);
235 1.26.2.2 jhawk splx(s);
236 1.26.2.2 jhawk
237 1.26.2.2 jhawk #if NBPFILTER > 0
238 1.26.2.2 jhawk bpfdetach(ifp);
239 1.26.2.2 jhawk #endif
240 1.26.2.2 jhawk ether_ifdetach(ifp);
241 1.26.2.2 jhawk if_detach(ifp);
242 1.26.2.2 jhawk free(ifv, M_DEVBUF);
243 1.26.2.2 jhawk }
244 1.26.2.2 jhawk
245 1.26.2.2 jhawk /*
246 1.26.2.2 jhawk * Configure a VLAN interface. Must be called at splnet().
247 1.26.2.2 jhawk */
248 1.26.2.2 jhawk static int
249 1.26.2.2 jhawk vlan_config(struct ifvlan *ifv, struct ifnet *p)
250 1.26.2.2 jhawk {
251 1.26.2.2 jhawk struct ifnet *ifp = &ifv->ifv_if;
252 1.26.2.2 jhawk int error;
253 1.26.2.2 jhawk
254 1.26.2.2 jhawk if (ifv->ifv_p != NULL)
255 1.26.2.2 jhawk return (EBUSY);
256 1.26.2.2 jhawk
257 1.26.2.2 jhawk switch (p->if_type) {
258 1.26.2.2 jhawk case IFT_ETHER:
259 1.26.2.2 jhawk {
260 1.26.2.2 jhawk struct ethercom *ec = (void *) p;
261 1.26.2.2 jhawk
262 1.26.2.2 jhawk ifv->ifv_msw = &vlan_ether_multisw;
263 1.26.2.2 jhawk ifv->ifv_encaplen = ETHER_VLAN_ENCAP_LEN;
264 1.26.2.2 jhawk ifv->ifv_mintu = ETHERMIN;
265 1.26.2.2 jhawk
266 1.26.2.2 jhawk /*
267 1.26.2.2 jhawk * If the parent supports the VLAN_MTU capability,
268 1.26.2.2 jhawk * i.e. can Tx/Rx larger than ETHER_MAX_LEN frames,
269 1.26.2.2 jhawk * enable it.
270 1.26.2.2 jhawk */
271 1.26.2.2 jhawk if (ec->ec_nvlans++ == 0 &&
272 1.26.2.2 jhawk (ec->ec_capabilities & ETHERCAP_VLAN_MTU) != 0) {
273 1.26.2.2 jhawk /*
274 1.26.2.2 jhawk * Enable Tx/Rx of VLAN-sized frames.
275 1.26.2.2 jhawk */
276 1.26.2.2 jhawk ec->ec_capenable |= ETHERCAP_VLAN_MTU;
277 1.26.2.2 jhawk if (p->if_flags & IFF_UP) {
278 1.26.2.2 jhawk struct ifreq ifr;
279 1.26.2.2 jhawk
280 1.26.2.2 jhawk ifr.ifr_flags = p->if_flags;
281 1.26.2.2 jhawk error = (*p->if_ioctl)(p, SIOCSIFFLAGS,
282 1.26.2.2 jhawk (caddr_t) &ifr);
283 1.26.2.2 jhawk if (error) {
284 1.26.2.2 jhawk if (ec->ec_nvlans-- == 1)
285 1.26.2.2 jhawk ec->ec_capenable &=
286 1.26.2.2 jhawk ~ETHERCAP_VLAN_MTU;
287 1.26.2.2 jhawk return (error);
288 1.26.2.2 jhawk }
289 1.26.2.2 jhawk }
290 1.26.2.2 jhawk ifv->ifv_mtufudge = 0;
291 1.26.2.2 jhawk } else if ((ec->ec_capabilities & ETHERCAP_VLAN_MTU) == 0) {
292 1.26.2.2 jhawk /*
293 1.26.2.2 jhawk * Fudge the MTU by the encapsulation size. This
294 1.26.2.2 jhawk * makes us incompatible with strictly compliant
295 1.26.2.2 jhawk * 802.1Q implementations, but allows us to use
296 1.26.2.2 jhawk * the feature with other NetBSD implementations,
297 1.26.2.2 jhawk * which might still be useful.
298 1.26.2.2 jhawk */
299 1.26.2.2 jhawk ifv->ifv_mtufudge = ifv->ifv_encaplen;
300 1.26.2.2 jhawk }
301 1.26.2.2 jhawk
302 1.26.2.2 jhawk /*
303 1.26.2.2 jhawk * We inherit the parent's Ethernet address.
304 1.26.2.2 jhawk */
305 1.26.2.2 jhawk ether_ifattach(ifp, LLADDR(p->if_sadl));
306 1.26.2.2 jhawk ifp->if_hdrlen = sizeof(struct ether_vlan_header); /* XXX? */
307 1.26.2.2 jhawk #if NBPFILTER > 0
308 1.26.2.2 jhawk bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB,
309 1.26.2.2 jhawk sizeof(struct ether_header));
310 1.26.2.2 jhawk #endif
311 1.26.2.2 jhawk break;
312 1.26.2.2 jhawk }
313 1.26.2.2 jhawk
314 1.26.2.2 jhawk default:
315 1.26.2.2 jhawk return (EPROTONOSUPPORT);
316 1.26.2.2 jhawk }
317 1.26.2.2 jhawk
318 1.26.2.2 jhawk ifv->ifv_p = p;
319 1.26.2.2 jhawk ifv->ifv_if.if_mtu = p->if_mtu - ifv->ifv_mtufudge;
320 1.26.2.2 jhawk ifv->ifv_if.if_flags = p->if_flags &
321 1.26.2.2 jhawk (IFF_UP | IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
322 1.26.2.2 jhawk
323 1.26.2.2 jhawk /*
324 1.26.2.2 jhawk * Inherit the if_type from the parent. This allows us
325 1.26.2.2 jhawk * to participate in bridges of that type.
326 1.26.2.2 jhawk */
327 1.26.2.2 jhawk ifv->ifv_if.if_type = p->if_type;
328 1.26.2.2 jhawk
329 1.26.2.2 jhawk return (0);
330 1.26.2.2 jhawk }
331 1.26.2.2 jhawk
332 1.26.2.2 jhawk /*
333 1.26.2.2 jhawk * Unconfigure a VLAN interface. Must be called at splnet().
334 1.26.2.2 jhawk */
335 1.26.2.2 jhawk static void
336 1.26.2.2 jhawk vlan_unconfig(struct ifnet *ifp)
337 1.26.2.2 jhawk {
338 1.26.2.2 jhawk struct ifvlan *ifv = ifp->if_softc;
339 1.26.2.2 jhawk
340 1.26.2.2 jhawk if (ifv->ifv_p == NULL)
341 1.26.2.2 jhawk return;
342 1.26.2.2 jhawk
343 1.26.2.2 jhawk /*
344 1.26.2.2 jhawk * Since the interface is being unconfigured, we need to empty the
345 1.26.2.2 jhawk * list of multicast groups that we may have joined while we were
346 1.26.2.2 jhawk * alive and remove them from the parent's list also.
347 1.26.2.2 jhawk */
348 1.26.2.2 jhawk (*ifv->ifv_msw->vmsw_purgemulti)(ifv);
349 1.26.2.2 jhawk
350 1.26.2.2 jhawk /* Disconnect from parent. */
351 1.26.2.2 jhawk switch (ifv->ifv_p->if_type) {
352 1.26.2.2 jhawk case IFT_ETHER:
353 1.26.2.2 jhawk {
354 1.26.2.2 jhawk struct ethercom *ec = (void *) ifv->ifv_p;
355 1.26.2.2 jhawk
356 1.26.2.2 jhawk if (ec->ec_nvlans-- == 1) {
357 1.26.2.2 jhawk /*
358 1.26.2.2 jhawk * Disable Tx/Rx of VLAN-sized frames.
359 1.26.2.2 jhawk */
360 1.26.2.2 jhawk ec->ec_capenable &= ~ETHERCAP_VLAN_MTU;
361 1.26.2.2 jhawk if (ifv->ifv_p->if_flags & IFF_UP) {
362 1.26.2.2 jhawk struct ifreq ifr;
363 1.26.2.2 jhawk
364 1.26.2.2 jhawk ifr.ifr_flags = ifv->ifv_p->if_flags;
365 1.26.2.2 jhawk (void) (*ifv->ifv_p->if_ioctl)(ifv->ifv_p,
366 1.26.2.2 jhawk SIOCSIFFLAGS, (caddr_t) &ifr);
367 1.26.2.2 jhawk }
368 1.26.2.2 jhawk }
369 1.26.2.2 jhawk
370 1.26.2.2 jhawk #if NBPFILTER > 0
371 1.26.2.2 jhawk bpfdetach(ifp);
372 1.26.2.2 jhawk #endif
373 1.26.2.2 jhawk ether_ifdetach(ifp);
374 1.26.2.2 jhawk break;
375 1.26.2.2 jhawk }
376 1.26.2.2 jhawk
377 1.26.2.2 jhawk #ifdef DIAGNOSTIC
378 1.26.2.2 jhawk default:
379 1.26.2.2 jhawk panic("vlan_unconfig: impossible");
380 1.26.2.2 jhawk #endif
381 1.26.2.2 jhawk }
382 1.26.2.2 jhawk
383 1.26.2.2 jhawk ifv->ifv_p = NULL;
384 1.26.2.2 jhawk ifv->ifv_if.if_mtu = 0;
385 1.26.2.2 jhawk ifv->ifv_flags = 0;
386 1.26.2.2 jhawk
387 1.26.2.2 jhawk if_down(ifp);
388 1.26.2.2 jhawk ifp->if_flags &= ~(IFF_UP|IFF_RUNNING);
389 1.26.2.2 jhawk }
390 1.26.2.2 jhawk
391 1.26.2.2 jhawk /*
392 1.26.2.2 jhawk * Called when a parent interface is detaching; destroy any VLAN
393 1.26.2.2 jhawk * configuration for the parent interface.
394 1.26.2.2 jhawk */
395 1.26.2.2 jhawk void
396 1.26.2.2 jhawk vlan_ifdetach(struct ifnet *p)
397 1.26.2.2 jhawk {
398 1.26.2.2 jhawk struct ifvlan *ifv;
399 1.26.2.2 jhawk int s;
400 1.26.2.2 jhawk
401 1.26.2.2 jhawk s = splnet();
402 1.26.2.2 jhawk
403 1.26.2.2 jhawk for (ifv = LIST_FIRST(&ifv_list); ifv != NULL;
404 1.26.2.2 jhawk ifv = LIST_NEXT(ifv, ifv_list)) {
405 1.26.2.2 jhawk if (ifv->ifv_p == p)
406 1.26.2.2 jhawk vlan_unconfig(&ifv->ifv_if);
407 1.26.2.2 jhawk }
408 1.26.2.2 jhawk
409 1.26.2.2 jhawk splx(s);
410 1.26.2.2 jhawk }
411 1.26.2.2 jhawk
412 1.26.2.2 jhawk static int
413 1.26.2.2 jhawk vlan_set_promisc(struct ifnet *ifp)
414 1.26.2.2 jhawk {
415 1.26.2.2 jhawk struct ifvlan *ifv = ifp->if_softc;
416 1.26.2.2 jhawk int error = 0;
417 1.26.2.2 jhawk
418 1.26.2.2 jhawk if ((ifp->if_flags & IFF_PROMISC) != 0) {
419 1.26.2.2 jhawk if ((ifv->ifv_flags & IFVF_PROMISC) == 0) {
420 1.26.2.2 jhawk error = ifpromisc(ifv->ifv_p, 1);
421 1.26.2.2 jhawk if (error == 0)
422 1.26.2.2 jhawk ifv->ifv_flags |= IFVF_PROMISC;
423 1.26.2.2 jhawk }
424 1.26.2.2 jhawk } else {
425 1.26.2.2 jhawk if ((ifv->ifv_flags & IFVF_PROMISC) != 0) {
426 1.26.2.2 jhawk error = ifpromisc(ifv->ifv_p, 0);
427 1.26.2.2 jhawk if (error == 0)
428 1.26.2.2 jhawk ifv->ifv_flags &= ~IFVF_PROMISC;
429 1.26.2.2 jhawk }
430 1.26.2.2 jhawk }
431 1.26.2.2 jhawk
432 1.26.2.2 jhawk return (error);
433 1.26.2.2 jhawk }
434 1.26.2.2 jhawk
435 1.26.2.2 jhawk static int
436 1.26.2.2 jhawk vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
437 1.26.2.2 jhawk {
438 1.26.2.2 jhawk struct proc *p = curproc; /* XXX */
439 1.26.2.2 jhawk struct ifvlan *ifv = ifp->if_softc;
440 1.26.2.2 jhawk struct ifaddr *ifa = (struct ifaddr *) data;
441 1.26.2.2 jhawk struct ifreq *ifr = (struct ifreq *) data;
442 1.26.2.2 jhawk struct ifnet *pr;
443 1.26.2.2 jhawk struct vlanreq vlr;
444 1.26.2.2 jhawk struct sockaddr *sa;
445 1.26.2.2 jhawk int s, error = 0;
446 1.26.2.2 jhawk
447 1.26.2.2 jhawk s = splnet();
448 1.26.2.2 jhawk
449 1.26.2.2 jhawk switch (cmd) {
450 1.26.2.2 jhawk case SIOCSIFADDR:
451 1.26.2.2 jhawk if (ifv->ifv_p != NULL) {
452 1.26.2.2 jhawk ifp->if_flags |= IFF_UP;
453 1.26.2.2 jhawk
454 1.26.2.2 jhawk switch (ifa->ifa_addr->sa_family) {
455 1.26.2.2 jhawk #ifdef INET
456 1.26.2.2 jhawk case AF_INET:
457 1.26.2.2 jhawk arp_ifinit(ifp, ifa);
458 1.26.2.2 jhawk break;
459 1.26.2.2 jhawk #endif
460 1.26.2.2 jhawk default:
461 1.26.2.2 jhawk break;
462 1.26.2.2 jhawk }
463 1.26.2.2 jhawk } else {
464 1.26.2.2 jhawk error = EINVAL;
465 1.26.2.2 jhawk }
466 1.26.2.2 jhawk break;
467 1.26.2.2 jhawk
468 1.26.2.2 jhawk case SIOCGIFADDR:
469 1.26.2.2 jhawk sa = (struct sockaddr *)&ifr->ifr_data;
470 1.26.2.2 jhawk memcpy(sa->sa_data, LLADDR(ifp->if_sadl), ETHER_ADDR_LEN);
471 1.26.2.2 jhawk break;
472 1.26.2.2 jhawk
473 1.26.2.2 jhawk case SIOCSIFMTU:
474 1.26.2.2 jhawk if (ifv->ifv_p != NULL) {
475 1.26.2.2 jhawk if (ifr->ifr_mtu >
476 1.26.2.2 jhawk (ifv->ifv_p->if_mtu - ifv->ifv_mtufudge) ||
477 1.26.2.2 jhawk ifr->ifr_mtu <
478 1.26.2.2 jhawk (ifv->ifv_mintu - ifv->ifv_mtufudge))
479 1.26.2.2 jhawk error = EINVAL;
480 1.26.2.2 jhawk else
481 1.26.2.2 jhawk ifp->if_mtu = ifr->ifr_mtu;
482 1.26.2.2 jhawk } else
483 1.26.2.2 jhawk error = EINVAL;
484 1.26.2.2 jhawk break;
485 1.26.2.2 jhawk
486 1.26.2.2 jhawk case SIOCSETVLAN:
487 1.26.2.2 jhawk if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
488 1.26.2.2 jhawk break;
489 1.26.2.2 jhawk if ((error = copyin(ifr->ifr_data, &vlr, sizeof(vlr))) != 0)
490 1.26.2.2 jhawk break;
491 1.26.2.2 jhawk if (vlr.vlr_parent[0] == '\0') {
492 1.26.2.2 jhawk vlan_unconfig(ifp);
493 1.26.2.2 jhawk break;
494 1.26.2.2 jhawk }
495 1.26.2.2 jhawk if (vlr.vlr_tag != EVL_VLANOFTAG(vlr.vlr_tag)) {
496 1.26.2.2 jhawk error = EINVAL; /* check for valid tag */
497 1.26.2.2 jhawk break;
498 1.26.2.2 jhawk }
499 1.26.2.2 jhawk if ((pr = ifunit(vlr.vlr_parent)) == 0) {
500 1.26.2.2 jhawk error = ENOENT;
501 1.26.2.2 jhawk break;
502 1.26.2.2 jhawk }
503 1.26.2.2 jhawk if ((error = vlan_config(ifv, pr)) != 0)
504 1.26.2.2 jhawk break;
505 1.26.2.2 jhawk ifv->ifv_tag = vlr.vlr_tag;
506 1.26.2.2 jhawk ifp->if_flags |= IFF_RUNNING;
507 1.26.2.2 jhawk
508 1.26.2.2 jhawk /* Update promiscuous mode, if necessary. */
509 1.26.2.2 jhawk vlan_set_promisc(ifp);
510 1.26.2.2 jhawk break;
511 1.26.2.2 jhawk
512 1.26.2.2 jhawk case SIOCGETVLAN:
513 1.26.2.2 jhawk memset(&vlr, 0, sizeof(vlr));
514 1.26.2.2 jhawk if (ifv->ifv_p != NULL) {
515 1.26.2.2 jhawk snprintf(vlr.vlr_parent, sizeof(vlr.vlr_parent), "%s",
516 1.26.2.2 jhawk ifv->ifv_p->if_xname);
517 1.26.2.2 jhawk vlr.vlr_tag = ifv->ifv_tag;
518 1.26.2.2 jhawk }
519 1.26.2.2 jhawk error = copyout(&vlr, ifr->ifr_data, sizeof(vlr));
520 1.26.2.2 jhawk break;
521 1.26.2.2 jhawk
522 1.26.2.2 jhawk case SIOCSIFFLAGS:
523 1.26.2.2 jhawk /*
524 1.26.2.2 jhawk * For promiscuous mode, we enable promiscuous mode on
525 1.26.2.2 jhawk * the parent if we need promiscuous on the VLAN interface.
526 1.26.2.2 jhawk */
527 1.26.2.2 jhawk if (ifv->ifv_p != NULL)
528 1.26.2.2 jhawk error = vlan_set_promisc(ifp);
529 1.26.2.2 jhawk break;
530 1.26.2.2 jhawk
531 1.26.2.2 jhawk case SIOCADDMULTI:
532 1.26.2.2 jhawk error = (ifv->ifv_p != NULL) ?
533 1.26.2.2 jhawk (*ifv->ifv_msw->vmsw_addmulti)(ifv, ifr) : EINVAL;
534 1.26.2.2 jhawk break;
535 1.26.2.2 jhawk
536 1.26.2.2 jhawk case SIOCDELMULTI:
537 1.26.2.2 jhawk error = (ifv->ifv_p != NULL) ?
538 1.26.2.2 jhawk (*ifv->ifv_msw->vmsw_delmulti)(ifv, ifr) : EINVAL;
539 1.26.2.2 jhawk break;
540 1.26.2.2 jhawk
541 1.26.2.2 jhawk default:
542 1.26.2.2 jhawk error = EINVAL;
543 1.26.2.2 jhawk }
544 1.26.2.2 jhawk
545 1.26.2.2 jhawk splx(s);
546 1.26.2.2 jhawk
547 1.26.2.2 jhawk return (error);
548 1.26.2.2 jhawk }
549 1.26.2.2 jhawk
550 1.26.2.2 jhawk static int
551 1.26.2.2 jhawk vlan_ether_addmulti(struct ifvlan *ifv, struct ifreq *ifr)
552 1.26.2.2 jhawk {
553 1.26.2.2 jhawk struct vlan_mc_entry *mc;
554 1.26.2.2 jhawk u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN];
555 1.26.2.2 jhawk int error;
556 1.26.2.2 jhawk
557 1.26.2.2 jhawk if (ifr->ifr_addr.sa_len > sizeof(struct sockaddr_storage))
558 1.26.2.2 jhawk return (EINVAL);
559 1.26.2.2 jhawk
560 1.26.2.2 jhawk error = ether_addmulti(ifr, &ifv->ifv_ec);
561 1.26.2.2 jhawk if (error != ENETRESET)
562 1.26.2.2 jhawk return (error);
563 1.26.2.2 jhawk
564 1.26.2.2 jhawk /*
565 1.26.2.2 jhawk * This is new multicast address. We have to tell parent
566 1.26.2.2 jhawk * about it. Also, remember this multicast address so that
567 1.26.2.2 jhawk * we can delete them on unconfigure.
568 1.26.2.2 jhawk */
569 1.26.2.2 jhawk MALLOC(mc, struct vlan_mc_entry *, sizeof(struct vlan_mc_entry),
570 1.26.2.2 jhawk M_DEVBUF, M_NOWAIT);
571 1.26.2.2 jhawk if (mc == NULL) {
572 1.26.2.2 jhawk error = ENOMEM;
573 1.26.2.2 jhawk goto alloc_failed;
574 1.26.2.2 jhawk }
575 1.26.2.2 jhawk
576 1.26.2.2 jhawk /*
577 1.26.2.2 jhawk * As ether_addmulti() returns ENETRESET, following two
578 1.26.2.2 jhawk * statement shouldn't fail.
579 1.26.2.2 jhawk */
580 1.26.2.2 jhawk (void)ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi);
581 1.26.2.2 jhawk ETHER_LOOKUP_MULTI(addrlo, addrhi, &ifv->ifv_ec, mc->mc_enm);
582 1.26.2.2 jhawk memcpy(&mc->mc_addr, &ifr->ifr_addr, ifr->ifr_addr.sa_len);
583 1.26.2.2 jhawk LIST_INSERT_HEAD(&ifv->ifv_mc_listhead, mc, mc_entries);
584 1.26.2.2 jhawk
585 1.26.2.2 jhawk error = (*ifv->ifv_p->if_ioctl)(ifv->ifv_p, SIOCADDMULTI,
586 1.26.2.2 jhawk (caddr_t)ifr);
587 1.26.2.2 jhawk if (error != 0)
588 1.26.2.2 jhawk goto ioctl_failed;
589 1.26.2.2 jhawk return (error);
590 1.26.2.2 jhawk
591 1.26.2.2 jhawk ioctl_failed:
592 1.26.2.2 jhawk LIST_REMOVE(mc, mc_entries);
593 1.26.2.2 jhawk FREE(mc, M_DEVBUF);
594 1.26.2.2 jhawk alloc_failed:
595 1.26.2.2 jhawk (void)ether_delmulti(ifr, &ifv->ifv_ec);
596 1.26.2.2 jhawk return (error);
597 1.26.2.2 jhawk }
598 1.26.2.2 jhawk
599 1.26.2.2 jhawk static int
600 1.26.2.2 jhawk vlan_ether_delmulti(struct ifvlan *ifv, struct ifreq *ifr)
601 1.26.2.2 jhawk {
602 1.26.2.2 jhawk struct ether_multi *enm;
603 1.26.2.2 jhawk struct vlan_mc_entry *mc;
604 1.26.2.2 jhawk u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN];
605 1.26.2.2 jhawk int error;
606 1.26.2.2 jhawk
607 1.26.2.2 jhawk /*
608 1.26.2.2 jhawk * Find a key to lookup vlan_mc_entry. We have to do this
609 1.26.2.2 jhawk * before calling ether_delmulti for obvious reason.
610 1.26.2.2 jhawk */
611 1.26.2.2 jhawk if ((error = ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi)) != 0)
612 1.26.2.2 jhawk return (error);
613 1.26.2.2 jhawk ETHER_LOOKUP_MULTI(addrlo, addrhi, &ifv->ifv_ec, enm);
614 1.26.2.2 jhawk
615 1.26.2.2 jhawk error = ether_delmulti(ifr, &ifv->ifv_ec);
616 1.26.2.2 jhawk if (error != ENETRESET)
617 1.26.2.2 jhawk return (error);
618 1.26.2.2 jhawk
619 1.26.2.2 jhawk /* We no longer use this multicast address. Tell parent so. */
620 1.26.2.2 jhawk error = (*ifv->ifv_p->if_ioctl)(ifv->ifv_p, SIOCDELMULTI,
621 1.26.2.2 jhawk (caddr_t)ifr);
622 1.26.2.2 jhawk if (error == 0) {
623 1.26.2.2 jhawk /* And forget about this address. */
624 1.26.2.2 jhawk for (mc = LIST_FIRST(&ifv->ifv_mc_listhead); mc != NULL;
625 1.26.2.2 jhawk mc = LIST_NEXT(mc, mc_entries)) {
626 1.26.2.2 jhawk if (mc->mc_enm == enm) {
627 1.26.2.2 jhawk LIST_REMOVE(mc, mc_entries);
628 1.26.2.2 jhawk FREE(mc, M_DEVBUF);
629 1.26.2.2 jhawk break;
630 1.26.2.2 jhawk }
631 1.26.2.2 jhawk }
632 1.26.2.2 jhawk KASSERT(mc != NULL);
633 1.26.2.2 jhawk } else
634 1.26.2.2 jhawk (void)ether_addmulti(ifr, &ifv->ifv_ec);
635 1.26.2.2 jhawk return (error);
636 1.26.2.2 jhawk }
637 1.26.2.2 jhawk
638 1.26.2.2 jhawk /*
639 1.26.2.2 jhawk * Delete any multicast address we have asked to add form parent
640 1.26.2.2 jhawk * interface. Called when the vlan is being unconfigured.
641 1.26.2.2 jhawk */
642 1.26.2.2 jhawk static void
643 1.26.2.2 jhawk vlan_ether_purgemulti(struct ifvlan *ifv)
644 1.26.2.2 jhawk {
645 1.26.2.2 jhawk struct ifnet *ifp = ifv->ifv_p; /* Parent. */
646 1.26.2.2 jhawk struct vlan_mc_entry *mc;
647 1.26.2.2 jhawk union {
648 1.26.2.2 jhawk struct ifreq ifreq;
649 1.26.2.2 jhawk struct {
650 1.26.2.2 jhawk char ifr_name[IFNAMSIZ];
651 1.26.2.2 jhawk struct sockaddr_storage ifr_ss;
652 1.26.2.2 jhawk } ifreq_storage;
653 1.26.2.2 jhawk } ifreq;
654 1.26.2.2 jhawk struct ifreq *ifr = &ifreq.ifreq;
655 1.26.2.2 jhawk
656 1.26.2.2 jhawk memcpy(ifr->ifr_name, ifp->if_xname, IFNAMSIZ);
657 1.26.2.2 jhawk while ((mc = LIST_FIRST(&ifv->ifv_mc_listhead)) != NULL) {
658 1.26.2.2 jhawk memcpy(&ifr->ifr_addr, &mc->mc_addr, mc->mc_addr.ss_len);
659 1.26.2.2 jhawk (void)(*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)ifr);
660 1.26.2.2 jhawk LIST_REMOVE(mc, mc_entries);
661 1.26.2.2 jhawk FREE(mc, M_DEVBUF);
662 1.26.2.2 jhawk }
663 1.26.2.2 jhawk }
664 1.26.2.2 jhawk
665 1.26.2.2 jhawk static void
666 1.26.2.2 jhawk vlan_start(struct ifnet *ifp)
667 1.26.2.2 jhawk {
668 1.26.2.2 jhawk struct ifvlan *ifv = ifp->if_softc;
669 1.26.2.2 jhawk struct ifnet *p = ifv->ifv_p;
670 1.26.2.2 jhawk struct ethercom *ec = (void *) ifv->ifv_p;
671 1.26.2.2 jhawk struct mbuf *m;
672 1.26.2.2 jhawk
673 1.26.2.2 jhawk ifp->if_flags |= IFF_OACTIVE;
674 1.26.2.2 jhawk
675 1.26.2.2 jhawk for (;;) {
676 1.26.2.2 jhawk IF_DEQUEUE(&ifp->if_snd, m);
677 1.26.2.2 jhawk if (m == NULL)
678 1.26.2.2 jhawk break;
679 1.26.2.2 jhawk
680 1.26.2.2 jhawk #if NBPFILTER > 0
681 1.26.2.2 jhawk if (ifp->if_bpf)
682 1.26.2.2 jhawk bpf_mtap(ifp->if_bpf, m);
683 1.26.2.2 jhawk #endif
684 1.26.2.2 jhawk /*
685 1.26.2.2 jhawk * If the parent can insert the tag itself, just mark
686 1.26.2.2 jhawk * the tag in the mbuf header.
687 1.26.2.2 jhawk */
688 1.26.2.2 jhawk if (ec->ec_capabilities & ETHERCAP_VLAN_HWTAGGING) {
689 1.26.2.2 jhawk struct mbuf *n;
690 1.26.2.2 jhawk n = m_aux_add(m, AF_LINK, ETHERTYPE_VLAN);
691 1.26.2.2 jhawk if (n == NULL) {
692 1.26.2.2 jhawk ifp->if_oerrors++;
693 1.26.2.2 jhawk m_freem(m);
694 1.26.2.2 jhawk continue;
695 1.26.2.2 jhawk }
696 1.26.2.2 jhawk *mtod(n, int *) = ifv->ifv_tag;
697 1.26.2.2 jhawk n->m_len = sizeof(int);
698 1.26.2.2 jhawk } else {
699 1.26.2.2 jhawk /*
700 1.26.2.2 jhawk * insert the tag ourselve
701 1.26.2.2 jhawk */
702 1.26.2.2 jhawk M_PREPEND(m, ifv->ifv_encaplen, M_DONTWAIT);
703 1.26.2.2 jhawk if (m == NULL) {
704 1.26.2.2 jhawk printf("%s: unable to prepend encap header",
705 1.26.2.2 jhawk ifv->ifv_p->if_xname);
706 1.26.2.2 jhawk ifp->if_oerrors++;
707 1.26.2.2 jhawk continue;
708 1.26.2.2 jhawk }
709 1.26.2.2 jhawk
710 1.26.2.2 jhawk switch (p->if_type) {
711 1.26.2.2 jhawk case IFT_ETHER:
712 1.26.2.2 jhawk {
713 1.26.2.2 jhawk struct ether_vlan_header *evl;
714 1.26.2.2 jhawk
715 1.26.2.2 jhawk if (m->m_len < sizeof(struct ether_vlan_header))
716 1.26.2.2 jhawk m = m_pullup(m,
717 1.26.2.2 jhawk sizeof(struct ether_vlan_header));
718 1.26.2.2 jhawk if (m == NULL) {
719 1.26.2.2 jhawk printf("%s: unable to pullup encap "
720 1.26.2.2 jhawk "header", ifv->ifv_p->if_xname);
721 1.26.2.2 jhawk ifp->if_oerrors++;
722 1.26.2.2 jhawk continue;
723 1.26.2.2 jhawk }
724 1.26.2.2 jhawk
725 1.26.2.2 jhawk /*
726 1.26.2.2 jhawk * Transform the Ethernet header into an
727 1.26.2.2 jhawk * Ethernet header with 802.1Q encapsulation.
728 1.26.2.2 jhawk */
729 1.26.2.2 jhawk memmove(mtod(m, caddr_t),
730 1.26.2.2 jhawk mtod(m, caddr_t) + ifv->ifv_encaplen,
731 1.26.2.2 jhawk sizeof(struct ether_header));
732 1.26.2.2 jhawk evl = mtod(m, struct ether_vlan_header *);
733 1.26.2.2 jhawk evl->evl_proto = evl->evl_encap_proto;
734 1.26.2.2 jhawk evl->evl_encap_proto = htons(ETHERTYPE_VLAN);
735 1.26.2.2 jhawk evl->evl_tag = htons(ifv->ifv_tag);
736 1.26.2.2 jhawk break;
737 1.26.2.2 jhawk }
738 1.26.2.2 jhawk
739 1.26.2.2 jhawk #ifdef DIAGNOSTIC
740 1.26.2.2 jhawk default:
741 1.26.2.2 jhawk panic("vlan_start: impossible");
742 1.26.2.2 jhawk #endif
743 1.26.2.2 jhawk }
744 1.26.2.2 jhawk }
745 1.26.2.2 jhawk
746 1.26.2.2 jhawk /*
747 1.26.2.2 jhawk * Send it, precisely as the parent's output routine
748 1.26.2.2 jhawk * would have. We are already running at splimp.
749 1.26.2.2 jhawk */
750 1.26.2.2 jhawk if (IF_QFULL(&p->if_snd)) {
751 1.26.2.2 jhawk IF_DROP(&p->if_snd);
752 1.26.2.2 jhawk /* XXX stats */
753 1.26.2.2 jhawk ifp->if_oerrors++;
754 1.26.2.2 jhawk m_freem(m);
755 1.26.2.2 jhawk continue;
756 1.26.2.2 jhawk }
757 1.26.2.2 jhawk
758 1.26.2.2 jhawk IF_ENQUEUE(&p->if_snd, m);
759 1.26.2.2 jhawk ifp->if_opackets++;
760 1.26.2.2 jhawk if ((p->if_flags & IFF_OACTIVE) == 0) {
761 1.26.2.2 jhawk (*p->if_start)(p);
762 1.26.2.2 jhawk }
763 1.26.2.2 jhawk }
764 1.26.2.2 jhawk
765 1.26.2.2 jhawk ifp->if_flags &= ~IFF_OACTIVE;
766 1.26.2.2 jhawk }
767 1.26.2.2 jhawk
768 1.26.2.2 jhawk /*
769 1.26.2.2 jhawk * Given an Ethernet frame, find a valid vlan interface corresponding to the
770 1.26.2.2 jhawk * given source interface and tag, then run the the real packet through
771 1.26.2.2 jhawk * the parent's input routine.
772 1.26.2.2 jhawk */
773 1.26.2.2 jhawk void
774 1.26.2.2 jhawk vlan_input(struct ifnet *ifp, struct mbuf *m)
775 1.26.2.2 jhawk {
776 1.26.2.2 jhawk struct ifvlan *ifv;
777 1.26.2.2 jhawk u_int tag;
778 1.26.2.2 jhawk struct mbuf *n;
779 1.26.2.2 jhawk
780 1.26.2.2 jhawk n = m_aux_find(m, AF_LINK, ETHERTYPE_VLAN);
781 1.26.2.2 jhawk if (n) {
782 1.26.2.2 jhawk /* m contains a normal ethernet frame, the tag is in m_aux */
783 1.26.2.2 jhawk tag = *mtod(n, int *);
784 1.26.2.2 jhawk m_aux_delete(m, n);
785 1.26.2.2 jhawk for (ifv = LIST_FIRST(&ifv_list); ifv != NULL;
786 1.26.2.2 jhawk ifv = LIST_NEXT(ifv, ifv_list))
787 1.26.2.2 jhawk if (ifp == ifv->ifv_p && tag == ifv->ifv_tag)
788 1.26.2.2 jhawk break;
789 1.26.2.2 jhawk } else {
790 1.26.2.2 jhawk switch (ifp->if_type) {
791 1.26.2.2 jhawk case IFT_ETHER:
792 1.26.2.2 jhawk {
793 1.26.2.2 jhawk struct ether_vlan_header *evl;
794 1.26.2.2 jhawk
795 1.26.2.2 jhawk if (m->m_len < sizeof(struct ether_vlan_header) &&
796 1.26.2.2 jhawk (m = m_pullup(m,
797 1.26.2.2 jhawk sizeof(struct ether_vlan_header))) == NULL) {
798 1.26.2.2 jhawk printf("%s: no memory for VLAN header, "
799 1.26.2.2 jhawk "dropping packet.\n", ifp->if_xname);
800 1.26.2.2 jhawk return;
801 1.26.2.2 jhawk }
802 1.26.2.2 jhawk evl = mtod(m, struct ether_vlan_header *);
803 1.26.2.2 jhawk KASSERT(ntohs(evl->evl_encap_proto) == ETHERTYPE_VLAN);
804 1.26.2.2 jhawk
805 1.26.2.2 jhawk tag = EVL_VLANOFTAG(ntohs(evl->evl_tag));
806 1.26.2.2 jhawk
807 1.26.2.2 jhawk /*
808 1.26.2.2 jhawk * Restore the original ethertype. We'll remove
809 1.26.2.2 jhawk * the encapsulation after we've found the vlan
810 1.26.2.2 jhawk * interface corresponding to the tag.
811 1.26.2.2 jhawk */
812 1.26.2.2 jhawk evl->evl_encap_proto = evl->evl_proto;
813 1.26.2.2 jhawk break;
814 1.26.2.2 jhawk }
815 1.26.2.2 jhawk
816 1.26.2.2 jhawk default:
817 1.26.2.2 jhawk tag = (u_int) -1; /* XXX GCC */
818 1.26.2.2 jhawk #ifdef DIAGNOSTIC
819 1.26.2.2 jhawk panic("vlan_input: impossible");
820 1.26.2.2 jhawk #endif
821 1.26.2.2 jhawk }
822 1.26.2.2 jhawk
823 1.26.2.2 jhawk for (ifv = LIST_FIRST(&ifv_list); ifv != NULL;
824 1.26.2.2 jhawk ifv = LIST_NEXT(ifv, ifv_list))
825 1.26.2.2 jhawk if (ifp == ifv->ifv_p && tag == ifv->ifv_tag)
826 1.26.2.2 jhawk break;
827 1.26.2.2 jhawk
828 1.26.2.2 jhawk
829 1.26.2.2 jhawk /*
830 1.26.2.2 jhawk * Now, remove the encapsulation header. The original
831 1.26.2.2 jhawk * header has already been fixed up above.
832 1.26.2.2 jhawk */
833 1.26.2.2 jhawk if (ifv) {
834 1.26.2.2 jhawk memmove(mtod(m, caddr_t) + ifv->ifv_encaplen,
835 1.26.2.2 jhawk mtod(m, caddr_t), sizeof(struct ether_header));
836 1.26.2.2 jhawk m_adj(m, ifv->ifv_encaplen);
837 1.26.2.2 jhawk }
838 1.26.2.2 jhawk }
839 1.26.2.2 jhawk
840 1.26.2.2 jhawk if (ifv == NULL ||
841 1.26.2.2 jhawk (ifv->ifv_if.if_flags & (IFF_UP|IFF_RUNNING)) !=
842 1.26.2.2 jhawk (IFF_UP|IFF_RUNNING)) {
843 1.26.2.2 jhawk m_free(m);
844 1.26.2.2 jhawk ifp->if_noproto++;
845 1.26.2.2 jhawk return;
846 1.26.2.2 jhawk }
847 1.26.2.2 jhawk m->m_pkthdr.rcvif = &ifv->ifv_if;
848 1.26.2.2 jhawk ifv->ifv_if.if_ipackets++;
849 1.26.2.2 jhawk
850 1.26.2.2 jhawk #if NBPFILTER > 0
851 1.26.2.2 jhawk if (ifv->ifv_if.if_bpf)
852 1.26.2.2 jhawk bpf_mtap(ifv->ifv_if.if_bpf, m);
853 1.26.2.2 jhawk #endif
854 1.26.2.2 jhawk
855 1.26.2.2 jhawk /* Pass it back through the parent's input routine. */
856 1.26.2.2 jhawk (*ifp->if_input)(&ifv->ifv_if, m);
857 1.26.2.2 jhawk }
858