Index: head/sbin/ifconfig/ifbridge.c =================================================================== --- head/sbin/ifconfig/ifbridge.c (revision 173319) +++ head/sbin/ifconfig/ifbridge.c (revision 173320) @@ -1,737 +1,759 @@ /*- * Copyright 2001 Wasabi Systems, Inc. * All rights reserved. * * Written by Jason R. Thorpe for Wasabi Systems, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project by * Wasabi Systems, Inc. * 4. The name of Wasabi Systems, Inc. may not be used to endorse * or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef lint static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ifconfig.h" #define PV2ID(pv, epri, eaddr) do { \ epri = pv >> 48; \ eaddr[0] = pv >> 40; \ eaddr[1] = pv >> 32; \ eaddr[2] = pv >> 24; \ eaddr[3] = pv >> 16; \ eaddr[4] = pv >> 8; \ eaddr[5] = pv >> 0; \ } while (0) static const char *stpstates[] = { "disabled", "listening", "learning", "forwarding", "blocking", "discarding" }; static const char *stpproto[] = { "stp", "-", "rstp" }; static const char *stproles[] = { "disabled", "root", "designated", "alternate", "backup" }; static int get_val(const char *cp, u_long *valp) { char *endptr; u_long val; errno = 0; val = strtoul(cp, &endptr, 0); if (cp[0] == '\0' || endptr[0] != '\0' || errno == ERANGE) return (-1); *valp = val; return (0); } static int do_cmd(int sock, u_long op, void *arg, size_t argsize, int set) { struct ifdrv ifd; memset(&ifd, 0, sizeof(ifd)); strlcpy(ifd.ifd_name, ifr.ifr_name, sizeof(ifd.ifd_name)); ifd.ifd_cmd = op; ifd.ifd_len = argsize; ifd.ifd_data = arg; return (ioctl(sock, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd)); } static void do_bridgeflag(int sock, const char *ifs, int flag, int set) { struct ifbreq req; strlcpy(req.ifbr_ifsname, ifs, sizeof(req.ifbr_ifsname)); if (do_cmd(sock, BRDGGIFFLGS, &req, sizeof(req), 0) < 0) err(1, "unable to get bridge flags"); if (set) req.ifbr_ifsflags |= flag; else req.ifbr_ifsflags &= ~flag; if (do_cmd(sock, BRDGSIFFLGS, &req, sizeof(req), 1) < 0) err(1, "unable to set bridge flags"); } static void bridge_interfaces(int s, const char *prefix) { struct ifbifconf bifc; struct ifbreq *req; char *inbuf = NULL, *ninbuf; char *p, *pad; int i, len = 8192; pad = strdup(prefix); if (pad == NULL) err(1, "strdup"); /* replace the prefix with whitespace */ for (p = pad; *p != '\0'; p++) { if(isprint(*p)) *p = ' '; } for (;;) { ninbuf = realloc(inbuf, len); if (ninbuf == NULL) err(1, "unable to allocate interface buffer"); bifc.ifbic_len = len; bifc.ifbic_buf = inbuf = ninbuf; if (do_cmd(s, BRDGGIFS, &bifc, sizeof(bifc), 0) < 0) err(1, "unable to get interface list"); if ((bifc.ifbic_len + sizeof(*req)) < len) break; len *= 2; } for (i = 0; i < bifc.ifbic_len / sizeof(*req); i++) { req = bifc.ifbic_req + i; printf("%s%s ", prefix, req->ifbr_ifsname); printb("flags", req->ifbr_ifsflags, IFBIFBITS); printf("\n"); - + + printf("%s", pad); + printf("ifmaxaddr %u", req->ifbr_addrmax); + printf(" port %u priority %u", req->ifbr_portno, + req->ifbr_priority); + printf(" path cost %u", req->ifbr_path_cost); + if (req->ifbr_ifsflags & IFBIF_STP) { - printf("%s", pad); - printf("port %u priority %u", - req->ifbr_portno, req->ifbr_priority); - printf(" path cost %u", req->ifbr_path_cost); if (req->ifbr_proto < sizeof(stpproto) / sizeof(stpproto[0])) printf(" proto %s", stpproto[req->ifbr_proto]); else printf(" ", req->ifbr_proto); printf("\n%s", pad); if (req->ifbr_role < sizeof(stproles) / sizeof(stproles[0])) printf("role %s", stproles[req->ifbr_role]); else printf("", req->ifbr_role); if (req->ifbr_state < sizeof(stpstates) / sizeof(stpstates[0])) printf(" state %s", stpstates[req->ifbr_state]); else printf(" ", req->ifbr_state); - printf("\n"); } + printf("\n"); } free(inbuf); } static void bridge_addresses(int s, const char *prefix) { struct ifbaconf ifbac; struct ifbareq *ifba; char *inbuf = NULL, *ninbuf; int i, len = 8192; struct ether_addr ea; for (;;) { ninbuf = realloc(inbuf, len); if (ninbuf == NULL) err(1, "unable to allocate address buffer"); ifbac.ifbac_len = len; ifbac.ifbac_buf = inbuf = ninbuf; if (do_cmd(s, BRDGRTS, &ifbac, sizeof(ifbac), 0) < 0) err(1, "unable to get address cache"); if ((ifbac.ifbac_len + sizeof(*ifba)) < len) break; len *= 2; } for (i = 0; i < ifbac.ifbac_len / sizeof(*ifba); i++) { ifba = ifbac.ifbac_req + i; memcpy(ea.octet, ifba->ifba_dst, sizeof(ea.octet)); printf("%s%s Vlan%d %s %lu ", prefix, ether_ntoa(&ea), ifba->ifba_vlan, ifba->ifba_ifsname, ifba->ifba_expire); printb("flags", ifba->ifba_flags, IFBAFBITS); printf("\n"); } free(inbuf); } static void bridge_status(int s) { struct ifbropreq ifbp; struct ifbrparam param; u_int16_t pri; u_int8_t ht, fd, ma, hc, pro; u_int8_t lladdr[ETHER_ADDR_LEN]; u_int16_t bprio; u_int32_t csize, ctime; if (do_cmd(s, BRDGGCACHE, ¶m, sizeof(param), 0) < 0) return; csize = param.ifbrp_csize; if (do_cmd(s, BRDGGTO, ¶m, sizeof(param), 0) < 0) return; ctime = param.ifbrp_ctime; if (do_cmd(s, BRDGPARAM, &ifbp, sizeof(ifbp), 0) < 0) return; pri = ifbp.ifbop_priority; pro = ifbp.ifbop_protocol; ht = ifbp.ifbop_hellotime; fd = ifbp.ifbop_fwddelay; hc = ifbp.ifbop_holdcount; ma = ifbp.ifbop_maxage; PV2ID(ifbp.ifbop_bridgeid, bprio, lladdr); printf("\tid %s priority %u hellotime %u fwddelay %u\n", ether_ntoa((struct ether_addr *)lladdr), pri, ht, fd); printf("\tmaxage %u holdcnt %u proto %s maxaddr %u timeout %u\n", ma, hc, stpproto[pro], csize, ctime); PV2ID(ifbp.ifbop_designated_root, bprio, lladdr); printf("\troot id %s priority %d ifcost %u port %u\n", ether_ntoa((struct ether_addr *)lladdr), bprio, ifbp.ifbop_root_path_cost, ifbp.ifbop_root_port & 0xfff); bridge_interfaces(s, "\tmember: "); return; } static void setbridge_add(const char *val, int d, int s, const struct afswtch *afp) { struct ifbreq req; memset(&req, 0, sizeof(req)); strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname)); if (do_cmd(s, BRDGADD, &req, sizeof(req), 1) < 0) err(1, "BRDGADD %s", val); } static void setbridge_delete(const char *val, int d, int s, const struct afswtch *afp) { struct ifbreq req; memset(&req, 0, sizeof(req)); strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname)); if (do_cmd(s, BRDGDEL, &req, sizeof(req), 1) < 0) err(1, "BRDGDEL %s", val); } static void setbridge_discover(const char *val, int d, int s, const struct afswtch *afp) { do_bridgeflag(s, val, IFBIF_DISCOVER, 1); } static void unsetbridge_discover(const char *val, int d, int s, const struct afswtch *afp) { do_bridgeflag(s, val, IFBIF_DISCOVER, 0); } static void setbridge_learn(const char *val, int d, int s, const struct afswtch *afp) { do_bridgeflag(s, val, IFBIF_LEARNING, 1); } static void unsetbridge_learn(const char *val, int d, int s, const struct afswtch *afp) { do_bridgeflag(s, val, IFBIF_LEARNING, 0); } static void setbridge_sticky(const char *val, int d, int s, const struct afswtch *afp) { do_bridgeflag(s, val, IFBIF_STICKY, 1); } static void unsetbridge_sticky(const char *val, int d, int s, const struct afswtch *afp) { do_bridgeflag(s, val, IFBIF_STICKY, 0); } static void setbridge_span(const char *val, int d, int s, const struct afswtch *afp) { struct ifbreq req; memset(&req, 0, sizeof(req)); strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname)); if (do_cmd(s, BRDGADDS, &req, sizeof(req), 1) < 0) err(1, "BRDGADDS %s", val); } static void unsetbridge_span(const char *val, int d, int s, const struct afswtch *afp) { struct ifbreq req; memset(&req, 0, sizeof(req)); strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname)); if (do_cmd(s, BRDGDELS, &req, sizeof(req), 1) < 0) err(1, "BRDGDELS %s", val); } static void setbridge_stp(const char *val, int d, int s, const struct afswtch *afp) { do_bridgeflag(s, val, IFBIF_STP, 1); } static void unsetbridge_stp(const char *val, int d, int s, const struct afswtch *afp) { do_bridgeflag(s, val, IFBIF_STP, 0); } static void setbridge_edge(const char *val, int d, int s, const struct afswtch *afp) { do_bridgeflag(s, val, IFBIF_BSTP_EDGE, 1); } static void unsetbridge_edge(const char *val, int d, int s, const struct afswtch *afp) { do_bridgeflag(s, val, IFBIF_BSTP_EDGE, 0); } static void setbridge_autoedge(const char *val, int d, int s, const struct afswtch *afp) { do_bridgeflag(s, val, IFBIF_BSTP_AUTOEDGE, 1); } static void unsetbridge_autoedge(const char *val, int d, int s, const struct afswtch *afp) { do_bridgeflag(s, val, IFBIF_BSTP_AUTOEDGE, 0); } static void setbridge_ptp(const char *val, int d, int s, const struct afswtch *afp) { do_bridgeflag(s, val, IFBIF_BSTP_PTP, 1); } static void unsetbridge_ptp(const char *val, int d, int s, const struct afswtch *afp) { do_bridgeflag(s, val, IFBIF_BSTP_PTP, 0); } static void setbridge_autoptp(const char *val, int d, int s, const struct afswtch *afp) { do_bridgeflag(s, val, IFBIF_BSTP_AUTOPTP, 1); } static void unsetbridge_autoptp(const char *val, int d, int s, const struct afswtch *afp) { do_bridgeflag(s, val, IFBIF_BSTP_AUTOPTP, 0); } static void setbridge_flush(const char *val, int d, int s, const struct afswtch *afp) { struct ifbreq req; memset(&req, 0, sizeof(req)); req.ifbr_ifsflags = IFBF_FLUSHDYN; if (do_cmd(s, BRDGFLUSH, &req, sizeof(req), 1) < 0) err(1, "BRDGFLUSH"); } static void setbridge_flushall(const char *val, int d, int s, const struct afswtch *afp) { struct ifbreq req; memset(&req, 0, sizeof(req)); req.ifbr_ifsflags = IFBF_FLUSHALL; if (do_cmd(s, BRDGFLUSH, &req, sizeof(req), 1) < 0) err(1, "BRDGFLUSH"); } static void setbridge_static(const char *val, const char *mac, int s, const struct afswtch *afp) { struct ifbareq req; struct ether_addr *ea; memset(&req, 0, sizeof(req)); strlcpy(req.ifba_ifsname, val, sizeof(req.ifba_ifsname)); ea = ether_aton(mac); if (ea == NULL) errx(1, "%s: invalid address: %s", val, mac); memcpy(req.ifba_dst, ea->octet, sizeof(req.ifba_dst)); req.ifba_flags = IFBAF_STATIC; req.ifba_vlan = 1; /* XXX allow user to specify */ if (do_cmd(s, BRDGSADDR, &req, sizeof(req), 1) < 0) err(1, "BRDGSADDR %s", val); } static void setbridge_deladdr(const char *val, int d, int s, const struct afswtch *afp) { struct ifbareq req; struct ether_addr *ea; memset(&req, 0, sizeof(req)); ea = ether_aton(val); if (ea == NULL) errx(1, "invalid address: %s", val); memcpy(req.ifba_dst, ea->octet, sizeof(req.ifba_dst)); if (do_cmd(s, BRDGDADDR, &req, sizeof(req), 1) < 0) err(1, "BRDGDADDR %s", val); } static void setbridge_addr(const char *val, int d, int s, const struct afswtch *afp) { bridge_addresses(s, ""); } static void setbridge_maxaddr(const char *arg, int d, int s, const struct afswtch *afp) { struct ifbrparam param; u_long val; if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0) errx(1, "invalid value: %s", arg); param.ifbrp_csize = val & 0xffffffff; if (do_cmd(s, BRDGSCACHE, ¶m, sizeof(param), 1) < 0) err(1, "BRDGSCACHE %s", arg); } static void setbridge_hellotime(const char *arg, int d, int s, const struct afswtch *afp) { struct ifbrparam param; u_long val; if (get_val(arg, &val) < 0 || (val & ~0xff) != 0) errx(1, "invalid value: %s", arg); param.ifbrp_hellotime = val & 0xff; if (do_cmd(s, BRDGSHT, ¶m, sizeof(param), 1) < 0) err(1, "BRDGSHT %s", arg); } static void setbridge_fwddelay(const char *arg, int d, int s, const struct afswtch *afp) { struct ifbrparam param; u_long val; if (get_val(arg, &val) < 0 || (val & ~0xff) != 0) errx(1, "invalid value: %s", arg); param.ifbrp_fwddelay = val & 0xff; if (do_cmd(s, BRDGSFD, ¶m, sizeof(param), 1) < 0) err(1, "BRDGSFD %s", arg); } static void setbridge_maxage(const char *arg, int d, int s, const struct afswtch *afp) { struct ifbrparam param; u_long val; if (get_val(arg, &val) < 0 || (val & ~0xff) != 0) errx(1, "invalid value: %s", arg); param.ifbrp_maxage = val & 0xff; if (do_cmd(s, BRDGSMA, ¶m, sizeof(param), 1) < 0) err(1, "BRDGSMA %s", arg); } static void setbridge_priority(const char *arg, int d, int s, const struct afswtch *afp) { struct ifbrparam param; u_long val; if (get_val(arg, &val) < 0 || (val & ~0xffff) != 0) errx(1, "invalid value: %s", arg); param.ifbrp_prio = val & 0xffff; if (do_cmd(s, BRDGSPRI, ¶m, sizeof(param), 1) < 0) err(1, "BRDGSPRI %s", arg); } static void setbridge_protocol(const char *arg, int d, int s, const struct afswtch *afp) { struct ifbrparam param; if (strcasecmp(arg, "stp") == 0) { param.ifbrp_proto = 0; } else if (strcasecmp(arg, "rstp") == 0) { param.ifbrp_proto = 2; } else { errx(1, "unknown stp protocol"); } if (do_cmd(s, BRDGSPROTO, ¶m, sizeof(param), 1) < 0) err(1, "BRDGSPROTO %s", arg); } static void setbridge_holdcount(const char *arg, int d, int s, const struct afswtch *afp) { struct ifbrparam param; u_long val; if (get_val(arg, &val) < 0 || (val & ~0xff) != 0) errx(1, "invalid value: %s", arg); param.ifbrp_txhc = val & 0xff; if (do_cmd(s, BRDGSTXHC, ¶m, sizeof(param), 1) < 0) err(1, "BRDGSTXHC %s", arg); } static void setbridge_ifpriority(const char *ifn, const char *pri, int s, const struct afswtch *afp) { struct ifbreq req; u_long val; memset(&req, 0, sizeof(req)); if (get_val(pri, &val) < 0 || (val & ~0xff) != 0) errx(1, "invalid value: %s", pri); strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname)); req.ifbr_priority = val & 0xff; if (do_cmd(s, BRDGSIFPRIO, &req, sizeof(req), 1) < 0) err(1, "BRDGSIFPRIO %s", pri); } static void setbridge_ifpathcost(const char *ifn, const char *cost, int s, const struct afswtch *afp) { struct ifbreq req; u_long val; memset(&req, 0, sizeof(req)); if (get_val(cost, &val) < 0) errx(1, "invalid value: %s", cost); strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname)); req.ifbr_path_cost = val; if (do_cmd(s, BRDGSIFCOST, &req, sizeof(req), 1) < 0) err(1, "BRDGSIFCOST %s", cost); } static void +setbridge_ifmaxaddr(const char *ifn, const char *arg, int s, + const struct afswtch *afp) +{ + struct ifbreq req; + u_long val; + + memset(&req, 0, sizeof(req)); + + if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0) + errx(1, "invalid value: %s", arg); + + strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname)); + req.ifbr_addrmax = val & 0xffffffff; + + if (do_cmd(s, BRDGSIFAMAX, &req, sizeof(req), 1) < 0) + err(1, "BRDGSIFAMAX %s", arg); +} + +static void setbridge_timeout(const char *arg, int d, int s, const struct afswtch *afp) { struct ifbrparam param; u_long val; if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0) errx(1, "invalid value: %s", arg); param.ifbrp_ctime = val & 0xffffffff; if (do_cmd(s, BRDGSTO, ¶m, sizeof(param), 1) < 0) err(1, "BRDGSTO %s", arg); } static void setbridge_private(const char *val, int d, int s, const struct afswtch *afp) { do_bridgeflag(s, val, IFBIF_PRIVATE, 1); } static void unsetbridge_private(const char *val, int d, int s, const struct afswtch *afp) { do_bridgeflag(s, val, IFBIF_PRIVATE, 0); } static struct cmd bridge_cmds[] = { DEF_CMD_ARG("addm", setbridge_add), DEF_CMD_ARG("deletem", setbridge_delete), DEF_CMD_ARG("discover", setbridge_discover), DEF_CMD_ARG("-discover", unsetbridge_discover), DEF_CMD_ARG("learn", setbridge_learn), DEF_CMD_ARG("-learn", unsetbridge_learn), DEF_CMD_ARG("sticky", setbridge_sticky), DEF_CMD_ARG("-sticky", unsetbridge_sticky), DEF_CMD_ARG("span", setbridge_span), DEF_CMD_ARG("-span", unsetbridge_span), DEF_CMD_ARG("stp", setbridge_stp), DEF_CMD_ARG("-stp", unsetbridge_stp), DEF_CMD_ARG("edge", setbridge_edge), DEF_CMD_ARG("-edge", unsetbridge_edge), DEF_CMD_ARG("autoedge", setbridge_autoedge), DEF_CMD_ARG("-autoedge", unsetbridge_autoedge), DEF_CMD_ARG("ptp", setbridge_ptp), DEF_CMD_ARG("-ptp", unsetbridge_ptp), DEF_CMD_ARG("autoptp", setbridge_autoptp), DEF_CMD_ARG("-autoptp", unsetbridge_autoptp), DEF_CMD("flush", 0, setbridge_flush), DEF_CMD("flushall", 0, setbridge_flushall), DEF_CMD_ARG2("static", setbridge_static), DEF_CMD_ARG("deladdr", setbridge_deladdr), DEF_CMD("addr", 1, setbridge_addr), DEF_CMD_ARG("maxaddr", setbridge_maxaddr), DEF_CMD_ARG("hellotime", setbridge_hellotime), DEF_CMD_ARG("fwddelay", setbridge_fwddelay), DEF_CMD_ARG("maxage", setbridge_maxage), DEF_CMD_ARG("priority", setbridge_priority), DEF_CMD_ARG("proto", setbridge_protocol), DEF_CMD_ARG("holdcnt", setbridge_holdcount), DEF_CMD_ARG2("ifpriority", setbridge_ifpriority), DEF_CMD_ARG2("ifpathcost", setbridge_ifpathcost), + DEF_CMD_ARG2("ifmaxaddr", setbridge_ifmaxaddr), DEF_CMD_ARG("timeout", setbridge_timeout), DEF_CMD_ARG("private", setbridge_private), DEF_CMD_ARG("-private", unsetbridge_private), }; static struct afswtch af_bridge = { .af_name = "af_bridge", .af_af = AF_UNSPEC, .af_other_status = bridge_status, }; static __constructor void bridge_ctor(void) { #define N(a) (sizeof(a) / sizeof(a[0])) int i; for (i = 0; i < N(bridge_cmds); i++) cmd_register(&bridge_cmds[i]); af_register(&af_bridge); #undef N } Index: head/sbin/ifconfig/ifconfig.8 =================================================================== --- head/sbin/ifconfig/ifconfig.8 (revision 173319) +++ head/sbin/ifconfig/ifconfig.8 (revision 173320) @@ -1,1940 +1,1945 @@ .\" Copyright (c) 1983, 1991, 1993 .\" The Regents of the University of California. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" 4. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" From: @(#)ifconfig.8 8.3 (Berkeley) 1/5/94 .\" $FreeBSD$ .\" .Dd October 31, 2007 .Dt IFCONFIG 8 .Os .Sh NAME .Nm ifconfig .Nd configure network interface parameters .Sh SYNOPSIS .Nm .Op Fl L .Op Fl k .Op Fl m .Op Fl n .Ar interface .Op Cm create .Op Ar address_family .Oo .Ar address .Op Ar dest_address .Oc .Op Ar parameters .Nm .Ar interface .Cm destroy .Nm .Fl a .Op Fl L .Op Fl d .Op Fl m .Op Fl u .Op Fl v .Op Ar address_family .Nm .Fl l .Op Fl d .Op Fl u .Op Ar address_family .Nm .Op Fl L .Op Fl d .Op Fl k .Op Fl m .Op Fl u .Op Fl v .Op Fl C .Nm .Op Fl g Ar groupname .Sh DESCRIPTION The .Nm utility is used to assign an address to a network interface and/or configure network interface parameters. The .Nm utility must be used at boot time to define the network address of each interface present on a machine; it may also be used at a later time to redefine an interface's address or other operating parameters. .Pp The following options are available: .Bl -tag -width indent .It Ar address For the .Tn DARPA Ns -Internet family, the address is either a host name present in the host name data base, .Xr hosts 5 , or a .Tn DARPA Internet address expressed in the Internet standard .Dq dot notation . .Pp It is also possible to use the CIDR notation (also known as the slash notation) to include the netmask. That is, one can specify an address like .Li 192.168.0.1/16 . .Pp For .Dq inet6 family, it is also possible to specify the prefix length using the slash notation, like .Li ::1/128 . See the .Cm prefixlen parameter below for more information. .\" For the Xerox Network Systems(tm) family, .\" addresses are .\" .Ar net:a.b.c.d.e.f , .\" where .\" .Ar net .\" is the assigned network number (in decimal), .\" and each of the six bytes of the host number, .\" .Ar a .\" through .\" .Ar f , .\" are specified in hexadecimal. .\" The host number may be omitted on IEEE 802 protocol .\" (Ethernet, FDDI, and Token Ring) interfaces, .\" which use the hardware physical address, .\" and on interfaces other than the first. .\" For the .\" .Tn ISO .\" family, addresses are specified as a long hexadecimal string, .\" as in the Xerox family. .\" However, two consecutive dots imply a zero .\" byte, and the dots are optional, if the user wishes to (carefully) .\" count out long strings of digits in network byte order. .Pp The link-level .Pq Dq link address is specified as a series of colon-separated hex digits. This can be used to e.g.\& set a new MAC address on an ethernet interface, though the mechanism used is not ethernet-specific. If the interface is already up when this option is used, it will be briefly brought down and then brought back up again in order to ensure that the receive filter in the underlying ethernet hardware is properly reprogrammed. .It Ar address_family Specify the address family which affects interpretation of the remaining parameters. Since an interface can receive transmissions in differing protocols with different naming schemes, specifying the address family is recommended. The address or protocol families currently supported are .Dq inet , .Dq inet6 , .Dq atalk , .Dq ipx , .\" .Dq iso , and .Dq link . .\" and .\" .Dq ns . The default is .Dq inet . .Dq ether and .Dq lladdr are synonyms for .Dq link . .It Ar dest_address Specify the address of the correspondent on the other end of a point to point link. .It Ar interface This parameter is a string of the form .Dq name unit , for example, .Dq Li ed0 . .It Ar groupname List the interfaces in the given group. .El .Pp The following parameters may be set with .Nm : .Bl -tag -width indent .It Cm add Another name for the .Cm alias parameter. Introduced for compatibility with .Bsx . .It Cm alias Establish an additional network address for this interface. This is sometimes useful when changing network numbers, and one wishes to accept packets addressed to the old interface. If the address is on the same subnet as the first network address for this interface, a non-conflicting netmask must be given. Usually .Li 0xffffffff is most appropriate. .It Fl alias Remove the network address specified. This would be used if you incorrectly specified an alias, or it was no longer needed. If you have incorrectly set an NS address having the side effect of specifying the host portion, removing all NS addresses will allow you to respecify the host portion. .It Cm anycast (Inet6 only.) Specify that the address configured is an anycast address. Based on the current specification, only routers may configure anycast addresses. Anycast address will not be used as source address of any of outgoing IPv6 packets. .It Cm arp Enable the use of the Address Resolution Protocol .Pq Xr arp 4 in mapping between network level addresses and link level addresses (default). This is currently implemented for mapping between .Tn DARPA Internet addresses and .Tn IEEE 802 48-bit MAC addresses (Ethernet, FDDI, and Token Ring addresses). .It Fl arp Disable the use of the Address Resolution Protocol .Pq Xr arp 4 . .It Cm staticarp If the Address Resolution Protocol is enabled, the host will only reply to requests for its addresses, and will never send any requests. .It Fl staticarp If the Address Resolution Protocol is enabled, the host will perform normally, sending out requests and listening for replies. .It Cm broadcast (Inet only.) Specify the address to use to represent broadcasts to the network. The default broadcast address is the address with a host part of all 1's. .It Cm debug Enable driver dependent debugging code; usually, this turns on extra console error logging. .It Fl debug Disable driver dependent debugging code. .It Cm promisc Put interface into permanently promiscuous mode. .It Fl promisc Disable permanently promiscuous mode. .It Cm delete Another name for the .Fl alias parameter. .It Cm down Mark an interface .Dq down . When an interface is marked .Dq down , the system will not attempt to transmit messages through that interface. If possible, the interface will be reset to disable reception as well. This action does not automatically disable routes using the interface. .It Cm group Ar group-name Assign the interface to a .Dq group . Any interface can be in multiple groups. .Pp Cloned interfaces are members of their interface family group by default. For example, a PPP interface such as .Em ppp0 is a member of the PPP interface family group, .Em ppp . .\" The interface(s) the default route(s) point to are members of the .\" .Em egress .\" interface group. .It Cm -group Ar group-name Remove the interface from the given .Dq group . .It Cm eui64 (Inet6 only.) Fill interface index (lowermost 64bit of an IPv6 address) automatically. .It Cm ipdst This is used to specify an Internet host who is willing to receive IP packets encapsulating IPX packets bound for a remote network. An apparent point to point link is constructed, and the address specified will be taken as the IPX address and network of the destination. .It Cm maclabel Ar label If Mandatory Access Control support is enabled in the kernel, set the MAC label to .Ar label . .\" (see .\" .Xr maclabel 7 ) . .It Cm media Ar type If the driver supports the media selection system, set the media type of the interface to .Ar type . Some interfaces support the mutually exclusive use of one of several different physical media connectors. For example, a 10Mbit/s Ethernet interface might support the use of either .Tn AUI or twisted pair connectors. Setting the media type to .Cm 10base5/AUI would change the currently active connector to the AUI port. Setting it to .Cm 10baseT/UTP would activate twisted pair. Refer to the interfaces' driver specific documentation or man page for a complete list of the available types. .It Cm mediaopt Ar opts If the driver supports the media selection system, set the specified media options on the interface. The .Ar opts argument is a comma delimited list of options to apply to the interface. Refer to the interfaces' driver specific man page for a complete list of available options. .It Fl mediaopt Ar opts If the driver supports the media selection system, disable the specified media options on the interface. .It Cm mode Ar mode If the driver supports the media selection system, set the specified operating mode on the interface to .Ar mode . For IEEE 802.11 wireless interfaces that support multiple operating modes this directive is used to select between 802.11a .Pq Cm 11a , 802.11b .Pq Cm 11b , and 802.11g .Pq Cm 11g operating modes. .It Cm inst Ar minst , Cm instance Ar minst Set the media instance to .Ar minst . This is useful for devices which have multiple physical layer interfaces .Pq PHYs . .It Cm name Ar name Set the interface name to .Ar name . .It Cm rxcsum , txcsum If the driver supports user-configurable checksum offloading, enable receive (or transmit) checksum offloading on the interface. Some drivers may not be able to enable these flags independently of each other, so setting one may also set the other. The driver will offload as much checksum work as it can reliably support, the exact level of offloading varies between drivers. .It Fl rxcsum , txcsum If the driver supports user-configurable checksum offloading, disable receive (or transmit) checksum offloading on the interface. These settings may not always be independent of each other. .It Cm tso If the driver supports .Xr tcp 4 segmentation offloading, enable TSO on the interface. Some drivers may not be able to support TSO for .Xr ip 4 and .Xr ip6 4 packets, so they may enable only one of them. .It Fl tso If the driver supports .Xr tcp 4 segmentation offloading, disable TSO on the interface. It will always disable TSO for .Xr ip 4 and .Xr ip6 4 . .It Cm lro If the driver supports .Xr tcp 4 large receive offloading, enable LRO on the interface. .It Fl lro If the driver supports .Xr tcp 4 large receive offloading, disable LRO on the interface. .It Cm vlanmtu , vlanhwtag If the driver offers user-configurable VLAN support, enable reception of extended frames or tag processing in hardware, respectively. Note that this must be issued on a physical interface associated with .Xr vlan 4 , not on a .Xr vlan 4 interface itself. .It Fl vlanmtu , vlanhwtag If the driver offers user-configurable VLAN support, disable reception of extended frames or tag processing in hardware, respectively. .It Cm polling Turn on .Xr polling 4 feature and disable interrupts on the interface, if driver supports this mode. .It Fl polling Turn off .Xr polling 4 feature and enable interrupt mode on the interface. .It Cm create Create the specified network pseudo-device. If the interface is given without a unit number, try to create a new device with an arbitrary unit number. If creation of an arbitrary device is successful, the new device name is printed to standard output unless the interface is renamed or destroyed in the same .Nm invocation. .It Cm destroy Destroy the specified network pseudo-device. .It Cm plumb Another name for the .Cm create parameter. Included for .Tn Solaris compatibility. .It Cm unplumb Another name for the .Cm destroy parameter. Included for .Tn Solaris compatibility. .It Cm metric Ar n Set the routing metric of the interface to .Ar n , default 0. The routing metric is used by the routing protocol .Pq Xr routed 8 . Higher metrics have the effect of making a route less favorable; metrics are counted as additional hops to the destination network or host. .It Cm mtu Ar n Set the maximum transmission unit of the interface to .Ar n , default is interface specific. The MTU is used to limit the size of packets that are transmitted on an interface. Not all interfaces support setting the MTU, and some interfaces have range restrictions. .It Cm netmask Ar mask .\" (Inet and ISO.) (Inet only.) Specify how much of the address to reserve for subdividing networks into sub-networks. The mask includes the network part of the local address and the subnet part, which is taken from the host field of the address. The mask can be specified as a single hexadecimal number with a leading .Ql 0x , with a dot-notation Internet address, or with a pseudo-network name listed in the network table .Xr networks 5 . The mask contains 1's for the bit positions in the 32-bit address which are to be used for the network and subnet parts, and 0's for the host part. The mask should contain at least the standard network portion, and the subnet field should be contiguous with the network portion. .Pp The netmask can also be specified in CIDR notation after the address. See the .Ar address option above for more information. .It Cm prefixlen Ar len (Inet6 only.) Specify that .Ar len bits are reserved for subdividing networks into sub-networks. The .Ar len must be integer, and for syntactical reason it must be between 0 to 128. It is almost always 64 under the current IPv6 assignment rule. If the parameter is omitted, 64 is used. .Pp The prefix can also be specified using the slash notation after the address. See the .Ar address option above for more information. .\" see .\" Xr eon 5 . .\" .It Cm nsellength Ar n .\" .Pf ( Tn ISO .\" only) .\" This specifies a trailing number of bytes for a received .\" .Tn NSAP .\" used for local identification, the remaining leading part of which is .\" taken to be the .\" .Tn NET .\" (Network Entity Title). .\" The default value is 1, which is conformant to US .\" .Tn GOSIP . .\" When an ISO address is set in an ifconfig command, .\" it is really the .\" .Tn NSAP .\" which is being specified. .\" For example, in .\" .Tn US GOSIP , .\" 20 hex digits should be .\" specified in the .\" .Tn ISO NSAP .\" to be assigned to the interface. .\" There is some evidence that a number different from 1 may be useful .\" for .\" .Tn AFI .\" 37 type addresses. .It Cm range Ar netrange Under appletalk, set the interface to respond to a .Ar netrange of the form .Ar startnet Ns - Ns Ar endnet . Appletalk uses this scheme instead of netmasks though .Fx implements it internally as a set of netmasks. .It Cm remove Another name for the .Fl alias parameter. Introduced for compatibility with .Bsx . .It Cm phase The argument following this specifies the version (phase) of the Appletalk network attached to the interface. Values of 1 or 2 are permitted. .Sm off .It Cm link Op Cm 0 No - Cm 2 .Sm on Enable special processing of the link level of the interface. These three options are interface specific in actual effect, however, they are in general used to select special modes of operation. An example of this is to enable SLIP compression, or to select the connector type for some Ethernet cards. Refer to the man page for the specific driver for more information. .Sm off .It Fl link Op Cm 0 No - Cm 2 .Sm on Disable special processing at the link level with the specified interface. .It Cm monitor Put the interface in monitor mode. No packets are transmitted, and received packets are discarded after .Xr bpf 4 processing. .It Fl monitor Take the interface out of monitor mode. .It Cm up Mark an interface .Dq up . This may be used to enable an interface after an .Dq Nm Cm down . It happens automatically when setting the first address on an interface. If the interface was reset when previously marked down, the hardware will be re-initialized. .El .Pp The following parameters are specific to IEEE 802.11 wireless interfaces: .Bl -tag -width indent .It Cm apbridge When operating as an access point, pass packets between wireless clients directly (default). To instead let them pass up through the system and be forwarded using some other mechanism, use .Fl apbridge . Disabling the internal bridging is useful when traffic is to be processed with packet filtering. .It Cm authmode Ar mode Set the desired authentication mode in infrastructure mode. Not all adaptors support all modes. The set of valid modes is .Cm none , open , shared (shared key), .Cm 8021x (IEEE 802.1x), and .Cm wpa (IEEE WPA/WPA2/802.11i). The .Cm 8021x and .Cm wpa modes are only useful when using an authentication service (a supplicant for client operation or an authenticator when operating as an access point). Modes are case insensitive. .It Cm bgscan Enable background scanning when operating as a station. Background scanning is a technique whereby a station associated to an access point will temporarily leave the channel to scan for neighboring stations. This allows a station to maintain a cache of nearby access points so that roaming between access points can be done without a lengthy scan operation. Background scanning is done only when a station is not busy and any outbound traffic will cancel a scan operation. Background scanning should never cause packets to be lost though there may be some small latency if outbound traffic interrupts a scan operation. By default background scanning is enabled if the device is capable. To disable background scanning, use .Fl bgscan . Background scanning is controlled by the .Cm bgscanidle and .Cm bgscanintvl parameters. Background scanning must be enabled for roaming; this is an artifact of the current implementation and may not be required in the future. .It Cm bgscanidle Ar idletime Set the minimum time a station must be idle (not transmitting or receiving frames) before a background scan is initiated. The .Ar idletime parameter is specified in milliseconds. By default a station must be idle at least 250 milliseconds before a background scan is initiated. The idle time may not be set to less than 100 milliseconds. .It Cm bgscanintvl Ar interval Set the interval at which background scanning is attempted. The .Ar interval parameter is specified in seconds. By default a background scan is considered every 300 seconds (5 minutes). The .Ar interval may not be set to less than 15 seconds. .It Cm bintval Ar interval Set the interval at which beacon frames are sent when operating in ad-hoc or ap mode. The .Ar interval parameter is specified in TU's (1024 usecs). By default beacon frames are transmitted every 100 TU's. .It Cm bmissthreshold Ar count Set the number of consecutive missed beacons at which the station will attempt to roam (i.e., search for a new access point). The .Ar count parameter must be in the range 1 to 255; though the upper bound may be reduced according to device capabilities. The default threshold is 7 consecutive missed beacons; but this may be overridden by the device driver. Another name for the .Cm bmissthreshold parameter is .Cm bmiss . .It Cm bssid Ar address Specify the MAC address of the access point to use when operating as a station in a BSS network. This overrides any automatic selection done by the system. To disable a previously selected access point, supply .Cm any , none , or .Cm - for the address. This option is useful when more than one access point uses the same SSID. Another name for the .Cm bssid parameter is .Cm ap . .It Cm burst Enable packet bursting. Packet bursting is a transmission technique whereby the wireless medium is acquired once to send multiple frames and the interframe spacing is reduced. This technique can significantly increase throughput by reducing transmission overhead. Packet bursting is supported by the 802.11e QoS specification and some devices that do not support QoS may still be capable. By default packet bursting is enabled if a device is capable of doing it. To disable packet bursting, use .Fl burst . .It Cm chanlist Ar channels Set the desired channels to use when scanning for access points, neighbors in an IBSS network, or looking for unoccupied channels when operating as an access point. The set of channels is specified as a comma-separated list with each element in the list representing either a single channel number or a range of the form .Dq Li a-b . Channel numbers must be in the range 1 to 255 and be permissible according to the operating characteristics of the device. .It Cm channel Ar number Set a single desired channel. Channels range from 1 to 255, but the exact selection available depends on the region your adaptor was manufactured for. Setting the channel to .Li 0 , .Cm any , or .Cm - will give you the default for your adaptor. Some adaptors ignore this setting unless you are in ad-hoc mode. Alternatively the frequency, in megahertz, may be specified instead of the channel number. .Pp When there are several ways to use a channel the channel number/frequency may be appended with attributes to clarify. For example, if a device is capable of operating on channel 6 with 802.11n and 802.11g then one can specify that g-only use should be used by specifying ``6:g''. Similarly the channel width can be specified by appending it with ``/''; e.g. ``6/40'' specifies a 40MHz wide channel, These attributes can be combined as in: ``6:ht/40''. The full set of flags specified following a `:'' are: .Cm a (802.11a), .Cm b (802.11b), .Cm d (Atheros Dynamic Turbo mode), .Cm g (802.11g), .Cm h or .Cm n (802.11n aka HT), .Cm s (Atheros Static Turbo mode), and .Cm t (Atheros Dynamic Turbo mode, or appended to ``st'' and ``dt''). The full set of channel widths following a '/' are: .Cm 5 (5MHz aka quarter-rate channel), .Cm 10 (10MHz aka half-rate channel), .Cm 20 (20MHz mostly for use in specifying ht20), and .Cm 40 (40MHz mostly for use in specifying ht40), In addition, a 40MHz HT channel specification may include the location of the extension channel by appending ``+'' or ``-'' for above and below, respectively; e.g. ``2437:ht/40+'' specifies 40MHz wide HT operation with the center channel at frequency 2437 and the extension channel above. .It Cm doth Enable inclusion of an 802.11h country information element in beacon frames transmitted when operating as an access point. By default 802.11h is enabled if the device is capable. To disable 802.11h use .Fl doth . .It Cm deftxkey Ar index Set the default key to use for transmission. Typically this is only set when using WEP encryption. The .Cm weptxkey is an alias for this request; it is provided for backwards compatibility. .It Cm dtimperiod Ar period Set the DTIM period for transmitting buffered multicast data frames when operating in ap mode. The .Ar period specifies the number of beacon intervals between DTIM and must be in the range 1 to 15. By default DTIM is 1 (i.e., DTIM occurs at each beacon). .It Cm dturbo Enable the use of Atheros Dynamic Turbo mode when communicating with another Dynamic Turbo-capable station. Dynamic Turbo mode is an Atheros-specific mechanism by which stations switch between normal 802.11 operation and a ``boosted'' mode in which a 40MHz wide channel is used for communication. Stations using Dynamic Turbo mode operate boosted only when the channel is free of non-dturbo stations; when a non-dturbo station is identified on the channel all stations will automatically drop back to normal operation. By default, Dynamic Turbo mode is not enabled, even if the device is capable. Note that turbo mode (dynamic or static) is only allowed on some channels depending on the regulatory constraints; use the .Cm list chan command to identify the channels where turbo mode may be used. To disable Dynamic Turbo mode use .Fl dturbo . .It Cm fragthreshold Ar length Set the threshold for which transmitted frames are broken into fragments. The .Ar length argument is the frame size in bytes and must be in the range 256 to 2346. Setting .Ar length to .Li 2346 , .Cm any , or .Cm - disables transmit fragmentation. Not all adaptors honor the fragmentation threshold. .It Cm hidessid When operating as an access point, do not broadcast the SSID in beacon frames or respond to probe request frames unless they are directed to the ap (i.e., they include the ap's SSID). By default, the SSID is included in beacon frames and undirected probe request frames are answered. To re-enable the broadcast of the SSID etc., use .Fl hidessid . .It Cm ff Enable the use of Atheros Fast Frames when communicating with another Fast Frames-capable station. Fast Frames are an encapsulation technique by which two 802.3 frames are transmitted in a single 802.11 frame. This can noticeably improve throughput but requires that the receiving station understand how to decapsulate the frame. Fast frame use is negotiated using the Atheros 802.11 vendor-specific protocol extension so enabling use is safe when communicating with non-Atheros devices. By default, use of fast frames is enabled if the device is capable. To explicitly disable fast frames, use .Fl ff . .It Cm list active Display the list of channels available for use taking into account any restrictions set with the .Cm chanlist directive. See the description of .Cm list chan for more information. .It Cm list caps Display the adaptor's capabilities, including the operating modes supported. .It Cm list chan Display the list of channels available for use. Channels are shown with their IEEE channel number, equivalent frequency, and usage modes. Channels identified as .Ql 11g are also usable in .Ql 11b mode. Channels identified as .Ql 11a Turbo may be used only for Atheros' Static Turbo mode (specified with . Cm mediaopt turbo ) . Channels marked with a .Ql * have a regulatory constraint that they be passively scanned. This means a station is not permitted to transmit on the channel until it identifies the channel is being used for 802.11 communication; typically by hearing a beacon frame from an access point operating on the channel. .Cm list freq is another way of requesting this information. By default a compacted list of channels is displayed; if the .Fl v option is specified then all channels are shown. .It Cm list mac Display the current MAC Access Control List state. Each address is prefixed with a character that indicates the current policy applied to it: .Ql + indicates the address is allowed access, .Ql - indicates the address is denied access, .Ql * indicates the address is present but the current policy open (so the ACL is not consulted). .It Cm list scan Display the access points and/or ad-hoc neighbors located in the vicinity. The .Fl v flag may be used to display long SSIDs. .Fl v also causes received information elements to be displayed symbolicaly. This information may be updated automatically by the adaptor and/or with a .Cm scan request or through background scanning. .Cm list ap is another way of requesting this information. .It Cm list sta When operating as an access point display the stations that are currently associated. When operating in ad-hoc mode display stations identified as neighbors in the IBSS. When operating in station mode display the access point. Capabilities advertised by the stations are described under the .Cm scan request. Depending on the capabilities of the stations the following flags can be included in the output: .Bl -tag -width 3n .It Li A Authorized. Indicates that the station is permitted to send/receive data frames. .It Li E Extended Rate Phy (ERP). Indicates that the station is operating in an 802.11g network using extended transmit rates. .It Li H High Throughput (HT). Indicates that the station is using MCS to send/receive frames. .It Li P Power Save. Indicates that the station is operating in power save mode. .It Li Q Quality of Service (QoS). Indicates that the station is using QoS encapsulation for data frame. QoS encapsulation is enabled only when WME mode is enabled. .El .Pp By default information elements received from associated stations are displayed in a short form; the .Fl v flag causes this information to be displayed symbolicaly. .It Cm list wme Display the current parameters to use when operating in WME mode. When WME mode is enabled for an adaptor this information will be displayed with the regular status; this command is mostly useful for examining parameters when WME mode is disabled. See the description of the .Cm wme directive for information on the various parameters. .It Cm mcastrate Ar rate Set the rate for transmitting multicast/broadcast frames. Rates are specified as megabits/second in decimal; e.g.\& 5.5 for 5.5 Mb/s. This rate should be valid for the current operating conditions; if an invalid rate is specified drivers are free to chose an appropriate rate. .It Cm powersave Enable powersave operation. When operating as a client, the station will conserve power by periodically turning off the radio and listening for messages from the access point telling it there are packets waiting. The station must then retrieve the packets. Not all devices support power save operation as a client. The 802.11 specification requires that all access points support power save but some drivers do not. Use .Fl powersave to disable powersave operation when operating as a client. .It Cm powersavesleep Ar sleep Set the desired max powersave sleep time in TU's (1024 usecs). By default the max powersave sleep time is 100 TU's. .It Cm protmode Ar technique For interfaces operating in 802.11g, use the specified .Ar technique for protecting OFDM frames in a mixed 11b/11g network. The set of valid techniques is .Cm off , cts (CTS to self), and .Cm rtscts (RTS/CTS). Technique names are case insensitive. Not all devices support .Cm cts as a protection technique. .It Cm pureg When operating as an access point in 802.11g mode allow only 11g-capable stations to associate (11b-only stations are not permitted to associate). To allow both 11g and 11b-only stations to associate, use .Fl pureg . .It Cm roaming Ar mode When operating as a station, control how the system will behave when communication with the current access point is broken. The .Ar mode argument may be one of .Cm device (leave it to the hardware device to decide), .Cm auto (handle either in the device or the operating system\[em]as appropriate), .Cm manual (do nothing until explicitly instructed). By default, the device is left to handle this if it is capable; otherwise, the operating system will automatically attempt to reestablish communication. Manual mode is used by applications such as .Xr wpa_supplicant 8 that want to control the selection of an access point. .It Cm roam:rssi11a Ar rssi Set the threshold for controlling roaming when operating in an 802.11a BSS. The .Ar rssi parameter specifies the receive signal strength in dBm units at which roaming should be considered. If the current rssi drops below this setting and background scanning is enabled, then the system will check if a more desirable access point is available and switch over to it. The current scan cache contents are used if they are considered valid according to the .Cm scanvalid parameter; otherwise a background scan operation is triggered before any selection occurs. By default .Ar rssi is set to 7 dBm. .It Cm roam:rssi11b Ar rssi Set the threshold for controlling roaming when operating in an 802.11b-only BSS. See .Cm roam:rssi11a for a description of this parameter. By default .Ar rssi is set to 7 dBm. .It Cm roam:rssi11g Ar rssi Set the threshold for controlling roaming when operating in a (mixed) 802.11g BSS. See .Cm roam:rssi11a for a description of this parameter. By default .Ar rssi is set to 7 dBm. .It Cm roam:rate11a Ar rate Set the threshold for controlling roaming when operating in an 802.11a BSS. The .Ar rate parameter specifies the transmit rate in megabits at which roaming should be considered. If the current transmit rate drops below this setting and background scanning is enabled, then the system will check if a more desirable access point is available and switch over to it. The current scan cache contents are used if they are considered valid according to the .Cm scanvalid parameter; otherwise a background scan operation is triggered before any selection occurs. By default .Ar rate is set to 12 Mb/s. .It Cm roam:rate11b Ar rate Set the threshold for controlling roaming when operating in an 802.11b-only BSS. See .Cm roam:rate11a for a description of this parameter. By default .Ar rate is set to 1 Mb/s. .It Cm roam:rate11g Ar rate Set the threshold for controlling roaming when operating in a (mixed) 802.11g BSS. See .Cm roam:rate11a for a description of this parameter. By default .Ar rate is set to 5 Mb/s. .It Cm rtsthreshold Ar length Set the threshold for which transmitted frames are preceded by transmission of an RTS control frame. The .Ar length argument is the frame size in bytes and must be in the range 1 to 2346. Setting .Ar length to .Li 2346 , .Cm any , or .Cm - disables transmission of RTS frames. Not all adaptors support setting the RTS threshold. .It Cm ssid Ar ssid Set the desired Service Set Identifier (aka network name). The SSID is a string up to 32 characters in length and may be specified as either a normal string or in hexadecimal when preceded by .Ql 0x . Additionally, the SSID may be cleared by setting it to .Ql - . .It Cm scan Initiate a scan of neighboring stations, wait for it to complete, and display all stations found. Only the super-user can initiate a scan. Depending on the capabilities of the APs, the following flags can be included in the output: .Bl -tag -width 3n .It Li A Channel Agility. Indicates that the station support channel hopping as described by the IEEE 802.11b specification. .It Li B Packet Binary Convolution Code (PBCC). A modulation alternative to the standard OFDM method. .It Dv C Pollreq .It Dv c Pollable .It Dv D Direct Sequence Spread Spectrum (DSSSOFDM). Indicates the the station supports DSSS modulation. .It Li E Extended Service Set (ESS). Indicates that the station is part of an infrastructure network (in contrast to an IBSS/ad-hoc network). .It Li I IBSS/ad-hoc network. Indicates that the station is part of an ad-hoc network (in contrast to an ESS network). .It Li P Privacy. Data confidentiality is required for all data frames exchanged within the BSS. This means that this BSS requires the station to use cryptographic means such as WEP, TKIP or AES-CCMP to encrypt/decrypt data frames being exchanged with others. .It Dv R Robust Security Network (RSN). Indicates that the station supports the IEEE 802.11i authentication and key management protocol. .It Li S Short Preamble. Indicates that the network is using short preambles (defined in 802.11b High Rate/DSSS PHY, short preamble utilizes a 56 bit sync field in contrast to a 128 bit field used in long preamble mode). .It Li s Short slot time. Indicates that the network is using a short slot time. .El .Pp Interesting information elements captured from the neighboring stations are displayed at the end of each row. Possible elements are: .Cm WME (station supports WME), .Cm WPA (station supports WPA), .Cm RSN (station supports 802.11i/RSN), .Cm HT (station supports 802.11n/HT communication), .Cm ATH (station supoprts Atheros protocol extensions), .Cm VEN (station supports unknown vendor-specific extensions). If the .Fl v flag is used the information element contents will be shown. .Pp The .Cm list scan request can be used to show recent scan results without initiating a new scan. .Pp The .Fl v flag may be used to prevent the shortening of long SSIDs. .It Cm scanvalid Ar threshold Set the maximum time the scan cache contents are considered valid; i.e. will be used without first triggering a scan operation to refresh the data. The .Ar threshold parameter is specified in seconds and defaults to 60 seconds. The minimum setting for .Ar threshold is 10 seconds. One should take care setting this threshold; if it is set too low then attempts to roam to another access point may trigger unnecessary background scan operations. .It Cm stationname Ar name Set the name of this station. The station name is not part of the IEEE 802.11 protocol though some interfaces support it. As such it only seems to be meaningful to identical or virtually identical equipment. Setting the station name is identical in syntax to setting the SSID. .It Cm txpower Ar power Set the power used to transmit frames. The .Ar power argument is specified in .5 dBm units. Out of range values are truncated. Typically only a few discreet power settings are available and the driver will use the setting closest to the specified value. Not all adaptors support changing the transmit power. .It Cm wepmode Ar mode Set the desired WEP mode. Not all adaptors support all modes. The set of valid modes is .Cm off , on , and .Cm mixed . The .Cm mixed mode explicitly tells the adaptor to allow association with access points which allow both encrypted and unencrypted traffic. On these adaptors, .Cm on means that the access point must only allow encrypted connections. On other adaptors, .Cm on is generally another name for .Cm mixed . Modes are case insensitive. .It Cm weptxkey Ar index Set the WEP key to be used for transmission. This is the same as setting the default transmission key with .Cm deftxkey . .It Cm wepkey Ar key Ns | Ns Ar index : Ns Ar key Set the selected WEP key. If an .Ar index is not given, key 1 is set. A WEP key will be either 5 or 13 characters (40 or 104 bits) depending of the local network and the capabilities of the adaptor. It may be specified either as a plain string or as a string of hexadecimal digits preceded by .Ql 0x . For maximum portability, hex keys are recommended; the mapping of text keys to WEP encryption is usually driver-specific. In particular, the .Tn Windows drivers do this mapping differently to .Fx . A key may be cleared by setting it to .Ql - . If WEP is supported then there are at least four keys. Some adaptors support more than four keys. If that is the case, then the first four keys (1-4) will be the standard temporary keys and any others will be adaptor specific keys such as permanent keys stored in NVRAM. .It Cm wme Enable Wireless Multimedia Extensions (WME) support, if available, for the specified interface. WME is a subset of the IEEE 802.11e standard to support the efficient communication of realtime and multimedia data. To disable WME support, use .Fl wme . .Pp The following parameters are meaningful only when WME support is in use. Parameters are specified per-AC (Access Category) and split into those that are used by a station when acting as an access point and those for client stations in the BSS. The latter are received from the access point and may not be changed (at the station). The following Access Categories are recognized: .Pp .Bl -tag -width ".Cm AC_BK" -compact .It Cm AC_BE (or .Cm BE ) best effort delivery, .It Cm AC_BK (or .Cm BK ) background traffic, .It Cm AC_VI (or .Cm VI ) video traffic, .It Cm AC_VO (or .Cm VO ) voice traffic. .El .Pp AC parameters are case-insensitive. Traffic classification is done in the operating system using the vlan priority associated with data frames or the ToS (Type of Service) indication in IP-encapsulated frames. If neither information is present, traffic is assigned to the Best Effort (BE) category. .Bl -tag -width indent .It Cm ack Ar ac Set the ACK policy for QoS transmissions by the local station; this controls whether or not data frames transmitted by a station require an ACK response from the receiving station. To disable waiting for an ACK use .Fl ack . This parameter is applied only to the local station. .It Cm acm Ar ac Enable the Admission Control Mandatory (ACM) mechanism for transmissions by the local station. To disable the ACM use .Fl acm . On stations in a BSS this parameter is read-only and indicates the setting received from the access point. NB: ACM is not supported right now. .It Cm aifs Ar ac Ar count Set the Arbitration Inter Frame Spacing (AIFS) channel access parameter to use for transmissions by the local station. On stations in a BSS this parameter is read-only and indicates the setting received from the access point. .It Cm cwmin Ar ac Ar count Set the CWmin channel access parameter to use for transmissions by the local station. On stations in a BSS this parameter is read-only and indicates the setting received from the access point. .It Cm cwmax Ar ac Ar count Set the CWmax channel access parameter to use for transmissions by the local station. On stations in a BSS this parameter is read-only and indicates the setting received from the access point. .It Cm txoplimit Ar ac Ar limit Set the Transmission Opportunity Limit channel access parameter to use for transmissions by the local station. This parameter defines an interval of time when a WME station has the right to initiate transmissions onto the wireless medium. On stations in a BSS this parameter is read-only and indicates the setting received from the access point. .It Cm bss:aifs Ar ac Ar count Set the AIFS channel access parameter to send to stations in a BSS. This parameter is meaningful only when operating in ap mode. .It Cm bss:cwmin Ar ac Ar count Set the CWmin channel access parameter to send to stations in a BSS. This parameter is meaningful only when operating in ap mode. .It Cm bss:cwmax Ar ac Ar count Set the CWmax channel access parameter to send to stations in a BSS. This parameter is meaningful only when operating in ap mode. .It Cm bss:txoplimit Ar ac Ar limit Set the TxOpLimit channel access parameter to send to stations in a BSS. This parameter is meaningful only when operating in ap mode. .El .El .Pp The following parameters support an optional access control list feature available with some adaptors when operating in ap mode; see .Xr wlan_acl 4 . This facility allows an access point to accept/deny association requests based on the MAC address of the station. Note that this feature does not significantly enhance security as MAC address spoofing is easy to do. .Bl -tag -width indent .It Cm mac:add Ar address Add the specified MAC address to the database. Depending on the policy setting association requests from the specified station will be allowed or denied. .It Cm mac:allow Set the ACL policy to permit association only by stations registered in the database. .It Cm mac:del Ar address Delete the specified MAC address from the database. .It Cm mac:deny Set the ACL policy to deny association only by stations registered in the database. .It Cm mac:kick Ar address Force the specified station to be deauthenticated. This typically is done to block a station after updating the address database. .It Cm mac:open Set the ACL policy to allow all stations to associate. .It Cm mac:flush Delete all entries in the database. .El .Pp The following parameters are for compatibility with other systems: .Bl -tag -width indent .It Cm nwid Ar ssid Another name for the .Cm ssid parameter. Included for .Nx compatibility. .It Cm station Ar name Another name for the .Cm stationname parameter. Included for .Bsx compatibility. .It Cm wep Another way of saying .Cm wepmode on . Included for .Bsx compatibility. .It Fl wep Another way of saying .Cm wepmode off . Included for .Bsx compatibility. .It Cm nwkey key Another way of saying: .Dq Li "wepmode on weptxkey 1 wepkey 1:key wepkey 2:- wepkey 3:- wepkey 4:-" . Included for .Nx compatibility. .It Cm nwkey Xo .Sm off .Ar n : k1 , k2 , k3 , k4 .Sm on .Xc Another way of saying .Dq Li "wepmode on weptxkey n wepkey 1:k1 wepkey 2:k2 wepkey 3:k3 wepkey 4:k4" . Included for .Nx compatibility. .It Fl nwkey Another way of saying .Cm wepmode off . Included for .Nx compatibility. .El .Pp The following parameters are specific to bridge interfaces: .Bl -tag -width indent .It Cm addm Ar interface Add the interface named by .Ar interface as a member of the bridge. The interface is put into promiscuous mode so that it can receive every packet sent on the network. .It Cm deletem Ar interface Remove the interface named by .Ar interface from the bridge. Promiscuous mode is disabled on the interface when it is removed from the bridge. .It Cm maxaddr Ar size Set the size of the bridge address cache to .Ar size . The default is 100 entries. .It Cm timeout Ar seconds Set the timeout of address cache entries to .Ar seconds seconds. If .Ar seconds is zero, then address cache entries will not be expired. The default is 240 seconds. .It Cm addr Display the addresses that have been learned by the bridge. .It Cm static Ar interface-name Ar address Add a static entry into the address cache pointing to .Ar interface-name . Static entries are never aged out of the cache or re-placed, even if the address is seen on a different interface. .It Cm deladdr Ar address Delete .Ar address from the address cache. .It Cm flush Delete all dynamically-learned addresses from the address cache. .It Cm flushall Delete all addresses, including static addresses, from the address cache. .It Cm discover Ar interface Mark an interface as a .Dq discovering interface. When the bridge has no address cache entry (either dynamic or static) for the destination address of a packet, the bridge will forward the packet to all member interfaces marked as .Dq discovering . This is the default for all interfaces added to a bridge. .It Cm -discover Ar interface Clear the .Dq discovering attribute on a member interface. For packets without the .Dq discovering attribute, the only packets forwarded on the interface are broadcast or multicast packets and packets for which the destination address is known to be on the interface's segment. .It Cm learn Ar interface Mark an interface as a .Dq learning interface. When a packet arrives on such an interface, the source address of the packet is entered into the address cache as being a destination address on the interface's segment. This is the default for all interfaces added to a bridge. .It Cm -learn Ar interface Clear the .Dq learning attribute on a member interface. .It Cm sticky Ar interface Mark an interface as a .Dq sticky interface. Dynamically learned address entries are treated at static once entered into the cache. Sticky entries are never aged out of the cache or replaced, even if the address is seen on a different interface. .It Cm -sticky Ar interface Clear the .Dq sticky attribute on a member interface. .It Cm private Ar interface Mark an interface as a .Dq private interface. A private interface does not forward any traffic to any other port that is also a private interface. .It Cm -private Ar interface Clear the .Dq private attribute on a member interface. .It Cm span Ar interface Add the interface named by .Ar interface as a span port on the bridge. Span ports transmit a copy of every frame received by the bridge. This is most useful for snooping a bridged network passively on another host connected to one of the span ports of the bridge. .It Cm -span Ar interface Delete the interface named by .Ar interface from the list of span ports of the bridge. .It Cm stp Ar interface Enable Spanning Tree protocol on .Ar interface . The .Xr if_bridge 4 driver has support for the IEEE 802.1D Spanning Tree protocol (STP). Spanning Tree is used to detect and remove loops in a network topology. .It Cm -stp Ar interface Disable Spanning Tree protocol on .Ar interface . This is the default for all interfaces added to a bridge. .It Cm edge Ar interface Set .Ar interface as an edge port. An edge port connects directly to end stations cannot create bridging loops in the network, this allows it to transition straight to forwarding. .It Cm -edge Ar interface Disable edge status on .Ar interface . .It Cm autoedge Ar interface Allow .Ar interface to automatically detect edge status. This is the default for all interfaces added to a bridge. .It Cm -autoedge Ar interface Disable automatic edge status on .Ar interface . .It Cm ptp Ar interface Set the .Ar interface as a point to point link. This is required for straight transitions to forwarding and should be enabled on a direct link to another RSTP capable switch. .It Cm -ptp Ar interface Disable point to point link status on .Ar interface . This should be disabled for a half duplex link and for an interface connected to a shared network segment, like a hub or a wireless network. .It Cm autoptp Ar interface Automatically detect the point to point status on .Ar interface by checking the full duplex link status. This is the default for interfaces added to the bridge. .It Cm -autoptp Ar interface Disable automatic point to point link detection on .Ar interface . .It Cm maxage Ar seconds Set the time that a Spanning Tree protocol configuration is valid. The default is 20 seconds. The minimum is 6 seconds and the maximum is 40 seconds. .It Cm fwddelay Ar seconds Set the time that must pass before an interface begins forwarding packets when Spanning Tree is enabled. The default is 15 seconds. The minimum is 4 seconds and the maximum is 30 seconds. .It Cm hellotime Ar seconds Set the time between broadcasting of Spanning Tree protocol configuration messages. The hello time may only be changed when operating in legacy stp mode. The default is 2 seconds. The minimum is 1 second and the maximum is 2 seconds. .It Cm priority Ar value Set the bridge priority for Spanning Tree. The default is 32768. The minimum is 0 and the maximum is 61440. .It Cm proto Ar value Set the Spanning Tree protocol. The default is rstp. The available options are stp and rstp. .It Cm holdcnt Ar value Set the transmit hold count for Spanning Tree. This is the number of packets transmitted before being rate limited. The default is 6. The minimum is 1 and the maximum is 10. .It Cm ifpriority Ar interface Ar value Set the Spanning Tree priority of .Ar interface to .Ar value . The default is 128. The minimum is 0 and the maximum is 240. .It Cm ifpathcost Ar interface Ar value Set the Spanning Tree path cost of .Ar interface to .Ar value . The default is calculated from the link speed. To change a previously selected path cost back to automatic, set the cost to 0. The minimum is 1 and the maximum is 200000000. +.It Cm ifmaxaddr Ar interface Ar size +Set the maximum number of hosts allowed from an interface, packets with unknown +source addresses are dropped until an existing host cache entry expires or is +removed. +Set to 0 to disable. .El .Pp The following parameters are specific to lagg interfaces: .Bl -tag -width indent .It Cm laggport Ar interface Add the interface named by .Ar interface as a port of the aggregation interface. .It Cm -laggport Ar interface Remove the interface named by .Ar interface from the aggregation interface. .It Cm laggproto Ar proto Set the aggregation protocol. The default is failover. The available options are failover, fec, lacp, loadbalance, roundrobin and none. .El .Pp The following parameters are specific to IP tunnel interfaces, .Xr gif 4 : .Bl -tag -width indent .It Cm tunnel Ar src_addr dest_addr Configure the physical source and destination address for IP tunnel interfaces. The arguments .Ar src_addr and .Ar dest_addr are interpreted as the outer source/destination for the encapsulating IPv4/IPv6 header. .It Fl tunnel Unconfigure the physical source and destination address for IP tunnel interfaces previously configured with .Cm tunnel . .It Cm deletetunnel Another name for the .Fl tunnel parameter. .El .Pp The following parameters are specific to .Xr pfsync 4 interfaces: .Bl -tag -width indent .It Cm maxupd Ar n Set the maximum number of updates for a single state which can be collapsed into one. This is an 8-bit number; the default value is 128. .El .Pp The following parameters are specific to .Xr vlan 4 interfaces: .Bl -tag -width indent .It Cm vlan Ar vlan_tag Set the VLAN tag value to .Ar vlan_tag . This value is a 16-bit number which is used to create an 802.1Q VLAN header for packets sent from the .Xr vlan 4 interface. Note that .Cm vlan and .Cm vlandev must both be set at the same time. .It Cm vlandev Ar iface Associate the physical interface .Ar iface with a .Xr vlan 4 interface. Packets transmitted through the .Xr vlan 4 interface will be diverted to the specified physical interface .Ar iface with 802.1Q VLAN encapsulation. Packets with 802.1Q encapsulation received by the parent interface with the correct VLAN tag will be diverted to the associated .Xr vlan 4 pseudo-interface. The .Xr vlan 4 interface is assigned a copy of the parent interface's flags and the parent's ethernet address. The .Cm vlandev and .Cm vlan must both be set at the same time. If the .Xr vlan 4 interface already has a physical interface associated with it, this command will fail. To change the association to another physical interface, the existing association must be cleared first. .Pp Note: if the hardware tagging capability is set on the parent interface, the .Xr vlan 4 pseudo interface's behavior changes: the .Xr vlan 4 interface recognizes that the parent interface supports insertion and extraction of VLAN tags on its own (usually in firmware) and that it should pass packets to and from the parent unaltered. .It Fl vlandev Op Ar iface If the driver is a .Xr vlan 4 pseudo device, disassociate the parent interface from it. This breaks the link between the .Xr vlan 4 interface and its parent, clears its VLAN tag, flags and its link address and shuts the interface down. The .Ar iface argument is useless and hence deprecated. .El .Pp The following parameters are specific to .Xr carp 4 interfaces: .Bl -tag -width indent .It Cm advbase Ar seconds Specifies the base of the advertisement interval in seconds. The acceptable values are 1 to 255. The default value is 1. .\" The default value is .\" .Dv CARP_DFLTINTV . .It Cm advskew Ar interval Specifies the skew to add to the base advertisement interval to make one host advertise slower than another host. It is specified in 1/256 of seconds. The acceptable values are 1 to 254. The default value is 0. .It Cm pass Ar phrase Set the authentication key to .Ar phrase . .It Cm vhid Ar n Set the virtual host ID. This is a required setting. Acceptable values are 1 to 255. .El .Pp The .Nm utility displays the current configuration for a network interface when no optional parameters are supplied. If a protocol family is specified, .Nm will report only the details specific to that protocol family. .Pp If the .Fl m flag is passed before an interface name, .Nm will display the capability list and all of the supported media for the specified interface. If .Fl L flag is supplied, address lifetime is displayed for IPv6 addresses, as time offset string. .Pp Optionally, the .Fl a flag may be used instead of an interface name. This flag instructs .Nm to display information about all interfaces in the system. The .Fl d flag limits this to interfaces that are down, and .Fl u limits this to interfaces that are up. When no arguments are given, .Fl a is implied. .Pp The .Fl l flag may be used to list all available interfaces on the system, with no other additional information. Use of this flag is mutually exclusive with all other flags and commands, except for .Fl d (only list interfaces that are down) and .Fl u (only list interfaces that are up). .Pp The .Fl v flag may be used to get more verbose status for an interface. .Pp The .Fl C flag may be used to list all of the interface cloners available on the system, with no additional information. Use of this flag is mutually exclusive with all other flags and commands. .Pp The .Fl k flag causes keying information for the interface, if available, to be printed. For example, the values of 802.11 WEP keys will be printed, if accessible to the current user. This information is not printed by default, as it may be considered sensitive. .Pp If the network interface driver is not present in the kernel then .Nm will attempt to load it. The .Fl n flag disables this behavior. .Pp Only the super-user may modify the configuration of a network interface. .Sh NOTES The media selection system is relatively new and only some drivers support it (or have need for it). .Sh EXAMPLES Assign the IPv4 address .Li 192.0.2.10 , with a network mask of .Li 255.255.255.0 , to the interface .Li fxp0 : .Dl # ifconfig fxp0 inet 192.0.2.10 netmask 255.255.255.0 .Pp Add the IPv4 address .Li 192.0.2.45 , with the CIDR network prefix .Li /28 , to the interface .Li ed0 , using .Cm add as a synonym for the canonical form of the option .Cm alias : .Dl # ifconfig ed0 inet 192.0.2.45/28 add .Pp Remove the IPv4 address .Li 192.0.2.45 from the interface .Li ed0 : .Dl # ifconfig ed0 inet 192.0.2.45 -alias .Pp Add the IPv6 address .Li 2001:DB8:DBDB::123/48 to the interface .Li em0 : .Dl # ifconfig em0 inet6 2001:db8:bdbd::123 prefixlen 48 alias Note that lower case hexadecimal IPv6 addresses are acceptable. .Pp Remove the IPv6 address added in the above example, using the .Li / character as shorthand for the network prefix, and using .Cm delete as a synonym for the canonical form of the option .Fl alias : .Dl # ifconfig em0 inet6 2001:db8:bdbd::123/48 delete .Pp Configure the interface .Li xl0 , to use 100baseTX, full duplex Ethernet media options: .Dl # ifconfig xl0 media 100baseTX mediaopt full-duplex .Pp Create the software network interface .Li gif1 : .Dl # ifconfig gif1 create .Pp Destroy the software network interface .Li gif1 : .Dl # ifconfig gif1 destroy .Sh DIAGNOSTICS Messages indicating the specified interface does not exist, the requested address is unknown, or the user is not privileged and tried to alter an interface's configuration. .Sh SEE ALSO .Xr netstat 1 , .Xr carp 4 , .Xr netintro 4 , .Xr pfsync 4 , .Xr polling 4 , .Xr vlan 4 , .\" .Xr eon 5 , .Xr rc 8 , .Xr routed 8 , .Xr sysctl 8 .Sh HISTORY The .Nm utility appeared in .Bx 4.2 . .Sh BUGS Basic IPv6 node operation requires a link-local address on each interface configured for IPv6. Normally, such an address is automatically configured by the kernel on each interface added to the system; this behaviour may be disabled by setting the sysctl MIB variable .Va net.inet6.ip6.auto_linklocal to 0. .Pp If you delete such an address using .Nm , the kernel may act very odd. Do this at your own risk. Index: head/sys/net/if_bridge.c =================================================================== --- head/sys/net/if_bridge.c (revision 173319) +++ head/sys/net/if_bridge.c (revision 173320) @@ -1,3327 +1,3390 @@ /* $NetBSD: if_bridge.c,v 1.31 2005/06/01 19:45:34 jdc Exp $ */ /* * Copyright 2001 Wasabi Systems, Inc. * All rights reserved. * * Written by Jason R. Thorpe for Wasabi Systems, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project by * Wasabi Systems, Inc. * 4. The name of Wasabi Systems, Inc. may not be used to endorse * or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Jason L. Wright * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * OpenBSD: if_bridge.c,v 1.60 2001/06/15 03:38:33 itojun Exp */ /* * Network interface bridge support. * * TODO: * * - Currently only supports Ethernet-like interfaces (Ethernet, * 802.11, VLANs on Ethernet, etc.) Figure out a nice way * to bridge other types of interfaces (FDDI-FDDI, and maybe * consider heterogenous bridges). */ #include __FBSDID("$FreeBSD$"); #include "opt_inet.h" #include "opt_inet6.h" #include "opt_carp.h" #include #include #include #include #include #include #include /* for net/if.h */ #include #include /* string functions */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* for struct arpcom */ #include #include #include #include #ifdef INET6 #include #include #endif #ifdef DEV_CARP #include #endif #include #include /* for struct arpcom */ #include #include #include #include #include #include #include /* * Size of the route hash table. Must be a power of two. */ #ifndef BRIDGE_RTHASH_SIZE #define BRIDGE_RTHASH_SIZE 1024 #endif #define BRIDGE_RTHASH_MASK (BRIDGE_RTHASH_SIZE - 1) /* * Maximum number of addresses to cache. */ #ifndef BRIDGE_RTABLE_MAX #define BRIDGE_RTABLE_MAX 100 #endif /* * Timeout (in seconds) for entries learned dynamically. */ #ifndef BRIDGE_RTABLE_TIMEOUT #define BRIDGE_RTABLE_TIMEOUT (20 * 60) /* same as ARP */ #endif /* * Number of seconds between walks of the route list. */ #ifndef BRIDGE_RTABLE_PRUNE_PERIOD #define BRIDGE_RTABLE_PRUNE_PERIOD (5 * 60) #endif /* * List of capabilities to mask on the member interface. */ #define BRIDGE_IFCAPS_MASK IFCAP_TXCSUM /* * Bridge interface list entry. */ struct bridge_iflist { LIST_ENTRY(bridge_iflist) bif_next; struct ifnet *bif_ifp; /* member if */ struct bstp_port bif_stp; /* STP state */ uint32_t bif_flags; /* member if flags */ int bif_mutecap; /* member muted caps */ + uint32_t bif_addrmax; /* max # of addresses */ + uint32_t bif_addrcnt; /* cur. # of addresses */ + uint32_t bif_addrexceeded;/* # of address violations */ }; /* * Bridge route node. */ struct bridge_rtnode { LIST_ENTRY(bridge_rtnode) brt_hash; /* hash table linkage */ LIST_ENTRY(bridge_rtnode) brt_list; /* list linkage */ - struct ifnet *brt_ifp; /* destination if */ + struct bridge_iflist *brt_dst; /* destination if */ unsigned long brt_expire; /* expiration time */ uint8_t brt_flags; /* address flags */ uint8_t brt_addr[ETHER_ADDR_LEN]; uint16_t brt_vlan; /* vlan id */ }; +#define brt_ifp brt_dst->bif_ifp /* * Software state for each bridge. */ struct bridge_softc { struct ifnet *sc_ifp; /* make this an interface */ LIST_ENTRY(bridge_softc) sc_list; struct mtx sc_mtx; struct cv sc_cv; uint32_t sc_brtmax; /* max # of addresses */ uint32_t sc_brtcnt; /* cur. # of addresses */ uint32_t sc_brttimeout; /* rt timeout in seconds */ struct callout sc_brcallout; /* bridge callout */ uint32_t sc_iflist_ref; /* refcount for sc_iflist */ uint32_t sc_iflist_xcnt; /* refcount for sc_iflist */ LIST_HEAD(, bridge_iflist) sc_iflist; /* member interface list */ LIST_HEAD(, bridge_rtnode) *sc_rthash; /* our forwarding table */ LIST_HEAD(, bridge_rtnode) sc_rtlist; /* list version of above */ uint32_t sc_rthash_key; /* key for hash */ LIST_HEAD(, bridge_iflist) sc_spanlist; /* span ports list */ struct bstp_state sc_stp; /* STP state */ uint32_t sc_brtexceeded; /* # of cache drops */ }; static struct mtx bridge_list_mtx; eventhandler_tag bridge_detach_cookie = NULL; int bridge_rtable_prune_period = BRIDGE_RTABLE_PRUNE_PERIOD; uma_zone_t bridge_rtnode_zone; static int bridge_clone_create(struct if_clone *, int, caddr_t); static void bridge_clone_destroy(struct ifnet *); static int bridge_ioctl(struct ifnet *, u_long, caddr_t); static void bridge_mutecaps(struct bridge_iflist *, int); static void bridge_ifdetach(void *arg __unused, struct ifnet *); static void bridge_init(void *); static void bridge_dummynet(struct mbuf *, struct ifnet *); static void bridge_stop(struct ifnet *, int); static void bridge_start(struct ifnet *); static struct mbuf *bridge_input(struct ifnet *, struct mbuf *); static int bridge_output(struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *); static void bridge_enqueue(struct bridge_softc *, struct ifnet *, struct mbuf *); static void bridge_rtdelete(struct bridge_softc *, struct ifnet *ifp, int); static void bridge_forward(struct bridge_softc *, struct bridge_iflist *, struct mbuf *m); static void bridge_timer(void *); static void bridge_broadcast(struct bridge_softc *, struct ifnet *, struct mbuf *, int); static void bridge_span(struct bridge_softc *, struct mbuf *); static int bridge_rtupdate(struct bridge_softc *, const uint8_t *, uint16_t, struct bridge_iflist *, int, uint8_t); static struct ifnet *bridge_rtlookup(struct bridge_softc *, const uint8_t *, uint16_t); static void bridge_rttrim(struct bridge_softc *); static void bridge_rtage(struct bridge_softc *); static void bridge_rtflush(struct bridge_softc *, int); static int bridge_rtdaddr(struct bridge_softc *, const uint8_t *, uint16_t); static int bridge_rtable_init(struct bridge_softc *); static void bridge_rtable_fini(struct bridge_softc *); static int bridge_rtnode_addr_cmp(const uint8_t *, const uint8_t *); static struct bridge_rtnode *bridge_rtnode_lookup(struct bridge_softc *, const uint8_t *, uint16_t); static int bridge_rtnode_insert(struct bridge_softc *, struct bridge_rtnode *); static void bridge_rtnode_destroy(struct bridge_softc *, struct bridge_rtnode *); static void bridge_rtable_expire(struct ifnet *, int); static void bridge_state_change(struct ifnet *, int); static struct bridge_iflist *bridge_lookup_member(struct bridge_softc *, const char *name); static struct bridge_iflist *bridge_lookup_member_if(struct bridge_softc *, struct ifnet *ifp); static void bridge_delete_member(struct bridge_softc *, struct bridge_iflist *, int); static void bridge_delete_span(struct bridge_softc *, struct bridge_iflist *); static int bridge_ioctl_add(struct bridge_softc *, void *); static int bridge_ioctl_del(struct bridge_softc *, void *); static int bridge_ioctl_gifflags(struct bridge_softc *, void *); static int bridge_ioctl_sifflags(struct bridge_softc *, void *); static int bridge_ioctl_scache(struct bridge_softc *, void *); static int bridge_ioctl_gcache(struct bridge_softc *, void *); static int bridge_ioctl_gifs(struct bridge_softc *, void *); static int bridge_ioctl_rts(struct bridge_softc *, void *); static int bridge_ioctl_saddr(struct bridge_softc *, void *); static int bridge_ioctl_sto(struct bridge_softc *, void *); static int bridge_ioctl_gto(struct bridge_softc *, void *); static int bridge_ioctl_daddr(struct bridge_softc *, void *); static int bridge_ioctl_flush(struct bridge_softc *, void *); static int bridge_ioctl_gpri(struct bridge_softc *, void *); static int bridge_ioctl_spri(struct bridge_softc *, void *); static int bridge_ioctl_ght(struct bridge_softc *, void *); static int bridge_ioctl_sht(struct bridge_softc *, void *); static int bridge_ioctl_gfd(struct bridge_softc *, void *); static int bridge_ioctl_sfd(struct bridge_softc *, void *); static int bridge_ioctl_gma(struct bridge_softc *, void *); static int bridge_ioctl_sma(struct bridge_softc *, void *); static int bridge_ioctl_sifprio(struct bridge_softc *, void *); static int bridge_ioctl_sifcost(struct bridge_softc *, void *); +static int bridge_ioctl_sifmaxaddr(struct bridge_softc *, void *); static int bridge_ioctl_addspan(struct bridge_softc *, void *); static int bridge_ioctl_delspan(struct bridge_softc *, void *); static int bridge_ioctl_gbparam(struct bridge_softc *, void *); static int bridge_ioctl_grte(struct bridge_softc *, void *); static int bridge_ioctl_gifsstp(struct bridge_softc *, void *); static int bridge_ioctl_sproto(struct bridge_softc *, void *); static int bridge_ioctl_stxhc(struct bridge_softc *, void *); static int bridge_pfil(struct mbuf **, struct ifnet *, struct ifnet *, int); static int bridge_ip_checkbasic(struct mbuf **mp); #ifdef INET6 static int bridge_ip6_checkbasic(struct mbuf **mp); #endif /* INET6 */ static int bridge_fragment(struct ifnet *, struct mbuf *, struct ether_header *, int, struct llc *); /* The default bridge vlan is 1 (IEEE 802.1Q-2003 Table 9-2) */ #define VLANTAGOF(_m) \ (_m->m_flags & M_VLANTAG) ? EVL_VLANOFTAG(_m->m_pkthdr.ether_vtag) : 1 static struct bstp_cb_ops bridge_ops = { .bcb_state = bridge_state_change, .bcb_rtage = bridge_rtable_expire }; SYSCTL_DECL(_net_link); SYSCTL_NODE(_net_link, IFT_BRIDGE, bridge, CTLFLAG_RW, 0, "Bridge"); static int pfil_onlyip = 1; /* only pass IP[46] packets when pfil is enabled */ static int pfil_bridge = 1; /* run pfil hooks on the bridge interface */ static int pfil_member = 1; /* run pfil hooks on the member interface */ static int pfil_ipfw = 0; /* layer2 filter with ipfw */ static int pfil_ipfw_arp = 0; /* layer2 filter with ipfw */ static int pfil_local_phys = 0; /* run pfil hooks on the physical interface for locally destined packets */ static int log_stp = 0; /* log STP state changes */ SYSCTL_INT(_net_link_bridge, OID_AUTO, pfil_onlyip, CTLFLAG_RW, &pfil_onlyip, 0, "Only pass IP packets when pfil is enabled"); SYSCTL_INT(_net_link_bridge, OID_AUTO, ipfw_arp, CTLFLAG_RW, &pfil_ipfw_arp, 0, "Filter ARP packets through IPFW layer2"); SYSCTL_INT(_net_link_bridge, OID_AUTO, pfil_bridge, CTLFLAG_RW, &pfil_bridge, 0, "Packet filter on the bridge interface"); SYSCTL_INT(_net_link_bridge, OID_AUTO, pfil_member, CTLFLAG_RW, &pfil_member, 0, "Packet filter on the member interface"); SYSCTL_INT(_net_link_bridge, OID_AUTO, pfil_local_phys, CTLFLAG_RW, &pfil_local_phys, 0, "Packet filter on the physical interface for locally destined packets"); SYSCTL_INT(_net_link_bridge, OID_AUTO, log_stp, CTLFLAG_RW, &log_stp, 0, "Log STP state changes"); struct bridge_control { int (*bc_func)(struct bridge_softc *, void *); int bc_argsize; int bc_flags; }; #define BC_F_COPYIN 0x01 /* copy arguments in */ #define BC_F_COPYOUT 0x02 /* copy arguments out */ #define BC_F_SUSER 0x04 /* do super-user check */ const struct bridge_control bridge_control_table[] = { { bridge_ioctl_add, sizeof(struct ifbreq), BC_F_COPYIN|BC_F_SUSER }, { bridge_ioctl_del, sizeof(struct ifbreq), BC_F_COPYIN|BC_F_SUSER }, { bridge_ioctl_gifflags, sizeof(struct ifbreq), BC_F_COPYIN|BC_F_COPYOUT }, { bridge_ioctl_sifflags, sizeof(struct ifbreq), BC_F_COPYIN|BC_F_SUSER }, { bridge_ioctl_scache, sizeof(struct ifbrparam), BC_F_COPYIN|BC_F_SUSER }, { bridge_ioctl_gcache, sizeof(struct ifbrparam), BC_F_COPYOUT }, { bridge_ioctl_gifs, sizeof(struct ifbifconf), BC_F_COPYIN|BC_F_COPYOUT }, { bridge_ioctl_rts, sizeof(struct ifbaconf), BC_F_COPYIN|BC_F_COPYOUT }, { bridge_ioctl_saddr, sizeof(struct ifbareq), BC_F_COPYIN|BC_F_SUSER }, { bridge_ioctl_sto, sizeof(struct ifbrparam), BC_F_COPYIN|BC_F_SUSER }, { bridge_ioctl_gto, sizeof(struct ifbrparam), BC_F_COPYOUT }, { bridge_ioctl_daddr, sizeof(struct ifbareq), BC_F_COPYIN|BC_F_SUSER }, { bridge_ioctl_flush, sizeof(struct ifbreq), BC_F_COPYIN|BC_F_SUSER }, { bridge_ioctl_gpri, sizeof(struct ifbrparam), BC_F_COPYOUT }, { bridge_ioctl_spri, sizeof(struct ifbrparam), BC_F_COPYIN|BC_F_SUSER }, { bridge_ioctl_ght, sizeof(struct ifbrparam), BC_F_COPYOUT }, { bridge_ioctl_sht, sizeof(struct ifbrparam), BC_F_COPYIN|BC_F_SUSER }, { bridge_ioctl_gfd, sizeof(struct ifbrparam), BC_F_COPYOUT }, { bridge_ioctl_sfd, sizeof(struct ifbrparam), BC_F_COPYIN|BC_F_SUSER }, { bridge_ioctl_gma, sizeof(struct ifbrparam), BC_F_COPYOUT }, { bridge_ioctl_sma, sizeof(struct ifbrparam), BC_F_COPYIN|BC_F_SUSER }, { bridge_ioctl_sifprio, sizeof(struct ifbreq), BC_F_COPYIN|BC_F_SUSER }, { bridge_ioctl_sifcost, sizeof(struct ifbreq), BC_F_COPYIN|BC_F_SUSER }, { bridge_ioctl_addspan, sizeof(struct ifbreq), BC_F_COPYIN|BC_F_SUSER }, { bridge_ioctl_delspan, sizeof(struct ifbreq), BC_F_COPYIN|BC_F_SUSER }, { bridge_ioctl_gbparam, sizeof(struct ifbropreq), BC_F_COPYOUT }, { bridge_ioctl_grte, sizeof(struct ifbrparam), BC_F_COPYOUT }, { bridge_ioctl_gifsstp, sizeof(struct ifbpstpconf), BC_F_COPYIN|BC_F_COPYOUT }, { bridge_ioctl_sproto, sizeof(struct ifbrparam), BC_F_COPYIN|BC_F_SUSER }, { bridge_ioctl_stxhc, sizeof(struct ifbrparam), BC_F_COPYIN|BC_F_SUSER }, + + { bridge_ioctl_sifmaxaddr, sizeof(struct ifbreq), + BC_F_COPYIN|BC_F_SUSER }, + }; const int bridge_control_table_size = sizeof(bridge_control_table) / sizeof(bridge_control_table[0]); LIST_HEAD(, bridge_softc) bridge_list; IFC_SIMPLE_DECLARE(bridge, 0); static int bridge_modevent(module_t mod, int type, void *data) { switch (type) { case MOD_LOAD: mtx_init(&bridge_list_mtx, "if_bridge list", NULL, MTX_DEF); if_clone_attach(&bridge_cloner); bridge_rtnode_zone = uma_zcreate("bridge_rtnode", sizeof(struct bridge_rtnode), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); LIST_INIT(&bridge_list); bridge_input_p = bridge_input; bridge_output_p = bridge_output; bridge_dn_p = bridge_dummynet; bridge_detach_cookie = EVENTHANDLER_REGISTER( ifnet_departure_event, bridge_ifdetach, NULL, EVENTHANDLER_PRI_ANY); break; case MOD_UNLOAD: EVENTHANDLER_DEREGISTER(ifnet_departure_event, bridge_detach_cookie); if_clone_detach(&bridge_cloner); uma_zdestroy(bridge_rtnode_zone); bridge_input_p = NULL; bridge_output_p = NULL; bridge_dn_p = NULL; mtx_destroy(&bridge_list_mtx); break; default: return (EOPNOTSUPP); } return (0); } static moduledata_t bridge_mod = { "if_bridge", bridge_modevent, 0 }; DECLARE_MODULE(if_bridge, bridge_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); MODULE_DEPEND(if_bridge, bridgestp, 1, 1, 1); /* * handler for net.link.bridge.pfil_ipfw */ static int sysctl_pfil_ipfw(SYSCTL_HANDLER_ARGS) { int enable = pfil_ipfw; int error; error = sysctl_handle_int(oidp, &enable, 0, req); enable = (enable) ? 1 : 0; if (enable != pfil_ipfw) { pfil_ipfw = enable; /* * Disable pfil so that ipfw doesnt run twice, if the user * really wants both then they can re-enable pfil_bridge and/or * pfil_member. Also allow non-ip packets as ipfw can filter by * layer2 type. */ if (pfil_ipfw) { pfil_onlyip = 0; pfil_bridge = 0; pfil_member = 0; } } return (error); } SYSCTL_PROC(_net_link_bridge, OID_AUTO, ipfw, CTLTYPE_INT|CTLFLAG_RW, &pfil_ipfw, 0, &sysctl_pfil_ipfw, "I", "Layer2 filter with IPFW"); /* * bridge_clone_create: * * Create a new bridge instance. */ static int bridge_clone_create(struct if_clone *ifc, int unit, caddr_t params) { struct bridge_softc *sc, *sc2; struct ifnet *bifp, *ifp; u_char eaddr[6]; int retry; sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO); ifp = sc->sc_ifp = if_alloc(IFT_ETHER); if (ifp == NULL) { free(sc, M_DEVBUF); return (ENOSPC); } BRIDGE_LOCK_INIT(sc); sc->sc_brtmax = BRIDGE_RTABLE_MAX; sc->sc_brttimeout = BRIDGE_RTABLE_TIMEOUT; /* Initialize our routing table. */ bridge_rtable_init(sc); callout_init_mtx(&sc->sc_brcallout, &sc->sc_mtx, 0); LIST_INIT(&sc->sc_iflist); LIST_INIT(&sc->sc_spanlist); ifp->if_softc = sc; if_initname(ifp, ifc->ifc_name, unit); ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl = bridge_ioctl; ifp->if_start = bridge_start; ifp->if_init = bridge_init; ifp->if_type = IFT_BRIDGE; IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; IFQ_SET_READY(&ifp->if_snd); /* * Generate a random ethernet address with a locally administered * address. * * Since we are using random ethernet addresses for the bridge, it is * possible that we might have address collisions, so make sure that * this hardware address isn't already in use on another bridge. */ for (retry = 1; retry != 0;) { arc4rand(eaddr, ETHER_ADDR_LEN, 1); eaddr[0] &= ~1; /* clear multicast bit */ eaddr[0] |= 2; /* set the LAA bit */ retry = 0; mtx_lock(&bridge_list_mtx); LIST_FOREACH(sc2, &bridge_list, sc_list) { bifp = sc2->sc_ifp; if (memcmp(eaddr, IF_LLADDR(bifp), ETHER_ADDR_LEN) == 0) retry = 1; } mtx_unlock(&bridge_list_mtx); } bstp_attach(&sc->sc_stp, &bridge_ops); ether_ifattach(ifp, eaddr); /* Now undo some of the damage... */ ifp->if_baudrate = 0; ifp->if_type = IFT_BRIDGE; mtx_lock(&bridge_list_mtx); LIST_INSERT_HEAD(&bridge_list, sc, sc_list); mtx_unlock(&bridge_list_mtx); return (0); } /* * bridge_clone_destroy: * * Destroy a bridge instance. */ static void bridge_clone_destroy(struct ifnet *ifp) { struct bridge_softc *sc = ifp->if_softc; struct bridge_iflist *bif; BRIDGE_LOCK(sc); bridge_stop(ifp, 1); ifp->if_flags &= ~IFF_UP; while ((bif = LIST_FIRST(&sc->sc_iflist)) != NULL) bridge_delete_member(sc, bif, 0); while ((bif = LIST_FIRST(&sc->sc_spanlist)) != NULL) { bridge_delete_span(sc, bif); } BRIDGE_UNLOCK(sc); callout_drain(&sc->sc_brcallout); mtx_lock(&bridge_list_mtx); LIST_REMOVE(sc, sc_list); mtx_unlock(&bridge_list_mtx); bstp_detach(&sc->sc_stp); ether_ifdetach(ifp); if_free_type(ifp, IFT_ETHER); /* Tear down the routing table. */ bridge_rtable_fini(sc); BRIDGE_LOCK_DESTROY(sc); free(sc, M_DEVBUF); } /* * bridge_ioctl: * * Handle a control request from the operator. */ static int bridge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { struct bridge_softc *sc = ifp->if_softc; struct thread *td = curthread; union { struct ifbreq ifbreq; struct ifbifconf ifbifconf; struct ifbareq ifbareq; struct ifbaconf ifbaconf; struct ifbrparam ifbrparam; struct ifbropreq ifbropreq; } args; struct ifdrv *ifd = (struct ifdrv *) data; const struct bridge_control *bc; int error = 0; switch (cmd) { case SIOCADDMULTI: case SIOCDELMULTI: break; case SIOCGDRVSPEC: case SIOCSDRVSPEC: if (ifd->ifd_cmd >= bridge_control_table_size) { error = EINVAL; break; } bc = &bridge_control_table[ifd->ifd_cmd]; if (cmd == SIOCGDRVSPEC && (bc->bc_flags & BC_F_COPYOUT) == 0) { error = EINVAL; break; } else if (cmd == SIOCSDRVSPEC && (bc->bc_flags & BC_F_COPYOUT) != 0) { error = EINVAL; break; } if (bc->bc_flags & BC_F_SUSER) { error = priv_check(td, PRIV_NET_BRIDGE); if (error) break; } if (ifd->ifd_len != bc->bc_argsize || ifd->ifd_len > sizeof(args)) { error = EINVAL; break; } bzero(&args, sizeof(args)); if (bc->bc_flags & BC_F_COPYIN) { error = copyin(ifd->ifd_data, &args, ifd->ifd_len); if (error) break; } BRIDGE_LOCK(sc); error = (*bc->bc_func)(sc, &args); BRIDGE_UNLOCK(sc); if (error) break; if (bc->bc_flags & BC_F_COPYOUT) error = copyout(&args, ifd->ifd_data, ifd->ifd_len); break; case SIOCSIFFLAGS: if (!(ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING)) { /* * If interface is marked down and it is running, * then stop and disable it. */ BRIDGE_LOCK(sc); bridge_stop(ifp, 1); BRIDGE_UNLOCK(sc); } else if ((ifp->if_flags & IFF_UP) && !(ifp->if_drv_flags & IFF_DRV_RUNNING)) { /* * If interface is marked up and it is stopped, then * start it. */ (*ifp->if_init)(sc); } break; case SIOCSIFMTU: /* Do not allow the MTU to be changed on the bridge */ error = EINVAL; break; default: /* * drop the lock as ether_ioctl() will call bridge_start() and * cause the lock to be recursed. */ error = ether_ioctl(ifp, cmd, data); break; } return (error); } /* * bridge_mutecaps: * * Clear or restore unwanted capabilities on the member interface */ static void bridge_mutecaps(struct bridge_iflist *bif, int mute) { struct ifnet *ifp = bif->bif_ifp; struct ifreq ifr; int error; if (ifp->if_ioctl == NULL) return; bzero(&ifr, sizeof(ifr)); ifr.ifr_reqcap = ifp->if_capenable; if (mute) { /* mask off and save capabilities */ bif->bif_mutecap = ifr.ifr_reqcap & BRIDGE_IFCAPS_MASK; if (bif->bif_mutecap != 0) ifr.ifr_reqcap &= ~BRIDGE_IFCAPS_MASK; } else /* restore muted capabilities */ ifr.ifr_reqcap |= bif->bif_mutecap; if (bif->bif_mutecap != 0) { IFF_LOCKGIANT(ifp); error = (*ifp->if_ioctl)(ifp, SIOCSIFCAP, (caddr_t)&ifr); IFF_UNLOCKGIANT(ifp); } } /* * bridge_lookup_member: * * Lookup a bridge member interface. */ static struct bridge_iflist * bridge_lookup_member(struct bridge_softc *sc, const char *name) { struct bridge_iflist *bif; struct ifnet *ifp; BRIDGE_LOCK_ASSERT(sc); LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { ifp = bif->bif_ifp; if (strcmp(ifp->if_xname, name) == 0) return (bif); } return (NULL); } /* * bridge_lookup_member_if: * * Lookup a bridge member interface by ifnet*. */ static struct bridge_iflist * bridge_lookup_member_if(struct bridge_softc *sc, struct ifnet *member_ifp) { struct bridge_iflist *bif; BRIDGE_LOCK_ASSERT(sc); LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { if (bif->bif_ifp == member_ifp) return (bif); } return (NULL); } /* * bridge_delete_member: * * Delete the specified member interface. */ static void bridge_delete_member(struct bridge_softc *sc, struct bridge_iflist *bif, int gone) { struct ifnet *ifs = bif->bif_ifp; BRIDGE_LOCK_ASSERT(sc); if (!gone) { switch (ifs->if_type) { case IFT_ETHER: case IFT_L2VLAN: /* * Take the interface out of promiscuous mode. */ (void) ifpromisc(ifs, 0); bridge_mutecaps(bif, 0); break; case IFT_GIF: break; default: #ifdef DIAGNOSTIC panic("bridge_delete_member: impossible"); #endif break; } } if (bif->bif_flags & IFBIF_STP) bstp_disable(&bif->bif_stp); ifs->if_bridge = NULL; BRIDGE_XLOCK(sc); LIST_REMOVE(bif, bif_next); BRIDGE_XDROP(sc); bridge_rtdelete(sc, ifs, IFBF_FLUSHALL); + KASSERT(bif->bif_addrcnt == 0, + ("%s: %d bridge routes referenced", __func__, bif->bif_addrcnt)); BRIDGE_UNLOCK(sc); bstp_destroy(&bif->bif_stp); /* prepare to free */ BRIDGE_LOCK(sc); free(bif, M_DEVBUF); } /* * bridge_delete_span: * * Delete the specified span interface. */ static void bridge_delete_span(struct bridge_softc *sc, struct bridge_iflist *bif) { BRIDGE_LOCK_ASSERT(sc); KASSERT(bif->bif_ifp->if_bridge == NULL, ("%s: not a span interface", __func__)); LIST_REMOVE(bif, bif_next); free(bif, M_DEVBUF); } static int bridge_ioctl_add(struct bridge_softc *sc, void *arg) { struct ifbreq *req = arg; struct bridge_iflist *bif = NULL; struct ifnet *ifs; int error = 0; ifs = ifunit(req->ifbr_ifsname); if (ifs == NULL) return (ENOENT); /* If it's in the span list, it can't be a member. */ LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) if (ifs == bif->bif_ifp) return (EBUSY); /* Allow the first Ethernet member to define the MTU */ if (ifs->if_type != IFT_GIF) { if (LIST_EMPTY(&sc->sc_iflist)) sc->sc_ifp->if_mtu = ifs->if_mtu; else if (sc->sc_ifp->if_mtu != ifs->if_mtu) { if_printf(sc->sc_ifp, "invalid MTU for %s\n", ifs->if_xname); return (EINVAL); } } if (ifs->if_bridge == sc) return (EEXIST); if (ifs->if_bridge != NULL) return (EBUSY); bif = malloc(sizeof(*bif), M_DEVBUF, M_NOWAIT|M_ZERO); if (bif == NULL) return (ENOMEM); bif->bif_ifp = ifs; bif->bif_flags = IFBIF_LEARNING | IFBIF_DISCOVER; switch (ifs->if_type) { case IFT_ETHER: case IFT_L2VLAN: /* * Place the interface into promiscuous mode. */ error = ifpromisc(ifs, 1); if (error) goto out; bridge_mutecaps(bif, 1); break; case IFT_GIF: break; default: error = EINVAL; goto out; } ifs->if_bridge = sc; bstp_create(&sc->sc_stp, &bif->bif_stp, bif->bif_ifp); /* * XXX: XLOCK HERE!?! * * NOTE: insert_***HEAD*** should be safe for the traversals. */ LIST_INSERT_HEAD(&sc->sc_iflist, bif, bif_next); out: if (error) { if (bif != NULL) free(bif, M_DEVBUF); } return (error); } static int bridge_ioctl_del(struct bridge_softc *sc, void *arg) { struct ifbreq *req = arg; struct bridge_iflist *bif; bif = bridge_lookup_member(sc, req->ifbr_ifsname); if (bif == NULL) return (ENOENT); bridge_delete_member(sc, bif, 0); return (0); } static int bridge_ioctl_gifflags(struct bridge_softc *sc, void *arg) { struct ifbreq *req = arg; struct bridge_iflist *bif; struct bstp_port *bp; bif = bridge_lookup_member(sc, req->ifbr_ifsname); if (bif == NULL) return (ENOENT); bp = &bif->bif_stp; req->ifbr_ifsflags = bif->bif_flags; req->ifbr_state = bp->bp_state; req->ifbr_priority = bp->bp_priority; req->ifbr_path_cost = bp->bp_path_cost; req->ifbr_portno = bif->bif_ifp->if_index & 0xfff; req->ifbr_proto = bp->bp_protover; req->ifbr_role = bp->bp_role; req->ifbr_stpflags = bp->bp_flags; + req->ifbr_addrcnt = bif->bif_addrcnt; + req->ifbr_addrmax = bif->bif_addrmax; + req->ifbr_addrexceeded = bif->bif_addrexceeded; /* Copy STP state options as flags */ if (bp->bp_operedge) req->ifbr_ifsflags |= IFBIF_BSTP_EDGE; if (bp->bp_flags & BSTP_PORT_AUTOEDGE) req->ifbr_ifsflags |= IFBIF_BSTP_AUTOEDGE; if (bp->bp_ptp_link) req->ifbr_ifsflags |= IFBIF_BSTP_PTP; if (bp->bp_flags & BSTP_PORT_AUTOPTP) req->ifbr_ifsflags |= IFBIF_BSTP_AUTOPTP; if (bp->bp_flags & BSTP_PORT_ADMEDGE) req->ifbr_ifsflags |= IFBIF_BSTP_ADMEDGE; if (bp->bp_flags & BSTP_PORT_ADMCOST) req->ifbr_ifsflags |= IFBIF_BSTP_ADMCOST; return (0); } static int bridge_ioctl_sifflags(struct bridge_softc *sc, void *arg) { struct ifbreq *req = arg; struct bridge_iflist *bif; struct bstp_port *bp; int error; bif = bridge_lookup_member(sc, req->ifbr_ifsname); if (bif == NULL) return (ENOENT); bp = &bif->bif_stp; if (req->ifbr_ifsflags & IFBIF_SPAN) /* SPAN is readonly */ return (EINVAL); if (req->ifbr_ifsflags & IFBIF_STP) { if ((bif->bif_flags & IFBIF_STP) == 0) { error = bstp_enable(&bif->bif_stp); if (error) return (error); } } else { if ((bif->bif_flags & IFBIF_STP) != 0) bstp_disable(&bif->bif_stp); } /* Pass on STP flags */ bstp_set_edge(bp, req->ifbr_ifsflags & IFBIF_BSTP_EDGE ? 1 : 0); bstp_set_autoedge(bp, req->ifbr_ifsflags & IFBIF_BSTP_AUTOEDGE ? 1 : 0); bstp_set_ptp(bp, req->ifbr_ifsflags & IFBIF_BSTP_PTP ? 1 : 0); bstp_set_autoptp(bp, req->ifbr_ifsflags & IFBIF_BSTP_AUTOPTP ? 1 : 0); /* Save the bits relating to the bridge */ bif->bif_flags = req->ifbr_ifsflags & IFBIFMASK; return (0); } static int bridge_ioctl_scache(struct bridge_softc *sc, void *arg) { struct ifbrparam *param = arg; sc->sc_brtmax = param->ifbrp_csize; bridge_rttrim(sc); return (0); } static int bridge_ioctl_gcache(struct bridge_softc *sc, void *arg) { struct ifbrparam *param = arg; param->ifbrp_csize = sc->sc_brtmax; return (0); } static int bridge_ioctl_gifs(struct bridge_softc *sc, void *arg) { struct ifbifconf *bifc = arg; struct bridge_iflist *bif; struct ifbreq breq; char *buf, *outbuf; int count, buflen, len, error = 0; count = 0; LIST_FOREACH(bif, &sc->sc_iflist, bif_next) count++; LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) count++; buflen = sizeof(breq) * count; if (bifc->ifbic_len == 0) { bifc->ifbic_len = buflen; return (0); } BRIDGE_UNLOCK(sc); outbuf = malloc(buflen, M_TEMP, M_WAITOK | M_ZERO); BRIDGE_LOCK(sc); count = 0; buf = outbuf; len = min(bifc->ifbic_len, buflen); bzero(&breq, sizeof(breq)); LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { if (len < sizeof(breq)) break; strlcpy(breq.ifbr_ifsname, bif->bif_ifp->if_xname, sizeof(breq.ifbr_ifsname)); /* Fill in the ifbreq structure */ error = bridge_ioctl_gifflags(sc, &breq); if (error) break; memcpy(buf, &breq, sizeof(breq)); count++; buf += sizeof(breq); len -= sizeof(breq); } LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) { if (len < sizeof(breq)) break; strlcpy(breq.ifbr_ifsname, bif->bif_ifp->if_xname, sizeof(breq.ifbr_ifsname)); breq.ifbr_ifsflags = bif->bif_flags; breq.ifbr_portno = bif->bif_ifp->if_index & 0xfff; memcpy(buf, &breq, sizeof(breq)); count++; buf += sizeof(breq); len -= sizeof(breq); } BRIDGE_UNLOCK(sc); bifc->ifbic_len = sizeof(breq) * count; error = copyout(outbuf, bifc->ifbic_req, bifc->ifbic_len); BRIDGE_LOCK(sc); free(outbuf, M_TEMP); return (error); } static int bridge_ioctl_rts(struct bridge_softc *sc, void *arg) { struct ifbaconf *bac = arg; struct bridge_rtnode *brt; struct ifbareq bareq; char *buf, *outbuf; int count, buflen, len, error = 0; if (bac->ifbac_len == 0) return (0); count = 0; LIST_FOREACH(brt, &sc->sc_rtlist, brt_list) count++; buflen = sizeof(bareq) * count; BRIDGE_UNLOCK(sc); outbuf = malloc(buflen, M_TEMP, M_WAITOK | M_ZERO); BRIDGE_LOCK(sc); count = 0; buf = outbuf; len = min(bac->ifbac_len, buflen); bzero(&bareq, sizeof(bareq)); LIST_FOREACH(brt, &sc->sc_rtlist, brt_list) { if (len < sizeof(bareq)) goto out; strlcpy(bareq.ifba_ifsname, brt->brt_ifp->if_xname, sizeof(bareq.ifba_ifsname)); memcpy(bareq.ifba_dst, brt->brt_addr, sizeof(brt->brt_addr)); bareq.ifba_vlan = brt->brt_vlan; if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC && time_uptime < brt->brt_expire) bareq.ifba_expire = brt->brt_expire - time_uptime; else bareq.ifba_expire = 0; bareq.ifba_flags = brt->brt_flags; memcpy(buf, &bareq, sizeof(bareq)); count++; buf += sizeof(bareq); len -= sizeof(bareq); } out: BRIDGE_UNLOCK(sc); bac->ifbac_len = sizeof(bareq) * count; error = copyout(outbuf, bac->ifbac_req, bac->ifbac_len); BRIDGE_LOCK(sc); free(outbuf, M_TEMP); return (error); } static int bridge_ioctl_saddr(struct bridge_softc *sc, void *arg) { struct ifbareq *req = arg; struct bridge_iflist *bif; int error; bif = bridge_lookup_member(sc, req->ifba_ifsname); if (bif == NULL) return (ENOENT); error = bridge_rtupdate(sc, req->ifba_dst, req->ifba_vlan, bif, 1, req->ifba_flags); return (error); } static int bridge_ioctl_sto(struct bridge_softc *sc, void *arg) { struct ifbrparam *param = arg; sc->sc_brttimeout = param->ifbrp_ctime; return (0); } static int bridge_ioctl_gto(struct bridge_softc *sc, void *arg) { struct ifbrparam *param = arg; param->ifbrp_ctime = sc->sc_brttimeout; return (0); } static int bridge_ioctl_daddr(struct bridge_softc *sc, void *arg) { struct ifbareq *req = arg; return (bridge_rtdaddr(sc, req->ifba_dst, req->ifba_vlan)); } static int bridge_ioctl_flush(struct bridge_softc *sc, void *arg) { struct ifbreq *req = arg; bridge_rtflush(sc, req->ifbr_ifsflags); return (0); } static int bridge_ioctl_gpri(struct bridge_softc *sc, void *arg) { struct ifbrparam *param = arg; struct bstp_state *bs = &sc->sc_stp; param->ifbrp_prio = bs->bs_bridge_priority; return (0); } static int bridge_ioctl_spri(struct bridge_softc *sc, void *arg) { struct ifbrparam *param = arg; return (bstp_set_priority(&sc->sc_stp, param->ifbrp_prio)); } static int bridge_ioctl_ght(struct bridge_softc *sc, void *arg) { struct ifbrparam *param = arg; struct bstp_state *bs = &sc->sc_stp; param->ifbrp_hellotime = bs->bs_bridge_htime >> 8; return (0); } static int bridge_ioctl_sht(struct bridge_softc *sc, void *arg) { struct ifbrparam *param = arg; return (bstp_set_htime(&sc->sc_stp, param->ifbrp_hellotime)); } static int bridge_ioctl_gfd(struct bridge_softc *sc, void *arg) { struct ifbrparam *param = arg; struct bstp_state *bs = &sc->sc_stp; param->ifbrp_fwddelay = bs->bs_bridge_fdelay >> 8; return (0); } static int bridge_ioctl_sfd(struct bridge_softc *sc, void *arg) { struct ifbrparam *param = arg; return (bstp_set_fdelay(&sc->sc_stp, param->ifbrp_fwddelay)); } static int bridge_ioctl_gma(struct bridge_softc *sc, void *arg) { struct ifbrparam *param = arg; struct bstp_state *bs = &sc->sc_stp; param->ifbrp_maxage = bs->bs_bridge_max_age >> 8; return (0); } static int bridge_ioctl_sma(struct bridge_softc *sc, void *arg) { struct ifbrparam *param = arg; return (bstp_set_maxage(&sc->sc_stp, param->ifbrp_maxage)); } static int bridge_ioctl_sifprio(struct bridge_softc *sc, void *arg) { struct ifbreq *req = arg; struct bridge_iflist *bif; bif = bridge_lookup_member(sc, req->ifbr_ifsname); if (bif == NULL) return (ENOENT); return (bstp_set_port_priority(&bif->bif_stp, req->ifbr_priority)); } static int bridge_ioctl_sifcost(struct bridge_softc *sc, void *arg) { struct ifbreq *req = arg; struct bridge_iflist *bif; bif = bridge_lookup_member(sc, req->ifbr_ifsname); if (bif == NULL) return (ENOENT); return (bstp_set_path_cost(&bif->bif_stp, req->ifbr_path_cost)); } static int +bridge_ioctl_sifmaxaddr(struct bridge_softc *sc, void *arg) +{ + struct ifbreq *req = arg; + struct bridge_iflist *bif; + + bif = bridge_lookup_member(sc, req->ifbr_ifsname); + if (bif == NULL) + return (ENOENT); + + bif->bif_addrmax = req->ifbr_addrmax; + return (0); +} + +static int bridge_ioctl_addspan(struct bridge_softc *sc, void *arg) { struct ifbreq *req = arg; struct bridge_iflist *bif = NULL; struct ifnet *ifs; ifs = ifunit(req->ifbr_ifsname); if (ifs == NULL) return (ENOENT); LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) if (ifs == bif->bif_ifp) return (EBUSY); if (ifs->if_bridge != NULL) return (EBUSY); switch (ifs->if_type) { case IFT_ETHER: case IFT_GIF: case IFT_L2VLAN: break; default: return (EINVAL); } bif = malloc(sizeof(*bif), M_DEVBUF, M_NOWAIT|M_ZERO); if (bif == NULL) return (ENOMEM); bif->bif_ifp = ifs; bif->bif_flags = IFBIF_SPAN; LIST_INSERT_HEAD(&sc->sc_spanlist, bif, bif_next); return (0); } static int bridge_ioctl_delspan(struct bridge_softc *sc, void *arg) { struct ifbreq *req = arg; struct bridge_iflist *bif; struct ifnet *ifs; ifs = ifunit(req->ifbr_ifsname); if (ifs == NULL) return (ENOENT); LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) if (ifs == bif->bif_ifp) break; if (bif == NULL) return (ENOENT); bridge_delete_span(sc, bif); return (0); } static int bridge_ioctl_gbparam(struct bridge_softc *sc, void *arg) { struct ifbropreq *req = arg; struct bstp_state *bs = &sc->sc_stp; struct bstp_port *root_port; req->ifbop_maxage = bs->bs_bridge_max_age >> 8; req->ifbop_hellotime = bs->bs_bridge_htime >> 8; req->ifbop_fwddelay = bs->bs_bridge_fdelay >> 8; root_port = bs->bs_root_port; if (root_port == NULL) req->ifbop_root_port = 0; else req->ifbop_root_port = root_port->bp_ifp->if_index; req->ifbop_holdcount = bs->bs_txholdcount; req->ifbop_priority = bs->bs_bridge_priority; req->ifbop_protocol = bs->bs_protover; req->ifbop_root_path_cost = bs->bs_root_pv.pv_cost; req->ifbop_bridgeid = bs->bs_bridge_pv.pv_dbridge_id; req->ifbop_designated_root = bs->bs_root_pv.pv_root_id; req->ifbop_designated_bridge = bs->bs_root_pv.pv_dbridge_id; req->ifbop_last_tc_time.tv_sec = bs->bs_last_tc_time.tv_sec; req->ifbop_last_tc_time.tv_usec = bs->bs_last_tc_time.tv_usec; return (0); } static int bridge_ioctl_grte(struct bridge_softc *sc, void *arg) { struct ifbrparam *param = arg; param->ifbrp_cexceeded = sc->sc_brtexceeded; return (0); } static int bridge_ioctl_gifsstp(struct bridge_softc *sc, void *arg) { struct ifbpstpconf *bifstp = arg; struct bridge_iflist *bif; struct bstp_port *bp; struct ifbpstpreq bpreq; char *buf, *outbuf; int count, buflen, len, error = 0; count = 0; LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { if ((bif->bif_flags & IFBIF_STP) != 0) count++; } buflen = sizeof(bpreq) * count; if (bifstp->ifbpstp_len == 0) { bifstp->ifbpstp_len = buflen; return (0); } BRIDGE_UNLOCK(sc); outbuf = malloc(buflen, M_TEMP, M_WAITOK | M_ZERO); BRIDGE_LOCK(sc); count = 0; buf = outbuf; len = min(bifstp->ifbpstp_len, buflen); bzero(&bpreq, sizeof(bpreq)); LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { if (len < sizeof(bpreq)) break; if ((bif->bif_flags & IFBIF_STP) == 0) continue; bp = &bif->bif_stp; bpreq.ifbp_portno = bif->bif_ifp->if_index & 0xfff; bpreq.ifbp_fwd_trans = bp->bp_forward_transitions; bpreq.ifbp_design_cost = bp->bp_desg_pv.pv_cost; bpreq.ifbp_design_port = bp->bp_desg_pv.pv_port_id; bpreq.ifbp_design_bridge = bp->bp_desg_pv.pv_dbridge_id; bpreq.ifbp_design_root = bp->bp_desg_pv.pv_root_id; memcpy(buf, &bpreq, sizeof(bpreq)); count++; buf += sizeof(bpreq); len -= sizeof(bpreq); } BRIDGE_UNLOCK(sc); bifstp->ifbpstp_len = sizeof(bpreq) * count; error = copyout(outbuf, bifstp->ifbpstp_req, bifstp->ifbpstp_len); BRIDGE_LOCK(sc); free(outbuf, M_TEMP); return (error); } static int bridge_ioctl_sproto(struct bridge_softc *sc, void *arg) { struct ifbrparam *param = arg; return (bstp_set_protocol(&sc->sc_stp, param->ifbrp_proto)); } static int bridge_ioctl_stxhc(struct bridge_softc *sc, void *arg) { struct ifbrparam *param = arg; return (bstp_set_holdcount(&sc->sc_stp, param->ifbrp_txhc)); } /* * bridge_ifdetach: * * Detach an interface from a bridge. Called when a member * interface is detaching. */ static void bridge_ifdetach(void *arg __unused, struct ifnet *ifp) { struct bridge_softc *sc = ifp->if_bridge; struct bridge_iflist *bif; /* Check if the interface is a bridge member */ if (sc != NULL) { BRIDGE_LOCK(sc); bif = bridge_lookup_member_if(sc, ifp); if (bif != NULL) bridge_delete_member(sc, bif, 1); BRIDGE_UNLOCK(sc); return; } /* Check if the interface is a span port */ mtx_lock(&bridge_list_mtx); LIST_FOREACH(sc, &bridge_list, sc_list) { BRIDGE_LOCK(sc); LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) if (ifp == bif->bif_ifp) { bridge_delete_span(sc, bif); break; } BRIDGE_UNLOCK(sc); } mtx_unlock(&bridge_list_mtx); } /* * bridge_init: * * Initialize a bridge interface. */ static void bridge_init(void *xsc) { struct bridge_softc *sc = (struct bridge_softc *)xsc; struct ifnet *ifp = sc->sc_ifp; if (ifp->if_drv_flags & IFF_DRV_RUNNING) return; BRIDGE_LOCK(sc); callout_reset(&sc->sc_brcallout, bridge_rtable_prune_period * hz, bridge_timer, sc); ifp->if_drv_flags |= IFF_DRV_RUNNING; bstp_init(&sc->sc_stp); /* Initialize Spanning Tree */ BRIDGE_UNLOCK(sc); } /* * bridge_stop: * * Stop the bridge interface. */ static void bridge_stop(struct ifnet *ifp, int disable) { struct bridge_softc *sc = ifp->if_softc; BRIDGE_LOCK_ASSERT(sc); if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) return; callout_stop(&sc->sc_brcallout); bstp_stop(&sc->sc_stp); bridge_rtflush(sc, IFBF_FLUSHDYN); ifp->if_drv_flags &= ~IFF_DRV_RUNNING; } /* * bridge_enqueue: * * Enqueue a packet on a bridge member interface. * */ static void bridge_enqueue(struct bridge_softc *sc, struct ifnet *dst_ifp, struct mbuf *m) { int len, err = 0; short mflags; struct mbuf *m0; len = m->m_pkthdr.len; mflags = m->m_flags; /* We may be sending a fragment so traverse the mbuf */ for (; m; m = m0) { m0 = m->m_nextpkt; m->m_nextpkt = NULL; /* * If underlying interface can not do VLAN tag insertion itself * then attach a packet tag that holds it. */ if ((m->m_flags & M_VLANTAG) && (dst_ifp->if_capenable & IFCAP_VLAN_HWTAGGING) == 0) { m = ether_vlanencap(m, m->m_pkthdr.ether_vtag); if (m == NULL) { if_printf(dst_ifp, "unable to prepend VLAN header\n"); dst_ifp->if_oerrors++; continue; } m->m_flags &= ~M_VLANTAG; } if (err == 0) IFQ_ENQUEUE(&dst_ifp->if_snd, m, err); } if (err == 0) { sc->sc_ifp->if_opackets++; sc->sc_ifp->if_obytes += len; dst_ifp->if_obytes += len; if (mflags & M_MCAST) { sc->sc_ifp->if_omcasts++; dst_ifp->if_omcasts++; } } if ((dst_ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) (*dst_ifp->if_start)(dst_ifp); } /* * bridge_dummynet: * * Receive a queued packet from dummynet and pass it on to the output * interface. * * The mbuf has the Ethernet header already attached. */ static void bridge_dummynet(struct mbuf *m, struct ifnet *ifp) { struct bridge_softc *sc; sc = ifp->if_bridge; /* * The packet didnt originate from a member interface. This should only * ever happen if a member interface is removed while packets are * queued for it. */ if (sc == NULL) { m_freem(m); return; } if (PFIL_HOOKED(&inet_pfil_hook) #ifdef INET6 || PFIL_HOOKED(&inet6_pfil_hook) #endif ) { if (bridge_pfil(&m, sc->sc_ifp, ifp, PFIL_OUT) != 0) return; if (m == NULL) return; } bridge_enqueue(sc, ifp, m); } /* * bridge_output: * * Send output from a bridge member interface. This * performs the bridging function for locally originated * packets. * * The mbuf has the Ethernet header already attached. We must * enqueue or free the mbuf before returning. */ static int bridge_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa, struct rtentry *rt) { struct ether_header *eh; struct ifnet *dst_if; struct bridge_softc *sc; uint16_t vlan; if (m->m_len < ETHER_HDR_LEN) { m = m_pullup(m, ETHER_HDR_LEN); if (m == NULL) return (0); } eh = mtod(m, struct ether_header *); sc = ifp->if_bridge; vlan = VLANTAGOF(m); BRIDGE_LOCK(sc); /* * If bridge is down, but the original output interface is up, * go ahead and send out that interface. Otherwise, the packet * is dropped below. */ if ((sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { dst_if = ifp; goto sendunicast; } /* * If the packet is a multicast, or we don't know a better way to * get there, send to all interfaces. */ if (ETHER_IS_MULTICAST(eh->ether_dhost)) dst_if = NULL; else dst_if = bridge_rtlookup(sc, eh->ether_dhost, vlan); if (dst_if == NULL) { struct bridge_iflist *bif; struct mbuf *mc; int error = 0, used = 0; bridge_span(sc, m); BRIDGE_LOCK2REF(sc, error); if (error) { m_freem(m); return (0); } LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { dst_if = bif->bif_ifp; if (dst_if->if_type == IFT_GIF) continue; if ((dst_if->if_drv_flags & IFF_DRV_RUNNING) == 0) continue; /* * If this is not the original output interface, * and the interface is participating in spanning * tree, make sure the port is in a state that * allows forwarding. */ if (dst_if != ifp && (bif->bif_flags & IFBIF_STP) && bif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) continue; if (LIST_NEXT(bif, bif_next) == NULL) { used = 1; mc = m; } else { mc = m_copypacket(m, M_DONTWAIT); if (mc == NULL) { sc->sc_ifp->if_oerrors++; continue; } } bridge_enqueue(sc, dst_if, mc); } if (used == 0) m_freem(m); BRIDGE_UNREF(sc); return (0); } sendunicast: /* * XXX Spanning tree consideration here? */ bridge_span(sc, m); if ((dst_if->if_drv_flags & IFF_DRV_RUNNING) == 0) { m_freem(m); BRIDGE_UNLOCK(sc); return (0); } BRIDGE_UNLOCK(sc); bridge_enqueue(sc, dst_if, m); return (0); } /* * bridge_start: * * Start output on a bridge. * */ static void bridge_start(struct ifnet *ifp) { struct bridge_softc *sc; struct mbuf *m; struct ether_header *eh; struct ifnet *dst_if; sc = ifp->if_softc; ifp->if_drv_flags |= IFF_DRV_OACTIVE; for (;;) { IFQ_DEQUEUE(&ifp->if_snd, m); if (m == 0) break; ETHER_BPF_MTAP(ifp, m); eh = mtod(m, struct ether_header *); dst_if = NULL; BRIDGE_LOCK(sc); if ((m->m_flags & (M_BCAST|M_MCAST)) == 0) { dst_if = bridge_rtlookup(sc, eh->ether_dhost, 1); } if (dst_if == NULL) bridge_broadcast(sc, ifp, m, 0); else { BRIDGE_UNLOCK(sc); bridge_enqueue(sc, dst_if, m); } } ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; } /* * bridge_forward: * * The forwarding function of the bridge. * * NOTE: Releases the lock on return. */ static void bridge_forward(struct bridge_softc *sc, struct bridge_iflist *sbif, struct mbuf *m) { struct bridge_iflist *dbif; struct ifnet *src_if, *dst_if, *ifp; struct ether_header *eh; uint16_t vlan; + int error; src_if = m->m_pkthdr.rcvif; ifp = sc->sc_ifp; sc->sc_ifp->if_ipackets++; sc->sc_ifp->if_ibytes += m->m_pkthdr.len; vlan = VLANTAGOF(m); if ((sbif->bif_flags & IFBIF_STP) && sbif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) { BRIDGE_UNLOCK(sc); m_freem(m); return; } eh = mtod(m, struct ether_header *); - /* - * If the interface is learning, and the source - * address is valid and not multicast, record - * the address. - */ - if ((sbif->bif_flags & IFBIF_LEARNING) != 0 && - ETHER_IS_MULTICAST(eh->ether_shost) == 0 && - (eh->ether_shost[0] == 0 && - eh->ether_shost[1] == 0 && - eh->ether_shost[2] == 0 && - eh->ether_shost[3] == 0 && - eh->ether_shost[4] == 0 && - eh->ether_shost[5] == 0) == 0) { - (void) bridge_rtupdate(sc, eh->ether_shost, vlan, + /* If the interface is learning, record the address. */ + if (sbif->bif_flags & IFBIF_LEARNING) { + error = bridge_rtupdate(sc, eh->ether_shost, vlan, sbif, 0, IFBAF_DYNAMIC); + /* + * If the interface has addresses limits then deny any source + * that is not in the cache. + */ + if (error && sbif->bif_addrmax) { + BRIDGE_UNLOCK(sc); + m_freem(m); + return; + } } if ((sbif->bif_flags & IFBIF_STP) != 0 && sbif->bif_stp.bp_state == BSTP_IFSTATE_LEARNING) { m_freem(m); BRIDGE_UNLOCK(sc); return; } /* * At this point, the port either doesn't participate * in spanning tree or it is in the forwarding state. */ /* * If the packet is unicast, destined for someone on * "this" side of the bridge, drop it. */ if ((m->m_flags & (M_BCAST|M_MCAST)) == 0) { dst_if = bridge_rtlookup(sc, eh->ether_dhost, vlan); if (src_if == dst_if) { BRIDGE_UNLOCK(sc); m_freem(m); return; } } else { /* ...forward it to all interfaces. */ sc->sc_ifp->if_imcasts++; dst_if = NULL; } /* * If we have a destination interface which is a member of our bridge, * OR this is a unicast packet, push it through the bpf(4) machinery. * For broadcast or multicast packets, don't bother because it will * be reinjected into ether_input. We do this before we pass the packets * through the pfil(9) framework, as it is possible that pfil(9) will * drop the packet, or possibly modify it, making it difficult to debug * firewall issues on the bridge. */ if (dst_if != NULL || (m->m_flags & (M_BCAST | M_MCAST)) == 0) ETHER_BPF_MTAP(ifp, m); /* run the packet filter */ if (PFIL_HOOKED(&inet_pfil_hook) #ifdef INET6 || PFIL_HOOKED(&inet6_pfil_hook) #endif ) { BRIDGE_UNLOCK(sc); if (bridge_pfil(&m, ifp, src_if, PFIL_IN) != 0) return; if (m == NULL) return; BRIDGE_LOCK(sc); } if (dst_if == NULL) { bridge_broadcast(sc, src_if, m, 1); return; } /* * At this point, we're dealing with a unicast frame * going to a different interface. */ if ((dst_if->if_drv_flags & IFF_DRV_RUNNING) == 0) { BRIDGE_UNLOCK(sc); m_freem(m); return; } dbif = bridge_lookup_member_if(sc, dst_if); if (dbif == NULL) { /* Not a member of the bridge (anymore?) */ BRIDGE_UNLOCK(sc); m_freem(m); return; } /* Private segments can not talk to each other */ if (sbif->bif_flags & dbif->bif_flags & IFBIF_PRIVATE) { BRIDGE_UNLOCK(sc); m_freem(m); return; } if ((dbif->bif_flags & IFBIF_STP) && dbif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) { BRIDGE_UNLOCK(sc); m_freem(m); return; } BRIDGE_UNLOCK(sc); if (PFIL_HOOKED(&inet_pfil_hook) #ifdef INET6 || PFIL_HOOKED(&inet6_pfil_hook) #endif ) { if (bridge_pfil(&m, sc->sc_ifp, dst_if, PFIL_OUT) != 0) return; if (m == NULL) return; } bridge_enqueue(sc, dst_if, m); } /* * bridge_input: * * Receive input from a member interface. Queue the packet for * bridging if it is not for us. */ static struct mbuf * bridge_input(struct ifnet *ifp, struct mbuf *m) { struct bridge_softc *sc = ifp->if_bridge; struct bridge_iflist *bif, *bif2; struct ifnet *bifp; struct ether_header *eh; struct mbuf *mc, *mc2; uint16_t vlan; + int error; if ((sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) return (m); bifp = sc->sc_ifp; vlan = VLANTAGOF(m); /* * Implement support for bridge monitoring. If this flag has been * set on this interface, discard the packet once we push it through * the bpf(4) machinery, but before we do, increment the byte and * packet counters associated with this interface. */ if ((bifp->if_flags & IFF_MONITOR) != 0) { m->m_pkthdr.rcvif = bifp; ETHER_BPF_MTAP(bifp, m); bifp->if_ipackets++; bifp->if_ibytes += m->m_pkthdr.len; m_freem(m); return (NULL); } BRIDGE_LOCK(sc); bif = bridge_lookup_member_if(sc, ifp); if (bif == NULL) { BRIDGE_UNLOCK(sc); return (m); } eh = mtod(m, struct ether_header *); if (memcmp(eh->ether_dhost, IF_LLADDR(bifp), ETHER_ADDR_LEN) == 0) { /* * Filter on the physical interface. */ if (pfil_local_phys && (PFIL_HOOKED(&inet_pfil_hook) #ifdef INET6 || PFIL_HOOKED(&inet6_pfil_hook) #endif )) { if (bridge_pfil(&m, NULL, ifp, PFIL_IN) != 0 || m == NULL) { BRIDGE_UNLOCK(sc); return (NULL); } } /* * If the packet is for us, set the packets source as the * bridge, and return the packet back to ether_input for * local processing. */ /* Note where to send the reply to */ - if (bif->bif_flags & IFBIF_LEARNING) - (void) bridge_rtupdate(sc, + if (bif->bif_flags & IFBIF_LEARNING) { + error = bridge_rtupdate(sc, eh->ether_shost, vlan, bif, 0, IFBAF_DYNAMIC); + /* + * If the interface has addresses limits then deny any + * source that is not in the cache. + */ + if (error && bif->bif_addrmax) { + BRIDGE_UNLOCK(sc); + m_freem(m); + return (NULL); + } + } /* Mark the packet as arriving on the bridge interface */ m->m_pkthdr.rcvif = bifp; ETHER_BPF_MTAP(bifp, m); bifp->if_ipackets++; BRIDGE_UNLOCK(sc); return (m); } bridge_span(sc, m); if (m->m_flags & (M_BCAST|M_MCAST)) { /* Tap off 802.1D packets; they do not get forwarded. */ if (memcmp(eh->ether_dhost, bstp_etheraddr, ETHER_ADDR_LEN) == 0) { m = bstp_input(&bif->bif_stp, ifp, m); if (m == NULL) { BRIDGE_UNLOCK(sc); return (NULL); } } if ((bif->bif_flags & IFBIF_STP) && bif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) { BRIDGE_UNLOCK(sc); return (m); } /* * Make a deep copy of the packet and enqueue the copy * for bridge processing; return the original packet for * local processing. */ mc = m_dup(m, M_DONTWAIT); if (mc == NULL) { BRIDGE_UNLOCK(sc); return (m); } /* Perform the bridge forwarding function with the copy. */ bridge_forward(sc, bif, mc); /* * Reinject the mbuf as arriving on the bridge so we have a * chance at claiming multicast packets. We can not loop back * here from ether_input as a bridge is never a member of a * bridge. */ KASSERT(bifp->if_bridge == NULL, ("loop created in bridge_input")); mc2 = m_dup(m, M_DONTWAIT); if (mc2 != NULL) { /* Keep the layer3 header aligned */ int i = min(mc2->m_pkthdr.len, max_protohdr); mc2 = m_copyup(mc2, i, ETHER_ALIGN); } if (mc2 != NULL) { mc2->m_pkthdr.rcvif = bifp; (*bifp->if_input)(bifp, mc2); } /* Return the original packet for local processing. */ return (m); } if ((bif->bif_flags & IFBIF_STP) && bif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) { BRIDGE_UNLOCK(sc); return (m); } #ifdef DEV_CARP # define OR_CARP_CHECK_WE_ARE_DST(iface) \ || ((iface)->if_carp \ && carp_forus((iface)->if_carp, eh->ether_dhost)) # define OR_CARP_CHECK_WE_ARE_SRC(iface) \ || ((iface)->if_carp \ && carp_forus((iface)->if_carp, eh->ether_shost)) #else # define OR_CARP_CHECK_WE_ARE_DST(iface) # define OR_CARP_CHECK_WE_ARE_SRC(iface) #endif #define GRAB_OUR_PACKETS(iface) \ if ((iface)->if_type == IFT_GIF) \ continue; \ /* It is destined for us. */ \ if (memcmp(IF_LLADDR((iface)), eh->ether_dhost, ETHER_ADDR_LEN) == 0 \ OR_CARP_CHECK_WE_ARE_DST((iface)) \ ) { \ - if (bif->bif_flags & IFBIF_LEARNING) \ - (void) bridge_rtupdate(sc, eh->ether_shost, \ + if (bif->bif_flags & IFBIF_LEARNING) { \ + error = bridge_rtupdate(sc, eh->ether_shost, \ vlan, bif, 0, IFBAF_DYNAMIC); \ + if (error && bif->bif_addrmax) { \ + BRIDGE_UNLOCK(sc); \ + m_freem(m); \ + return (NULL); \ + } \ + } \ m->m_pkthdr.rcvif = iface; \ BRIDGE_UNLOCK(sc); \ return (m); \ } \ \ /* We just received a packet that we sent out. */ \ if (memcmp(IF_LLADDR((iface)), eh->ether_shost, ETHER_ADDR_LEN) == 0 \ OR_CARP_CHECK_WE_ARE_SRC((iface)) \ ) { \ BRIDGE_UNLOCK(sc); \ m_freem(m); \ return (NULL); \ } /* * Unicast. Make sure it's not for us. * * Give a chance for ifp at first priority. This will help when the * packet comes through the interface like VLAN's with the same MACs * on several interfaces from the same bridge. This also will save * some CPU cycles in case the destination interface and the input * interface (eq ifp) are the same. */ do { GRAB_OUR_PACKETS(ifp) } while (0); /* Now check the all bridge members. */ LIST_FOREACH(bif2, &sc->sc_iflist, bif_next) { GRAB_OUR_PACKETS(bif2->bif_ifp) } #undef OR_CARP_CHECK_WE_ARE_DST #undef OR_CARP_CHECK_WE_ARE_SRC #undef GRAB_OUR_PACKETS /* Perform the bridge forwarding function. */ bridge_forward(sc, bif, m); return (NULL); } /* * bridge_broadcast: * * Send a frame to all interfaces that are members of * the bridge, except for the one on which the packet * arrived. * * NOTE: Releases the lock on return. */ static void bridge_broadcast(struct bridge_softc *sc, struct ifnet *src_if, struct mbuf *m, int runfilt) { struct bridge_iflist *dbif, *sbif; struct mbuf *mc; struct ifnet *dst_if; int error = 0, used = 0, i; sbif = bridge_lookup_member_if(sc, src_if); BRIDGE_LOCK2REF(sc, error); if (error) { m_freem(m); return; } /* Filter on the bridge interface before broadcasting */ if (runfilt && (PFIL_HOOKED(&inet_pfil_hook) #ifdef INET6 || PFIL_HOOKED(&inet6_pfil_hook) #endif )) { if (bridge_pfil(&m, sc->sc_ifp, NULL, PFIL_OUT) != 0) goto out; if (m == NULL) goto out; } LIST_FOREACH(dbif, &sc->sc_iflist, bif_next) { dst_if = dbif->bif_ifp; if (dst_if == src_if) continue; /* Private segments can not talk to each other */ if (sbif && (sbif->bif_flags & dbif->bif_flags & IFBIF_PRIVATE)) continue; if ((dbif->bif_flags & IFBIF_STP) && dbif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) continue; if ((dbif->bif_flags & IFBIF_DISCOVER) == 0 && (m->m_flags & (M_BCAST|M_MCAST)) == 0) continue; if ((dst_if->if_drv_flags & IFF_DRV_RUNNING) == 0) continue; if (LIST_NEXT(dbif, bif_next) == NULL) { mc = m; used = 1; } else { mc = m_dup(m, M_DONTWAIT); if (mc == NULL) { sc->sc_ifp->if_oerrors++; continue; } } /* * Filter on the output interface. Pass a NULL bridge interface * pointer so we do not redundantly filter on the bridge for * each interface we broadcast on. */ if (runfilt && (PFIL_HOOKED(&inet_pfil_hook) #ifdef INET6 || PFIL_HOOKED(&inet6_pfil_hook) #endif )) { if (used == 0) { /* Keep the layer3 header aligned */ i = min(mc->m_pkthdr.len, max_protohdr); mc = m_copyup(mc, i, ETHER_ALIGN); if (mc == NULL) { sc->sc_ifp->if_oerrors++; continue; } } if (bridge_pfil(&mc, NULL, dst_if, PFIL_OUT) != 0) continue; if (mc == NULL) continue; } bridge_enqueue(sc, dst_if, mc); } if (used == 0) m_freem(m); out: BRIDGE_UNREF(sc); } /* * bridge_span: * * Duplicate a packet out one or more interfaces that are in span mode, * the original mbuf is unmodified. */ static void bridge_span(struct bridge_softc *sc, struct mbuf *m) { struct bridge_iflist *bif; struct ifnet *dst_if; struct mbuf *mc; if (LIST_EMPTY(&sc->sc_spanlist)) return; LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) { dst_if = bif->bif_ifp; if ((dst_if->if_drv_flags & IFF_DRV_RUNNING) == 0) continue; mc = m_copypacket(m, M_DONTWAIT); if (mc == NULL) { sc->sc_ifp->if_oerrors++; continue; } bridge_enqueue(sc, dst_if, mc); } } /* * bridge_rtupdate: * * Add a bridge routing entry. */ static int bridge_rtupdate(struct bridge_softc *sc, const uint8_t *dst, uint16_t vlan, struct bridge_iflist *bif, int setflags, uint8_t flags) { struct bridge_rtnode *brt; - struct ifnet *dst_if = bif->bif_ifp; int error; BRIDGE_LOCK_ASSERT(sc); + /* Check the source address is valid and not multicast. */ + if (ETHER_IS_MULTICAST(dst) || + (dst[0] == 0 && dst[1] == 0 && dst[2] == 0 && + dst[3] == 0 && dst[4] == 0 && dst[5] == 0) != 0) + return (EINVAL); + /* 802.1p frames map to vlan 1 */ if (vlan == 0) vlan = 1; /* * A route for this destination might already exist. If so, * update it, otherwise create a new one. */ if ((brt = bridge_rtnode_lookup(sc, dst, vlan)) == NULL) { if (sc->sc_brtcnt >= sc->sc_brtmax) { sc->sc_brtexceeded++; return (ENOSPC); } + /* Check per interface address limits (if enabled) */ + if (bif->bif_addrmax && bif->bif_addrcnt >= bif->bif_addrmax) { + bif->bif_addrexceeded++; + return (ENOSPC); + } /* * Allocate a new bridge forwarding node, and * initialize the expiration time and Ethernet * address. */ brt = uma_zalloc(bridge_rtnode_zone, M_NOWAIT | M_ZERO); if (brt == NULL) return (ENOMEM); if (bif->bif_flags & IFBIF_STICKY) brt->brt_flags = IFBAF_STICKY; else brt->brt_flags = IFBAF_DYNAMIC; - brt->brt_ifp = dst_if; memcpy(brt->brt_addr, dst, ETHER_ADDR_LEN); brt->brt_vlan = vlan; if ((error = bridge_rtnode_insert(sc, brt)) != 0) { uma_zfree(bridge_rtnode_zone, brt); return (error); } + brt->brt_dst = bif; + bif->bif_addrcnt++; } - if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) - brt->brt_ifp = dst_if; + if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC && + brt->brt_dst != bif) { + brt->brt_dst->bif_addrcnt--; + brt->brt_dst = bif; + brt->brt_dst->bif_addrcnt++; + } + if ((flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) brt->brt_expire = time_uptime + sc->sc_brttimeout; if (setflags) brt->brt_flags = flags; return (0); } /* * bridge_rtlookup: * * Lookup the destination interface for an address. */ static struct ifnet * bridge_rtlookup(struct bridge_softc *sc, const uint8_t *addr, uint16_t vlan) { struct bridge_rtnode *brt; BRIDGE_LOCK_ASSERT(sc); if ((brt = bridge_rtnode_lookup(sc, addr, vlan)) == NULL) return (NULL); return (brt->brt_ifp); } /* * bridge_rttrim: * * Trim the routine table so that we have a number * of routing entries less than or equal to the * maximum number. */ static void bridge_rttrim(struct bridge_softc *sc) { struct bridge_rtnode *brt, *nbrt; BRIDGE_LOCK_ASSERT(sc); /* Make sure we actually need to do this. */ if (sc->sc_brtcnt <= sc->sc_brtmax) return; /* Force an aging cycle; this might trim enough addresses. */ bridge_rtage(sc); if (sc->sc_brtcnt <= sc->sc_brtmax) return; LIST_FOREACH_SAFE(brt, &sc->sc_rtlist, brt_list, nbrt) { if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) { bridge_rtnode_destroy(sc, brt); if (sc->sc_brtcnt <= sc->sc_brtmax) return; } } } /* * bridge_timer: * * Aging timer for the bridge. */ static void bridge_timer(void *arg) { struct bridge_softc *sc = arg; BRIDGE_LOCK_ASSERT(sc); bridge_rtage(sc); if (sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING) callout_reset(&sc->sc_brcallout, bridge_rtable_prune_period * hz, bridge_timer, sc); } /* * bridge_rtage: * * Perform an aging cycle. */ static void bridge_rtage(struct bridge_softc *sc) { struct bridge_rtnode *brt, *nbrt; BRIDGE_LOCK_ASSERT(sc); LIST_FOREACH_SAFE(brt, &sc->sc_rtlist, brt_list, nbrt) { if ((brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) { if (time_uptime >= brt->brt_expire) bridge_rtnode_destroy(sc, brt); } } } /* * bridge_rtflush: * * Remove all dynamic addresses from the bridge. */ static void bridge_rtflush(struct bridge_softc *sc, int full) { struct bridge_rtnode *brt, *nbrt; BRIDGE_LOCK_ASSERT(sc); LIST_FOREACH_SAFE(brt, &sc->sc_rtlist, brt_list, nbrt) { if (full || (brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) bridge_rtnode_destroy(sc, brt); } } /* * bridge_rtdaddr: * * Remove an address from the table. */ static int bridge_rtdaddr(struct bridge_softc *sc, const uint8_t *addr, uint16_t vlan) { struct bridge_rtnode *brt; int found = 0; BRIDGE_LOCK_ASSERT(sc); /* * If vlan is zero then we want to delete for all vlans so the lookup * may return more than one. */ while ((brt = bridge_rtnode_lookup(sc, addr, vlan)) != NULL) { bridge_rtnode_destroy(sc, brt); found = 1; } return (found ? 0 : ENOENT); } /* * bridge_rtdelete: * * Delete routes to a speicifc member interface. */ static void bridge_rtdelete(struct bridge_softc *sc, struct ifnet *ifp, int full) { struct bridge_rtnode *brt, *nbrt; BRIDGE_LOCK_ASSERT(sc); LIST_FOREACH_SAFE(brt, &sc->sc_rtlist, brt_list, nbrt) { if (brt->brt_ifp == ifp && (full || (brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC)) bridge_rtnode_destroy(sc, brt); } } /* * bridge_rtable_init: * * Initialize the route table for this bridge. */ static int bridge_rtable_init(struct bridge_softc *sc) { int i; sc->sc_rthash = malloc(sizeof(*sc->sc_rthash) * BRIDGE_RTHASH_SIZE, M_DEVBUF, M_NOWAIT); if (sc->sc_rthash == NULL) return (ENOMEM); for (i = 0; i < BRIDGE_RTHASH_SIZE; i++) LIST_INIT(&sc->sc_rthash[i]); sc->sc_rthash_key = arc4random(); LIST_INIT(&sc->sc_rtlist); return (0); } /* * bridge_rtable_fini: * * Deconstruct the route table for this bridge. */ static void bridge_rtable_fini(struct bridge_softc *sc) { + KASSERT(sc->sc_brtcnt == 0, + ("%s: %d bridge routes referenced", __func__, sc->sc_brtcnt)); free(sc->sc_rthash, M_DEVBUF); } /* * The following hash function is adapted from "Hash Functions" by Bob Jenkins * ("Algorithm Alley", Dr. Dobbs Journal, September 1997). */ #define mix(a, b, c) \ do { \ a -= b; a -= c; a ^= (c >> 13); \ b -= c; b -= a; b ^= (a << 8); \ c -= a; c -= b; c ^= (b >> 13); \ a -= b; a -= c; a ^= (c >> 12); \ b -= c; b -= a; b ^= (a << 16); \ c -= a; c -= b; c ^= (b >> 5); \ a -= b; a -= c; a ^= (c >> 3); \ b -= c; b -= a; b ^= (a << 10); \ c -= a; c -= b; c ^= (b >> 15); \ } while (/*CONSTCOND*/0) static __inline uint32_t bridge_rthash(struct bridge_softc *sc, const uint8_t *addr) { uint32_t a = 0x9e3779b9, b = 0x9e3779b9, c = sc->sc_rthash_key; b += addr[5] << 8; b += addr[4]; a += addr[3] << 24; a += addr[2] << 16; a += addr[1] << 8; a += addr[0]; mix(a, b, c); return (c & BRIDGE_RTHASH_MASK); } #undef mix static int bridge_rtnode_addr_cmp(const uint8_t *a, const uint8_t *b) { int i, d; for (i = 0, d = 0; i < ETHER_ADDR_LEN && d == 0; i++) { d = ((int)a[i]) - ((int)b[i]); } return (d); } /* * bridge_rtnode_lookup: * * Look up a bridge route node for the specified destination. Compare the * vlan id or if zero then just return the first match. */ static struct bridge_rtnode * bridge_rtnode_lookup(struct bridge_softc *sc, const uint8_t *addr, uint16_t vlan) { struct bridge_rtnode *brt; uint32_t hash; int dir; BRIDGE_LOCK_ASSERT(sc); hash = bridge_rthash(sc, addr); LIST_FOREACH(brt, &sc->sc_rthash[hash], brt_hash) { dir = bridge_rtnode_addr_cmp(addr, brt->brt_addr); if (dir == 0 && (brt->brt_vlan == vlan || vlan == 0)) return (brt); if (dir > 0) return (NULL); } return (NULL); } /* * bridge_rtnode_insert: * * Insert the specified bridge node into the route table. We * assume the entry is not already in the table. */ static int bridge_rtnode_insert(struct bridge_softc *sc, struct bridge_rtnode *brt) { struct bridge_rtnode *lbrt; uint32_t hash; int dir; BRIDGE_LOCK_ASSERT(sc); hash = bridge_rthash(sc, brt->brt_addr); lbrt = LIST_FIRST(&sc->sc_rthash[hash]); if (lbrt == NULL) { LIST_INSERT_HEAD(&sc->sc_rthash[hash], brt, brt_hash); goto out; } do { dir = bridge_rtnode_addr_cmp(brt->brt_addr, lbrt->brt_addr); if (dir == 0 && brt->brt_vlan == lbrt->brt_vlan) return (EEXIST); if (dir > 0) { LIST_INSERT_BEFORE(lbrt, brt, brt_hash); goto out; } if (LIST_NEXT(lbrt, brt_hash) == NULL) { LIST_INSERT_AFTER(lbrt, brt, brt_hash); goto out; } lbrt = LIST_NEXT(lbrt, brt_hash); } while (lbrt != NULL); #ifdef DIAGNOSTIC panic("bridge_rtnode_insert: impossible"); #endif out: LIST_INSERT_HEAD(&sc->sc_rtlist, brt, brt_list); sc->sc_brtcnt++; return (0); } /* * bridge_rtnode_destroy: * * Destroy a bridge rtnode. */ static void bridge_rtnode_destroy(struct bridge_softc *sc, struct bridge_rtnode *brt) { BRIDGE_LOCK_ASSERT(sc); LIST_REMOVE(brt, brt_hash); LIST_REMOVE(brt, brt_list); sc->sc_brtcnt--; + brt->brt_dst->bif_addrcnt--; uma_zfree(bridge_rtnode_zone, brt); } /* * bridge_rtable_expire: * * Set the expiry time for all routes on an interface. */ static void bridge_rtable_expire(struct ifnet *ifp, int age) { struct bridge_softc *sc = ifp->if_bridge; struct bridge_rtnode *brt; BRIDGE_LOCK(sc); /* * If the age is zero then flush, otherwise set all the expiry times to * age for the interface */ if (age == 0) bridge_rtdelete(sc, ifp, IFBF_FLUSHDYN); else { LIST_FOREACH(brt, &sc->sc_rtlist, brt_list) { /* Cap the expiry time to 'age' */ if (brt->brt_ifp == ifp && brt->brt_expire > time_uptime + age && (brt->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) brt->brt_expire = time_uptime + age; } } BRIDGE_UNLOCK(sc); } /* * bridge_state_change: * * Callback from the bridgestp code when a port changes states. */ static void bridge_state_change(struct ifnet *ifp, int state) { struct bridge_softc *sc = ifp->if_bridge; static const char *stpstates[] = { "disabled", "listening", "learning", "forwarding", "blocking", "discarding" }; if (log_stp) log(LOG_NOTICE, "%s: state changed to %s on %s\n", sc->sc_ifp->if_xname, stpstates[state], ifp->if_xname); } /* * Send bridge packets through pfil if they are one of the types pfil can deal * with, or if they are ARP or REVARP. (pfil will pass ARP and REVARP without * question.) If *bifp or *ifp are NULL then packet filtering is skipped for * that interface. */ static int bridge_pfil(struct mbuf **mp, struct ifnet *bifp, struct ifnet *ifp, int dir) { int snap, error, i, hlen; struct ether_header *eh1, eh2; struct ip_fw_args args; struct ip *ip; struct llc llc1; u_int16_t ether_type; snap = 0; error = -1; /* Default error if not error == 0 */ #if 0 /* we may return with the IP fields swapped, ensure its not shared */ KASSERT(M_WRITABLE(*mp), ("%s: modifying a shared mbuf", __func__)); #endif if (pfil_bridge == 0 && pfil_member == 0 && pfil_ipfw == 0) return (0); /* filtering is disabled */ i = min((*mp)->m_pkthdr.len, max_protohdr); if ((*mp)->m_len < i) { *mp = m_pullup(*mp, i); if (*mp == NULL) { printf("%s: m_pullup failed\n", __func__); return (-1); } } eh1 = mtod(*mp, struct ether_header *); ether_type = ntohs(eh1->ether_type); /* * Check for SNAP/LLC. */ if (ether_type < ETHERMTU) { struct llc *llc2 = (struct llc *)(eh1 + 1); if ((*mp)->m_len >= ETHER_HDR_LEN + 8 && llc2->llc_dsap == LLC_SNAP_LSAP && llc2->llc_ssap == LLC_SNAP_LSAP && llc2->llc_control == LLC_UI) { ether_type = htons(llc2->llc_un.type_snap.ether_type); snap = 1; } } /* * If we're trying to filter bridge traffic, don't look at anything * other than IP and ARP traffic. If the filter doesn't understand * IPv6, don't allow IPv6 through the bridge either. This is lame * since if we really wanted, say, an AppleTalk filter, we are hosed, * but of course we don't have an AppleTalk filter to begin with. * (Note that since pfil doesn't understand ARP it will pass *ALL* * ARP traffic.) */ switch (ether_type) { case ETHERTYPE_ARP: case ETHERTYPE_REVARP: if (pfil_ipfw_arp == 0) return (0); /* Automatically pass */ break; case ETHERTYPE_IP: #ifdef INET6 case ETHERTYPE_IPV6: #endif /* INET6 */ break; default: /* * Check to see if the user wants to pass non-ip * packets, these will not be checked by pfil(9) and * passed unconditionally so the default is to drop. */ if (pfil_onlyip) goto bad; } /* Strip off the Ethernet header and keep a copy. */ m_copydata(*mp, 0, ETHER_HDR_LEN, (caddr_t) &eh2); m_adj(*mp, ETHER_HDR_LEN); /* Strip off snap header, if present */ if (snap) { m_copydata(*mp, 0, sizeof(struct llc), (caddr_t) &llc1); m_adj(*mp, sizeof(struct llc)); } /* * Check the IP header for alignment and errors */ if (dir == PFIL_IN) { switch (ether_type) { case ETHERTYPE_IP: error = bridge_ip_checkbasic(mp); break; #ifdef INET6 case ETHERTYPE_IPV6: error = bridge_ip6_checkbasic(mp); break; #endif /* INET6 */ default: error = 0; } if (error) goto bad; } if (IPFW_LOADED && pfil_ipfw != 0 && dir == PFIL_OUT && ifp != NULL) { error = -1; args.rule = ip_dn_claim_rule(*mp); if (args.rule != NULL && fw_one_pass) goto ipfwpass; /* packet already partially processed */ args.m = *mp; args.oif = ifp; args.next_hop = NULL; args.eh = &eh2; args.inp = NULL; /* used by ipfw uid/gid/jail rules */ i = ip_fw_chk_ptr(&args); *mp = args.m; if (*mp == NULL) return (error); if (DUMMYNET_LOADED && (i == IP_FW_DUMMYNET)) { /* put the Ethernet header back on */ M_PREPEND(*mp, ETHER_HDR_LEN, M_DONTWAIT); if (*mp == NULL) return (error); bcopy(&eh2, mtod(*mp, caddr_t), ETHER_HDR_LEN); /* * Pass the pkt to dummynet, which consumes it. The * packet will return to us via bridge_dummynet(). */ args.oif = ifp; ip_dn_io_ptr(*mp, DN_TO_IFB_FWD, &args); return (error); } if (i != IP_FW_PASS) /* drop */ goto bad; } ipfwpass: error = 0; /* * Run the packet through pfil */ switch (ether_type) { case ETHERTYPE_IP: /* * before calling the firewall, swap fields the same as * IP does. here we assume the header is contiguous */ ip = mtod(*mp, struct ip *); ip->ip_len = ntohs(ip->ip_len); ip->ip_off = ntohs(ip->ip_off); /* * Run pfil on the member interface and the bridge, both can * be skipped by clearing pfil_member or pfil_bridge. * * Keep the order: * in_if -> bridge_if -> out_if */ if (pfil_bridge && dir == PFIL_OUT && bifp != NULL) error = pfil_run_hooks(&inet_pfil_hook, mp, bifp, dir, NULL); if (*mp == NULL || error != 0) /* filter may consume */ break; if (pfil_member && ifp != NULL) error = pfil_run_hooks(&inet_pfil_hook, mp, ifp, dir, NULL); if (*mp == NULL || error != 0) /* filter may consume */ break; if (pfil_bridge && dir == PFIL_IN && bifp != NULL) error = pfil_run_hooks(&inet_pfil_hook, mp, bifp, dir, NULL); if (*mp == NULL || error != 0) /* filter may consume */ break; /* check if we need to fragment the packet */ if (pfil_member && ifp != NULL && dir == PFIL_OUT) { i = (*mp)->m_pkthdr.len; if (i > ifp->if_mtu) { error = bridge_fragment(ifp, *mp, &eh2, snap, &llc1); return (error); } } /* Recalculate the ip checksum and restore byte ordering */ ip = mtod(*mp, struct ip *); hlen = ip->ip_hl << 2; if (hlen < sizeof(struct ip)) goto bad; if (hlen > (*mp)->m_len) { if ((*mp = m_pullup(*mp, hlen)) == 0) goto bad; ip = mtod(*mp, struct ip *); if (ip == NULL) goto bad; } ip->ip_len = htons(ip->ip_len); ip->ip_off = htons(ip->ip_off); ip->ip_sum = 0; if (hlen == sizeof(struct ip)) ip->ip_sum = in_cksum_hdr(ip); else ip->ip_sum = in_cksum(*mp, hlen); break; #ifdef INET6 case ETHERTYPE_IPV6: if (pfil_bridge && dir == PFIL_OUT && bifp != NULL) error = pfil_run_hooks(&inet6_pfil_hook, mp, bifp, dir, NULL); if (*mp == NULL || error != 0) /* filter may consume */ break; if (pfil_member && ifp != NULL) error = pfil_run_hooks(&inet6_pfil_hook, mp, ifp, dir, NULL); if (*mp == NULL || error != 0) /* filter may consume */ break; if (pfil_bridge && dir == PFIL_IN && bifp != NULL) error = pfil_run_hooks(&inet6_pfil_hook, mp, bifp, dir, NULL); break; #endif default: error = 0; break; } if (*mp == NULL) return (error); if (error != 0) goto bad; error = -1; /* * Finally, put everything back the way it was and return */ if (snap) { M_PREPEND(*mp, sizeof(struct llc), M_DONTWAIT); if (*mp == NULL) return (error); bcopy(&llc1, mtod(*mp, caddr_t), sizeof(struct llc)); } M_PREPEND(*mp, ETHER_HDR_LEN, M_DONTWAIT); if (*mp == NULL) return (error); bcopy(&eh2, mtod(*mp, caddr_t), ETHER_HDR_LEN); return (0); bad: m_freem(*mp); *mp = NULL; return (error); } /* * Perform basic checks on header size since * pfil assumes ip_input has already processed * it for it. Cut-and-pasted from ip_input.c. * Given how simple the IPv6 version is, * does the IPv4 version really need to be * this complicated? * * XXX Should we update ipstat here, or not? * XXX Right now we update ipstat but not * XXX csum_counter. */ static int bridge_ip_checkbasic(struct mbuf **mp) { struct mbuf *m = *mp; struct ip *ip; int len, hlen; u_short sum; if (*mp == NULL) return (-1); if (IP_HDR_ALIGNED_P(mtod(m, caddr_t)) == 0) { if ((m = m_copyup(m, sizeof(struct ip), (max_linkhdr + 3) & ~3)) == NULL) { /* XXXJRT new stat, please */ ipstat.ips_toosmall++; goto bad; } } else if (__predict_false(m->m_len < sizeof (struct ip))) { if ((m = m_pullup(m, sizeof (struct ip))) == NULL) { ipstat.ips_toosmall++; goto bad; } } ip = mtod(m, struct ip *); if (ip == NULL) goto bad; if (ip->ip_v != IPVERSION) { ipstat.ips_badvers++; goto bad; } hlen = ip->ip_hl << 2; if (hlen < sizeof(struct ip)) { /* minimum header length */ ipstat.ips_badhlen++; goto bad; } if (hlen > m->m_len) { if ((m = m_pullup(m, hlen)) == 0) { ipstat.ips_badhlen++; goto bad; } ip = mtod(m, struct ip *); if (ip == NULL) goto bad; } if (m->m_pkthdr.csum_flags & CSUM_IP_CHECKED) { sum = !(m->m_pkthdr.csum_flags & CSUM_IP_VALID); } else { if (hlen == sizeof(struct ip)) { sum = in_cksum_hdr(ip); } else { sum = in_cksum(m, hlen); } } if (sum) { ipstat.ips_badsum++; goto bad; } /* Retrieve the packet length. */ len = ntohs(ip->ip_len); /* * Check for additional length bogosity */ if (len < hlen) { ipstat.ips_badlen++; goto bad; } /* * Check that the amount of data in the buffers * is as at least much as the IP header would have us expect. * Drop packet if shorter than we expect. */ if (m->m_pkthdr.len < len) { ipstat.ips_tooshort++; goto bad; } /* Checks out, proceed */ *mp = m; return (0); bad: *mp = m; return (-1); } #ifdef INET6 /* * Same as above, but for IPv6. * Cut-and-pasted from ip6_input.c. * XXX Should we update ip6stat, or not? */ static int bridge_ip6_checkbasic(struct mbuf **mp) { struct mbuf *m = *mp; struct ip6_hdr *ip6; /* * If the IPv6 header is not aligned, slurp it up into a new * mbuf with space for link headers, in the event we forward * it. Otherwise, if it is aligned, make sure the entire base * IPv6 header is in the first mbuf of the chain. */ if (IP6_HDR_ALIGNED_P(mtod(m, caddr_t)) == 0) { struct ifnet *inifp = m->m_pkthdr.rcvif; if ((m = m_copyup(m, sizeof(struct ip6_hdr), (max_linkhdr + 3) & ~3)) == NULL) { /* XXXJRT new stat, please */ ip6stat.ip6s_toosmall++; in6_ifstat_inc(inifp, ifs6_in_hdrerr); goto bad; } } else if (__predict_false(m->m_len < sizeof(struct ip6_hdr))) { struct ifnet *inifp = m->m_pkthdr.rcvif; if ((m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) { ip6stat.ip6s_toosmall++; in6_ifstat_inc(inifp, ifs6_in_hdrerr); goto bad; } } ip6 = mtod(m, struct ip6_hdr *); if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) { ip6stat.ip6s_badvers++; in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr); goto bad; } /* Checks out, proceed */ *mp = m; return (0); bad: *mp = m; return (-1); } #endif /* INET6 */ /* * bridge_fragment: * * Return a fragmented mbuf chain. */ static int bridge_fragment(struct ifnet *ifp, struct mbuf *m, struct ether_header *eh, int snap, struct llc *llc) { struct mbuf *m0; struct ip *ip; int error = -1; if (m->m_len < sizeof(struct ip) && (m = m_pullup(m, sizeof(struct ip))) == NULL) goto out; ip = mtod(m, struct ip *); error = ip_fragment(ip, &m, ifp->if_mtu, ifp->if_hwassist, CSUM_DELAY_IP); if (error) goto out; /* walk the chain and re-add the Ethernet header */ for (m0 = m; m0; m0 = m0->m_nextpkt) { if (error == 0) { if (snap) { M_PREPEND(m0, sizeof(struct llc), M_DONTWAIT); if (m0 == NULL) { error = ENOBUFS; continue; } bcopy(llc, mtod(m0, caddr_t), sizeof(struct llc)); } M_PREPEND(m0, ETHER_HDR_LEN, M_DONTWAIT); if (m0 == NULL) { error = ENOBUFS; continue; } bcopy(eh, mtod(m0, caddr_t), ETHER_HDR_LEN); } else m_freem(m); } if (error == 0) ipstat.ips_fragmented++; return (error); out: if (m != NULL) m_freem(m); return (error); } Index: head/sys/net/if_bridgevar.h =================================================================== --- head/sys/net/if_bridgevar.h (revision 173319) +++ head/sys/net/if_bridgevar.h (revision 173320) @@ -1,323 +1,328 @@ /* $NetBSD: if_bridgevar.h,v 1.4 2003/07/08 07:13:50 itojun Exp $ */ /* * Copyright 2001 Wasabi Systems, Inc. * All rights reserved. * * Written by Jason R. Thorpe for Wasabi Systems, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project by * Wasabi Systems, Inc. * 4. The name of Wasabi Systems, Inc. may not be used to endorse * or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Jason L. Wright * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * OpenBSD: if_bridge.h,v 1.14 2001/03/22 03:48:29 jason Exp * * $FreeBSD$ */ /* * Data structure and control definitions for bridge interfaces. */ #include #include #include /* * Commands used in the SIOCSDRVSPEC ioctl. Note the lookup of the * bridge interface itself is keyed off the ifdrv structure. */ #define BRDGADD 0 /* add bridge member (ifbreq) */ #define BRDGDEL 1 /* delete bridge member (ifbreq) */ #define BRDGGIFFLGS 2 /* get member if flags (ifbreq) */ #define BRDGSIFFLGS 3 /* set member if flags (ifbreq) */ #define BRDGSCACHE 4 /* set cache size (ifbrparam) */ #define BRDGGCACHE 5 /* get cache size (ifbrparam) */ #define BRDGGIFS 6 /* get member list (ifbifconf) */ #define BRDGRTS 7 /* get address list (ifbaconf) */ #define BRDGSADDR 8 /* set static address (ifbareq) */ #define BRDGSTO 9 /* set cache timeout (ifbrparam) */ #define BRDGGTO 10 /* get cache timeout (ifbrparam) */ #define BRDGDADDR 11 /* delete address (ifbareq) */ #define BRDGFLUSH 12 /* flush address cache (ifbreq) */ #define BRDGGPRI 13 /* get priority (ifbrparam) */ #define BRDGSPRI 14 /* set priority (ifbrparam) */ #define BRDGGHT 15 /* get hello time (ifbrparam) */ #define BRDGSHT 16 /* set hello time (ifbrparam) */ #define BRDGGFD 17 /* get forward delay (ifbrparam) */ #define BRDGSFD 18 /* set forward delay (ifbrparam) */ #define BRDGGMA 19 /* get max age (ifbrparam) */ #define BRDGSMA 20 /* set max age (ifbrparam) */ #define BRDGSIFPRIO 21 /* set if priority (ifbreq) */ #define BRDGSIFCOST 22 /* set if path cost (ifbreq) */ #define BRDGADDS 23 /* add bridge span member (ifbreq) */ #define BRDGDELS 24 /* delete bridge span member (ifbreq) */ #define BRDGPARAM 25 /* get bridge STP params (ifbropreq) */ #define BRDGGRTE 26 /* get cache drops (ifbrparam) */ #define BRDGGIFSSTP 27 /* get member STP params list * (ifbpstpconf) */ #define BRDGSPROTO 28 /* set protocol (ifbrparam) */ #define BRDGSTXHC 29 /* set tx hold count (ifbrparam) */ +#define BRDGSIFAMAX 30 /* set max interface addrs (ifbreq) */ /* * Generic bridge control request. */ struct ifbreq { char ifbr_ifsname[IFNAMSIZ]; /* member if name */ uint32_t ifbr_ifsflags; /* member if flags */ uint32_t ifbr_stpflags; /* member if STP flags */ uint32_t ifbr_path_cost; /* member if STP cost */ uint8_t ifbr_portno; /* member if port number */ uint8_t ifbr_priority; /* member if STP priority */ uint8_t ifbr_proto; /* member if STP protocol */ uint8_t ifbr_role; /* member if STP role */ uint8_t ifbr_state; /* member if STP state */ + uint32_t ifbr_addrcnt; /* member if addr number */ + uint32_t ifbr_addrmax; /* member if addr max */ + uint32_t ifbr_addrexceeded; /* member if addr violations */ + uint8_t pad[32]; }; /* BRDGGIFFLAGS, BRDGSIFFLAGS */ #define IFBIF_LEARNING 0x0001 /* if can learn */ #define IFBIF_DISCOVER 0x0002 /* if sends packets w/ unknown dest. */ #define IFBIF_STP 0x0004 /* if participates in spanning tree */ #define IFBIF_SPAN 0x0008 /* if is a span port */ #define IFBIF_STICKY 0x0010 /* if learned addresses stick */ #define IFBIF_BSTP_EDGE 0x0020 /* member stp edge port */ #define IFBIF_BSTP_AUTOEDGE 0x0040 /* member stp autoedge enabled */ #define IFBIF_BSTP_PTP 0x0080 /* member stp point to point */ #define IFBIF_BSTP_AUTOPTP 0x0100 /* member stp autoptp enabled */ #define IFBIF_BSTP_ADMEDGE 0x0200 /* member stp admin edge enabled */ #define IFBIF_BSTP_ADMCOST 0x0400 /* member stp admin path cost */ #define IFBIF_PRIVATE 0x0800 /* if is a private segment */ #define IFBIFBITS "\020\001LEARNING\002DISCOVER\003STP\004SPAN" \ "\005STICKY\014PRIVATE\006EDGE\007AUTOEDGE\010PTP" \ "\011AUTOPTP" #define IFBIFMASK ~(IFBIF_BSTP_EDGE|IFBIF_BSTP_AUTOEDGE|IFBIF_BSTP_PTP| \ IFBIF_BSTP_AUTOPTP|IFBIF_BSTP_ADMEDGE| \ IFBIF_BSTP_ADMCOST) /* not saved */ /* BRDGFLUSH */ #define IFBF_FLUSHDYN 0x00 /* flush learned addresses only */ #define IFBF_FLUSHALL 0x01 /* flush all addresses */ /* * Interface list structure. */ struct ifbifconf { uint32_t ifbic_len; /* buffer size */ union { caddr_t ifbicu_buf; struct ifbreq *ifbicu_req; } ifbic_ifbicu; #define ifbic_buf ifbic_ifbicu.ifbicu_buf #define ifbic_req ifbic_ifbicu.ifbicu_req }; /* * Bridge address request. */ struct ifbareq { char ifba_ifsname[IFNAMSIZ]; /* member if name */ unsigned long ifba_expire; /* address expire time */ uint8_t ifba_flags; /* address flags */ uint8_t ifba_dst[ETHER_ADDR_LEN];/* destination address */ uint16_t ifba_vlan; /* vlan id */ }; #define IFBAF_TYPEMASK 0x03 /* address type mask */ #define IFBAF_DYNAMIC 0x00 /* dynamically learned address */ #define IFBAF_STATIC 0x01 /* static address */ #define IFBAF_STICKY 0x02 /* sticky address */ #define IFBAFBITS "\020\1STATIC\2STICKY" /* * Address list structure. */ struct ifbaconf { uint32_t ifbac_len; /* buffer size */ union { caddr_t ifbacu_buf; struct ifbareq *ifbacu_req; } ifbac_ifbacu; #define ifbac_buf ifbac_ifbacu.ifbacu_buf #define ifbac_req ifbac_ifbacu.ifbacu_req }; /* * Bridge parameter structure. */ struct ifbrparam { union { uint32_t ifbrpu_int32; uint16_t ifbrpu_int16; uint8_t ifbrpu_int8; } ifbrp_ifbrpu; }; #define ifbrp_csize ifbrp_ifbrpu.ifbrpu_int32 /* cache size */ #define ifbrp_ctime ifbrp_ifbrpu.ifbrpu_int32 /* cache time (sec) */ #define ifbrp_prio ifbrp_ifbrpu.ifbrpu_int16 /* bridge priority */ #define ifbrp_proto ifbrp_ifbrpu.ifbrpu_int8 /* bridge protocol */ #define ifbrp_txhc ifbrp_ifbrpu.ifbrpu_int8 /* bpdu tx holdcount */ #define ifbrp_hellotime ifbrp_ifbrpu.ifbrpu_int8 /* hello time (sec) */ #define ifbrp_fwddelay ifbrp_ifbrpu.ifbrpu_int8 /* fwd time (sec) */ #define ifbrp_maxage ifbrp_ifbrpu.ifbrpu_int8 /* max age (sec) */ #define ifbrp_cexceeded ifbrp_ifbrpu.ifbrpu_int32 /* # of cache dropped * adresses */ /* * Bridge current operational parameters structure. */ struct ifbropreq { uint8_t ifbop_holdcount; uint8_t ifbop_maxage; uint8_t ifbop_hellotime; uint8_t ifbop_fwddelay; uint8_t ifbop_protocol; uint16_t ifbop_priority; uint16_t ifbop_root_port; uint32_t ifbop_root_path_cost; uint64_t ifbop_bridgeid; uint64_t ifbop_designated_root; uint64_t ifbop_designated_bridge; struct timeval ifbop_last_tc_time; }; /* * Bridge member operational STP params structure. */ struct ifbpstpreq { uint8_t ifbp_portno; /* bp STP port number */ uint32_t ifbp_fwd_trans; /* bp STP fwd transitions */ uint32_t ifbp_design_cost; /* bp STP designated cost */ uint32_t ifbp_design_port; /* bp STP designated port */ uint64_t ifbp_design_bridge; /* bp STP designated bridge */ uint64_t ifbp_design_root; /* bp STP designated root */ }; /* * Bridge STP ports list structure. */ struct ifbpstpconf { uint32_t ifbpstp_len; /* buffer size */ union { caddr_t ifbpstpu_buf; struct ifbpstpreq *ifbpstpu_req; } ifbpstp_ifbpstpu; #define ifbpstp_buf ifbpstp_ifbpstpu.ifbpstpu_buf #define ifbpstp_req ifbpstp_ifbpstpu.ifbpstpu_req }; #ifdef _KERNEL #define BRIDGE_LOCK_INIT(_sc) do { \ mtx_init(&(_sc)->sc_mtx, "if_bridge", NULL, MTX_DEF); \ cv_init(&(_sc)->sc_cv, "if_bridge_cv"); \ } while (0) #define BRIDGE_LOCK_DESTROY(_sc) do { \ mtx_destroy(&(_sc)->sc_mtx); \ cv_destroy(&(_sc)->sc_cv); \ } while (0) #define BRIDGE_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) #define BRIDGE_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) #define BRIDGE_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_mtx, MA_OWNED) #define BRIDGE_LOCK2REF(_sc, _err) do { \ mtx_assert(&(_sc)->sc_mtx, MA_OWNED); \ if ((_sc)->sc_iflist_xcnt > 0) \ (_err) = EBUSY; \ else \ (_sc)->sc_iflist_ref++; \ mtx_unlock(&(_sc)->sc_mtx); \ } while (0) #define BRIDGE_UNREF(_sc) do { \ mtx_lock(&(_sc)->sc_mtx); \ (_sc)->sc_iflist_ref--; \ if (((_sc)->sc_iflist_xcnt > 0) && ((_sc)->sc_iflist_ref == 0)) \ cv_broadcast(&(_sc)->sc_cv); \ mtx_unlock(&(_sc)->sc_mtx); \ } while (0) #define BRIDGE_XLOCK(_sc) do { \ mtx_assert(&(_sc)->sc_mtx, MA_OWNED); \ (_sc)->sc_iflist_xcnt++; \ while ((_sc)->sc_iflist_ref > 0) \ cv_wait(&(_sc)->sc_cv, &(_sc)->sc_mtx); \ } while (0) #define BRIDGE_XDROP(_sc) do { \ mtx_assert(&(_sc)->sc_mtx, MA_OWNED); \ (_sc)->sc_iflist_xcnt--; \ } while (0) #define BRIDGE_INPUT(_ifp, _m) do { \ KASSERT(bridge_input_p != NULL, \ ("%s: if_bridge not loaded!", __func__)); \ _m = (*bridge_input_p)(_ifp, _m); \ if (_m != NULL) \ _ifp = _m->m_pkthdr.rcvif; \ } while (0) #define BRIDGE_OUTPUT(_ifp, _m, _err) do { \ KASSERT(bridge_output_p != NULL, \ ("%s: if_bridge not loaded!", __func__)); \ _err = (*bridge_output_p)(_ifp, _m, NULL, NULL); \ } while (0) extern struct mbuf *(*bridge_input_p)(struct ifnet *, struct mbuf *); extern int (*bridge_output_p)(struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *); extern void (*bridge_dn_p)(struct mbuf *, struct ifnet *); #endif /* _KERNEL */