diff options
author | rwatson <rwatson@FreeBSD.org> | 2000-03-11 00:24:29 +0000 |
---|---|---|
committer | rwatson <rwatson@FreeBSD.org> | 2000-03-11 00:24:29 +0000 |
commit | 2bf7fb4443657c73135a45e4c526e1315a86d1db (patch) | |
tree | 43f1ca67a00b8dfcf13357b1ba0452403c08b5ff /sys/netinet/if_ether.c | |
parent | 024aa99ddd71845ee5ffdde94fa0e7dd00f30bbd (diff) | |
download | FreeBSD-src-2bf7fb4443657c73135a45e4c526e1315a86d1db.zip FreeBSD-src-2bf7fb4443657c73135a45e4c526e1315a86d1db.tar.gz |
The function arpintr() incorrectly checks m->m_len to detect incomplete
ARP packets. This can incorrectly reject complete frames since the frame
could be stored in more than one mbuf.
The following patches fix the length comparisson, and add several
diagnostic log messages to the interrupt handler for out-of-the-norm ARP
packets. This should make ARP problems easier to detect, diagnose and
fix.
Submitted by: C. Stephen Gunn <csg@waterspout.com>
Approved by: jkh
Reviewed by: rwatson
Diffstat (limited to 'sys/netinet/if_ether.c')
-rw-r--r-- | sys/netinet/if_ether.c | 49 |
1 files changed, 36 insertions, 13 deletions
diff --git a/sys/netinet/if_ether.c b/sys/netinet/if_ether.c index c87b72d..00bfb84 100644 --- a/sys/netinet/if_ether.c +++ b/sys/netinet/if_ether.c @@ -430,9 +430,9 @@ arpresolve(ac, rt, m, dst, desten, rt0) static void arpintr() { - register struct mbuf *m; + register struct mbuf *m, *m0; register struct arphdr *ar; - int s; + int s, ml; while (arpintrq.ifq_head) { s = splimp(); @@ -440,21 +440,44 @@ arpintr() splx(s); if (m == 0 || (m->m_flags & M_PKTHDR) == 0) panic("arpintr"); - if (m->m_len >= sizeof(struct arphdr) && - (ar = mtod(m, struct arphdr *)) && - (ntohs(ar->ar_hrd) == ARPHRD_ETHER || - ntohs(ar->ar_hrd) == ARPHRD_IEEE802) && - m->m_len >= - sizeof(struct arphdr) + 2 * ar->ar_hln + 2 * ar->ar_pln) + + if (m->m_len < sizeof(struct arphdr) && + (m = m_pullup(m, sizeof(struct arphdr)) == NULL)) { + log(LOG_ERR, "arp: runt packet -- m_pullup failed."); + continue; + } + ar = mtod(m, struct arphdr *); + + if (ntohs(ar->ar_hrd) != ARPHRD_ETHER + && ntohs(ar->ar_hrd) != ARPHRD_IEEE802) { + log(LOG_ERR, + "arp: unknown hardware address format (%2D)", + (unsigned char *)&ar->ar_hrd, ""); + m_freem(m); + continue; + } - switch (ntohs(ar->ar_pro)) { + m0 = m; + ml = 0; + while (m0 != NULL) { + ml += m0->m_len; /* wanna implement m_size?? */ + m0 = m0->m_next; + } + if (ml < sizeof(struct arphdr) + 2 * ar->ar_hln + + 2 * ar->ar_pln) { + log(LOG_ERR, "arp: runt packet."); + m_freem(m); + continue; + } + + switch (ntohs(ar->ar_pro)) { #ifdef INET - case ETHERTYPE_IP: - in_arpinput(m); - continue; + case ETHERTYPE_IP: + in_arpinput(m); + continue; #endif - } + } m_freem(m); } } |