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