summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjulian <julian@FreeBSD.org>1999-10-26 11:40:23 +0000
committerjulian <julian@FreeBSD.org>1999-10-26 11:40:23 +0000
commit226fbf47146cb040a886724dee6ba4250518539e (patch)
treed160098d30285050d8e8651b88c47461fc0a0099
parent48eeb0662db3f5abb8727e7567fc64ec7468a9d1 (diff)
downloadFreeBSD-src-226fbf47146cb040a886724dee6ba4250518539e.zip
FreeBSD-src-226fbf47146cb040a886724dee6ba4250518539e.tar.gz
Minor hack in the netgraph interface to ethernets.
-rw-r--r--sys/net/if_ethersubr.c71
1 files changed, 60 insertions, 11 deletions
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c
index 04e3ea8..79d8b62 100644
--- a/sys/net/if_ethersubr.c
+++ b/sys/net/if_ethersubr.c
@@ -1133,29 +1133,78 @@ bad:
/*
* pass an mbuf out to the connected hook
- */
+ * More complicated than just an m_prepend, as it tries to save later nodes
+ * from needing to do lots of m_pullups.
+ */
static void
ngether_send(struct arpcom *ac, struct ether_header *eh, struct mbuf *m)
-{
+{
+ int room;
node_p node = AC2NG(ac);
struct ether_header *eh2;
-
+
if (node && LIST_FIRST(&(node->hooks))) {
- M_PREPEND(m, sizeof(*eh), M_DONTWAIT);
- if (m == 0)
- return;
- eh2 = mtod(m, struct ether_header *);
/*
- * Possibly 'eh' already points
- * to the right place.
+ * Possibly the header is already on the front,
*/
- if (eh2 != eh)
- bcopy(eh, eh2, sizeof(*eh));
+ eh2 = mtod(m, struct ether_header *) - 1;
+ if ( eh == eh2) {
+ /*
+ * This is the case so just move the markers back to
+ * re-include it. We lucked out.
+ * This allows us to avoid a yucky m_pullup
+ * in later nodes if it works.
+ */
+ m->m_len += sizeof(*eh);
+ m->m_data -= sizeof(*eh);
+ m->m_pkthdr.len += sizeof(*eh);
+ } else {
+ /*
+ * Alternatively there may be room even though
+ * it is stored somewhere else. If so, copy it in.
+ * This only safe because we KNOW that this packet has
+ * just been generated by an ethernet card, so there
+ * are no aliases to the buffer. (unlike in outgoing
+ * packets).
+ * Nearly all ethernet cards will end up producing mbufs
+ * that fall into these cases. So we are not optimising
+ * contorted cases.
+ */
+
+ if (m->m_flags & M_EXT) {
+ room = (mtod(m, caddr_t) - m->m_ext.ext_buf);
+ if (room > m->m_ext.ext_size) /* garbage */
+ room = 0; /* fail immediatly */
+ } else {
+ room = (mtod(m, caddr_t) - m->m_pktdat);
+ }
+ if (room > sizeof (*eh)) {
+ /* we have room, just copy it and adjust */
+ m->m_len += sizeof(*eh);
+ m->m_data -= sizeof(*eh);
+ m->m_pkthdr.len += sizeof(*eh);
+ bcopy ((caddr_t)eh, (caddr_t)eh2, sizeof(*eh));
+ } else {
+ /*
+ * Doing anything more is likely to get more
+ * expensive than it's worth..
+ * it's probable that everything else is in one
+ * big lump. The next node will do an m_pullup()
+ * for exactly the amount of data it needs and
+ * hopefully everything after that will not
+ * need one. So let's just use m_prepend.
+ */
+ m = m_prepend(m, MHLEN, M_DONTWAIT);
+ if (m == NULL)
+ return;
+ }
+ }
ng_queue_data(LIST_FIRST(&(node->hooks)), m, NULL);
} else {
m_freem(m);
}
}
+
/*
* do local shutdown processing..
* This node will refuse to go away, unless the hardware says to..
OpenPOWER on IntegriCloud