xref: /openbsd-src/sbin/ifconfig/brconfig.c (revision 4da14ec4d2304810ee0d3a112d6786385ad405de)
1*4da14ec4Sdenis /*	$OpenBSD: brconfig.c,v 1.33 2025/01/06 17:49:29 denis Exp $	*/
21c4929fdSclaudio 
31c4929fdSclaudio /*
41c4929fdSclaudio  * Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net)
51c4929fdSclaudio  * All rights reserved.
61c4929fdSclaudio  *
71c4929fdSclaudio  * Redistribution and use in source and binary forms, with or without
81c4929fdSclaudio  * modification, are permitted provided that the following conditions
91c4929fdSclaudio  * are met:
101c4929fdSclaudio  * 1. Redistributions of source code must retain the above copyright
111c4929fdSclaudio  *    notice, this list of conditions and the following disclaimer.
121c4929fdSclaudio  * 2. Redistributions in binary form must reproduce the above copyright
131c4929fdSclaudio  *    notice, this list of conditions and the following disclaimer in the
141c4929fdSclaudio  *    documentation and/or other materials provided with the distribution.
151c4929fdSclaudio  *
161c4929fdSclaudio  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
171c4929fdSclaudio  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
181c4929fdSclaudio  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
191c4929fdSclaudio  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
201c4929fdSclaudio  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
211c4929fdSclaudio  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
221c4929fdSclaudio  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
231c4929fdSclaudio  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
241c4929fdSclaudio  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
251c4929fdSclaudio  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
261c4929fdSclaudio  * POSSIBILITY OF SUCH DAMAGE.
271c4929fdSclaudio  */
281c4929fdSclaudio 
291c4929fdSclaudio #ifndef SMALL
301c4929fdSclaudio 
311c4929fdSclaudio #include <stdio.h>
321c4929fdSclaudio #include <sys/types.h>
331c4929fdSclaudio #include <sys/stdint.h>
341c4929fdSclaudio #include <unistd.h>
351c4929fdSclaudio #include <stdlib.h>
361c4929fdSclaudio #include <sys/socket.h>
371c4929fdSclaudio #include <sys/ioctl.h>
381c4929fdSclaudio #include <net/if.h>
391c4929fdSclaudio #include <netinet/in.h>
401c4929fdSclaudio #include <netinet/if_ether.h>
411c4929fdSclaudio #include <net/if_bridge.h>
42d72e8ec4Sreyk #include <netdb.h>
431c4929fdSclaudio #include <string.h>
441c4929fdSclaudio #include <err.h>
451c4929fdSclaudio #include <errno.h>
461c4929fdSclaudio #include <getopt.h>
471c4929fdSclaudio #include <limits.h>
48d6404d18Shenning #include <arpa/inet.h>
491c4929fdSclaudio 
50d6a6566dSbluhm #include "ifconfig.h"
511c4929fdSclaudio 
521c4929fdSclaudio void bridge_ifsetflag(const char *, u_int32_t);
531c4929fdSclaudio void bridge_ifclrflag(const char *, u_int32_t);
541c4929fdSclaudio 
551c4929fdSclaudio void bridge_list(char *);
561c4929fdSclaudio void bridge_cfg(const char *);
571c4929fdSclaudio void bridge_badrule(int, char **, int);
581c4929fdSclaudio void bridge_showrule(struct ifbrlreq *);
59d6404d18Shenning int bridge_arprule(struct ifbrlreq *, int *, char ***);
601c4929fdSclaudio 
611c4929fdSclaudio #define	IFBAFBITS	"\020\1STATIC"
621c4929fdSclaudio #define	IFBIFBITS	\
6370d427baSgoda "\020\1LEARNING\2DISCOVER\3BLOCKNONIP\4STP\5EDGE\6AUTOEDGE\7PTP\10AUTOPTP\11SPAN\15LOCAL"
641c4929fdSclaudio 
651c4929fdSclaudio #define	PV2ID(pv, epri, eaddr)	do {					\
661c4929fdSclaudio 	epri	 = pv >> 48;						\
671c4929fdSclaudio 	eaddr[0] = pv >> 40;						\
681c4929fdSclaudio 	eaddr[1] = pv >> 32;						\
691c4929fdSclaudio 	eaddr[2] = pv >> 24;						\
701c4929fdSclaudio 	eaddr[3] = pv >> 16;						\
711c4929fdSclaudio 	eaddr[4] = pv >> 8;						\
721c4929fdSclaudio 	eaddr[5] = pv >> 0;						\
731c4929fdSclaudio } while (0)
741c4929fdSclaudio 
751c4929fdSclaudio char *stpstates[] = {
761c4929fdSclaudio 	"disabled",
771c4929fdSclaudio 	"listening",
781c4929fdSclaudio 	"learning",
791c4929fdSclaudio 	"forwarding",
801c4929fdSclaudio 	"blocking",
811c4929fdSclaudio 	"discarding"
821c4929fdSclaudio };
831c4929fdSclaudio char *stpproto[] = {
841c4929fdSclaudio 	"stp",
851c4929fdSclaudio 	"(none)",
861c4929fdSclaudio 	"rstp",
871c4929fdSclaudio };
881c4929fdSclaudio char *stproles[] = {
891c4929fdSclaudio 	"disabled",
901c4929fdSclaudio 	"root",
911c4929fdSclaudio 	"designated",
921c4929fdSclaudio 	"alternate",
931c4929fdSclaudio 	"backup"
941c4929fdSclaudio };
951c4929fdSclaudio 
961c4929fdSclaudio 
971c4929fdSclaudio void
981c4929fdSclaudio setdiscover(const char *val, int d)
991c4929fdSclaudio {
1001c4929fdSclaudio 	bridge_ifsetflag(val, IFBIF_DISCOVER);
1011c4929fdSclaudio }
1021c4929fdSclaudio 
1031c4929fdSclaudio void
1041c4929fdSclaudio unsetdiscover(const char *val, int d)
1051c4929fdSclaudio {
1061c4929fdSclaudio 	bridge_ifclrflag(val, IFBIF_DISCOVER);
1071c4929fdSclaudio }
1081c4929fdSclaudio 
1091c4929fdSclaudio void
1101c4929fdSclaudio setblocknonip(const char *val, int d)
1111c4929fdSclaudio {
1121c4929fdSclaudio 	bridge_ifsetflag(val, IFBIF_BLOCKNONIP);
1131c4929fdSclaudio }
1141c4929fdSclaudio 
1151c4929fdSclaudio void
1161c4929fdSclaudio unsetblocknonip(const char *val, int d)
1171c4929fdSclaudio {
1181c4929fdSclaudio 	bridge_ifclrflag(val, IFBIF_BLOCKNONIP);
1191c4929fdSclaudio }
1201c4929fdSclaudio 
1211c4929fdSclaudio void
1221c4929fdSclaudio setlearn(const char *val, int d)
1231c4929fdSclaudio {
1241c4929fdSclaudio 	bridge_ifsetflag(val, IFBIF_LEARNING);
1251c4929fdSclaudio }
1261c4929fdSclaudio 
1271c4929fdSclaudio void
1281c4929fdSclaudio unsetlearn(const char *val, int d)
1291c4929fdSclaudio {
1301c4929fdSclaudio 	bridge_ifclrflag(val, IFBIF_LEARNING);
1311c4929fdSclaudio }
1321c4929fdSclaudio 
1331c4929fdSclaudio void
1341c4929fdSclaudio setstp(const char *val, int d)
1351c4929fdSclaudio {
1361c4929fdSclaudio 	bridge_ifsetflag(val, IFBIF_STP);
1371c4929fdSclaudio }
1381c4929fdSclaudio 
1391c4929fdSclaudio void
1401c4929fdSclaudio unsetstp(const char *val, int d)
1411c4929fdSclaudio {
1421c4929fdSclaudio 	bridge_ifclrflag(val, IFBIF_STP);
1431c4929fdSclaudio }
1441c4929fdSclaudio 
1451c4929fdSclaudio void
1461c4929fdSclaudio setedge(const char *val, int d)
1471c4929fdSclaudio {
1481c4929fdSclaudio 	bridge_ifsetflag(val, IFBIF_BSTP_EDGE);
1491c4929fdSclaudio }
1501c4929fdSclaudio 
1511c4929fdSclaudio void
1521c4929fdSclaudio unsetedge(const char *val, int d)
1531c4929fdSclaudio {
1541c4929fdSclaudio 	bridge_ifclrflag(val, IFBIF_BSTP_EDGE);
1551c4929fdSclaudio }
1561c4929fdSclaudio 
1571c4929fdSclaudio void
1581c4929fdSclaudio setautoedge(const char *val, int d)
1591c4929fdSclaudio {
1601c4929fdSclaudio 	bridge_ifsetflag(val, IFBIF_BSTP_AUTOEDGE);
1611c4929fdSclaudio }
1621c4929fdSclaudio 
1631c4929fdSclaudio void
1641c4929fdSclaudio unsetautoedge(const char *val, int d)
1651c4929fdSclaudio {
1661c4929fdSclaudio 	bridge_ifclrflag(val, IFBIF_BSTP_AUTOEDGE);
1671c4929fdSclaudio }
1681c4929fdSclaudio 
1691c4929fdSclaudio void
1701c4929fdSclaudio setptp(const char *val, int d)
1711c4929fdSclaudio {
1721c4929fdSclaudio 	bridge_ifsetflag(val, IFBIF_BSTP_PTP);
1731c4929fdSclaudio }
1741c4929fdSclaudio 
1751c4929fdSclaudio void
1761c4929fdSclaudio unsetptp(const char *val, int d)
1771c4929fdSclaudio {
1781c4929fdSclaudio 	bridge_ifclrflag(val, IFBIF_BSTP_PTP);
1791c4929fdSclaudio }
1801c4929fdSclaudio 
1811c4929fdSclaudio void
1821c4929fdSclaudio setautoptp(const char *val, int d)
1831c4929fdSclaudio {
1841c4929fdSclaudio 	bridge_ifsetflag(val, IFBIF_BSTP_AUTOPTP);
1851c4929fdSclaudio }
1861c4929fdSclaudio 
1871c4929fdSclaudio void
1881c4929fdSclaudio unsetautoptp(const char *val, int d)
1891c4929fdSclaudio {
1901c4929fdSclaudio 	bridge_ifclrflag(val, IFBIF_BSTP_AUTOPTP);
1911c4929fdSclaudio }
1921c4929fdSclaudio 
19370d427baSgoda void
19470d427baSgoda addlocal(const char *ifsname, int d)
19570d427baSgoda {
19670d427baSgoda 	struct ifbreq breq;
19770d427baSgoda 
19870d427baSgoda 	if (strncmp(ifsname, "vether", (sizeof("vether") - 1)) != 0)
19970d427baSgoda 		errx(1, "only vether can be local interface");
20070d427baSgoda 
20170d427baSgoda 	/* Add local */
2024cfa599eSbluhm 	strlcpy(breq.ifbr_name, ifname, sizeof(breq.ifbr_name));
20370d427baSgoda 	strlcpy(breq.ifbr_ifsname, ifsname, sizeof(breq.ifbr_ifsname));
204d6a6566dSbluhm 	if (ioctl(sock, SIOCBRDGADDL, (caddr_t)&breq) == -1) {
20570d427baSgoda 		if (errno == EEXIST)
206e44d6524Sjsg 			return;
20770d427baSgoda 		else
2084cfa599eSbluhm 			err(1, "%s: ioctl SIOCBRDGADDL %s", ifname, ifsname);
20970d427baSgoda 	}
21070d427baSgoda }
2111c4929fdSclaudio 
2121c4929fdSclaudio void
2131c4929fdSclaudio bridge_ifsetflag(const char *ifsname, u_int32_t flag)
2141c4929fdSclaudio {
2151c4929fdSclaudio 	struct ifbreq req;
2161c4929fdSclaudio 
2174cfa599eSbluhm 	strlcpy(req.ifbr_name, ifname, sizeof(req.ifbr_name));
2181c4929fdSclaudio 	strlcpy(req.ifbr_ifsname, ifsname, sizeof(req.ifbr_ifsname));
219d6a6566dSbluhm 	if (ioctl(sock, SIOCBRDGGIFFLGS, (caddr_t)&req) == -1)
2204cfa599eSbluhm 		err(1, "%s: ioctl SIOCBRDGGIFFLGS %s", ifname, ifsname);
2211c4929fdSclaudio 
2221c4929fdSclaudio 	req.ifbr_ifsflags |= flag & ~IFBIF_RO_MASK;
2231c4929fdSclaudio 
224d6a6566dSbluhm 	if (ioctl(sock, SIOCBRDGSIFFLGS, (caddr_t)&req) == -1)
2254cfa599eSbluhm 		err(1, "%s: ioctl SIOCBRDGSIFFLGS %s", ifname, ifsname);
2261c4929fdSclaudio }
2271c4929fdSclaudio 
2281c4929fdSclaudio void
2291c4929fdSclaudio bridge_ifclrflag(const char *ifsname, u_int32_t flag)
2301c4929fdSclaudio {
2311c4929fdSclaudio 	struct ifbreq req;
2321c4929fdSclaudio 
2334cfa599eSbluhm 	strlcpy(req.ifbr_name, ifname, sizeof(req.ifbr_name));
2341c4929fdSclaudio 	strlcpy(req.ifbr_ifsname, ifsname, sizeof(req.ifbr_ifsname));
2351c4929fdSclaudio 
236d6a6566dSbluhm 	if (ioctl(sock, SIOCBRDGGIFFLGS, (caddr_t)&req) == -1)
2374cfa599eSbluhm 		err(1, "%s: ioctl SIOCBRDGGIFFLGS %s", ifname, ifsname);
2381c4929fdSclaudio 
2391c4929fdSclaudio 	req.ifbr_ifsflags &= ~(flag | IFBIF_RO_MASK);
2401c4929fdSclaudio 
241d6a6566dSbluhm 	if (ioctl(sock, SIOCBRDGSIFFLGS, (caddr_t)&req) == -1)
2424cfa599eSbluhm 		err(1, "%s: ioctl SIOCBRDGSIFFLGS %s", ifname, ifsname);
2431c4929fdSclaudio }
2441c4929fdSclaudio 
2451c4929fdSclaudio void
2461c4929fdSclaudio bridge_flushall(const char *val, int p)
2471c4929fdSclaudio {
2481c4929fdSclaudio 	struct ifbreq req;
2491c4929fdSclaudio 
2504cfa599eSbluhm 	strlcpy(req.ifbr_name, ifname, sizeof(req.ifbr_name));
2511c4929fdSclaudio 	req.ifbr_ifsflags = IFBF_FLUSHALL;
252d6a6566dSbluhm 	if (ioctl(sock, SIOCBRDGFLUSH, &req) == -1)
2534cfa599eSbluhm 		err(1, "%s", ifname);
2541c4929fdSclaudio }
2551c4929fdSclaudio 
2561c4929fdSclaudio void
2571c4929fdSclaudio bridge_flush(const char *val, int p)
2581c4929fdSclaudio {
2591c4929fdSclaudio 	struct ifbreq req;
2601c4929fdSclaudio 
2614cfa599eSbluhm 	strlcpy(req.ifbr_name, ifname, sizeof(req.ifbr_name));
2621c4929fdSclaudio 	req.ifbr_ifsflags = IFBF_FLUSHDYN;
263d6a6566dSbluhm 	if (ioctl(sock, SIOCBRDGFLUSH, &req) == -1)
2644cfa599eSbluhm 		err(1, "%s", ifname);
2651c4929fdSclaudio }
2661c4929fdSclaudio 
2671c4929fdSclaudio void
2681c4929fdSclaudio bridge_cfg(const char *delim)
2691c4929fdSclaudio {
2701c4929fdSclaudio 	struct ifbropreq ifbp;
2711c4929fdSclaudio 	u_int16_t pri;
2721c4929fdSclaudio 	u_int8_t ht, fd, ma, hc, proto;
2731c4929fdSclaudio 	u_int8_t lladdr[ETHER_ADDR_LEN];
2741c4929fdSclaudio 	u_int16_t bprio;
2751c4929fdSclaudio 
2764cfa599eSbluhm 	strlcpy(ifbp.ifbop_name, ifname, sizeof(ifbp.ifbop_name));
277d6a6566dSbluhm 	if (ioctl(sock, SIOCBRDGGPARAM, (caddr_t)&ifbp) == -1) {
278aa570dfbSdlg 		if (errno == ENOTTY)
279aa570dfbSdlg 			return;
2804cfa599eSbluhm 		err(1, "%s SIOCBRDGGPARAM", ifname);
281aa570dfbSdlg 	}
282aa570dfbSdlg 
2831c4929fdSclaudio 	printf("%s", delim);
2841c4929fdSclaudio 	pri = ifbp.ifbop_priority;
2851c4929fdSclaudio 	ht = ifbp.ifbop_hellotime;
2861c4929fdSclaudio 	fd = ifbp.ifbop_fwddelay;
2871c4929fdSclaudio 	ma = ifbp.ifbop_maxage;
2881c4929fdSclaudio 	hc = ifbp.ifbop_holdcount;
2891c4929fdSclaudio 	proto = ifbp.ifbop_protocol;
2901c4929fdSclaudio 
2911c4929fdSclaudio 	printf("priority %u hellotime %u fwddelay %u maxage %u "
2921c4929fdSclaudio 	    "holdcnt %u proto %s\n", pri, ht, fd, ma, hc, stpproto[proto]);
2931c4929fdSclaudio 
2941c4929fdSclaudio 	if (aflag)
2951c4929fdSclaudio 		return;
2961c4929fdSclaudio 
2971c4929fdSclaudio 	PV2ID(ifbp.ifbop_desg_bridge, bprio, lladdr);
2981c4929fdSclaudio 	printf("\tdesignated: id %s priority %u\n",
2991c4929fdSclaudio 	    ether_ntoa((struct ether_addr *)lladdr), bprio);
3001c4929fdSclaudio 
3011c4929fdSclaudio 	if (ifbp.ifbop_root_bridge == ifbp.ifbop_desg_bridge)
3021c4929fdSclaudio 		return;
3031c4929fdSclaudio 
3041c4929fdSclaudio 	PV2ID(ifbp.ifbop_root_bridge, bprio, lladdr);
3051c4929fdSclaudio 	printf("\troot: id %s priority %u ifcost %u port %u\n",
3061c4929fdSclaudio 	    ether_ntoa((struct ether_addr *)lladdr), bprio,
3071c4929fdSclaudio 	    ifbp.ifbop_root_path_cost, ifbp.ifbop_root_port & 0xfff);
3081c4929fdSclaudio }
3091c4929fdSclaudio 
3101c4929fdSclaudio void
3111c4929fdSclaudio bridge_list(char *delim)
3121c4929fdSclaudio {
3131c4929fdSclaudio 	struct ifbreq *reqp;
3141c4929fdSclaudio 	struct ifbifconf bifc;
3151c4929fdSclaudio 	int i, len = 8192;
3161c4929fdSclaudio 	char buf[sizeof(reqp->ifbr_ifsname) + 1], *inbuf = NULL, *inb;
3171c4929fdSclaudio 
3181c4929fdSclaudio 	while (1) {
3191c4929fdSclaudio 		bifc.ifbic_len = len;
3201c4929fdSclaudio 		inb = realloc(inbuf, len);
3211c4929fdSclaudio 		if (inb == NULL)
3221c4929fdSclaudio 			err(1, "malloc");
3231c4929fdSclaudio 		bifc.ifbic_buf = inbuf = inb;
3244cfa599eSbluhm 		strlcpy(bifc.ifbic_name, ifname, sizeof(bifc.ifbic_name));
325d6a6566dSbluhm 		if (ioctl(sock, SIOCBRDGIFS, &bifc) == -1) {
326aa570dfbSdlg 			if (errno == ENOTTY)
327aa570dfbSdlg 				return;
3284cfa599eSbluhm 			err(1, "%s SIOCBRDGIFS", ifname);
329aa570dfbSdlg 		}
3301c4929fdSclaudio 		if (bifc.ifbic_len + sizeof(*reqp) < len)
3311c4929fdSclaudio 			break;
3321c4929fdSclaudio 		len *= 2;
3331c4929fdSclaudio 	}
3341c4929fdSclaudio 	for (i = 0; i < bifc.ifbic_len / sizeof(*reqp); i++) {
3351c4929fdSclaudio 		reqp = bifc.ifbic_req + i;
3361c4929fdSclaudio 		strlcpy(buf, reqp->ifbr_ifsname, sizeof(buf));
3371c4929fdSclaudio 		printf("%s%s ", delim, buf);
3381c4929fdSclaudio 		printb("flags", reqp->ifbr_ifsflags, IFBIFBITS);
3391c4929fdSclaudio 		printf("\n");
3401c4929fdSclaudio 		if (reqp->ifbr_ifsflags & IFBIF_SPAN)
3411c4929fdSclaudio 			continue;
3421c4929fdSclaudio 		printf("\t\t");
3431c4929fdSclaudio 		printf("port %u ifpriority %u ifcost %u",
3441c4929fdSclaudio 		    reqp->ifbr_portno, reqp->ifbr_priority,
3451c4929fdSclaudio 		    reqp->ifbr_path_cost);
3460a04437dSmpi 		if (reqp->ifbr_protected) {
3470a04437dSmpi 			int v;
3480a04437dSmpi 
3490a04437dSmpi 			v = ffs(reqp->ifbr_protected);
3500a04437dSmpi 			printf(" protected %u", v);
3510a04437dSmpi 			while (++v < 32) {
3520a04437dSmpi 				if ((1 << (v - 1)) & reqp->ifbr_protected)
3530a04437dSmpi 					printf(",%u", v);
3540a04437dSmpi 			}
355478f2fecStedu 		}
3561c4929fdSclaudio 		if (reqp->ifbr_ifsflags & IFBIF_STP)
3571c4929fdSclaudio 			printf(" %s role %s",
3581c4929fdSclaudio 			    stpstates[reqp->ifbr_state],
3591c4929fdSclaudio 			    stproles[reqp->ifbr_role]);
3601c4929fdSclaudio 		printf("\n");
361a5ab8f93Srzalamena 		bridge_rules(buf, 1);
3621c4929fdSclaudio 	}
3631c4929fdSclaudio 	free(bifc.ifbic_buf);
3641c4929fdSclaudio }
3651c4929fdSclaudio 
3661c4929fdSclaudio void
3671c4929fdSclaudio bridge_add(const char *ifn, int d)
3681c4929fdSclaudio {
3691c4929fdSclaudio 	struct ifbreq req;
3701c4929fdSclaudio 
3714cfa599eSbluhm 	strlcpy(req.ifbr_name, ifname, sizeof(req.ifbr_name));
3721c4929fdSclaudio 	strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
373d6a6566dSbluhm 	if (ioctl(sock, SIOCBRDGADD, &req) == -1) {
3741c4929fdSclaudio 		if (errno == EEXIST)
3751c4929fdSclaudio 			return;
3764cfa599eSbluhm 		err(1, "%s: %s", ifname, ifn);
3771c4929fdSclaudio 	}
3781c4929fdSclaudio }
3791c4929fdSclaudio 
3801c4929fdSclaudio void
3811c4929fdSclaudio bridge_delete(const char *ifn, int d)
3821c4929fdSclaudio {
3831c4929fdSclaudio 	struct ifbreq req;
3841c4929fdSclaudio 
3854cfa599eSbluhm 	strlcpy(req.ifbr_name, ifname, sizeof(req.ifbr_name));
3861c4929fdSclaudio 	strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
387d6a6566dSbluhm 	if (ioctl(sock, SIOCBRDGDEL, &req) == -1)
3884cfa599eSbluhm 		err(1, "%s: %s", ifname, ifn);
3891c4929fdSclaudio }
3901c4929fdSclaudio 
3911c4929fdSclaudio void
3921c4929fdSclaudio bridge_addspan(const char *ifn, int d)
3931c4929fdSclaudio {
3941c4929fdSclaudio 	struct ifbreq req;
3951c4929fdSclaudio 
3964cfa599eSbluhm 	strlcpy(req.ifbr_name, ifname, sizeof(req.ifbr_name));
3971c4929fdSclaudio 	strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
398d6a6566dSbluhm 	if (ioctl(sock, SIOCBRDGADDS, &req) == -1) {
39925d098c8Scamield 		if (errno == EEXIST)
40025d098c8Scamield 			return;
4014cfa599eSbluhm 		err(1, "%s: %s", ifname, ifn);
4021c4929fdSclaudio 	}
40325d098c8Scamield }
4041c4929fdSclaudio 
4051c4929fdSclaudio void
4061c4929fdSclaudio bridge_delspan(const char *ifn, int d)
4071c4929fdSclaudio {
4081c4929fdSclaudio 	struct ifbreq req;
4091c4929fdSclaudio 
4104cfa599eSbluhm 	strlcpy(req.ifbr_name, ifname, sizeof(req.ifbr_name));
4111c4929fdSclaudio 	strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
412d6a6566dSbluhm 	if (ioctl(sock, SIOCBRDGDELS, &req) == -1)
4134cfa599eSbluhm 		err(1, "%s: %s", ifname, ifn);
4141c4929fdSclaudio }
4151c4929fdSclaudio 
4161c4929fdSclaudio void
4171c4929fdSclaudio bridge_timeout(const char *arg, int d)
4181c4929fdSclaudio {
4191c4929fdSclaudio 	struct ifbrparam bp;
4205a276e38Skn 	const char *errstr;
4211c4929fdSclaudio 
4225a276e38Skn 	bp.ifbrp_ctime = strtonum(arg, 0, UINT32_MAX, &errstr);
4235a276e38Skn 	if (errstr)
4245a276e38Skn 		err(1, "timeout %s is: %s", arg, errstr);
4251c4929fdSclaudio 
4264cfa599eSbluhm 	strlcpy(bp.ifbrp_name, ifname, sizeof(bp.ifbrp_name));
427d6a6566dSbluhm 	if (ioctl(sock, SIOCBRDGSTO, (caddr_t)&bp) == -1)
4284cfa599eSbluhm 		err(1, "%s", ifname);
4291c4929fdSclaudio }
4301c4929fdSclaudio 
4311c4929fdSclaudio void
4321c4929fdSclaudio bridge_maxage(const char *arg, int d)
4331c4929fdSclaudio {
4341c4929fdSclaudio 	struct ifbrparam bp;
4355a276e38Skn 	const char *errstr;
4361c4929fdSclaudio 
4375a276e38Skn 	bp.ifbrp_maxage = strtonum(arg, 0, UINT8_MAX, &errstr);
4385a276e38Skn 	if (errstr)
4395a276e38Skn 		errx(1, "maxage %s is: %s", arg, errstr);
4401c4929fdSclaudio 
4414cfa599eSbluhm 	strlcpy(bp.ifbrp_name, ifname, sizeof(bp.ifbrp_name));
442d6a6566dSbluhm 	if (ioctl(sock, SIOCBRDGSMA, (caddr_t)&bp) == -1)
4434cfa599eSbluhm 		err(1, "%s", ifname);
4441c4929fdSclaudio }
4451c4929fdSclaudio 
4461c4929fdSclaudio void
4471c4929fdSclaudio bridge_priority(const char *arg, int d)
4481c4929fdSclaudio {
4491c4929fdSclaudio 	struct ifbrparam bp;
4505a276e38Skn 	const char *errstr;
4511c4929fdSclaudio 
4525a276e38Skn 	bp.ifbrp_prio  = strtonum(arg, 0, UINT16_MAX, &errstr);
4535a276e38Skn 	if (errstr)
4545a276e38Skn 		errx(1, "spanpriority %s is: %s", arg, errstr);
4551c4929fdSclaudio 
4564cfa599eSbluhm 	strlcpy(bp.ifbrp_name, ifname, sizeof(bp.ifbrp_name));
457d6a6566dSbluhm 	if (ioctl(sock, SIOCBRDGSPRI, (caddr_t)&bp) == -1)
4584cfa599eSbluhm 		err(1, "%s", ifname);
4591c4929fdSclaudio }
4601c4929fdSclaudio 
4611c4929fdSclaudio void
4624cfa599eSbluhm bridge_protect(const char *ifsname, const char *val)
4630a04437dSmpi {
4640a04437dSmpi 	struct ifbreq breq;
4650a04437dSmpi 	unsigned long v;
4660a04437dSmpi 	char *optlist, *str;
4675a276e38Skn 	const char *errstr;
4680a04437dSmpi 
4694cfa599eSbluhm 	strlcpy(breq.ifbr_name, ifname, sizeof(breq.ifbr_name));
4704cfa599eSbluhm 	strlcpy(breq.ifbr_ifsname, ifsname, sizeof(breq.ifbr_ifsname));
4710a04437dSmpi 	breq.ifbr_protected = 0;
4720a04437dSmpi 
4730a04437dSmpi 	/* We muck with the string, so copy it. */
4740a04437dSmpi 	optlist = strdup(val);
4750a04437dSmpi 	if (optlist == NULL)
4760a04437dSmpi 		err(1, "strdup");
4770a04437dSmpi 
4780a04437dSmpi 	str = strtok(optlist, ",");
4790a04437dSmpi 	while (str != NULL) {
4805a276e38Skn 		v = strtonum(str, 1, 31, &errstr);
4815a276e38Skn 		if (errstr)
4825a276e38Skn 			err(1, "protected domain %s is: %s", str, errstr);
4830a04437dSmpi 		breq.ifbr_protected |= (1 << (v - 1));
4840a04437dSmpi 		str = strtok(NULL, ",");
4850a04437dSmpi 	}
4860a04437dSmpi 
487d6a6566dSbluhm 	if (ioctl(sock, SIOCBRDGSIFPROT, (caddr_t)&breq) == -1)
4884cfa599eSbluhm 		err(1, "%s: %s", ifname, val);
4890a04437dSmpi 
4900a04437dSmpi 	free(optlist);
4910a04437dSmpi }
4920a04437dSmpi 
4930a04437dSmpi void
4944cfa599eSbluhm bridge_unprotect(const char *ifsname, int d)
4950a04437dSmpi {
4960a04437dSmpi 	struct ifbreq breq;
4970a04437dSmpi 
4984cfa599eSbluhm 	strlcpy(breq.ifbr_name, ifname, sizeof(breq.ifbr_name));
4994cfa599eSbluhm 	strlcpy(breq.ifbr_ifsname, ifsname, sizeof(breq.ifbr_ifsname));
5000a04437dSmpi 
5010a04437dSmpi 	breq.ifbr_protected = 0;
5020a04437dSmpi 
503d6a6566dSbluhm 	if (ioctl(sock, SIOCBRDGSIFPROT, (caddr_t)&breq) == -1)
5044cfa599eSbluhm 		err(1, "%s: %d", ifname, 0);
5050a04437dSmpi }
5060a04437dSmpi 
5070a04437dSmpi void
5081c4929fdSclaudio bridge_proto(const char *arg, int d)
5091c4929fdSclaudio {
5101c4929fdSclaudio 	struct ifbrparam bp;
5111c4929fdSclaudio 	int i, proto = -1;
5121c4929fdSclaudio 
5131c4929fdSclaudio 	for (i = 0; i <= BSTP_PROTO_MAX; i++)
5141c4929fdSclaudio 		if (strcmp(arg, stpproto[i]) == 0) {
5151c4929fdSclaudio 			proto = i;
5161c4929fdSclaudio 			break;
5171c4929fdSclaudio 		}
5181c4929fdSclaudio 	if (proto == -1)
519ce8a0246Sgsoares 		errx(1, "invalid arg for proto: %s", arg);
5201c4929fdSclaudio 
5214cfa599eSbluhm 	strlcpy(bp.ifbrp_name, ifname, sizeof(bp.ifbrp_name));
5221c4929fdSclaudio 	bp.ifbrp_prio = proto;
523d6a6566dSbluhm 	if (ioctl(sock, SIOCBRDGSPROTO, (caddr_t)&bp) == -1)
5244cfa599eSbluhm 		err(1, "%s", ifname);
5251c4929fdSclaudio }
5261c4929fdSclaudio 
5271c4929fdSclaudio void
5281c4929fdSclaudio bridge_fwddelay(const char *arg, int d)
5291c4929fdSclaudio {
5301c4929fdSclaudio 	struct ifbrparam bp;
5315a276e38Skn 	const char *errstr;
5321c4929fdSclaudio 
5335a276e38Skn 	bp.ifbrp_fwddelay = strtonum(arg, 0, UINT8_MAX, &errstr);
5345a276e38Skn 	if (errstr)
5355a276e38Skn 		errx(1, "fwddelay %s is: %s", arg, errstr);
5361c4929fdSclaudio 
5374cfa599eSbluhm 	strlcpy(bp.ifbrp_name, ifname, sizeof(bp.ifbrp_name));
5385a276e38Skn 
539d6a6566dSbluhm 	if (ioctl(sock, SIOCBRDGSFD, (caddr_t)&bp) == -1)
5404cfa599eSbluhm 		err(1, "%s", ifname);
5411c4929fdSclaudio }
5421c4929fdSclaudio 
5431c4929fdSclaudio void
5441c4929fdSclaudio bridge_hellotime(const char *arg, int d)
5451c4929fdSclaudio {
5461c4929fdSclaudio 	struct ifbrparam bp;
5475a276e38Skn 	const char *errstr;
5481c4929fdSclaudio 
5495a276e38Skn 	bp.ifbrp_hellotime = strtonum(arg, 0, UINT8_MAX, &errstr);
5505a276e38Skn 	if (errstr)
5515a276e38Skn 		errx(1, "hellotime %s is: %s", arg, errstr);
5521c4929fdSclaudio 
5534cfa599eSbluhm 	strlcpy(bp.ifbrp_name, ifname, sizeof(bp.ifbrp_name));
5545a276e38Skn 
555d6a6566dSbluhm 	if (ioctl(sock, SIOCBRDGSHT, (caddr_t)&bp) == -1)
5564cfa599eSbluhm 		err(1, "%s", ifname);
5571c4929fdSclaudio }
5581c4929fdSclaudio 
5591c4929fdSclaudio void
5601c4929fdSclaudio bridge_maxaddr(const char *arg, int d)
5611c4929fdSclaudio {
5621c4929fdSclaudio 	struct ifbrparam bp;
5635a276e38Skn 	const char *errstr;
5641c4929fdSclaudio 
5655a276e38Skn 	bp.ifbrp_csize = strtonum(arg, 0, UINT32_MAX, &errstr);
5665a276e38Skn 	if (errstr)
5675a276e38Skn 		errx(1, "maxaddr %s is: %s", arg, errstr);
5681c4929fdSclaudio 
5694cfa599eSbluhm 	strlcpy(bp.ifbrp_name, ifname, sizeof(bp.ifbrp_name));
570d6a6566dSbluhm 	if (ioctl(sock, SIOCBRDGSCACHE, (caddr_t)&bp) == -1)
5714cfa599eSbluhm 		err(1, "%s", ifname);
5721c4929fdSclaudio }
5731c4929fdSclaudio 
5741c4929fdSclaudio void
5751c4929fdSclaudio bridge_deladdr(const char *addr, int d)
5761c4929fdSclaudio {
5771c4929fdSclaudio 	struct ifbareq ifba;
5781c4929fdSclaudio 	struct ether_addr *ea;
5791c4929fdSclaudio 
5804cfa599eSbluhm 	strlcpy(ifba.ifba_name, ifname, sizeof(ifba.ifba_name));
5811c4929fdSclaudio 	ea = ether_aton(addr);
5821c4929fdSclaudio 	if (ea == NULL)
5832eb2836bSderaadt 		err(1, "Invalid address: %s", addr);
5841c4929fdSclaudio 
5851c4929fdSclaudio 	bcopy(ea, &ifba.ifba_dst, sizeof(struct ether_addr));
5861c4929fdSclaudio 
587d6a6566dSbluhm 	if (ioctl(sock, SIOCBRDGDADDR, &ifba) == -1)
5884cfa599eSbluhm 		err(1, "%s: %s", ifname, addr);
5891c4929fdSclaudio }
5901c4929fdSclaudio 
5911c4929fdSclaudio void
5924cfa599eSbluhm bridge_ifprio(const char *ifsname, const char *val)
5931c4929fdSclaudio {
5941c4929fdSclaudio 	struct ifbreq breq;
5955a276e38Skn 	const char *errstr;
5965a276e38Skn 
5975a276e38Skn 	breq.ifbr_priority = strtonum(val, 0, UINT8_MAX, &errstr);
5985a276e38Skn 	if (errstr)
5995a276e38Skn 		errx(1, "ifpriority %s is: %s", val, errstr);
6001c4929fdSclaudio 
6014cfa599eSbluhm 	strlcpy(breq.ifbr_name, ifname, sizeof(breq.ifbr_name));
6024cfa599eSbluhm 	strlcpy(breq.ifbr_ifsname, ifsname, sizeof(breq.ifbr_ifsname));
6031c4929fdSclaudio 
604d6a6566dSbluhm 	if (ioctl(sock, SIOCBRDGSIFPRIO, (caddr_t)&breq) == -1)
6054cfa599eSbluhm 		err(1, "%s: %s", ifname, val);
6061c4929fdSclaudio }
6071c4929fdSclaudio 
6081c4929fdSclaudio void
6094cfa599eSbluhm bridge_ifcost(const char *ifsname, const char *val)
6101c4929fdSclaudio {
6111c4929fdSclaudio 	struct ifbreq breq;
6125a276e38Skn 	const char *errstr;
6135a276e38Skn 
6145a276e38Skn 	breq.ifbr_path_cost = strtonum(val, 0, UINT32_MAX, &errstr);
6155a276e38Skn 	if (errstr)
6165a276e38Skn 		errx(1, "ifcost %s is: %s", val, errstr);
6171c4929fdSclaudio 
6184cfa599eSbluhm 	strlcpy(breq.ifbr_name, ifname, sizeof(breq.ifbr_name));
6194cfa599eSbluhm 	strlcpy(breq.ifbr_ifsname, ifsname, sizeof(breq.ifbr_ifsname));
6201c4929fdSclaudio 
621d6a6566dSbluhm 	if (ioctl(sock, SIOCBRDGSIFCOST, (caddr_t)&breq) == -1)
6224cfa599eSbluhm 		err(1, "%s: %s", ifname, val);
6231c4929fdSclaudio }
6241c4929fdSclaudio 
6251c4929fdSclaudio void
6264cfa599eSbluhm bridge_noifcost(const char *ifsname, int d)
6271c4929fdSclaudio {
6281c4929fdSclaudio 	struct ifbreq breq;
6291c4929fdSclaudio 
6304cfa599eSbluhm 	strlcpy(breq.ifbr_name, ifname, sizeof(breq.ifbr_name));
6314cfa599eSbluhm 	strlcpy(breq.ifbr_ifsname, ifsname, sizeof(breq.ifbr_ifsname));
6321c4929fdSclaudio 
6331c4929fdSclaudio 	breq.ifbr_path_cost = 0;
6341c4929fdSclaudio 
635d6a6566dSbluhm 	if (ioctl(sock, SIOCBRDGSIFCOST, (caddr_t)&breq) == -1)
6364cfa599eSbluhm 		err(1, "%s", ifname);
6371c4929fdSclaudio }
6381c4929fdSclaudio 
6391c4929fdSclaudio void
6404cfa599eSbluhm bridge_addaddr(const char *ifsname, const char *addr)
6411c4929fdSclaudio {
6421c4929fdSclaudio 	struct ifbareq ifba;
6431c4929fdSclaudio 	struct ether_addr *ea;
6441c4929fdSclaudio 
6454cfa599eSbluhm 	strlcpy(ifba.ifba_name, ifname, sizeof(ifba.ifba_name));
6464cfa599eSbluhm 	strlcpy(ifba.ifba_ifsname, ifsname, sizeof(ifba.ifba_ifsname));
6471c4929fdSclaudio 
6481c4929fdSclaudio 	ea = ether_aton(addr);
6491c4929fdSclaudio 	if (ea == NULL)
6502eb2836bSderaadt 		errx(1, "Invalid address: %s", addr);
6511c4929fdSclaudio 
6521c4929fdSclaudio 	bcopy(ea, &ifba.ifba_dst, sizeof(struct ether_addr));
6531c4929fdSclaudio 	ifba.ifba_flags = IFBAF_STATIC;
6541c4929fdSclaudio 
655d6a6566dSbluhm 	if (ioctl(sock, SIOCBRDGSADDR, &ifba) == -1)
6564cfa599eSbluhm 		err(1, "%s: %s", ifname, addr);
6571c4929fdSclaudio }
6581c4929fdSclaudio 
6591c4929fdSclaudio void
66008d7dbbbSdlg bridge_addendpoint(const char *endpoint, const char *addr)
66108d7dbbbSdlg {
66208d7dbbbSdlg 	struct ifbareq ifba;
66308d7dbbbSdlg 	struct ether_addr *ea;
66408d7dbbbSdlg 	struct addrinfo *res;
66508d7dbbbSdlg 	int ecode;
66608d7dbbbSdlg 
66708d7dbbbSdlg 	/* should we handle ports? */
66808d7dbbbSdlg 	ecode = getaddrinfo(endpoint, NULL, NULL, &res);
66908d7dbbbSdlg 	if (ecode != 0) {
67008d7dbbbSdlg                 errx(1, "%s endpoint %s: %s", ifname, endpoint,
67108d7dbbbSdlg                     gai_strerror(ecode));
67208d7dbbbSdlg 	}
67308d7dbbbSdlg 	if (res->ai_addrlen > sizeof(ifba.ifba_dstsa))
67408d7dbbbSdlg 		errx(1, "%s: addrlen > dstsa", __func__);
67508d7dbbbSdlg 
67608d7dbbbSdlg 	ea = ether_aton(addr);
67708d7dbbbSdlg 	if (ea == NULL) {
67808d7dbbbSdlg 		errx(1, "%s endpoint %s %s: invalid Ethernet address",
67908d7dbbbSdlg 		    ifname, endpoint, addr);
68008d7dbbbSdlg 	}
68108d7dbbbSdlg 
68208d7dbbbSdlg 	memset(&ifba, 0, sizeof(ifba));
68308d7dbbbSdlg 	strlcpy(ifba.ifba_name, ifname, sizeof(ifba.ifba_name));
68408d7dbbbSdlg 	strlcpy(ifba.ifba_ifsname, ifname, sizeof(ifba.ifba_ifsname));
68508d7dbbbSdlg 	memcpy(&ifba.ifba_dst, ea, sizeof(struct ether_addr));
68608d7dbbbSdlg 	memcpy(&ifba.ifba_dstsa, res->ai_addr, res->ai_addrlen);
68708d7dbbbSdlg 	ifba.ifba_flags = IFBAF_STATIC;
68808d7dbbbSdlg 
68908d7dbbbSdlg 	freeaddrinfo(res);
69008d7dbbbSdlg 
69108d7dbbbSdlg 	if (ioctl(sock, SIOCBRDGSADDR, &ifba) == -1)
69208d7dbbbSdlg 		err(1, "%s endpoint %s %s", ifname, endpoint, addr);
69308d7dbbbSdlg }
69408d7dbbbSdlg 
69508d7dbbbSdlg void
696*4da14ec4Sdenis bridge_delendpoint(const char *addr, int d)
697*4da14ec4Sdenis {
698*4da14ec4Sdenis 	struct ifbareq ifba;
699*4da14ec4Sdenis 	struct ether_addr *ea;
700*4da14ec4Sdenis 	int ecode;
701*4da14ec4Sdenis 
702*4da14ec4Sdenis 	ea = ether_aton(addr);
703*4da14ec4Sdenis 	if (ea == NULL) {
704*4da14ec4Sdenis 		errx(1, "%s -endpoint %s: invalid Ethernet address",
705*4da14ec4Sdenis 		    ifname, addr);
706*4da14ec4Sdenis 	}
707*4da14ec4Sdenis 
708*4da14ec4Sdenis 	memset(&ifba, 0, sizeof(ifba));
709*4da14ec4Sdenis 	strlcpy(ifba.ifba_name, ifname, sizeof(ifba.ifba_name));
710*4da14ec4Sdenis 	strlcpy(ifba.ifba_ifsname, ifname, sizeof(ifba.ifba_ifsname));
711*4da14ec4Sdenis 	memcpy(&ifba.ifba_dst, ea, sizeof(struct ether_addr));
712*4da14ec4Sdenis 	ifba.ifba_flags = IFBAF_STATIC;
713*4da14ec4Sdenis 
714*4da14ec4Sdenis 	if (ioctl(sock, SIOCBRDGDADDR, &ifba) == -1)
715*4da14ec4Sdenis 		err(1, "%s -endpoint %s", ifname, addr);
716*4da14ec4Sdenis }
717*4da14ec4Sdenis 
718*4da14ec4Sdenis void
7191c4929fdSclaudio bridge_addrs(const char *delim, int d)
7201c4929fdSclaudio {
721d72e8ec4Sreyk 	char dstaddr[NI_MAXHOST];
722d72e8ec4Sreyk 	char dstport[NI_MAXSERV];
72365618f4cSreyk 	const int niflag = NI_NUMERICHOST|NI_DGRAM;
7241c4929fdSclaudio 	struct ifbaconf ifbac;
7251c4929fdSclaudio 	struct ifbareq *ifba;
7261c4929fdSclaudio 	char *inbuf = NULL, buf[sizeof(ifba->ifba_ifsname) + 1], *inb;
727d72e8ec4Sreyk 	struct sockaddr *sa;
7281c4929fdSclaudio 	int i, len = 8192;
7291c4929fdSclaudio 
7301c4929fdSclaudio 	/* ifconfig will call us with the argv of the command */
7311c4929fdSclaudio 	if (strcmp(delim, "addr") == 0)
7321c4929fdSclaudio 		delim = "";
7331c4929fdSclaudio 
7341c4929fdSclaudio 	while (1) {
7351c4929fdSclaudio 		ifbac.ifbac_len = len;
7361c4929fdSclaudio 		inb = realloc(inbuf, len);
7371c4929fdSclaudio 		if (inb == NULL)
7382eb2836bSderaadt 			err(1, "malloc");
7391c4929fdSclaudio 		ifbac.ifbac_buf = inbuf = inb;
7404cfa599eSbluhm 		strlcpy(ifbac.ifbac_name, ifname, sizeof(ifbac.ifbac_name));
741d6a6566dSbluhm 		if (ioctl(sock, SIOCBRDGRTS, &ifbac) == -1) {
7421c4929fdSclaudio 			if (errno == ENETDOWN)
7431c4929fdSclaudio 				return;
7444cfa599eSbluhm 			err(1, "%s", ifname);
7451c4929fdSclaudio 		}
7461c4929fdSclaudio 		if (ifbac.ifbac_len + sizeof(*ifba) < len)
7471c4929fdSclaudio 			break;
7481c4929fdSclaudio 		len *= 2;
7491c4929fdSclaudio 	}
7501c4929fdSclaudio 
7511c4929fdSclaudio 	for (i = 0; i < ifbac.ifbac_len / sizeof(*ifba); i++) {
7521c4929fdSclaudio 		ifba = ifbac.ifbac_req + i;
7531c4929fdSclaudio 		strlcpy(buf, ifba->ifba_ifsname, sizeof(buf));
7541c4929fdSclaudio 		printf("%s%s %s %u ", delim, ether_ntoa(&ifba->ifba_dst),
7551c4929fdSclaudio 		    buf, ifba->ifba_age);
756d72e8ec4Sreyk 		sa = (struct sockaddr *)&ifba->ifba_dstsa;
7571c4929fdSclaudio 		printb("flags", ifba->ifba_flags, IFBAFBITS);
758d72e8ec4Sreyk 		if (sa->sa_family != AF_UNSPEC &&
759d72e8ec4Sreyk 		    getnameinfo(sa, sa->sa_len,
760d72e8ec4Sreyk 		    dstaddr, sizeof(dstaddr),
761d72e8ec4Sreyk 		    dstport, sizeof(dstport), niflag) == 0)
762d72e8ec4Sreyk 			printf(" tunnel %s:%s", dstaddr, dstport);
7631c4929fdSclaudio 		printf("\n");
7641c4929fdSclaudio 	}
7651c4929fdSclaudio 	free(inbuf);
7661c4929fdSclaudio }
7671c4929fdSclaudio 
7681c4929fdSclaudio void
7691c4929fdSclaudio bridge_holdcnt(const char *value, int d)
7701c4929fdSclaudio {
7711c4929fdSclaudio 	struct ifbrparam bp;
7721c4929fdSclaudio 	const char *errstr;
7731c4929fdSclaudio 
7741c4929fdSclaudio 	bp.ifbrp_txhc = strtonum(value, 0, UINT8_MAX, &errstr);
7751c4929fdSclaudio 	if (errstr)
7765a276e38Skn 		err(1, "holdcnt %s is: %s", value, errstr);
7771c4929fdSclaudio 
7784cfa599eSbluhm 	strlcpy(bp.ifbrp_name, ifname, sizeof(bp.ifbrp_name));
779d6a6566dSbluhm 	if (ioctl(sock, SIOCBRDGSTXHC, (caddr_t)&bp) == -1)
7804cfa599eSbluhm 		err(1, "%s", ifname);
7811c4929fdSclaudio }
7821c4929fdSclaudio 
7831c4929fdSclaudio /*
7844cfa599eSbluhm  * Check to make sure interface is really a bridge interface.
7851c4929fdSclaudio  */
7861c4929fdSclaudio int
7874cfa599eSbluhm is_bridge()
7881c4929fdSclaudio {
7891c4929fdSclaudio 	struct ifbaconf ifbac;
7901c4929fdSclaudio 
7911c4929fdSclaudio 	ifbac.ifbac_len = 0;
7924cfa599eSbluhm 	strlcpy(ifbac.ifbac_name, ifname, sizeof(ifbac.ifbac_name));
793d6a6566dSbluhm 	if (ioctl(sock, SIOCBRDGRTS, (caddr_t)&ifbac) == -1) {
7941c4929fdSclaudio 		if (errno == ENETDOWN)
7951c4929fdSclaudio 			return (1);
7961c4929fdSclaudio 		return (0);
7971c4929fdSclaudio 	}
7981c4929fdSclaudio 	return (1);
7991c4929fdSclaudio }
8001c4929fdSclaudio 
801efea9761Skn /* no tpmr(4) specific ioctls, name is enough if ifconfig.c:printif() passed */
802efea9761Skn int
803efea9761Skn is_tpmr(void)
804efea9761Skn {
805efea9761Skn 	return (strncmp(ifname, "tpmr", sizeof("tpmr") - 1) == 0);
806efea9761Skn }
807efea9761Skn 
8081c4929fdSclaudio void
8091c4929fdSclaudio bridge_status(void)
8101c4929fdSclaudio {
8111c4929fdSclaudio 	struct ifbrparam bp1, bp2;
812efea9761Skn 
813efea9761Skn 	if (is_tpmr()) {
814efea9761Skn 		bridge_list("\t");
815efea9761Skn 		return;
816efea9761Skn 	}
8171c4929fdSclaudio 
8184b4b0d56Skn 	if (!is_bridge())
8191c4929fdSclaudio 		return;
8201c4929fdSclaudio 
8211c4929fdSclaudio 	bridge_cfg("\t");
8221c4929fdSclaudio 	bridge_list("\t");
8231c4929fdSclaudio 
8241c4929fdSclaudio 	if (aflag && !ifaliases)
8251c4929fdSclaudio 		return;
8261c4929fdSclaudio 
8274cfa599eSbluhm 	strlcpy(bp1.ifbrp_name, ifname, sizeof(bp1.ifbrp_name));
828d6a6566dSbluhm 	if (ioctl(sock, SIOCBRDGGCACHE, (caddr_t)&bp1) == -1)
8291c4929fdSclaudio 		return;
8301c4929fdSclaudio 
8314cfa599eSbluhm 	strlcpy(bp2.ifbrp_name, ifname, sizeof(bp2.ifbrp_name));
832d6a6566dSbluhm 	if (ioctl(sock, SIOCBRDGGTO, (caddr_t)&bp2) == -1)
8331c4929fdSclaudio 		return;
8341c4929fdSclaudio 
8351c4929fdSclaudio 	printf("\tAddresses (max cache: %u, timeout: %u):\n",
8361c4929fdSclaudio 	    bp1.ifbrp_csize, bp2.ifbrp_ctime);
8371c4929fdSclaudio 
8381c4929fdSclaudio 	bridge_addrs("\t\t", 0);
8391c4929fdSclaudio }
8401c4929fdSclaudio 
8411c4929fdSclaudio void
8424cfa599eSbluhm bridge_flushrule(const char *ifsname, int d)
8431c4929fdSclaudio {
8441c4929fdSclaudio 	struct ifbrlreq req;
8451c4929fdSclaudio 
8464cfa599eSbluhm 	strlcpy(req.ifbr_name, ifname, sizeof(req.ifbr_name));
8474cfa599eSbluhm 	strlcpy(req.ifbr_ifsname, ifsname, sizeof(req.ifbr_ifsname));
848d6a6566dSbluhm 	if (ioctl(sock, SIOCBRDGFRL, &req) == -1)
8494cfa599eSbluhm 		err(1, "%s: %s", ifname, ifsname);
8501c4929fdSclaudio }
8511c4929fdSclaudio 
8521c4929fdSclaudio void
8534cfa599eSbluhm bridge_rules(const char *ifsname, int usetab)
8541c4929fdSclaudio {
8551c4929fdSclaudio 	char *inbuf = NULL, *inb;
8561c4929fdSclaudio 	struct ifbrlconf ifc;
8571c4929fdSclaudio 	struct ifbrlreq *ifrp;
8581c4929fdSclaudio 	int len = 8192, i;
8591c4929fdSclaudio 
8601c4929fdSclaudio 	while (1) {
8611c4929fdSclaudio 		ifc.ifbrl_len = len;
8621c4929fdSclaudio 		inb = realloc(inbuf, len);
8631c4929fdSclaudio 		if (inb == NULL)
8641c4929fdSclaudio 			err(1, "malloc");
8651c4929fdSclaudio 		ifc.ifbrl_buf = inbuf = inb;
8664cfa599eSbluhm 		strlcpy(ifc.ifbrl_name, ifname, sizeof(ifc.ifbrl_name));
8674cfa599eSbluhm 		strlcpy(ifc.ifbrl_ifsname, ifsname, sizeof(ifc.ifbrl_ifsname));
868d6a6566dSbluhm 		if (ioctl(sock, SIOCBRDGGRL, &ifc) == -1)
8691c4929fdSclaudio 			err(1, "ioctl(SIOCBRDGGRL)");
8701c4929fdSclaudio 		if (ifc.ifbrl_len + sizeof(*ifrp) < len)
8711c4929fdSclaudio 			break;
8721c4929fdSclaudio 		len *= 2;
8731c4929fdSclaudio 	}
8741c4929fdSclaudio 	ifrp = ifc.ifbrl_req;
8751c4929fdSclaudio 	for (i = 0; i < ifc.ifbrl_len; i += sizeof(*ifrp)) {
8761c4929fdSclaudio 		ifrp = (struct ifbrlreq *)((caddr_t)ifc.ifbrl_req + i);
877a5ab8f93Srzalamena 
878a5ab8f93Srzalamena 		if (usetab)
879a5ab8f93Srzalamena 			printf("\t");
880a5ab8f93Srzalamena 
8811c4929fdSclaudio 		bridge_showrule(ifrp);
8821c4929fdSclaudio 	}
8831c4929fdSclaudio }
8841c4929fdSclaudio 
8851c4929fdSclaudio void
8861c4929fdSclaudio bridge_showrule(struct ifbrlreq *r)
8871c4929fdSclaudio {
8881c4929fdSclaudio 	if (r->ifbr_action == BRL_ACTION_BLOCK)
8891c4929fdSclaudio 		printf("block ");
8901c4929fdSclaudio 	else if (r->ifbr_action == BRL_ACTION_PASS)
8911c4929fdSclaudio 		printf("pass ");
8921c4929fdSclaudio 	else
8931c4929fdSclaudio 		printf("[neither block nor pass?]\n");
8941c4929fdSclaudio 
8951c4929fdSclaudio 	if ((r->ifbr_flags & (BRL_FLAG_IN | BRL_FLAG_OUT)) ==
8961c4929fdSclaudio 	    (BRL_FLAG_IN | BRL_FLAG_OUT))
8971c4929fdSclaudio 		printf("in/out ");
8981c4929fdSclaudio 	else if (r->ifbr_flags & BRL_FLAG_IN)
8991c4929fdSclaudio 		printf("in ");
9001c4929fdSclaudio 	else if (r->ifbr_flags & BRL_FLAG_OUT)
9011c4929fdSclaudio 		printf("out ");
9021c4929fdSclaudio 	else
9031c4929fdSclaudio 		printf("[neither in nor out?]\n");
9041c4929fdSclaudio 
9051c4929fdSclaudio 	printf("on %s", r->ifbr_ifsname);
9061c4929fdSclaudio 
9071c4929fdSclaudio 	if (r->ifbr_flags & BRL_FLAG_SRCVALID)
9081c4929fdSclaudio 		printf(" src %s", ether_ntoa(&r->ifbr_src));
9091c4929fdSclaudio 	if (r->ifbr_flags & BRL_FLAG_DSTVALID)
9101c4929fdSclaudio 		printf(" dst %s", ether_ntoa(&r->ifbr_dst));
9111c4929fdSclaudio 	if (r->ifbr_tagname[0])
9121c4929fdSclaudio 		printf(" tag %s", r->ifbr_tagname);
9131c4929fdSclaudio 
914d6404d18Shenning 	if (r->ifbr_arpf.brla_flags & BRLA_ARP)
915d6404d18Shenning 		printf(" arp");
916d6404d18Shenning 	if (r->ifbr_arpf.brla_flags & BRLA_RARP)
917d6404d18Shenning 		printf(" rarp");
918d6404d18Shenning 	if (r->ifbr_arpf.brla_op == ARPOP_REQUEST ||
919d6404d18Shenning 	    r->ifbr_arpf.brla_op == ARPOP_REVREQUEST)
920d6404d18Shenning 		printf(" request");
921d6404d18Shenning 	if (r->ifbr_arpf.brla_op == ARPOP_REPLY ||
922d6404d18Shenning 	    r->ifbr_arpf.brla_op == ARPOP_REVREPLY)
923d6404d18Shenning 		printf(" reply");
924d6404d18Shenning 	if (r->ifbr_arpf.brla_flags & BRLA_SHA)
925d6404d18Shenning 		printf(" sha %s", ether_ntoa(&r->ifbr_arpf.brla_sha));
926d6404d18Shenning 	if (r->ifbr_arpf.brla_flags & BRLA_THA)
927d6404d18Shenning 		printf(" tha %s", ether_ntoa(&r->ifbr_arpf.brla_tha));
928d6404d18Shenning 	if (r->ifbr_arpf.brla_flags & BRLA_SPA)
929d6404d18Shenning 		printf(" spa %s", inet_ntoa(r->ifbr_arpf.brla_spa));
930d6404d18Shenning 	if (r->ifbr_arpf.brla_flags & BRLA_TPA)
931d6404d18Shenning 		printf(" tpa %s", inet_ntoa(r->ifbr_arpf.brla_tpa));
932d6404d18Shenning 
9331c4929fdSclaudio 	printf("\n");
9341c4929fdSclaudio }
9351c4929fdSclaudio 
9361c4929fdSclaudio /*
9371c4929fdSclaudio  * Parse a rule definition and send it upwards.
9381c4929fdSclaudio  *
9391c4929fdSclaudio  * Syntax:
9401c4929fdSclaudio  *	{block|pass} {in|out|in/out} on {ifs} [src {mac}] [dst {mac}]
9411c4929fdSclaudio  */
9421c4929fdSclaudio int
9431c4929fdSclaudio bridge_rule(int targc, char **targv, int ln)
9441c4929fdSclaudio {
9451c4929fdSclaudio 	char **argv = targv;
9461c4929fdSclaudio 	int argc = targc;
9471c4929fdSclaudio 	struct ifbrlreq rule;
9481c4929fdSclaudio 	struct ether_addr *ea, *dea;
9491c4929fdSclaudio 
9501c4929fdSclaudio 	if (argc == 0) {
951ce8a0246Sgsoares 		warnx("invalid rule");
9522eb2836bSderaadt 		return (1);
9531c4929fdSclaudio 	}
954d6404d18Shenning 	bzero(&rule, sizeof(rule));
9554cfa599eSbluhm 	strlcpy(rule.ifbr_name, ifname, sizeof(rule.ifbr_name));
9561c4929fdSclaudio 
9571c4929fdSclaudio 	if (strcmp(argv[0], "block") == 0)
9581c4929fdSclaudio 		rule.ifbr_action = BRL_ACTION_BLOCK;
9591c4929fdSclaudio 	else if (strcmp(argv[0], "pass") == 0)
9601c4929fdSclaudio 		rule.ifbr_action = BRL_ACTION_PASS;
9611c4929fdSclaudio 	else
9621c4929fdSclaudio 		goto bad_rule;
9631c4929fdSclaudio 	argc--;	argv++;
9641c4929fdSclaudio 
9651c4929fdSclaudio 	if (argc == 0) {
9661c4929fdSclaudio 		bridge_badrule(targc, targv, ln);
9672eb2836bSderaadt 		return (1);
9681c4929fdSclaudio 	}
9691c4929fdSclaudio 	if (strcmp(argv[0], "in") == 0)
9701c4929fdSclaudio 		rule.ifbr_flags |= BRL_FLAG_IN;
9711c4929fdSclaudio 	else if (strcmp(argv[0], "out") == 0)
9721c4929fdSclaudio 		rule.ifbr_flags |= BRL_FLAG_OUT;
9731c4929fdSclaudio 	else if (strcmp(argv[0], "in/out") == 0)
9741c4929fdSclaudio 		rule.ifbr_flags |= BRL_FLAG_IN | BRL_FLAG_OUT;
9751c4929fdSclaudio 	else if (strcmp(argv[0], "on") == 0) {
9761c4929fdSclaudio 		rule.ifbr_flags |= BRL_FLAG_IN | BRL_FLAG_OUT;
9771c4929fdSclaudio 		argc++; argv--;
9781c4929fdSclaudio 	} else
9791c4929fdSclaudio 		goto bad_rule;
9801c4929fdSclaudio 	argc--; argv++;
9811c4929fdSclaudio 
9821c4929fdSclaudio 	if (argc == 0 || strcmp(argv[0], "on"))
9831c4929fdSclaudio 		goto bad_rule;
9841c4929fdSclaudio 	argc--; argv++;
9851c4929fdSclaudio 
9861c4929fdSclaudio 	if (argc == 0)
9871c4929fdSclaudio 		goto bad_rule;
9881c4929fdSclaudio 	strlcpy(rule.ifbr_ifsname, argv[0], sizeof(rule.ifbr_ifsname));
9891c4929fdSclaudio 	argc--; argv++;
9901c4929fdSclaudio 
9911c4929fdSclaudio 	while (argc) {
992d6404d18Shenning 		dea = NULL;
9931c4929fdSclaudio 		if (strcmp(argv[0], "dst") == 0) {
9941c4929fdSclaudio 			if (rule.ifbr_flags & BRL_FLAG_DSTVALID)
9951c4929fdSclaudio 				goto bad_rule;
9961c4929fdSclaudio 			rule.ifbr_flags |= BRL_FLAG_DSTVALID;
9971c4929fdSclaudio 			dea = &rule.ifbr_dst;
998d6404d18Shenning 			argc--; argv++;
9991c4929fdSclaudio 		} else if (strcmp(argv[0], "src") == 0) {
10001c4929fdSclaudio 			if (rule.ifbr_flags & BRL_FLAG_SRCVALID)
10011c4929fdSclaudio 				goto bad_rule;
10021c4929fdSclaudio 			rule.ifbr_flags |= BRL_FLAG_SRCVALID;
10031c4929fdSclaudio 			dea = &rule.ifbr_src;
1004d6404d18Shenning 			argc--; argv++;
10051c4929fdSclaudio 		} else if (strcmp(argv[0], "tag") == 0) {
10061c4929fdSclaudio 			if (argc < 2) {
1007ce8a0246Sgsoares 				warnx("missing tag name");
10081c4929fdSclaudio 				goto bad_rule;
10091c4929fdSclaudio 			}
10101c4929fdSclaudio 			if (rule.ifbr_tagname[0]) {
1011ce8a0246Sgsoares 				warnx("tag already defined");
10121c4929fdSclaudio 				goto bad_rule;
10131c4929fdSclaudio 			}
1014d6404d18Shenning 			argc--; argv++;
1015d6404d18Shenning 			if (strlcpy(rule.ifbr_tagname, argv[0],
10161c4929fdSclaudio 			    PF_TAG_NAME_SIZE) > PF_TAG_NAME_SIZE) {
1017d6404d18Shenning 				warnx("tag name '%s' too long", argv[0]);
10181c4929fdSclaudio 				goto bad_rule;
10191c4929fdSclaudio 			}
1020d6404d18Shenning 			argc--; argv++;
1021d6404d18Shenning 		} else if (strcmp(argv[0], "arp") == 0) {
1022d6404d18Shenning 			rule.ifbr_arpf.brla_flags |= BRLA_ARP;
1023d6404d18Shenning 			argc--; argv++;
1024d6404d18Shenning 			if (bridge_arprule(&rule, &argc, &argv) == -1)
1025d6404d18Shenning 				goto bad_rule;
1026d6404d18Shenning 		} else if (strcmp(argv[0], "rarp") == 0) {
1027d6404d18Shenning 			rule.ifbr_arpf.brla_flags |= BRLA_RARP;
1028d6404d18Shenning 			argc--; argv++;
1029d6404d18Shenning 			if (bridge_arprule(&rule, &argc, &argv) == -1)
1030d6404d18Shenning 				goto bad_rule;
10311c4929fdSclaudio 		} else
10321c4929fdSclaudio 			goto bad_rule;
10331c4929fdSclaudio 
1034d6404d18Shenning 		if (dea != NULL) {
10351c4929fdSclaudio 			if (argc == 0)
10361c4929fdSclaudio 				goto bad_rule;
10371c4929fdSclaudio 			ea = ether_aton(argv[0]);
10381c4929fdSclaudio 			if (ea == NULL) {
10392eb2836bSderaadt 				warnx("invalid address: %s", argv[0]);
10402eb2836bSderaadt 				return (1);
10411c4929fdSclaudio 			}
10421c4929fdSclaudio 			bcopy(ea, dea, sizeof(*dea));
10431c4929fdSclaudio 			argc--; argv++;
10441c4929fdSclaudio 		}
1045d6404d18Shenning 	}
10461c4929fdSclaudio 
1047d6a6566dSbluhm 	if (ioctl(sock, SIOCBRDGARL, &rule) == -1) {
10484cfa599eSbluhm 		warn("%s", ifname);
10492eb2836bSderaadt 		return (1);
10501c4929fdSclaudio 	}
10511c4929fdSclaudio 	return (0);
10521c4929fdSclaudio 
10531c4929fdSclaudio bad_rule:
10541c4929fdSclaudio 	bridge_badrule(targc, targv, ln);
10552eb2836bSderaadt 	return (1);
10561c4929fdSclaudio }
10571c4929fdSclaudio 
1058d6404d18Shenning int
1059d6404d18Shenning bridge_arprule(struct ifbrlreq *rule, int *argc, char ***argv)
1060d6404d18Shenning {
1061d6404d18Shenning 	while (*argc) {
1062d6404d18Shenning 		struct ether_addr	*ea, *dea = NULL;
1063d6404d18Shenning 		struct in_addr		 ia, *dia = NULL;
1064d6404d18Shenning 
1065d6404d18Shenning 		if (strcmp((*argv)[0], "request") == 0) {
1066d6404d18Shenning 			if (rule->ifbr_arpf.brla_flags & BRLA_ARP)
1067d6404d18Shenning 				rule->ifbr_arpf.brla_op = ARPOP_REQUEST;
1068d6404d18Shenning 			else if (rule->ifbr_arpf.brla_flags & BRLA_RARP)
1069d6404d18Shenning 				rule->ifbr_arpf.brla_op = ARPOP_REVREQUEST;
1070d6404d18Shenning 			else
1071d6404d18Shenning 				errx(1, "bridge_arprule: arp/rarp undefined");
1072d6404d18Shenning 		} else if (strcmp((*argv)[0], "reply") == 0) {
1073d6404d18Shenning 			if (rule->ifbr_arpf.brla_flags & BRLA_ARP)
1074d6404d18Shenning 				rule->ifbr_arpf.brla_op = ARPOP_REPLY;
1075d6404d18Shenning 			else if (rule->ifbr_arpf.brla_flags & BRLA_RARP)
1076d6404d18Shenning 				rule->ifbr_arpf.brla_op = ARPOP_REVREPLY;
1077d6404d18Shenning 			else
1078d6404d18Shenning 				errx(1, "bridge_arprule: arp/rarp undefined");
1079d6404d18Shenning 		} else if (strcmp((*argv)[0], "sha") == 0) {
1080d6404d18Shenning 			rule->ifbr_arpf.brla_flags |= BRLA_SHA;
1081d6404d18Shenning 			dea = &rule->ifbr_arpf.brla_sha;
1082d6404d18Shenning 		} else if (strcmp((*argv)[0], "tha") == 0) {
1083d6404d18Shenning 			rule->ifbr_arpf.brla_flags |= BRLA_THA;
1084d6404d18Shenning 			dea = &rule->ifbr_arpf.brla_tha;
1085d6404d18Shenning 		} else if (strcmp((*argv)[0], "spa") == 0) {
1086d6404d18Shenning 			rule->ifbr_arpf.brla_flags |= BRLA_SPA;
1087d6404d18Shenning 			dia = &rule->ifbr_arpf.brla_spa;
1088d6404d18Shenning 		} else if (strcmp((*argv)[0], "tpa") == 0) {
1089d6404d18Shenning 			rule->ifbr_arpf.brla_flags |= BRLA_TPA;
1090d6404d18Shenning 			dia = &rule->ifbr_arpf.brla_tpa;
1091d6404d18Shenning 		} else
1092d6404d18Shenning 			return (0);
1093d6404d18Shenning 
1094d6404d18Shenning 		(*argc)--; (*argv)++;
1095d6404d18Shenning 		if (dea != NULL) {
1096d6404d18Shenning 			if (*argc == 0)
1097d6404d18Shenning 				return (-1);
1098d6404d18Shenning 			ea = ether_aton((*argv)[0]);
1099d6404d18Shenning 			if (ea == NULL) {
1100d6404d18Shenning 				warnx("invalid address: %s", (*argv)[0]);
1101d6404d18Shenning 				return (-1);
1102d6404d18Shenning 			}
1103d6404d18Shenning 			bcopy(ea, dea, sizeof(*dea));
1104d6404d18Shenning 			(*argc)--; (*argv)++;
1105d6404d18Shenning 		}
1106d6404d18Shenning 		if (dia != NULL) {
1107d6404d18Shenning 			if (*argc == 0)
1108d6404d18Shenning 				return (-1);
1109d6404d18Shenning 			ia.s_addr = inet_addr((*argv)[0]);
1110d6404d18Shenning 			if (ia.s_addr == INADDR_NONE) {
1111d6404d18Shenning 				warnx("invalid address: %s", (*argv)[0]);
1112d6404d18Shenning 				return (-1);
1113d6404d18Shenning 			}
1114d6404d18Shenning 			bcopy(&ia, dia, sizeof(*dia));
1115d6404d18Shenning 			(*argc)--; (*argv)++;
1116d6404d18Shenning 		}
1117d6404d18Shenning 	}
1118d6404d18Shenning 	return (0);
1119d6404d18Shenning }
1120d6404d18Shenning 
1121d6404d18Shenning 
1122d6404d18Shenning #define MAXRULEWORDS 32
11231c4929fdSclaudio 
11241c4929fdSclaudio void
11251c4929fdSclaudio bridge_rulefile(const char *fname, int d)
11261c4929fdSclaudio {
11271c4929fdSclaudio 	FILE *f;
11281c4929fdSclaudio 	char *str, *argv[MAXRULEWORDS], buf[1024];
11291c4929fdSclaudio 	int ln = 0, argc = 0;
11301c4929fdSclaudio 
11311c4929fdSclaudio 	f = fopen(fname, "r");
11321c4929fdSclaudio 	if (f == NULL)
11332eb2836bSderaadt 		err(1, "%s", fname);
11341c4929fdSclaudio 
11351c4929fdSclaudio 	while (fgets(buf, sizeof(buf), f) != NULL) {
11361c4929fdSclaudio 		ln++;
11371c4929fdSclaudio 		if (buf[0] == '#' || buf[0] == '\n')
11381c4929fdSclaudio 			continue;
11391c4929fdSclaudio 
11401c4929fdSclaudio 		argc = 0;
11411c4929fdSclaudio 		str = strtok(buf, "\n\t\r ");
11421c4929fdSclaudio 		while (str != NULL && argc < MAXRULEWORDS) {
11431c4929fdSclaudio 			argv[argc++] = str;
11441c4929fdSclaudio 			str = strtok(NULL, "\n\t\r ");
11451c4929fdSclaudio 		}
11461c4929fdSclaudio 
11471c4929fdSclaudio 		/* Rule is too long if there's more. */
11481c4929fdSclaudio 		if (str != NULL) {
1149ce8a0246Sgsoares 			warnx("invalid rule: %d: %s ...", ln, buf);
11501c4929fdSclaudio 			continue;
11511c4929fdSclaudio 		}
11521c4929fdSclaudio 
11531c4929fdSclaudio 		bridge_rule(argc, argv, ln);
11541c4929fdSclaudio 	}
11551c4929fdSclaudio 	fclose(f);
11561c4929fdSclaudio }
11571c4929fdSclaudio 
11581c4929fdSclaudio void
11591c4929fdSclaudio bridge_badrule(int argc, char *argv[], int ln)
11601c4929fdSclaudio {
11612eb2836bSderaadt 	extern const char *__progname;
11621c4929fdSclaudio 	int i;
11631c4929fdSclaudio 
11642eb2836bSderaadt 	fprintf(stderr, "%s: invalid rule: ", __progname);
11651c4929fdSclaudio 	if (ln != -1)
11661c4929fdSclaudio 		fprintf(stderr, "%d: ", ln);
11672eb2836bSderaadt 	for (i = 0; i < argc; i++)
11681c4929fdSclaudio 		fprintf(stderr, "%s ", argv[i]);
11691c4929fdSclaudio 	fprintf(stderr, "\n");
11701c4929fdSclaudio }
11711c4929fdSclaudio 
11721c4929fdSclaudio #endif
1173