From f0e881b9d32cf7b9e101a60b5eea3fb94093124a Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Fri, 27 Aug 1999 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1999-08-27 --- ip/tcp.c | 27 +++++++++------- port/devbridge.c | 84 ++++++++++++++++++++++++++++++++++-------------- 2 files changed, 74 insertions(+), 37 deletions(-) diff --git a/ip/tcp.c b/ip/tcp.c index 5f2c6a0d6e8c2e621aa140735b4c0849ac03f71e..b8f8b5af9c8cb6117bf43d3a8d91038dc7da0deb 100644 --- a/ip/tcp.c +++ b/ip/tcp.c @@ -766,7 +766,8 @@ ntohtcp(Tcp *tcph, Block **bpp) Tcphdr *h; uchar *optr; ushort hdrlen; - ushort i, optlen; + ushort optlen; + int n; *bpp = pullupblock(*bpp, TCP_PKT+TCP_HDRSIZE); if(*bpp == nil) @@ -800,23 +801,25 @@ ntohtcp(Tcp *tcph, Block **bpp) tcph->wnd, nhgets(h->length)-hdrlen-TCP_PKT); */ optr = h->tcpopt; - for(i = TCP_HDRSIZE; i < hdrlen;) { - switch(optr[i]) { - default: - i += optr[i+1]; - break; - case EOLOPT: - return hdrlen; - case NOOPOPT: - i++; + n = hdrlen - TCP_HDRSIZE; + while(n > 0 && *optr != EOLOPT) { + if(*optr == NOOPOPT) { + n--; + optr++; + continue; + } + optlen = optr[1]; + if(optlen < 2 || optlen > n) break; +if(0) print("tcpopt %d %d\n", *optr, optlen); + switch(*optr) { case MSSOPT: - optlen = optr[i+1]; if(optlen == MSS_LENGTH) tcph->mss = nhgets(optr+2); - i += optlen; break; } + n -= optlen; + optr += optlen; } return hdrlen; } diff --git a/port/devbridge.c b/port/devbridge.c index eeef75481329d2aae9380d20450f1e353ef8d9f8..ba71ee8c5816c2e50e87dff29f20f05819e08c7a 100644 --- a/port/devbridge.c +++ b/port/devbridge.c @@ -135,8 +135,11 @@ enum { IP_VER = 0x40, /* Using IP version 4 */ IP_HLEN = 0x05, /* Header length in characters */ IP_TCPPROTO = 6, + EOLOPT = 0, + NOOPOPT = 1, MSSOPT = 2, MSS_LENGTH = 4, /* Mean segment size */ + SYN = 0x02, /* Pkt. is synchronise */ }; struct Iphdr @@ -163,9 +166,6 @@ struct Tcphdr uchar win[2]; uchar cksum[2]; uchar urg[2]; - /* Options segment */ - uchar opt[2]; - uchar mss[2]; }; static Bridge bridgetab[Maxbridge]; @@ -850,20 +850,20 @@ ethermultiwrite(Bridge *b, Block *bp, Port *port) } static void -tcpmsshack(Block *bp) +tcpmsshack(Etherpkt *epkt, int n) { - int n = BLEN(bp); int hl; - Etherpkt *epkt; Iphdr *iphdr; Tcphdr *tcphdr; + ulong mss; + ulong cksum; + int optlen; + uchar *optr; - epkt = (Etherpkt*)bp->rp; // check it is an ip packet if(nhgets(epkt->type) != 0x800) return; -print("tcpmsshack is IP\n"); - iphdr = (Iphdr*)(bp->rp + ETHERHDRSIZE); + iphdr = (Iphdr*)(epkt->data); n -= ETHERHDRSIZE; if(n < sizeof(Iphdr)) return; @@ -873,30 +873,65 @@ print("tcpmsshack is IP\n"); hl = (iphdr->vihl&0xF)<<2; if((iphdr->vihl&0xF0) != IP_VER || hl < (IP_HLEN<<2)) return; - } else { + } else hl = IP_HLEN<<2; - } -print("tcpmsshack is ok IP\n"); // check TCP if(iphdr->proto != IP_TCPPROTO) return; -print("tcpmsshack is TCP\n"); - tcphdr = (Tcphdr*)((uchar*)(iphdr) + hl); n -= hl; if(n < sizeof(Tcphdr)) return; + tcphdr = (Tcphdr*)((uchar*)(iphdr) + hl); + // MSS can only appear in SYN packet + if(!(tcphdr->flag[1] & SYN)) + return; hl = (tcphdr->flag[0] & 0xf0)>>2; - if(hl < sizeof(Tcphdr)) + if(n < hl) return; -print("tcpmsshack is big enough\n"); + // check for MSS option - // for the momment, assume MSS is the first option - // we could do better, but since options are not aligned, - // this would make the checksum correction code tougher - if(tcphdr->opt[0] != MSSOPT || tcphdr->opt[1] != MSS_LENGTH) + optr = (uchar*)(tcphdr) + sizeof(Tcphdr); + n = hl - sizeof(Tcphdr); + for(;;) { + if(n <= 0 || *optr == EOLOPT) return; -print("got mss = %d\n", nhgets(tcphdr->mss)); + if(*optr == NOOPOPT) { + n--; + optr++; + continue; + } + optlen = optr[1]; + if(optlen < 2 || optlen > n) + return; + if(*optr == MSSOPT && optlen == MSS_LENGTH) + break; + n -= optlen; + optr += optlen; + } + + mss = nhgets(optr+2); + if(mss <= TcpMssMax) + return; + // fit checksum + cksum = nhgets(tcphdr->cksum); + if(optr-(uchar*)tcphdr & 1) { +print("tcpmsshack: odd alignment!\n"); + // odd alignments are a pain + cksum += nhgets(optr+1); + cksum -= (optr[1]<<8)|(TcpMssMax>>8); + cksum += (cksum>>16); + cksum &= 0xffff; + cksum += nhgets(optr+3); + cksum -= ((TcpMssMax&0xff)<<8)|optr[4]; + cksum += (cksum>>16); + } else { + cksum += mss; + cksum -= TcpMssMax; + cksum += (cksum>>16); + } + hnputs(tcphdr->cksum, cksum); + hnputs(optr+2, TcpMssMax); } /* @@ -937,8 +972,11 @@ if(0)print("devbridge: etherread: blocklen = %d\n", blocklen(bp)); if(blocklen(bp) < ETHERMINTU) error("short packet"); port->in++; + ep = (Etherpkt*)bp->rp; cacheupdate(b, ep->s, port->id); + if(b->tcpmss) + tcpmsshack(ep, BLEN(bp)); if(ep->d[0] & 1) { log(b, Logmcast, "mulitcast: port=%d src=%E dst=%E type=%#.4ux\n", @@ -951,14 +989,10 @@ if(0)print("devbridge: etherread: blocklen = %d\n", blocklen(bp)); if(ce == nil) { b->miss++; port->inunknown++; - if(b->tcpmss) - tcpmsshack(bp); bp2 = bp; bp = nil; ethermultiwrite(b, bp2, port); } else if (ce->port != port->id) { b->hit++; - if(b->tcpmss) - tcpmsshack(bp); bp2 = bp; bp = nil; oport = b->port[ce->port]; oport->out++;