Changeset View
Changeset View
Standalone View
Standalone View
sys/net/if_bridge.c
Show First 20 Lines • Show All 1,964 Lines • ▼ Show 20 Lines | bridge_dummynet(struct mbuf *m, struct ifnet *ifp) | ||||
* ever happen if a member interface is removed while packets are | * ever happen if a member interface is removed while packets are | ||||
* queued for it. | * queued for it. | ||||
*/ | */ | ||||
if (sc == NULL) { | if (sc == NULL) { | ||||
m_freem(m); | m_freem(m); | ||||
return; | return; | ||||
} | } | ||||
if (PFIL_HOOKED(&V_inet_pfil_hook) | if (PFIL_HOOKED_OUT(V_inet_pfil_head) | ||||
#ifdef INET6 | #ifdef INET6 | ||||
|| PFIL_HOOKED(&V_inet6_pfil_hook) | || PFIL_HOOKED_OUT(V_inet6_pfil_head) | ||||
#endif | #endif | ||||
) { | ) { | ||||
if (bridge_pfil(&m, sc->sc_ifp, ifp, PFIL_OUT) != 0) | if (bridge_pfil(&m, sc->sc_ifp, ifp, PFIL_OUT) != 0) | ||||
return; | return; | ||||
if (m == NULL) | if (m == NULL) | ||||
return; | return; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 241 Lines • ▼ Show 20 Lines | bridge_forward(struct bridge_softc *sc, struct bridge_iflist *sbif, | ||||
* through the pfil(9) framework, as it is possible that pfil(9) will | * 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 | * drop the packet, or possibly modify it, making it difficult to debug | ||||
* firewall issues on the bridge. | * firewall issues on the bridge. | ||||
*/ | */ | ||||
if (dst_if != NULL || (m->m_flags & (M_BCAST | M_MCAST)) == 0) | if (dst_if != NULL || (m->m_flags & (M_BCAST | M_MCAST)) == 0) | ||||
ETHER_BPF_MTAP(ifp, m); | ETHER_BPF_MTAP(ifp, m); | ||||
/* run the packet filter */ | /* run the packet filter */ | ||||
if (PFIL_HOOKED(&V_inet_pfil_hook) | if (PFIL_HOOKED_IN(V_inet_pfil_head) | ||||
#ifdef INET6 | #ifdef INET6 | ||||
|| PFIL_HOOKED(&V_inet6_pfil_hook) | || PFIL_HOOKED_IN(V_inet6_pfil_head) | ||||
#endif | #endif | ||||
) { | ) { | ||||
BRIDGE_UNLOCK(sc); | BRIDGE_UNLOCK(sc); | ||||
if (bridge_pfil(&m, ifp, src_if, PFIL_IN) != 0) | if (bridge_pfil(&m, ifp, src_if, PFIL_IN) != 0) | ||||
return; | return; | ||||
if (m == NULL) | if (m == NULL) | ||||
return; | return; | ||||
BRIDGE_LOCK(sc); | BRIDGE_LOCK(sc); | ||||
Show All 21 Lines | if (sbif->bif_flags & dbif->bif_flags & IFBIF_PRIVATE) | ||||
goto drop; | goto drop; | ||||
if ((dbif->bif_flags & IFBIF_STP) && | if ((dbif->bif_flags & IFBIF_STP) && | ||||
dbif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) | dbif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) | ||||
goto drop; | goto drop; | ||||
BRIDGE_UNLOCK(sc); | BRIDGE_UNLOCK(sc); | ||||
if (PFIL_HOOKED(&V_inet_pfil_hook) | if (PFIL_HOOKED_OUT(V_inet_pfil_head) | ||||
#ifdef INET6 | #ifdef INET6 | ||||
|| PFIL_HOOKED(&V_inet6_pfil_hook) | || PFIL_HOOKED_OUT(V_inet6_pfil_head) | ||||
#endif | #endif | ||||
) { | ) { | ||||
if (bridge_pfil(&m, ifp, dst_if, PFIL_OUT) != 0) | if (bridge_pfil(&m, ifp, dst_if, PFIL_OUT) != 0) | ||||
return; | return; | ||||
if (m == NULL) | if (m == NULL) | ||||
return; | return; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 120 Lines • ▼ Show 20 Lines | || ((iface)->if_carp \ | ||||
&& (*carp_forus_p)((iface), eh->ether_shost)) | && (*carp_forus_p)((iface), eh->ether_shost)) | ||||
#else | #else | ||||
# define OR_CARP_CHECK_WE_ARE_DST(iface) | # define OR_CARP_CHECK_WE_ARE_DST(iface) | ||||
# define OR_CARP_CHECK_WE_ARE_SRC(iface) | # define OR_CARP_CHECK_WE_ARE_SRC(iface) | ||||
#endif | #endif | ||||
#ifdef INET6 | #ifdef INET6 | ||||
# define OR_PFIL_HOOKED_INET6 \ | # define OR_PFIL_HOOKED_INET6 \ | ||||
|| PFIL_HOOKED(&V_inet6_pfil_hook) | || PFIL_HOOKED_IN(V_inet6_pfil_head) | ||||
#else | #else | ||||
# define OR_PFIL_HOOKED_INET6 | # define OR_PFIL_HOOKED_INET6 | ||||
#endif | #endif | ||||
#define GRAB_OUR_PACKETS(iface) \ | #define GRAB_OUR_PACKETS(iface) \ | ||||
if ((iface)->if_type == IFT_GIF) \ | if ((iface)->if_type == IFT_GIF) \ | ||||
continue; \ | continue; \ | ||||
/* It is destined for us. */ \ | /* It is destined for us. */ \ | ||||
if (memcmp(IF_LLADDR((iface)), eh->ether_dhost, ETHER_ADDR_LEN) == 0 \ | if (memcmp(IF_LLADDR((iface)), eh->ether_dhost, ETHER_ADDR_LEN) == 0 \ | ||||
OR_CARP_CHECK_WE_ARE_DST((iface)) \ | OR_CARP_CHECK_WE_ARE_DST((iface)) \ | ||||
) { \ | ) { \ | ||||
if ((iface)->if_type == IFT_BRIDGE) { \ | if ((iface)->if_type == IFT_BRIDGE) { \ | ||||
ETHER_BPF_MTAP(iface, m); \ | ETHER_BPF_MTAP(iface, m); \ | ||||
if_inc_counter(iface, IFCOUNTER_IPACKETS, 1); \ | if_inc_counter(iface, IFCOUNTER_IPACKETS, 1); \ | ||||
if_inc_counter(iface, IFCOUNTER_IBYTES, m->m_pkthdr.len); \ | if_inc_counter(iface, IFCOUNTER_IBYTES, m->m_pkthdr.len); \ | ||||
/* Filter on the physical interface. */ \ | /* Filter on the physical interface. */ \ | ||||
if (V_pfil_local_phys && \ | if (V_pfil_local_phys && \ | ||||
(PFIL_HOOKED(&V_inet_pfil_hook) \ | (PFIL_HOOKED_IN(V_inet_pfil_head) \ | ||||
OR_PFIL_HOOKED_INET6)) { \ | OR_PFIL_HOOKED_INET6)) { \ | ||||
if (bridge_pfil(&m, NULL, ifp, \ | if (bridge_pfil(&m, NULL, ifp, \ | ||||
PFIL_IN) != 0 || m == NULL) { \ | PFIL_IN) != 0 || m == NULL) { \ | ||||
BRIDGE_UNLOCK(sc); \ | BRIDGE_UNLOCK(sc); \ | ||||
return (NULL); \ | return (NULL); \ | ||||
} \ | } \ | ||||
eh = mtod(m, struct ether_header *); \ | eh = mtod(m, struct ether_header *); \ | ||||
} \ | } \ | ||||
▲ Show 20 Lines • Show All 73 Lines • ▼ Show 20 Lines | bridge_broadcast(struct bridge_softc *sc, struct ifnet *src_if, | ||||
BRIDGE_LOCK2REF(sc, error); | BRIDGE_LOCK2REF(sc, error); | ||||
if (error) { | if (error) { | ||||
m_freem(m); | m_freem(m); | ||||
return; | return; | ||||
} | } | ||||
/* Filter on the bridge interface before broadcasting */ | /* Filter on the bridge interface before broadcasting */ | ||||
if (runfilt && (PFIL_HOOKED(&V_inet_pfil_hook) | if (runfilt && (PFIL_HOOKED_OUT(V_inet_pfil_head) | ||||
#ifdef INET6 | #ifdef INET6 | ||||
|| PFIL_HOOKED(&V_inet6_pfil_hook) | || PFIL_HOOKED_OUT(V_inet6_pfil_head) | ||||
#endif | #endif | ||||
)) { | )) { | ||||
if (bridge_pfil(&m, sc->sc_ifp, NULL, PFIL_OUT) != 0) | if (bridge_pfil(&m, sc->sc_ifp, NULL, PFIL_OUT) != 0) | ||||
goto out; | goto out; | ||||
if (m == NULL) | if (m == NULL) | ||||
goto out; | goto out; | ||||
} | } | ||||
Show All 28 Lines | if (LIST_NEXT(dbif, bif_next) == NULL) { | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Filter on the output interface. Pass a NULL bridge interface | * Filter on the output interface. Pass a NULL bridge interface | ||||
* pointer so we do not redundantly filter on the bridge for | * pointer so we do not redundantly filter on the bridge for | ||||
* each interface we broadcast on. | * each interface we broadcast on. | ||||
*/ | */ | ||||
if (runfilt && (PFIL_HOOKED(&V_inet_pfil_hook) | if (runfilt && (PFIL_HOOKED_OUT(V_inet_pfil_head) | ||||
#ifdef INET6 | #ifdef INET6 | ||||
|| PFIL_HOOKED(&V_inet6_pfil_hook) | || PFIL_HOOKED_OUT(V_inet6_pfil_head) | ||||
#endif | #endif | ||||
)) { | )) { | ||||
if (used == 0) { | if (used == 0) { | ||||
/* Keep the layer3 header aligned */ | /* Keep the layer3 header aligned */ | ||||
i = min(mc->m_pkthdr.len, max_protohdr); | i = min(mc->m_pkthdr.len, max_protohdr); | ||||
mc = m_copyup(mc, i, ETHER_ALIGN); | mc = m_copyup(mc, i, ETHER_ALIGN); | ||||
if (mc == NULL) { | if (mc == NULL) { | ||||
if_inc_counter(sc->sc_ifp, IFCOUNTER_OERRORS, 1); | if_inc_counter(sc->sc_ifp, IFCOUNTER_OERRORS, 1); | ||||
▲ Show 20 Lines • Show All 518 Lines • ▼ Show 20 Lines | |||||
static int | static int | ||||
bridge_pfil(struct mbuf **mp, struct ifnet *bifp, struct ifnet *ifp, int dir) | bridge_pfil(struct mbuf **mp, struct ifnet *bifp, struct ifnet *ifp, int dir) | ||||
{ | { | ||||
int snap, error, i, hlen; | int snap, error, i, hlen; | ||||
struct ether_header *eh1, eh2; | struct ether_header *eh1, eh2; | ||||
struct ip *ip; | struct ip *ip; | ||||
struct llc llc1; | struct llc llc1; | ||||
u_int16_t ether_type; | u_int16_t ether_type; | ||||
pfil_return_t rv; | |||||
snap = 0; | snap = 0; | ||||
error = -1; /* Default error if not error == 0 */ | error = -1; /* Default error if not error == 0 */ | ||||
#if 0 | #if 0 | ||||
/* we may return with the IP fields swapped, ensure its not shared */ | /* we may return with the IP fields swapped, ensure its not shared */ | ||||
KASSERT(M_WRITABLE(*mp), ("%s: modifying a shared mbuf", __func__)); | KASSERT(M_WRITABLE(*mp), ("%s: modifying a shared mbuf", __func__)); | ||||
#endif | #endif | ||||
▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | default: | ||||
* packets, these will not be checked by pfil(9) and | * packets, these will not be checked by pfil(9) and | ||||
* passed unconditionally so the default is to drop. | * passed unconditionally so the default is to drop. | ||||
*/ | */ | ||||
if (V_pfil_onlyip) | if (V_pfil_onlyip) | ||||
goto bad; | goto bad; | ||||
} | } | ||||
/* Run the packet through pfil before stripping link headers */ | /* Run the packet through pfil before stripping link headers */ | ||||
if (PFIL_HOOKED(&V_link_pfil_hook) && V_pfil_ipfw != 0 && | if (PFIL_HOOKED_OUT(V_link_pfil_head) && V_pfil_ipfw != 0 && | ||||
dir == PFIL_OUT && ifp != NULL) { | dir == PFIL_OUT && ifp != NULL) { | ||||
switch (pfil_run_hooks(V_link_pfil_head, mp, ifp, dir, NULL)) { | |||||
error = pfil_run_hooks(&V_link_pfil_hook, mp, ifp, dir, 0, | case PFIL_DROPPED: | ||||
NULL); | return (EPERM); | ||||
case PFIL_CONSUMED: | |||||
if (*mp == NULL || error != 0) /* packet consumed by filter */ | return (0); | ||||
return (error); | |||||
} | } | ||||
} | |||||
/* Strip off the Ethernet header and keep a copy. */ | /* Strip off the Ethernet header and keep a copy. */ | ||||
m_copydata(*mp, 0, ETHER_HDR_LEN, (caddr_t) &eh2); | m_copydata(*mp, 0, ETHER_HDR_LEN, (caddr_t) &eh2); | ||||
m_adj(*mp, ETHER_HDR_LEN); | m_adj(*mp, ETHER_HDR_LEN); | ||||
/* Strip off snap header, if present */ | /* Strip off snap header, if present */ | ||||
if (snap) { | if (snap) { | ||||
m_copydata(*mp, 0, sizeof(struct llc), (caddr_t) &llc1); | m_copydata(*mp, 0, sizeof(struct llc), (caddr_t) &llc1); | ||||
Show All 20 Lines | if (error) | ||||
goto bad; | goto bad; | ||||
} | } | ||||
error = 0; | error = 0; | ||||
/* | /* | ||||
* Run the packet through pfil | * Run the packet through pfil | ||||
*/ | */ | ||||
rv = PFIL_PASS; | |||||
switch (ether_type) { | switch (ether_type) { | ||||
case ETHERTYPE_IP: | case ETHERTYPE_IP: | ||||
/* | /* | ||||
* Run pfil on the member interface and the bridge, both can | * Run pfil on the member interface and the bridge, both can | ||||
* be skipped by clearing pfil_member or pfil_bridge. | * be skipped by clearing pfil_member or pfil_bridge. | ||||
* | * | ||||
* Keep the order: | * Keep the order: | ||||
* in_if -> bridge_if -> out_if | * in_if -> bridge_if -> out_if | ||||
*/ | */ | ||||
if (V_pfil_bridge && dir == PFIL_OUT && bifp != NULL) | if (V_pfil_bridge && dir == PFIL_OUT && bifp != NULL && (rv = | ||||
error = pfil_run_hooks(&V_inet_pfil_hook, mp, bifp, | pfil_run_hooks(V_inet_pfil_head, mp, bifp, dir, NULL)) != | ||||
dir, 0, NULL); | PFIL_PASS) | ||||
if (*mp == NULL || error != 0) /* filter may consume */ | |||||
break; | break; | ||||
if (V_pfil_member && ifp != NULL) | if (V_pfil_member && ifp != NULL && (rv = | ||||
error = pfil_run_hooks(&V_inet_pfil_hook, mp, ifp, | pfil_run_hooks(V_inet_pfil_head, mp, ifp, dir, NULL)) != | ||||
dir, 0, NULL); | PFIL_PASS) | ||||
if (*mp == NULL || error != 0) /* filter may consume */ | |||||
break; | break; | ||||
if (V_pfil_bridge && dir == PFIL_IN && bifp != NULL) | if (V_pfil_bridge && dir == PFIL_IN && bifp != NULL && (rv = | ||||
error = pfil_run_hooks(&V_inet_pfil_hook, mp, bifp, | pfil_run_hooks(V_inet_pfil_head, mp, bifp, dir, NULL)) != | ||||
dir, 0, NULL); | PFIL_PASS) | ||||
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 */ | /* bridge_fragment generates a mbuf chain of packets */ | ||||
/* that already include eth headers */ | /* 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) { | ||||
Show All 19 Lines | case ETHERTYPE_IP: | ||||
if (hlen == sizeof(struct ip)) | if (hlen == sizeof(struct ip)) | ||||
ip->ip_sum = in_cksum_hdr(ip); | ip->ip_sum = in_cksum_hdr(ip); | ||||
else | else | ||||
ip->ip_sum = in_cksum(*mp, hlen); | ip->ip_sum = in_cksum(*mp, hlen); | ||||
break; | break; | ||||
#ifdef INET6 | #ifdef INET6 | ||||
case ETHERTYPE_IPV6: | case ETHERTYPE_IPV6: | ||||
if (V_pfil_bridge && dir == PFIL_OUT && bifp != NULL) | if (V_pfil_bridge && dir == PFIL_OUT && bifp != NULL && (rv = | ||||
error = pfil_run_hooks(&V_inet6_pfil_hook, mp, bifp, | pfil_run_hooks(V_inet6_pfil_head, mp, bifp, dir, NULL)) != | ||||
dir, 0, NULL); | PFIL_PASS) | ||||
if (*mp == NULL || error != 0) /* filter may consume */ | |||||
break; | break; | ||||
if (V_pfil_member && ifp != NULL) | if (V_pfil_member && ifp != NULL && (rv = | ||||
error = pfil_run_hooks(&V_inet6_pfil_hook, mp, ifp, | pfil_run_hooks(V_inet6_pfil_head, mp, ifp, dir, NULL)) != | ||||
dir, 0, NULL); | PFIL_PASS) | ||||
if (*mp == NULL || error != 0) /* filter may consume */ | |||||
break; | break; | ||||
if (V_pfil_bridge && dir == PFIL_IN && bifp != NULL) | if (V_pfil_bridge && dir == PFIL_IN && bifp != NULL && (rv = | ||||
error = pfil_run_hooks(&V_inet6_pfil_hook, mp, bifp, | pfil_run_hooks(V_inet6_pfil_head, mp, bifp, dir, NULL)) != | ||||
dir, 0, NULL); | PFIL_PASS) | ||||
break; | break; | ||||
break; | |||||
#endif | #endif | ||||
} | |||||
switch (rv) { | |||||
case PFIL_CONSUMED: | |||||
return (0); | |||||
case PFIL_DROPPED: | |||||
return (EPERM); | |||||
default: | default: | ||||
error = 0; | |||||
break; | break; | ||||
} | } | ||||
if (*mp == NULL) | |||||
return (error); | |||||
if (error != 0) | |||||
goto bad; | |||||
error = -1; | error = -1; | ||||
/* | /* | ||||
* Finally, put everything back the way it was and return | * Finally, put everything back the way it was and return | ||||
*/ | */ | ||||
if (snap) { | if (snap) { | ||||
M_PREPEND(*mp, sizeof(struct llc), M_NOWAIT); | M_PREPEND(*mp, sizeof(struct llc), M_NOWAIT); | ||||
▲ Show 20 Lines • Show All 292 Lines • Show Last 20 Lines |