if_bridge.c revision 1.1 1 /* $NetBSD: if_bridge.c,v 1.1 2001/08/17 21:37:27 thorpej 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 bareq.ifba_expire = brt->brt_expire - mono_time.tv_sec;
742 bareq.ifba_flags = brt->brt_flags;
743
744 error = copyout(&bareq, bac->ifbac_req + count, sizeof(bareq));
745 if (error)
746 goto out;
747 count++;
748 len -= sizeof(bareq);
749 }
750 out:
751 bac->ifbac_len = sizeof(bareq) * count;
752 return (error);
753 }
754
755 int
756 bridge_ioctl_saddr(struct bridge_softc *sc, void *arg)
757 {
758 struct ifbareq *req = arg;
759 struct bridge_iflist *bif;
760 int error;
761
762 bif = bridge_lookup_member(sc, req->ifba_ifsname);
763 if (bif == NULL)
764 return (ENOENT);
765
766 error = bridge_rtupdate(sc, req->ifba_dst, bif->bif_ifp, 1,
767 req->ifba_flags);
768
769 return (error);
770 }
771
772 int
773 bridge_ioctl_sto(struct bridge_softc *sc, void *arg)
774 {
775 struct ifbrparam *param = arg;
776
777 sc->sc_brttimeout = param->ifbrp_ctime;
778
779 return (0);
780 }
781
782 int
783 bridge_ioctl_gto(struct bridge_softc *sc, void *arg)
784 {
785 struct ifbrparam *param = arg;
786
787 param->ifbrp_ctime = sc->sc_brttimeout;
788
789 return (0);
790 }
791
792 int
793 bridge_ioctl_daddr(struct bridge_softc *sc, void *arg)
794 {
795 struct ifbareq *req = arg;
796
797 return (bridge_rtdaddr(sc, req->ifba_dst));
798 }
799
800 int
801 bridge_ioctl_flush(struct bridge_softc *sc, void *arg)
802 {
803 struct ifbreq *req = arg;
804
805 bridge_rtflush(sc, req->ifbr_ifsflags);
806
807 return (0);
808 }
809
810 int
811 bridge_ioctl_gpri(struct bridge_softc *sc, void *arg)
812 {
813 struct ifbrparam *param = arg;
814
815 param->ifbrp_prio = sc->sc_bridge_priority;
816
817 return (0);
818 }
819
820 int
821 bridge_ioctl_spri(struct bridge_softc *sc, void *arg)
822 {
823 struct ifbrparam *param = arg;
824
825 sc->sc_bridge_priority = param->ifbrp_prio;
826
827 if (sc->sc_if.if_flags & IFF_RUNNING)
828 bstp_initialization(sc);
829
830 return (0);
831 }
832
833 int
834 bridge_ioctl_ght(struct bridge_softc *sc, void *arg)
835 {
836 struct ifbrparam *param = arg;
837
838 param->ifbrp_hellotime = sc->sc_bridge_hello_time >> 8;
839
840 return (0);
841 }
842
843 int
844 bridge_ioctl_sht(struct bridge_softc *sc, void *arg)
845 {
846 struct ifbrparam *param = arg;
847
848 if (param->ifbrp_hellotime == 0)
849 return (EINVAL);
850 sc->sc_bridge_hello_time = param->ifbrp_hellotime << 8;
851
852 if (sc->sc_if.if_flags & IFF_RUNNING)
853 bstp_initialization(sc);
854
855 return (0);
856 }
857
858 int
859 bridge_ioctl_gfd(struct bridge_softc *sc, void *arg)
860 {
861 struct ifbrparam *param = arg;
862
863 param->ifbrp_fwddelay = sc->sc_bridge_forward_delay >> 8;
864
865 return (0);
866 }
867
868 int
869 bridge_ioctl_sfd(struct bridge_softc *sc, void *arg)
870 {
871 struct ifbrparam *param = arg;
872
873 if (param->ifbrp_fwddelay == 0)
874 return (EINVAL);
875 sc->sc_bridge_forward_delay = param->ifbrp_fwddelay << 8;
876
877 if (sc->sc_if.if_flags & IFF_RUNNING)
878 bstp_initialization(sc);
879
880 return (0);
881 }
882
883 int
884 bridge_ioctl_gma(struct bridge_softc *sc, void *arg)
885 {
886 struct ifbrparam *param = arg;
887
888 param->ifbrp_maxage = sc->sc_bridge_max_age >> 8;
889
890 return (0);
891 }
892
893 int
894 bridge_ioctl_sma(struct bridge_softc *sc, void *arg)
895 {
896 struct ifbrparam *param = arg;
897
898 if (param->ifbrp_maxage == 0)
899 return (EINVAL);
900 sc->sc_bridge_max_age = param->ifbrp_maxage << 8;
901
902 if (sc->sc_if.if_flags & IFF_RUNNING)
903 bstp_initialization(sc);
904
905 return (0);
906 }
907
908 int
909 bridge_ioctl_sifprio(struct bridge_softc *sc, void *arg)
910 {
911 struct ifbreq *req = arg;
912 struct bridge_iflist *bif;
913
914 bif = bridge_lookup_member(sc, req->ifbr_ifsname);
915 if (bif == NULL)
916 return (ENOENT);
917
918 bif->bif_priority = req->ifbr_priority;
919
920 if (sc->sc_if.if_flags & IFF_RUNNING)
921 bstp_initialization(sc);
922
923 return (0);
924 }
925
926 /*
927 * bridge_ifdetach:
928 *
929 * Detach an interface from a bridge. Called when a member
930 * interface is detaching.
931 */
932 void
933 bridge_ifdetach(struct ifnet *ifp)
934 {
935 struct bridge_softc *sc = ifp->if_bridge;
936 struct ifbreq breq;
937
938 memset(&breq, 0, sizeof(breq));
939 sprintf(breq.ifbr_ifsname, ifp->if_xname);
940
941 (void) bridge_ioctl_del(sc, &breq);
942 }
943
944 /*
945 * bridge_init:
946 *
947 * Initialize a bridge interface.
948 */
949 int
950 bridge_init(struct ifnet *ifp)
951 {
952 struct bridge_softc *sc = ifp->if_softc;
953
954 if (ifp->if_flags & IFF_RUNNING)
955 return (0);
956
957 callout_reset(&sc->sc_brcallout, bridge_rtable_prune_period * hz,
958 bridge_timer, sc);
959
960 ifp->if_flags |= IFF_RUNNING;
961 return (0);
962 }
963
964 /*
965 * bridge_stop:
966 *
967 * Stop the bridge interface.
968 */
969 void
970 bridge_stop(struct ifnet *ifp, int disable)
971 {
972 struct bridge_softc *sc = ifp->if_softc;
973
974 if ((ifp->if_flags & IFF_RUNNING) == 0)
975 return;
976
977 callout_stop(&sc->sc_brcallout);
978 bstp_stop(sc);
979
980 IF_PURGE(&ifp->if_snd);
981
982 bridge_rtflush(sc, IFBF_FLUSHDYN);
983
984 ifp->if_flags &= ~IFF_RUNNING;
985 }
986
987 /*
988 * bridge_enqueue:
989 *
990 * Enqueue a packet on a bridge member interface.
991 *
992 * NOTE: must be called at splnet().
993 */
994 __inline void
995 bridge_enqueue(struct bridge_softc *sc, struct ifnet *dst_ifp, struct mbuf *m)
996 {
997 ALTQ_DECL(struct altq_pktattr pktattr;)
998 int len, error;
999 short mflags;
1000
1001 #ifdef ALTQ
1002 /*
1003 * If ALTQ is enabled on the member interface, do
1004 * classification; the queueing discipline might
1005 * not require classification, but might require
1006 * the address family/header pointer in the pktattr.
1007 */
1008 if (ALTQ_IS_ENABLED(&dst_ifp->if_snd)) {
1009 /* XXX IFT_ETHER */
1010 altq_etherclassify(&dst_ifp->if_snd, m, &pktattr);
1011 }
1012 #endif /* ALTQ */
1013
1014 len = m->m_pkthdr.len;
1015 mflags = m->m_flags;
1016 IFQ_ENQUEUE(&dst_ifp->if_snd, m, &pktattr, error);
1017 if (error) {
1018 /* mbuf is already freed */
1019 sc->sc_if.if_oerrors++;
1020 return;
1021 }
1022
1023 sc->sc_if.if_opackets++;
1024 sc->sc_if.if_obytes += len;
1025
1026 dst_ifp->if_obytes += len;
1027
1028 if (mflags & M_MCAST) {
1029 sc->sc_if.if_omcasts++;
1030 dst_ifp->if_omcasts++;
1031 }
1032
1033 if ((dst_ifp->if_flags & IFF_OACTIVE) == 0)
1034 (*dst_ifp->if_start)(dst_ifp);
1035 }
1036
1037 /*
1038 * bridge_output:
1039 *
1040 * Send output from a bridge member interface. This
1041 * performs the bridging function for locally originated
1042 * packets.
1043 *
1044 * The mbuf has the Ethernet header already attached. We must
1045 * enqueue or free the mbuf before returning.
1046 */
1047 int
1048 bridge_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa,
1049 struct rtentry *rt)
1050 {
1051 struct ether_header *eh;
1052 struct ifnet *dst_if;
1053 struct bridge_softc *sc;
1054 int s;
1055
1056 if (m->m_len < ETHER_HDR_LEN) {
1057 m = m_pullup(m, ETHER_HDR_LEN);
1058 if (m == NULL)
1059 return (0);
1060 }
1061
1062 eh = mtod(m, struct ether_header *);
1063 sc = ifp->if_bridge;
1064
1065 s = splnet();
1066
1067 /*
1068 * If bridge is down, but the original output interface is up,
1069 * go ahead and send out that interface. Otherwise, the packet
1070 * is dropped below.
1071 */
1072 if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) {
1073 dst_if = ifp;
1074 goto sendunicast;
1075 }
1076
1077 /*
1078 * If the packet is a multicast, or we don't know a better way to
1079 * get there, send to all interfaces.
1080 */
1081 if (ETHER_IS_MULTICAST(eh->ether_dhost))
1082 dst_if = NULL;
1083 else
1084 dst_if = bridge_rtlookup(sc, eh->ether_dhost);
1085 if (dst_if == NULL) {
1086 struct bridge_iflist *bif;
1087 struct mbuf *mc;
1088 int used = 0;
1089
1090 LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
1091 dst_if = bif->bif_ifp;
1092 if ((dst_if->if_flags & IFF_RUNNING) == 0)
1093 continue;
1094
1095 /*
1096 * If this is not the original output interface,
1097 * and the interface is participating in spanning
1098 * tree, make sure the port is in a state that
1099 * allows forwarding.
1100 */
1101 if (dst_if != ifp &&
1102 (bif->bif_flags & IFBIF_STP) != 0) {
1103 switch (bif->bif_state) {
1104 case BSTP_IFSTATE_BLOCKING:
1105 case BSTP_IFSTATE_LISTENING:
1106 case BSTP_IFSTATE_DISABLED:
1107 continue;
1108 }
1109 }
1110
1111 if (LIST_NEXT(bif, bif_next) == NULL) {
1112 used = 1;
1113 mc = m;
1114 } else {
1115 mc = m_copym(m, 0, M_COPYALL, M_NOWAIT);
1116 if (mc == NULL) {
1117 sc->sc_if.if_oerrors++;
1118 continue;
1119 }
1120 }
1121
1122 bridge_enqueue(sc, dst_if, mc);
1123 }
1124 if (used == 0)
1125 m_freem(m);
1126 splx(s);
1127 return (0);
1128 }
1129
1130 sendunicast:
1131 /*
1132 * XXX Spanning tree consideration here?
1133 */
1134
1135 if ((dst_if->if_flags & IFF_RUNNING) == 0) {
1136 m_freem(m);
1137 splx(s);
1138 return (0);
1139 }
1140
1141 bridge_enqueue(sc, dst_if, m);
1142
1143 splx(s);
1144 return (0);
1145 }
1146
1147 /*
1148 * bridge_start:
1149 *
1150 * Start output on a bridge.
1151 *
1152 * NOTE: This routine should never be called in this implementation.
1153 */
1154 void
1155 bridge_start(struct ifnet *ifp)
1156 {
1157
1158 printf("%s: bridge_start() called\n", ifp->if_xname);
1159 }
1160
1161 /*
1162 * bridge_forward:
1163 *
1164 * The fowarding function of the bridge.
1165 */
1166 void
1167 bridge_forward(struct bridge_softc *sc, struct mbuf *m)
1168 {
1169 struct bridge_iflist *bif;
1170 struct ifnet *src_if, *dst_if;
1171 struct ether_header *eh;
1172
1173 src_if = m->m_pkthdr.rcvif;
1174
1175 sc->sc_if.if_ipackets++;
1176 sc->sc_if.if_ibytes += m->m_pkthdr.len;
1177
1178 /*
1179 * Look up the bridge_iflist.
1180 * XXX This should be more efficient.
1181 */
1182 bif = bridge_lookup_member(sc, src_if->if_xname);
1183 if (bif == NULL) {
1184 /* Interface is not a bridge member (anymore?) */
1185 m_freem(m);
1186 return;
1187 }
1188
1189 if (bif->bif_flags & IFBIF_STP) {
1190 switch (bif->bif_state) {
1191 case BSTP_IFSTATE_BLOCKING:
1192 case BSTP_IFSTATE_LISTENING:
1193 case BSTP_IFSTATE_DISABLED:
1194 m_freem(m);
1195 return;
1196 }
1197 }
1198
1199 eh = mtod(m, struct ether_header *);
1200
1201 /*
1202 * If the interface is learning, and the source
1203 * address is valid and not multicast, record
1204 * the address.
1205 */
1206 if ((bif->bif_flags & IFBIF_LEARNING) != 0 &&
1207 ETHER_IS_MULTICAST(eh->ether_shost) == 0 &&
1208 (eh->ether_shost[0] == 0 &&
1209 eh->ether_shost[1] == 0 &&
1210 eh->ether_shost[2] == 0 &&
1211 eh->ether_shost[3] == 0 &&
1212 eh->ether_shost[4] == 0 &&
1213 eh->ether_shost[5] == 0) == 0) {
1214 (void) bridge_rtupdate(sc, eh->ether_shost,
1215 src_if, 0, IFBAF_DYNAMIC);
1216 }
1217
1218 if ((bif->bif_flags & IFBIF_STP) != 0 &&
1219 bif->bif_state == BSTP_IFSTATE_LEARNING) {
1220 m_freem(m);
1221 return;
1222 }
1223
1224 /*
1225 * At this point, the port either doesn't participate
1226 * in spanning tree or it is in the forwarding state.
1227 */
1228
1229 /*
1230 * If the packet is unicast, destined for someone on
1231 * "this" side of the bridge, drop it.
1232 */
1233 if ((m->m_flags & (M_BCAST|M_MCAST)) == 0) {
1234 dst_if = bridge_rtlookup(sc, eh->ether_dhost);
1235 if (src_if == dst_if) {
1236 m_freem(m);
1237 return;
1238 }
1239 } else {
1240 /* ...forward it to all interfaces. */
1241 sc->sc_if.if_imcasts++;
1242 dst_if = NULL;
1243 }
1244
1245 if (dst_if == NULL) {
1246 bridge_broadcast(sc, src_if, m);
1247 return;
1248 }
1249
1250 /*
1251 * At this point, we're dealing with a unicast frame
1252 * going to a different interface.
1253 */
1254 if ((dst_if->if_flags & IFF_RUNNING) == 0) {
1255 m_freem(m);
1256 return;
1257 }
1258 /* XXX This needs to be more efficient. */
1259 bif = bridge_lookup_member(sc, dst_if->if_xname);
1260 if (bif == NULL) {
1261 /* Not a member of the bridge (anymore?) */
1262 m_freem(m);
1263 return;
1264 }
1265
1266 if (bif->bif_flags & IFBIF_STP) {
1267 switch (bif->bif_state) {
1268 case BSTP_IFSTATE_DISABLED:
1269 case BSTP_IFSTATE_BLOCKING:
1270 m_freem(m);
1271 return;
1272 }
1273 }
1274
1275 bridge_enqueue(sc, dst_if, m);
1276 }
1277
1278 /*
1279 * bridge_input:
1280 *
1281 * Receive input from a member interface. Queue the packet for
1282 * bridging if it is not for us.
1283 */
1284 struct mbuf *
1285 bridge_input(struct ifnet *ifp, struct mbuf *m)
1286 {
1287 struct bridge_softc *sc = ifp->if_bridge;
1288 struct bridge_iflist *bif;
1289 struct ether_header *eh;
1290 struct mbuf *mc;
1291
1292 if ((sc->sc_if.if_flags & IFF_RUNNING) == 0)
1293 return (m);
1294
1295 /* XXX This needs to be more efficient. */
1296 bif = bridge_lookup_member(sc, ifp->if_xname);
1297 if (bif == NULL)
1298 return (m);
1299
1300 eh = mtod(m, struct ether_header *);
1301
1302 if (m->m_flags & (M_BCAST|M_MCAST)) {
1303 /* Tap off 802.1D packets; they do not get forwarded. */
1304 if (memcmp(eh->ether_dhost, bstp_etheraddr,
1305 ETHER_ADDR_LEN) == 0) {
1306 m = bstp_input(ifp, m);
1307 if (m == NULL)
1308 return (NULL);
1309 }
1310
1311 if (bif->bif_flags & IFBIF_STP) {
1312 switch (bif->bif_state) {
1313 case BSTP_IFSTATE_BLOCKING:
1314 case BSTP_IFSTATE_LISTENING:
1315 case BSTP_IFSTATE_DISABLED:
1316 return (m);
1317 }
1318 }
1319
1320 /*
1321 * Make a deep copy of the packet and enqueue the copy
1322 * for bridge processing; return the original packet for
1323 * local processing.
1324 */
1325 mc = m_dup(m, 0, M_COPYALL, M_NOWAIT);
1326 if (mc == NULL)
1327 return (m);
1328
1329 /* Perform the bridge forwarding function with the copy. */
1330 bridge_forward(sc, mc);
1331
1332 /* Return the original packet for local processing. */
1333 return (m);
1334 }
1335
1336 if (bif->bif_flags & IFBIF_STP) {
1337 switch (bif->bif_state) {
1338 case BSTP_IFSTATE_BLOCKING:
1339 case BSTP_IFSTATE_LISTENING:
1340 case BSTP_IFSTATE_DISABLED:
1341 return (m);
1342 }
1343 }
1344
1345 /*
1346 * Unicast. Make sure it's not for us.
1347 */
1348 LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
1349 /* It is destined for us. */
1350 if (memcmp(LLADDR(bif->bif_ifp->if_sadl), eh->ether_dhost,
1351 ETHER_ADDR_LEN) == 0) {
1352 if (bif->bif_flags & IFBIF_LEARNING)
1353 (void) bridge_rtupdate(sc,
1354 eh->ether_shost, ifp, 0, IFBAF_DYNAMIC);
1355 m->m_pkthdr.rcvif = bif->bif_ifp;
1356 return (m);
1357 }
1358
1359 /* We just received a packet that we sent out. */
1360 if (memcmp(LLADDR(bif->bif_ifp->if_sadl), eh->ether_shost,
1361 ETHER_ADDR_LEN) == 0) {
1362 m_freem(m);
1363 return (NULL);
1364 }
1365 }
1366
1367 /* Perform the bridge forwarding function. */
1368 bridge_forward(sc, m);
1369
1370 return (NULL);
1371 }
1372
1373 /*
1374 * bridge_broadcast:
1375 *
1376 * Send a frame to all interfaces that are members of
1377 * the bridge, except for the one on which the packet
1378 * arrived.
1379 */
1380 void
1381 bridge_broadcast(struct bridge_softc *sc, struct ifnet *src_if,
1382 struct mbuf *m)
1383 {
1384 struct bridge_iflist *bif;
1385 struct mbuf *mc;
1386 struct ifnet *dst_if;
1387 int used = 0;
1388
1389 LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
1390 dst_if = bif->bif_ifp;
1391 if (dst_if == src_if)
1392 continue;
1393
1394 if (bif->bif_flags & IFBIF_STP) {
1395 switch (bif->bif_state) {
1396 case BSTP_IFSTATE_BLOCKING:
1397 case BSTP_IFSTATE_DISABLED:
1398 continue;
1399 }
1400 }
1401
1402 if ((bif->bif_flags & IFBIF_DISCOVER) == 0 &&
1403 (m->m_flags & (M_BCAST|M_MCAST)) == 0)
1404 continue;
1405
1406 if ((dst_if->if_flags & IFF_RUNNING) == 0)
1407 continue;
1408
1409 if (LIST_NEXT(bif, bif_next) == NULL) {
1410 mc = m;
1411 used = 1;
1412 } else {
1413 mc = m_copym(m, 0, M_COPYALL, M_DONTWAIT);
1414 if (mc == NULL) {
1415 sc->sc_if.if_oerrors++;
1416 continue;
1417 }
1418 }
1419
1420 bridge_enqueue(sc, dst_if, mc);
1421 }
1422 if (used == 0)
1423 m_freem(m);
1424 }
1425
1426 /*
1427 * bridge_rtupdate:
1428 *
1429 * Add a bridge routing entry.
1430 */
1431 int
1432 bridge_rtupdate(struct bridge_softc *sc, const uint8_t *dst,
1433 struct ifnet *dst_if, int setflags, uint8_t flags)
1434 {
1435 struct bridge_rtnode *brt;
1436 int error;
1437
1438 /*
1439 * A route for this destination might already exist. If so,
1440 * update it, otherwise create a new one.
1441 */
1442 if ((brt = bridge_rtnode_lookup(sc, dst)) == NULL) {
1443 if (sc->sc_brtcnt >= sc->sc_brtmax)
1444 return (ENOSPC);
1445
1446 /*
1447 * Allocate a new bridge forwarding node, and
1448 * initialize the expiration time and Ethernet
1449 * address.
1450 */
1451 brt = pool_get(&bridge_rtnode_pool, PR_NOWAIT);
1452 if (brt == NULL)
1453 return (ENOMEM);
1454
1455 memset(brt, 0, sizeof(*brt));
1456 brt->brt_expire = mono_time.tv_sec + sc->sc_brttimeout;
1457 brt->brt_flags = IFBAF_DYNAMIC;
1458 memcpy(brt->brt_addr, dst, ETHER_ADDR_LEN);
1459
1460 if ((error = bridge_rtnode_insert(sc, brt)) != 0) {
1461 pool_put(&bridge_rtnode_pool, brt);
1462 return (error);
1463 }
1464 }
1465
1466 brt->brt_ifp = dst_if;
1467 if (setflags) {
1468 brt->brt_flags = flags;
1469 brt->brt_expire = (flags & IFBAF_STATIC) ? 0 :
1470 mono_time.tv_sec + sc->sc_brttimeout;
1471 }
1472
1473 return (0);
1474 }
1475
1476 /*
1477 * bridge_rtlookup:
1478 *
1479 * Lookup the destination interface for an address.
1480 */
1481 struct ifnet *
1482 bridge_rtlookup(struct bridge_softc *sc, const uint8_t *addr)
1483 {
1484 struct bridge_rtnode *brt;
1485
1486 if ((brt = bridge_rtnode_lookup(sc, addr)) == NULL)
1487 return (NULL);
1488
1489 return (brt->brt_ifp);
1490 }
1491
1492 /*
1493 * bridge_rttrim:
1494 *
1495 * Trim the routine table so that we have a number
1496 * of routing entries less than or equal to the
1497 * maximum number.
1498 */
1499 void
1500 bridge_rttrim(struct bridge_softc *sc)
1501 {
1502 struct bridge_rtnode *brt, *nbrt;
1503
1504 /* Make sure we actually need to do this. */
1505 if (sc->sc_brtcnt <= sc->sc_brtmax)
1506 return;
1507
1508 /* Force an aging cycle; this might trim enough addresses. */
1509 bridge_rtage(sc);
1510 if (sc->sc_brtcnt <= sc->sc_brtmax)
1511 return;
1512
1513 for (brt = LIST_FIRST(&sc->sc_rtlist); brt != NULL; brt = nbrt) {
1514 nbrt = LIST_NEXT(brt, brt_list);
1515 if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) {
1516 bridge_rtnode_destroy(sc, brt);
1517 if (sc->sc_brtcnt <= sc->sc_brtmax)
1518 return;
1519 }
1520 }
1521 }
1522
1523 /*
1524 * bridge_timer:
1525 *
1526 * Aging timer for the bridge.
1527 */
1528 void
1529 bridge_timer(void *arg)
1530 {
1531 struct bridge_softc *sc = arg;
1532 int s;
1533
1534 s = splnet();
1535 bridge_rtage(sc);
1536 splx(s);
1537
1538 if (sc->sc_if.if_flags & IFF_RUNNING)
1539 callout_reset(&sc->sc_brcallout,
1540 bridge_rtable_prune_period * hz, bridge_timer, sc);
1541 }
1542
1543 /*
1544 * bridge_rtage:
1545 *
1546 * Perform an aging cycle.
1547 */
1548 void
1549 bridge_rtage(struct bridge_softc *sc)
1550 {
1551 struct bridge_rtnode *brt, *nbrt;
1552
1553 for (brt = LIST_FIRST(&sc->sc_rtlist); brt != NULL; brt = nbrt) {
1554 nbrt = LIST_NEXT(brt, brt_list);
1555 if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) {
1556 if (mono_time.tv_sec >= brt->brt_expire)
1557 bridge_rtnode_destroy(sc, brt);
1558 }
1559 }
1560 }
1561
1562 /*
1563 * bridge_rtflush:
1564 *
1565 * Remove all dynamic addresses from the bridge.
1566 */
1567 void
1568 bridge_rtflush(struct bridge_softc *sc, int full)
1569 {
1570 struct bridge_rtnode *brt, *nbrt;
1571
1572 for (brt = LIST_FIRST(&sc->sc_rtlist); brt != NULL; brt = nbrt) {
1573 nbrt = LIST_NEXT(brt, brt_list);
1574 if (full || (brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC)
1575 bridge_rtnode_destroy(sc, brt);
1576 }
1577 }
1578
1579 /*
1580 * bridge_rtdaddr:
1581 *
1582 * Remove an address from the table.
1583 */
1584 int
1585 bridge_rtdaddr(struct bridge_softc *sc, const uint8_t *addr)
1586 {
1587 struct bridge_rtnode *brt;
1588
1589 if ((brt = bridge_rtnode_lookup(sc, addr)) == NULL)
1590 return (ENOENT);
1591
1592 bridge_rtnode_destroy(sc, brt);
1593 return (0);
1594 }
1595
1596 /*
1597 * bridge_rtdelete:
1598 *
1599 * Delete routes to a speicifc member interface.
1600 */
1601 void
1602 bridge_rtdelete(struct bridge_softc *sc, struct ifnet *ifp)
1603 {
1604 struct bridge_rtnode *brt, *nbrt;
1605
1606 for (brt = LIST_FIRST(&sc->sc_rtlist); brt != NULL; brt = nbrt) {
1607 nbrt = LIST_NEXT(brt, brt_list);
1608 if (brt->brt_ifp == ifp)
1609 bridge_rtnode_destroy(sc, brt);
1610 }
1611 }
1612
1613 /*
1614 * bridge_rtable_init:
1615 *
1616 * Initialize the route table for this bridge.
1617 */
1618 int
1619 bridge_rtable_init(struct bridge_softc *sc)
1620 {
1621 int i;
1622
1623 sc->sc_rthash = malloc(sizeof(*sc->sc_rthash) * BRIDGE_RTHASH_SIZE,
1624 M_DEVBUF, M_NOWAIT);
1625 if (sc->sc_rthash == NULL)
1626 return (ENOMEM);
1627
1628 for (i = 0; i < BRIDGE_RTHASH_SIZE; i++)
1629 LIST_INIT(&sc->sc_rthash[i]);
1630
1631 #if NRND > 0
1632 rnd_extract_data(&sc->sc_rthash_key, sizeof(sc->sc_rthash_key),
1633 RND_EXTRACT_ANY);
1634 #else
1635 sc->sc_rthash_key = random();
1636 #endif /* NRND > 0 */
1637
1638 LIST_INIT(&sc->sc_rtlist);
1639
1640 return (0);
1641 }
1642
1643 /*
1644 * bridge_rtable_fini:
1645 *
1646 * Deconstruct the route table for this bridge.
1647 */
1648 void
1649 bridge_rtable_fini(struct bridge_softc *sc)
1650 {
1651
1652 free(sc->sc_rthash, M_DEVBUF);
1653 }
1654
1655 /*
1656 * The following hash function is adapted from "Hash Functions" by Bob Jenkins
1657 * ("Algorithm Alley", Dr. Dobbs Journal, September 1997).
1658 */
1659 #define mix(a, b, c) \
1660 do { \
1661 a -= b; a -= c; a ^= (c >> 13); \
1662 b -= c; b -= a; b ^= (a << 8); \
1663 c -= a; c -= b; c ^= (b >> 13); \
1664 a -= b; a -= c; a ^= (c >> 12); \
1665 b -= c; b -= a; b ^= (a << 16); \
1666 c -= a; c -= b; c ^= (b >> 5); \
1667 a -= b; a -= c; a ^= (c >> 3); \
1668 b -= c; b -= a; b ^= (a << 10); \
1669 c -= a; c -= b; c ^= (b >> 15); \
1670 } while (/*CONSTCOND*/0)
1671
1672 static __inline uint32_t
1673 bridge_rthash(struct bridge_softc *sc, const uint8_t *addr)
1674 {
1675 uint32_t a = 0x9e3779b9, b = 0x9e3779b9, c = sc->sc_rthash_key;
1676
1677 b += addr[5] << 8;
1678 b += addr[4];
1679 a += addr[3] << 24;
1680 a += addr[2] << 16;
1681 a += addr[1] << 8;
1682 a += addr[0];
1683
1684 mix(a, b, c);
1685
1686 return (c & BRIDGE_RTHASH_MASK);
1687 }
1688
1689 #undef mix
1690
1691 /*
1692 * bridge_rtnode_lookup:
1693 *
1694 * Look up a bridge route node for the specified destination.
1695 */
1696 struct bridge_rtnode *
1697 bridge_rtnode_lookup(struct bridge_softc *sc, const uint8_t *addr)
1698 {
1699 struct bridge_rtnode *brt;
1700 uint32_t hash;
1701 int dir;
1702
1703 hash = bridge_rthash(sc, addr);
1704 LIST_FOREACH(brt, &sc->sc_rthash[hash], brt_hash) {
1705 dir = memcmp(addr, brt->brt_addr, ETHER_ADDR_LEN);
1706 if (dir == 0)
1707 return (brt);
1708 if (dir > 0)
1709 return (NULL);
1710 }
1711
1712 return (NULL);
1713 }
1714
1715 /*
1716 * bridge_rtnode_insert:
1717 *
1718 * Insert the specified bridge node into the route table. We
1719 * assume the entry is not already in the table.
1720 */
1721 int
1722 bridge_rtnode_insert(struct bridge_softc *sc, struct bridge_rtnode *brt)
1723 {
1724 struct bridge_rtnode *lbrt;
1725 uint32_t hash;
1726 int dir;
1727
1728 hash = bridge_rthash(sc, brt->brt_addr);
1729
1730 lbrt = LIST_FIRST(&sc->sc_rthash[hash]);
1731 if (lbrt == NULL) {
1732 LIST_INSERT_HEAD(&sc->sc_rthash[hash], brt, brt_hash);
1733 goto out;
1734 }
1735
1736 do {
1737 dir = memcmp(brt->brt_addr, lbrt->brt_addr, ETHER_ADDR_LEN);
1738 if (dir == 0)
1739 return (EEXIST);
1740 if (dir > 0) {
1741 LIST_INSERT_BEFORE(lbrt, brt, brt_hash);
1742 goto out;
1743 }
1744 if (LIST_NEXT(lbrt, brt_hash) == NULL) {
1745 LIST_INSERT_AFTER(lbrt, brt, brt_hash);
1746 goto out;
1747 }
1748 lbrt = LIST_NEXT(lbrt, brt_hash);
1749 } while (lbrt != NULL);
1750
1751 #ifdef DIAGNOSTIC
1752 panic("bridge_rtnode_insert: impossible");
1753 #endif
1754
1755 out:
1756 LIST_INSERT_HEAD(&sc->sc_rtlist, brt, brt_list);
1757 sc->sc_brtcnt++;
1758
1759 return (0);
1760 }
1761
1762 /*
1763 * bridge_rtnode_destroy:
1764 *
1765 * Destroy a bridge rtnode.
1766 */
1767 void
1768 bridge_rtnode_destroy(struct bridge_softc *sc, struct bridge_rtnode *brt)
1769 {
1770
1771 LIST_REMOVE(brt, brt_hash);
1772
1773 LIST_REMOVE(brt, brt_list);
1774 sc->sc_brtcnt--;
1775 pool_put(&bridge_rtnode_pool, brt);
1776 }
1777