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