diff options
author | archie <archie@FreeBSD.org> | 2000-05-14 02:18:43 +0000 |
---|---|---|
committer | archie <archie@FreeBSD.org> | 2000-05-14 02:18:43 +0000 |
commit | fa21035b4e2f11d2c8f90174690853600b670e2d (patch) | |
tree | 9afb8dacfff6d7607064d8aa2bbf2da5069e8be6 /sys/net | |
parent | d066b073153b986a54fd18a31d6bcc5d697933a2 (diff) | |
download | FreeBSD-src-fa21035b4e2f11d2c8f90174690853600b670e2d.zip FreeBSD-src-fa21035b4e2f11d2c8f90174690853600b670e2d.tar.gz |
Move code to handle BPF and bridging for incoming Ethernet packets out
of the individual drivers and into the common routine ether_input().
Also, remove the (incomplete) hack for matching ethernet headers
in the ip_fw code.
The good news: net result of 1016 lines removed, and this should make
bridging now work with *all* Ethernet drivers.
The bad news: it's nearly impossible to test every driver, especially
for bridging, and I was unable to get much testing help on the mailing
lists.
Reviewed by: freebsd-net
Diffstat (limited to 'sys/net')
-rw-r--r-- | sys/net/bridge.c | 58 | ||||
-rw-r--r-- | sys/net/bridge.h | 7 | ||||
-rw-r--r-- | sys/net/if_ethersubr.c | 69 | ||||
-rw-r--r-- | sys/net/if_vlan.c | 26 |
4 files changed, 87 insertions, 73 deletions
diff --git a/sys/net/bridge.c b/sys/net/bridge.c index e3fcc3f..83b711e 100644 --- a/sys/net/bridge.c +++ b/sys/net/bridge.c @@ -31,9 +31,8 @@ * A bridging table holds the source MAC address/dest. interface for each * known node. The table is indexed using an hash of the source address. * - * Input packets are tapped near the end of the input routine in each - * driver (near the call to bpf_mtap, or before the call to ether_input) - * and analysed calling bridge_in(). Depending on the result, the packet + * Input packets are tapped near the beginning of ether_input(), and + * analysed by calling bridge_in(). Depending on the result, the packet * can be forwarded to one or more output interfaces using bdg_forward(), * and/or sent to the upper layer (e.g. in case of multicast). * @@ -163,7 +162,7 @@ static struct bdg_softc *ifp2sc = NULL ; #define IFP_CHK(ifp, x) \ if (ifp2sc[ifp->if_index].magic != 0xDEADBEEF) { x ; } -#define SAMECLUSTER(ifp,src,eh) \ +#define SAMECLUSTER(ifp,src) \ (src == NULL || CLUSTER(ifp) == CLUSTER(src) ) /* @@ -473,11 +472,9 @@ bdginit(void *dummy) /* * bridge_in() is invoked to perform bridging decision on input packets. + * * On Input: - * m packet to be bridged. The mbuf need not to hold the - * whole packet, only the first 14 bytes suffice. We - * assume them to be contiguous. No alignment assumptions - * because they are not a problem on i386 class machines. + * eh Ethernet header of the incoming packet. * * On Return: destination of packet, one of * BDG_BCAST broadcast @@ -490,16 +487,12 @@ bdginit(void *dummy) * to fetch more of the packet, or simply drop it completely. */ - struct ifnet * -bridge_in(struct mbuf *m) +bridge_in(struct ifnet *ifp, struct ether_header *eh) { int index; - struct ifnet *ifp = m->m_pkthdr.rcvif, *dst , *old ; + struct ifnet *dst , *old ; int dropit = MUTED(ifp) ; - struct ether_header *eh; - - eh = mtod(m, struct ether_header *); /* * hash the source address @@ -545,7 +538,7 @@ bridge_in(struct mbuf *m) bcopy(eh->ether_shost, bdg_table[index].etheraddr, 6); bdg_table[index].name = ifp ; } - dst = bridge_dst_lookup(m); + dst = bridge_dst_lookup(eh); /* Return values: * BDG_BCAST, BDG_MCAST, BDG_LOCAL, BDG_UNKNOWN, BDG_DROP, ifp. * For muted interfaces, the first 3 are changed in BDG_LOCAL, @@ -599,7 +592,7 @@ bridge_in(struct mbuf *m) * *m0 -- pointer to the packet (NULL if still existent) */ int -bdg_forward (struct mbuf **m0, struct ifnet *dst) +bdg_forward(struct mbuf **m0, struct ether_header *const eh, struct ifnet *dst) { struct ifnet *src = (*m0)->m_pkthdr.rcvif; /* could be NULL in output */ struct ifnet *ifp, *last = NULL ; @@ -608,8 +601,6 @@ bdg_forward (struct mbuf **m0, struct ifnet *dst) int once = 0; /* loop only once */ struct mbuf *m ; - struct ether_header *eh = mtod(*m0, struct ether_header *); /* XXX */ - if (dst == BDG_DROP) { /* this should not happen */ printf("xx bdg_forward for BDG_DROP\n"); m_freem(*m0) ; @@ -642,7 +633,6 @@ bdg_forward (struct mbuf **m0, struct ifnet *dst) * ethernet header. */ if (ip_fw_chk_ptr) { - u_int16_t dummy = 0 ; struct ip_fw_chain *rule = NULL ; int off; struct ip *ip ; @@ -658,7 +648,6 @@ bdg_forward (struct mbuf **m0, struct ifnet *dst) (*m0) = m = m->m_next ; src = m->m_pkthdr.rcvif; /* could be NULL in output */ - eh = mtod(m, struct ether_header *); /* XXX */ canfree = 1 ; /* for sure, a copy is not needed later. */ goto forward; /* HACK! I should obey the fw_one_pass */ } @@ -680,7 +669,7 @@ bdg_forward (struct mbuf **m0, struct ifnet *dst) * Need to make a copy (and for good measure, make sure that * the header is contiguous). The original is still in *m0 */ - int needed = min(MHLEN, 14+max_protohdr) ; + int needed = min(MHLEN, max_protohdr) ; needed = min(needed, (*m0)->m_len ) ; m = m_copypacket( (*m0), M_DONTWAIT); @@ -688,8 +677,7 @@ bdg_forward (struct mbuf **m0, struct ifnet *dst) printf("-- bdg: m_copypacket failed.\n") ; return ENOBUFS ; } - m = m_pullup(m, needed) ; - if ( m == NULL ) { + if (m->m_len < needed && (m = m_pullup(m, needed)) == NULL) { printf("-- bdg: pullup failed.\n") ; return ENOBUFS ; } @@ -699,8 +687,7 @@ bdg_forward (struct mbuf **m0, struct ifnet *dst) * 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 */ - eh = mtod(m, struct ether_header *); - ip = (struct ip *)(eh + 1 ) ; + ip = mtod(m, struct ip *); NTOHS(ip->ip_len); NTOHS(ip->ip_id); NTOHS(ip->ip_off); @@ -709,7 +696,7 @@ bdg_forward (struct mbuf **m0, struct ifnet *dst) * The third parameter to the firewall code is the dst. interface. * Since we apply checks only on input pkts we use NULL. */ - off = (*ip_fw_chk_ptr)(NULL, 0, NULL, &dummy, &m, &rule, NULL) ; + off = (*ip_fw_chk_ptr)(&ip, 0, NULL, NULL, &m, &rule, NULL); if (m == NULL) { /* pkt discarded by firewall */ /* @@ -724,11 +711,9 @@ bdg_forward (struct mbuf **m0, struct ifnet *dst) /* * If we get here, the firewall has passed the pkt, but the - * mbuf pointer might have changed. Restore eh, ip, and the - * fields NTOHS()'d. Then, if canfree==1, also restore *m0. + * mbuf pointer might have changed. Restore the fields NTOHS()'d. + * Then, if canfree==1, also restore *m0. */ - eh = mtod(m, struct ether_header *); - ip = (struct ip *)(eh + 1 ) ; HTONS(ip->ip_len); HTONS(ip->ip_id); HTONS(ip->ip_off); @@ -774,11 +759,10 @@ forward: * but better than having packets corrupt! */ if (canfree == 0 ) { - int needed = min(MHLEN, 14+max_protohdr) ; + int needed = min(MHLEN, max_protohdr) ; needed = min(needed, (*m0)->m_len ) ; - *m0 = m_pullup( *m0, needed) ; - if ( *m0 == NULL ) { + if ((*m0)->m_len < needed && (*m0 = m_pullup(*m0, needed)) == NULL) { printf("-- bdg: pullup failed.\n") ; return ENOBUFS ; } @@ -795,9 +779,13 @@ forward: return ENOBUFS ; /* the original is still there... */ } /* - * Last part of ether_output: queue pkt and start + * Last part of ether_output: add header, queue pkt and start * output if interface not yet active. */ + M_PREPEND(m, ETHER_HDR_LEN, M_DONTWAIT); + if (m == NULL) + return ENOBUFS; + bcopy(eh, mtod(m, struct ether_header *), ETHER_HDR_LEN); s = splimp(); if (IF_QFULL(&last->if_snd)) { IF_DROP(&last->if_snd); @@ -828,7 +816,7 @@ forward: ! IF_QFULL(&ifp->if_snd) && (ifp->if_flags & (IFF_UP|IFF_RUNNING)) == (IFF_UP|IFF_RUNNING) && - SAMECLUSTER(ifp, src, eh) && !MUTED(ifp) ) + SAMECLUSTER(ifp, src) && !MUTED(ifp) ) last = ifp ; ifp = ifp->if_link.tqe_next ; if (ifp == NULL) diff --git a/sys/net/bridge.h b/sys/net/bridge.h index 9be9078..ea2db41 100644 --- a/sys/net/bridge.h +++ b/sys/net/bridge.h @@ -49,9 +49,9 @@ extern int bdg_ports ; #define HASH_FN(addr) ( \ ntohs( ((short *)addr)[1] ^ ((short *)addr)[2] ) & (HASH_SIZE -1)) -struct ifnet *bridge_in(struct mbuf *m); +struct ifnet *bridge_in(struct ifnet *ifp, struct ether_header *eh); /* bdg_forward frees the mbuf if necessary, returning null */ -int bdg_forward (struct mbuf **m, struct ifnet *dst); +int bdg_forward(struct mbuf **m0, struct ether_header *eh, struct ifnet *dst); #ifdef __i386__ #define BDG_MATCH(a,b) ( \ @@ -109,9 +109,8 @@ struct bdg_stats { */ static __inline struct ifnet * -bridge_dst_lookup(struct mbuf *m) +bridge_dst_lookup(struct ether_header *eh) { - struct ether_header *eh = mtod(m, struct ether_header *); struct ifnet *dst ; int index ; u_char *eth_addr = bdg_addresses ; diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index f7a5158..1a5b0c9 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -56,6 +56,7 @@ #include <net/if_llc.h> #include <net/if_dl.h> #include <net/if_types.h> +#include <net/bpf.h> #if defined(INET) || defined(INET6) #include <netinet/in.h> @@ -365,19 +366,22 @@ ether_output(ifp, m, dst, rt0) return (0); /* XXX */ } } + #ifdef BRIDGE if (do_bridge) { - struct mbuf *m0 = m ; - - if (m->m_pkthdr.rcvif) - m->m_pkthdr.rcvif = NULL ; - ifp = bridge_dst_lookup(m); - bdg_forward(&m0, ifp); - if (m0) - m_freem(m0); + struct ether_header hdr; + + m->m_pkthdr.rcvif = NULL; + bcopy(mtod(m, struct ether_header *), &hdr, ETHER_HDR_LEN); + m_adj(m, ETHER_HDR_LEN); + ifp = bridge_dst_lookup(&hdr); + bdg_forward(&m, &hdr, ifp); + if (m != NULL) + m_freem(m); return (0); } #endif + s = splimp(); /* * Queue message on interface, and start output if interface @@ -421,6 +425,55 @@ ether_input(ifp, eh, m) register struct llc *l; #endif + /* Check for a BPF tap */ + if (ifp->if_bpf != NULL) { + struct m_hdr mh; + + /* This kludge is OK; BPF treats the "mbuf" as read-only */ + mh.mh_next = m; + mh.mh_data = (char *)eh; + mh.mh_len = ETHER_HDR_LEN; + bpf_mtap(ifp, (struct mbuf *)&mh); + } + +#ifdef BRIDGE + /* Check for bridging mode */ + if (do_bridge) { + struct ifnet *bif; + + /* Check with bridging code */ + if ((bif = bridge_in(ifp, eh)) == BDG_DROP) { + m_freem(m); + return; + } + if (bif != BDG_LOCAL) + bdg_forward(&m, eh, bif); /* needs forwarding */ + if (bif == BDG_LOCAL + || bif == BDG_BCAST + || bif == BDG_MCAST) + goto recvLocal; /* receive locally */ + + /* If not local and not multicast, just drop it */ + if (m != NULL) + m_freem(m); + return; + } +#endif + + /* Discard packet if upper layers shouldn't see it. This should + only happen when the interface is in promiscuous mode. */ + if ((ifp->if_flags & IFF_PROMISC) != 0 + && (eh->ether_dhost[0] & 1) == 0 + && bcmp(eh->ether_dhost, + IFP2AC(ifp)->ac_enaddr, ETHER_ADDR_LEN) != 0) { + m_freem(m); + return; + } + +#ifdef BRIDGE +recvLocal: +#endif + /* Discard packet if interface is not up */ if ((ifp->if_flags & IFF_UP) == 0) { m_freem(m); return; diff --git a/sys/net/if_vlan.c b/sys/net/if_vlan.c index 19d85b0..7bf08bd 100644 --- a/sys/net/if_vlan.c +++ b/sys/net/if_vlan.c @@ -305,19 +305,6 @@ vlan_input_tag(struct ether_header *eh, struct mbuf *m, u_int16_t t) */ m->m_pkthdr.rcvif = &ifv->ifv_if; - if (ifv->ifv_if.if_bpf) { - /* - * Do the usual BPF fakery. Note that we don't support - * promiscuous mode here, since it would require the - * drivers to know about VLANs and we're not ready for - * that yet. - */ - struct mbuf m0; - m0.m_next = m; - m0.m_len = sizeof(struct ether_header); - m0.m_data = (char *)eh; - bpf_mtap(&ifv->ifv_if, &m0); - } ifv->ifv_if.if_ipackets++; ether_input(&ifv->ifv_if, eh, m); return 0; @@ -355,19 +342,6 @@ vlan_input(struct ether_header *eh, struct mbuf *m) m->m_len -= EVL_ENCAPLEN; m->m_pkthdr.len -= EVL_ENCAPLEN; - if (ifv->ifv_if.if_bpf) { - /* - * Do the usual BPF fakery. Note that we don't support - * promiscuous mode here, since it would require the - * drivers to know about VLANs and we're not ready for - * that yet. - */ - struct mbuf m0; - m0.m_next = m; - m0.m_len = sizeof(struct ether_header); - m0.m_data = (char *)eh; - bpf_mtap(&ifv->ifv_if, &m0); - } ifv->ifv_if.if_ipackets++; ether_input(&ifv->ifv_if, eh, m); return 0; |