Line data Source code
1 : /* $OpenBSD: bridgectl.c,v 1.8 2018/02/05 05:06:51 henning Exp $ */
2 :
3 : /*
4 : * Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net)
5 : * All rights reserved.
6 : *
7 : * Redistribution and use in source and binary forms, with or without
8 : * modification, are permitted provided that the following conditions
9 : * are met:
10 : * 1. Redistributions of source code must retain the above copyright
11 : * notice, this list of conditions and the following disclaimer.
12 : * 2. Redistributions in binary form must reproduce the above copyright
13 : * notice, this list of conditions and the following disclaimer in the
14 : * documentation and/or other materials provided with the distribution.
15 : *
16 : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 : * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 : * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20 : * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 : * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 : * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24 : * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25 : * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 : * POSSIBILITY OF SUCH DAMAGE.
27 : *
28 : * Effort sponsored in part by the Defense Advanced Research Projects
29 : * Agency (DARPA) and Air Force Research Laboratory, Air Force
30 : * Materiel Command, USAF, under agreement number F30602-01-2-0537.
31 : *
32 : */
33 :
34 : #include "pf.h"
35 :
36 : #include <sys/param.h>
37 : #include <sys/systm.h>
38 : #include <sys/mbuf.h>
39 : #include <sys/socket.h>
40 : #include <sys/ioctl.h>
41 : #include <sys/timeout.h>
42 : #include <sys/kernel.h>
43 :
44 : #include <crypto/siphash.h>
45 :
46 : #include <net/if.h>
47 :
48 : #include <netinet/in.h>
49 : #include <netinet/if_ether.h>
50 :
51 : #include <net/if_bridge.h>
52 :
53 :
54 : int bridge_rtfind(struct bridge_softc *, struct ifbaconf *);
55 : int bridge_rtdaddr(struct bridge_softc *, struct ether_addr *);
56 : u_int32_t bridge_hash(struct bridge_softc *, struct ether_addr *);
57 :
58 : int bridge_brlconf(struct bridge_softc *, struct ifbrlconf *);
59 : int bridge_addrule(struct bridge_iflist *, struct ifbrlreq *, int out);
60 :
61 : int
62 0 : bridgectl_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
63 : {
64 0 : struct bridge_softc *sc = (struct bridge_softc *)ifp->if_softc;
65 0 : struct ifbreq *req = (struct ifbreq *)data;
66 0 : struct ifbrlreq *brlreq = (struct ifbrlreq *)data;
67 0 : struct ifbareq *bareq = (struct ifbareq *)data;
68 0 : struct ifbrparam *bparam = (struct ifbrparam *)data;
69 : struct bridge_iflist *p;
70 : struct ifnet *ifs;
71 : int error = 0;
72 :
73 0 : switch (cmd) {
74 : case SIOCBRDGRTS:
75 0 : error = bridge_rtfind(sc, (struct ifbaconf *)data);
76 0 : break;
77 : case SIOCBRDGFLUSH:
78 0 : bridge_rtflush(sc, req->ifbr_ifsflags);
79 0 : break;
80 : case SIOCBRDGSADDR:
81 0 : ifs = ifunit(bareq->ifba_ifsname);
82 0 : if (ifs == NULL) { /* no such interface */
83 : error = ENOENT;
84 0 : break;
85 : }
86 0 : p = (struct bridge_iflist *)ifs->if_bridgeport;
87 0 : if (p == NULL || p->bridge_sc != sc) {
88 : error = ESRCH;
89 0 : break;
90 : }
91 :
92 0 : ifs = bridge_rtupdate(sc, &bareq->ifba_dst, ifs, 1,
93 0 : bareq->ifba_flags, NULL);
94 0 : if (ifs == NULL)
95 0 : error = ENOMEM;
96 : break;
97 : case SIOCBRDGDADDR:
98 0 : error = bridge_rtdaddr(sc, &bareq->ifba_dst);
99 0 : break;
100 : case SIOCBRDGGCACHE:
101 0 : bparam->ifbrp_csize = sc->sc_brtmax;
102 0 : break;
103 : case SIOCBRDGSCACHE:
104 0 : sc->sc_brtmax = bparam->ifbrp_csize;
105 0 : break;
106 : case SIOCBRDGSTO:
107 0 : if (bparam->ifbrp_ctime < 0 ||
108 0 : bparam->ifbrp_ctime > INT_MAX / hz) {
109 : error = EINVAL;
110 0 : break;
111 : }
112 0 : sc->sc_brttimeout = bparam->ifbrp_ctime;
113 0 : if (bparam->ifbrp_ctime != 0)
114 0 : timeout_add_sec(&sc->sc_brtimeout, sc->sc_brttimeout);
115 : else
116 0 : timeout_del(&sc->sc_brtimeout);
117 : break;
118 : case SIOCBRDGGTO:
119 0 : bparam->ifbrp_ctime = sc->sc_brttimeout;
120 0 : break;
121 : case SIOCBRDGARL:
122 0 : ifs = ifunit(brlreq->ifbr_ifsname);
123 0 : if (ifs == NULL) {
124 : error = ENOENT;
125 0 : break;
126 : }
127 0 : p = (struct bridge_iflist *)ifs->if_bridgeport;
128 0 : if (p == NULL || p->bridge_sc != sc) {
129 : error = ESRCH;
130 0 : break;
131 : }
132 0 : if ((brlreq->ifbr_action != BRL_ACTION_BLOCK &&
133 0 : brlreq->ifbr_action != BRL_ACTION_PASS) ||
134 0 : (brlreq->ifbr_flags & (BRL_FLAG_IN|BRL_FLAG_OUT)) == 0) {
135 : error = EINVAL;
136 0 : break;
137 : }
138 0 : if (brlreq->ifbr_flags & BRL_FLAG_IN) {
139 0 : error = bridge_addrule(p, brlreq, 0);
140 0 : if (error)
141 : break;
142 : }
143 0 : if (brlreq->ifbr_flags & BRL_FLAG_OUT) {
144 0 : error = bridge_addrule(p, brlreq, 1);
145 0 : if (error)
146 : break;
147 : }
148 : break;
149 : case SIOCBRDGFRL:
150 0 : ifs = ifunit(brlreq->ifbr_ifsname);
151 0 : if (ifs == NULL) {
152 : error = ENOENT;
153 0 : break;
154 : }
155 0 : p = (struct bridge_iflist *)ifs->if_bridgeport;
156 0 : if (p == NULL || p->bridge_sc != sc) {
157 : error = ESRCH;
158 0 : break;
159 : }
160 0 : bridge_flushrule(p);
161 0 : break;
162 : case SIOCBRDGGRL:
163 0 : error = bridge_brlconf(sc, (struct ifbrlconf *)data);
164 0 : break;
165 : default:
166 : break;
167 : }
168 :
169 0 : return (error);
170 : }
171 :
172 : struct ifnet *
173 0 : bridge_rtupdate(struct bridge_softc *sc, struct ether_addr *ea,
174 : struct ifnet *ifp, int setflags, u_int8_t flags, struct mbuf *m)
175 : {
176 : struct bridge_rtnode *p, *q;
177 : struct bridge_tunneltag *brtag = NULL;
178 : u_int32_t h;
179 : int dir;
180 :
181 0 : if (m != NULL) {
182 : /* Check if the mbuf was tagged with a tunnel endpoint addr */
183 0 : brtag = bridge_tunnel(m);
184 0 : }
185 :
186 0 : h = bridge_hash(sc, ea);
187 0 : p = LIST_FIRST(&sc->sc_rts[h]);
188 0 : if (p == NULL) {
189 0 : if (sc->sc_brtcnt >= sc->sc_brtmax)
190 : goto done;
191 0 : p = malloc(sizeof(*p), M_DEVBUF, M_NOWAIT);
192 0 : if (p == NULL)
193 : goto done;
194 :
195 0 : bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
196 0 : p->brt_if = ifp;
197 0 : p->brt_age = 1;
198 0 : bridge_copytag(brtag, &p->brt_tunnel);
199 :
200 0 : if (setflags)
201 0 : p->brt_flags = flags;
202 : else
203 0 : p->brt_flags = IFBAF_DYNAMIC;
204 :
205 0 : LIST_INSERT_HEAD(&sc->sc_rts[h], p, brt_next);
206 0 : sc->sc_brtcnt++;
207 0 : goto want;
208 : }
209 :
210 0 : do {
211 : q = p;
212 0 : p = LIST_NEXT(p, brt_next);
213 :
214 0 : dir = memcmp(ea, &q->brt_addr, sizeof(q->brt_addr));
215 0 : if (dir == 0) {
216 0 : if (setflags) {
217 0 : q->brt_if = ifp;
218 0 : q->brt_flags = flags;
219 0 : } else if (!(q->brt_flags & IFBAF_STATIC))
220 0 : q->brt_if = ifp;
221 :
222 0 : if (q->brt_if == ifp)
223 0 : q->brt_age = 1;
224 0 : ifp = q->brt_if;
225 0 : bridge_copytag(brtag, &q->brt_tunnel);
226 :
227 0 : goto want;
228 : }
229 :
230 0 : if (dir > 0) {
231 0 : if (sc->sc_brtcnt >= sc->sc_brtmax)
232 : goto done;
233 0 : p = malloc(sizeof(*p), M_DEVBUF, M_NOWAIT);
234 0 : if (p == NULL)
235 : goto done;
236 :
237 0 : bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
238 0 : p->brt_if = ifp;
239 0 : p->brt_age = 1;
240 0 : bridge_copytag(brtag, &p->brt_tunnel);
241 :
242 0 : if (setflags)
243 0 : p->brt_flags = flags;
244 : else
245 0 : p->brt_flags = IFBAF_DYNAMIC;
246 :
247 0 : LIST_INSERT_BEFORE(q, p, brt_next);
248 0 : sc->sc_brtcnt++;
249 0 : goto want;
250 : }
251 :
252 0 : if (p == NULL) {
253 0 : if (sc->sc_brtcnt >= sc->sc_brtmax)
254 : goto done;
255 0 : p = malloc(sizeof(*p), M_DEVBUF, M_NOWAIT);
256 0 : if (p == NULL)
257 : goto done;
258 :
259 0 : bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
260 0 : p->brt_if = ifp;
261 0 : p->brt_age = 1;
262 0 : bridge_copytag(brtag, &p->brt_tunnel);
263 :
264 0 : if (setflags)
265 0 : p->brt_flags = flags;
266 : else
267 0 : p->brt_flags = IFBAF_DYNAMIC;
268 0 : LIST_INSERT_AFTER(q, p, brt_next);
269 0 : sc->sc_brtcnt++;
270 0 : goto want;
271 : }
272 0 : } while (p != NULL);
273 :
274 : done:
275 0 : ifp = NULL;
276 : want:
277 0 : return (ifp);
278 : }
279 :
280 : struct bridge_rtnode *
281 0 : bridge_rtlookup(struct bridge_softc *sc, struct ether_addr *ea)
282 : {
283 : struct bridge_rtnode *p;
284 : u_int32_t h;
285 : int dir;
286 :
287 0 : h = bridge_hash(sc, ea);
288 0 : LIST_FOREACH(p, &sc->sc_rts[h], brt_next) {
289 0 : dir = memcmp(ea, &p->brt_addr, sizeof(p->brt_addr));
290 0 : if (dir == 0)
291 0 : return (p);
292 0 : if (dir > 0)
293 : goto fail;
294 : }
295 : fail:
296 0 : return (NULL);
297 0 : }
298 :
299 : u_int32_t
300 0 : bridge_hash(struct bridge_softc *sc, struct ether_addr *addr)
301 : {
302 0 : return SipHash24((SIPHASH_KEY *)sc->sc_hashkey, addr, ETHER_ADDR_LEN) &
303 : BRIDGE_RTABLE_MASK;
304 : }
305 :
306 : /*
307 : * Perform an aging cycle
308 : */
309 : void
310 0 : bridge_rtage(void *vsc)
311 : {
312 0 : struct bridge_softc *sc = vsc;
313 : struct bridge_rtnode *n, *p;
314 : int i;
315 :
316 0 : KERNEL_ASSERT_LOCKED();
317 :
318 0 : for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
319 0 : n = LIST_FIRST(&sc->sc_rts[i]);
320 0 : while (n != NULL) {
321 0 : if ((n->brt_flags & IFBAF_TYPEMASK) == IFBAF_STATIC) {
322 0 : n->brt_age = !n->brt_age;
323 0 : if (n->brt_age)
324 0 : n->brt_age = 0;
325 0 : n = LIST_NEXT(n, brt_next);
326 0 : } else if (n->brt_age) {
327 0 : n->brt_age = 0;
328 0 : n = LIST_NEXT(n, brt_next);
329 0 : } else {
330 0 : p = LIST_NEXT(n, brt_next);
331 0 : LIST_REMOVE(n, brt_next);
332 0 : sc->sc_brtcnt--;
333 0 : free(n, M_DEVBUF, sizeof *n);
334 : n = p;
335 : }
336 : }
337 : }
338 :
339 0 : if (sc->sc_brttimeout != 0)
340 0 : timeout_add_sec(&sc->sc_brtimeout, sc->sc_brttimeout);
341 0 : }
342 :
343 : void
344 0 : bridge_rtagenode(struct ifnet *ifp, int age)
345 : {
346 : struct bridge_softc *sc;
347 : struct bridge_rtnode *n;
348 : int i;
349 :
350 0 : sc = ((struct bridge_iflist *)ifp->if_bridgeport)->bridge_sc;
351 0 : if (sc == NULL)
352 0 : return;
353 :
354 : /*
355 : * If the age is zero then flush, otherwise set all the expiry times to
356 : * age for the interface
357 : */
358 0 : if (age == 0)
359 0 : bridge_rtdelete(sc, ifp, 1);
360 : else {
361 0 : for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
362 0 : LIST_FOREACH(n, &sc->sc_rts[i], brt_next) {
363 : /* Cap the expiry time to 'age' */
364 0 : if (n->brt_if == ifp &&
365 0 : n->brt_age > time_uptime + age &&
366 0 : (n->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC)
367 0 : n->brt_age = time_uptime + age;
368 : }
369 : }
370 : }
371 0 : }
372 :
373 : /*
374 : * Remove all dynamic addresses from the cache
375 : */
376 : void
377 0 : bridge_rtflush(struct bridge_softc *sc, int full)
378 : {
379 : int i;
380 : struct bridge_rtnode *p, *n;
381 :
382 0 : for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
383 0 : n = LIST_FIRST(&sc->sc_rts[i]);
384 0 : while (n != NULL) {
385 0 : if (full ||
386 0 : (n->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) {
387 0 : p = LIST_NEXT(n, brt_next);
388 0 : LIST_REMOVE(n, brt_next);
389 0 : sc->sc_brtcnt--;
390 0 : free(n, M_DEVBUF, sizeof *n);
391 : n = p;
392 0 : } else
393 0 : n = LIST_NEXT(n, brt_next);
394 : }
395 : }
396 0 : }
397 :
398 : /*
399 : * Remove an address from the cache
400 : */
401 : int
402 0 : bridge_rtdaddr(struct bridge_softc *sc, struct ether_addr *ea)
403 : {
404 : int h;
405 : struct bridge_rtnode *p;
406 :
407 0 : h = bridge_hash(sc, ea);
408 0 : LIST_FOREACH(p, &sc->sc_rts[h], brt_next) {
409 0 : if (memcmp(ea, &p->brt_addr, sizeof(p->brt_addr)) == 0) {
410 0 : LIST_REMOVE(p, brt_next);
411 0 : sc->sc_brtcnt--;
412 0 : free(p, M_DEVBUF, sizeof *p);
413 0 : return (0);
414 : }
415 : }
416 :
417 0 : return (ENOENT);
418 0 : }
419 :
420 : /*
421 : * Delete routes to a specific interface member.
422 : */
423 : void
424 0 : bridge_rtdelete(struct bridge_softc *sc, struct ifnet *ifp, int dynonly)
425 : {
426 : int i;
427 : struct bridge_rtnode *n, *p;
428 :
429 : /*
430 : * Loop through all of the hash buckets and traverse each
431 : * chain looking for routes to this interface.
432 : */
433 0 : for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
434 0 : n = LIST_FIRST(&sc->sc_rts[i]);
435 0 : while (n != NULL) {
436 0 : if (n->brt_if != ifp) {
437 : /* Not ours */
438 0 : n = LIST_NEXT(n, brt_next);
439 0 : continue;
440 : }
441 0 : if (dynonly &&
442 0 : (n->brt_flags & IFBAF_TYPEMASK) != IFBAF_DYNAMIC) {
443 : /* only deleting dynamics */
444 0 : n = LIST_NEXT(n, brt_next);
445 0 : continue;
446 : }
447 0 : p = LIST_NEXT(n, brt_next);
448 0 : LIST_REMOVE(n, brt_next);
449 0 : sc->sc_brtcnt--;
450 0 : free(n, M_DEVBUF, sizeof *n);
451 : n = p;
452 : }
453 : }
454 0 : }
455 :
456 : /*
457 : * Gather all of the routes for this interface.
458 : */
459 : int
460 0 : bridge_rtfind(struct bridge_softc *sc, struct ifbaconf *baconf)
461 : {
462 : int i, error = 0, onlycnt = 0;
463 : u_int32_t cnt = 0;
464 : struct bridge_rtnode *n;
465 0 : struct ifbareq bareq;
466 :
467 0 : if (baconf->ifbac_len == 0)
468 0 : onlycnt = 1;
469 :
470 0 : for (i = 0, cnt = 0; i < BRIDGE_RTABLE_SIZE; i++) {
471 0 : LIST_FOREACH(n, &sc->sc_rts[i], brt_next) {
472 0 : if (!onlycnt) {
473 0 : if (baconf->ifbac_len < sizeof(struct ifbareq))
474 : goto done;
475 0 : bcopy(sc->sc_if.if_xname, bareq.ifba_name,
476 : sizeof(bareq.ifba_name));
477 0 : bcopy(n->brt_if->if_xname, bareq.ifba_ifsname,
478 : sizeof(bareq.ifba_ifsname));
479 0 : bcopy(&n->brt_addr, &bareq.ifba_dst,
480 : sizeof(bareq.ifba_dst));
481 0 : bridge_copyaddr(&n->brt_tunnel.brtag_peer.sa,
482 0 : sstosa(&bareq.ifba_dstsa));
483 0 : bareq.ifba_age = n->brt_age;
484 0 : bareq.ifba_flags = n->brt_flags;
485 0 : error = copyout((caddr_t)&bareq,
486 0 : (caddr_t)(baconf->ifbac_req + cnt), sizeof(bareq));
487 0 : if (error)
488 : goto done;
489 0 : baconf->ifbac_len -= sizeof(struct ifbareq);
490 0 : }
491 0 : cnt++;
492 : }
493 : }
494 : done:
495 0 : baconf->ifbac_len = cnt * sizeof(struct ifbareq);
496 0 : return (error);
497 0 : }
498 :
499 : void
500 0 : bridge_update(struct ifnet *ifp, struct ether_addr *ea, int delete)
501 : {
502 : struct bridge_softc *sc;
503 : struct bridge_iflist *bif;
504 : u_int8_t *addr;
505 :
506 0 : addr = (u_int8_t *)ea;
507 :
508 0 : bif = (struct bridge_iflist *)ifp->if_bridgeport;
509 0 : sc = bif->bridge_sc;
510 :
511 : /*
512 : * Update the bridge interface if it is in
513 : * the learning state.
514 : */
515 0 : if ((bif->bif_flags & IFBIF_LEARNING) &&
516 0 : (ETHER_IS_MULTICAST(addr) == 0) &&
517 0 : !(addr[0] == 0 && addr[1] == 0 && addr[2] == 0 &&
518 0 : addr[3] == 0 && addr[4] == 0 && addr[5] == 0)) {
519 : /* Care must be taken with spanning tree */
520 0 : if ((bif->bif_flags & IFBIF_STP) &&
521 0 : (bif->bif_state == BSTP_IFSTATE_DISCARDING))
522 0 : return;
523 :
524 : /* Delete the address from the bridge */
525 0 : bridge_rtdaddr(sc, ea);
526 :
527 0 : if (!delete) {
528 : /* Update the bridge table */
529 0 : bridge_rtupdate(sc, ea, ifp, 0, IFBAF_DYNAMIC, NULL);
530 0 : }
531 : }
532 0 : }
533 :
534 : /*
535 : * bridge filter/matching rules
536 : */
537 : int
538 0 : bridge_brlconf(struct bridge_softc *sc, struct ifbrlconf *bc)
539 : {
540 : struct ifnet *ifp;
541 : struct bridge_iflist *ifl;
542 : struct brl_node *n;
543 0 : struct ifbrlreq req;
544 : int error = 0;
545 : u_int32_t i = 0, total = 0;
546 :
547 0 : ifp = ifunit(bc->ifbrl_ifsname);
548 0 : if (ifp == NULL)
549 0 : return (ENOENT);
550 0 : ifl = (struct bridge_iflist *)ifp->if_bridgeport;
551 0 : if (ifl == NULL || ifl->bridge_sc != sc)
552 0 : return (ESRCH);
553 :
554 0 : SIMPLEQ_FOREACH(n, &ifl->bif_brlin, brl_next) {
555 0 : total++;
556 : }
557 0 : SIMPLEQ_FOREACH(n, &ifl->bif_brlout, brl_next) {
558 0 : total++;
559 : }
560 :
561 0 : if (bc->ifbrl_len == 0) {
562 : i = total;
563 0 : goto done;
564 : }
565 :
566 0 : SIMPLEQ_FOREACH(n, &ifl->bif_brlin, brl_next) {
567 0 : bzero(&req, sizeof req);
568 0 : if (bc->ifbrl_len < sizeof(req))
569 : goto done;
570 0 : strlcpy(req.ifbr_name, sc->sc_if.if_xname, IFNAMSIZ);
571 0 : strlcpy(req.ifbr_ifsname, ifl->ifp->if_xname, IFNAMSIZ);
572 0 : req.ifbr_action = n->brl_action;
573 0 : req.ifbr_flags = n->brl_flags;
574 0 : req.ifbr_src = n->brl_src;
575 0 : req.ifbr_dst = n->brl_dst;
576 0 : req.ifbr_arpf = n->brl_arpf;
577 : #if NPF > 0
578 0 : req.ifbr_tagname[0] = '\0';
579 0 : if (n->brl_tag)
580 0 : pf_tag2tagname(n->brl_tag, req.ifbr_tagname);
581 : #endif
582 0 : error = copyout((caddr_t)&req,
583 0 : (caddr_t)(bc->ifbrl_buf + (i * sizeof(req))), sizeof(req));
584 0 : if (error)
585 : goto done;
586 0 : i++;
587 0 : bc->ifbrl_len -= sizeof(req);
588 : }
589 :
590 0 : SIMPLEQ_FOREACH(n, &ifl->bif_brlout, brl_next) {
591 0 : bzero(&req, sizeof req);
592 0 : if (bc->ifbrl_len < sizeof(req))
593 : goto done;
594 0 : strlcpy(req.ifbr_name, sc->sc_if.if_xname, IFNAMSIZ);
595 0 : strlcpy(req.ifbr_ifsname, ifl->ifp->if_xname, IFNAMSIZ);
596 0 : req.ifbr_action = n->brl_action;
597 0 : req.ifbr_flags = n->brl_flags;
598 0 : req.ifbr_src = n->brl_src;
599 0 : req.ifbr_dst = n->brl_dst;
600 0 : req.ifbr_arpf = n->brl_arpf;
601 : #if NPF > 0
602 0 : req.ifbr_tagname[0] = '\0';
603 0 : if (n->brl_tag)
604 0 : pf_tag2tagname(n->brl_tag, req.ifbr_tagname);
605 : #endif
606 0 : error = copyout((caddr_t)&req,
607 0 : (caddr_t)(bc->ifbrl_buf + (i * sizeof(req))), sizeof(req));
608 0 : if (error)
609 : goto done;
610 0 : i++;
611 0 : bc->ifbrl_len -= sizeof(req);
612 : }
613 :
614 : done:
615 0 : bc->ifbrl_len = i * sizeof(req);
616 0 : return (error);
617 0 : }
618 :
619 : u_int8_t
620 0 : bridge_arpfilter(struct brl_node *n, struct ether_header *eh, struct mbuf *m)
621 : {
622 0 : struct ether_arp ea;
623 :
624 0 : if (!(n->brl_arpf.brla_flags & (BRLA_ARP|BRLA_RARP)))
625 0 : return (1);
626 :
627 0 : if (ntohs(eh->ether_type) != ETHERTYPE_ARP)
628 0 : return (0);
629 0 : if (m->m_pkthdr.len <= ETHER_HDR_LEN + sizeof(ea))
630 0 : return (0); /* log error? */
631 0 : m_copydata(m, ETHER_HDR_LEN, sizeof(ea), (caddr_t)&ea);
632 :
633 0 : if (ntohs(ea.arp_hrd) != ARPHRD_ETHER ||
634 0 : ntohs(ea.arp_pro) != ETHERTYPE_IP ||
635 0 : ea.arp_hln != ETHER_ADDR_LEN ||
636 0 : ea.arp_pln != sizeof(struct in_addr))
637 0 : return (0);
638 0 : if ((n->brl_arpf.brla_flags & BRLA_ARP) &&
639 0 : ntohs(ea.arp_op) != ARPOP_REQUEST &&
640 0 : ntohs(ea.arp_op) != ARPOP_REPLY)
641 0 : return (0);
642 0 : if ((n->brl_arpf.brla_flags & BRLA_RARP) &&
643 0 : ntohs(ea.arp_op) != ARPOP_REVREQUEST &&
644 0 : ntohs(ea.arp_op) != ARPOP_REVREPLY)
645 0 : return (0);
646 0 : if (n->brl_arpf.brla_op && ntohs(ea.arp_op) != n->brl_arpf.brla_op)
647 0 : return (0);
648 0 : if (n->brl_arpf.brla_flags & BRLA_SHA &&
649 0 : memcmp(ea.arp_sha, &n->brl_arpf.brla_sha, ETHER_ADDR_LEN))
650 0 : return (0);
651 0 : if (n->brl_arpf.brla_flags & BRLA_THA &&
652 0 : memcmp(ea.arp_tha, &n->brl_arpf.brla_tha, ETHER_ADDR_LEN))
653 0 : return (0);
654 0 : if (n->brl_arpf.brla_flags & BRLA_SPA &&
655 0 : memcmp(ea.arp_spa, &n->brl_arpf.brla_spa, sizeof(struct in_addr)))
656 0 : return (0);
657 0 : if (n->brl_arpf.brla_flags & BRLA_TPA &&
658 0 : memcmp(ea.arp_tpa, &n->brl_arpf.brla_tpa, sizeof(struct in_addr)))
659 0 : return (0);
660 :
661 0 : return (1);
662 0 : }
663 :
664 : u_int8_t
665 0 : bridge_filterrule(struct brl_head *h, struct ether_header *eh, struct mbuf *m)
666 : {
667 : struct brl_node *n;
668 : u_int8_t flags;
669 :
670 0 : SIMPLEQ_FOREACH(n, h, brl_next) {
671 0 : if (!bridge_arpfilter(n, eh, m))
672 : continue;
673 0 : flags = n->brl_flags & (BRL_FLAG_SRCVALID|BRL_FLAG_DSTVALID);
674 0 : if (flags == 0)
675 : goto return_action;
676 0 : if (flags == (BRL_FLAG_SRCVALID|BRL_FLAG_DSTVALID)) {
677 0 : if (memcmp(eh->ether_shost, &n->brl_src,
678 : ETHER_ADDR_LEN))
679 : continue;
680 0 : if (memcmp(eh->ether_dhost, &n->brl_dst,
681 : ETHER_ADDR_LEN))
682 : continue;
683 : goto return_action;
684 : }
685 0 : if (flags == BRL_FLAG_SRCVALID) {
686 0 : if (memcmp(eh->ether_shost, &n->brl_src,
687 : ETHER_ADDR_LEN))
688 : continue;
689 : goto return_action;
690 : }
691 0 : if (flags == BRL_FLAG_DSTVALID) {
692 0 : if (memcmp(eh->ether_dhost, &n->brl_dst,
693 : ETHER_ADDR_LEN))
694 : continue;
695 : goto return_action;
696 : }
697 : }
698 0 : return (BRL_ACTION_PASS);
699 :
700 : return_action:
701 : #if NPF > 0
702 0 : pf_tag_packet(m, n->brl_tag, -1);
703 : #endif
704 0 : return (n->brl_action);
705 0 : }
706 :
707 : int
708 0 : bridge_addrule(struct bridge_iflist *bif, struct ifbrlreq *req, int out)
709 : {
710 : struct brl_node *n;
711 :
712 0 : n = malloc(sizeof(*n), M_DEVBUF, M_NOWAIT);
713 0 : if (n == NULL)
714 0 : return (ENOMEM);
715 0 : bcopy(&req->ifbr_src, &n->brl_src, sizeof(struct ether_addr));
716 0 : bcopy(&req->ifbr_dst, &n->brl_dst, sizeof(struct ether_addr));
717 0 : n->brl_action = req->ifbr_action;
718 0 : n->brl_flags = req->ifbr_flags;
719 0 : n->brl_arpf = req->ifbr_arpf;
720 : #if NPF > 0
721 0 : if (req->ifbr_tagname[0])
722 0 : n->brl_tag = pf_tagname2tag(req->ifbr_tagname, 1);
723 : else
724 0 : n->brl_tag = 0;
725 : #endif
726 0 : if (out) {
727 0 : n->brl_flags &= ~BRL_FLAG_IN;
728 0 : n->brl_flags |= BRL_FLAG_OUT;
729 0 : SIMPLEQ_INSERT_TAIL(&bif->bif_brlout, n, brl_next);
730 0 : } else {
731 0 : n->brl_flags &= ~BRL_FLAG_OUT;
732 0 : n->brl_flags |= BRL_FLAG_IN;
733 0 : SIMPLEQ_INSERT_TAIL(&bif->bif_brlin, n, brl_next);
734 : }
735 0 : return (0);
736 0 : }
737 :
738 : void
739 0 : bridge_flushrule(struct bridge_iflist *bif)
740 : {
741 : struct brl_node *p;
742 :
743 0 : while (!SIMPLEQ_EMPTY(&bif->bif_brlin)) {
744 : p = SIMPLEQ_FIRST(&bif->bif_brlin);
745 0 : SIMPLEQ_REMOVE_HEAD(&bif->bif_brlin, brl_next);
746 : #if NPF > 0
747 0 : pf_tag_unref(p->brl_tag);
748 : #endif
749 0 : free(p, M_DEVBUF, sizeof *p);
750 : }
751 0 : while (!SIMPLEQ_EMPTY(&bif->bif_brlout)) {
752 : p = SIMPLEQ_FIRST(&bif->bif_brlout);
753 0 : SIMPLEQ_REMOVE_HEAD(&bif->bif_brlout, brl_next);
754 : #if NPF > 0
755 0 : pf_tag_unref(p->brl_tag);
756 : #endif
757 0 : free(p, M_DEVBUF, sizeof *p);
758 : }
759 0 : }
|