Date: Wed, 25 Aug 1999 17:20:00 +0700 From: bp@butya.kz To: FreeBSD-gnats-submit@freebsd.org Subject: kern/13374: PATCH: IPX checksuming code doesn't work at all Message-ID: <E11Ja9w-0007pf-00@lion.butya.kz>
next in thread | raw e-mail | index | archive | help
>Number: 13374 >Category: kern >Synopsis: PATCH: IPX checksuming code doesn't work at all >Confidential: no >Severity: serious >Priority: high >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Wed Aug 25 03:30:00 PDT 1999 >Closed-Date: >Last-Modified: >Originator: Boris Popov >Release: FreeBSD 3.2-STABLE i386 >Organization: none >Environment: 3.2-stable, 4.0-current with IPX support >Description: IPX checksums aren't calculated correctly (they was copied from XNS stack). This patch corrects this problem and enables using of chksums on a per socket basis. >How-To-Repeat: Try to use IPX checksums in NetWare environment. >Fix: diff -u org/ipx.h ./ipx.h --- org/ipx.h Mon Feb 16 00:00:00 1998 +++ ./ipx.h Wed Aug 25 12:15:04 1999 @@ -95,6 +95,7 @@ #define SO_ALL_PACKETS 7 #define SO_MTU 8 #define SO_IPXTUN_ROUTE 9 +#define SO_IPX_CHECKSUM 10 /* * IPX addressing diff -u org/ipx_cksum.c ./ipx_cksum.c --- org/ipx_cksum.c Mon Feb 16 00:00:00 1998 +++ ./ipx_cksum.c Wed Aug 25 16:58:24 1999 @@ -38,173 +38,76 @@ #include <sys/param.h> #include <sys/mbuf.h> +#include <sys/libkern.h> +#include <netipx/ipx.h> #include <netipx/ipx_var.h> -/* - * Checksum routine for Network Systems Protocol Packets (Big-Endian). - * - * This routine is very heavily used in the network - * code and should be modified for each CPU to be as fast as possible. - */ -#define ADDCARRY(x) { if ((x) > 65535) (x) -= 65535; } -#define FOLD(x) {l_util.l = (x); (x) = l_util.s[0] + l_util.s[1]; ADDCARRY(x);} +#define SUMADV sum += *w++ u_short -ipx_cksum(m, len) - struct mbuf *m; - int len; -{ - register u_short *w; - register int sum = 0; - register int mlen = 0; - register int sum2; - +ipx_cksum(struct mbuf *m, int len) { + u_int32_t sum = 0; + u_short *w; + u_char oldtc; + int mlen, words; + struct ipx *ipx; union { - u_short s[2]; - long l; - } l_util; - - for (;m != NULL && len; m = m->m_next) { - if (m->m_len == 0) - continue; - /* - * Each trip around loop adds in - * word from one mbuf segment. - */ - w = mtod(m, u_short *); - if (mlen == -1) { - /* - * There is a byte left from the last segment; - * ones-complement add it into the checksum. - */ -#if BYTE_ORDER == BIG_ENDIAN - sum += *(u_char *)w; -#else - sum += *(u_char *)w << 8; -#endif - sum += sum; - w = (u_short *)(1 + (char *)w); - mlen = m->m_len - 1; - len--; - FOLD(sum); - } else - mlen = m->m_len; - if (len < mlen) - mlen = len; - len -= mlen; - /* - * We can do a 16 bit ones complement sum using - * 32 bit arithmetic registers for adding, - * with carries from the low added - * into the high (by normal carry-chaining) - * so long as we fold back before 16 carries have occured. - */ - if (1 & (int) w) - goto uuuuglyy; -#ifndef TINY -/* -DTINY reduces the size from 1250 to 550, but slows it down by 22% */ - while ((mlen -= 32) >= 0) { - sum += w[0]; sum += sum; sum += w[1]; sum += sum; - sum += w[2]; sum += sum; sum += w[3]; sum += sum; - sum += w[4]; sum += sum; sum += w[5]; sum += sum; - sum += w[6]; sum += sum; sum += w[7]; sum += sum; - FOLD(sum); - sum += w[8]; sum += sum; sum += w[9]; sum += sum; - sum += w[10]; sum += sum; sum += w[11]; sum += sum; - sum += w[12]; sum += sum; sum += w[13]; sum += sum; - sum += w[14]; sum += sum; sum += w[15]; sum += sum; - FOLD(sum); - w += 16; - } - mlen += 32; -#endif - while ((mlen -= 8) >= 0) { - sum += w[0]; sum += sum; sum += w[1]; sum += sum; - sum += w[2]; sum += sum; sum += w[3]; sum += sum; - FOLD(sum); - w += 4; - } - mlen += 8; - while ((mlen -= 2) >= 0) { - sum += *w++; sum += sum; - } - goto commoncase; -uuuuglyy: -#if BYTE_ORDER == BIG_ENDIAN -#define ww(n) (((u_char *)w)[n + n + 1]) -#define vv(n) (((u_char *)w)[n + n]) -#else -#if BYTE_ORDER == LITTLE_ENDIAN -#define vv(n) (((u_char *)w)[n + n + 1]) -#define ww(n) (((u_char *)w)[n + n]) -#endif -#endif - sum2 = 0; -#ifndef TINY - while ((mlen -= 32) >= 0) { - sum += ww(0); sum += sum; sum += ww(1); sum += sum; - sum += ww(2); sum += sum; sum += ww(3); sum += sum; - sum += ww(4); sum += sum; sum += ww(5); sum += sum; - sum += ww(6); sum += sum; sum += ww(7); sum += sum; - FOLD(sum); - sum += ww(8); sum += sum; sum += ww(9); sum += sum; - sum += ww(10); sum += sum; sum += ww(11); sum += sum; - sum += ww(12); sum += sum; sum += ww(13); sum += sum; - sum += ww(14); sum += sum; sum += ww(15); sum += sum; - FOLD(sum); - sum2 += vv(0); sum2 += sum2; sum2 += vv(1); sum2 += sum2; - sum2 += vv(2); sum2 += sum2; sum2 += vv(3); sum2 += sum2; - sum2 += vv(4); sum2 += sum2; sum2 += vv(5); sum2 += sum2; - sum2 += vv(6); sum2 += sum2; sum2 += vv(7); sum2 += sum2; - FOLD(sum2); - sum2 += vv(8); sum2 += sum2; sum2 += vv(9); sum2 += sum2; - sum2 += vv(10); sum2 += sum2; sum2 += vv(11); sum2 += sum2; - sum2 += vv(12); sum2 += sum2; sum2 += vv(13); sum2 += sum2; - sum2 += vv(14); sum2 += sum2; sum2 += vv(15); sum2 += sum2; - FOLD(sum2); - w += 16; - } - mlen += 32; -#endif - while ((mlen -= 8) >= 0) { - sum += ww(0); sum += sum; sum += ww(1); sum += sum; - sum += ww(2); sum += sum; sum += ww(3); sum += sum; - FOLD(sum); - sum2 += vv(0); sum2 += sum2; sum2 += vv(1); sum2 += sum2; - sum2 += vv(2); sum2 += sum2; sum2 += vv(3); sum2 += sum2; - FOLD(sum2); - w += 4; - } - mlen += 8; - while ((mlen -= 2) >= 0) { - sum += ww(0); sum += sum; - sum2 += vv(0); sum2 += sum2; - w++; - } - sum += (sum2 << 8); -commoncase: - if (mlen == -1) { -#if BYTE_ORDER == BIG_ENDIAN - sum += *(u_char *)w << 8; -#else - sum += *(u_char *)w; -#endif - } - FOLD(sum); - } - if (mlen == -1) { - /* We had an odd number of bytes to sum; assume a garbage - byte of zero and clean up */ - sum += sum; - FOLD(sum); + u_char b[2]; + u_short w; + } buf; + + ipx = mtod(m, struct ipx*); + oldtc = ipx->ipx_tc; + ipx->ipx_tc = 0; + w = &ipx->ipx_len; + len -= 2; + mlen = 2; + + for(;;) { + mlen = imin(m->m_len - mlen, len); + words = mlen / 2; + len -= mlen & ~1; + while (words >= 16) { + SUMADV; SUMADV; SUMADV; SUMADV; + SUMADV; SUMADV; SUMADV; SUMADV; + SUMADV; SUMADV; SUMADV; SUMADV; + SUMADV; SUMADV; SUMADV; SUMADV; + words -= 16; + } + while (words--) + SUMADV; + if (len == 0) + break; + mlen &= 1; + if (mlen) { + buf.b[0] = *(u_char*)w; + if (--len == 0) { + buf.b[1] = 0; + sum += buf.w; + break; + } + } + m = m->m_next; + if (m == NULL) + break; + w = mtod(m, u_short*); + if (mlen) { + buf.b[1] = *(u_char*)w; + sum += buf.w; + ((u_char*)w)++; + if (--len == 0) + break; + } } - /* - * sum has already been kept to low sixteen bits. - * just examine result and exit. - */ - if(sum == 0xffff) - sum = 0; + + ipx->ipx_tc = oldtc; + + sum = (sum & 0xffff) + (sum >> 16); + if (sum >= 0x10000) + sum++; + if (sum) + sum = ~sum; return (sum); } diff -u org/ipx_input.c ./ipx_input.c --- org/ipx_input.c Mon Jun 22 01:00:00 1998 +++ ./ipx_input.c Wed Aug 25 16:57:43 1999 @@ -130,9 +130,7 @@ register struct mbuf *m; register struct ipxpcb *ipxp; struct ipx_ifaddr *ia; - register int i; int len, s; - char oddshortpacket = 0; next: /* @@ -171,15 +169,6 @@ ipx = mtod(m, struct ipx *); len = ntohs(ipx->ipx_len); - if ((len < m->m_pkthdr.len) && (oddshortpacket = len & 1)) { - /* - * If this packet is of odd length, and the length - * inside the header is less than the received packet - * length, preserve garbage byte for possible checksum. - */ - len++; - } - /* * Check that the amount of data in the buffers * is as at least much as the IPX header would have us expect. @@ -197,9 +186,8 @@ } else m_adj(m, len - m->m_pkthdr.len); } - if (ipxcksum && ((i = ipx->ipx_sum) != 0xffff)) { - ipx->ipx_sum = 0; - if (i != (ipx->ipx_sum = ipx_cksum(m, len))) { + if (ipxcksum && ipx->ipx_sum != 0xffff) { + if (ipx->ipx_sum != ipx_cksum(m, len)) { ipxstat.ipxs_badsum++; goto bad; } @@ -274,9 +262,6 @@ * Switch out to protocol's input routine. */ if (ipxp != NULL) { - if (oddshortpacket) { - m_adj(m, -1); - } ipxstat.ipxs_delivered++; if ((ipxp->ipxp_flags & IPXP_ALL_PACKETS) == 0) switch (ipx->ipx_pt) { @@ -396,32 +381,15 @@ goto cleanup; } } - /* XXX - * I think the checksum generation is bogus. According to the NLSP - * spec the ipx_tc (hop count) field and the ipx_sum should be - * zero'ed before generating the checksum, ie. it should not be - * necesary to recompute it in the forwarding function. + /* + * We don't need to recompute checksum because ipx_tc field + * is ignored by checksum calculation routine, however + * it may be desirable to reset checksum if ipxcksum == 0 */ - /* need to adjust checksum */ - if (ipxcksum && ipx->ipx_sum != 0xffff) { - union bytes { - u_char c[4]; - u_short s[2]; - long l; - } x; - register int shift; - x.l = 0; - x.c[0] = agedelta; - shift = (((((int)ntohs(ipx->ipx_len)) + 1) >> 1) - 2) & 0xf; - x.l = ipx->ipx_sum + (x.s[0] << shift); - x.l = x.s[0] + x.s[1]; - x.l = x.s[0] + x.s[1]; - if (x.l == 0xffff) - ipx->ipx_sum = 0; - else - ipx->ipx_sum = x.l; - } else +#if 0 + if (!ipxcksum) ipx->ipx_sum = 0xffff; +#endif error = ipx_outputfl(m, &ipx_droute, flags); if (error == 0) { diff -u org/ipx_outputfl.c ./ipx_outputfl.c --- org/ipx_outputfl.c Sun Apr 11 14:46:00 1999 +++ ./ipx_outputfl.c Wed Aug 25 12:17:07 1999 @@ -247,12 +247,8 @@ ipx->ipx_dna.x_net = dst.sipx_addr.x_net; m1 = m_copym(m, 0, M_COPYALL, M_DONTWAIT); - if(ipx->ipx_sum != 0xffff) { - int len = ntohs(ipx->ipx_len); - ipx->ipx_sum = 0; - len = ((len - 1) | 1) + 1; - ipx->ipx_sum = ipx_cksum(m, len); - } + if(ipx->ipx_sum != 0xffff) + ipx->ipx_sum = ipx_cksum(m, ntohs(ipx->ipx_len)); if(m1) { error = (*ifp->if_output)(ifp, m1, (struct sockaddr *)&dst, NULL); diff -u org/ipx_pcb.c ./ipx_pcb.c --- org/ipx_pcb.c Sat May 22 00:22:00 1999 +++ ./ipx_pcb.c Wed Aug 25 12:15:04 1999 @@ -66,6 +66,8 @@ return (ENOBUFS); bzero(ipxp, sizeof *ipxp); ipxp->ipxp_socket = so; + if (ipxcksum) + ipxp->ipxp_flags |= IPXP_CHECKSUM; insque(ipxp, head); so->so_pcb = (caddr_t)ipxp; return (0); diff -u org/ipx_pcb.h ./ipx_pcb.h --- org/ipx_pcb.h Mon Feb 16 00:00:00 1998 +++ ./ipx_pcb.h Wed Aug 25 12:15:05 1999 @@ -64,6 +64,7 @@ #define IPXP_RAWIN 0x2 /* show headers on input */ #define IPXP_RAWOUT 0x4 /* show header on output */ #define IPXP_ALL_PACKETS 0x8 /* Turn off higher proto processing */ +#define IPXP_CHECKSUM 0x10 /* use checksum on this socket */ #define IPX_WILDCARD 1 diff -u org/ipx_usrreq.c ./ipx_usrreq.c --- org/ipx_usrreq.c Sat May 22 00:22:00 1999 +++ ./ipx_usrreq.c Wed Aug 25 12:17:27 1999 @@ -214,7 +214,7 @@ m = mprev; if ((m->m_flags & M_EXT) == 0 && (m->m_len + m->m_data < &m->m_dat[MLEN])) { - m->m_len++; + mtod(m, char*)[m->m_len++] = 0; } else { struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); @@ -250,9 +250,7 @@ ipx->ipx_len = htons((u_short)len); - if (ipxcksum) { - ipx->ipx_sum = 0; - len = ((len - 1) | 1) + 1; + if (ipxp->ipxp_flags & IPXP_CHECKSUM) { ipx->ipx_sum = ipx_cksum(m, len); } else ipx->ipx_sum = 0xffff; @@ -333,6 +331,10 @@ case SO_HEADERS_ON_INPUT: mask = IPXP_RAWIN; goto get_flags; + + case SO_IPX_CHECKSUM: + mask = IPXP_CHECKSUM; + goto get_flags; case SO_HEADERS_ON_OUTPUT: mask = IPXP_RAWOUT; @@ -371,6 +373,9 @@ case SO_HEADERS_ON_INPUT: mask = IPXP_RAWIN; goto set_head; + + case SO_IPX_CHECKSUM: + mask = IPXP_CHECKSUM; case SO_HEADERS_ON_OUTPUT: mask = IPXP_RAWOUT; Only in .: org diff -u org/spx_usrreq.c ./spx_usrreq.c --- org/spx_usrreq.c Sun Feb 7 11:15:00 1999 +++ ./spx_usrreq.c Wed Aug 25 12:17:54 1999 @@ -1081,11 +1081,7 @@ si->si_ack = htons(cb->s_ack); if (ipxcksum) { - si->si_sum = 0; - len = ntohs(si->si_len); - if (len & 1) - len++; - si->si_sum = ipx_cksum(m, len); + si->si_sum = ipx_cksum(m, ntohs(si->si_len)); } else si->si_sum = 0xffff; >Release-Note: >Audit-Trail: >Unformatted: To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-bugs" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?E11Ja9w-0007pf-00>