|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: * Copyright 1998 Massachusetts Institute of Technology
24: *
25: * Permission to use, copy, modify, and distribute this software and
26: * its documentation for any purpose and without fee is hereby
27: * granted, provided that both the above copyright notice and this
28: * permission notice appear in all copies, that both the above
29: * copyright notice and this permission notice appear in all
30: * supporting documentation, and that the name of M.I.T. not be used
31: * in advertising or publicity pertaining to distribution of the
32: * software without specific, written prior permission. M.I.T. makes
33: * no representations about the suitability of this software for any
34: * purpose. It is provided "as is" without express or implied
35: * warranty.
36: *
37: * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
38: * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
39: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
40: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
41: * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48: * SUCH DAMAGE.
49: *
50: */
51:
52: /*
53: * if_vlan.c - pseudo-device driver for IEEE 802.1Q virtual LANs.
54: * Might be extended some day to also handle IEEE 802.1p priority
55: * tagging. This is sort of sneaky in the implementation, since
56: * we need to pretend to be enough of an Ethernet implementation
57: * to make arp work. The way we do this is by telling everyone
58: * that we are an Ethernet, and then catch the packets that
59: * ether_output() left on our output queue queue when it calls
60: * if_start(), rewrite them for use by the real outgoing interface,
61: * and ask it to send them.
62: *
63: *
64: * XXX It's incorrect to assume that we must always kludge up
65: * headers on the physical device's behalf: some devices support
66: * VLAN tag insersion and extraction in firmware. For these cases,
67: * one can change the behavior of the vlan interface by setting
68: * the LINK0 flag on it (that is setting the vlan interface's LINK0
69: * flag, _not_ the parent's LINK0 flag; we try to leave the parent
70: * alone). If the interface as the LINK0 flag set, then it will
71: * not modify the ethernet header on output because the parent
72: * can do that for itself. On input, the parent can call vlan_input_tag()
73: * directly in order to supply us with an incoming mbuf and the vlan
74: * tag value that goes with it.
75: */
76:
77: #include "vlan.h"
78: #if NVLAN > 0
79: #include "opt_inet.h"
80: #include "bpfilter.h"
81:
82: #include <sys/param.h>
83: #include <sys/kernel.h>
84: #include <sys/mbuf.h>
85: #include <sys/socket.h>
86: #include <sys/sockio.h>
87: #include <sys/sysctl.h>
88: #include <sys/systm.h>
89:
90: #if NBPFILTER > 0
91: #include <net/bpf.h>
92: #endif
93: #include <net/ethernet.h>
94: #include <net/if.h>
95: #include <net/if_arp.h>
96: #include <net/if_dl.h>
97: #include <net/if_types.h>
98: #include <net/if_vlan_var.h>
99:
100: #if INET
101: #include <netinet/in.h>
102: #include <netinet/if_ether.h>
103: #endif
104:
105: SYSCTL_DECL(_net_link);
106: SYSCTL_NODE(_net_link, IFT_8021_VLAN, vlan, CTLFLAG_RW, 0, "IEEE 802.1Q VLAN");
107: SYSCTL_NODE(_net_link_vlan, PF_LINK, link, CTLFLAG_RW, 0, "for consistency");
108:
109: u_int vlan_proto = ETHERTYPE_VLAN;
110: SYSCTL_INT(_net_link_vlan_link, VLANCTL_PROTO, proto, CTLFLAG_RW, &vlan_proto,
111: 0, "Ethernet protocol used for VLAN encapsulation");
112:
113: static struct ifvlan ifv_softc[NVLAN];
114:
115: static void vlan_start(struct ifnet *ifp);
116: static void vlan_ifinit(void *foo);
117: static int vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr);
118: static int vlan_setmulti(struct ifnet *ifp);
119: static int vlan_unconfig(struct ifnet *ifp);
120: static int vlan_config(struct ifvlan *ifv, struct ifnet *p);
121:
122: /*
123: * Program our multicast filter. What we're actually doing is
124: * programming the multicast filter of the parent. This has the
125: * side effect of causing the parent interface to receive multicast
126: * traffic that it doesn't really want, which ends up being discarded
127: * later by the upper protocol layers. Unfortunately, there's no way
128: * to avoid this: there really is only one physical interface.
129: */
130: static int vlan_setmulti(struct ifnet *ifp)
131: {
132: struct ifnet *ifp_p;
133: struct ifmultiaddr *ifma, *rifma = NULL;
134: struct ifvlan *sc;
135: struct vlan_mc_entry *mc = NULL;
136: struct sockaddr_dl sdl;
137: int error;
138:
139: /* Find the parent. */
140: sc = ifp->if_softc;
141: ifp_p = sc->ifv_p;
142:
143: sdl.sdl_len = ETHER_ADDR_LEN;
144: sdl.sdl_family = AF_LINK;
145:
146: /* First, remove any existing filter entries. */
147: while(sc->vlan_mc_listhead.slh_first != NULL) {
148: mc = sc->vlan_mc_listhead.slh_first;
149: bcopy((char *)&mc->mc_addr, LLADDR(&sdl), ETHER_ADDR_LEN);
150: error = if_delmulti(ifp_p, (struct sockaddr *)&sdl);
151: if (error)
152: return(error);
153: SLIST_REMOVE_HEAD(&sc->vlan_mc_listhead, mc_entries);
154: FREE(mc, M_DEVBUF);
155: }
156:
157: /* Now program new ones. */
158: for (ifma = ifp->if_multiaddrs.lh_first;
159: ifma != NULL;ifma = ifma->ifma_link.le_next) {
160: if (ifma->ifma_addr->sa_family != AF_LINK)
161: continue;
162: mc = _MALLOC(sizeof(struct vlan_mc_entry), M_DEVBUF, M_NOWAIT);
163: bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
164: (char *)&mc->mc_addr, ETHER_ADDR_LEN);
165: SLIST_INSERT_HEAD(&sc->vlan_mc_listhead, mc, mc_entries);
166: error = if_addmulti(ifp_p, (struct sockaddr *)&sdl, &rifma);
167: if (error)
168: return(error);
169: }
170:
171: return(0);
172: }
173:
174: static void
175: vlaninit(void *dummy)
176: {
177: int i;
178:
179: for (i = 0; i < NVLAN; i++) {
180: struct ifnet *ifp = &ifv_softc[i].ifv_if;
181:
182: ifp->if_softc = &ifv_softc[i];
183: ifp->if_name = "vlan";
184: ifp->if_family = APPLE_IF_FAM_VLAN;
185: ifp->if_unit = i;
186: /* NB: flags are not set here */
187: ifp->if_linkmib = &ifv_softc[i].ifv_mib;
188: ifp->if_linkmiblen = sizeof ifv_softc[i].ifv_mib;
189: /* NB: mtu is not set here */
190:
191: ifp->if_init = vlan_ifinit;
192: ifp->if_start = vlan_start;
193: ifp->if_ioctl = vlan_ioctl;
194: ifp->if_output = ether_output;
195: ifp->if_snd.ifq_maxlen = ifqmaxlen;
196: if_attach(ifp);
197: ether_ifattach(ifp);
198: #if NBPFILTER > 0
199: bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
200: #endif
201: /* Now undo some of the damage... */
202: ifp->if_data.ifi_type = IFT_8021_VLAN;
203: ifp->if_data.ifi_hdrlen = EVL_ENCAPLEN;
204: ifp->if_resolvemulti = 0;
205: }
206: }
207: PSEUDO_SET(vlaninit, if_vlan);
208:
209: static void
210: vlan_ifinit(void *foo)
211: {
212: return;
213: }
214:
215: static void
216: vlan_start(struct ifnet *ifp)
217: {
218: struct ifvlan *ifv;
219: struct ifnet *p;
220: struct ether_vlan_header *evl;
221: struct mbuf *m;
222:
223: ifv = ifp->if_softc;
224: p = ifv->ifv_p;
225:
226: ifp->if_flags |= IFF_OACTIVE;
227: for (;;) {
228: IF_DEQUEUE(&ifp->if_snd, m);
229: if (m == 0)
230: break;
231: #if NBPFILTER > 0
232: if (ifp->if_bpf)
233: bpf_mtap(ifp, m);
234: #endif /* NBPFILTER > 0 */
235:
236: /*
237: * If the LINK0 flag is set, it means the underlying interface
238: * can do VLAN tag insertion itself and doesn't require us to
239: * create a special header for it. In this case, we just pass
240: * the packet along. However, we need some way to tell the
241: * interface where the packet came from so that it knows how
242: * to find the VLAN tag to use, so we set the rcvif in the
243: * mbuf header to our ifnet.
244: *
245: * Note: we also set the M_PROTO1 flag in the mbuf to let
246: * the parent driver know that the rcvif pointer is really
247: * valid. We need to do this because sometimes mbufs will
248: * be allocated by other parts of the system that contain
249: * garbage in the rcvif pointer. Using the M_PROTO1 flag
250: * lets the driver perform a proper sanity check and avoid
251: * following potentially bogus rcvif pointers off into
252: * never-never land.
253: */
254: if (ifp->if_flags & IFF_LINK0) {
255: m->m_pkthdr.rcvif = ifp;
256: m->m_flags |= M_PROTO1;
257: } else {
258: M_PREPEND(m, EVL_ENCAPLEN, M_DONTWAIT);
259: if (m == 0)
260: continue;
261: /* M_PREPEND takes care of m_len, m_pkthdr.len for us */
262:
263: /*
264: * Transform the Ethernet header into an Ethernet header
265: * with 802.1Q encapsulation.
266: */
267: bcopy(mtod(m, char *) + EVL_ENCAPLEN, mtod(m, char *),
268: sizeof(struct ether_header));
269: evl = mtod(m, struct ether_vlan_header *);
270: evl->evl_proto = evl->evl_encap_proto;
271: evl->evl_encap_proto = htons(vlan_proto);
272: evl->evl_tag = htons(ifv->ifv_tag);
273: #ifdef DEBUG
274: printf("vlan_start: %*D\n", sizeof *evl,
275: (char *)evl, ":");
276: #endif
277: }
278:
279: /*
280: * Send it, precisely as ether_output() would have.
281: * We are already running at splimp.
282: */
283: if (IF_QFULL(&p->if_snd)) {
284: IF_DROP(&p->if_snd);
285: /* XXX stats */
286: ifp->if_oerrors++;
287: m_freem(m);
288: continue;
289: }
290: IF_ENQUEUE(&p->if_snd, m);
291: if ((p->if_flags & IFF_OACTIVE) == 0) {
292: p->if_start(p);
293: ifp->if_opackets++;
294: }
295: }
296: ifp->if_flags &= ~IFF_OACTIVE;
297:
298: return;
299: }
300:
301: void
302: vlan_input_tag(struct ether_header *eh, struct mbuf *m, u_int16_t t)
303: {
304: int i;
305: struct ifvlan *ifv;
306:
307: for (i = 0; i < NVLAN; i++) {
308: ifv = &ifv_softc[i];
309: if (ifv->ifv_tag == t)
310: break;
311: }
312:
313: if (i >= NVLAN || (ifv->ifv_if.if_flags & IFF_UP) == 0) {
314: m_freem(m);
315: ifv->ifv_p->if_data.ifi_noproto++;
316: return;
317: }
318:
319: /*
320: * Having found a valid vlan interface corresponding to
321: * the given source interface and vlan tag, run the
322: * the real packet through ethert_input().
323: */
324: m->m_pkthdr.rcvif = &ifv->ifv_if;
325:
326: #if NBPFILTER > 0
327: if (ifv->ifv_if.if_bpf) {
328: /*
329: * Do the usual BPF fakery. Note that we don't support
330: * promiscuous mode here, since it would require the
331: * drivers to know about VLANs and we're not ready for
332: * that yet.
333: */
334: struct mbuf m0;
335: m0.m_next = m;
336: m0.m_len = sizeof(struct ether_header);
337: m0.m_data = (char *)eh;
338: bpf_mtap(&ifv->ifv_if, &m0);
339: }
340: #endif
341: ifv->ifv_if.if_ipackets++;
342: ether_input(&ifv->ifv_if, eh, m);
343: return;
344: }
345:
346: int
347: vlan_input(struct ether_header *eh, struct mbuf *m)
348: {
349: int i;
350: struct ifvlan *ifv;
351:
352: for (i = 0; i < NVLAN; i++) {
353: ifv = &ifv_softc[i];
354: if (m->m_pkthdr.rcvif == ifv->ifv_p
355: && (EVL_VLANOFTAG(ntohs(*mtod(m, u_int16_t *)))
356: == ifv->ifv_tag))
357: break;
358: }
359:
360: if (i >= NVLAN || (ifv->ifv_if.if_flags & IFF_UP) == 0) {
361: m_freem(m);
362: return -1; /* so ether_input can take note */
363: }
364:
365: /*
366: * Having found a valid vlan interface corresponding to
367: * the given source interface and vlan tag, remove the
368: * encapsulation, and run the real packet through
369: * ether_input() a second time (it had better be
370: * reentrant!).
371: */
372: m->m_pkthdr.rcvif = &ifv->ifv_if;
373: eh->ether_type = mtod(m, u_int16_t *)[1];
374: m->m_data += EVL_ENCAPLEN;
375: m->m_len -= EVL_ENCAPLEN;
376: m->m_pkthdr.len -= EVL_ENCAPLEN;
377:
378: #if NBPFILTER > 0
379: if (ifv->ifv_if.if_bpf) {
380: /*
381: * Do the usual BPF fakery. Note that we don't support
382: * promiscuous mode here, since it would require the
383: * drivers to know about VLANs and we're not ready for
384: * that yet.
385: */
386: struct mbuf m0;
387: m0.m_next = m;
388: m0.m_len = sizeof(struct ether_header);
389: m0.m_data = (char *)eh;
390: bpf_mtap(&ifv->ifv_if, &m0);
391: }
392: #endif
393: ifv->ifv_if.if_ipackets++;
394: ether_input(&ifv->ifv_if, eh, m);
395: return 0;
396: }
397:
398: static int
399: vlan_config(struct ifvlan *ifv, struct ifnet *p)
400: {
401: struct ifaddr *ifa1, *ifa2;
402: struct sockaddr_dl *sdl1, *sdl2;
403:
404: if (p->if_data.ifi_type != IFT_ETHER)
405: return EPROTONOSUPPORT;
406: if (ifv->ifv_p)
407: return EBUSY;
408: ifv->ifv_p = p;
409: if (p->if_data.ifi_hdrlen == sizeof(struct ether_vlan_header))
410: ifv->ifv_if.if_mtu = p->if_mtu;
411: else
412: ifv->ifv_if.if_mtu = p->if_data.ifi_mtu - EVL_ENCAPLEN;
413:
414: /*
415: * Preserve the state of the LINK0 flag for ourselves.
416: */
417: ifv->ifv_if.if_flags = (p->if_flags & ~(IFF_LINK0));
418:
419: /*
420: * Set up our ``Ethernet address'' to reflect the underlying
421: * physical interface's.
422: */
423: ifa1 = ifnet_addrs[ifv->ifv_if.if_index - 1];
424: ifa2 = ifnet_addrs[p->if_index - 1];
425: sdl1 = (struct sockaddr_dl *)ifa1->ifa_addr;
426: sdl2 = (struct sockaddr_dl *)ifa2->ifa_addr;
427: sdl1->sdl_type = IFT_ETHER;
428: sdl1->sdl_alen = ETHER_ADDR_LEN;
429: bcopy(LLADDR(sdl2), LLADDR(sdl1), ETHER_ADDR_LEN);
430: bcopy(LLADDR(sdl2), ifv->ifv_ac.ac_enaddr, ETHER_ADDR_LEN);
431: return 0;
432: }
433:
434: static int
435: vlan_unconfig(struct ifnet *ifp)
436: {
437: struct ifaddr *ifa;
438: struct sockaddr_dl *sdl;
439: struct vlan_mc_entry *mc;
440: struct ifvlan *ifv;
441: struct ifnet *p;
442: int error;
443:
444: ifv = ifp->if_softc;
445: p = ifv->ifv_p;
446:
447: /*
448: * Since the interface is being unconfigured, we need to
449: * empty the list of multicast groups that we may have joined
450: * while we were alive and remove them from the parent's list
451: * as well.
452: */
453: while(ifv->vlan_mc_listhead.slh_first != NULL) {
454: struct sockaddr_dl sdl;
455:
456: sdl.sdl_len = ETHER_ADDR_LEN;
457: sdl.sdl_family = AF_LINK;
458: mc = ifv->vlan_mc_listhead.slh_first;
459: bcopy((char *)&mc->mc_addr, LLADDR(&sdl), ETHER_ADDR_LEN);
460: error = if_delmulti(p, (struct sockaddr *)&sdl);
461: error = if_delmulti(ifp, (struct sockaddr *)&sdl);
462: if (error)
463: return(error);
464: SLIST_REMOVE_HEAD(&ifv->vlan_mc_listhead, mc_entries);
465: FREE(mc, M_DEVBUF);
466: }
467:
468: /* Disconnect from parent. */
469: ifv->ifv_p = NULL;
470: ifv->ifv_if.if_mtu = ETHERMTU;
471:
472: /* Clear our MAC address. */
473: ifa = ifnet_addrs[ifv->ifv_if.if_index - 1];
474: sdl = (struct sockaddr_dl *)ifa->ifa_addr;
475: sdl->sdl_type = IFT_ETHER;
476: sdl->sdl_alen = ETHER_ADDR_LEN;
477: bzero(LLADDR(sdl), ETHER_ADDR_LEN);
478: bzero(ifv->ifv_ac.ac_enaddr, ETHER_ADDR_LEN);
479:
480: return 0;
481: }
482:
483: static int
484: vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
485: {
486: struct ifaddr *ifa;
487: struct ifnet *p;
488: struct ifreq *ifr;
489: struct ifvlan *ifv;
490: struct vlanreq vlr;
491: int error = 0;
492:
493: ifr = (struct ifreq *)data;
494: ifa = (struct ifaddr *)data;
495: ifv = ifp->if_softc;
496:
497: switch (cmd) {
498: case SIOCSIFADDR:
499: ifp->if_flags |= IFF_UP;
500:
501: switch (ifa->ifa_addr->sa_family) {
502: #if INET
503: case AF_INET:
504: arp_ifinit(&ifv->ifv_ac, ifa);
505: break;
506: #endif
507: default:
508: break;
509: }
510: break;
511:
512: case SIOCGIFADDR:
513: {
514: struct sockaddr *sa;
515:
516: sa = (struct sockaddr *) &ifr->ifr_data;
517: bcopy(((struct arpcom *)ifp->if_softc)->ac_enaddr,
518: (caddr_t) sa->sa_data, ETHER_ADDR_LEN);
519: }
520: break;
521:
522: case SIOCSIFMTU:
523: /*
524: * Set the interface MTU.
525: * This is bogus. The underlying interface might support
526: * jumbo frames.
527: */
528: if (ifr->ifr_mtu > ETHERMTU) {
529: error = EINVAL;
530: } else {
531: ifp->if_mtu = ifr->ifr_mtu;
532: }
533: break;
534:
535: case SIOCSETVLAN:
536: error = copyin(ifr->ifr_data, &vlr, sizeof vlr);
537: if (error)
538: break;
539: if (vlr.vlr_parent[0] == '\0') {
540: vlan_unconfig(ifp);
541: if_down(ifp);
542: ifp->if_flags = 0;
543: break;
544: }
545: p = ifunit(vlr.vlr_parent);
546: if (p == 0) {
547: error = ENOENT;
548: break;
549: }
550: error = vlan_config(ifv, p);
551: if (error)
552: break;
553: ifv->ifv_tag = vlr.vlr_tag;
554: break;
555:
556: case SIOCGETVLAN:
557: bzero(&vlr, sizeof vlr);
558: if (ifv->ifv_p) {
559: snprintf(vlr.vlr_parent, sizeof(vlr.vlr_parent),
560: "%s%d", ifv->ifv_p->if_name, ifv->ifv_p->if_unit);
561: vlr.vlr_tag = ifv->ifv_tag;
562: }
563: error = copyout(&vlr, ifr->ifr_data, sizeof vlr);
564: break;
565:
566: case SIOCSIFFLAGS:
567: /*
568: * We don't support promiscuous mode
569: * right now because it would require help from the
570: * underlying drivers, which hasn't been implemented.
571: */
572: if (ifr->ifr_flags & (IFF_PROMISC)) {
573: ifp->if_flags &= ~(IFF_PROMISC);
574: error = EINVAL;
575: }
576: break;
577: case SIOCADDMULTI:
578: case SIOCDELMULTI:
579: error = vlan_setmulti(ifp);
580: break;
581: default:
582: error = EINVAL;
583: }
584: return error;
585: }
586:
587: #endif /* NVLAN > 0 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.