--- sys/conf/files.orig Mon Apr 12 13:03:40 2004 +++ sys/conf/files Mon Apr 12 17:03:03 2004 @@ -1197,6 +1197,7 @@ net/bpf.c standard net/bpf_filter.c optional bpf net/bridge.c optional bridge +net/bridge_filter.c optional bridge net/bsd_comp.c optional ppp_bsdcomp net/if.c standard net/if_arcsubr.c optional arcnet --- sys/net/bridge.c.orig Thu Feb 26 04:55:27 2004 +++ sys/net/bridge.c Mon Apr 12 18:13:01 2004 @@ -92,7 +92,6 @@ #include #include #include -#include #include #include /* for net/if.h */ #include /* string functions */ @@ -109,11 +108,6 @@ #include #include /* for struct arpcom */ -#ifdef PFIL_HOOKS -#include -#include -#endif - #include #include #include @@ -163,38 +157,10 @@ struct bdg_addr *my_macs; /* local MAC addresses */ }; - -extern struct protosw inetsw[]; /* from netinet/ip_input.c */ - static int n_clusters; /* number of clusters */ static struct cluster_softc *clusters; -static struct mtx bdg_mtx; -#define BDG_LOCK_INIT() mtx_init(&bdg_mtx, "bridge", NULL, MTX_DEF) -#define BDG_LOCK_DESTROY() mtx_destroy(&bdg_mtx) -#define BDG_LOCK() mtx_lock(&bdg_mtx) -#define BDG_UNLOCK() mtx_unlock(&bdg_mtx) -#define BDG_LOCK_ASSERT() mtx_assert(&bdg_mtx, MA_OWNED) - -#define BDG_MUTED(ifp) (ifp2sc[ifp->if_index].flags & IFF_MUTE) -#define BDG_MUTE(ifp) ifp2sc[ifp->if_index].flags |= IFF_MUTE -#define BDG_CLUSTER(ifp) (ifp2sc[ifp->if_index].cluster) - -#define BDG_SAMECLUSTER(ifp,src) \ - (src == NULL || BDG_CLUSTER(ifp) == BDG_CLUSTER(src) ) - -#ifdef __i386__ -#define BDG_MATCH(a,b) ( \ - ((u_int16_t *)(a))[2] == ((u_int16_t *)(b))[2] && \ - *((u_int32_t *)(a)) == *((u_int32_t *)(b)) ) -#define IS_ETHER_BROADCAST(a) ( \ - *((u_int32_t *)(a)) == 0xffffffff && \ - ((u_int16_t *)(a))[2] == 0xffff ) -#else -/* for machines that do not support unaligned access */ -#define BDG_MATCH(a,b) ETHER_ADDR_EQ(a,b) -#define IS_ETHER_BROADCAST(a) ETHER_ADDR_EQ(a,"\377\377\377\377\377\377") -#endif +struct mtx bdg_mtx; SYSCTL_DECL(_net_link_ether); SYSCTL_NODE(_net_link_ether, OID_AUTO, bridge, CTLFLAG_RD, 0, @@ -243,9 +209,6 @@ static int bdginit(void); static void parse_bdg_cfg(void); -static int bdg_ipf; /* IPFilter enabled in bridge */ -SYSCTL_INT(_net_link_ether_bridge, OID_AUTO, ipf, CTLFLAG_RW, - &bdg_ipf, 0,"Pass bridged pkts through IPFilter"); static int bdg_ipfw; SYSCTL_INT(_net_link_ether_bridge, OID_AUTO, ipfw, CTLFLAG_RW, &bdg_ipfw,0,"Pass bridged pkts through firewall"); @@ -264,7 +227,7 @@ static int bdg_thru; SYSCTL_INT(_net_link_ether_bridge, OID_AUTO, packets, CTLFLAG_RW, &bdg_thru, 0, "Packets through bridge"); -static int bdg_dropped; +int bdg_dropped; SYSCTL_INT(_net_link_ether_bridge, OID_AUTO, dropped, CTLFLAG_RW, &bdg_dropped, 0, "Packets dropped in bdg_forward"); static int bdg_predict; @@ -287,7 +250,7 @@ /* * System initialization */ -static struct bdg_stats bdg_stats ; +struct bdg_stats bdg_stats ; SYSCTL_STRUCT(_net_link_ether_bridge, OID_AUTO, stats, CTLFLAG_RD, &bdg_stats, bdg_stats, "bridge statistics"); @@ -632,8 +595,6 @@ SYSCTL_OID_COMPAT(parent, nbr, name, (access), \ ptr, arg, handler, fmt, descr) -SYSCTL_INT_COMPAT(_net_link_ether, OID_AUTO, bridge_ipf, CTLFLAG_RW, - &bdg_ipf, 0,"Pass bridged pkts through IPFilter"); SYSCTL_INT_COMPAT(_net_link_ether, OID_AUTO, bridge_ipfw, CTLFLAG_RW, &bdg_ipfw,0,"Pass bridged pkts through firewall"); SYSCTL_STRUCT_COMPAT(_net_link_ether, PF_BDG, bdgstats, CTLFLAG_RD, @@ -704,7 +665,7 @@ * We assume this is only called for interfaces for which bridging * is enabled, i.e. BDG_USED(ifp) is true. */ -static __inline struct ifnet * +struct ifnet * bridge_dst_lookup(struct ether_header *eh, struct cluster_softc *c) { bdg_hash_table *bt; /* pointer to entry in hash table */ @@ -870,7 +831,7 @@ * not the source interface, and * belong to the same cluster as the 'real_dst'. */ -static __inline int +int bridge_ifok(struct ifnet *ifp, struct ifnet *src, struct ifnet *dst) { return (BDG_USED(ifp) @@ -960,11 +921,7 @@ * Additional restrictions may apply e.g. non-IP, short packets, * and pkts already gone through a pipe. */ - if (src != NULL && ( -#ifdef PFIL_HOOKS - (inet_pfil_hook.ph_busy_count >= 0 && bdg_ipf != 0) || -#endif - (IPFW_LOADED && bdg_ipfw != 0))) { + if (src != NULL && (IPFW_LOADED && bdg_ipfw != 0)) { int i; @@ -994,39 +951,6 @@ bcopy(eh, &save_eh, ETHER_HDR_LEN); /* local copy for restore */ m_adj(m0, ETHER_HDR_LEN); /* temporarily strip header */ -#ifdef PFIL_HOOKS - /* - * NetBSD-style generic packet filter, pfil(9), hooks. - * Enables ipf(8) in bridging. - */ - if (inet_pfil_hook.ph_busy_count >= 0 && - m0->m_pkthdr.len >= sizeof(struct ip) && - ntohs(save_eh.ether_type) == ETHERTYPE_IP) { - /* - * before calling the firewall, swap fields the same as IP does. - * here we assume the pkt is an IP one and the header is contiguous - */ - struct ip *ip = mtod(m0, struct ip *); - - ip->ip_len = ntohs(ip->ip_len); - ip->ip_off = ntohs(ip->ip_off); - - if (pfil_run_hooks(&inet_pfil_hook, &m0, src, PFIL_IN) != 0) { - /* NB: hook should consume packet */ - return NULL; - } - if (m0 == NULL) /* consumed by filter */ - return m0; - /* - * If we get here, the firewall has passed the pkt, but the mbuf - * pointer might have changed. Restore ip and the fields ntohs()'d. - */ - ip = mtod(m0, struct ip *); - ip->ip_len = htons(ip->ip_len); - ip->ip_off = htons(ip->ip_off); - } -#endif /* PFIL_HOOKS */ - /* * Prepare arguments and call the firewall. */ @@ -1083,6 +1007,14 @@ return m0; } forward: +#ifdef PFIL_HOOKS + return bridge_pfil_filter(m0, src, dst, real_dst); + /* + * XXX + * Forwading would be done in bridge_pfil_filter with fragmentaion + * and possibly generation of ICMP error. + */ +#endif /* * Again, bring up the headers in case of shared bufs to avoid * corruptions in the future. --- sys/net/bridge.h.orig Fri Nov 15 09:00:14 2002 +++ sys/net/bridge.h Mon Apr 12 16:57:26 2004 @@ -27,6 +27,11 @@ * $FreeBSD: src/sys/net/bridge.h,v 1.12 2002/11/15 00:00:14 sam Exp $ */ +#ifdef _KERNEL_ +#include +#include +#endif + extern int do_bridge; /* @@ -99,8 +104,34 @@ #define BDG_STAT(ifp, type) bdg_stats.s[ifp->if_index].p_in[(uintptr_t)type]++ - +#define BDG_MUTED(ifp) (ifp2sc[ifp->if_index].flags & IFF_MUTE) +#define BDG_MUTE(ifp) ifp2sc[ifp->if_index].flags |= IFF_MUTE +#define BDG_CLUSTER(ifp) (ifp2sc[ifp->if_index].cluster) + +#define BDG_SAMECLUSTER(ifp,src) \ + (src == NULL || BDG_CLUSTER(ifp) == BDG_CLUSTER(src) ) + +#ifdef __i386__ +#define BDG_MATCH(a,b) ( \ + ((u_int16_t *)(a))[2] == ((u_int16_t *)(b))[2] && \ + *((u_int32_t *)(a)) == *((u_int32_t *)(b)) ) +#define IS_ETHER_BROADCAST(a) ( \ + *((u_int32_t *)(a)) == 0xffffffff && \ + ((u_int16_t *)(a))[2] == 0xffff ) +#else +/* for machines that do not support unaligned access */ +#define BDG_MATCH(a,b) ETHER_ADDR_EQ(a,b) +#define IS_ETHER_BROADCAST(a) ETHER_ADDR_EQ(a,"\377\377\377\377\377\377") +#endif + #ifdef _KERNEL +#define BDG_LOCK_INIT() mtx_init(&bdg_mtx, "bridge", NULL, MTX_DEF) +#define BDG_LOCK_DESTROY() mtx_destroy(&bdg_mtx) +#define BDG_LOCK() mtx_lock(&bdg_mtx) +#define BDG_UNLOCK() mtx_unlock(&bdg_mtx) +#define BDG_LOCK_ASSERT() mtx_assert(&bdg_mtx, MA_OWNED) +extern struct mtx bdg_mtx; + typedef struct ifnet *bridge_in_t(struct ifnet *, struct ether_header *); /* bdg_forward frees the mbuf if necessary, returning null */ typedef struct mbuf *bdg_forward_t(struct mbuf *, struct ifnet *); @@ -110,4 +141,15 @@ extern bdgtakeifaces_t *bdgtakeifaces_ptr; #define BDG_LOADED (bdgtakeifaces_ptr != NULL) + +extern int bdg_dropped; +extern struct bdg_stats bdg_stats; +struct ifnet * + bridge_dst_lookup(struct ether_header *, struct cluster_softc *); +int bridge_ifok(struct ifnet *, struct ifnet *, struct ifnet *); +#ifdef PFIL_HOOKS +struct mbuf * + bridge_pfil_filter(struct mbuf *, struct ifnet *, struct ifnet *, + struct ifnet *); +#endif #endif /* KERNEL */ --- sys/net/bridge_filter.c.orig Mon Apr 12 18:56:31 2004 +++ sys/net/bridge_filter.c Mon Apr 12 19:02:36 2004 @@ -0,0 +1,596 @@ +/* $OpenBSD: if_bridge.c,v 1.131 2004/02/10 20:20:01 itojun Exp $ */ + +/* + * Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Effort sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F30602-01-2-0537. + * + */ +#include "opt_pfil_hooks.h" +#include "opt_inet.h" +#include "opt_inet6.h" +#include "opt_random_ip_id.h" + +#ifdef PFIL_HOOKS +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef INET +#include +#include +#include +#include +#include +#include +#include +#endif + +#ifdef INET6 +#include +#include +#endif + +#include + +#define BRIDGE_HANDOFF(m, ifp) \ + do { \ + if (((m)->m_pkthdr.len - sizeof(struct ether_header)) > \ + (ifp)->if_mtu) \ + bridge_fragment((ifp), (m)); \ + else { \ + if (IF_HANDOFF(&(ifp)->if_snd, (m), ifp)) \ + BDG_STAT((ifp), BDG_OUT); \ + else \ + bdg_dropped++; \ + } \ + } while(0) + +static struct mbuf *bridge_filter(struct mbuf *, struct ifnet *, int); +static void bridge_broadcast(struct ifnet *, struct ifnet *, struct mbuf *); +static void bridge_fragment(struct ifnet *, struct mbuf *); +#ifdef INET +static void bridge_send_icmp_err(struct ifnet *, struct ether_header *, + struct mbuf *, int, struct llc *, int, int); +#endif + +/* + * TODO + * MAC filtering capability + * packet tagging + * -- These require ioctl interface and a bridge device node. + */ + +struct mbuf * +bridge_pfil_filter(struct mbuf *m, struct ifnet *src, struct ifnet *dst, + struct ifnet *real_dst) +{ + /* inbound filtering */ + if (src != NULL) { + if ((m = bridge_filter(m, src, PFIL_IN)) == NULL) + return (NULL); + real_dst = src; + } + /* outbound filtering & forward */ + if (dst == BDG_BCAST || dst == BDG_MCAST || dst == BDG_UNKNOWN) { + bridge_broadcast(src, real_dst, m); + /* + * m still valid... m should be return back to caller + * in order to make ARP work. + */ + } else if (dst && bridge_ifok(dst, src, real_dst)) { + if ((m = bridge_filter(m, dst, PFIL_OUT)) == NULL) + return (NULL); + BRIDGE_HANDOFF(m, dst); + m = NULL; + } + return m; +} + +/* + * Filter IP packets by peeking into the ethernet frame. This violates + * the ISO model, but allows us to act as a IP filter at the data link + * layer. As a result, most of this code will look familiar to those + * who've read net/if_ethersubr.c and netinet/ip_input.c + */ +static struct mbuf * +bridge_filter(struct mbuf *m, struct ifnet *ifp, int dir) +{ + struct ether_addr *src, *dst; + struct ether_header eh; + struct llc llc; + int hassnap = 0; +#ifdef INET + struct ip *ip; + int hlen; +#endif + u_int16_t etype; + + m_copydata(m, 0, sizeof(struct ether_header), (caddr_t)&eh); + dst = (struct ether_addr *)&eh.ether_dhost[0]; + src = (struct ether_addr *)&eh.ether_shost[0]; + + etype = ntohs(eh.ether_type); + + if (etype != ETHERTYPE_IP && etype != ETHERTYPE_IPV6) { + if (etype > ETHERMTU || + m->m_pkthdr.len < (LLC_SNAPFRAMELEN + + sizeof(struct ether_header))) + return (m); + + m_copydata(m, sizeof(struct ether_header), + LLC_SNAPFRAMELEN, (caddr_t)&llc); + + if (llc.llc_dsap != LLC_SNAP_LSAP || + llc.llc_ssap != LLC_SNAP_LSAP || + llc.llc_control != LLC_UI || + llc.llc_snap.org_code[0] || + llc.llc_snap.org_code[1] || + 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; + } + + m_adj(m, sizeof(struct ether_header)); + if (hassnap) + m_adj(m, LLC_SNAPFRAMELEN); + + switch (etype) { + +#ifdef INET + case ETHERTYPE_IP: + 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 *); + + 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; + } + + if (ntohs(ip->ip_len) < hlen) + goto dropit; + + if (m->m_pkthdr.len < ntohs(ip->ip_len)) + goto dropit; + if (m->m_pkthdr.len > ntohs(ip->ip_len)) { + if (m->m_len == m->m_pkthdr.len) { + m->m_len = ntohs(ip->ip_len); + m->m_pkthdr.len = ntohs(ip->ip_len); + } else + m_adj(m, ntohs(ip->ip_len) - m->m_pkthdr.len); + } +#ifndef __FreeBSD__ +#ifdef IPSEC + if ((sc->sc_if.if_flags & IFF_LINK2) == IFF_LINK2 && + bridge_ipsec(dir, AF_INET, hlen, m)) + return (NULL); +#endif /* IPSEC */ +#endif + +#ifdef __FreeBSD__ + ip->ip_len = ntohs(ip->ip_len); + ip->ip_off = ntohs(ip->ip_off); + m->m_pkthdr.rcvif = ifp; + if (pfil_run_hooks(&inet_pfil_hook, &m, ifp, dir) != 0) + goto dropit; + if (m == NULL) + return (NULL); + ip = mtod(m, struct ip *); + ip->ip_len = htons(ip->ip_len); + ip->ip_off = htons(ip->ip_off); +#else +#if NPF > 0 + /* 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; +#endif /* NPF */ +#endif + + /* 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 *); + ip->ip_sum = 0; + if (hlen == sizeof(struct ip)) + ip->ip_sum = in_cksum_hdr(ip); + else + ip->ip_sum = in_cksum(m, hlen); + break; +#endif /* INET */ + +#ifdef INET6 + case ETHERTYPE_IPV6: { + struct ip6_hdr *ip6; + + 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; + } + +#ifndef __FreeBSD__ +#ifdef IPSEC + hlen = sizeof(struct ip6_hdr); + + if ((sc->sc_if.if_flags & IFF_LINK2) == IFF_LINK2 && + bridge_ipsec(dir, AF_INET6, hlen, m)) + return (NULL); +#endif /* IPSEC */ +#endif + +#ifdef __FreeBSD__ + m->m_pkthdr.rcvif = ifp; + if (pfil_run_hooks(&inet6_pfil_hook, &m, ifp, dir) != 0) + goto dropit; + if (m == NULL) + return (NULL); +#else +#if NPF > 0 + if (pf_test6(dir, ifp, &m) != PF_PASS) + goto dropit; + if (m == NULL) + return (NULL); +#endif /* NPF */ +#endif + + break; + } +#endif /* INET6 */ + + default: + goto dropit; + break; + } + + /* Reattach SNAP header */ + if (hassnap) { + M_PREPEND(m, LLC_SNAPFRAMELEN, M_DONTWAIT); + if (m == NULL) + goto dropit; + bcopy(&llc, mtod(m, caddr_t), LLC_SNAPFRAMELEN); + } + + /* Reattach ethernet header */ + M_PREPEND(m, sizeof(eh), M_DONTWAIT); + if (m == NULL) + goto dropit; + bcopy(&eh, mtod(m, caddr_t), sizeof(eh)); + + return (m); + +dropit: + if (m != NULL) + m_freem(m); + return (NULL); +} + +static void +bridge_broadcast(struct ifnet *src_if, struct ifnet *dst_if, struct mbuf *m) +{ + struct ifnet *ifp, *prev = NULL; + struct mbuf *mc = NULL; + + IFNET_RLOCK(); + TAILQ_FOREACH(ifp, &ifnet, if_link) { + if (!bridge_ifok(ifp, src_if, dst_if)) + continue; + if (prev) { + IFNET_RUNLOCK(); /* XXX */ + if ((mc = bridge_filter(mc, prev, PFIL_OUT)) == NULL) { + IFNET_RLOCK(); + prev = NULL; + continue; + } + IFNET_RLOCK(); + BRIDGE_HANDOFF(mc, prev); + } + mc = m_dup(m, M_DONTWAIT); + if (mc == NULL) { + bdg_dropped++; + continue; + } + prev = ifp; + } + IFNET_RUNLOCK(); + + if (prev != NULL) { + if ((mc = bridge_filter(mc, prev, PFIL_OUT)) == NULL) + return; + BRIDGE_HANDOFF(mc, prev); + } +} + +static void +bridge_fragment(struct ifnet *ifp, struct mbuf *m) +{ + struct ether_header eh; + struct llc llc; + struct mbuf *m0; + int len, error = 0; + int hassnap = 0; +#ifdef INET + u_int16_t etype; + struct ip *ip; +#endif + +#ifndef INET + goto dropit; +#else + m_copydata(m, 0, sizeof(struct ether_header), (caddr_t)&eh); + etype = ntohs(eh.ether_type); + +#if NVLAN > 0 + if (etype == ETHERTYPE_8021Q && + (ifp->if_capabilities & IFCAP_VLAN_MTU) && + ((m->m_pkthdr.len - sizeof(struct ether_vlan_header)) <= + ifp->if_mtu)) { + IF_HANDOFF(&ifp->if_snd, m, ifp); + return; + } +#endif + + if (etype != ETHERTYPE_IP) { + if (etype > ETHERMTU || + m->m_pkthdr.len < (LLC_SNAPFRAMELEN + + sizeof(struct ether_header))) + goto dropit; + + m_copydata(m, sizeof(struct ether_header), + LLC_SNAPFRAMELEN, (caddr_t)&llc); + + if (llc.llc_dsap != LLC_SNAP_LSAP || + llc.llc_ssap != LLC_SNAP_LSAP || + 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)) + goto dropit; + + hassnap = 1; + } + + m_adj(m, sizeof(struct ether_header)); + if (hassnap) + m_adj(m, LLC_SNAPFRAMELEN); + + if (m->m_len < sizeof(struct ip) && + (m = m_pullup(m, sizeof(struct ip))) == NULL) + goto dropit; + ip = mtod(m, struct ip *); + + /* Respect IP_DF, return a ICMP_UNREACH_NEEDFRAG. */ + if (ip->ip_off & htons(IP_DF)) { + bridge_send_icmp_err(ifp, &eh, m, hassnap, &llc, + ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG); + bdg_dropped++; + return; + } + + /* ip_fragment() requires host byte ordering, Sigh */ + ip->ip_len = ntohs(ip->ip_len); + ip->ip_off = ntohs(ip->ip_off); + error = ip_fragment(ip, &m, ifp->if_mtu, ifp->if_hwassist, + m->m_pkthdr.csum_flags & ~ifp->if_hwassist); + if (error) + goto dropit; + + for (; m; m = m0) { + m0 = m->m_nextpkt; + m->m_nextpkt = NULL; + if (error == 0) { + if (hassnap) { + M_PREPEND(m, LLC_SNAPFRAMELEN, M_DONTWAIT); + if (m == NULL) { + error = ENOBUFS; + continue; + } + bcopy(&llc, mtod(m, caddr_t), + LLC_SNAPFRAMELEN); + } + M_PREPEND(m, sizeof(eh), M_DONTWAIT); + if (m == NULL) { + error = ENOBUFS; + continue; + } + len = m->m_pkthdr.len; + bcopy(&eh, mtod(m, caddr_t), sizeof(eh)); + if (IF_HANDOFF(&ifp->if_snd, m, ifp) == 0) { + bdg_dropped++; + continue; + } + BDG_STAT(ifp, BDG_OUT); + } else + m_freem(m); + } + + if (error == 0) + ipstat.ips_fragmented++; + + return; +#endif /* INET */ + dropit: + bdg_dropped++; + if (m != NULL) + m_freem(m); +} + +#ifdef INET +static void +bridge_send_icmp_err(struct ifnet *ifp, struct ether_header *eh, + struct mbuf *n, int hassnap, struct llc *llc, int type, int code) +{ + struct ifnet *dst_if; + struct ip *ip; + struct icmp *icp; + struct in_addr t; + struct mbuf *m, *n2; + int hlen; + u_int8_t ether_tmp[ETHER_ADDR_LEN]; + + /* Swap ethernet addresses */ + bcopy(&eh->ether_dhost, ðer_tmp, sizeof(ether_tmp)); + bcopy(&eh->ether_shost, &eh->ether_dhost, sizeof(ether_tmp)); + bcopy(ðer_tmp, &eh->ether_shost, sizeof(ether_tmp)); + + BDG_LOCK(); + dst_if = bridge_dst_lookup(eh, BDG_CLUSTER(ifp)); + BDG_UNLOCK(); + if (dst_if == BDG_DROP || dst_if == BDG_BCAST || dst_if == BDG_MCAST || + dst_if == BDG_LOCAL || dst_if == BDG_UNKNOWN) { + m_freem(n); + return; + } + if (!bridge_ifok(dst_if, ifp, ifp)) { + m_freem(n); + return; + } + /* process unicast only */ + n2 = m_copypacket(n, M_DONTWAIT); + if (!n2) { + m_freem(n); + return; + } + + /* icmp_do_error() requries host byte ordering as well */ + ip = mtod(n, struct ip *); + ip->ip_len = ntohs(ip->ip_len); + ip->ip_off = ntohs(ip->ip_off); + m = icmp_do_error(n, type, code, 0, ifp); + if (m == NULL) { + m_freem(n2); + return; + } + + n = n2; + + ip = mtod(m, struct ip *); + hlen = ip->ip_hl << 2; + t = ip->ip_dst; + ip->ip_dst = ip->ip_src; + ip->ip_src = t; + /* reset to network byte ordering */ + ip->ip_len = htons(ip->ip_len); + ip->ip_off = htons(ip->ip_off); + + m->m_data += hlen; + m->m_len -= hlen; + icp = mtod(m, struct icmp *); + icp->icmp_cksum = 0; + icp->icmp_cksum = in_cksum(m, ntohs(ip->ip_len) - hlen); + m->m_data -= hlen; + m->m_len += hlen; + + ip->ip_v = IPVERSION; + ip->ip_off &= htons(IP_DF); +#ifdef RANDOM_IP_ID + ip->ip_id = htons(ip_randomid()); +#else + ip->ip_id = htons(ip_id++); +#endif + ip->ip_ttl = MAXTTL; + ip->ip_sum = 0; + ip->ip_sum = in_cksum(m, hlen); + + /* Reattach SNAP header */ + if (hassnap) { + M_PREPEND(m, LLC_SNAPFRAMELEN, M_DONTWAIT); + if (m == NULL) + goto dropit; + bcopy(llc, mtod(m, caddr_t), LLC_SNAPFRAMELEN); + } + + /* Reattach ethernet header */ + M_PREPEND(m, sizeof(*eh), M_DONTWAIT); + if (m == NULL) + goto dropit; + bcopy(eh, mtod(m, caddr_t), sizeof(*eh)); + if (IF_HANDOFF(&dst_if->if_snd, m, dst_if)) + BDG_STAT(dst_if, BDG_OUT); + else + bdg_dropped++; + m_freem(n); + return; + + dropit: + m_freem(n); +} +#endif /* INET */ +#endif --- sys/net/if_ethersubr.c.orig Thu Apr 8 05:46:11 2004 +++ sys/net/if_ethersubr.c Mon Apr 12 16:23:20 2004 @@ -591,14 +591,8 @@ * while doing its job. This is reflected by it * returning a NULL mbuf pointer. */ - if (m == NULL) { - if (bif == BDG_BCAST || bif == BDG_MCAST) - if_printf(ifp, - "bridge dropped %s packet\n", - bif == BDG_BCAST ? "broadcast" : - "multicast"); + if (m == NULL) return; - } /* * But in some cases the bridge may return the * packet for us to free; sigh. --- sys/netinet/ip_icmp.c.orig Thu Apr 8 05:46:13 2004 +++ sys/netinet/ip_icmp.c Mon Apr 12 16:23:20 2004 @@ -134,11 +134,19 @@ * in response to bad packet ip. */ void -icmp_error(n, type, code, dest, destifp) - struct mbuf *n; - int type, code; - n_long dest; - struct ifnet *destifp; +icmp_error(struct mbuf *n, int type, int code, n_long dest, + struct ifnet *destifp) +{ + struct mbuf *m; + + m = icmp_do_error(n, type, code, dest, destifp); + if (m != NULL) + icmp_reflect(m); +} + +struct mbuf * +icmp_do_error(struct mbuf *n, int type, int code, n_long dest, + struct ifnet *destifp) { register struct ip *oip = mtod(n, struct ip *), *nip; register unsigned oiplen = oip->ip_hl << 2; @@ -242,10 +250,12 @@ m_tag_unlink(n, mtag); m_tag_prepend(m, mtag); } - icmp_reflect(m); + m_freem(n); + return (m); freeit: m_freem(n); + return (NULL); } /* --- sys/netinet/ip_icmp.h.orig Thu Apr 8 05:46:13 2004 +++ sys/netinet/ip_icmp.h Mon Apr 12 16:23:20 2004 @@ -191,6 +191,8 @@ (type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY) #ifdef _KERNEL +struct mbuf * + icmp_do_error(struct mbuf *, int, int, n_long, struct ifnet *); void icmp_error(struct mbuf *, int, int, n_long, struct ifnet *); void icmp_input(struct mbuf *, int); #endif --- sys/modules/bridge/Makefile.orig Wed Sep 24 02:54:04 2003 +++ sys/modules/bridge/Makefile Mon Apr 12 16:33:59 2004 @@ -2,16 +2,27 @@ .PATH: ${.CURDIR}/../../net KMOD= bridge -SRCS= bridge.c -SRCS+= opt_pfil_hooks.h +SRCS= bridge.c bridge_filter.c +SRCS+= opt_pfil_hooks.h opt_inet.h opt_inet6.h opt_random_ip_id.h # -# By default don't enable pfil hooks support. This means you -# cannot use ipfilter together with the bridge. To enable it -# uncomment the line below +# By default enable pfil hooks support. To disable it comment +# the line below # opt_pfil_hooks.h: -# echo "#define PFIL_HOOKS 1" > opt_pfil_hooks.h - touch opt_pfil_hooks.h + echo "#define PFIL_HOOKS 1" > opt_pfil_hooks.h + +opt_inet.h: + echo "#define INET 1" > opt_inet.h + +opt_inet6.h: +.if defined(NOINET6) + echo > opt_inet6.h +.else + echo "#define INET6 1" > opt_inet6.h +.endif + +opt_random_ip_id.h: + echo "#define RANDOM_IP_ID 1" > opt_random_ip_id.h .include