diff options
-rw-r--r-- | sys/net/if_bridge.c | 176 |
1 files changed, 113 insertions, 63 deletions
diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c index ada2d292a28..9e826016e00 100644 --- a/sys/net/if_bridge.c +++ b/sys/net/if_bridge.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_bridge.c,v 1.86 2002/03/14 01:27:09 millert Exp $ */ +/* $OpenBSD: if_bridge.c,v 1.87 2002/03/18 10:31:25 jasoni Exp $ */ /* * Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net) @@ -64,6 +64,11 @@ #include <net/if_enc.h> #endif +#ifdef INET6 +#include <netinet/ip6.h> +#include <netinet6/ip6_var.h> +#endif + #if NPF > 0 #include <net/pfvar.h> #define BRIDGE_IN PF_IN @@ -2136,8 +2141,11 @@ bridge_filter(sc, dir, ifp, eh, m) int hassnap = 0; struct ip *ip; int hlen; + u_int16_t etype; + + etype = ntohs(eh->ether_type); - if (eh->ether_type != htons(ETHERTYPE_IP)) { + if (etype != ETHERTYPE_IP && etype != ETHERTYPE_IPV6) { if (eh->ether_type > ETHERMTU || m->m_pkthdr.len < (LLC_SNAPFRAMELEN + sizeof(struct ether_header))) @@ -2151,8 +2159,11 @@ bridge_filter(sc, dir, ifp, eh, m) llc.llc_control != LLC_UI || llc.llc_snap.org_code[0] || llc.llc_snap.org_code[1] || - llc.llc_snap.org_code[2] || - llc.llc_snap.ether_type != htons(ETHERTYPE_IP)) + llc.llc_snap.org_code[2]) + return (m); + + etype = ntohs(llc.llc_snap.ether_type); + if (etype != ETHERTYPE_IP && etype != ETHERTYPE_IPV6) return (m); hassnap = 1; } @@ -2161,75 +2172,114 @@ bridge_filter(sc, dir, ifp, eh, m) if (hassnap) m_adj(m, LLC_SNAPFRAMELEN); - if (m->m_pkthdr.len < sizeof(struct ip)) - goto dropit; - - /* Copy minimal header, and drop invalids */ - if (m->m_len < sizeof(struct ip) && - (m = m_pullup(m, sizeof(struct ip))) == NULL) { - ipstat.ips_toosmall++; - return (NULL); - } - ip = mtod(m, struct ip *); + switch (etype) { - if (ip->ip_v != IPVERSION) { - ipstat.ips_badvers++; - goto dropit; - } + case ETHERTYPE_IP: + if (m->m_pkthdr.len < sizeof(struct ip)) + goto dropit; - hlen = ip->ip_hl << 2; /* get whole header length */ - if (hlen < sizeof(struct ip)) { - ipstat.ips_badhlen++; - goto dropit; - } - if (hlen > m->m_len) { - if ((m = m_pullup(m, hlen)) == NULL) { - ipstat.ips_badhlen++; + /* Copy minimal header, and drop invalids */ + if (m->m_len < sizeof(struct ip) && + (m = m_pullup(m, sizeof(struct ip))) == NULL) { + ipstat.ips_toosmall++; return (NULL); } ip = mtod(m, struct ip *); - } - - if ((ip->ip_sum = in_cksum(m, hlen)) != 0) { - ipstat.ips_badsum++; - goto dropit; - } + + if (ip->ip_v != IPVERSION) { + ipstat.ips_badvers++; + goto dropit; + } + + hlen = ip->ip_hl << 2; /* get whole header length */ + if (hlen < sizeof(struct ip)) { + ipstat.ips_badhlen++; + goto dropit; + } + if (hlen > m->m_len) { + if ((m = m_pullup(m, hlen)) == NULL) { + ipstat.ips_badhlen++; + return (NULL); + } + ip = mtod(m, struct ip *); + } + + if ((ip->ip_sum = in_cksum(m, hlen)) != 0) { + ipstat.ips_badsum++; + goto dropit; + } + + NTOHS(ip->ip_len); + if (ip->ip_len < hlen) + goto dropit; + NTOHS(ip->ip_id); + NTOHS(ip->ip_off); + + if (m->m_pkthdr.len < ip->ip_len) + goto dropit; + if (m->m_pkthdr.len > ip->ip_len) { + if (m->m_len == m->m_pkthdr.len) { + m->m_len = ip->ip_len; + m->m_pkthdr.len = ip->ip_len; + } else + m_adj(m, ip->ip_len - m->m_pkthdr.len); + } + + /* Finally, we get to filter the packet! */ + m->m_pkthdr.rcvif = ifp; + if (pf_test(dir, ifp, &m) != PF_PASS) + goto dropit; + if (m == NULL) + goto dropit; + + /* Rebuild the IP header */ + if (m->m_len < hlen && ((m = m_pullup(m, hlen)) == NULL)) + return (NULL); + if (m->m_len < sizeof(struct ip)) + goto dropit; + ip = mtod(m, struct ip *); + HTONS(ip->ip_len); + HTONS(ip->ip_id); + HTONS(ip->ip_off); + ip->ip_sum = 0; + ip->ip_sum = in_cksum(m, hlen); - NTOHS(ip->ip_len); - if (ip->ip_len < hlen) - goto dropit; - NTOHS(ip->ip_id); - NTOHS(ip->ip_off); + break; - if (m->m_pkthdr.len < ip->ip_len) - goto dropit; - if (m->m_pkthdr.len > ip->ip_len) { - if (m->m_len == m->m_pkthdr.len) { - m->m_len = ip->ip_len; - m->m_pkthdr.len = ip->ip_len; - } else - m_adj(m, ip->ip_len - m->m_pkthdr.len); - } +#ifdef INET6 + case ETHERTYPE_IPV6: { + struct ip6_hdr *ip6; - /* Finally, we get to filter the packet! */ - m->m_pkthdr.rcvif = ifp; - if (pf_test(dir, ifp, &m) != PF_PASS) - goto dropit; - if (m == NULL) - goto dropit; + if (m->m_len < sizeof(struct ip6_hdr)) { + if ((m = m_pullup(m, sizeof(struct ip6_hdr))) + == NULL) { + ip6stat.ip6s_toosmall++; + return (NULL); + } + } + + 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 dropit; + } - /* Rebuild the IP header */ - if (m->m_len < hlen && ((m = m_pullup(m, hlen)) == NULL)) - return (NULL); - if (m->m_len < sizeof(struct ip)) + if (pf_test6(dir, ifp, &m) != PF_PASS) + goto dropit; + if (m == NULL) + return (NULL); + + break; + } +#endif /* INET6 */ + + default: goto dropit; - ip = mtod(m, struct ip *); - HTONS(ip->ip_len); - HTONS(ip->ip_id); - HTONS(ip->ip_off); - ip->ip_sum = 0; - ip->ip_sum = in_cksum(m, hlen); - + break; + } + /* Reattach SNAP header */ if (hassnap) { M_PREPEND(m, LLC_SNAPFRAMELEN, M_DONTWAIT); |