Subject: Ethersubr fix for netiso
To: None <tech-net@netbsd.org>
From: Ignatios Souvatzis <is@netbsd.org>
List: tech-net
Date: 12/01/2006 14:52:10
--PEIAKu/WMn1b1Hv9
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Hi,
when Perry asked for NETISO testing code, I wrote some, and found bugs.
Basically, when ether_input() calls (indirectly) clnp_input(), it does
horrible things.
Namely, it does an overlapping struct assign (on a memory area
formerly m_adj'ed away!) which might have worked with ancient
compilers, but creates address corruption now. (== netbsd-3-1).
All to get rid of the intermediate 3-byte 802.x llc field.
As the clnp_input is aware of being called by ethernet anyway (and
sort of needs to), I decided to just give it the full ethernet
header with llc, and let it throw it away itself (it does an m_adj
itself, so this is for free). Saving in the ISO networking path:
two memcpy if done right, one memmove if the current code was
trivially repaired.
I suspect that any modern compiler would integrate one additional
compare-to-constant and and conditional branch (which are executed
additionally for the DIX protocols) into the big DIX switch, so no
cost created there, or else, say, 2 instruction cycles (== about one
nanosecond for modern machines).
if_fddisubr and if_tokensubr will need similar patches; at least for
fddi this won't create a penalty because it hasn't any DIX type
field, so there's a convenient switch case already to move the
m_adj() to.
Any comments?
(Code is tested for AF_INET, AF_INET6 and AF_ISO).
Regards,
-is
--PEIAKu/WMn1b1Hv9
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=ether_diff_netiso
Index: sys/netiso/clnp_input.c
===================================================================
RCS file: /cvsroot/src/sys/netiso/clnp_input.c,v
retrieving revision 1.30
diff -u -r1.30 clnp_input.c
--- sys/netiso/clnp_input.c 11 Dec 2005 12:25:12 -0000 1.30
+++ sys/netiso/clnp_input.c 1 Dec 2006 13:38:52 -0000
@@ -199,9 +199,7 @@
case IFT_ETHER:
bcopy((caddr_t) (mtod(m, struct ether_header *)->ether_dhost),
(caddr_t) sh.snh_dhost, 2 * sizeof(sh.snh_dhost));
- m->m_data += sizeof(struct ether_header);
- m->m_len -= sizeof(struct ether_header);
- m->m_pkthdr.len -= sizeof(struct ether_header);
+ m_adj(m, sizeof(struct ether_header) + 3);
break;
case IFT_FDDI:
bcopy((caddr_t) (mtod(m, struct fddi_header *)->fddi_dhost),
Index: sys/net/if_ethersubr.c
===================================================================
RCS file: /cvsroot/src/sys/net/if_ethersubr.c,v
retrieving revision 1.138
diff -u -r1.138 if_ethersubr.c
--- sys/net/if_ethersubr.c 24 Nov 2006 01:04:30 -0000 1.138
+++ sys/net/if_ethersubr.c 1 Dec 2006 13:38:52 -0000
@@ -859,62 +859,65 @@
}
}
- /* Strip off the Ethernet header. */
- m_adj(m, sizeof(struct ether_header));
-
/* If the CRC is still on the packet, trim it off. */
if (m->m_flags & M_HASFCS) {
m_adj(m, -ETHER_CRC_LEN);
m->m_flags &= ~M_HASFCS;
}
- switch (etype) {
+ if (etype > ETHERMTU + sizeof (struct ether_header)) {
+ /* Strip off the Ethernet header. */
+ m_adj(m, sizeof(struct ether_header));
+
+ switch (etype) {
#ifdef INET
- case ETHERTYPE_IP:
+ case ETHERTYPE_IP:
#ifdef GATEWAY
- if (ipflow_fastforward(m))
- return;
+ if (ipflow_fastforward(m))
+ return;
#endif
- schednetisr(NETISR_IP);
- inq = &ipintrq;
- break;
+ schednetisr(NETISR_IP);
+ inq = &ipintrq;
+ break;
- case ETHERTYPE_ARP:
- schednetisr(NETISR_ARP);
- inq = &arpintrq;
- break;
+ case ETHERTYPE_ARP:
+ schednetisr(NETISR_ARP);
+ inq = &arpintrq;
+ break;
- case ETHERTYPE_REVARP:
- revarpinput(m); /* XXX queue? */
- return;
+ case ETHERTYPE_REVARP:
+ revarpinput(m); /* XXX queue? */
+ return;
#endif
#ifdef INET6
- case ETHERTYPE_IPV6:
- schednetisr(NETISR_IPV6);
- inq = &ip6intrq;
- break;
+ case ETHERTYPE_IPV6:
+ schednetisr(NETISR_IPV6);
+ inq = &ip6intrq;
+ break;
#endif
#ifdef IPX
- case ETHERTYPE_IPX:
- schednetisr(NETISR_IPX);
- inq = &ipxintrq;
- break;
+ case ETHERTYPE_IPX:
+ schednetisr(NETISR_IPX);
+ inq = &ipxintrq;
+ break;
#endif
#ifdef NETATALK
- case ETHERTYPE_ATALK:
- schednetisr(NETISR_ATALK);
- inq = &atintrq1;
- break;
- case ETHERTYPE_AARP:
- /* probably this should be done with a NETISR as well */
- aarpinput(ifp, m); /* XXX */
- return;
+ case ETHERTYPE_ATALK:
+ schednetisr(NETISR_ATALK);
+ inq = &atintrq1;
+ break;
+ case ETHERTYPE_AARP:
+ /* probably this should be done with a NETISR as well */
+ aarpinput(ifp, m); /* XXX */
+ return;
#endif /* NETATALK */
- default:
+ default:
+ m_freem(m);
+ return;
+ }
+ } else {
#if defined (ISO) || defined (LLC) || defined (NETATALK)
- if (etype > ETHERMTU)
- goto dropanyway;
- l = mtod(m, struct llc *);
+ l = (struct llc *)(eh+1);
switch (l->llc_dsap) {
#ifdef NETATALK
case LLC_SNAP_LSAP:
@@ -929,7 +932,8 @@
ntohs(l->llc_snap_ether_type) ==
ETHERTYPE_ATALK) {
inq = &atintrq2;
- m_adj(m, sizeof(struct llc));
+ m_adj(m, sizeof(struct ether_header)
+ + sizeof(struct llc));
schednetisr(NETISR_ATALK);
break;
}
@@ -939,7 +943,8 @@
sizeof(aarp_org_code)) == 0 &&
ntohs(l->llc_snap_ether_type) ==
ETHERTYPE_AARP) {
- m_adj( m, sizeof(struct llc));
+ m_adj( m, sizeof(struct ether_header)
+ + sizeof(struct llc));
aarpinput(ifp, m); /* XXX */
return;
}
@@ -954,18 +959,13 @@
switch (l->llc_control) {
case LLC_UI:
/* LLC_UI_P forbidden in class 1 service */
- if ((l->llc_dsap == LLC_ISO_LSAP) &&
+ if ((l->llc_dsap == LLC_ISO_LSAP) && /* XXX? case tested */
(l->llc_ssap == LLC_ISO_LSAP)) {
/* LSAP for ISO */
- if (m->m_pkthdr.len > etype)
+ /* XXX length computation?? */
+ if (m->m_pkthdr.len > etype + sizeof(struct ether_header))
m_adj(m, etype - m->m_pkthdr.len);
- m->m_data += 3; /* XXX */
- m->m_len -= 3; /* XXX */
- m->m_pkthdr.len -= 3; /* XXX */
- M_PREPEND(m, sizeof *eh, M_DONTWAIT);
- if (m == 0)
- return;
- *mtod(m, struct ether_header *) = *eh;
+
#ifdef ARGO_DEBUG
if (argo_debug[D_ETHER])
printf("clnp packet");
@@ -978,7 +978,8 @@
case LLC_XID:
case LLC_XID_P:
- if(m->m_len < 6)
+ if(m->m_len < 6 + sizeof(struct ether_header))
+ /* XXX m_pullup? */
goto dropanyway;
l->llc_window = 0;
l->llc_fid = 9;
@@ -995,6 +996,8 @@
l->llc_dsap = l->llc_ssap;
l->llc_ssap = c;
+ m_adj(m, sizeof(struct ether_header));
+ /* XXX we can optimize here? */
if (m->m_flags & (M_BCAST | M_MCAST))
bcopy(LLADDR(ifp->if_sadl),
(caddr_t)eh->ether_dhost, 6);
@@ -1023,9 +1026,9 @@
m_freem(m);
return;
}
-#else /* ISO || LLC || NETATALK*/
- m_freem(m);
- return;
+#else /* ISO || LLC || NETATALK*/
+ m_freem(m);
+ return;
#endif /* ISO || LLC || NETATALK*/
}
--PEIAKu/WMn1b1Hv9--