diff options
-rw-r--r-- | sys/net/if.c | 8 | ||||
-rw-r--r-- | sys/net/if.h | 7 | ||||
-rw-r--r-- | sys/net/if_ethersubr.c | 48 | ||||
-rw-r--r-- | sys/net/if_llc.h | 1 | ||||
-rw-r--r-- | sys/net/if_types.h | 1 | ||||
-rw-r--r-- | sys/net/if_var.h | 2 | ||||
-rw-r--r-- | sys/netinet/if_ether.c | 12 | ||||
-rw-r--r-- | sys/sys/sockio.h | 5 |
8 files changed, 80 insertions, 4 deletions
diff --git a/sys/net/if.c b/sys/net/if.c index a39b2accf535..d244f4e9d455 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -93,6 +93,7 @@ SYSCTL_INT(_net_link, OID_AUTO, log_link_state_change, CTLFLAG_RW, &log_link_state_change, 0, "log interface link state change events"); +void (*bstp_linkstate_p)(struct ifnet *ifp, int state); void (*ng_ether_link_state_p)(struct ifnet *ifp, int state); struct mbuf *(*tbr_dequeue_ptr)(struct ifaltq *, int) = NULL; @@ -337,6 +338,7 @@ if_findindex(struct ifnet *ifp) case IFT_XETHER: case IFT_ISO88025: case IFT_L2VLAN: + case IFT_BRIDGE: snprintf(eaddr, 18, "%6D", IFP2AC(ifp)->ac_enaddr, ":"); break; default: @@ -1049,6 +1051,11 @@ do_link_state_change(void *arg, int pending) if (ifp->if_carp) carp_carpdev_state(ifp->if_carp); #endif + if (ifp->if_bridge) { + KASSERT(bstp_linkstate_p != NULL,("if_bridge bstp not loaded!")); + (*bstp_linkstate_p)(ifp, link_state); + } + if (pending > 1) if_printf(ifp, "%d link states coalesced\n", pending); if (log_link_state_change) @@ -1932,6 +1939,7 @@ if_setlladdr(struct ifnet *ifp, const u_char *lladdr, int len) case IFT_XETHER: case IFT_ISO88025: case IFT_L2VLAN: + case IFT_BRIDGE: bcopy(lladdr, IFP2AC(ifp)->ac_enaddr, len); /* * XXX We also need to store the lladdr in LLADDR(sdl), diff --git a/sys/net/if.h b/sys/net/if.h index b4d5bdbed3b9..39bff634af75 100644 --- a/sys/net/if.h +++ b/sys/net/if.h @@ -281,6 +281,13 @@ struct ifmediareq { int *ifm_ulist; /* media words */ }; +struct ifdrv { + char ifd_name[IFNAMSIZ]; /* if name, e.g. "en0" */ + unsigned long ifd_cmd; + size_t ifd_len; + void *ifd_data; +}; + /* * Structure used to retrieve aux status data from interfaces. * Kernel suppliers to this interface should respect the formatting diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index 7f4b1ce5adf3..7c62f374995b 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -114,6 +114,10 @@ bdg_forward_t *bdg_forward_ptr; bdgtakeifaces_t *bdgtakeifaces_ptr; struct bdg_softc *ifp2sc; +struct mbuf *(*bridge_input_p)(struct ifnet *, struct mbuf *); +int (*bridge_output_p)(struct ifnet *, struct mbuf *, + struct sockaddr *, struct rtentry *); + static const u_char etherbroadcastaddr[ETHER_ADDR_LEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; @@ -283,6 +287,15 @@ ether_output(struct ifnet *ifp, struct mbuf *m, (void)memcpy(eh->ether_shost, IFP2AC(ifp)->ac_enaddr, sizeof(eh->ether_shost)); + /* + * Bridges require special output handling. + */ + if (ifp->if_bridge) { + KASSERT(bridge_output_p != NULL, + ("ether_input: if_bridge not loaded!")); + return ((*bridge_output_p)(ifp, m, NULL, NULL)); + } + /* * If a simplex interface, and the packet is being sent to our * Ethernet address or a broadcast address, loopback a copy. @@ -577,6 +590,41 @@ ether_input(struct ifnet *ifp, struct mbuf *m) return; } + /* + * Tap the packet off here for a bridge. bridge_input() + * will return NULL if it has consumed the packet, otherwise + * it gets processed as normal. Note that bridge_input() + * will always return the original packet if we need to + * process it locally. + */ + if (ifp->if_bridge) { + KASSERT(bridge_input_p != NULL, + ("ether_input: if_bridge not loaded!")); + + /* Mark the packet as broadcast or multicast. This is also set + * further down the code in ether_demux() but since the bridge + * input routine rarely returns a mbuf for further processing, + * it is an acceptable duplication. + */ + if (ETHER_IS_MULTICAST(eh->ether_dhost)) { + if (bcmp(etherbroadcastaddr, eh->ether_dhost, + sizeof(etherbroadcastaddr)) == 0) + m->m_flags |= M_BCAST; + else + m->m_flags |= M_MCAST; + } + + m = (*bridge_input_p)(ifp, m); + if (m == NULL) + return; + /* + * Bridge has determined that the packet is for us. + * Update our interface pointer -- we may have had + * to "bridge" the packet locally. + */ + ifp = m->m_pkthdr.rcvif; + } + /* Check for bridging mode */ if (BDG_ACTIVE(ifp) ) if ((m = bridge_in_ptr(ifp, m)) == NULL) diff --git a/sys/net/if_llc.h b/sys/net/if_llc.h index afdcda8d7c7d..8d96686c0aac 100644 --- a/sys/net/if_llc.h +++ b/sys/net/if_llc.h @@ -149,6 +149,7 @@ struct frmrinfo { /* * ISO PDTR 10178 contains among others */ +#define LLC_8021D_LSAP 0x42 #define LLC_X25_LSAP 0x7e #define LLC_SNAP_LSAP 0xaa #define LLC_ISO_LSAP 0xfe diff --git a/sys/net/if_types.h b/sys/net/if_types.h index e60b65dca961..1dff5c295de7 100644 --- a/sys/net/if_types.h +++ b/sys/net/if_types.h @@ -238,6 +238,7 @@ #define IFT_ATMVCIENDPT 0xc2 /* ATM VCI End Point */ #define IFT_OPTICALCHANNEL 0xc3 /* Optical Channel */ #define IFT_OPTICALTRANSPORT 0xc4 /* Optical Transport */ +#define IFT_BRIDGE 0xd1 /* Transparent bridge interface */ #define IFT_STF 0xd7 /* 6to4 interface */ diff --git a/sys/net/if_var.h b/sys/net/if_var.h index 6a17905b0958..b189a7006b10 100644 --- a/sys/net/if_var.h +++ b/sys/net/if_var.h @@ -184,6 +184,8 @@ struct ifnet { struct ifaltq if_snd; /* output queue (includes altq) */ const u_int8_t *if_broadcastaddr; /* linklevel broadcast bytestring */ + void *if_bridge; /* bridge glue */ + struct lltable *lltables; /* list of L3-L2 resolution tables */ struct label *if_label; /* interface MAC label */ diff --git a/sys/netinet/if_ether.c b/sys/netinet/if_ether.c index 56d411dc2ddd..83e5449bb5f3 100644 --- a/sys/netinet/if_ether.c +++ b/sys/netinet/if_ether.c @@ -553,10 +553,14 @@ in_arpinput(m) u_int8_t *enaddr = NULL; int op, rif_len; int req_len; + int bridged = 0; #ifdef DEV_CARP int carp_match = 0; #endif + if (do_bridge || ifp->if_bridge) + bridged = 1; + req_len = arphdr_len2(ifp->if_addrlen, sizeof(struct in_addr)); if (m->m_len < req_len && (m = m_pullup(m, req_len)) == NULL) { log(LOG_ERR, "in_arp: runt packet -- m_pullup failed\n"); @@ -578,7 +582,7 @@ in_arpinput(m) * XXX: This is really ugly! */ LIST_FOREACH(ia, INADDR_HASH(itaddr.s_addr), ia_hash) { - if ((do_bridge || (ia->ia_ifp == ifp)) && + if ((bridged || (ia->ia_ifp == ifp)) && itaddr.s_addr == ia->ia_addr.sin_addr.s_addr) goto match; #ifdef DEV_CARP @@ -591,7 +595,7 @@ in_arpinput(m) #endif } LIST_FOREACH(ia, INADDR_HASH(isaddr.s_addr), ia_hash) - if ((do_bridge || (ia->ia_ifp == ifp)) && + if ((bridged || (ia->ia_ifp == ifp)) && isaddr.s_addr == ia->ia_addr.sin_addr.s_addr) goto match; /* @@ -606,7 +610,7 @@ in_arpinput(m) /* * If bridging, fall back to using any inet address. */ - if (!do_bridge || (ia = TAILQ_FIRST(&in_ifaddrhead)) == NULL) + if (!bridged || (ia = TAILQ_FIRST(&in_ifaddrhead)) == NULL) goto drop; match: if (!enaddr) @@ -639,7 +643,7 @@ match: la = arplookup(isaddr.s_addr, itaddr.s_addr == myaddr.s_addr, 0); if (la && (rt = la->la_rt) && (sdl = SDL(rt->rt_gateway))) { /* the following is not an error when doing bridging */ - if (!do_bridge && rt->rt_ifp != ifp + if (!bridged && rt->rt_ifp != ifp #ifdef DEV_CARP && (ifp->if_type != IFT_CARP || !carp_match) #endif diff --git a/sys/sys/sockio.h b/sys/sys/sockio.h index 4c064e25450f..82059a43d988 100644 --- a/sys/sys/sockio.h +++ b/sys/sys/sockio.h @@ -105,6 +105,11 @@ #define SIOCGPRIVATE_0 _IOWR('i', 80, struct ifreq) /* device private 0 */ #define SIOCGPRIVATE_1 _IOWR('i', 81, struct ifreq) /* device private 1 */ +#define SIOCSDRVSPEC _IOW('i', 123, struct ifdrv) /* set driver-specific + parameters */ +#define SIOCGDRVSPEC _IOWR('i', 123, struct ifdrv) /* get driver-specific + parameters */ + #define SIOCIFCREATE _IOWR('i', 122, struct ifreq) /* create clone if */ #define SIOCIFDESTROY _IOW('i', 121, struct ifreq) /* destroy clone if */ #define SIOCIFGCLONERS _IOWR('i', 120, struct if_clonereq) /* get cloners */ |