1 /* $OpenBSD: brconfig.c,v 1.33 2004/09/14 22:13:03 deraadt 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
29 #include <stdio.h>
30 #include <sys/types.h>
31 #include <unistd.h>
32 #include <stdlib.h>
33 #include <sys/param.h>
34 #include <sys/socket.h>
35 #include <sys/ioctl.h>
36 #include <net/if.h>
37 #include <net/if_dl.h>
38 #include <netinet/in.h>
39 #include <netinet/if_ether.h>
40 #include <net/if_bridge.h>
41 #include <sys/errno.h>
42 #include <string.h>
43 #include <err.h>
44 #include <sysexits.h>
45 #include <limits.h>
46
47 void usage(void);
48 int bridge_setflag(int, char *, short);
49 int bridge_clrflag(int, char *, short);
50 int bridge_ifsetflag(int, char *, char *, u_int32_t);
51 int bridge_ifclrflag(int, char *, char *, u_int32_t);
52 int bridge_list(int, char *, char *);
53 int bridge_cfg(int, char *, char *);
54 int bridge_addrs(int, char *, char *);
55 int bridge_addaddr(int, char *, char *, char *);
56 int bridge_deladdr(int, char *, char *);
57 int bridge_maxaddr(int, char *, char *);
58 int bridge_maxage(int, char *, char *);
59 int bridge_priority(int, char *, char *);
60 int bridge_fwddelay(int, char *, char *);
61 int bridge_hellotime(int, char *, char *);
62 int bridge_ifprio(int, char *, char *, char *);
63 int bridge_ifcost(int, char *, char *, char *);
64 int bridge_timeout(int, char *, char *);
65 int bridge_flush(int, char *);
66 int bridge_flushall(int, char *);
67 int bridge_add(int, char *, char *);
68 int bridge_delete(int, char *, char *);
69 int bridge_addspan(int, char *, char *);
70 int bridge_delspan(int, char *, char *);
71 int bridge_status(int, char *);
72 int is_bridge(int, char *);
73 int bridge_show_all(int);
74 void printb(char *, unsigned short, char *);
75 int bridge_rule(int, char *, int, char **, int);
76 int bridge_rules(int, char *, char *, char *);
77 int bridge_flushrule(int, char *, char *);
78 void bridge_badrule(int, char **, int);
79 void bridge_showrule(struct ifbrlreq *, char *);
80 int bridge_rulefile(int, char *, char *);
81
82 /* if_flags bits: borrowed from ifconfig.c */
83 #define IFFBITS \
84 "\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6NOTRAILERS\7RUNNING\10NOARP\
85 \11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2\20MULTICAST"
86
87 #define IFBAFBITS "\020\1STATIC"
88 #define IFBIFBITS "\020\1LEARNING\2DISCOVER\3BLOCKNONIP\4STP\11SPAN"
89
90 char *stpstates[] = {
91 "disabled",
92 "listening",
93 "learning",
94 "forwarding",
95 "blocking",
96 };
97
98 void
usage(void)99 usage(void)
100 {
101 fprintf(stderr, "usage: brconfig -a\n");
102 fprintf(stderr,
103 " brconfig interface [up] [down] [add if] [del if] ...\n");
104 }
105
106 int
main(int argc,char * argv[])107 main(int argc, char *argv[])
108 {
109 int error = 0, sock;
110 char *brdg;
111
112 if (argc < 2) {
113 usage();
114 return (EX_USAGE);
115 }
116
117 sock = socket(AF_INET, SOCK_DGRAM, 0);
118 if (sock < 0)
119 err(1, "socket");
120
121 argc--; argv++;
122 brdg = argv[0];
123
124 if (strcmp(brdg, "-a") == 0)
125 return bridge_show_all(sock);
126
127 if (strlen(brdg) >= IFNAMSIZ) {
128 warnx("%s is not a bridge", brdg);
129 return (EX_USAGE);
130 }
131
132 if (!is_bridge(sock, brdg)) {
133 if (errno == ENXIO)
134 warn("%s", brdg);
135 else
136 warnx("%s is not a bridge", brdg);
137 return (EX_USAGE);
138 }
139
140 if (argc == 1) {
141 error = bridge_status(sock, brdg);
142 return (error);
143 }
144
145 for (argc--, argv++; argc != 0; argc--, argv++) {
146 if (strcmp("add", argv[0]) == 0) {
147 argc--; argv++;
148 if (argc == 0) {
149 warnx("add requires an argument");
150 return (EX_USAGE);
151 }
152 error = bridge_add(sock, brdg, argv[0]);
153 if (error)
154 return (error);
155 } else if (strcmp("delete", argv[0]) == 0 ||
156 strcmp("del", argv[0]) == 0) {
157 argc--; argv++;
158 if (argc == 0) {
159 warnx("delete requires an argument");
160 return (EX_USAGE);
161 }
162 error = bridge_delete(sock, brdg, argv[0]);
163 if (error)
164 return (error);
165 } else if (strcmp("addspan", argv[0]) == 0) {
166 argc--; argv++;
167 if (argc == 0) {
168 warnx("addspan requires an argument");
169 return (EX_USAGE);
170 }
171 error = bridge_addspan(sock, brdg, argv[0]);
172 if (error)
173 return (error);
174 } else if (strcmp("delspan", argv[0]) == 0) {
175 argc--; argv++;
176 if (argc == 0) {
177 warnx("delspan requires an argument");
178 return (EX_USAGE);
179 }
180 error = bridge_delspan(sock, brdg, argv[0]);
181 if (error)
182 return (error);
183 } else if (strcmp("up", argv[0]) == 0) {
184 error = bridge_setflag(sock, brdg, IFF_UP);
185 if (error)
186 return (error);
187 } else if (strcmp("down", argv[0]) == 0) {
188 error = bridge_clrflag(sock, brdg, IFF_UP);
189 if (error)
190 return (error);
191 } else if (strcmp("discover", argv[0]) == 0) {
192 argc--; argv++;
193 if (argc == 0) {
194 warnx("discover requires an argument");
195 return (EX_USAGE);
196 }
197 error = bridge_ifsetflag(sock, brdg, argv[0],
198 IFBIF_DISCOVER);
199 if (error)
200 return (error);
201 } else if (strcmp("-discover", argv[0]) == 0) {
202 argc--; argv++;
203 if (argc == 0) {
204 warnx("-discover requires an argument");
205 return (EX_USAGE);
206 }
207 error = bridge_ifclrflag(sock, brdg, argv[0],
208 IFBIF_DISCOVER);
209 if (error)
210 return (error);
211 } else if (strcmp("blocknonip", argv[0]) == 0) {
212 argc--; argv++;
213 if (argc == 0) {
214 warnx("blocknonip requires an argument");
215 return (EX_USAGE);
216 }
217 error = bridge_ifsetflag(sock, brdg, argv[0],
218 IFBIF_BLOCKNONIP);
219 if (error)
220 return (error);
221 } else if (strcmp("-blocknonip", argv[0]) == 0) {
222 argc--; argv++;
223 if (argc == 0) {
224 warnx("-blocknonip requires an argument");
225 return (EX_USAGE);
226 }
227 error = bridge_ifclrflag(sock, brdg, argv[0],
228 IFBIF_BLOCKNONIP);
229 if (error)
230 return (error);
231 } else if (strcmp("learn", argv[0]) == 0) {
232 argc--; argv++;
233 if (argc == 0) {
234 warnx("learn requires an argument");
235 return (EX_USAGE);
236 }
237 error = bridge_ifsetflag(sock, brdg, argv[0],
238 IFBIF_LEARNING);
239 if (error)
240 return (error);
241 } else if (strcmp("-learn", argv[0]) == 0) {
242 argc--; argv++;
243 if (argc == 0) {
244 warnx("-learn requires an argument");
245 return (EX_USAGE);
246 }
247 error = bridge_ifclrflag(sock, brdg, argv[0],
248 IFBIF_LEARNING);
249 if (error)
250 return (error);
251 } else if (strcmp("flush", argv[0]) == 0) {
252 error = bridge_flush(sock, brdg);
253 if (error)
254 return (error);
255 } else if (strcmp("flushall", argv[0]) == 0) {
256 error = bridge_flushall(sock, brdg);
257 if (error)
258 return (error);
259 } else if (strcmp("static", argv[0]) == 0) {
260 argc--; argv++;
261 if (argc < 2) {
262 warnx("static requires 2 arguments");
263 return (EX_USAGE);
264 }
265 error = bridge_addaddr(sock, brdg, argv[0], argv[1]);
266 if (error)
267 return (error);
268 argc--; argv++;
269 } else if (strcmp("deladdr", argv[0]) == 0) {
270 argc--; argv++;
271 if (argc == 0) {
272 warnx("deladdr requires an argument");
273 return (EX_USAGE);
274 }
275 error = bridge_deladdr(sock, brdg, argv[0]);
276 if (error)
277 return (error);
278 } else if (strcmp("link0", argv[0]) == 0) {
279 error = bridge_setflag(sock, brdg, IFF_LINK0);
280 if (error)
281 return (error);
282 } else if (strcmp("-link0", argv[0]) == 0) {
283 error = bridge_clrflag(sock, brdg, IFF_LINK0);
284 if (error)
285 return (error);
286 } else if (strcmp("link1", argv[0]) == 0) {
287 error = bridge_setflag(sock, brdg, IFF_LINK1);
288 if (error)
289 return (error);
290 } else if (strcmp("-link1", argv[0]) == 0) {
291 error = bridge_clrflag(sock, brdg, IFF_LINK1);
292 if (error)
293 return (error);
294 } else if (strcmp("link2", argv[0]) == 0) {
295 error = bridge_setflag(sock, brdg, IFF_LINK2);
296 if (error)
297 return (error);
298 } else if (strcmp("-link2", argv[0]) == 0) {
299 error = bridge_clrflag(sock, brdg, IFF_LINK2);
300 if (error)
301 return (error);
302 } else if (strcmp("addr", argv[0]) == 0) {
303 error = bridge_addrs(sock, brdg, "");
304 if (error)
305 return (error);
306 } else if (strcmp("maxaddr", argv[0]) == 0) {
307 argc--; argv++;
308 if (argc == 0) {
309 warnx("maxaddr requires an argument");
310 return (EX_USAGE);
311 }
312 error = bridge_maxaddr(sock, brdg, argv[0]);
313 if (error)
314 return (error);
315 } else if (strcmp("hellotime", argv[0]) == 0) {
316 argc--; argv++;
317 if (argc == 0) {
318 warnx("hellotime requires an argument");
319 return (EX_USAGE);
320 }
321 error = bridge_hellotime(sock, brdg, argv[0]);
322 if (error)
323 return (error);
324 } else if (strcmp("fwddelay", argv[0]) == 0) {
325 argc--; argv++;
326 if (argc == 0) {
327 warnx("fwddelay requires an argument");
328 return (EX_USAGE);
329 }
330 error = bridge_fwddelay(sock, brdg, argv[0]);
331 if (error)
332 return (error);
333 } else if (strcmp("maxage", argv[0]) == 0) {
334 argc--; argv++;
335 if (argc == 0) {
336 warnx("maxage requires an argument");
337 return (EX_USAGE);
338 }
339 error = bridge_maxage(sock, brdg, argv[0]);
340 if (error)
341 return (error);
342 } else if (strcmp("priority", argv[0]) == 0) {
343 argc--; argv++;
344 if (argc == 0) {
345 warnx("priority requires an argument");
346 return (EX_USAGE);
347 }
348 error = bridge_priority(sock, brdg, argv[0]);
349 if (error)
350 return (error);
351 } else if (strcmp("ifpriority", argv[0]) == 0) {
352 argc--; argv++;
353 if (argc < 2) {
354 warnx("ifpriority requires 2 arguments");
355 return (EX_USAGE);
356 }
357 error = bridge_ifprio(sock, brdg, argv[0], argv[1]);
358 if (error)
359 return (error);
360 argc--; argv++;
361 } else if (strcmp("ifcost", argv[0]) == 0) {
362 argc--; argv++;
363 if (argc < 2) {
364 warnx("ifcost requires 2 arguments");
365 return (EX_USAGE);
366 }
367 error = bridge_ifcost(sock, brdg, argv[0], argv[1]);
368 if (error)
369 return (error);
370 argc--; argv++;
371 } else if (strcmp("rules", argv[0]) == 0) {
372 argc--; argv++;
373 if (argc == 0) {
374 warnx("rules requires an argument");
375 return (EX_USAGE);
376 }
377 error = bridge_rules(sock, brdg, argv[0], NULL);
378 if (error)
379 return (error);
380 } else if (strcmp("rule", argv[0]) == 0) {
381 argc--; argv++;
382 return (bridge_rule(sock, brdg, argc, argv, -1));
383 } else if (strcmp("rulefile", argv[0]) == 0) {
384 argc--; argv++;
385 if (argc == 0) {
386 warnx("rulefile requires an argument");
387 return (EX_USAGE);
388 }
389 error = bridge_rulefile(sock, brdg, argv[0]);
390 if (error)
391 return (error);
392 } else if (strcmp("flushrule", argv[0]) == 0) {
393 argc--; argv++;
394 if (argc == 0) {
395 warnx("flushrule requires an argument");
396 return (EX_USAGE);
397 }
398 error = bridge_flushrule(sock, brdg, argv[0]);
399 if (error)
400 return (error);
401 } else if (strcmp("timeout", argv[0]) == 0) {
402 argc--; argv++;
403 if (argc == 0) {
404 warnx("timeout requires an argument");
405 return (EX_USAGE);
406 }
407 error = bridge_timeout(sock, brdg, argv[0]);
408 if (error)
409 return (error);
410 } else if (strcmp("stp", argv[0]) == 0) {
411 argc--; argv++;
412 if (argc == 0) {
413 warnx("stp requires an argument");
414 return (EX_USAGE);
415 }
416 error = bridge_ifsetflag(sock, brdg, argv[0],
417 IFBIF_STP);
418 if (error)
419 return (error);
420 } else if (strcmp("-stp", argv[0]) == 0) {
421 argc--; argv++;
422 if (argc == 0) {
423 warnx("-stp requires an argument");
424 return (EX_USAGE);
425 }
426 error = bridge_ifclrflag(sock, brdg, argv[0],
427 IFBIF_STP);
428 if (error)
429 return (error);
430 } else {
431 warnx("unrecognized option: %s", argv[0]);
432 return (EX_USAGE);
433 }
434 }
435
436 return (0);
437 }
438
439 int
bridge_ifsetflag(int s,char * brdg,char * ifsname,u_int32_t flag)440 bridge_ifsetflag(int s, char *brdg, char *ifsname, u_int32_t flag)
441 {
442 struct ifbreq req;
443
444 strlcpy(req.ifbr_name, brdg, sizeof(req.ifbr_name));
445 strlcpy(req.ifbr_ifsname, ifsname, sizeof(req.ifbr_ifsname));
446 if (ioctl(s, SIOCBRDGGIFFLGS, (caddr_t)&req) < 0) {
447 warn("%s: %s", brdg, ifsname);
448 return (EX_IOERR);
449 }
450
451 req.ifbr_ifsflags |= flag;
452
453 if (ioctl(s, SIOCBRDGSIFFLGS, (caddr_t)&req) < 0) {
454 warn("%s: %s", brdg, ifsname);
455 return (EX_IOERR);
456 }
457 return (0);
458 }
459
460 int
bridge_ifclrflag(int s,char * brdg,char * ifsname,u_int32_t flag)461 bridge_ifclrflag(int s, char *brdg, char *ifsname, u_int32_t flag)
462 {
463 struct ifbreq req;
464
465 strlcpy(req.ifbr_name, brdg, sizeof(req.ifbr_name));
466 strlcpy(req.ifbr_ifsname, ifsname, sizeof(req.ifbr_ifsname));
467
468 if (ioctl(s, SIOCBRDGGIFFLGS, (caddr_t)&req) < 0) {
469 warn("%s: %s", brdg, ifsname);
470 return (EX_IOERR);
471 }
472
473 req.ifbr_ifsflags &= ~flag;
474
475 if (ioctl(s, SIOCBRDGSIFFLGS, (caddr_t)&req) < 0) {
476 warn("%s: %s", brdg, ifsname);
477 return (EX_IOERR);
478 }
479 return (0);
480 }
481
482 int
bridge_show_all(int s)483 bridge_show_all(int s)
484 {
485 char *inbuf = NULL, *inb;
486 struct ifconf ifc;
487 struct ifreq *ifrp, ifreq;
488 int len = 8192, i;
489
490 while (1) {
491 ifc.ifc_len = len;
492 inb = realloc(inbuf, len);
493 if (inb == NULL)
494 err(1, "malloc");
495 ifc.ifc_buf = inbuf = inb;
496 if (ioctl(s, SIOCGIFCONF, &ifc) < 0)
497 err(1, "ioctl(SIOCGIFCONF)");
498 if (ifc.ifc_len + sizeof(struct ifreq) < len)
499 break;
500 len *= 2;
501 }
502 ifrp = ifc.ifc_req;
503 ifreq.ifr_name[0] = '\0';
504 for (i = 0; i < ifc.ifc_len; ) {
505 ifrp = (struct ifreq *)((caddr_t)ifc.ifc_req + i);
506 i += sizeof(ifrp->ifr_name) +
507 (ifrp->ifr_addr.sa_len > sizeof(struct sockaddr) ?
508 ifrp->ifr_addr.sa_len : sizeof(struct sockaddr));
509 if (ifrp->ifr_addr.sa_family != AF_LINK)
510 continue;
511 if (!is_bridge(s, ifrp->ifr_name))
512 continue;
513 bridge_status(s, ifrp->ifr_name);
514 }
515 free(inbuf);
516 return (0);
517 }
518
519 int
bridge_setflag(int s,char * brdg,short f)520 bridge_setflag(int s, char *brdg, short f)
521 {
522 struct ifreq ifr;
523
524 strlcpy(ifr.ifr_name, brdg, sizeof(ifr.ifr_name));
525
526 if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
527 warn("%s", brdg);
528 if (errno == EPERM)
529 return (EX_NOPERM);
530 return (EX_IOERR);
531 }
532
533 ifr.ifr_flags |= f;
534
535 if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) {
536 warn("%s", brdg);
537 if (errno == EPERM)
538 return (EX_NOPERM);
539 return (EX_IOERR);
540 }
541
542 return (0);
543 }
544
545 int
bridge_clrflag(int s,char * brdg,short f)546 bridge_clrflag(int s, char *brdg, short f)
547 {
548 struct ifreq ifr;
549
550 strlcpy(ifr.ifr_name, brdg, sizeof(ifr.ifr_name));
551
552 if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
553 warn("%s", brdg);
554 if (errno == EPERM)
555 return (EX_NOPERM);
556 return (EX_IOERR);
557 }
558
559 ifr.ifr_flags &= ~(f);
560
561 if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) {
562 warn("%s", brdg);
563 if (errno == EPERM)
564 return (EX_NOPERM);
565 return (EX_IOERR);
566 }
567
568 return (0);
569 }
570
571 int
bridge_flushall(int s,char * brdg)572 bridge_flushall(int s, char *brdg)
573 {
574 struct ifbreq req;
575
576 strlcpy(req.ifbr_name, brdg, sizeof(req.ifbr_name));
577 req.ifbr_ifsflags = IFBF_FLUSHALL;
578 if (ioctl(s, SIOCBRDGFLUSH, &req) < 0) {
579 warn("%s", brdg);
580 return (EX_IOERR);
581 }
582 return (0);
583 }
584
585 int
bridge_flush(int s,char * brdg)586 bridge_flush(int s, char *brdg)
587 {
588 struct ifbreq req;
589
590 strlcpy(req.ifbr_name, brdg, sizeof(req.ifbr_name));
591 req.ifbr_ifsflags = IFBF_FLUSHDYN;
592 if (ioctl(s, SIOCBRDGFLUSH, &req) < 0) {
593 warn("%s", brdg);
594 return (EX_IOERR);
595 }
596 return (0);
597 }
598
599 int
bridge_cfg(int s,char * brdg,char * delim)600 bridge_cfg(int s, char *brdg, char *delim)
601 {
602 struct ifbrparam ifbp;
603 u_int16_t pri;
604 u_int8_t ht, fd, ma;
605
606 strlcpy(ifbp.ifbrp_name, brdg, sizeof(ifbp.ifbrp_name));
607 if (ioctl(s, SIOCBRDGGPRI, (caddr_t)&ifbp)) {
608 warn("%s", brdg);
609 return (EX_IOERR);
610 }
611 pri = ifbp.ifbrp_prio;
612
613 if (ioctl(s, SIOCBRDGGHT, (caddr_t)&ifbp)) {
614 warn("%s", brdg);
615 return (EX_IOERR);
616 }
617 ht = ifbp.ifbrp_hellotime;
618
619 if (ioctl(s, SIOCBRDGGFD, (caddr_t)&ifbp)) {
620 warn("%s", brdg);
621 return (EX_IOERR);
622 }
623 fd = ifbp.ifbrp_fwddelay;
624
625 if (ioctl(s, SIOCBRDGGMA, (caddr_t)&ifbp)) {
626 warn("%s", brdg);
627 return (EX_IOERR);
628 }
629 ma = ifbp.ifbrp_maxage;
630
631 printf("%spriority %u hellotime %u fwddelay %u maxage %u\n",
632 delim, pri, ht, fd, ma);
633
634 return (0);
635 }
636
637 int
bridge_list(int s,char * brdg,char * delim)638 bridge_list(int s, char *brdg, char *delim)
639 {
640 struct ifbreq *reqp;
641 struct ifbifconf bifc;
642 int i, len = 8192;
643 char buf[sizeof(reqp->ifbr_ifsname) + 1], *inbuf = NULL, *inb;
644
645 while (1) {
646 bifc.ifbic_len = len;
647 inb = realloc(inbuf, len);
648 if (inb == NULL)
649 err(1, "malloc");
650 bifc.ifbic_buf = inbuf = inb;
651 strlcpy(bifc.ifbic_name, brdg, sizeof(bifc.ifbic_name));
652 if (ioctl(s, SIOCBRDGIFS, &bifc) < 0)
653 err(1, "%s", brdg);
654 if (bifc.ifbic_len + sizeof(*reqp) < len)
655 break;
656 len *= 2;
657 }
658 for (i = 0; i < bifc.ifbic_len / sizeof(*reqp); i++) {
659 reqp = bifc.ifbic_req + i;
660 strlcpy(buf, reqp->ifbr_ifsname, sizeof(buf));
661 printf("%s%s ", delim, buf);
662 printb("flags", reqp->ifbr_ifsflags, IFBIFBITS);
663 printf("\n");
664 if (reqp->ifbr_ifsflags & IFBIF_SPAN)
665 continue;
666 printf("\t\t\t");
667 printf("port %u ifpriority %u ifcost %u",
668 reqp->ifbr_portno, reqp->ifbr_priority,
669 reqp->ifbr_path_cost);
670 if (reqp->ifbr_ifsflags & IFBIF_STP)
671 printf(" %s", stpstates[reqp->ifbr_state]);
672 printf("\n");
673 bridge_rules(s, brdg, buf, delim);
674 }
675 free(bifc.ifbic_buf);
676 return (0); /* NOTREACHED */
677 }
678
679 int
bridge_add(int s,char * brdg,char * ifn)680 bridge_add(int s, char *brdg, char *ifn)
681 {
682 struct ifbreq req;
683
684 strlcpy(req.ifbr_name, brdg, sizeof(req.ifbr_name));
685 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
686 if (ioctl(s, SIOCBRDGADD, &req) < 0) {
687 warn("%s: %s", brdg, ifn);
688 if (errno == EPERM)
689 return (EX_NOPERM);
690 return (EX_IOERR);
691 }
692 return (0);
693 }
694
695 int
bridge_delete(int s,char * brdg,char * ifn)696 bridge_delete(int s, char *brdg, char *ifn)
697 {
698 struct ifbreq req;
699
700 strlcpy(req.ifbr_name, brdg, sizeof(req.ifbr_name));
701 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
702 if (ioctl(s, SIOCBRDGDEL, &req) < 0) {
703 warn("%s: %s", brdg, ifn);
704 if (errno == EPERM)
705 return (EX_NOPERM);
706 return (EX_IOERR);
707 }
708 return (0);
709 }
710
711 int
bridge_addspan(int s,char * brdg,char * ifn)712 bridge_addspan(int s, char *brdg, char *ifn)
713 {
714 struct ifbreq req;
715
716 strlcpy(req.ifbr_name, brdg, sizeof(req.ifbr_name));
717 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
718 if (ioctl(s, SIOCBRDGADDS, &req) < 0) {
719 warn("%s: %s", brdg, ifn);
720 if (errno == EPERM)
721 return (EX_NOPERM);
722 return (EX_IOERR);
723 }
724 return (0);
725 }
726
727 int
bridge_delspan(int s,char * brdg,char * ifn)728 bridge_delspan(int s, char *brdg, char *ifn)
729 {
730 struct ifbreq req;
731
732 strlcpy(req.ifbr_name, brdg, sizeof(req.ifbr_name));
733 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
734 if (ioctl(s, SIOCBRDGDELS, &req) < 0) {
735 warn("%s: %s", brdg, ifn);
736 if (errno == EPERM)
737 return (EX_NOPERM);
738 return (EX_IOERR);
739 }
740 return (0);
741 }
742
743 int
bridge_timeout(int s,char * brdg,char * arg)744 bridge_timeout(int s, char *brdg, char *arg)
745 {
746 struct ifbrparam bp;
747 long newtime;
748 char *endptr;
749
750 errno = 0;
751 newtime = strtol(arg, &endptr, 0);
752 if (arg[0] == '\0' || endptr[0] != '\0' ||
753 (newtime & ~INT_MAX) != 0L ||
754 (errno == ERANGE && newtime == LONG_MAX)) {
755 printf("invalid arg for timeout: %s\n", arg);
756 return (EX_USAGE);
757 }
758
759 strlcpy(bp.ifbrp_name, brdg, sizeof(bp.ifbrp_name));
760 bp.ifbrp_ctime = newtime;
761 if (ioctl(s, SIOCBRDGSTO, (caddr_t)&bp) < 0) {
762 warn("%s", brdg);
763 return (EX_IOERR);
764 }
765 return (0);
766 }
767
768 int
bridge_maxage(int s,char * brdg,char * arg)769 bridge_maxage(int s, char *brdg, char *arg)
770 {
771 struct ifbrparam bp;
772 unsigned long v;
773 char *endptr;
774
775 errno = 0;
776 v = strtoul(arg, &endptr, 0);
777 if (arg[0] == '\0' || endptr[0] != '\0' || v > 0xffUL ||
778 (errno == ERANGE && v == ULONG_MAX)) {
779 printf("invalid arg for maxage: %s\n", arg);
780 return (EX_USAGE);
781 }
782
783 strlcpy(bp.ifbrp_name, brdg, sizeof(bp.ifbrp_name));
784 bp.ifbrp_maxage = v;
785 if (ioctl(s, SIOCBRDGSMA, (caddr_t)&bp) < 0) {
786 warn("%s", brdg);
787 return (EX_IOERR);
788 }
789 return (0);
790 }
791
792 int
bridge_priority(int s,char * brdg,char * arg)793 bridge_priority(int s, char *brdg, char *arg)
794 {
795 struct ifbrparam bp;
796 unsigned long v;
797 char *endptr;
798
799 errno = 0;
800 v = strtoul(arg, &endptr, 0);
801 if (arg[0] == '\0' || endptr[0] != '\0' || v > 0xffffUL ||
802 (errno == ERANGE && v == ULONG_MAX)) {
803 printf("invalid arg for maxage: %s\n", arg);
804 return (EX_USAGE);
805 }
806
807 strlcpy(bp.ifbrp_name, brdg, sizeof(bp.ifbrp_name));
808 bp.ifbrp_prio = v;
809 if (ioctl(s, SIOCBRDGSPRI, (caddr_t)&bp) < 0) {
810 warn("%s", brdg);
811 return (EX_IOERR);
812 }
813 return (0);
814 }
815
816 int
bridge_fwddelay(int s,char * brdg,char * arg)817 bridge_fwddelay(int s, char *brdg, char *arg)
818 {
819 struct ifbrparam bp;
820 unsigned long v;
821 char *endptr;
822
823 errno = 0;
824 v = strtoul(arg, &endptr, 0);
825 if (arg[0] == '\0' || endptr[0] != '\0' || v > 0xffUL ||
826 (errno == ERANGE && v == ULONG_MAX)) {
827 printf("invalid arg for fwddelay: %s\n", arg);
828 return (EX_USAGE);
829 }
830
831 strlcpy(bp.ifbrp_name, brdg, sizeof(bp.ifbrp_name));
832 bp.ifbrp_fwddelay = v;
833 if (ioctl(s, SIOCBRDGSFD, (caddr_t)&bp) < 0) {
834 warn("%s", brdg);
835 return (EX_IOERR);
836 }
837 return (0);
838 }
839
840 int
bridge_hellotime(int s,char * brdg,char * arg)841 bridge_hellotime(int s, char *brdg, char *arg)
842 {
843 struct ifbrparam bp;
844 unsigned long v;
845 char *endptr;
846
847 errno = 0;
848 v = strtoul(arg, &endptr, 0);
849 if (arg[0] == '\0' || endptr[0] != '\0' || v > 0xffUL ||
850 (errno == ERANGE && v == ULONG_MAX)) {
851 printf("invalid arg for hellotime: %s\n", arg);
852 return (EX_USAGE);
853 }
854
855 strlcpy(bp.ifbrp_name, brdg, sizeof(bp.ifbrp_name));
856 bp.ifbrp_hellotime = v;
857 if (ioctl(s, SIOCBRDGSHT, (caddr_t)&bp) < 0) {
858 warn("%s", brdg);
859 return (EX_IOERR);
860 }
861 return (0);
862 }
863
864 int
bridge_maxaddr(int s,char * brdg,char * arg)865 bridge_maxaddr(int s, char *brdg, char *arg)
866 {
867 struct ifbrparam bp;
868 unsigned long newsize;
869 char *endptr;
870
871 errno = 0;
872 newsize = strtoul(arg, &endptr, 0);
873 if (arg[0] == '\0' || endptr[0] != '\0' || newsize > 0xffffffffUL ||
874 (errno == ERANGE && newsize == ULONG_MAX)) {
875 printf("invalid arg for maxaddr: %s\n", arg);
876 return (EX_USAGE);
877 }
878
879 strlcpy(bp.ifbrp_name, brdg, sizeof(bp.ifbrp_name));
880 bp.ifbrp_csize = newsize;
881 if (ioctl(s, SIOCBRDGSCACHE, (caddr_t)&bp) < 0) {
882 warn("%s", brdg);
883 return (EX_IOERR);
884 }
885 return (0);
886 }
887
888 int
bridge_deladdr(int s,char * brdg,char * addr)889 bridge_deladdr(int s, char *brdg, char *addr)
890 {
891 struct ifbareq ifba;
892 struct ether_addr *ea;
893
894 strlcpy(ifba.ifba_name, brdg, sizeof(ifba.ifba_name));
895 ea = ether_aton(addr);
896 if (ea == NULL) {
897 warnx("Invalid address: %s", addr);
898 return (EX_USAGE);
899 }
900 memmove(&ifba.ifba_dst, ea, sizeof(struct ether_addr));
901
902 if (ioctl(s, SIOCBRDGDADDR, &ifba) < 0) {
903 warn("%s: %s", brdg, addr);
904 return (EX_IOERR);
905 }
906
907 return (0);
908 }
909
910 int
bridge_ifprio(int s,char * brdg,char * ifname,char * val)911 bridge_ifprio(int s, char *brdg, char *ifname, char *val)
912 {
913 struct ifbreq breq;
914 unsigned long v;
915 char *endptr;
916
917 strlcpy(breq.ifbr_name, brdg, sizeof(breq.ifbr_name));
918 strlcpy(breq.ifbr_ifsname, ifname, sizeof(breq.ifbr_ifsname));
919
920 errno = 0;
921 v = strtoul(val, &endptr, 0);
922 if (val[0] == '\0' || endptr[0] != '\0' || v > 0xffUL ||
923 (errno == ERANGE && v == ULONG_MAX)) {
924 printf("invalid arg for ifpriority: %s\n", val);
925 return (EX_USAGE);
926 }
927 breq.ifbr_priority = v;
928
929 if (ioctl(s, SIOCBRDGSIFPRIO, (caddr_t)&breq) < 0) {
930 warn("%s: %s", brdg, val);
931 return (EX_IOERR);
932 }
933 return (0);
934 }
935
936 int
bridge_ifcost(int s,char * brdg,char * ifname,char * val)937 bridge_ifcost(int s, char *brdg, char *ifname, char *val)
938 {
939 struct ifbreq breq;
940 unsigned long v;
941 char *endptr;
942
943 strlcpy(breq.ifbr_name, brdg, sizeof(breq.ifbr_name));
944 strlcpy(breq.ifbr_ifsname, ifname, sizeof(breq.ifbr_ifsname));
945
946 errno = 0;
947 v = strtoul(val, &endptr, 0);
948 if (val[0] == '\0' || endptr[0] != '\0' ||
949 v < 1 || v > 0xffffffffUL ||
950 (errno == ERANGE && v == ULONG_MAX)) {
951 printf("invalid arg for ifcost: %s\n", val);
952 return (EX_USAGE);
953 }
954 breq.ifbr_path_cost = v;
955
956 if (ioctl(s, SIOCBRDGSIFCOST, (caddr_t)&breq) < 0) {
957 warn("%s: %s", brdg, val);
958 return (EX_IOERR);
959 }
960 return (0);
961 }
962
963 int
bridge_addaddr(int s,char * brdg,char * ifname,char * addr)964 bridge_addaddr(int s, char *brdg, char *ifname, char *addr)
965 {
966 struct ifbareq ifba;
967 struct ether_addr *ea;
968
969 strlcpy(ifba.ifba_name, brdg, sizeof(ifba.ifba_name));
970 strlcpy(ifba.ifba_ifsname, ifname, sizeof(ifba.ifba_ifsname));
971
972 ea = ether_aton(addr);
973 if (ea == NULL) {
974 warnx("Invalid address: %s", addr);
975 return (EX_USAGE);
976 }
977 memmove(&ifba.ifba_dst, ea, sizeof(struct ether_addr));
978 ifba.ifba_flags = IFBAF_STATIC;
979
980 if (ioctl(s, SIOCBRDGSADDR, &ifba) < 0) {
981 warn("%s: %s", brdg, addr);
982 return (EX_IOERR);
983 }
984
985 return (0);
986 }
987
988 int
bridge_addrs(int s,char * brdg,char * delim)989 bridge_addrs(int s, char *brdg, char *delim)
990 {
991 struct ifbaconf ifbac;
992 struct ifbareq *ifba;
993 char *inbuf = NULL, buf[sizeof(ifba->ifba_ifsname) + 1], *inb;
994 int i, len = 8192;
995
996 while (1) {
997 ifbac.ifbac_len = len;
998 inb = realloc(inbuf, len);
999 if (inb == NULL)
1000 err(EX_IOERR, "malloc");
1001 ifbac.ifbac_buf = inbuf = inb;
1002 strlcpy(ifbac.ifbac_name, brdg, sizeof(ifbac.ifbac_name));
1003 if (ioctl(s, SIOCBRDGRTS, &ifbac) < 0) {
1004 if (errno == ENETDOWN)
1005 return (0);
1006 err(EX_IOERR, "%s", brdg);
1007 }
1008 if (ifbac.ifbac_len + sizeof(*ifba) < len)
1009 break;
1010 len *= 2;
1011 }
1012
1013 for (i = 0; i < ifbac.ifbac_len / sizeof(*ifba); i++) {
1014 ifba = ifbac.ifbac_req + i;
1015 strlcpy(buf, ifba->ifba_ifsname, sizeof(buf));
1016 printf("%s%s %s %u ", delim, ether_ntoa(&ifba->ifba_dst),
1017 buf, ifba->ifba_age);
1018 printb("flags", ifba->ifba_flags, IFBAFBITS);
1019 printf("\n");
1020 }
1021 free(inbuf);
1022 return (0);
1023 }
1024
1025 /*
1026 * Check to make sure 'brdg' is really a bridge interface.
1027 */
1028 int
is_bridge(int s,char * brdg)1029 is_bridge(int s, char *brdg)
1030 {
1031 struct ifreq ifr;
1032 struct ifbaconf ifbac;
1033
1034 strlcpy(ifr.ifr_name, brdg, sizeof(ifr.ifr_name));
1035
1036 if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0)
1037 return (0);
1038
1039 ifbac.ifbac_len = 0;
1040 strlcpy(ifbac.ifbac_name, brdg, sizeof(ifbac.ifbac_name));
1041 if (ioctl(s, SIOCBRDGRTS, (caddr_t)&ifbac) < 0) {
1042 if (errno == ENETDOWN)
1043 return (1);
1044 return (0);
1045 }
1046 return (1);
1047 }
1048
1049 int
bridge_status(int s,char * brdg)1050 bridge_status(int s, char *brdg)
1051 {
1052 struct ifreq ifr;
1053 struct ifbrparam bp1, bp2;
1054 int err;
1055
1056 strlcpy(ifr.ifr_name, brdg, sizeof(ifr.ifr_name));
1057 if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
1058 warn("%s", brdg);
1059 if (errno == EPERM)
1060 return (EX_NOPERM);
1061 return (EX_IOERR);
1062 }
1063
1064 printf("%s: ", brdg);
1065 printb("flags", ifr.ifr_flags, IFFBITS);
1066 printf("\n");
1067
1068 printf("\tConfiguration:\n");
1069 err = bridge_cfg(s, brdg, "\t\t");
1070 if (err)
1071 return (err);
1072
1073 printf("\tInterfaces:\n");
1074 err = bridge_list(s, brdg, "\t\t");
1075 if (err)
1076 return (err);
1077
1078 strlcpy(bp1.ifbrp_name, brdg, sizeof(bp1.ifbrp_name));
1079 if (ioctl(s, SIOCBRDGGCACHE, (caddr_t)&bp1) < 0) {
1080 warn("%s", brdg);
1081 return (EX_IOERR);
1082 }
1083
1084 strlcpy(bp2.ifbrp_name, brdg, sizeof(bp2.ifbrp_name));
1085 if (ioctl(s, SIOCBRDGGTO, (caddr_t)&bp2) < 0) {
1086 warn("%s", brdg);
1087 return (EX_IOERR);
1088 }
1089
1090 printf("\tAddresses (max cache: %u, timeout: %u):\n",
1091 bp1.ifbrp_csize, bp2.ifbrp_ctime);
1092
1093 err = bridge_addrs(s, brdg, "\t\t");
1094 return (err);
1095 }
1096
1097 int
bridge_flushrule(int s,char * brdg,char * ifname)1098 bridge_flushrule(int s, char *brdg, char *ifname)
1099 {
1100 struct ifbrlreq req;
1101
1102 strlcpy(req.ifbr_name, brdg, sizeof(req.ifbr_name));
1103 strlcpy(req.ifbr_ifsname, ifname, sizeof(req.ifbr_ifsname));
1104 if (ioctl(s, SIOCBRDGFRL, &req) < 0) {
1105 warn("%s: %s", brdg, ifname);
1106 return (EX_USAGE);
1107 }
1108 return (0);
1109 }
1110
1111 int
bridge_rules(int s,char * brdg,char * ifname,char * delim)1112 bridge_rules(int s, char *brdg, char *ifname, char *delim)
1113 {
1114 char *inbuf = NULL, *inb;
1115 struct ifbrlconf ifc;
1116 struct ifbrlreq *ifrp;
1117 int len = 8192, i;
1118
1119 while (1) {
1120 ifc.ifbrl_len = len;
1121 inb = realloc(inbuf, len);
1122 if (inb == NULL)
1123 err(1, "malloc");
1124 ifc.ifbrl_buf = inbuf = inb;
1125 strlcpy(ifc.ifbrl_name, brdg, sizeof(ifc.ifbrl_name));
1126 strlcpy(ifc.ifbrl_ifsname, ifname, sizeof(ifc.ifbrl_ifsname));
1127 if (ioctl(s, SIOCBRDGGRL, &ifc) < 0)
1128 err(1, "ioctl(SIOCBRDGGRL)");
1129 if (ifc.ifbrl_len + sizeof(*ifrp) < len)
1130 break;
1131 len *= 2;
1132 }
1133 ifrp = ifc.ifbrl_req;
1134 for (i = 0; i < ifc.ifbrl_len; i += sizeof(*ifrp)) {
1135 ifrp = (struct ifbrlreq *)((caddr_t)ifc.ifbrl_req + i);
1136 bridge_showrule(ifrp, delim);
1137 }
1138 return (0);
1139 }
1140
1141 void
bridge_showrule(struct ifbrlreq * r,char * delim)1142 bridge_showrule(struct ifbrlreq *r, char *delim)
1143 {
1144 if (delim)
1145 printf("%s ", delim);
1146 else
1147 printf("%s: ", r->ifbr_name);
1148
1149 if (r->ifbr_action == BRL_ACTION_BLOCK)
1150 printf("block ");
1151 else if (r->ifbr_action == BRL_ACTION_PASS)
1152 printf("pass ");
1153 else
1154 printf("[neither block nor pass?]\n");
1155
1156 if ((r->ifbr_flags & (BRL_FLAG_IN | BRL_FLAG_OUT)) ==
1157 (BRL_FLAG_IN | BRL_FLAG_OUT))
1158 printf("in/out ");
1159 else if (r->ifbr_flags & BRL_FLAG_IN)
1160 printf("in ");
1161 else if (r->ifbr_flags & BRL_FLAG_OUT)
1162 printf("out ");
1163 else
1164 printf("[neither in nor out?]\n");
1165
1166 printf("on %s", r->ifbr_ifsname);
1167
1168 if (r->ifbr_flags & BRL_FLAG_SRCVALID)
1169 printf(" src %s", ether_ntoa(&r->ifbr_src));
1170 if (r->ifbr_flags & BRL_FLAG_DSTVALID)
1171 printf(" dst %s", ether_ntoa(&r->ifbr_dst));
1172 if (r->ifbr_tagname[0])
1173 printf(" tag %s", r->ifbr_tagname);
1174
1175 printf("\n");
1176 }
1177
1178 /*
1179 * Parse a rule definition and send it upwards.
1180 *
1181 * Syntax:
1182 * {block|pass} {in|out|in/out} on {ifs} [src {mac}] [dst {mac}]
1183 */
1184 int
bridge_rule(int s,char * brdg,int targc,char ** targv,int ln)1185 bridge_rule(int s, char *brdg, int targc, char **targv, int ln)
1186 {
1187 char **argv = targv;
1188 int argc = targc;
1189 struct ifbrlreq rule;
1190 struct ether_addr *ea, *dea;
1191
1192 if (argc == 0) {
1193 fprintf(stderr, "invalid rule\n");
1194 return (EX_USAGE);
1195 }
1196 rule.ifbr_tagname[0] = 0;
1197 rule.ifbr_flags = 0;
1198 rule.ifbr_action = 0;
1199 strlcpy(rule.ifbr_name, brdg, sizeof(rule.ifbr_name));
1200
1201 if (strcmp(argv[0], "block") == 0)
1202 rule.ifbr_action = BRL_ACTION_BLOCK;
1203 else if (strcmp(argv[0], "pass") == 0)
1204 rule.ifbr_action = BRL_ACTION_PASS;
1205 else
1206 goto bad_rule;
1207 argc--; argv++;
1208
1209 if (argc == 0) {
1210 bridge_badrule(targc, targv, ln);
1211 return (EX_USAGE);
1212 }
1213 if (strcmp(argv[0], "in") == 0)
1214 rule.ifbr_flags |= BRL_FLAG_IN;
1215 else if (strcmp(argv[0], "out") == 0)
1216 rule.ifbr_flags |= BRL_FLAG_OUT;
1217 else if (strcmp(argv[0], "in/out") == 0)
1218 rule.ifbr_flags |= BRL_FLAG_IN | BRL_FLAG_OUT;
1219 else
1220 goto bad_rule;
1221 argc--; argv++;
1222
1223 if (argc == 0 || strcmp(argv[0], "on"))
1224 goto bad_rule;
1225 argc--; argv++;
1226
1227 if (argc == 0)
1228 goto bad_rule;
1229 strlcpy(rule.ifbr_ifsname, argv[0], sizeof(rule.ifbr_ifsname));
1230 argc--; argv++;
1231
1232 while (argc) {
1233 if (strcmp(argv[0], "dst") == 0) {
1234 if (rule.ifbr_flags & BRL_FLAG_DSTVALID)
1235 goto bad_rule;
1236 rule.ifbr_flags |= BRL_FLAG_DSTVALID;
1237 dea = &rule.ifbr_dst;
1238 } else if (strcmp(argv[0], "src") == 0) {
1239 if (rule.ifbr_flags & BRL_FLAG_SRCVALID)
1240 goto bad_rule;
1241 rule.ifbr_flags |= BRL_FLAG_SRCVALID;
1242 dea = &rule.ifbr_src;
1243 } else if (strcmp(argv[0], "tag") == 0) {
1244 if (argc < 2) {
1245 fprintf(stderr, "missing tag name\n");
1246 goto bad_rule;
1247 }
1248 if (rule.ifbr_tagname[0]) {
1249 fprintf(stderr, "tag already defined\n");
1250 goto bad_rule;
1251 }
1252 if (strlcpy(rule.ifbr_tagname, argv[1],
1253 PF_TAG_NAME_SIZE) > PF_TAG_NAME_SIZE) {
1254 fprintf(stderr, "tag name too long\n");
1255 goto bad_rule;
1256 }
1257 dea = NULL;
1258 } else
1259 goto bad_rule;
1260
1261 argc--; argv++;
1262
1263 if (argc == 0)
1264 goto bad_rule;
1265 if (dea != NULL) {
1266 ea = ether_aton(argv[0]);
1267 if (ea == NULL) {
1268 warnx("Invalid address: %s", argv[0]);
1269 return (EX_USAGE);
1270 }
1271 memmove(dea, ea, sizeof(*dea));
1272 }
1273 argc--; argv++;
1274 }
1275
1276 if (ioctl(s, SIOCBRDGARL, &rule) < 0) {
1277 warn("%s", brdg);
1278 return (EX_IOERR);
1279 }
1280 return (0);
1281
1282 bad_rule:
1283 bridge_badrule(targc, targv, ln);
1284 return (EX_USAGE);
1285 }
1286
1287 #define MAXRULEWORDS 8
1288
1289 int
bridge_rulefile(int s,char * brdg,char * fname)1290 bridge_rulefile(int s, char *brdg, char *fname)
1291 {
1292 FILE *f;
1293 char *str, *argv[MAXRULEWORDS], buf[1024];
1294 int ln = 0, argc = 0, err = 0, xerr;
1295
1296 f = fopen(fname, "r");
1297 if (f == NULL) {
1298 warn("%s", fname);
1299 return (EX_IOERR);
1300 }
1301
1302 while (fgets(buf, sizeof(buf), f) != NULL) {
1303 ln++;
1304 if (buf[0] == '#' || buf[0] == '\n')
1305 continue;
1306
1307 argc = 0;
1308 str = strtok(buf, "\n\t\r ");
1309 while (str != NULL && argc < MAXRULEWORDS) {
1310 argv[argc++] = str;
1311 str = strtok(NULL, "\n\t\r ");
1312 }
1313
1314 /* Rule is too long if there's more. */
1315 if (str != NULL) {
1316 fprintf(stderr, "invalid rule: %d: %s ...\n", ln, buf);
1317 continue;
1318 }
1319
1320 xerr = bridge_rule(s, brdg, argc, argv, ln);
1321 if (xerr)
1322 err = xerr;
1323 }
1324 fclose(f);
1325 return (err);
1326 }
1327
1328 void
bridge_badrule(int argc,char * argv[],int ln)1329 bridge_badrule(int argc, char *argv[], int ln)
1330 {
1331 int i;
1332
1333 fprintf(stderr, "invalid rule: ");
1334 if (ln != -1)
1335 fprintf(stderr, "%d: ", ln);
1336 for (i = 0; i < argc; i++) {
1337 fprintf(stderr, "%s ", argv[i]);
1338 }
1339 fprintf(stderr, "\n");
1340 }
1341
1342 /*
1343 * Print a value ala the %b format of the kernel's printf
1344 * (borrowed from ifconfig.c)
1345 */
1346 void
printb(char * s,unsigned short v,char * bits)1347 printb(char *s, unsigned short v, char *bits)
1348 {
1349 int i, any = 0;
1350 char c;
1351
1352 if (bits && *bits == 8)
1353 printf("%s=%o", s, v);
1354 else
1355 printf("%s=%x", s, v);
1356 bits++;
1357 if (bits) {
1358 putchar('<');
1359 while ((i = *bits++)) {
1360 if (v & (1 << (i-1))) {
1361 if (any)
1362 putchar(',');
1363 any = 1;
1364 for (; (c = *bits) > 32; bits++)
1365 putchar(c);
1366 } else
1367 for (; *bits > 32; bits++)
1368 ;
1369 }
1370 putchar('>');
1371 }
1372 }
1373