summaryrefslogtreecommitdiffstats
path: root/sys/net
diff options
context:
space:
mode:
authorarchie <archie@FreeBSD.org>2000-05-14 02:18:43 +0000
committerarchie <archie@FreeBSD.org>2000-05-14 02:18:43 +0000
commitfa21035b4e2f11d2c8f90174690853600b670e2d (patch)
tree9afb8dacfff6d7607064d8aa2bbf2da5069e8be6 /sys/net
parentd066b073153b986a54fd18a31d6bcc5d697933a2 (diff)
downloadFreeBSD-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.c58
-rw-r--r--sys/net/bridge.h7
-rw-r--r--sys/net/if_ethersubr.c69
-rw-r--r--sys/net/if_vlan.c26
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;
OpenPOWER on IntegriCloud