Changeset View
Changeset View
Standalone View
Standalone View
head/sys/net/if_bridge.c
Show First 20 Lines • Show All 327 Lines • ▼ Show 20 Lines | |||||
static int bridge_ioctl_sproto(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_ioctl_stxhc(struct bridge_softc *, void *); | ||||
static int bridge_pfil(struct mbuf **, struct ifnet *, struct ifnet *, | static int bridge_pfil(struct mbuf **, struct ifnet *, struct ifnet *, | ||||
int); | int); | ||||
static int bridge_ip_checkbasic(struct mbuf **mp); | static int bridge_ip_checkbasic(struct mbuf **mp); | ||||
#ifdef INET6 | #ifdef INET6 | ||||
static int bridge_ip6_checkbasic(struct mbuf **mp); | static int bridge_ip6_checkbasic(struct mbuf **mp); | ||||
#endif /* INET6 */ | #endif /* INET6 */ | ||||
static int bridge_fragment(struct ifnet *, struct mbuf *, | static int bridge_fragment(struct ifnet *, struct mbuf **mp, | ||||
struct ether_header *, int, struct llc *); | struct ether_header *, int, struct llc *); | ||||
static void bridge_linkstate(struct ifnet *ifp); | static void bridge_linkstate(struct ifnet *ifp); | ||||
static void bridge_linkcheck(struct bridge_softc *sc); | static void bridge_linkcheck(struct bridge_softc *sc); | ||||
extern void (*bridge_linkstate_p)(struct ifnet *ifp); | extern void (*bridge_linkstate_p)(struct ifnet *ifp); | ||||
/* The default bridge vlan is 1 (IEEE 802.1Q-2003 Table 9-2) */ | /* The default bridge vlan is 1 (IEEE 802.1Q-2003 Table 9-2) */ | ||||
#define VLANTAGOF(_m) \ | #define VLANTAGOF(_m) \ | ||||
▲ Show 20 Lines • Show All 1,567 Lines • ▼ Show 20 Lines | if ((m->m_flags & M_VLANTAG) && | ||||
if_printf(dst_ifp, | if_printf(dst_ifp, | ||||
"unable to prepend VLAN header\n"); | "unable to prepend VLAN header\n"); | ||||
if_inc_counter(dst_ifp, IFCOUNTER_OERRORS, 1); | if_inc_counter(dst_ifp, IFCOUNTER_OERRORS, 1); | ||||
continue; | continue; | ||||
} | } | ||||
m->m_flags &= ~M_VLANTAG; | m->m_flags &= ~M_VLANTAG; | ||||
} | } | ||||
M_ASSERTPKTHDR(m); /* We shouldn't transmit mbuf without pkthdr */ | |||||
if ((err = dst_ifp->if_transmit(dst_ifp, m))) { | if ((err = dst_ifp->if_transmit(dst_ifp, m))) { | ||||
m_freem(m0); | m_freem(m0); | ||||
if_inc_counter(sc->sc_ifp, IFCOUNTER_OERRORS, 1); | if_inc_counter(sc->sc_ifp, IFCOUNTER_OERRORS, 1); | ||||
break; | break; | ||||
} | } | ||||
if_inc_counter(sc->sc_ifp, IFCOUNTER_OPACKETS, 1); | if_inc_counter(sc->sc_ifp, IFCOUNTER_OPACKETS, 1); | ||||
if_inc_counter(sc->sc_ifp, IFCOUNTER_OBYTES, len); | if_inc_counter(sc->sc_ifp, IFCOUNTER_OBYTES, len); | ||||
▲ Show 20 Lines • Show All 1,301 Lines • ▼ Show 20 Lines | case ETHERTYPE_IP: | ||||
if (V_pfil_bridge && dir == PFIL_IN && bifp != NULL) | if (V_pfil_bridge && dir == PFIL_IN && bifp != NULL) | ||||
error = pfil_run_hooks(&V_inet_pfil_hook, mp, bifp, | error = pfil_run_hooks(&V_inet_pfil_hook, mp, bifp, | ||||
dir, NULL); | dir, NULL); | ||||
if (*mp == NULL || error != 0) /* filter may consume */ | if (*mp == NULL || error != 0) /* filter may consume */ | ||||
break; | break; | ||||
/* check if we need to fragment the packet */ | /* check if we need to fragment the packet */ | ||||
/* bridge_fragment generates a mbuf chain of packets */ | |||||
/* that already include eth headers */ | |||||
if (V_pfil_member && ifp != NULL && dir == PFIL_OUT) { | if (V_pfil_member && ifp != NULL && dir == PFIL_OUT) { | ||||
i = (*mp)->m_pkthdr.len; | i = (*mp)->m_pkthdr.len; | ||||
if (i > ifp->if_mtu) { | if (i > ifp->if_mtu) { | ||||
error = bridge_fragment(ifp, *mp, &eh2, snap, | error = bridge_fragment(ifp, mp, &eh2, snap, | ||||
&llc1); | &llc1); | ||||
return (error); | return (error); | ||||
} | } | ||||
} | } | ||||
/* Recalculate the ip checksum. */ | /* Recalculate the ip checksum. */ | ||||
ip = mtod(*mp, struct ip *); | ip = mtod(*mp, struct ip *); | ||||
hlen = ip->ip_hl << 2; | hlen = ip->ip_hl << 2; | ||||
▲ Show 20 Lines • Show All 222 Lines • ▼ Show 20 Lines | bad: | ||||
*mp = m; | *mp = m; | ||||
return (-1); | return (-1); | ||||
} | } | ||||
#endif /* INET6 */ | #endif /* INET6 */ | ||||
/* | /* | ||||
* bridge_fragment: | * bridge_fragment: | ||||
* | * | ||||
* Return a fragmented mbuf chain. | * Fragment mbuf chain in multiple packets and prepend ethernet header. | ||||
*/ | */ | ||||
static int | static int | ||||
bridge_fragment(struct ifnet *ifp, struct mbuf *m, struct ether_header *eh, | bridge_fragment(struct ifnet *ifp, struct mbuf **mp, struct ether_header *eh, | ||||
int snap, struct llc *llc) | int snap, struct llc *llc) | ||||
{ | { | ||||
struct mbuf *m0; | struct mbuf *m = *mp, *nextpkt = NULL, *mprev = NULL, *mcur = NULL; | ||||
struct ip *ip; | struct ip *ip; | ||||
int error = -1; | int error = -1; | ||||
if (m->m_len < sizeof(struct ip) && | if (m->m_len < sizeof(struct ip) && | ||||
(m = m_pullup(m, sizeof(struct ip))) == NULL) | (m = m_pullup(m, sizeof(struct ip))) == NULL) | ||||
goto out; | goto dropit; | ||||
ip = mtod(m, struct ip *); | ip = mtod(m, struct ip *); | ||||
m->m_pkthdr.csum_flags |= CSUM_IP; | m->m_pkthdr.csum_flags |= CSUM_IP; | ||||
error = ip_fragment(ip, &m, ifp->if_mtu, ifp->if_hwassist); | error = ip_fragment(ip, &m, ifp->if_mtu, ifp->if_hwassist); | ||||
if (error) | if (error) | ||||
goto out; | goto dropit; | ||||
/* walk the chain and re-add the Ethernet header */ | /* | ||||
for (m0 = m; m0; m0 = m0->m_nextpkt) { | * Walk the chain and re-add the Ethernet header for | ||||
if (error == 0) { | * each mbuf packet. | ||||
*/ | |||||
for (mcur = m; mcur; mcur = mcur->m_nextpkt) { | |||||
nextpkt = mcur->m_nextpkt; | |||||
mcur->m_nextpkt = NULL; | |||||
if (snap) { | if (snap) { | ||||
M_PREPEND(m0, sizeof(struct llc), M_NOWAIT); | M_PREPEND(mcur, sizeof(struct llc), M_NOWAIT); | ||||
if (m0 == NULL) { | if (mcur == NULL) { | ||||
error = ENOBUFS; | error = ENOBUFS; | ||||
continue; | if (mprev != NULL) | ||||
mprev->m_nextpkt = nextpkt; | |||||
goto dropit; | |||||
} | } | ||||
bcopy(llc, mtod(m0, caddr_t), | bcopy(llc, mtod(mcur, caddr_t),sizeof(struct llc)); | ||||
sizeof(struct llc)); | |||||
} | } | ||||
M_PREPEND(m0, ETHER_HDR_LEN, M_NOWAIT); | |||||
if (m0 == NULL) { | M_PREPEND(mcur, ETHER_HDR_LEN, M_NOWAIT); | ||||
if (mcur == NULL) { | |||||
error = ENOBUFS; | error = ENOBUFS; | ||||
continue; | if (mprev != NULL) | ||||
mprev->m_nextpkt = nextpkt; | |||||
goto dropit; | |||||
} | } | ||||
bcopy(eh, mtod(m0, caddr_t), ETHER_HDR_LEN); | bcopy(eh, mtod(mcur, caddr_t), ETHER_HDR_LEN); | ||||
} else | |||||
m_freem(m); | /* | ||||
* The previous two M_PREPEND could have inserted one or two | |||||
* mbufs in front so we have to update the previous packet's | |||||
* m_nextpkt. | |||||
*/ | |||||
mcur->m_nextpkt = nextpkt; | |||||
if (mprev != NULL) | |||||
mprev->m_nextpkt = mcur; | |||||
else { | |||||
/* The first mbuf in the original chain needs to be | |||||
* updated. */ | |||||
*mp = mcur; | |||||
} | } | ||||
mprev = mcur; | |||||
} | |||||
if (error == 0) | |||||
KMOD_IPSTAT_INC(ips_fragmented); | KMOD_IPSTAT_INC(ips_fragmented); | ||||
return (error); | return (error); | ||||
out: | dropit: | ||||
if (m != NULL) | for (mcur = *mp; mcur; mcur = m) { /* droping the full packet chain */ | ||||
m_freem(m); | m = mcur->m_nextpkt; | ||||
m_freem(mcur); | |||||
} | |||||
return (error); | return (error); | ||||
} | } | ||||
static void | static void | ||||
bridge_linkstate(struct ifnet *ifp) | bridge_linkstate(struct ifnet *ifp) | ||||
{ | { | ||||
struct bridge_softc *sc = ifp->if_bridge; | struct bridge_softc *sc = ifp->if_bridge; | ||||
struct bridge_iflist *bif; | struct bridge_iflist *bif; | ||||
Show All 37 Lines |