xref: /openbsd/sbin/ifconfig/brconfig.c (revision 264ca280)
1 /*	$OpenBSD: brconfig.c,v 1.9 2015/07/18 06:50:24 rzalamena 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 #ifndef SMALL
30 
31 #include <stdio.h>
32 #include <sys/types.h>
33 #include <sys/stdint.h>
34 #include <unistd.h>
35 #include <stdlib.h>
36 #include <sys/socket.h>
37 #include <sys/ioctl.h>
38 #include <net/if.h>
39 #include <net/if_dl.h>
40 #include <netinet/in.h>
41 #include <netinet/if_ether.h>
42 #include <net/if_bridge.h>
43 #include <netdb.h>
44 #include <string.h>
45 #include <err.h>
46 #include <errno.h>
47 #include <getopt.h>
48 #include <limits.h>
49 
50 #include "brconfig.h"
51 
52 void bridge_ifsetflag(const char *, u_int32_t);
53 void bridge_ifclrflag(const char *, u_int32_t);
54 
55 void bridge_list(char *);
56 void bridge_cfg(const char *);
57 void bridge_badrule(int, char **, int);
58 void bridge_showrule(struct ifbrlreq *);
59 
60 #define	IFBAFBITS	"\020\1STATIC"
61 #define	IFBIFBITS	\
62 "\020\1LEARNING\2DISCOVER\3BLOCKNONIP\4STP\5EDGE\6AUTOEDGE\7PTP\10AUTOPTP\11SPAN"
63 
64 #define	PV2ID(pv, epri, eaddr)	do {					\
65 	epri	 = pv >> 48;						\
66 	eaddr[0] = pv >> 40;						\
67 	eaddr[1] = pv >> 32;						\
68 	eaddr[2] = pv >> 24;						\
69 	eaddr[3] = pv >> 16;						\
70 	eaddr[4] = pv >> 8;						\
71 	eaddr[5] = pv >> 0;						\
72 } while (0)
73 
74 char *stpstates[] = {
75 	"disabled",
76 	"listening",
77 	"learning",
78 	"forwarding",
79 	"blocking",
80 	"discarding"
81 };
82 char *stpproto[] = {
83 	"stp",
84 	"(none)",
85 	"rstp",
86 };
87 char *stproles[] = {
88 	"disabled",
89 	"root",
90 	"designated",
91 	"alternate",
92 	"backup"
93 };
94 
95 
96 void
97 setdiscover(const char *val, int d)
98 {
99 	bridge_ifsetflag(val, IFBIF_DISCOVER);
100 }
101 
102 void
103 unsetdiscover(const char *val, int d)
104 {
105 	bridge_ifclrflag(val, IFBIF_DISCOVER);
106 }
107 
108 void
109 setblocknonip(const char *val, int d)
110 {
111 	bridge_ifsetflag(val, IFBIF_BLOCKNONIP);
112 }
113 
114 void
115 unsetblocknonip(const char *val, int d)
116 {
117 	bridge_ifclrflag(val, IFBIF_BLOCKNONIP);
118 }
119 
120 void
121 setlearn(const char *val, int d)
122 {
123 	bridge_ifsetflag(val, IFBIF_LEARNING);
124 }
125 
126 void
127 unsetlearn(const char *val, int d)
128 {
129 	bridge_ifclrflag(val, IFBIF_LEARNING);
130 }
131 
132 void
133 setstp(const char *val, int d)
134 {
135 	bridge_ifsetflag(val, IFBIF_STP);
136 }
137 
138 void
139 unsetstp(const char *val, int d)
140 {
141 	bridge_ifclrflag(val, IFBIF_STP);
142 }
143 
144 void
145 setedge(const char *val, int d)
146 {
147 	bridge_ifsetflag(val, IFBIF_BSTP_EDGE);
148 }
149 
150 void
151 unsetedge(const char *val, int d)
152 {
153 	bridge_ifclrflag(val, IFBIF_BSTP_EDGE);
154 }
155 
156 void
157 setautoedge(const char *val, int d)
158 {
159 	bridge_ifsetflag(val, IFBIF_BSTP_AUTOEDGE);
160 }
161 
162 void
163 unsetautoedge(const char *val, int d)
164 {
165 	bridge_ifclrflag(val, IFBIF_BSTP_AUTOEDGE);
166 }
167 
168 void
169 setptp(const char *val, int d)
170 {
171 	bridge_ifsetflag(val, IFBIF_BSTP_PTP);
172 }
173 
174 void
175 unsetptp(const char *val, int d)
176 {
177 	bridge_ifclrflag(val, IFBIF_BSTP_PTP);
178 }
179 
180 void
181 setautoptp(const char *val, int d)
182 {
183 	bridge_ifsetflag(val, IFBIF_BSTP_AUTOPTP);
184 }
185 
186 void
187 unsetautoptp(const char *val, int d)
188 {
189 	bridge_ifclrflag(val, IFBIF_BSTP_AUTOPTP);
190 }
191 
192 
193 void
194 bridge_ifsetflag(const char *ifsname, u_int32_t flag)
195 {
196 	struct ifbreq req;
197 
198 	strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name));
199 	strlcpy(req.ifbr_ifsname, ifsname, sizeof(req.ifbr_ifsname));
200 	if (ioctl(s, SIOCBRDGGIFFLGS, (caddr_t)&req) < 0)
201 		err(1, "%s: ioctl SIOCBRDGGIFFLGS %s", name, ifsname);
202 
203 	req.ifbr_ifsflags |= flag & ~IFBIF_RO_MASK;
204 
205 	if (ioctl(s, SIOCBRDGSIFFLGS, (caddr_t)&req) < 0)
206 		err(1, "%s: ioctl SIOCBRDGSIFFLGS %s", name, ifsname);
207 }
208 
209 void
210 bridge_ifclrflag(const char *ifsname, u_int32_t flag)
211 {
212 	struct ifbreq req;
213 
214 	strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name));
215 	strlcpy(req.ifbr_ifsname, ifsname, sizeof(req.ifbr_ifsname));
216 
217 	if (ioctl(s, SIOCBRDGGIFFLGS, (caddr_t)&req) < 0)
218 		err(1, "%s: ioctl SIOCBRDGGIFFLGS %s", name, ifsname);
219 
220 	req.ifbr_ifsflags &= ~(flag | IFBIF_RO_MASK);
221 
222 	if (ioctl(s, SIOCBRDGSIFFLGS, (caddr_t)&req) < 0)
223 		err(1, "%s: ioctl SIOCBRDGSIFFLGS %s", name, ifsname);
224 }
225 
226 void
227 bridge_flushall(const char *val, int p)
228 {
229 	struct ifbreq req;
230 
231 	strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name));
232 	req.ifbr_ifsflags = IFBF_FLUSHALL;
233 	if (ioctl(s, SIOCBRDGFLUSH, &req) < 0)
234 		err(1, "%s", name);
235 }
236 
237 void
238 bridge_flush(const char *val, int p)
239 {
240 	struct ifbreq req;
241 
242 	strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name));
243 	req.ifbr_ifsflags = IFBF_FLUSHDYN;
244 	if (ioctl(s, SIOCBRDGFLUSH, &req) < 0)
245 		err(1, "%s", name);
246 }
247 
248 void
249 bridge_cfg(const char *delim)
250 {
251 	struct ifbropreq ifbp;
252 	u_int16_t pri;
253 	u_int8_t ht, fd, ma, hc, proto;
254 	u_int8_t lladdr[ETHER_ADDR_LEN];
255 	u_int16_t bprio;
256 
257 	strlcpy(ifbp.ifbop_name, name, sizeof(ifbp.ifbop_name));
258 	if (ioctl(s, SIOCBRDGGPARAM, (caddr_t)&ifbp))
259 		err(1, "%s", name);
260 	printf("%s", delim);
261 	pri = ifbp.ifbop_priority;
262 	ht = ifbp.ifbop_hellotime;
263 	fd = ifbp.ifbop_fwddelay;
264 	ma = ifbp.ifbop_maxage;
265 	hc = ifbp.ifbop_holdcount;
266 	proto = ifbp.ifbop_protocol;
267 
268 	printf("priority %u hellotime %u fwddelay %u maxage %u "
269 	    "holdcnt %u proto %s\n", pri, ht, fd, ma, hc, stpproto[proto]);
270 
271 	if (aflag)
272 		return;
273 
274 	PV2ID(ifbp.ifbop_desg_bridge, bprio, lladdr);
275 	printf("\tdesignated: id %s priority %u\n",
276 	    ether_ntoa((struct ether_addr *)lladdr), bprio);
277 
278 	if (ifbp.ifbop_root_bridge == ifbp.ifbop_desg_bridge)
279 		return;
280 
281 	PV2ID(ifbp.ifbop_root_bridge, bprio, lladdr);
282 	printf("\troot: id %s priority %u ifcost %u port %u\n",
283 	    ether_ntoa((struct ether_addr *)lladdr), bprio,
284 	    ifbp.ifbop_root_path_cost, ifbp.ifbop_root_port & 0xfff);
285 }
286 
287 void
288 bridge_list(char *delim)
289 {
290 	struct ifbreq *reqp;
291 	struct ifbifconf bifc;
292 	int i, len = 8192;
293 	char buf[sizeof(reqp->ifbr_ifsname) + 1], *inbuf = NULL, *inb;
294 
295 	while (1) {
296 		bifc.ifbic_len = len;
297 		inb = realloc(inbuf, len);
298 		if (inb == NULL)
299 			err(1, "malloc");
300 		bifc.ifbic_buf = inbuf = inb;
301 		strlcpy(bifc.ifbic_name, name, sizeof(bifc.ifbic_name));
302 		if (ioctl(s, SIOCBRDGIFS, &bifc) < 0)
303 			err(1, "%s", name);
304 		if (bifc.ifbic_len + sizeof(*reqp) < len)
305 			break;
306 		len *= 2;
307 	}
308 	for (i = 0; i < bifc.ifbic_len / sizeof(*reqp); i++) {
309 		reqp = bifc.ifbic_req + i;
310 		strlcpy(buf, reqp->ifbr_ifsname, sizeof(buf));
311 		printf("%s%s ", delim, buf);
312 		printb("flags", reqp->ifbr_ifsflags, IFBIFBITS);
313 		printf("\n");
314 		if (reqp->ifbr_ifsflags & IFBIF_SPAN)
315 			continue;
316 		printf("\t\t");
317 		printf("port %u ifpriority %u ifcost %u",
318 		    reqp->ifbr_portno, reqp->ifbr_priority,
319 		    reqp->ifbr_path_cost);
320 		if (reqp->ifbr_ifsflags & IFBIF_STP)
321 			printf(" %s role %s",
322 			    stpstates[reqp->ifbr_state],
323 			    stproles[reqp->ifbr_role]);
324 		printf("\n");
325 		bridge_rules(buf, 1);
326 	}
327 	free(bifc.ifbic_buf);
328 }
329 
330 void
331 bridge_add(const char *ifn, int d)
332 {
333 	struct ifbreq req;
334 
335 	strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name));
336 	strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
337 	if (ioctl(s, SIOCBRDGADD, &req) < 0) {
338 		if (errno == EEXIST)
339 			return;
340 		err(1, "%s: %s", name, ifn);
341 	}
342 }
343 
344 void
345 bridge_delete(const char *ifn, int d)
346 {
347 	struct ifbreq req;
348 
349 	strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name));
350 	strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
351 	if (ioctl(s, SIOCBRDGDEL, &req) < 0)
352 		err(1, "%s: %s", name, ifn);
353 }
354 
355 void
356 bridge_addspan(const char *ifn, int d)
357 {
358 	struct ifbreq req;
359 
360 	strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name));
361 	strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
362 	if (ioctl(s, SIOCBRDGADDS, &req) < 0) {
363 		if (errno == EEXIST)
364 			return;
365 		err(1, "%s: %s", name, ifn);
366 	}
367 }
368 
369 void
370 bridge_delspan(const char *ifn, int d)
371 {
372 	struct ifbreq req;
373 
374 	strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name));
375 	strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
376 	if (ioctl(s, SIOCBRDGDELS, &req) < 0)
377 		err(1, "%s: %s", name, ifn);
378 }
379 
380 void
381 bridge_timeout(const char *arg, int d)
382 {
383 	struct ifbrparam bp;
384 	long newtime;
385 	char *endptr;
386 
387 	errno = 0;
388 	newtime = strtol(arg, &endptr, 0);
389 	if (arg[0] == '\0' || endptr[0] != '\0' ||
390 	    (newtime & ~INT_MAX) != 0L ||
391 	    (errno == ERANGE && newtime == LONG_MAX))
392 		errx(1, "invalid arg for timeout: %s", arg);
393 
394 	strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name));
395 	bp.ifbrp_ctime = newtime;
396 	if (ioctl(s, SIOCBRDGSTO, (caddr_t)&bp) < 0)
397 		err(1, "%s", name);
398 }
399 
400 void
401 bridge_maxage(const char *arg, int d)
402 {
403 	struct ifbrparam bp;
404 	unsigned long v;
405 	char *endptr;
406 
407 	errno = 0;
408 	v = strtoul(arg, &endptr, 0);
409 	if (arg[0] == '\0' || endptr[0] != '\0' || v > 0xffUL ||
410 	    (errno == ERANGE && v == ULONG_MAX))
411 		errx(1, "invalid arg for maxage: %s", arg);
412 
413 	strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name));
414 	bp.ifbrp_maxage = v;
415 	if (ioctl(s, SIOCBRDGSMA, (caddr_t)&bp) < 0)
416 		err(1, "%s", name);
417 }
418 
419 void
420 bridge_priority(const char *arg, int d)
421 {
422 	struct ifbrparam bp;
423 	unsigned long v;
424 	char *endptr;
425 
426 	errno = 0;
427 	v = strtoul(arg, &endptr, 0);
428 	if (arg[0] == '\0' || endptr[0] != '\0' || v > 0xffffUL ||
429 	    (errno == ERANGE && v == ULONG_MAX))
430 		errx(1, "invalid arg for spanpriority: %s", arg);
431 
432 	strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name));
433 	bp.ifbrp_prio = v;
434 	if (ioctl(s, SIOCBRDGSPRI, (caddr_t)&bp) < 0)
435 		err(1, "%s", name);
436 }
437 
438 void
439 bridge_proto(const char *arg, int d)
440 {
441 	struct ifbrparam bp;
442 	int i, proto = -1;
443 
444 	for (i = 0; i <= BSTP_PROTO_MAX; i++)
445 		if (strcmp(arg, stpproto[i]) == 0) {
446 			proto = i;
447 			break;
448 		}
449 	if (proto == -1)
450 		errx(1, "invalid arg for proto: %s", arg);
451 
452 	strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name));
453 	bp.ifbrp_prio = proto;
454 	if (ioctl(s, SIOCBRDGSPROTO, (caddr_t)&bp) < 0)
455 		err(1, "%s", name);
456 }
457 
458 void
459 bridge_fwddelay(const char *arg, int d)
460 {
461 	struct ifbrparam bp;
462 	unsigned long v;
463 	char *endptr;
464 
465 	errno = 0;
466 	v = strtoul(arg, &endptr, 0);
467 	if (arg[0] == '\0' || endptr[0] != '\0' || v > 0xffUL ||
468 	    (errno == ERANGE && v == ULONG_MAX))
469 		errx(1, "invalid arg for fwddelay: %s", arg);
470 
471 	strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name));
472 	bp.ifbrp_fwddelay = v;
473 	if (ioctl(s, SIOCBRDGSFD, (caddr_t)&bp) < 0)
474 		err(1, "%s", name);
475 }
476 
477 void
478 bridge_hellotime(const char *arg, int d)
479 {
480 	struct ifbrparam bp;
481 	unsigned long v;
482 	char *endptr;
483 
484 	errno = 0;
485 	v = strtoul(arg, &endptr, 0);
486 	if (arg[0] == '\0' || endptr[0] != '\0' || v > 0xffUL ||
487 	    (errno == ERANGE && v == ULONG_MAX))
488 		errx(1, "invalid arg for hellotime: %s", arg);
489 
490 	strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name));
491 	bp.ifbrp_hellotime = v;
492 	if (ioctl(s, SIOCBRDGSHT, (caddr_t)&bp) < 0)
493 		err(1, "%s", name);
494 }
495 
496 void
497 bridge_maxaddr(const char *arg, int d)
498 {
499 	struct ifbrparam bp;
500 	unsigned long newsize;
501 	char *endptr;
502 
503 	errno = 0;
504 	newsize = strtoul(arg, &endptr, 0);
505 	if (arg[0] == '\0' || endptr[0] != '\0' || newsize > 0xffffffffUL ||
506 	    (errno == ERANGE && newsize == ULONG_MAX))
507 		errx(1, "invalid arg for maxaddr: %s", arg);
508 
509 	strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name));
510 	bp.ifbrp_csize = newsize;
511 	if (ioctl(s, SIOCBRDGSCACHE, (caddr_t)&bp) < 0)
512 		err(1, "%s", name);
513 }
514 
515 void
516 bridge_deladdr(const char *addr, int d)
517 {
518 	struct ifbareq ifba;
519 	struct ether_addr *ea;
520 
521 	strlcpy(ifba.ifba_name, name, sizeof(ifba.ifba_name));
522 	ea = ether_aton(addr);
523 	if (ea == NULL)
524 		err(1, "Invalid address: %s", addr);
525 
526 	bcopy(ea, &ifba.ifba_dst, sizeof(struct ether_addr));
527 
528 	if (ioctl(s, SIOCBRDGDADDR, &ifba) < 0)
529 		err(1, "%s: %s", name, addr);
530 }
531 
532 void
533 bridge_ifprio(const char *ifname, const char *val)
534 {
535 	struct ifbreq breq;
536 	unsigned long v;
537 	char *endptr;
538 
539 	strlcpy(breq.ifbr_name, name, sizeof(breq.ifbr_name));
540 	strlcpy(breq.ifbr_ifsname, ifname, sizeof(breq.ifbr_ifsname));
541 
542 	errno = 0;
543 	v = strtoul(val, &endptr, 0);
544 	if (val[0] == '\0' || endptr[0] != '\0' || v > 0xffUL ||
545 	    (errno == ERANGE && v == ULONG_MAX))
546 		err(1, "invalid arg for ifpriority: %s", val);
547 	breq.ifbr_priority = v;
548 
549 	if (ioctl(s, SIOCBRDGSIFPRIO, (caddr_t)&breq) < 0)
550 		err(1, "%s: %s", name, val);
551 }
552 
553 void
554 bridge_ifcost(const char *ifname, const char *val)
555 {
556 	struct ifbreq breq;
557 	unsigned long v;
558 	char *endptr;
559 
560 	strlcpy(breq.ifbr_name, name, sizeof(breq.ifbr_name));
561 	strlcpy(breq.ifbr_ifsname, ifname, sizeof(breq.ifbr_ifsname));
562 
563 	errno = 0;
564 	v = strtoul(val, &endptr, 0);
565 	if (val[0] == '\0' || endptr[0] != '\0' ||
566 	    v < 0 || v > 0xffffffffUL ||
567 	    (errno == ERANGE && v == ULONG_MAX))
568 		errx(1, "invalid arg for ifcost: %s", val);
569 
570 	breq.ifbr_path_cost = v;
571 
572 	if (ioctl(s, SIOCBRDGSIFCOST, (caddr_t)&breq) < 0)
573 		err(1, "%s: %s", name, val);
574 }
575 
576 void
577 bridge_noifcost(const char *ifname, int d)
578 {
579 	struct ifbreq breq;
580 
581 	strlcpy(breq.ifbr_name, name, sizeof(breq.ifbr_name));
582 	strlcpy(breq.ifbr_ifsname, ifname, sizeof(breq.ifbr_ifsname));
583 
584 	breq.ifbr_path_cost = 0;
585 
586 	if (ioctl(s, SIOCBRDGSIFCOST, (caddr_t)&breq) < 0)
587 		err(1, "%s", name);
588 }
589 
590 void
591 bridge_addaddr(const char *ifname, const char *addr)
592 {
593 	struct ifbareq ifba;
594 	struct ether_addr *ea;
595 
596 	strlcpy(ifba.ifba_name, name, sizeof(ifba.ifba_name));
597 	strlcpy(ifba.ifba_ifsname, ifname, sizeof(ifba.ifba_ifsname));
598 
599 	ea = ether_aton(addr);
600 	if (ea == NULL)
601 		errx(1, "Invalid address: %s", addr);
602 
603 	bcopy(ea, &ifba.ifba_dst, sizeof(struct ether_addr));
604 	ifba.ifba_flags = IFBAF_STATIC;
605 
606 	if (ioctl(s, SIOCBRDGSADDR, &ifba) < 0)
607 		err(1, "%s: %s", name, addr);
608 }
609 
610 void
611 bridge_addrs(const char *delim, int d)
612 {
613 	char dstaddr[NI_MAXHOST];
614 	char dstport[NI_MAXSERV];
615 	const int niflag = NI_NUMERICHOST|NI_DGRAM;
616 	struct ifbaconf ifbac;
617 	struct ifbareq *ifba;
618 	char *inbuf = NULL, buf[sizeof(ifba->ifba_ifsname) + 1], *inb;
619 	struct sockaddr *sa;
620 	int i, len = 8192;
621 
622 	/* ifconfig will call us with the argv of the command */
623 	if (strcmp(delim, "addr") == 0)
624 		delim = "";
625 
626 	while (1) {
627 		ifbac.ifbac_len = len;
628 		inb = realloc(inbuf, len);
629 		if (inb == NULL)
630 			err(1, "malloc");
631 		ifbac.ifbac_buf = inbuf = inb;
632 		strlcpy(ifbac.ifbac_name, name, sizeof(ifbac.ifbac_name));
633 		if (ioctl(s, SIOCBRDGRTS, &ifbac) < 0) {
634 			if (errno == ENETDOWN)
635 				return;
636 			err(1, "%s", name);
637 		}
638 		if (ifbac.ifbac_len + sizeof(*ifba) < len)
639 			break;
640 		len *= 2;
641 	}
642 
643 	for (i = 0; i < ifbac.ifbac_len / sizeof(*ifba); i++) {
644 		ifba = ifbac.ifbac_req + i;
645 		strlcpy(buf, ifba->ifba_ifsname, sizeof(buf));
646 		printf("%s%s %s %u ", delim, ether_ntoa(&ifba->ifba_dst),
647 		    buf, ifba->ifba_age);
648 		sa = (struct sockaddr *)&ifba->ifba_dstsa;
649 		printb("flags", ifba->ifba_flags, IFBAFBITS);
650 		if (sa->sa_family != AF_UNSPEC &&
651 		    getnameinfo(sa, sa->sa_len,
652 		    dstaddr, sizeof(dstaddr),
653 		    dstport, sizeof(dstport), niflag) == 0)
654 			printf(" tunnel %s:%s", dstaddr, dstport);
655 		printf("\n");
656 	}
657 	free(inbuf);
658 }
659 
660 void
661 bridge_holdcnt(const char *value, int d)
662 {
663 	struct ifbrparam bp;
664 	const char *errstr;
665 
666 	bp.ifbrp_txhc = strtonum(value, 0, UINT8_MAX, &errstr);
667 	if (errstr)
668 		err(1, "holdcnt %s %s", value, errstr);
669 
670 	strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name));
671 	if (ioctl(s, SIOCBRDGSTXHC, (caddr_t)&bp) < 0)
672 		err(1, "%s", name);
673 }
674 
675 /*
676  * Check to make sure 'brdg' is really a bridge interface.
677  */
678 int
679 is_bridge(char *brdg)
680 {
681 	struct ifreq ifr;
682 	struct ifbaconf ifbac;
683 
684 	strlcpy(ifr.ifr_name, brdg, sizeof(ifr.ifr_name));
685 
686 	if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0)
687 		return (0);
688 
689 	ifbac.ifbac_len = 0;
690 	strlcpy(ifbac.ifbac_name, brdg, sizeof(ifbac.ifbac_name));
691 	if (ioctl(s, SIOCBRDGRTS, (caddr_t)&ifbac) < 0) {
692 		if (errno == ENETDOWN)
693 			return (1);
694 		return (0);
695 	}
696 	return (1);
697 }
698 
699 void
700 bridge_status(void)
701 {
702 	struct ifreq ifr;
703 	struct ifbrparam bp1, bp2;
704 
705 	if (!is_bridge(name))
706 		return;
707 
708 	strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
709 	if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0)
710 		return;
711 
712 	bridge_cfg("\t");
713 
714 	bridge_list("\t");
715 
716 	if (aflag && !ifaliases)
717 		return;
718 
719 	strlcpy(bp1.ifbrp_name, name, sizeof(bp1.ifbrp_name));
720 	if (ioctl(s, SIOCBRDGGCACHE, (caddr_t)&bp1) < 0)
721 		return;
722 
723 	strlcpy(bp2.ifbrp_name, name, sizeof(bp2.ifbrp_name));
724 	if (ioctl(s, SIOCBRDGGTO, (caddr_t)&bp2) < 0)
725 		return;
726 
727 	printf("\tAddresses (max cache: %u, timeout: %u):\n",
728 	    bp1.ifbrp_csize, bp2.ifbrp_ctime);
729 
730 	bridge_addrs("\t\t", 0);
731 }
732 
733 void
734 bridge_flushrule(const char *ifname, int d)
735 {
736 	struct ifbrlreq req;
737 
738 	strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name));
739 	strlcpy(req.ifbr_ifsname, ifname, sizeof(req.ifbr_ifsname));
740 	if (ioctl(s, SIOCBRDGFRL, &req) < 0)
741 		err(1, "%s: %s", name, ifname);
742 }
743 
744 void
745 bridge_rules(const char *ifname, int usetab)
746 {
747 	char *inbuf = NULL, *inb;
748 	struct ifbrlconf ifc;
749 	struct ifbrlreq *ifrp;
750 	int len = 8192, i;
751 
752 	while (1) {
753 		ifc.ifbrl_len = len;
754 		inb = realloc(inbuf, len);
755 		if (inb == NULL)
756 			err(1, "malloc");
757 		ifc.ifbrl_buf = inbuf = inb;
758 		strlcpy(ifc.ifbrl_name, name, sizeof(ifc.ifbrl_name));
759 		strlcpy(ifc.ifbrl_ifsname, ifname, sizeof(ifc.ifbrl_ifsname));
760 		if (ioctl(s, SIOCBRDGGRL, &ifc) < 0)
761 			err(1, "ioctl(SIOCBRDGGRL)");
762 		if (ifc.ifbrl_len + sizeof(*ifrp) < len)
763 			break;
764 		len *= 2;
765 	}
766 	ifrp = ifc.ifbrl_req;
767 	for (i = 0; i < ifc.ifbrl_len; i += sizeof(*ifrp)) {
768 		ifrp = (struct ifbrlreq *)((caddr_t)ifc.ifbrl_req + i);
769 
770 		if (usetab)
771 			printf("\t");
772 
773 		bridge_showrule(ifrp);
774 	}
775 }
776 
777 void
778 bridge_showrule(struct ifbrlreq *r)
779 {
780 	if (r->ifbr_action == BRL_ACTION_BLOCK)
781 		printf("block ");
782 	else if (r->ifbr_action == BRL_ACTION_PASS)
783 		printf("pass ");
784 	else
785 		printf("[neither block nor pass?]\n");
786 
787 	if ((r->ifbr_flags & (BRL_FLAG_IN | BRL_FLAG_OUT)) ==
788 	    (BRL_FLAG_IN | BRL_FLAG_OUT))
789 		printf("in/out ");
790 	else if (r->ifbr_flags & BRL_FLAG_IN)
791 		printf("in ");
792 	else if (r->ifbr_flags & BRL_FLAG_OUT)
793 		printf("out ");
794 	else
795 		printf("[neither in nor out?]\n");
796 
797 	printf("on %s", r->ifbr_ifsname);
798 
799 	if (r->ifbr_flags & BRL_FLAG_SRCVALID)
800 		printf(" src %s", ether_ntoa(&r->ifbr_src));
801 	if (r->ifbr_flags & BRL_FLAG_DSTVALID)
802 		printf(" dst %s", ether_ntoa(&r->ifbr_dst));
803 	if (r->ifbr_tagname[0])
804 		printf(" tag %s", r->ifbr_tagname);
805 
806 	printf("\n");
807 }
808 
809 /*
810  * Parse a rule definition and send it upwards.
811  *
812  * Syntax:
813  *	{block|pass} {in|out|in/out} on {ifs} [src {mac}] [dst {mac}]
814  */
815 int
816 bridge_rule(int targc, char **targv, int ln)
817 {
818 	char **argv = targv;
819 	int argc = targc;
820 	struct ifbrlreq rule;
821 	struct ether_addr *ea, *dea;
822 
823 	if (argc == 0) {
824 		warnx("invalid rule");
825 		return (1);
826 	}
827 	rule.ifbr_tagname[0] = 0;
828 	rule.ifbr_flags = 0;
829 	rule.ifbr_action = 0;
830 	strlcpy(rule.ifbr_name, name, sizeof(rule.ifbr_name));
831 
832 	if (strcmp(argv[0], "block") == 0)
833 		rule.ifbr_action = BRL_ACTION_BLOCK;
834 	else if (strcmp(argv[0], "pass") == 0)
835 		rule.ifbr_action = BRL_ACTION_PASS;
836 	else
837 		goto bad_rule;
838 	argc--;	argv++;
839 
840 	if (argc == 0) {
841 		bridge_badrule(targc, targv, ln);
842 		return (1);
843 	}
844 	if (strcmp(argv[0], "in") == 0)
845 		rule.ifbr_flags |= BRL_FLAG_IN;
846 	else if (strcmp(argv[0], "out") == 0)
847 		rule.ifbr_flags |= BRL_FLAG_OUT;
848 	else if (strcmp(argv[0], "in/out") == 0)
849 		rule.ifbr_flags |= BRL_FLAG_IN | BRL_FLAG_OUT;
850 	else if (strcmp(argv[0], "on") == 0) {
851 		rule.ifbr_flags |= BRL_FLAG_IN | BRL_FLAG_OUT;
852 		argc++; argv--;
853 	} else
854 		goto bad_rule;
855 	argc--; argv++;
856 
857 	if (argc == 0 || strcmp(argv[0], "on"))
858 		goto bad_rule;
859 	argc--; argv++;
860 
861 	if (argc == 0)
862 		goto bad_rule;
863 	strlcpy(rule.ifbr_ifsname, argv[0], sizeof(rule.ifbr_ifsname));
864 	argc--; argv++;
865 
866 	while (argc) {
867 		if (strcmp(argv[0], "dst") == 0) {
868 			if (rule.ifbr_flags & BRL_FLAG_DSTVALID)
869 				goto bad_rule;
870 			rule.ifbr_flags |= BRL_FLAG_DSTVALID;
871 			dea = &rule.ifbr_dst;
872 		} else if (strcmp(argv[0], "src") == 0) {
873 			if (rule.ifbr_flags & BRL_FLAG_SRCVALID)
874 				goto bad_rule;
875 			rule.ifbr_flags |= BRL_FLAG_SRCVALID;
876 			dea = &rule.ifbr_src;
877 		} else if (strcmp(argv[0], "tag") == 0) {
878 			if (argc < 2) {
879 				warnx("missing tag name");
880 				goto bad_rule;
881 			}
882 			if (rule.ifbr_tagname[0]) {
883 				warnx("tag already defined");
884 				goto bad_rule;
885 			}
886 			if (strlcpy(rule.ifbr_tagname, argv[1],
887 			    PF_TAG_NAME_SIZE) > PF_TAG_NAME_SIZE) {
888 				warnx("tag name '%s' too long", argv[1]);
889 				goto bad_rule;
890 			}
891 			dea = NULL;
892 		} else
893 			goto bad_rule;
894 
895 		argc--; argv++;
896 
897 		if (argc == 0)
898 			goto bad_rule;
899 		if (dea != NULL) {
900 			ea = ether_aton(argv[0]);
901 			if (ea == NULL) {
902 				warnx("invalid address: %s", argv[0]);
903 				return (1);
904 			}
905 			bcopy(ea, dea, sizeof(*dea));
906 		}
907 		argc--; argv++;
908 	}
909 
910 	if (ioctl(s, SIOCBRDGARL, &rule) < 0) {
911 		warn("%s", name);
912 		return (1);
913 	}
914 	return (0);
915 
916 bad_rule:
917 	bridge_badrule(targc, targv, ln);
918 	return (1);
919 }
920 
921 #define MAXRULEWORDS 8
922 
923 void
924 bridge_rulefile(const char *fname, int d)
925 {
926 	FILE *f;
927 	char *str, *argv[MAXRULEWORDS], buf[1024];
928 	int ln = 0, argc = 0;
929 
930 	f = fopen(fname, "r");
931 	if (f == NULL)
932 		err(1, "%s", fname);
933 
934 	while (fgets(buf, sizeof(buf), f) != NULL) {
935 		ln++;
936 		if (buf[0] == '#' || buf[0] == '\n')
937 			continue;
938 
939 		argc = 0;
940 		str = strtok(buf, "\n\t\r ");
941 		while (str != NULL && argc < MAXRULEWORDS) {
942 			argv[argc++] = str;
943 			str = strtok(NULL, "\n\t\r ");
944 		}
945 
946 		/* Rule is too long if there's more. */
947 		if (str != NULL) {
948 			warnx("invalid rule: %d: %s ...", ln, buf);
949 			continue;
950 		}
951 
952 		bridge_rule(argc, argv, ln);
953 	}
954 	fclose(f);
955 }
956 
957 void
958 bridge_badrule(int argc, char *argv[], int ln)
959 {
960 	extern const char *__progname;
961 	int i;
962 
963 	fprintf(stderr, "%s: invalid rule: ", __progname);
964 	if (ln != -1)
965 		fprintf(stderr, "%d: ", ln);
966 	for (i = 0; i < argc; i++)
967 		fprintf(stderr, "%s ", argv[i]);
968 	fprintf(stderr, "\n");
969 }
970 
971 #endif
972