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