if_bridge.c revision 1.2.2.2 1 /* $NetBSD: if_bridge.c,v 1.2.2.2 2001/08/24 00:12:08 nathanw Exp $ */
2
3 /*
4 * Copyright 2001 Wasabi Systems, Inc.
5 * All rights reserved.
6 *
7 * Written by Jason R. Thorpe for Wasabi Systems, Inc.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed for the NetBSD Project by
20 * Wasabi Systems, Inc.
21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22 * or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 */
37
38 /*
39 * Copyright (c) 1999, 2000 Jason L. Wright (jason (at) thought.net)
40 * All rights reserved.
41 *
42 * Redistribution and use in source and binary forms, with or without
43 * modification, are permitted provided that the following conditions
44 * are met:
45 * 1. Redistributions of source code must retain the above copyright
46 * notice, this list of conditions and the following disclaimer.
47 * 2. Redistributions in binary form must reproduce the above copyright
48 * notice, this list of conditions and the following disclaimer in the
49 * documentation and/or other materials provided with the distribution.
50 * 3. All advertising materials mentioning features or use of this software
51 * must display the following acknowledgement:
52 * This product includes software developed by Jason L. Wright
53 * 4. The name of the author may not be used to endorse or promote products
54 * derived from this software without specific prior written permission.
55 *
56 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
57 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
58 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
59 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
60 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
61 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
62 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
63 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
64 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
65 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
66 * POSSIBILITY OF SUCH DAMAGE.
67 *
68 * OpenBSD: if_bridge.c,v 1.60 2001/06/15 03:38:33 itojun Exp
69 */
70
71 /*
72 * Network interface bridge support.
73 *
74 * TODO:
75 *
76 * - Currently only supports Ethernet-like interfaces (Ethernet,
77 * 802.11, VLANs on Ethernet, etc.) Figure out a nice way
78 * to bridge other types of interfaces (FDDI-FDDI, and maybe
79 * consider heterogenous bridges).
80 *
81 * - Add packet filter hooks.
82 */
83
84 #include "bpfilter.h"
85 #include "rnd.h"
86
87 #include <sys/param.h>
88 #include <sys/kernel.h>
89 #include <sys/mbuf.h>
90 #include <sys/queue.h>
91 #include <sys/socket.h>
92 #include <sys/sockio.h>
93 #include <sys/systm.h>
94 #include <sys/proc.h>
95 #include <sys/pool.h>
96
97 #if NRND > 0
98 #include <sys/rnd.h>
99 #endif
100
101 #if NBPFILTER > 0
102 #include <net/bpf.h>
103 #endif
104 #include <net/if.h>
105 #include <net/if_dl.h>
106 #include <net/if_types.h>
107 #include <net/if_llc.h>
108
109 #include <net/if_ether.h>
110 #include <net/if_bridgevar.h>
111
112 /*
113 * Size of the route hash table. Must be a power of two.
114 */
115 #ifndef BRIDGE_RTHASH_SIZE
116 #define BRIDGE_RTHASH_SIZE 1024
117 #endif
118
119 #define BRIDGE_RTHASH_MASK (BRIDGE_RTHASH_SIZE - 1)
120
121 /*
122 * Maximum number of addresses to cache.
123 */
124 #ifndef BRIDGE_RTABLE_MAX
125 #define BRIDGE_RTABLE_MAX 100
126 #endif
127
128 /*
129 * Spanning tree defaults.
130 */
131 #define BSTP_DEFAULT_MAX_AGE (20 * 256)
132 #define BSTP_DEFAULT_HELLO_TIME (2 * 256)
133 #define BSTP_DEFAULT_FORWARD_DELAY (15 * 256)
134 #define BSTP_DEFAULT_HOLD_TIME (1 * 256)
135 #define BSTP_DEFAULT_BRIDGE_PRIORITY 0x8000
136 #define BSTP_DEFAULT_PORT_PRIORITY 0x80
137 #define BSTP_DEFAULT_PATH_COST 55
138
139 /*
140 * Timeout (in seconds) for entries learned dynamically.
141 */
142 #ifndef BRIDGE_RTABLE_TIMEOUT
143 #define BRIDGE_RTABLE_TIMEOUT (20 * 60) /* same as ARP */
144 #endif
145
146 /*
147 * Number of seconds between walks of the route list.
148 */
149 #ifndef BRIDGE_RTABLE_PRUNE_PERIOD
150 #define BRIDGE_RTABLE_PRUNE_PERIOD (5 * 60)
151 #endif
152
153 int bridge_rtable_prune_period = BRIDGE_RTABLE_PRUNE_PERIOD;
154
155 struct pool bridge_rtnode_pool;
156
157 void bridgeattach(int);
158
159 int bridge_clone_create(struct if_clone *, int);
160 void bridge_clone_destroy(struct ifnet *);
161
162 int bridge_ioctl(struct ifnet *, u_long, caddr_t);
163 int bridge_init(struct ifnet *);
164 void bridge_stop(struct ifnet *, int);
165 void bridge_start(struct ifnet *);
166
167 void bridge_forward(struct bridge_softc *, struct mbuf *m);
168
169 void bridge_timer(void *);
170
171 void bridge_broadcast(struct bridge_softc *, struct ifnet *, struct mbuf *);
172
173 int bridge_rtupdate(struct bridge_softc *, const uint8_t *,
174 struct ifnet *, int, uint8_t);
175 struct ifnet *bridge_rtlookup(struct bridge_softc *, const uint8_t *);
176 void bridge_rttrim(struct bridge_softc *);
177 void bridge_rtage(struct bridge_softc *);
178 void bridge_rtflush(struct bridge_softc *, int);
179 int bridge_rtdaddr(struct bridge_softc *, const uint8_t *);
180 void bridge_rtdelete(struct bridge_softc *, struct ifnet *ifp);
181
182 int bridge_rtable_init(struct bridge_softc *);
183 void bridge_rtable_fini(struct bridge_softc *);
184
185 struct bridge_rtnode *bridge_rtnode_lookup(struct bridge_softc *,
186 const uint8_t *);
187 int bridge_rtnode_insert(struct bridge_softc *, struct bridge_rtnode *);
188 void bridge_rtnode_destroy(struct bridge_softc *, struct bridge_rtnode *);
189
190 struct bridge_iflist *bridge_lookup_member(struct bridge_softc *,
191 const char *name);
192 void bridge_delete_member(struct bridge_softc *, struct bridge_iflist *);
193
194 int bridge_ioctl_add(struct bridge_softc *, void *);
195 int bridge_ioctl_del(struct bridge_softc *, void *);
196 int bridge_ioctl_gifflags(struct bridge_softc *, void *);
197 int bridge_ioctl_sifflags(struct bridge_softc *, void *);
198 int bridge_ioctl_scache(struct bridge_softc *, void *);
199 int bridge_ioctl_gcache(struct bridge_softc *, void *);
200 int bridge_ioctl_gifs(struct bridge_softc *, void *);
201 int bridge_ioctl_rts(struct bridge_softc *, void *);
202 int bridge_ioctl_saddr(struct bridge_softc *, void *);
203 int bridge_ioctl_sto(struct bridge_softc *, void *);
204 int bridge_ioctl_gto(struct bridge_softc *, void *);
205 int bridge_ioctl_daddr(struct bridge_softc *, void *);
206 int bridge_ioctl_flush(struct bridge_softc *, void *);
207 int bridge_ioctl_gpri(struct bridge_softc *, void *);
208 int bridge_ioctl_spri(struct bridge_softc *, void *);
209 int bridge_ioctl_ght(struct bridge_softc *, void *);
210 int bridge_ioctl_sht(struct bridge_softc *, void *);
211 int bridge_ioctl_gfd(struct bridge_softc *, void *);
212 int bridge_ioctl_sfd(struct bridge_softc *, void *);
213 int bridge_ioctl_gma(struct bridge_softc *, void *);
214 int bridge_ioctl_sma(struct bridge_softc *, void *);
215 int bridge_ioctl_sifprio(struct bridge_softc *, void *);
216
217 struct bridge_control {
218 int (*bc_func)(struct bridge_softc *, void *);
219 int bc_argsize;
220 int bc_flags;
221 };
222
223 #define BC_F_COPYIN 0x01 /* copy arguments in */
224 #define BC_F_COPYOUT 0x02 /* copy arguments out */
225 #define BC_F_SUSER 0x04 /* do super-user check */
226
227 const struct bridge_control bridge_control_table[] = {
228 { bridge_ioctl_add, sizeof(struct ifbreq),
229 BC_F_COPYIN|BC_F_SUSER },
230 { bridge_ioctl_del, sizeof(struct ifbreq),
231 BC_F_COPYIN|BC_F_SUSER },
232
233 { bridge_ioctl_gifflags, sizeof(struct ifbreq),
234 BC_F_COPYIN|BC_F_COPYOUT },
235 { bridge_ioctl_sifflags, sizeof(struct ifbreq),
236 BC_F_COPYIN|BC_F_SUSER },
237
238 { bridge_ioctl_scache, sizeof(struct ifbrparam),
239 BC_F_COPYIN|BC_F_SUSER },
240 { bridge_ioctl_gcache, sizeof(struct ifbrparam),
241 BC_F_COPYOUT },
242
243 { bridge_ioctl_gifs, sizeof(struct ifbifconf),
244 BC_F_COPYIN|BC_F_COPYOUT },
245 { bridge_ioctl_rts, sizeof(struct ifbaconf),
246 BC_F_COPYIN|BC_F_COPYOUT },
247
248 { bridge_ioctl_saddr, sizeof(struct ifbareq),
249 BC_F_COPYIN|BC_F_SUSER },
250
251 { bridge_ioctl_sto, sizeof(struct ifbrparam),
252 BC_F_COPYIN|BC_F_SUSER },
253 { bridge_ioctl_gto, sizeof(struct ifbrparam),
254 BC_F_COPYOUT },
255
256 { bridge_ioctl_daddr, sizeof(struct ifbareq),
257 BC_F_COPYIN|BC_F_SUSER },
258
259 { bridge_ioctl_flush, sizeof(struct ifbreq),
260 BC_F_COPYIN|BC_F_SUSER },
261
262 { bridge_ioctl_gpri, sizeof(struct ifbrparam),
263 BC_F_COPYOUT },
264 { bridge_ioctl_spri, sizeof(struct ifbrparam),
265 BC_F_COPYIN|BC_F_SUSER },
266
267 { bridge_ioctl_ght, sizeof(struct ifbrparam),
268 BC_F_COPYOUT },
269 { bridge_ioctl_sht, sizeof(struct ifbrparam),
270 BC_F_COPYIN|BC_F_SUSER },
271
272 { bridge_ioctl_gfd, sizeof(struct ifbrparam),
273 BC_F_COPYOUT },
274 { bridge_ioctl_sfd, sizeof(struct ifbrparam),
275 BC_F_COPYIN|BC_F_SUSER },
276
277 { bridge_ioctl_gma, sizeof(struct ifbrparam),
278 BC_F_COPYOUT },
279 { bridge_ioctl_sma, sizeof(struct ifbrparam),
280 BC_F_COPYIN|BC_F_SUSER },
281
282 { bridge_ioctl_sifprio, sizeof(struct ifbreq),
283 BC_F_COPYIN|BC_F_SUSER },
284 };
285 const int bridge_control_table_size =
286 sizeof(bridge_control_table) / sizeof(bridge_control_table[0]);
287
288 LIST_HEAD(, bridge_softc) bridge_list;
289
290 struct if_clone bridge_cloner =
291 IF_CLONE_INITIALIZER("bridge", bridge_clone_create, bridge_clone_destroy);
292
293 /*
294 * bridgeattach:
295 *
296 * Pseudo-device attach routine.
297 */
298 void
299 bridgeattach(int n)
300 {
301
302 pool_init(&bridge_rtnode_pool, sizeof(struct bridge_rtnode),
303 0, 0, 0, "brtpl", 0, NULL, NULL, 0);
304
305 LIST_INIT(&bridge_list);
306 if_clone_attach(&bridge_cloner);
307 }
308
309 /*
310 * bridge_clone_create:
311 *
312 * Create a new bridge instance.
313 */
314 int
315 bridge_clone_create(struct if_clone *ifc, int unit)
316 {
317 struct bridge_softc *sc;
318 struct ifnet *ifp;
319 int s;
320
321 sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK);
322 memset(sc, 0, sizeof(*sc));
323 ifp = &sc->sc_if;
324
325 sc->sc_brtmax = BRIDGE_RTABLE_MAX;
326 sc->sc_brttimeout = BRIDGE_RTABLE_TIMEOUT;
327 sc->sc_bridge_max_age = BSTP_DEFAULT_MAX_AGE;
328 sc->sc_bridge_hello_time = BSTP_DEFAULT_HELLO_TIME;
329 sc->sc_bridge_forward_delay = BSTP_DEFAULT_FORWARD_DELAY;
330 sc->sc_bridge_priority = BSTP_DEFAULT_BRIDGE_PRIORITY;
331 sc->sc_hold_time = BSTP_DEFAULT_HOLD_TIME;
332
333 /* Initialize our routing table. */
334 bridge_rtable_init(sc);
335
336 callout_init(&sc->sc_brcallout);
337 callout_init(&sc->sc_bstpcallout);
338
339 LIST_INIT(&sc->sc_iflist);
340
341 sprintf(ifp->if_xname, "%s%d", ifc->ifc_name, unit);
342 ifp->if_softc = sc;
343 ifp->if_mtu = ETHERMTU;
344 ifp->if_ioctl = bridge_ioctl;
345 ifp->if_output = bridge_output;
346 ifp->if_start = bridge_start;
347 ifp->if_stop = bridge_stop;
348 ifp->if_init = bridge_init;
349 ifp->if_type = IFT_PROPVIRTUAL; /* XXX IFT_BRIDGE */
350 ifp->if_addrlen = 0;
351 ifp->if_dlt = DLT_EN10MB;
352 ifp->if_hdrlen = ETHER_HDR_LEN;
353
354 if_attach(ifp);
355
356 if_alloc_sadl(ifp);
357
358 s = splnet();
359 LIST_INSERT_HEAD(&bridge_list, sc, sc_list);
360 splx(s);
361
362 return (0);
363 }
364
365 /*
366 * bridge_clone_destroy:
367 *
368 * Destroy a bridge instance.
369 */
370 void
371 bridge_clone_destroy(struct ifnet *ifp)
372 {
373 struct bridge_softc *sc = ifp->if_softc;
374 struct bridge_iflist *bif;
375 int s;
376
377 s = splnet();
378
379 bridge_stop(ifp, 1);
380
381 while ((bif = LIST_FIRST(&sc->sc_iflist)) != NULL)
382 bridge_delete_member(sc, bif);
383
384 LIST_REMOVE(sc, sc_list);
385
386 splx(s);
387
388 if_detach(ifp);
389
390 /* Tear down the routing table. */
391 bridge_rtable_fini(sc);
392
393 free(sc, M_DEVBUF);
394 }
395
396 /*
397 * bridge_ioctl:
398 *
399 * Handle a control request from the operator.
400 */
401 int
402 bridge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
403 {
404 struct bridge_softc *sc = ifp->if_softc;
405 struct proc *p = curproc; /* XXX */
406 union {
407 struct ifbreq ifbreq;
408 struct ifbifconf ifbifconf;
409 struct ifbareq ifbareq;
410 struct ifbaconf ifbaconf;
411 struct ifbrparam ifbrparam;
412 } args;
413 struct ifdrv *ifd = (struct ifdrv *) data;
414 const struct bridge_control *bc;
415 int s, error = 0;
416
417 s = splnet();
418
419 switch (cmd) {
420 case SIOCGDRVSPEC:
421 case SIOCSDRVSPEC:
422 if (ifd->ifd_cmd >= bridge_control_table_size) {
423 error = EINVAL;
424 break;
425 }
426 bc = &bridge_control_table[ifd->ifd_cmd];
427
428 if (cmd == SIOCGDRVSPEC &&
429 (bc->bc_flags & BC_F_COPYOUT) == 0)
430 return (EINVAL);
431 else if (cmd == SIOCSDRVSPEC &&
432 (bc->bc_flags & BC_F_COPYOUT) != 0)
433 return (EINVAL);
434
435 if (bc->bc_flags & BC_F_SUSER) {
436 error = suser(p->p_ucred, &p->p_acflag);
437 if (error)
438 break;
439 }
440
441 if (ifd->ifd_len != bc->bc_argsize ||
442 ifd->ifd_len > sizeof(args)) {
443 error = EINVAL;
444 break;
445 }
446
447 if (bc->bc_flags & BC_F_COPYIN) {
448 error = copyin(ifd->ifd_data, &args, ifd->ifd_len);
449 if (error)
450 break;
451 }
452
453 error = (*bc->bc_func)(sc, &args);
454 if (error)
455 break;
456
457 if (bc->bc_flags & BC_F_COPYOUT)
458 error = copyout(&args, ifd->ifd_data, ifd->ifd_len);
459
460 break;
461
462 case SIOCSIFFLAGS:
463 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) == IFF_RUNNING) {
464 /*
465 * If interface is marked down and it is running,
466 * then stop and disable it.
467 */
468 (*ifp->if_stop)(ifp, 1);
469 } else if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) == IFF_UP) {
470 /*
471 * If interface is marked up and it is stopped, then
472 * start it.
473 */
474 error = (*ifp->if_init)(ifp);
475 }
476 break;
477
478 default:
479 error = ENOTTY;
480 break;
481 }
482
483 splx(s);
484
485 return (error);
486 }
487
488 /*
489 * bridge_lookup_member:
490 *
491 * Lookup a bridge member interface. Must be called at splnet().
492 */
493 struct bridge_iflist *
494 bridge_lookup_member(struct bridge_softc *sc, const char *name)
495 {
496 struct bridge_iflist *bif;
497 struct ifnet *ifp;
498
499 LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
500 ifp = bif->bif_ifp;
501 if (strcmp(ifp->if_xname, name) == 0)
502 return (bif);
503 }
504
505 return (NULL);
506 }
507
508 /*
509 * bridge_delete_member:
510 *
511 * Delete the specified member interface.
512 */
513 void
514 bridge_delete_member(struct bridge_softc *sc, struct bridge_iflist *bif)
515 {
516 struct ifnet *ifs = bif->bif_ifp;
517
518 switch (ifs->if_type) {
519 case IFT_ETHER:
520 /*
521 * Take the interface out of promiscuous mode.
522 */
523 (void) ifpromisc(ifs, 0);
524 break;
525
526 default:
527 #ifdef DIAGNOSTIC
528 panic("bridge_delete_member: impossible");
529 #endif
530 break;
531 }
532
533 ifs->if_bridge = NULL;
534 LIST_REMOVE(bif, bif_next);
535
536 bridge_rtdelete(sc, ifs);
537
538 free(bif, M_DEVBUF);
539
540 if (sc->sc_if.if_flags & IFF_RUNNING)
541 bstp_initialization(sc);
542 }
543
544 int
545 bridge_ioctl_add(struct bridge_softc *sc, void *arg)
546 {
547 struct ifbreq *req = arg;
548 struct bridge_iflist *bif = NULL;
549 struct ifnet *ifs;
550 int error = 0;
551
552 ifs = ifunit(req->ifbr_ifsname);
553 if (ifs == NULL)
554 return (ENOENT);
555
556 if (ifs->if_bridge == sc)
557 return (EEXIST);
558
559 if (ifs->if_bridge != NULL)
560 return (EBUSY);
561
562 bif = malloc(sizeof(*bif), M_DEVBUF, M_NOWAIT);
563 if (bif == NULL)
564 return (ENOMEM);
565
566 switch (ifs->if_type) {
567 case IFT_ETHER:
568 /*
569 * Place the interface into promiscuous mode.
570 */
571 error = ifpromisc(ifs, 1);
572 if (error)
573 goto out;
574 break;
575
576 default:
577 return (EINVAL);
578 }
579
580 bif->bif_ifp = ifs;
581 bif->bif_flags = IFBIF_LEARNING | IFBIF_DISCOVER;
582 bif->bif_priority = BSTP_DEFAULT_PORT_PRIORITY;
583 bif->bif_path_cost = BSTP_DEFAULT_PATH_COST;
584
585 ifs->if_bridge = sc;
586 LIST_INSERT_HEAD(&sc->sc_iflist, bif, bif_next);
587
588 if (sc->sc_if.if_flags & IFF_RUNNING)
589 bstp_initialization(sc);
590 else
591 bstp_stop(sc);
592
593 out:
594 if (error) {
595 if (bif != NULL)
596 free(bif, M_DEVBUF);
597 }
598 return (error);
599 }
600
601 int
602 bridge_ioctl_del(struct bridge_softc *sc, void *arg)
603 {
604 struct ifbreq *req = arg;
605 struct bridge_iflist *bif;
606
607 bif = bridge_lookup_member(sc, req->ifbr_ifsname);
608 if (bif == NULL)
609 return (ENOENT);
610
611 bridge_delete_member(sc, bif);
612
613 return (0);
614 }
615
616 int
617 bridge_ioctl_gifflags(struct bridge_softc *sc, void *arg)
618 {
619 struct ifbreq *req = arg;
620 struct bridge_iflist *bif;
621
622 bif = bridge_lookup_member(sc, req->ifbr_ifsname);
623 if (bif == NULL)
624 return (ENOENT);
625
626 req->ifbr_ifsflags = bif->bif_flags;
627 req->ifbr_state = bif->bif_state;
628 req->ifbr_priority = bif->bif_priority;
629 req->ifbr_portno = bif->bif_ifp->if_index & 0xff;
630
631 return (0);
632 }
633
634 int
635 bridge_ioctl_sifflags(struct bridge_softc *sc, void *arg)
636 {
637 struct ifbreq *req = arg;
638 struct bridge_iflist *bif;
639
640 bif = bridge_lookup_member(sc, req->ifbr_ifsname);
641 if (bif == NULL)
642 return (ENOENT);
643
644 if (req->ifbr_ifsflags & IFBIF_STP) {
645 switch (bif->bif_ifp->if_type) {
646 case IFT_ETHER:
647 /* These can do spanning tree. */
648 break;
649
650 default:
651 /* Nothing else can. */
652 return (EINVAL);
653 }
654 }
655
656 bif->bif_flags = req->ifbr_ifsflags;
657
658 if (sc->sc_if.if_flags & IFF_RUNNING)
659 bstp_initialization(sc);
660
661 return (0);
662 }
663
664 int
665 bridge_ioctl_scache(struct bridge_softc *sc, void *arg)
666 {
667 struct ifbrparam *param = arg;
668
669 sc->sc_brtmax = param->ifbrp_csize;
670 bridge_rttrim(sc);
671
672 return (0);
673 }
674
675 int
676 bridge_ioctl_gcache(struct bridge_softc *sc, void *arg)
677 {
678 struct ifbrparam *param = arg;
679
680 param->ifbrp_csize = sc->sc_brtmax;
681
682 return (0);
683 }
684
685 int
686 bridge_ioctl_gifs(struct bridge_softc *sc, void *arg)
687 {
688 struct ifbifconf *bifc = arg;
689 struct bridge_iflist *bif;
690 struct ifbreq breq;
691 int count, len, error = 0;
692
693 count = 0;
694 LIST_FOREACH(bif, &sc->sc_iflist, bif_next)
695 count++;
696
697 if (bifc->ifbic_len == 0) {
698 bifc->ifbic_len = sizeof(breq) * count;
699 return (0);
700 }
701
702 count = 0;
703 len = bifc->ifbic_len;
704 LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
705 if (len < sizeof(breq))
706 break;
707
708 strcpy(breq.ifbr_ifsname, bif->bif_ifp->if_xname);
709 breq.ifbr_ifsflags = bif->bif_flags;
710 breq.ifbr_state = bif->bif_state;
711 breq.ifbr_priority = bif->bif_priority;
712 breq.ifbr_portno = bif->bif_ifp->if_index & 0xff;
713 error = copyout(&breq, bifc->ifbic_req + count, sizeof(breq));
714 if (error)
715 break;
716 count++;
717 len -= sizeof(breq);
718 }
719
720 bifc->ifbic_len = sizeof(breq) * count;
721 return (error);
722 }
723
724 int
725 bridge_ioctl_rts(struct bridge_softc *sc, void *arg)
726 {
727 struct ifbaconf *bac = arg;
728 struct bridge_rtnode *brt;
729 struct ifbareq bareq;
730 int count = 0, error = 0, len;
731
732 if (bac->ifbac_len == 0)
733 return (0);
734
735 len = bac->ifbac_len;
736 LIST_FOREACH(brt, &sc->sc_rtlist, brt_list) {
737 if (len < sizeof(bareq))
738 goto out;
739 strcpy(bareq.ifba_ifsname, brt->brt_ifp->if_xname);
740 memcpy(bareq.ifba_dst, brt->brt_addr, sizeof(brt->brt_addr));
741 if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC)
742 bareq.ifba_expire = brt->brt_expire - mono_time.tv_sec;
743 else
744 bareq.ifba_expire = 0;
745 bareq.ifba_flags = brt->brt_flags;
746
747 error = copyout(&bareq, bac->ifbac_req + count, sizeof(bareq));
748 if (error)
749 goto out;
750 count++;
751 len -= sizeof(bareq);
752 }
753 out:
754 bac->ifbac_len = sizeof(bareq) * count;
755 return (error);
756 }
757
758 int
759 bridge_ioctl_saddr(struct bridge_softc *sc, void *arg)
760 {
761 struct ifbareq *req = arg;
762 struct bridge_iflist *bif;
763 int error;
764
765 bif = bridge_lookup_member(sc, req->ifba_ifsname);
766 if (bif == NULL)
767 return (ENOENT);
768
769 error = bridge_rtupdate(sc, req->ifba_dst, bif->bif_ifp, 1,
770 req->ifba_flags);
771
772 return (error);
773 }
774
775 int
776 bridge_ioctl_sto(struct bridge_softc *sc, void *arg)
777 {
778 struct ifbrparam *param = arg;
779
780 sc->sc_brttimeout = param->ifbrp_ctime;
781
782 return (0);
783 }
784
785 int
786 bridge_ioctl_gto(struct bridge_softc *sc, void *arg)
787 {
788 struct ifbrparam *param = arg;
789
790 param->ifbrp_ctime = sc->sc_brttimeout;
791
792 return (0);
793 }
794
795 int
796 bridge_ioctl_daddr(struct bridge_softc *sc, void *arg)
797 {
798 struct ifbareq *req = arg;
799
800 return (bridge_rtdaddr(sc, req->ifba_dst));
801 }
802
803 int
804 bridge_ioctl_flush(struct bridge_softc *sc, void *arg)
805 {
806 struct ifbreq *req = arg;
807
808 bridge_rtflush(sc, req->ifbr_ifsflags);
809
810 return (0);
811 }
812
813 int
814 bridge_ioctl_gpri(struct bridge_softc *sc, void *arg)
815 {
816 struct ifbrparam *param = arg;
817
818 param->ifbrp_prio = sc->sc_bridge_priority;
819
820 return (0);
821 }
822
823 int
824 bridge_ioctl_spri(struct bridge_softc *sc, void *arg)
825 {
826 struct ifbrparam *param = arg;
827
828 sc->sc_bridge_priority = param->ifbrp_prio;
829
830 if (sc->sc_if.if_flags & IFF_RUNNING)
831 bstp_initialization(sc);
832
833 return (0);
834 }
835
836 int
837 bridge_ioctl_ght(struct bridge_softc *sc, void *arg)
838 {
839 struct ifbrparam *param = arg;
840
841 param->ifbrp_hellotime = sc->sc_bridge_hello_time >> 8;
842
843 return (0);
844 }
845
846 int
847 bridge_ioctl_sht(struct bridge_softc *sc, void *arg)
848 {
849 struct ifbrparam *param = arg;
850
851 if (param->ifbrp_hellotime == 0)
852 return (EINVAL);
853 sc->sc_bridge_hello_time = param->ifbrp_hellotime << 8;
854
855 if (sc->sc_if.if_flags & IFF_RUNNING)
856 bstp_initialization(sc);
857
858 return (0);
859 }
860
861 int
862 bridge_ioctl_gfd(struct bridge_softc *sc, void *arg)
863 {
864 struct ifbrparam *param = arg;
865
866 param->ifbrp_fwddelay = sc->sc_bridge_forward_delay >> 8;
867
868 return (0);
869 }
870
871 int
872 bridge_ioctl_sfd(struct bridge_softc *sc, void *arg)
873 {
874 struct ifbrparam *param = arg;
875
876 if (param->ifbrp_fwddelay == 0)
877 return (EINVAL);
878 sc->sc_bridge_forward_delay = param->ifbrp_fwddelay << 8;
879
880 if (sc->sc_if.if_flags & IFF_RUNNING)
881 bstp_initialization(sc);
882
883 return (0);
884 }
885
886 int
887 bridge_ioctl_gma(struct bridge_softc *sc, void *arg)
888 {
889 struct ifbrparam *param = arg;
890
891 param->ifbrp_maxage = sc->sc_bridge_max_age >> 8;
892
893 return (0);
894 }
895
896 int
897 bridge_ioctl_sma(struct bridge_softc *sc, void *arg)
898 {
899 struct ifbrparam *param = arg;
900
901 if (param->ifbrp_maxage == 0)
902 return (EINVAL);
903 sc->sc_bridge_max_age = param->ifbrp_maxage << 8;
904
905 if (sc->sc_if.if_flags & IFF_RUNNING)
906 bstp_initialization(sc);
907
908 return (0);
909 }
910
911 int
912 bridge_ioctl_sifprio(struct bridge_softc *sc, void *arg)
913 {
914 struct ifbreq *req = arg;
915 struct bridge_iflist *bif;
916
917 bif = bridge_lookup_member(sc, req->ifbr_ifsname);
918 if (bif == NULL)
919 return (ENOENT);
920
921 bif->bif_priority = req->ifbr_priority;
922
923 if (sc->sc_if.if_flags & IFF_RUNNING)
924 bstp_initialization(sc);
925
926 return (0);
927 }
928
929 /*
930 * bridge_ifdetach:
931 *
932 * Detach an interface from a bridge. Called when a member
933 * interface is detaching.
934 */
935 void
936 bridge_ifdetach(struct ifnet *ifp)
937 {
938 struct bridge_softc *sc = ifp->if_bridge;
939 struct ifbreq breq;
940
941 memset(&breq, 0, sizeof(breq));
942 sprintf(breq.ifbr_ifsname, ifp->if_xname);
943
944 (void) bridge_ioctl_del(sc, &breq);
945 }
946
947 /*
948 * bridge_init:
949 *
950 * Initialize a bridge interface.
951 */
952 int
953 bridge_init(struct ifnet *ifp)
954 {
955 struct bridge_softc *sc = ifp->if_softc;
956
957 if (ifp->if_flags & IFF_RUNNING)
958 return (0);
959
960 callout_reset(&sc->sc_brcallout, bridge_rtable_prune_period * hz,
961 bridge_timer, sc);
962
963 ifp->if_flags |= IFF_RUNNING;
964 return (0);
965 }
966
967 /*
968 * bridge_stop:
969 *
970 * Stop the bridge interface.
971 */
972 void
973 bridge_stop(struct ifnet *ifp, int disable)
974 {
975 struct bridge_softc *sc = ifp->if_softc;
976
977 if ((ifp->if_flags & IFF_RUNNING) == 0)
978 return;
979
980 callout_stop(&sc->sc_brcallout);
981 bstp_stop(sc);
982
983 IF_PURGE(&ifp->if_snd);
984
985 bridge_rtflush(sc, IFBF_FLUSHDYN);
986
987 ifp->if_flags &= ~IFF_RUNNING;
988 }
989
990 /*
991 * bridge_enqueue:
992 *
993 * Enqueue a packet on a bridge member interface.
994 *
995 * NOTE: must be called at splnet().
996 */
997 __inline void
998 bridge_enqueue(struct bridge_softc *sc, struct ifnet *dst_ifp, struct mbuf *m)
999 {
1000 ALTQ_DECL(struct altq_pktattr pktattr;)
1001 int len, error;
1002 short mflags;
1003
1004 #ifdef ALTQ
1005 /*
1006 * If ALTQ is enabled on the member interface, do
1007 * classification; the queueing discipline might
1008 * not require classification, but might require
1009 * the address family/header pointer in the pktattr.
1010 */
1011 if (ALTQ_IS_ENABLED(&dst_ifp->if_snd)) {
1012 /* XXX IFT_ETHER */
1013 altq_etherclassify(&dst_ifp->if_snd, m, &pktattr);
1014 }
1015 #endif /* ALTQ */
1016
1017 len = m->m_pkthdr.len;
1018 mflags = m->m_flags;
1019 IFQ_ENQUEUE(&dst_ifp->if_snd, m, &pktattr, error);
1020 if (error) {
1021 /* mbuf is already freed */
1022 sc->sc_if.if_oerrors++;
1023 return;
1024 }
1025
1026 sc->sc_if.if_opackets++;
1027 sc->sc_if.if_obytes += len;
1028
1029 dst_ifp->if_obytes += len;
1030
1031 if (mflags & M_MCAST) {
1032 sc->sc_if.if_omcasts++;
1033 dst_ifp->if_omcasts++;
1034 }
1035
1036 if ((dst_ifp->if_flags & IFF_OACTIVE) == 0)
1037 (*dst_ifp->if_start)(dst_ifp);
1038 }
1039
1040 /*
1041 * bridge_output:
1042 *
1043 * Send output from a bridge member interface. This
1044 * performs the bridging function for locally originated
1045 * packets.
1046 *
1047 * The mbuf has the Ethernet header already attached. We must
1048 * enqueue or free the mbuf before returning.
1049 */
1050 int
1051 bridge_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa,
1052 struct rtentry *rt)
1053 {
1054 struct ether_header *eh;
1055 struct ifnet *dst_if;
1056 struct bridge_softc *sc;
1057 int s;
1058
1059 if (m->m_len < ETHER_HDR_LEN) {
1060 m = m_pullup(m, ETHER_HDR_LEN);
1061 if (m == NULL)
1062 return (0);
1063 }
1064
1065 eh = mtod(m, struct ether_header *);
1066 sc = ifp->if_bridge;
1067
1068 s = splnet();
1069
1070 /*
1071 * If bridge is down, but the original output interface is up,
1072 * go ahead and send out that interface. Otherwise, the packet
1073 * is dropped below.
1074 */
1075 if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) {
1076 dst_if = ifp;
1077 goto sendunicast;
1078 }
1079
1080 /*
1081 * If the packet is a multicast, or we don't know a better way to
1082 * get there, send to all interfaces.
1083 */
1084 if (ETHER_IS_MULTICAST(eh->ether_dhost))
1085 dst_if = NULL;
1086 else
1087 dst_if = bridge_rtlookup(sc, eh->ether_dhost);
1088 if (dst_if == NULL) {
1089 struct bridge_iflist *bif;
1090 struct mbuf *mc;
1091 int used = 0;
1092
1093 LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
1094 dst_if = bif->bif_ifp;
1095 if ((dst_if->if_flags & IFF_RUNNING) == 0)
1096 continue;
1097
1098 /*
1099 * If this is not the original output interface,
1100 * and the interface is participating in spanning
1101 * tree, make sure the port is in a state that
1102 * allows forwarding.
1103 */
1104 if (dst_if != ifp &&
1105 (bif->bif_flags & IFBIF_STP) != 0) {
1106 switch (bif->bif_state) {
1107 case BSTP_IFSTATE_BLOCKING:
1108 case BSTP_IFSTATE_LISTENING:
1109 case BSTP_IFSTATE_DISABLED:
1110 continue;
1111 }
1112 }
1113
1114 if (LIST_NEXT(bif, bif_next) == NULL) {
1115 used = 1;
1116 mc = m;
1117 } else {
1118 mc = m_copym(m, 0, M_COPYALL, M_NOWAIT);
1119 if (mc == NULL) {
1120 sc->sc_if.if_oerrors++;
1121 continue;
1122 }
1123 }
1124
1125 bridge_enqueue(sc, dst_if, mc);
1126 }
1127 if (used == 0)
1128 m_freem(m);
1129 splx(s);
1130 return (0);
1131 }
1132
1133 sendunicast:
1134 /*
1135 * XXX Spanning tree consideration here?
1136 */
1137
1138 if ((dst_if->if_flags & IFF_RUNNING) == 0) {
1139 m_freem(m);
1140 splx(s);
1141 return (0);
1142 }
1143
1144 bridge_enqueue(sc, dst_if, m);
1145
1146 splx(s);
1147 return (0);
1148 }
1149
1150 /*
1151 * bridge_start:
1152 *
1153 * Start output on a bridge.
1154 *
1155 * NOTE: This routine should never be called in this implementation.
1156 */
1157 void
1158 bridge_start(struct ifnet *ifp)
1159 {
1160
1161 printf("%s: bridge_start() called\n", ifp->if_xname);
1162 }
1163
1164 /*
1165 * bridge_forward:
1166 *
1167 * The fowarding function of the bridge.
1168 */
1169 void
1170 bridge_forward(struct bridge_softc *sc, struct mbuf *m)
1171 {
1172 struct bridge_iflist *bif;
1173 struct ifnet *src_if, *dst_if;
1174 struct ether_header *eh;
1175
1176 src_if = m->m_pkthdr.rcvif;
1177
1178 sc->sc_if.if_ipackets++;
1179 sc->sc_if.if_ibytes += m->m_pkthdr.len;
1180
1181 /*
1182 * Look up the bridge_iflist.
1183 * XXX This should be more efficient.
1184 */
1185 bif = bridge_lookup_member(sc, src_if->if_xname);
1186 if (bif == NULL) {
1187 /* Interface is not a bridge member (anymore?) */
1188 m_freem(m);
1189 return;
1190 }
1191
1192 if (bif->bif_flags & IFBIF_STP) {
1193 switch (bif->bif_state) {
1194 case BSTP_IFSTATE_BLOCKING:
1195 case BSTP_IFSTATE_LISTENING:
1196 case BSTP_IFSTATE_DISABLED:
1197 m_freem(m);
1198 return;
1199 }
1200 }
1201
1202 eh = mtod(m, struct ether_header *);
1203
1204 /*
1205 * If the interface is learning, and the source
1206 * address is valid and not multicast, record
1207 * the address.
1208 */
1209 if ((bif->bif_flags & IFBIF_LEARNING) != 0 &&
1210 ETHER_IS_MULTICAST(eh->ether_shost) == 0 &&
1211 (eh->ether_shost[0] == 0 &&
1212 eh->ether_shost[1] == 0 &&
1213 eh->ether_shost[2] == 0 &&
1214 eh->ether_shost[3] == 0 &&
1215 eh->ether_shost[4] == 0 &&
1216 eh->ether_shost[5] == 0) == 0) {
1217 (void) bridge_rtupdate(sc, eh->ether_shost,
1218 src_if, 0, IFBAF_DYNAMIC);
1219 }
1220
1221 if ((bif->bif_flags & IFBIF_STP) != 0 &&
1222 bif->bif_state == BSTP_IFSTATE_LEARNING) {
1223 m_freem(m);
1224 return;
1225 }
1226
1227 /*
1228 * At this point, the port either doesn't participate
1229 * in spanning tree or it is in the forwarding state.
1230 */
1231
1232 /*
1233 * If the packet is unicast, destined for someone on
1234 * "this" side of the bridge, drop it.
1235 */
1236 if ((m->m_flags & (M_BCAST|M_MCAST)) == 0) {
1237 dst_if = bridge_rtlookup(sc, eh->ether_dhost);
1238 if (src_if == dst_if) {
1239 m_freem(m);
1240 return;
1241 }
1242 } else {
1243 /* ...forward it to all interfaces. */
1244 sc->sc_if.if_imcasts++;
1245 dst_if = NULL;
1246 }
1247
1248 if (dst_if == NULL) {
1249 bridge_broadcast(sc, src_if, m);
1250 return;
1251 }
1252
1253 /*
1254 * At this point, we're dealing with a unicast frame
1255 * going to a different interface.
1256 */
1257 if ((dst_if->if_flags & IFF_RUNNING) == 0) {
1258 m_freem(m);
1259 return;
1260 }
1261 /* XXX This needs to be more efficient. */
1262 bif = bridge_lookup_member(sc, dst_if->if_xname);
1263 if (bif == NULL) {
1264 /* Not a member of the bridge (anymore?) */
1265 m_freem(m);
1266 return;
1267 }
1268
1269 if (bif->bif_flags & IFBIF_STP) {
1270 switch (bif->bif_state) {
1271 case BSTP_IFSTATE_DISABLED:
1272 case BSTP_IFSTATE_BLOCKING:
1273 m_freem(m);
1274 return;
1275 }
1276 }
1277
1278 bridge_enqueue(sc, dst_if, m);
1279 }
1280
1281 /*
1282 * bridge_input:
1283 *
1284 * Receive input from a member interface. Queue the packet for
1285 * bridging if it is not for us.
1286 */
1287 struct mbuf *
1288 bridge_input(struct ifnet *ifp, struct mbuf *m)
1289 {
1290 struct bridge_softc *sc = ifp->if_bridge;
1291 struct bridge_iflist *bif;
1292 struct ether_header *eh;
1293 struct mbuf *mc;
1294
1295 if ((sc->sc_if.if_flags & IFF_RUNNING) == 0)
1296 return (m);
1297
1298 /* XXX This needs to be more efficient. */
1299 bif = bridge_lookup_member(sc, ifp->if_xname);
1300 if (bif == NULL)
1301 return (m);
1302
1303 eh = mtod(m, struct ether_header *);
1304
1305 if (m->m_flags & (M_BCAST|M_MCAST)) {
1306 /* Tap off 802.1D packets; they do not get forwarded. */
1307 if (memcmp(eh->ether_dhost, bstp_etheraddr,
1308 ETHER_ADDR_LEN) == 0) {
1309 m = bstp_input(ifp, m);
1310 if (m == NULL)
1311 return (NULL);
1312 }
1313
1314 if (bif->bif_flags & IFBIF_STP) {
1315 switch (bif->bif_state) {
1316 case BSTP_IFSTATE_BLOCKING:
1317 case BSTP_IFSTATE_LISTENING:
1318 case BSTP_IFSTATE_DISABLED:
1319 return (m);
1320 }
1321 }
1322
1323 /*
1324 * Make a deep copy of the packet and enqueue the copy
1325 * for bridge processing; return the original packet for
1326 * local processing.
1327 */
1328 mc = m_dup(m, 0, M_COPYALL, M_NOWAIT);
1329 if (mc == NULL)
1330 return (m);
1331
1332 /* Perform the bridge forwarding function with the copy. */
1333 bridge_forward(sc, mc);
1334
1335 /* Return the original packet for local processing. */
1336 return (m);
1337 }
1338
1339 if (bif->bif_flags & IFBIF_STP) {
1340 switch (bif->bif_state) {
1341 case BSTP_IFSTATE_BLOCKING:
1342 case BSTP_IFSTATE_LISTENING:
1343 case BSTP_IFSTATE_DISABLED:
1344 return (m);
1345 }
1346 }
1347
1348 /*
1349 * Unicast. Make sure it's not for us.
1350 */
1351 LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
1352 /* It is destined for us. */
1353 if (memcmp(LLADDR(bif->bif_ifp->if_sadl), eh->ether_dhost,
1354 ETHER_ADDR_LEN) == 0) {
1355 if (bif->bif_flags & IFBIF_LEARNING)
1356 (void) bridge_rtupdate(sc,
1357 eh->ether_shost, ifp, 0, IFBAF_DYNAMIC);
1358 m->m_pkthdr.rcvif = bif->bif_ifp;
1359 return (m);
1360 }
1361
1362 /* We just received a packet that we sent out. */
1363 if (memcmp(LLADDR(bif->bif_ifp->if_sadl), eh->ether_shost,
1364 ETHER_ADDR_LEN) == 0) {
1365 m_freem(m);
1366 return (NULL);
1367 }
1368 }
1369
1370 /* Perform the bridge forwarding function. */
1371 bridge_forward(sc, m);
1372
1373 return (NULL);
1374 }
1375
1376 /*
1377 * bridge_broadcast:
1378 *
1379 * Send a frame to all interfaces that are members of
1380 * the bridge, except for the one on which the packet
1381 * arrived.
1382 */
1383 void
1384 bridge_broadcast(struct bridge_softc *sc, struct ifnet *src_if,
1385 struct mbuf *m)
1386 {
1387 struct bridge_iflist *bif;
1388 struct mbuf *mc;
1389 struct ifnet *dst_if;
1390 int used = 0;
1391
1392 LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
1393 dst_if = bif->bif_ifp;
1394 if (dst_if == src_if)
1395 continue;
1396
1397 if (bif->bif_flags & IFBIF_STP) {
1398 switch (bif->bif_state) {
1399 case BSTP_IFSTATE_BLOCKING:
1400 case BSTP_IFSTATE_DISABLED:
1401 continue;
1402 }
1403 }
1404
1405 if ((bif->bif_flags & IFBIF_DISCOVER) == 0 &&
1406 (m->m_flags & (M_BCAST|M_MCAST)) == 0)
1407 continue;
1408
1409 if ((dst_if->if_flags & IFF_RUNNING) == 0)
1410 continue;
1411
1412 if (LIST_NEXT(bif, bif_next) == NULL) {
1413 mc = m;
1414 used = 1;
1415 } else {
1416 mc = m_copym(m, 0, M_COPYALL, M_DONTWAIT);
1417 if (mc == NULL) {
1418 sc->sc_if.if_oerrors++;
1419 continue;
1420 }
1421 }
1422
1423 bridge_enqueue(sc, dst_if, mc);
1424 }
1425 if (used == 0)
1426 m_freem(m);
1427 }
1428
1429 /*
1430 * bridge_rtupdate:
1431 *
1432 * Add a bridge routing entry.
1433 */
1434 int
1435 bridge_rtupdate(struct bridge_softc *sc, const uint8_t *dst,
1436 struct ifnet *dst_if, int setflags, uint8_t flags)
1437 {
1438 struct bridge_rtnode *brt;
1439 int error;
1440
1441 /*
1442 * A route for this destination might already exist. If so,
1443 * update it, otherwise create a new one.
1444 */
1445 if ((brt = bridge_rtnode_lookup(sc, dst)) == NULL) {
1446 if (sc->sc_brtcnt >= sc->sc_brtmax)
1447 return (ENOSPC);
1448
1449 /*
1450 * Allocate a new bridge forwarding node, and
1451 * initialize the expiration time and Ethernet
1452 * address.
1453 */
1454 brt = pool_get(&bridge_rtnode_pool, PR_NOWAIT);
1455 if (brt == NULL)
1456 return (ENOMEM);
1457
1458 memset(brt, 0, sizeof(*brt));
1459 brt->brt_expire = mono_time.tv_sec + sc->sc_brttimeout;
1460 brt->brt_flags = IFBAF_DYNAMIC;
1461 memcpy(brt->brt_addr, dst, ETHER_ADDR_LEN);
1462
1463 if ((error = bridge_rtnode_insert(sc, brt)) != 0) {
1464 pool_put(&bridge_rtnode_pool, brt);
1465 return (error);
1466 }
1467 }
1468
1469 brt->brt_ifp = dst_if;
1470 if (setflags) {
1471 brt->brt_flags = flags;
1472 brt->brt_expire = (flags & IFBAF_STATIC) ? 0 :
1473 mono_time.tv_sec + sc->sc_brttimeout;
1474 }
1475
1476 return (0);
1477 }
1478
1479 /*
1480 * bridge_rtlookup:
1481 *
1482 * Lookup the destination interface for an address.
1483 */
1484 struct ifnet *
1485 bridge_rtlookup(struct bridge_softc *sc, const uint8_t *addr)
1486 {
1487 struct bridge_rtnode *brt;
1488
1489 if ((brt = bridge_rtnode_lookup(sc, addr)) == NULL)
1490 return (NULL);
1491
1492 return (brt->brt_ifp);
1493 }
1494
1495 /*
1496 * bridge_rttrim:
1497 *
1498 * Trim the routine table so that we have a number
1499 * of routing entries less than or equal to the
1500 * maximum number.
1501 */
1502 void
1503 bridge_rttrim(struct bridge_softc *sc)
1504 {
1505 struct bridge_rtnode *brt, *nbrt;
1506
1507 /* Make sure we actually need to do this. */
1508 if (sc->sc_brtcnt <= sc->sc_brtmax)
1509 return;
1510
1511 /* Force an aging cycle; this might trim enough addresses. */
1512 bridge_rtage(sc);
1513 if (sc->sc_brtcnt <= sc->sc_brtmax)
1514 return;
1515
1516 for (brt = LIST_FIRST(&sc->sc_rtlist); brt != NULL; brt = nbrt) {
1517 nbrt = LIST_NEXT(brt, brt_list);
1518 if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) {
1519 bridge_rtnode_destroy(sc, brt);
1520 if (sc->sc_brtcnt <= sc->sc_brtmax)
1521 return;
1522 }
1523 }
1524 }
1525
1526 /*
1527 * bridge_timer:
1528 *
1529 * Aging timer for the bridge.
1530 */
1531 void
1532 bridge_timer(void *arg)
1533 {
1534 struct bridge_softc *sc = arg;
1535 int s;
1536
1537 s = splnet();
1538 bridge_rtage(sc);
1539 splx(s);
1540
1541 if (sc->sc_if.if_flags & IFF_RUNNING)
1542 callout_reset(&sc->sc_brcallout,
1543 bridge_rtable_prune_period * hz, bridge_timer, sc);
1544 }
1545
1546 /*
1547 * bridge_rtage:
1548 *
1549 * Perform an aging cycle.
1550 */
1551 void
1552 bridge_rtage(struct bridge_softc *sc)
1553 {
1554 struct bridge_rtnode *brt, *nbrt;
1555
1556 for (brt = LIST_FIRST(&sc->sc_rtlist); brt != NULL; brt = nbrt) {
1557 nbrt = LIST_NEXT(brt, brt_list);
1558 if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) {
1559 if (mono_time.tv_sec >= brt->brt_expire)
1560 bridge_rtnode_destroy(sc, brt);
1561 }
1562 }
1563 }
1564
1565 /*
1566 * bridge_rtflush:
1567 *
1568 * Remove all dynamic addresses from the bridge.
1569 */
1570 void
1571 bridge_rtflush(struct bridge_softc *sc, int full)
1572 {
1573 struct bridge_rtnode *brt, *nbrt;
1574
1575 for (brt = LIST_FIRST(&sc->sc_rtlist); brt != NULL; brt = nbrt) {
1576 nbrt = LIST_NEXT(brt, brt_list);
1577 if (full || (brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC)
1578 bridge_rtnode_destroy(sc, brt);
1579 }
1580 }
1581
1582 /*
1583 * bridge_rtdaddr:
1584 *
1585 * Remove an address from the table.
1586 */
1587 int
1588 bridge_rtdaddr(struct bridge_softc *sc, const uint8_t *addr)
1589 {
1590 struct bridge_rtnode *brt;
1591
1592 if ((brt = bridge_rtnode_lookup(sc, addr)) == NULL)
1593 return (ENOENT);
1594
1595 bridge_rtnode_destroy(sc, brt);
1596 return (0);
1597 }
1598
1599 /*
1600 * bridge_rtdelete:
1601 *
1602 * Delete routes to a speicifc member interface.
1603 */
1604 void
1605 bridge_rtdelete(struct bridge_softc *sc, struct ifnet *ifp)
1606 {
1607 struct bridge_rtnode *brt, *nbrt;
1608
1609 for (brt = LIST_FIRST(&sc->sc_rtlist); brt != NULL; brt = nbrt) {
1610 nbrt = LIST_NEXT(brt, brt_list);
1611 if (brt->brt_ifp == ifp)
1612 bridge_rtnode_destroy(sc, brt);
1613 }
1614 }
1615
1616 /*
1617 * bridge_rtable_init:
1618 *
1619 * Initialize the route table for this bridge.
1620 */
1621 int
1622 bridge_rtable_init(struct bridge_softc *sc)
1623 {
1624 int i;
1625
1626 sc->sc_rthash = malloc(sizeof(*sc->sc_rthash) * BRIDGE_RTHASH_SIZE,
1627 M_DEVBUF, M_NOWAIT);
1628 if (sc->sc_rthash == NULL)
1629 return (ENOMEM);
1630
1631 for (i = 0; i < BRIDGE_RTHASH_SIZE; i++)
1632 LIST_INIT(&sc->sc_rthash[i]);
1633
1634 #if NRND > 0
1635 rnd_extract_data(&sc->sc_rthash_key, sizeof(sc->sc_rthash_key),
1636 RND_EXTRACT_ANY);
1637 #else
1638 sc->sc_rthash_key = random();
1639 #endif /* NRND > 0 */
1640
1641 LIST_INIT(&sc->sc_rtlist);
1642
1643 return (0);
1644 }
1645
1646 /*
1647 * bridge_rtable_fini:
1648 *
1649 * Deconstruct the route table for this bridge.
1650 */
1651 void
1652 bridge_rtable_fini(struct bridge_softc *sc)
1653 {
1654
1655 free(sc->sc_rthash, M_DEVBUF);
1656 }
1657
1658 /*
1659 * The following hash function is adapted from "Hash Functions" by Bob Jenkins
1660 * ("Algorithm Alley", Dr. Dobbs Journal, September 1997).
1661 */
1662 #define mix(a, b, c) \
1663 do { \
1664 a -= b; a -= c; a ^= (c >> 13); \
1665 b -= c; b -= a; b ^= (a << 8); \
1666 c -= a; c -= b; c ^= (b >> 13); \
1667 a -= b; a -= c; a ^= (c >> 12); \
1668 b -= c; b -= a; b ^= (a << 16); \
1669 c -= a; c -= b; c ^= (b >> 5); \
1670 a -= b; a -= c; a ^= (c >> 3); \
1671 b -= c; b -= a; b ^= (a << 10); \
1672 c -= a; c -= b; c ^= (b >> 15); \
1673 } while (/*CONSTCOND*/0)
1674
1675 static __inline uint32_t
1676 bridge_rthash(struct bridge_softc *sc, const uint8_t *addr)
1677 {
1678 uint32_t a = 0x9e3779b9, b = 0x9e3779b9, c = sc->sc_rthash_key;
1679
1680 b += addr[5] << 8;
1681 b += addr[4];
1682 a += addr[3] << 24;
1683 a += addr[2] << 16;
1684 a += addr[1] << 8;
1685 a += addr[0];
1686
1687 mix(a, b, c);
1688
1689 return (c & BRIDGE_RTHASH_MASK);
1690 }
1691
1692 #undef mix
1693
1694 /*
1695 * bridge_rtnode_lookup:
1696 *
1697 * Look up a bridge route node for the specified destination.
1698 */
1699 struct bridge_rtnode *
1700 bridge_rtnode_lookup(struct bridge_softc *sc, const uint8_t *addr)
1701 {
1702 struct bridge_rtnode *brt;
1703 uint32_t hash;
1704 int dir;
1705
1706 hash = bridge_rthash(sc, addr);
1707 LIST_FOREACH(brt, &sc->sc_rthash[hash], brt_hash) {
1708 dir = memcmp(addr, brt->brt_addr, ETHER_ADDR_LEN);
1709 if (dir == 0)
1710 return (brt);
1711 if (dir > 0)
1712 return (NULL);
1713 }
1714
1715 return (NULL);
1716 }
1717
1718 /*
1719 * bridge_rtnode_insert:
1720 *
1721 * Insert the specified bridge node into the route table. We
1722 * assume the entry is not already in the table.
1723 */
1724 int
1725 bridge_rtnode_insert(struct bridge_softc *sc, struct bridge_rtnode *brt)
1726 {
1727 struct bridge_rtnode *lbrt;
1728 uint32_t hash;
1729 int dir;
1730
1731 hash = bridge_rthash(sc, brt->brt_addr);
1732
1733 lbrt = LIST_FIRST(&sc->sc_rthash[hash]);
1734 if (lbrt == NULL) {
1735 LIST_INSERT_HEAD(&sc->sc_rthash[hash], brt, brt_hash);
1736 goto out;
1737 }
1738
1739 do {
1740 dir = memcmp(brt->brt_addr, lbrt->brt_addr, ETHER_ADDR_LEN);
1741 if (dir == 0)
1742 return (EEXIST);
1743 if (dir > 0) {
1744 LIST_INSERT_BEFORE(lbrt, brt, brt_hash);
1745 goto out;
1746 }
1747 if (LIST_NEXT(lbrt, brt_hash) == NULL) {
1748 LIST_INSERT_AFTER(lbrt, brt, brt_hash);
1749 goto out;
1750 }
1751 lbrt = LIST_NEXT(lbrt, brt_hash);
1752 } while (lbrt != NULL);
1753
1754 #ifdef DIAGNOSTIC
1755 panic("bridge_rtnode_insert: impossible");
1756 #endif
1757
1758 out:
1759 LIST_INSERT_HEAD(&sc->sc_rtlist, brt, brt_list);
1760 sc->sc_brtcnt++;
1761
1762 return (0);
1763 }
1764
1765 /*
1766 * bridge_rtnode_destroy:
1767 *
1768 * Destroy a bridge rtnode.
1769 */
1770 void
1771 bridge_rtnode_destroy(struct bridge_softc *sc, struct bridge_rtnode *brt)
1772 {
1773
1774 LIST_REMOVE(brt, brt_hash);
1775
1776 LIST_REMOVE(brt, brt_list);
1777 sc->sc_brtcnt--;
1778 pool_put(&bridge_rtnode_pool, brt);
1779 }
1780