diff options
Diffstat (limited to 'sys/net')
-rw-r--r-- | sys/net/ethernet.h | 6 | ||||
-rw-r--r-- | sys/net/if_bridge.c | 197 | ||||
-rw-r--r-- | sys/net/if_bridgevar.h | 4 | ||||
-rw-r--r-- | sys/net/if_ethersubr.c | 5 | ||||
-rw-r--r-- | sys/net/if_gif.h | 3 | ||||
-rw-r--r-- | sys/net/if_lagg.c | 1 | ||||
-rw-r--r-- | sys/net/if_ovpn.c | 321 | ||||
-rw-r--r-- | sys/net/if_ovpn.h | 1 | ||||
-rw-r--r-- | sys/net/if_tuntap.c | 76 | ||||
-rw-r--r-- | sys/net/if_vlan.c | 12 | ||||
-rw-r--r-- | sys/net/pfvar.h | 17 |
11 files changed, 499 insertions, 144 deletions
diff --git a/sys/net/ethernet.h b/sys/net/ethernet.h index cf4f75bd0b6c..01485cf26e06 100644 --- a/sys/net/ethernet.h +++ b/sys/net/ethernet.h @@ -62,6 +62,8 @@ struct ether_header { u_char ether_shost[ETHER_ADDR_LEN]; u_short ether_type; } __packed; +_Static_assert(sizeof(struct ether_header) == ETHER_HDR_LEN, + "size of struct ether_header is wrong"); /* * Structure of a 48-bit Ethernet address. @@ -69,6 +71,8 @@ struct ether_header { struct ether_addr { u_char octet[ETHER_ADDR_LEN]; } __packed; +_Static_assert(sizeof(struct ether_addr) == ETHER_ADDR_LEN, + "size of struct ether_addr is wrong"); #define ETHER_IS_MULTICAST(addr) (*(addr) & 0x01) /* is address mcast/bcast? */ #define ETHER_IS_IPV6_MULTICAST(addr) \ @@ -112,6 +116,8 @@ struct ether_vlan_header { uint16_t evl_tag; uint16_t evl_proto; } __packed; +_Static_assert(sizeof(struct ether_vlan_header) == ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN, + "size of struct ether_vlan_header is wrong"); #define EVL_VLID_MASK 0x0FFF #define EVL_PRI_MASK 0xE000 diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c index 5b3ee740d75e..0a35fb4095fb 100644 --- a/sys/net/if_bridge.c +++ b/sys/net/if_bridge.c @@ -76,31 +76,34 @@ * heterogeneous bridges). */ -#include <sys/cdefs.h> #include "opt_inet.h" #include "opt_inet6.h" +#define EXTERR_CATEGORY EXTERR_CAT_BRIDGE + #include <sys/param.h> +#include <sys/ctype.h> /* string functions */ #include <sys/eventhandler.h> -#include <sys/mbuf.h> +#include <sys/exterrvar.h> +#include <sys/jail.h> +#include <sys/kernel.h> +#include <sys/lock.h> #include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/module.h> +#include <sys/mutex.h> +#include <sys/priv.h> +#include <sys/proc.h> #include <sys/protosw.h> +#include <sys/random.h> #include <sys/systm.h> -#include <sys/jail.h> -#include <sys/time.h> #include <sys/socket.h> /* for net/if.h */ #include <sys/sockio.h> -#include <sys/ctype.h> /* string functions */ -#include <sys/kernel.h> -#include <sys/random.h> #include <sys/syslog.h> #include <sys/sysctl.h> +#include <sys/time.h> + #include <vm/uma.h> -#include <sys/module.h> -#include <sys/priv.h> -#include <sys/proc.h> -#include <sys/lock.h> -#include <sys/mutex.h> #include <net/bpf.h> #include <net/if.h> @@ -254,8 +257,8 @@ struct bridge_iflist { uint32_t bif_addrcnt; /* cur. # of addresses */ uint32_t bif_addrexceeded;/* # of address violations */ struct epoch_context bif_epoch_ctx; - ether_vlanid_t bif_untagged; /* untagged vlan id */ - ifbvlan_set_t bif_vlan_set; /* allowed tagged vlans */ + ether_vlanid_t bif_pvid; /* port vlan id */ + ifbvlan_set_t bif_vlan_set; /* if allowed tagged vlans */ }; /* @@ -404,7 +407,7 @@ 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_sifuntagged(struct bridge_softc *, void *); +static int bridge_ioctl_sifpvid(struct bridge_softc *, void *); static int bridge_ioctl_sifvlanset(struct bridge_softc *, void *); static int bridge_ioctl_gifvlanset(struct bridge_softc *, void *); static int bridge_ioctl_addspan(struct bridge_softc *, void *); @@ -625,7 +628,7 @@ static const struct bridge_control bridge_control_table[] = { { bridge_ioctl_sifmaxaddr, sizeof(struct ifbreq), BC_F_COPYIN|BC_F_SUSER }, - { bridge_ioctl_sifuntagged, sizeof(struct ifbreq), + { bridge_ioctl_sifpvid, sizeof(struct ifbreq), BC_F_COPYIN|BC_F_SUSER }, { bridge_ioctl_sifvlanset, sizeof(struct ifbif_vlan_req), @@ -986,31 +989,37 @@ bridge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) case SIOCGDRVSPEC: case SIOCSDRVSPEC: if (ifd->ifd_cmd >= bridge_control_table_size) { - error = EINVAL; + error = EXTERROR(EINVAL, "Invalid control command"); break; } bc = &bridge_control_table[ifd->ifd_cmd]; if (cmd == SIOCGDRVSPEC && (bc->bc_flags & BC_F_COPYOUT) == 0) { - error = EINVAL; + error = EXTERROR(EINVAL, + "Inappropriate ioctl for command " + "(expected SIOCSDRVSPEC)"); break; } else if (cmd == SIOCSDRVSPEC && (bc->bc_flags & BC_F_COPYOUT) != 0) { - error = EINVAL; + error = EXTERROR(EINVAL, + "Inappropriate ioctl for command " + "(expected SIOCGDRVSPEC)"); break; } if (bc->bc_flags & BC_F_SUSER) { error = priv_check(td, PRIV_NET_BRIDGE); - if (error) + if (error) { + EXTERROR(error, "PRIV_NET_BRIDGE required"); break; + } } if (ifd->ifd_len != bc->bc_argsize || ifd->ifd_len > sizeof(args)) { - error = EINVAL; + error = EXTERROR(EINVAL, "Invalid argument size"); break; } @@ -1062,7 +1071,8 @@ bridge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) oldmtu = sc->sc_ifp->if_mtu; if (ifr->ifr_mtu < IF_MINMTU) { - error = EINVAL; + error = EXTERROR(EINVAL, + "Requested MTU is lower than IF_MINMTU"); break; } if (CK_LIST_EMPTY(&sc->sc_iflist)) { @@ -1088,6 +1098,8 @@ bridge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) (*bif->bif_ifp->if_ioctl)(bif->bif_ifp, SIOCSIFMTU, (caddr_t)ifr); } + EXTERROR(error, + "Failed to set MTU on member interface"); } else { sc->sc_ifp->if_mtu = ifr->ifr_mtu; } @@ -1125,14 +1137,14 @@ bridge_mutecaps(struct bridge_softc *sc) mask = BRIDGE_IFCAPS_MASK; CK_LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { - /* Every member must support it or its disabled */ + /* Every member must support it or it's disabled */ mask &= bif->bif_savedcaps; } CK_LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { enabled = bif->bif_ifp->if_capenable; enabled &= ~BRIDGE_IFCAPS_STRIP; - /* strip off mask bits and enable them again if allowed */ + /* Strip off mask bits and enable them again if allowed */ enabled &= ~BRIDGE_IFCAPS_MASK; enabled |= mask; bridge_set_ifcap(sc, bif, enabled); @@ -1282,7 +1294,7 @@ bridge_delete_member(struct bridge_softc *sc, struct bridge_iflist *bif, #endif break; } - /* reneable any interface capabilities */ + /* Re-enable any interface capabilities */ bridge_set_ifcap(sc, bif, bif->bif_savedcaps); } bstp_destroy(&bif->bif_stp); /* prepare to free */ @@ -1318,21 +1330,48 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg) ifs = ifunit(req->ifbr_ifsname); if (ifs == NULL) - return (ENOENT); + return (EXTERROR(ENOENT, "No such interface", + req->ifbr_ifsname)); if (ifs->if_ioctl == NULL) /* must be supported */ - return (EINVAL); + return (EXTERROR(EINVAL, "Interface must support ioctl(2)")); + + /* + * If the new interface is a vlan(4), it could be a bridge SVI. + * Don't allow such things to be added to bridges. + */ + if (ifs->if_type == IFT_L2VLAN) { + struct ifnet *parent; + struct epoch_tracker et; + bool is_bridge; + + /* + * Entering NET_EPOCH with BRIDGE_LOCK held, but this is okay + * since we don't sleep here. + */ + NET_EPOCH_ENTER(et); + parent = VLAN_TRUNKDEV(ifs); + is_bridge = (parent != NULL && parent->if_type == IFT_BRIDGE); + NET_EPOCH_EXIT(et); + + if (is_bridge) + return (EXTERROR(EINVAL, + "Bridge SVI cannot be added to a bridge")); + } /* If it's in the span list, it can't be a member. */ CK_LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) if (ifs == bif->bif_ifp) - return (EBUSY); + return (EXTERROR(EBUSY, + "Span interface cannot be a member")); if (ifs->if_bridge) { struct bridge_iflist *sbif = ifs->if_bridge; if (sbif->bif_sc == sc) - return (EEXIST); + return (EXTERROR(EEXIST, + "Interface is already a member of this bridge")); - return (EBUSY); + return (EXTERROR(EBUSY, + "Interface is already a member of another bridge")); } switch (ifs->if_type) { @@ -1342,7 +1381,7 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg) /* permitted interface types */ break; default: - return (EINVAL); + return (EXTERROR(EINVAL, "Unsupported interface type")); } #ifdef INET6 @@ -1394,11 +1433,15 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg) CK_STAILQ_FOREACH(ifa, &ifs->if_addrhead, ifa_link) { #ifdef INET if (ifa->ifa_addr->sa_family == AF_INET) - return (EINVAL); + return (EXTERROR(EINVAL, + "Member interface may not have " + "an IPv4 address configured")); #endif #ifdef INET6 if (ifa->ifa_addr->sa_family == AF_INET6) - return (EINVAL); + return (EXTERROR(EINVAL, + "Member interface may not have " + "an IPv6 address configured")); #endif } } @@ -1420,7 +1463,8 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg) " new member %s\n", sc->sc_ifp->if_xname, ifr.ifr_mtu, ifs->if_xname); - return (EINVAL); + return (EXTERROR(EINVAL, + "Failed to set MTU on new member")); } } @@ -1482,7 +1526,7 @@ bridge_ioctl_del(struct bridge_softc *sc, void *arg) bif = bridge_lookup_member(sc, req->ifbr_ifsname); if (bif == NULL) - return (ENOENT); + return (EXTERROR(ENOENT, "Interface is not a bridge member")); bridge_delete_member(sc, bif, 0); @@ -1498,7 +1542,7 @@ bridge_ioctl_gifflags(struct bridge_softc *sc, void *arg) bif = bridge_lookup_member(sc, req->ifbr_ifsname); if (bif == NULL) - return (ENOENT); + return (EXTERROR(ENOENT, "Interface is not a bridge member")); bp = &bif->bif_stp; req->ifbr_ifsflags = bif->bif_flags; @@ -1512,7 +1556,7 @@ bridge_ioctl_gifflags(struct bridge_softc *sc, void *arg) req->ifbr_addrcnt = bif->bif_addrcnt; req->ifbr_addrmax = bif->bif_addrmax; req->ifbr_addrexceeded = bif->bif_addrexceeded; - req->ifbr_untagged = bif->bif_untagged; + req->ifbr_pvid = bif->bif_pvid; /* Copy STP state options as flags */ if (bp->bp_operedge) @@ -1541,12 +1585,12 @@ bridge_ioctl_sifflags(struct bridge_softc *sc, void *arg) bif = bridge_lookup_member(sc, req->ifbr_ifsname); if (bif == NULL) - return (ENOENT); + return (EXTERROR(ENOENT, "Interface is not a bridge member")); bp = &bif->bif_stp; if (req->ifbr_ifsflags & IFBIF_SPAN) /* SPAN is readonly */ - return (EINVAL); + return (EXTERROR(EINVAL, "Span interface cannot be modified")); NET_EPOCH_ENTER(et); @@ -1555,7 +1599,8 @@ bridge_ioctl_sifflags(struct bridge_softc *sc, void *arg) error = bstp_enable(&bif->bif_stp); if (error) { NET_EPOCH_EXIT(et); - return (error); + return (EXTERROR(error, + "Failed to enable STP")); } } } else { @@ -1724,7 +1769,7 @@ bridge_ioctl_saddr(struct bridge_softc *sc, void *arg) bif = bridge_lookup_member(sc, req->ifba_ifsname); if (bif == NULL) { NET_EPOCH_EXIT(et); - return (ENOENT); + return (EXTERROR(ENOENT, "Interface is not a bridge member")); } /* bridge_rtupdate() may acquire the lock. */ @@ -1858,7 +1903,7 @@ bridge_ioctl_sifprio(struct bridge_softc *sc, void *arg) bif = bridge_lookup_member(sc, req->ifbr_ifsname); if (bif == NULL) - return (ENOENT); + return (EXTERROR(ENOENT, "Interface is not a bridge member")); return (bstp_set_port_priority(&bif->bif_stp, req->ifbr_priority)); } @@ -1871,7 +1916,7 @@ bridge_ioctl_sifcost(struct bridge_softc *sc, void *arg) bif = bridge_lookup_member(sc, req->ifbr_ifsname); if (bif == NULL) - return (ENOENT); + return (EXTERROR(ENOENT, "Interface is not a bridge member")); return (bstp_set_path_cost(&bif->bif_stp, req->ifbr_path_cost)); } @@ -1884,28 +1929,28 @@ bridge_ioctl_sifmaxaddr(struct bridge_softc *sc, void *arg) bif = bridge_lookup_member(sc, req->ifbr_ifsname); if (bif == NULL) - return (ENOENT); + return (EXTERROR(ENOENT, "Interface is not a bridge member")); bif->bif_addrmax = req->ifbr_addrmax; return (0); } static int -bridge_ioctl_sifuntagged(struct bridge_softc *sc, void *arg) +bridge_ioctl_sifpvid(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 (EXTERROR(ENOENT, "Interface is not a bridge member")); - if (req->ifbr_untagged > DOT1Q_VID_MAX) - return (EINVAL); + if (req->ifbr_pvid > DOT1Q_VID_MAX) + return (EXTERROR(EINVAL, "Invalid VLAN ID")); - if (req->ifbr_untagged != DOT1Q_VID_NULL) + if (req->ifbr_pvid != DOT1Q_VID_NULL) bif->bif_flags |= IFBIF_VLANFILTER; - bif->bif_untagged = req->ifbr_untagged; + bif->bif_pvid = req->ifbr_pvid; return (0); } @@ -1917,12 +1962,12 @@ bridge_ioctl_sifvlanset(struct bridge_softc *sc, void *arg) bif = bridge_lookup_member(sc, req->bv_ifname); if (bif == NULL) - return (ENOENT); + return (EXTERROR(ENOENT, "Interface is not a bridge member")); /* Reject invalid VIDs. */ if (BRVLAN_TEST(&req->bv_set, DOT1Q_VID_NULL) || BRVLAN_TEST(&req->bv_set, DOT1Q_VID_RSVD_IMPL)) - return (EINVAL); + return (EXTERROR(EINVAL, "Invalid VLAN ID in set")); switch (req->bv_op) { /* Replace the existing vlan set with the new set */ @@ -1942,7 +1987,8 @@ bridge_ioctl_sifvlanset(struct bridge_softc *sc, void *arg) /* Invalid or unknown operation */ default: - return (EINVAL); + return (EXTERROR(EINVAL, + "Unsupported BRDGSIFVLANSET operation")); } /* @@ -1962,7 +2008,7 @@ bridge_ioctl_gifvlanset(struct bridge_softc *sc, void *arg) bif = bridge_lookup_member(sc, req->bv_ifname); if (bif == NULL) - return (ENOENT); + return (EXTERROR(ENOENT, "Interface is not a bridge member")); BIT_COPY(BRVLAN_SETSIZE, &bif->bif_vlan_set, &req->bv_set); return (0); @@ -1977,14 +2023,16 @@ bridge_ioctl_addspan(struct bridge_softc *sc, void *arg) ifs = ifunit(req->ifbr_ifsname); if (ifs == NULL) - return (ENOENT); + return (EXTERROR(ENOENT, "No such interface")); CK_LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) if (ifs == bif->bif_ifp) - return (EBUSY); + return (EXTERROR(EBUSY, + "Interface is already a span port")); if (ifs->if_bridge != NULL) - return (EBUSY); + return (EXTERROR(EEXIST, + "Interface is already a bridge member")); switch (ifs->if_type) { case IFT_ETHER: @@ -1992,7 +2040,7 @@ bridge_ioctl_addspan(struct bridge_softc *sc, void *arg) case IFT_L2VLAN: break; default: - return (EINVAL); + return (EXTERROR(EINVAL, "Unsupported interface type")); } bif = malloc(sizeof(*bif), M_DEVBUF, M_NOWAIT|M_ZERO); @@ -2016,14 +2064,14 @@ bridge_ioctl_delspan(struct bridge_softc *sc, void *arg) ifs = ifunit(req->ifbr_ifsname); if (ifs == NULL) - return (ENOENT); + return (EXTERROR(ENOENT, "No such interface")); CK_LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) if (ifs == bif->bif_ifp) break; if (bif == NULL) - return (ENOENT); + return (EXTERROR(ENOENT, "Interface is not a span port")); bridge_delete_span(sc, bif); @@ -2278,8 +2326,8 @@ bridge_enqueue(struct bridge_softc *sc, struct ifnet *dst_ifp, struct mbuf *m, * the VLAN header. */ if ((bif->bif_flags & IFBIF_VLANFILTER) && - bif->bif_untagged != DOT1Q_VID_NULL && - VLANTAGOF(m) == bif->bif_untagged) { + bif->bif_pvid != DOT1Q_VID_NULL && + VLANTAGOF(m) == bif->bif_pvid) { m->m_flags &= ~M_VLANTAG; m->m_pkthdr.ether_vtag = 0; } @@ -3145,14 +3193,14 @@ bridge_vfilter_in(const struct bridge_iflist *sbif, struct mbuf *m) * The frame doesn't have a tag. If the interface does not * have an untagged vlan configured, drop the frame. */ - if (sbif->bif_untagged == DOT1Q_VID_NULL) + if (sbif->bif_pvid == DOT1Q_VID_NULL) return (false); /* * Otherwise, insert a new tag based on the interface's * untagged vlan id. */ - m->m_pkthdr.ether_vtag = sbif->bif_untagged; + m->m_pkthdr.ether_vtag = sbif->bif_pvid; m->m_flags |= M_VLANTAG; } else { /* @@ -3213,7 +3261,7 @@ bridge_vfilter_out(const struct bridge_iflist *dbif, const struct mbuf *m) * If the frame's vlan matches the interfaces's untagged vlan, * allow it. */ - if (vlan == dbif->bif_untagged) + if (vlan == dbif->bif_pvid) return (true); /* @@ -3244,10 +3292,11 @@ bridge_rtupdate(struct bridge_softc *sc, const uint8_t *dst, BRIDGE_LOCK_OR_NET_EPOCH_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); + if (ETHER_IS_MULTICAST(dst)) + return (EXTERROR(EINVAL, "Multicast address not permitted")); + if (dst[0] == 0 && dst[1] == 0 && dst[2] == 0 && + dst[3] == 0 && dst[4] == 0 && dst[5] == 0) + return (EXTERROR(EINVAL, "Zero address not permitted")); /* * A route for this destination might already exist. If so, @@ -3266,13 +3315,14 @@ bridge_rtupdate(struct bridge_softc *sc, const uint8_t *dst, if (sc->sc_brtcnt >= sc->sc_brtmax) { sc->sc_brtexceeded++; BRIDGE_RT_UNLOCK(sc); - return (ENOSPC); + return (EXTERROR(ENOSPC, "Address table is full")); } /* Check per interface address limits (if enabled) */ if (bif->bif_addrmax && bif->bif_addrcnt >= bif->bif_addrmax) { bif->bif_addrexceeded++; BRIDGE_RT_UNLOCK(sc); - return (ENOSPC); + return (EXTERROR(ENOSPC, + "Interface address limit exceeded")); } /* @@ -3283,7 +3333,8 @@ bridge_rtupdate(struct bridge_softc *sc, const uint8_t *dst, brt = uma_zalloc(V_bridge_rtnode_zone, M_NOWAIT | M_ZERO); if (brt == NULL) { BRIDGE_RT_UNLOCK(sc); - return (ENOMEM); + return (EXTERROR(ENOMEM, + "Cannot allocate address node")); } brt->brt_vnet = curvnet; @@ -3631,7 +3682,7 @@ bridge_rtnode_insert(struct bridge_softc *sc, struct bridge_rtnode *brt) do { dir = bridge_rtnode_addr_cmp(brt->brt_addr, lbrt->brt_addr); if (dir == 0 && brt->brt_vlan == lbrt->brt_vlan) - return (EEXIST); + return (EXTERROR(EEXIST, "Address already exists")); if (dir > 0) { CK_LIST_INSERT_BEFORE(lbrt, brt, brt_hash); goto out; diff --git a/sys/net/if_bridgevar.h b/sys/net/if_bridgevar.h index 97b63e3d4416..c458dcc152a0 100644 --- a/sys/net/if_bridgevar.h +++ b/sys/net/if_bridgevar.h @@ -124,7 +124,7 @@ #define BRDGSPROTO 28 /* set protocol (ifbrparam) */ #define BRDGSTXHC 29 /* set tx hold count (ifbrparam) */ #define BRDGSIFAMAX 30 /* set max interface addrs (ifbreq) */ -#define BRDGSIFUNTAGGED 31 /* set if untagged vlan */ +#define BRDGSIFPVID 31 /* set if PVID */ #define BRDGSIFVLANSET 32 /* set if vlan set */ #define BRDGGIFVLANSET 33 /* get if vlan set */ @@ -144,7 +144,7 @@ struct ifbreq { uint32_t ifbr_addrcnt; /* member if addr number */ uint32_t ifbr_addrmax; /* member if addr max */ uint32_t ifbr_addrexceeded; /* member if addr violations */ - ether_vlanid_t ifbr_untagged; /* member if untagged vlan */ + ether_vlanid_t ifbr_pvid; /* member if PVID */ uint8_t pad[32]; }; diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index 7be4dfac23e7..3ae0c01c0efc 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -92,11 +92,6 @@ #include <crypto/sha1.h> -#ifdef CTASSERT -CTASSERT(sizeof (struct ether_header) == ETHER_ADDR_LEN * 2 + 2); -CTASSERT(sizeof (struct ether_addr) == ETHER_ADDR_LEN); -#endif - VNET_DEFINE(pfil_head_t, link_pfil_head); /* Packet filter hooks */ /* netgraph node hooks for ng_ether(4) */ diff --git a/sys/net/if_gif.h b/sys/net/if_gif.h index 3c1846b8f82a..c6692d3dd6bc 100644 --- a/sys/net/if_gif.h +++ b/sys/net/if_gif.h @@ -120,7 +120,8 @@ int in6_gif_setopts(struct gif_softc *, u_int); #define GIFGOPTS _IOWR('i', 150, struct ifreq) #define GIFSOPTS _IOW('i', 151, struct ifreq) +#define GIF_NOCLAMP 0x0001 #define GIF_IGNORE_SOURCE 0x0002 -#define GIF_OPTMASK (GIF_IGNORE_SOURCE) +#define GIF_OPTMASK (GIF_NOCLAMP|GIF_IGNORE_SOURCE) #endif /* _NET_IF_GIF_H_ */ diff --git a/sys/net/if_lagg.c b/sys/net/if_lagg.c index 9867a718e148..5b52bfa80e3b 100644 --- a/sys/net/if_lagg.c +++ b/sys/net/if_lagg.c @@ -718,6 +718,7 @@ lagg_capabilities(struct lagg_softc *sc) sc->sc_ifp->if_capenable = ena; sc->sc_ifp->if_capenable2 = ena2; sc->sc_ifp->if_hwassist = hwa; + (void)if_hw_tsomax_update(sc->sc_ifp, &hw_tsomax); getmicrotime(&sc->sc_ifp->if_lastchange); if (sc->sc_ifflags & IFF_DEBUG) diff --git a/sys/net/if_ovpn.c b/sys/net/if_ovpn.c index 7bdbc565f4ca..fe3e7bbd7fff 100644 --- a/sys/net/if_ovpn.c +++ b/sys/net/if_ovpn.c @@ -34,11 +34,13 @@ #include <sys/epoch.h> #include <sys/file.h> #include <sys/filedesc.h> +#include <sys/jail.h> #include <sys/kernel.h> #include <sys/malloc.h> #include <sys/mbuf.h> #include <sys/module.h> #include <sys/nv.h> +#include <sys/osd.h> #include <sys/priv.h> #include <sys/protosw.h> #include <sys/rmlock.h> @@ -79,7 +81,6 @@ #include "if_ovpn.h" struct ovpn_kkey_dir { - int refcount; uint8_t key[32]; uint8_t keylen; uint8_t nonce[8]; @@ -132,6 +133,9 @@ struct ovpn_notification { /* Delete notification */ enum ovpn_del_reason del_reason; struct ovpn_peer_counters counters; + + /* Float notification */ + struct sockaddr_storage address; }; struct ovpn_softc; @@ -196,6 +200,10 @@ struct ovpn_softc { struct epoch_context epoch_ctx; }; +struct ovpn_mtag { + struct sockaddr_storage addr; +}; + static struct ovpn_kpeer *ovpn_find_peer(struct ovpn_softc *, uint32_t); static bool ovpn_udp_input(struct mbuf *, int, struct inpcb *, const struct sockaddr *, void *); @@ -205,7 +213,10 @@ static int ovpn_encap(struct ovpn_softc *, uint32_t, struct mbuf *); static int ovpn_get_af(struct mbuf *); static void ovpn_free_kkey_dir(struct ovpn_kkey_dir *); static bool ovpn_check_replay(struct ovpn_kkey_dir *, uint32_t); -static int ovpn_peer_compare(struct ovpn_kpeer *, struct ovpn_kpeer *); +static int ovpn_peer_compare(const struct ovpn_kpeer *, + const struct ovpn_kpeer *); +static bool ovpn_sockaddr_compare(const struct sockaddr *, + const struct sockaddr *); static RB_PROTOTYPE(ovpn_kpeers, ovpn_kpeer, tree, ovpn_peer_compare); static RB_GENERATE(ovpn_kpeers, ovpn_kpeer, tree, ovpn_peer_compare); @@ -278,11 +289,48 @@ SYSCTL_INT(_net_link_openvpn, OID_AUTO, netisr_queue, "Use netisr_queue() rather than netisr_dispatch()."); static int -ovpn_peer_compare(struct ovpn_kpeer *a, struct ovpn_kpeer *b) +ovpn_peer_compare(const struct ovpn_kpeer *a, const struct ovpn_kpeer *b) { return (a->peerid - b->peerid); } +static bool +ovpn_sockaddr_compare(const struct sockaddr *a, + const struct sockaddr *b) +{ + if (a->sa_family != b->sa_family) + return (false); + MPASS(a->sa_len == b->sa_len); + + switch (a->sa_family) { + case AF_INET: { + const struct sockaddr_in *a4, *b4; + + a4 = (const struct sockaddr_in *)a; + b4 = (const struct sockaddr_in *)b; + + if (a4->sin_port != b4->sin_port) + return (false); + + return (a4->sin_addr.s_addr == b4->sin_addr.s_addr); + } + case AF_INET6: { + const struct sockaddr_in6 *a6, *b6; + + a6 = (const struct sockaddr_in6 *)a; + b6 = (const struct sockaddr_in6 *)b; + + if (a6->sin6_port != b6->sin6_port) + return (false); + + return (memcmp(&a6->sin6_addr, &b6->sin6_addr, + sizeof(a6->sin6_addr)) == 0); + } + default: + panic("Unknown address family %d", a->sa_family); + } +} + static struct ovpn_kpeer * ovpn_find_peer(struct ovpn_softc *sc, uint32_t peerid) { @@ -304,15 +352,15 @@ ovpn_find_only_peer(struct ovpn_softc *sc) } static uint16_t -ovpn_get_port(struct sockaddr_storage *s) +ovpn_get_port(const struct sockaddr_storage *s) { switch (s->ss_family) { case AF_INET: { - struct sockaddr_in *in = (struct sockaddr_in *)s; + const struct sockaddr_in *in = (const struct sockaddr_in *)s; return (in->sin_port); } case AF_INET6: { - struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)s; + const struct sockaddr_in6 *in6 = (const struct sockaddr_in6 *)s; return (in6->sin6_port); } default: @@ -320,6 +368,25 @@ ovpn_get_port(struct sockaddr_storage *s) } } +static void +ovpn_set_port(struct sockaddr_storage *s, unsigned short port) +{ + switch (s->ss_family) { + case AF_INET: { + struct sockaddr_in *in = (struct sockaddr_in *)s; + in->sin_port = port; + break; + } + case AF_INET6: { + struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)s; + in6->sin6_port = port; + break; + } + default: + panic("Unsupported address family %d", s->ss_family); + } +} + static int ovpn_nvlist_to_sockaddr(const nvlist_t *nvl, struct sockaddr_storage *sa) { @@ -333,14 +400,16 @@ ovpn_nvlist_to_sockaddr(const nvlist_t *nvl, struct sockaddr_storage *sa) return (EINVAL); af = nvlist_get_number(nvl, "af"); - switch (af) { #ifdef INET case AF_INET: { struct sockaddr_in *in = (struct sockaddr_in *)sa; size_t len; const void *addr = nvlist_get_binary(nvl, "address", &len); + + memset(in, 0, sizeof(*in)); in->sin_family = af; + in->sin_len = sizeof(*in); if (len != sizeof(in->sin_addr)) return (EINVAL); @@ -354,7 +423,10 @@ ovpn_nvlist_to_sockaddr(const nvlist_t *nvl, struct sockaddr_storage *sa) struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)sa; size_t len; const void *addr = nvlist_get_binary(nvl, "address", &len); + + memset(in6, 0, sizeof(*in6)); in6->sin6_family = af; + in6->sin6_len = sizeof(*in6); if (len != sizeof(in6->sin6_addr)) return (EINVAL); @@ -370,31 +442,42 @@ ovpn_nvlist_to_sockaddr(const nvlist_t *nvl, struct sockaddr_storage *sa) return (0); } -static bool -ovpn_has_peers(struct ovpn_softc *sc) +static int +ovpn_add_sockaddr(nvlist_t *parent, const char *name, const struct sockaddr *s) { - OVPN_ASSERT(sc); - - return (sc->peercount > 0); -} + nvlist_t *nvl; -static void -ovpn_rele_so(struct ovpn_softc *sc) -{ - bool has_peers; + nvl = nvlist_create(0); + if (nvl == NULL) + return (ENOMEM); - OVPN_WASSERT(sc); + nvlist_add_number(nvl, "af", s->sa_family); - if (sc->so == NULL) - return; + switch (s->sa_family) { + case AF_INET: { + const struct sockaddr_in *s4 = (const struct sockaddr_in *)s; - has_peers = ovpn_has_peers(sc); + nvlist_add_number(nvl, "port", s4->sin_port); + nvlist_add_binary(nvl, "address", &s4->sin_addr, + sizeof(s4->sin_addr)); + break; + } + case AF_INET6: { + const struct sockaddr_in6 *s6 = (const struct sockaddr_in6 *)s; - if (! has_peers) { - MPASS(sc->peercount == 0); - } else { - MPASS(sc->peercount > 0); + nvlist_add_number(nvl, "port", s6->sin6_port); + nvlist_add_binary(nvl, "address", &s6->sin6_addr, + sizeof(s6->sin6_addr)); + break; + } + default: + nvlist_destroy(nvl); + return (EINVAL); } + + nvlist_move_nvlist(parent, name, nvl); + + return (0); } static void @@ -449,6 +532,33 @@ ovpn_notify_key_rotation(struct ovpn_softc *sc, struct ovpn_kpeer *peer) } } +static int +ovpn_notify_float(struct ovpn_softc *sc, uint32_t peerid, + const struct sockaddr_storage *remote) +{ + struct ovpn_notification *n; + + n = malloc(sizeof(*n), M_OVPN, M_NOWAIT | M_ZERO); + if (n == NULL) + return (ENOMEM); + + n->peerid = peerid; + n->type = OVPN_NOTIF_FLOAT; + memcpy(&n->address, remote, sizeof(n->address)); + + if (buf_ring_enqueue(sc->notifring, n) != 0) { + free(n, M_OVPN); + return (ENOMEM); + } else if (sc->so != NULL) { + /* Wake up userspace */ + sc->so->so_error = EAGAIN; + sorwakeup(sc->so); + sowwakeup(sc->so); + } + + return (0); +} + static void ovpn_peer_release_ref(struct ovpn_kpeer *peer, bool locked) { @@ -485,8 +595,6 @@ ovpn_peer_release_ref(struct ovpn_kpeer *peer, bool locked) ovpn_free_kkey_dir(peer->keys[i].decrypt); } - ovpn_rele_so(sc); - callout_stop(&peer->ping_send); callout_stop(&peer->ping_rcv); uma_zfree_pcpu(pcpu_zone_4, peer->last_active); @@ -502,7 +610,7 @@ ovpn_new_peer(struct ifnet *ifp, const nvlist_t *nvl) #ifdef INET6 struct epoch_tracker et; #endif - struct sockaddr_storage remote; + struct sockaddr_storage local, remote; struct ovpn_kpeer *peer = NULL; struct file *fp = NULL; struct ovpn_softc *sc = ifp->if_softc; @@ -571,20 +679,37 @@ ovpn_new_peer(struct ifnet *ifp, const nvlist_t *nvl) callout_init_rm(&peer->ping_send, &sc->lock, CALLOUT_SHAREDLOCK); callout_init_rm(&peer->ping_rcv, &sc->lock, 0); - peer->local.ss_len = sizeof(peer->local); - ret = sosockaddr(so, (struct sockaddr *)&peer->local); - if (ret) + memset(&local, 0, sizeof(local)); + local.ss_len = sizeof(local); + ret = sosockaddr(so, (struct sockaddr *)&local); + if (ret != 0) goto error; + if (nvlist_exists_nvlist(nvl, "local")) { + struct sockaddr_storage local1; + + ret = ovpn_nvlist_to_sockaddr(nvlist_get_nvlist(nvl, "local"), + &local1); + if (ret != 0) + goto error; - if (ovpn_get_port(&peer->local) == 0) { + /* + * openvpn doesn't provide a port here when in multihome mode, + * just steal the one the socket is bound to. + */ + if (ovpn_get_port(&local1) == 0) + ovpn_set_port(&local1, ovpn_get_port(&local)); + memcpy(&local, &local1, sizeof(local1)); + } + if (ovpn_get_port(&local) == 0) { ret = EINVAL; goto error; } - if (peer->local.ss_family != remote.ss_family) { + if (local.ss_family != remote.ss_family) { ret = EINVAL; goto error; } + memcpy(&peer->local, &local, sizeof(local)); memcpy(&peer->remote, &remote, sizeof(remote)); #ifdef INET6 @@ -633,6 +758,7 @@ ovpn_new_peer(struct ifnet *ifp, const nvlist_t *nvl) * a new one. */ ret = udp_set_kernel_tunneling(sc->so, NULL, NULL, NULL); + MPASS(ret == 0); sorele(sc->so); sc->so = NULL; } @@ -1364,12 +1490,36 @@ opvn_get_pkt(struct ovpn_softc *sc, nvlist_t **onvl) } nvlist_add_number(nvl, "peerid", n->peerid); nvlist_add_number(nvl, "notification", n->type); - if (n->type == OVPN_NOTIF_DEL_PEER) { + switch (n->type) { + case OVPN_NOTIF_DEL_PEER: { nvlist_add_number(nvl, "del_reason", n->del_reason); /* No error handling, because we want to send the notification * even if we can't attach the counters. */ ovpn_notif_add_counters(nvl, n); + break; + } + case OVPN_NOTIF_FLOAT: { + int ret; + + ret = ovpn_add_sockaddr(nvl, "address", + (struct sockaddr *)&n->address); + + if (ret) { + /* + * Try to re-enqueue the notification. Maybe we'll + * have better luck next time. No error handling, + * because if we fail to re-enqueue there's nothing we can do. + */ + (void)ovpn_notify_float(sc, n->peerid, &n->address); + nvlist_destroy(nvl); + free(n, M_OVPN); + return (ret); + } + break; + } + default: + break; } free(n, M_OVPN); @@ -1525,6 +1675,7 @@ ovpn_finish_rx(struct ovpn_softc *sc, struct mbuf *m, struct rm_priotracker *_ovpn_lock_trackerp) { uint32_t af; + struct m_tag *mtag; OVPN_RASSERT(sc); NET_EPOCH_ASSERT(); @@ -1543,6 +1694,38 @@ ovpn_finish_rx(struct ovpn_softc *sc, struct mbuf *m, OVPN_RUNLOCK(sc); + /* Check if the peer changed to a new source address. */ + mtag = m_tag_find(m, PACKET_TAG_OVPN, NULL); + if (mtag != NULL) { + struct ovpn_mtag *ot = (struct ovpn_mtag *)(mtag + 1); + + OVPN_WLOCK(sc); + + /* + * Check the address against the peer's remote again, because we may race + * against ourselves (i.e. we may have tagged multiple packets to indicate we + * floated). + */ + if (ovpn_sockaddr_compare((struct sockaddr *)&ot->addr, + (struct sockaddr *)&peer->remote)) { + OVPN_WUNLOCK(sc); + goto skip_float; + } + + /* And notify userspace. */ + if (ovpn_notify_float(sc, peer->peerid, &ot->addr) == 0) { + /* + * Update the 'remote' for this peer, but only if + * we've actually enqueued the notification. + * Otherwise we can try again later. + */ + memcpy(&peer->remote, &ot->addr, sizeof(peer->remote)); + } + + OVPN_WUNLOCK(sc); + } + +skip_float: OVPN_COUNTER_ADD(sc, received_data_pkts, 1); OVPN_COUNTER_ADD(sc, tunnel_bytes_received, m->m_pkthdr.len); OVPN_PEER_COUNTER_ADD(peer, pkt_in, 1); @@ -2305,6 +2488,29 @@ ovpn_udp_input(struct mbuf *m, int off, struct inpcb *inp, return (true); } + /* + * If we got this from a different address than we expected tag the packet. + * We'll deal with notifiying userspace later, after we've decrypted and + * verified. + */ + if (! ovpn_sockaddr_compare((struct sockaddr *)&peer->remote, sa)) { + struct m_tag *mt; + struct ovpn_mtag *ot; + + MPASS(sa->sa_len <= sizeof(ot->addr)); + mt = m_tag_get(PACKET_TAG_OVPN, sizeof(*ot), M_NOWAIT); + /* + * If we fail to allocate here we'll just try again on the next + * packet. + */ + if (mt != NULL) { + ot = (struct ovpn_mtag *)(mt + 1); + memcpy(&ot->addr, sa, sa->sa_len); + + m_tag_prepend(m, mt); + } + } + if (key->decrypt->cipher == OVPN_CIPHER_ALG_NONE) { /* Now remove the outer headers */ m_adj_decap(m, sizeof(struct udphdr) + ohdrlen); @@ -2519,6 +2725,7 @@ ovpn_clone_destroy_cb(struct epoch_context *ctx) COUNTER_ARRAY_FREE(sc->counters, OVPN_COUNTER_SIZE); + rm_destroy(&sc->lock); if_free(sc->ifp); free(sc, M_OVPN); } @@ -2579,23 +2786,53 @@ vnet_ovpn_init(const void *unused __unused) VNET_SYSINIT(vnet_ovpn_init, SI_SUB_PSEUDO, SI_ORDER_ANY, vnet_ovpn_init, NULL); -static void -vnet_ovpn_uninit(const void *unused __unused) +static int +ovpn_prison_remove(void *obj, void *data __unused) { - if_clone_detach(V_ovpn_cloner); +#ifdef VIMAGE + struct prison *pr; + + pr = obj; + if (prison_owns_vnet(pr)) { + CURVNET_SET(pr->pr_vnet); + if (V_ovpn_cloner != NULL) { + ifc_detach_cloner(V_ovpn_cloner); + V_ovpn_cloner = NULL; + } + CURVNET_RESTORE(); + } +#endif + return (0); } -VNET_SYSUNINIT(vnet_ovpn_uninit, SI_SUB_PSEUDO, SI_ORDER_ANY, - vnet_ovpn_uninit, NULL); static int ovpnmodevent(module_t mod, int type, void *data) { + static int ovpn_osd_jail_slot; + switch (type) { - case MOD_LOAD: - /* Done in vnet_ovpn_init() */ + case MOD_LOAD: { + /* + * Registration is handled in vnet_ovpn_init(), but cloned + * interfaces must be destroyed via PR_METHOD_REMOVE since they + * hold a reference to the prison via the UDP socket, which + * prevents the prison from being destroyed. + */ + osd_method_t methods[PR_MAXMETHOD] = { + [PR_METHOD_REMOVE] = ovpn_prison_remove, + }; + ovpn_osd_jail_slot = osd_jail_register(NULL, methods); break; + } case MOD_UNLOAD: - /* Done in vnet_ovpn_uninit() */ + if (ovpn_osd_jail_slot != 0) + osd_jail_deregister(ovpn_osd_jail_slot); + CURVNET_SET(vnet0); + if (V_ovpn_cloner != NULL) { + ifc_detach_cloner(V_ovpn_cloner); + V_ovpn_cloner = NULL; + } + CURVNET_RESTORE(); break; default: return (EOPNOTSUPP); diff --git a/sys/net/if_ovpn.h b/sys/net/if_ovpn.h index 2d6b8c1e7eff..2a24c35788a9 100644 --- a/sys/net/if_ovpn.h +++ b/sys/net/if_ovpn.h @@ -37,6 +37,7 @@ enum ovpn_notif_type { OVPN_NOTIF_DEL_PEER, OVPN_NOTIF_ROTATE_KEY, + OVPN_NOTIF_FLOAT, }; enum ovpn_del_reason { diff --git a/sys/net/if_tuntap.c b/sys/net/if_tuntap.c index 3bab04aa4d38..5e6f65c04b2f 100644 --- a/sys/net/if_tuntap.c +++ b/sys/net/if_tuntap.c @@ -74,6 +74,7 @@ #include <sys/malloc.h> #include <sys/random.h> #include <sys/ctype.h> +#include <sys/osd.h> #include <net/ethernet.h> #include <net/if.h> @@ -178,6 +179,7 @@ struct tuntap_softc { static struct mtx tunmtx; static eventhandler_tag arrival_tag; static eventhandler_tag clone_tag; +static int tuntap_osd_jail_slot; static const char tunname[] = "tun"; static const char tapname[] = "tap"; static const char vmnetname[] = "vmnet"; @@ -497,6 +499,10 @@ vmnet_clone_match(struct if_clone *ifc, const char *name) return (0); } +/* + * Create a clone via the ifnet cloning mechanism. Note that this is invoked + * indirectly by tunclone() below. + */ static int tun_clone_create(struct if_clone *ifc, char *name, size_t len, struct ifc_data *ifd, struct ifnet **ifpp) @@ -532,15 +538,19 @@ tun_clone_create(struct if_clone *ifc, char *name, size_t len, if (i != 0) i = tun_create_device(drv, unit, NULL, &dev, name); if (i == 0) { - dev_ref(dev); + struct tuntap_softc *tp; + tuncreate(dev); - struct tuntap_softc *tp = dev->si_drv1; + tp = dev->si_drv1; *ifpp = tp->tun_ifp; } return (i); } +/* + * Create a clone via devfs access. + */ static void tunclone(void *arg, struct ucred *cred, char *name, int namelen, struct cdev **dev) @@ -595,11 +605,12 @@ tunclone(void *arg, struct ucred *cred, char *name, int namelen, } i = tun_create_device(drv, u, cred, dev, name); - } - if (i == 0) { + } else { + /* Consumed by the dev_clone invoker. */ dev_ref(*dev); - if_clone_create(name, namelen, NULL); } + if (i == 0) + if_clone_create(name, namelen, NULL); out: CURVNET_RESTORE(); } @@ -670,16 +681,6 @@ VNET_SYSINIT(vnet_tun_init, SI_SUB_PROTO_IF, SI_ORDER_ANY, vnet_tun_init, NULL); static void -vnet_tun_uninit(const void *unused __unused) -{ - - for (u_int i = 0; i < NDRV; ++i) - if_clone_detach(V_tuntap_driver_cloners[i]); -} -VNET_SYSUNINIT(vnet_tun_uninit, SI_SUB_PROTO_IF, SI_ORDER_ANY, - vnet_tun_uninit, NULL); - -static void tun_uninit(const void *unused __unused) { struct tuntap_driver *drv; @@ -689,6 +690,16 @@ tun_uninit(const void *unused __unused) EVENTHANDLER_DEREGISTER(ifnet_arrival_event, arrival_tag); EVENTHANDLER_DEREGISTER(dev_clone, clone_tag); + CURVNET_SET(vnet0); + for (u_int i = 0; i < NDRV; i++) { + if_clone_detach(V_tuntap_driver_cloners[i]); + V_tuntap_driver_cloners[i] = NULL; + } + CURVNET_RESTORE(); + + if (tuntap_osd_jail_slot != 0) + osd_jail_deregister(tuntap_osd_jail_slot); + mtx_lock(&tunmtx); while ((tp = TAILQ_FIRST(&tunhead)) != NULL) { TAILQ_REMOVE(&tunhead, tp, tun_list); @@ -724,6 +735,30 @@ tuntap_driver_from_ifnet(const struct ifnet *ifp) return (NULL); } +/* + * Remove devices that were created by devfs cloning, as they hold references + * which prevent the prison from collapsing, in which state VNET sysuninits will + * not be invoked. + */ +static int +tuntap_prison_remove(void *obj, void *data __unused) +{ +#ifdef VIMAGE + struct prison *pr; + + pr = obj; + if (prison_owns_vnet(pr)) { + CURVNET_SET(pr->pr_vnet); + for (u_int i = 0; i < NDRV; i++) { + if_clone_detach(V_tuntap_driver_cloners[i]); + V_tuntap_driver_cloners[i] = NULL; + } + CURVNET_RESTORE(); + } +#endif + return (0); +} + static int tuntapmodevent(module_t mod, int type, void *data) { @@ -738,8 +773,12 @@ tuntapmodevent(module_t mod, int type, void *data) clone_setup(&drv->clones); drv->unrhdr = new_unrhdr(0, IF_MAXUNIT, &tunmtx); } + osd_method_t methods[PR_MAXMETHOD] = { + [PR_METHOD_REMOVE] = tuntap_prison_remove, + }; + tuntap_osd_jail_slot = osd_jail_register(NULL, methods); arrival_tag = EVENTHANDLER_REGISTER(ifnet_arrival_event, - tunrename, 0, 1000); + tunrename, 0, 1000); if (arrival_tag == NULL) return (ENOMEM); clone_tag = EVENTHANDLER_REGISTER(dev_clone, tunclone, 0, 1000); @@ -747,7 +786,7 @@ tuntapmodevent(module_t mod, int type, void *data) return (ENOMEM); break; case MOD_UNLOAD: - /* See tun_uninit, so it's done after the vnet_sysuninit() */ + /* See tun_uninit(). */ break; default: return EOPNOTSUPP; @@ -798,6 +837,8 @@ tun_create_device(struct tuntap_driver *drv, int unit, struct ucred *cr, args.mda_si_drv1 = tp; error = make_dev_s(&args, dev, "%s", name); if (error != 0) { + mtx_destroy(&tp->tun_mtx); + cv_destroy(&tp->tun_cv); free(tp, M_TUN); return (error); } @@ -914,7 +955,6 @@ tap_transmit(struct ifnet *ifp, struct mbuf *m) return (error); } -/* XXX: should return an error code so it can fail. */ static void tuncreate(struct cdev *dev) { diff --git a/sys/net/if_vlan.c b/sys/net/if_vlan.c index 22fcb7bf7c64..61000018e5a4 100644 --- a/sys/net/if_vlan.c +++ b/sys/net/if_vlan.c @@ -2336,6 +2336,18 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) error = ENOENT; break; } + + /* + * If the ifp is in a bridge, do not allow setting the device + * to a bridge; this prevents having a bridge SVI as a bridge + * member (which is not permitted). + */ + if (ifp->if_bridge != NULL && p->if_type == IFT_BRIDGE) { + if_rele(p); + error = EINVAL; + break; + } + if (vlr.vlr_proto == 0) vlr.vlr_proto = ETHERTYPE_VLAN; oldmtu = ifp->if_mtu; diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index 36fab1a03ee6..d55afe750869 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -331,6 +331,14 @@ MALLOC_DECLARE(M_PF_RULE_ITEM); SDT_PROVIDER_DECLARE(pf); SDT_PROBE_DECLARE(pf, , test, reason_set); +SDT_PROBE_DECLARE(pf, , log, log); + +#define DPFPRINTF(n, fmt, x...) \ + do { \ + SDT_PROBE2(pf, , log, log, (n), fmt); \ + if (V_pf_status.debug >= (n)) \ + printf(fmt "\n", ##x); \ + } while (0) struct pfi_dynaddr { TAILQ_ENTRY(pfi_dynaddr) entry; @@ -1370,7 +1378,6 @@ struct pf_kruleset { struct pf_krulequeue queues[2]; struct { struct pf_krulequeue *ptr; - struct pf_krule **ptr_array; u_int32_t rcount; u_int32_t ticket; int open; @@ -1677,6 +1684,9 @@ struct pf_pdesc { u_int32_t fragoff; /* fragment header offset */ u_int32_t jumbolen; /* length from v6 jumbo header */ u_int32_t badopts; /* v4 options or v6 routing headers */ +#define PF_OPT_OTHER 0x0001 +#define PF_OPT_JUMBO 0x0002 +#define PF_OPT_ROUTER_ALERT 0x0004 u_int16_t *ip_sum; u_int16_t flags; /* Let SCRUB trigger behavior in @@ -2500,7 +2510,7 @@ int pfr_match_addr(struct pfr_ktable *, struct pf_addr *, sa_family_t); void pfr_update_stats(struct pfr_ktable *, struct pf_addr *, sa_family_t, u_int64_t, int, int, int); int pfr_pool_get(struct pfr_ktable *, int *, struct pf_addr *, sa_family_t, - pf_addr_filter_func_t); + pf_addr_filter_func_t, bool); void pfr_dynaddr_update(struct pfr_ktable *, struct pfi_dynaddr *); struct pfr_ktable * pfr_attach_table(struct pf_kruleset *, char *); @@ -2534,6 +2544,8 @@ int pfr_ina_rollback(struct pfr_table *, u_int32_t, int *, int); int pfr_ina_commit(struct pfr_table *, u_int32_t, int *, int *, int); int pfr_ina_define(struct pfr_table *, struct pfr_addr *, int, int *, int *, u_int32_t, int); +struct pfr_ktable + *pfr_ktable_select_active(struct pfr_ktable *); MALLOC_DECLARE(PFI_MTYPE); VNET_DECLARE(struct pfi_kkif *, pfi_all); @@ -2712,7 +2724,6 @@ u_short pf_map_addr(u_int8_t, struct pf_krule *, u_short pf_map_addr_sn(u_int8_t, struct pf_krule *, struct pf_addr *, struct pf_addr *, struct pfi_kkif **nkif, struct pf_addr *, - struct pf_ksrc_node **, struct pf_srchash **, struct pf_kpool *, pf_sn_types_t); int pf_get_transaddr_af(struct pf_krule *, struct pf_pdesc *); |