From 0cce6ce90069d8914d160dfb6511736eb61f2dfc Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Thu, 3 Sep 1992 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1992-09-03 --- pc/dat.h | 28 +++-- pc/devhard.c | 275 +++++++++++++++++++++++++---------------------- pc/main.c | 38 +++++-- port/devbit.c | 24 ++++- port/devip.c | 37 ++++--- port/ipdat.h | 18 ++-- port/tcpif.c | 21 ++-- port/tcpinput.c | 127 +++++++++++----------- port/tcpoutput.c | 47 ++++---- port/tcptimer.c | 125 ++++++++++----------- 10 files changed, 400 insertions(+), 340 deletions(-) diff --git a/pc/dat.h b/pc/dat.h index bb094b441d6631f37ae29747772c25be9595f727..0bdcc569e2dfef566e7f439671d65bdf1f183b8b 100644 --- a/pc/dat.h +++ b/pc/dat.h @@ -182,14 +182,30 @@ extern User *u; extern int flipD[]; /* for flipping bitblt destination polarity */ +/* + * bootline passed by boot program + */ +#define BOOTLINE ((char *)0x80000100) + +/* + * configuration info + */ enum { - PMUnsx20= 0, - PMUother= 1, - - Mouseserial= 0, - MousePS2= 1, - Mouseother= 2, + /* what kind of power management */ + PMUother= 0, + PMUnsx20= 1, + + /* what kind of mouse */ + Mouseother= 0, + Mouseserial= 1, + MousePS2= 2, + + /* how to reset the processor */ + Resetother= 0, + Reset8042= 1, + Resetheadland= 2, }; extern int mousetype; extern int pmutype; +extern int resettype; diff --git a/pc/devhard.c b/pc/devhard.c index f308dc39d8f26065209fc4ab65b5a2994fc080e8..a873afd495247bf14e4eccde751436c22bb3545f 100644 --- a/pc/devhard.c +++ b/pc/devhard.c @@ -6,7 +6,7 @@ #include "io.h" #include "../port/error.h" -#define DPRINT if(0)print +#define DPRINT if(1)print typedef struct Drive Drive; typedef struct Ident Ident; @@ -53,44 +53,6 @@ enum #define DRIVE(x) (((x)>>4)&0x7) #define MKQID(d,p) (((d)<<4) | (p)) -/* - * ident sector from drive - */ -struct Ident -{ - ushort magic; /* drive type magic */ - ushort lcyls; /* logical number of cylinders */ - ushort rcyl; /* number of removable cylinders */ - ushort lheads; /* logical number of heads */ - ushort b2t; /* unformatted bytes/track */ - ushort b2s; /* unformated bytes/sector */ - ushort ls2t; /* logical sectors/track */ - ushort gap; /* bytes in inter-sector gaps */ - ushort sync; /* bytes in sync fields */ - ushort magic2; /* must be 0x0000 */ - ushort serial[10]; /* serial number */ - ushort type; /* controller type (0x0003) */ - ushort bsize; /* buffer size/512 */ - ushort ecc; /* ecc bytes returned by read long */ - ushort firm[4]; /* firmware revision */ - ushort model[20]; /* model number */ - ushort s2i; /* number of sectors/interrupt */ - ushort dwtf; /* double word transfer flag */ - ushort alernate; - ushort piomode; - ushort dmamode; - ushort reserved[76]; - ushort ncyls; /* native number of cylinders */ - ushort nheads; /* native number of heads, sectors */ - ushort dlcyls; /* default logical number of cyinders */ - ushort dlheads; /* default logical number of heads, sectors */ - ushort interface; - ushort power; /* 0xFFFF if power commands supported */ - ushort flags; - ushort ageprog; /* MSB = age, LSB = program */ - ushort reserved2[120]; -}; - struct Partition { ulong start; @@ -126,8 +88,6 @@ struct Drive int sectors; /* sectors/track */ int heads; /* heads/cyl */ long cyl; /* cylinders/drive */ - - Ident id; /* disk properties */ }; /* @@ -161,8 +121,9 @@ static void hardintr(Ureg*); static long hardxfer(Drive*, Partition*, int, long, long, char*); static void hardident(Drive*); static void hardsetbuf(Drive*, int); -static void hardinitparam(Drive*); +static void hardparams(Drive*); static void hardpart(Drive*); +static int hardprobe(Drive*, int, int, int); static int hardgen(Chan *c, Dirtab *tab, long ntab, long s, Dir *dirp) @@ -237,66 +198,24 @@ Chan* hardattach(char *spec) { Drive *dp; - static int drivecomment=1; for(dp = hard; dp < &hard[conf.nhard]; dp++){ - if(!waserror()){ - /* - * the following is magic to determine the parameters - * (number of cylinders/sectors/heads) on an IDE drive. - * I haven't found a method that is guaranteed to work. - * For some drives, it may be necessary to compile the - * numbers into this driver and circumvent this code. - * The BIOS disk type & tables doesn't help since the - * types are inconsistent from one BIOS to the next. - */ - dp->bytes = 512; /* until we know better */ - hardsetbuf(dp, 0); /* turned off during ident */ - hardident(dp); - hardsetbuf(dp, 1); - /* - * for now use the configuration word to identify the - * wayward 6386 disk. BUG!!! This word isn't - * meant to identify disks, but we have nothing - * better. - */ - switch(dp->id.magic){ - case 0x324A: /* hard drive on the AT&T 6386, it lies */ - dp->cyl = dp->id.lcyls - 4; - dp->heads = dp->id.lheads; - dp->sectors = dp->id.ls2t - 1; - break; - default: /* others: we hope this works */ - dp->cyl = dp->id.lcyls; - dp->heads = dp->id.lheads; - dp->sectors = dp->id.ls2t; - break; - } - dp->bytes = 512; - dp->cap = dp->bytes * dp->cyl * dp->heads * dp->sectors; - dp->online = 1; - /* - * Try reading the partition table (last disk sector). - * If an error occurs set the drive parameters and try - * again. This works if the parameters reported - * by the disk are the physical parameters rather than - * the current logical ones (as they are on the NCR 3170). - * - * We don't routinely set the parameters since it confuses - * some disks (on the Gateway and AT&T Safari for example). - */ - if(waserror()){ - hardinitparam(dp); /* set drive parameters */ - hardpart(); - } else { - hardpart(); - poperror(); - } - poperror(); - } else + if(waserror()){ dp->online = 0; + continue; + } + if(!dp->online){ + hardparams(dp); + dp->online = 1; + hardsetbuf(dp, 1); + } + + /* + * read Plan 9 partition table + */ + hardpart(dp); + poperror(); } - drivecomment=0; /* only the first time */ return devattach('w', spec); } @@ -629,35 +548,42 @@ hardsetbuf(Drive *dp, int on) } /* - * set the drive parameters + * ident sector from drive */ -static void -hardinitparam(Drive *dp) +struct Ident { - Controller *cp = dp->cp; - - qlock(cp); - if(waserror()){ - qunlock(cp); - nexterror(); - } - - cmdreadywait(cp); - - cp->cmd = Cinitparam; - outb(cp->pbase+Psector, dp->sectors); - outb(cp->pbase+Pdh, 0x20 | (dp->heads-1) | (dp->drive<<4)); - outb(cp->pbase+Pcmd, Cinitparam); - - sleep(&cp->r, cmddone, cp); - - if(cp->status & Serr) - DPRINT("hd%d initparam err: status %lux, err %lux\n", - dp-hard, cp->status, cp->error); - - poperror(); - qunlock(cp); -} + ushort magic; /* drive type magic */ + ushort lcyls; /* logical number of cylinders */ + ushort rcyl; /* number of removable cylinders */ + ushort lheads; /* logical number of heads */ + ushort b2t; /* unformatted bytes/track */ + ushort b2s; /* unformated bytes/sector */ + ushort ls2t; /* logical sectors/track */ + ushort gap; /* bytes in inter-sector gaps */ + ushort sync; /* bytes in sync fields */ + ushort magic2; /* must be 0x0000 */ + ushort serial[10]; /* serial number */ + ushort type; /* controller type (0x0003) */ + ushort bsize; /* buffer size/512 */ + ushort ecc; /* ecc bytes returned by read long */ + ushort firm[4]; /* firmware revision */ + ushort model[20]; /* model number */ + ushort s2i; /* number of sectors/interrupt */ + ushort dwtf; /* double word transfer flag */ + ushort alernate; + ushort piomode; + ushort dmamode; + ushort reserved[76]; + ushort ncyls; /* native number of cylinders */ + ushort nheads; /* native number of heads, sectors */ + ushort dlcyls; /* default logical number of cyinders */ + ushort dlheads; /* default logical number of heads, sectors */ + ushort interface; + ushort power; /* 0xFFFF if power commands supported */ + ushort flags; + ushort ageprog; /* MSB = age, LSB = program */ + ushort reserved2[120]; +}; /* * get parameters from the drive @@ -667,6 +593,7 @@ hardident(Drive *dp) { Controller *cp; char *buf; + Ident *ip; cp = dp->cp; buf = smalloc(Maxxfer); @@ -690,7 +617,8 @@ hardident(Drive *dp) DPRINT("bad disk ident status\n"); error(Eio); } - memmove(&dp->id, buf, dp->bytes); + ip = (Ident*)buf; + /* * this function appears to respond with an extra interrupt after * the ident information is read, except on the safari. The following @@ -700,6 +628,11 @@ hardident(Drive *dp) */ if (cp->cmd == Cident2) tsleep(&cp->r, return0, 0, 10); + + dp->cyl = ip->lcyls; + dp->heads = ip->lheads; + dp->sectors = ip->ls2t; + dp->cap = dp->bytes * dp->cyl * dp->heads * dp->sectors; cp->cmd = 0; cp->buf = 0; free(buf); @@ -707,6 +640,96 @@ hardident(Drive *dp) qunlock(cp); } +/* + * probe the given sector to see if it exists + */ +static int +hardprobe(Drive *dp, int cyl, int sec, int head) +{ + Controller *cp; + char *buf; + int rv; + + cp = dp->cp; + buf = smalloc(Maxxfer); + qlock(cp); + if(waserror()){ + qunlock(cp); + nexterror(); + } + + cmdreadywait(cp); + + cp->cmd = Cread; + cp->dp = dp; + cp->status = 0; + cp->nsecs = 1; + + outb(cp->pbase+Pcount, 1); + outb(cp->pbase+Psector, sec+1); + outb(cp->pbase+Pdh, 0x20 | head); + outb(cp->pbase+Pcyllsb, cyl); + outb(cp->pbase+Pcylmsb, cyl>>8); + outb(cp->pbase+Pcmd, Cread); + + sleep(&cp->r, cmddone, cp); + + if(cp->status & Serr) + rv = -1; + else + rv = 0; + + cp->buf = 0; + free(buf); + poperror(); + qunlock(cp); + return rv; +} + +/* + * figure out the drive parameters + */ +static void +hardparams(Drive *dp) +{ + int i, hi, lo; + + /* + * first try the easy way, ask the drive and make sure it + * isn't lying. + */ + dp->bytes = 512; + hardident(dp); + if(hardprobe(dp, dp->cyl-1, dp->sectors-1, dp->heads-1) == 0) + return; + + /* + * the drive lied, determine parameters by seeing which ones + * work to read sectors. + */ + for(i = 0; i < 32; i++) + if(hardprobe(dp, 0, 0, i) < 0) + break; + dp->heads = i; + for(i = 0; i < 128; i++) + if(hardprobe(dp, 0, i, 0) < 0) + break; + dp->sectors = i; + for(i = 512; ; i += 512) + if(hardprobe(dp, i, dp->sectors-1, dp->heads-1) < 0) + break; + lo = i - 512; + hi = i; + for(; hi-lo > 1;){ + i = lo + (hi - lo)/2; + if(hardprobe(dp, i, dp->sectors-1, dp->heads-1) < 0) + hi = i; + else + lo = i; + } + dp->cyl = lo + 1; + dp->cap = dp->bytes * dp->cyl * dp->heads * dp->sectors; +} /* * Read block replacement table. diff --git a/pc/main.c b/pc/main.c index af1cd8955a433a1dea3fd6ba2c8b5890d25e0e9e..0f273617e00fc0b3d6d35dd583204772cbb67721 100644 --- a/pc/main.c +++ b/pc/main.c @@ -7,9 +7,12 @@ #include "ureg.h" #include "init.h" +/* configuration parameters */ int mousetype; int pmutype; -uchar *sp; /* stack pointer for /boot */ +int resettype; + +uchar *sp; /* stack pointer for /boot */ void main(void) @@ -41,24 +44,24 @@ main(void) } /* - * this should be changed to describe architecture dependencies outside the - * PC model + * This tries to capture architecture dependencies since things + * like power management/reseting/mouse are outside the hardware + * model. */ void ident(void) { char *id = (char*)(ROMBIOS + 0xFF40); - /* check for a safari (tres special) */ if(strncmp(id, "AT&TNSX", 7) == 0){ mousetype = MousePS2; pmutype = PMUnsx20; + resettype = Resetheadland; }else if(strncmp(id, "NCRD.0", 6) == 0){ mousetype = MousePS2; - pmutype = PMUother; + resettype = Reset8042; }else{ mousetype = Mouseserial; - pmutype = PMUother; } } @@ -184,12 +187,22 @@ bootargs(ulong base) int i, ac; uchar *av[32]; uchar **lsp; + char *cp = BOOTLINE; + char buf[64]; sp = (uchar*)base + BY2PG - MAXSYSARG*BY2WD; ac = 0; av[ac++] = pusharg("/386/9safari"); av[ac++] = pusharg("-p"); + cp[64] = 0; + if(strncmp(cp, "fd!", 3) == 0){ + sprint(buf, "local!#f/fd%ddisk", atoi(cp+3)); + av[ac++] = pusharg(buf); + } else if(strncmp(cp, "hd!", 3) == 0){ + sprint(buf, "local!#w/hd%ddisk", atoi(cp+3)); + av[ac++] = pusharg(buf); + } /* 4 byte word align stack */ sp = (uchar*)((ulong)sp & ~3); @@ -413,9 +426,16 @@ exit(int ispanic) print("exiting\n"); if(ispanic) for(;;); - i8042reset(); /* via keyboard controller */ - print("can't reset via software, do something drastic!\n"); - for(;;); + + switch(resettype){ + case Resetheadland: + headreset(); + case Reset8042: + i8042reset(); /* via keyboard controller */ + default: + print("Reset the machine!\n"); + for(;;); + } } /* diff --git a/port/devbit.c b/port/devbit.c index e7df0c981d91bb4cfcd0dd22fc3b9d60b177a923..071a24caae8ffd665407c1dcb6b2440416bf8dff 100644 --- a/port/devbit.c +++ b/port/devbit.c @@ -1661,11 +1661,18 @@ bitstring(GBitmap *bp, Point pt, GFont *f, uchar *p, long l, Fcode fc) Rectangle rect; ushort r; GCacheinfo *c; + int x; + Fcode clr; - full = (fc==S || fc==notS); /* for reverse-video */ + clr = 0; + full = (fc&~S)^(D&~S); /* result involves source */ if(full){ rect.min.y = 0; rect.max.y = f->height; + /* set clr to result under fc if source pixel is zero */ + /* hard to do without knowing layout of bits, so we cheat */ + clr = (fc&3); /* fc&3 is result if source is zero */ + clr |= clr<<2; /* fc&(3<<2) is result if source is one */ } while(l > 0){ @@ -1678,10 +1685,17 @@ bitstring(GBitmap *bp, Point pt, GFont *f, uchar *p, long l, Fcode fc) if(!full){ rect.min.y = c->top; rect.max.y = c->bottom; - }else if(c->left > 0) - gbitblt(bp, pt, f->b, - Rect(pt.x, pt.y, pt.x+c->left, pt.y+f->height), - fc==S? 0 : F); + }else{ + if(c->left > 0) + gbitblt(bp, pt, bp, + Rect(pt.x, pt.y, pt.x+c->left, pt.y+f->height), + clr); + x = c->left+(c->xright-c->x); + if(x < c->width) + gbitblt(bp, Pt(pt.x+x, pt.y), bp, + Rect(pt.x+x, pt.y, pt.x+c->width, pt.y+f->height), + clr); + } rect.min.x = c->x; rect.max.x = c->xright; gbitblt(bp, Pt(pt.x+c->left, pt.y+rect.min.y), f->b, rect, fc); diff --git a/port/devip.c b/port/devip.c index 03ff50a24f9c09214e7e8a34bbf3464352b0ef2e..54ab148b8d51b83a9f096897cc97a384eebe5389 100644 --- a/port/devip.c +++ b/port/devip.c @@ -23,9 +23,10 @@ Ipifc *ipifc[Nrprotocol+1]; QLock ipalloc; /* Protocol port allocation lock */ Ipconv **tcpbase; -Streamput udpstiput, udpstoput, tcpstiput, tcpstoput, iliput, iloput, bsdiput, bsdoput; -Streamopen udpstopen, tcpstopen, ilopen, bsdopen; -Streamclose udpstclose, tcpstclose, ilclose, bsdclose; +Streamput udpstiput, udpstoput, tcpstiput, tcpstoput; +Streamput iliput, iloput, bsdiput, bsdoput; +Streamopen udpstopen, tcpstopen, ilopen, bsdopen; +Streamclose udpstclose, tcpstclose, ilclose, bsdclose; Qinfo tcpinfo = { tcpstiput, tcpstoput, tcpstopen, tcpstclose, "tcp", 0, 1 }; Qinfo udpinfo = { udpstiput, udpstoput, udpstopen, udpstclose, "udp" }; @@ -76,8 +77,8 @@ ipinit(void) Chan * ipattach(char *spec) { - Chan *c; int i; + Chan *c; /* fail if ip is not yet configured */ if(Ipoutput == 0) @@ -169,8 +170,8 @@ ipcreateconv(Ipifc *ifc, int id) Ipconv* ipincoming(Ipifc *ifc, Ipconv *from) { - Ipconv **p, **etab; Ipconv *new; + Ipconv **p, **etab; /* look for an unused existing conversation */ etab = &ifc->conv[Nipconv]; @@ -554,10 +555,11 @@ udpstoput(Queue *q, Block *bp) hnputs(uh->udpplen, ptcllen); hnputl(uh->udpsrc, Myip[Myself]); hnputs(uh->udpsport, cp->psrc); - if(cp->headers){ + if(cp->headers) { hnputl(uh->udpdst, addr); hnputs(uh->udpdport, port); - } else { + } + else { hnputl(uh->udpdst, cp->dst); hnputs(uh->udpdport, cp->pdst); } @@ -627,14 +629,17 @@ tcpstoput(Queue *q, Block *bp) switch(tcb->state) { case Listen: tcb->flags |= ACTIVE; - send_syn(tcb); - setstate(s, Syn_sent); + tcpsndsyn(tcb); + tcpsetstate(s, Syn_sent); /* No break */ case Syn_sent: case Syn_received: case Established: case Close_wait: + /* + * Push data + */ qlock(tcb); if(waserror()) { qunlock(tcb); @@ -649,7 +654,7 @@ tcpstoput(Queue *q, Block *bp) f->next = bp; } tcprcvwin(s); - tcp_output(s); + tcpoutput(s); poperror(); qunlock(tcb); break; @@ -686,7 +691,7 @@ tcpstopen(Queue *q, Stream *s) if(tcpbase == 0) tcpbase = ipifc[s->dev]->conv; ifc = ipifc[s->dev]; - initipifc(ifc, IP_TCPPROTO, tcp_input, 1500, 512, ETHER_HDR); + initipifc(ifc, IP_TCPPROTO, tcpinput, 1500, 512, ETHER_HDR); ipc = ipcreateconv(ifc, s->id); ipc->readq = RD(q); @@ -730,8 +735,8 @@ iplocalfill(Chan *c, char *buf, int len) void ipstatusfill(Chan *c, char *buf, int len) { - int connection; Ipconv *cp; + int connection; if(len < 64) error(Ebadarg); @@ -759,9 +764,9 @@ iphavecon(Ipconv *s) int iplisten(Chan *c) { - Ipconv **p, **etab, *new; Ipconv *s; int connection; + Ipconv **p, **etab, *new; connection = STREAMID(c->qid.path); s = ipcreateconv(ipifc[c->dev], connection); @@ -850,20 +855,20 @@ tcpstclose(Queue *q) case Established: tcb->sndcnt++; tcb->snd.nxt++; - setstate(s, Finwait1); + tcpsetstate(s, Finwait1); goto output; case Close_wait: tcb->sndcnt++; tcb->snd.nxt++; - setstate(s, Last_ack); + tcpsetstate(s, Last_ack); output: qlock(tcb); if(waserror()) { qunlock(tcb); nexterror(); } - tcp_output(s); + tcpoutput(s); poperror(); qunlock(tcb); break; diff --git a/port/ipdat.h b/port/ipdat.h index 1cb73d55238221d6b66d530f405d5c6b6535dea0..f980ff07d7d823a1f6724aeae1e9cdc4445df832 100644 --- a/port/ipdat.h +++ b/port/ipdat.h @@ -472,7 +472,7 @@ void proc_syn(Ipconv*, char, Tcp*); ushort ptcl_csum(Block*bp, int, int); int pullb(Block **, int); void reset(Ipaddr, Ipaddr, char, ushort, Tcp*); -void send_syn(Tcpctl*); +void tcpsndsyn(Tcpctl*); int seq_ge(int, int); int seq_gt(int, int); int seq_gt(int, int); @@ -480,14 +480,14 @@ int seq_le(int, int); int seq_lt(int, int); int seq_within(int, int, int); int seq_within(int, int, int); -void setstate(Ipconv *, char); -void start_timer(Timer *); -void state_upcall(Ipconv*, char oldstate, char newstate); -void stop_timer(Timer *); -void tcp_acktimer(void *); -void tcp_input(Ipifc*, Block *); -void tcp_output(Ipconv*); -void tcp_timeout(void *); +void tcpsetstate(Ipconv *, char); +void tcpgo(Timer *); +void tcphalt(Timer *); +void tcpxstate(Ipconv*, char oldstate, char newstate); +void tcpacktimer(void *); +void tcpinput(Ipifc*, Block *); +void tcpoutput(Ipconv*); +void tcptimeout(void *); void tcpackproc(void*); void tcpflow(void*); void tcpflushincoming(Ipconv*); diff --git a/port/tcpif.c b/port/tcpif.c index ca3856aee6d8b6ec6a5cc56f8e6d6fdd777e08b5..2fec1ed7a97803d24b95e3014d4b76980af4b647 100644 --- a/port/tcpif.c +++ b/port/tcpif.c @@ -11,24 +11,21 @@ extern int tcpdbg; #define DPRINT if(tcpdbg) print void -state_upcall(Ipconv *s, char oldstate, char newstate) +tcpxstate(Ipconv *s, char oldstate, char newstate) { - Block *bp; int len; + Block *bp; Tcpctl *tcb = &s->tcpctl; - DPRINT("state_upcall: %s -> %s err %s\n", - tcpstate[oldstate], tcpstate[newstate], s->err); - if(oldstate == newstate) return; switch(newstate) { case Closed: - s->psrc = 0; + s->psrc = 0; /* This connection is toast */ s->pdst = 0; s->dst = 0; - /* NO break */ + case Close_wait: /* Remote closes */ if(s->err) { len = strlen(s->err); @@ -46,7 +43,7 @@ state_upcall(Ipconv *s, char oldstate, char newstate) qunlock(s); nexterror(); } - if(s->readq == 0){ + if(s->readq == 0) { if(newstate == Close_wait) putb(&tcb->rcvq, bp); else @@ -84,7 +81,7 @@ tcpstart(Ipconv *s, int mode, ushort window, char tos) switch(mode){ case TCP_PASSIVE: tcb->flags |= CLONE; - setstate(s, Listen); + tcpsetstate(s, Listen); break; case TCP_ACTIVE: @@ -95,9 +92,9 @@ tcpstart(Ipconv *s, int mode, ushort window, char tos) qunlock(tcb); nexterror(); } - send_syn(tcb); - setstate(s, Syn_sent); - tcp_output(s); + tcpsndsyn(tcb); + tcpsetstate(s, Syn_sent); + tcpoutput(s); poperror(); qunlock(tcb); sleep(&tcb->syner, notsyner, tcb); diff --git a/port/tcpinput.c b/port/tcpinput.c index 49db6b3056f90286cb8a4dd42702033e1dae0cb0..c5f54247f5e10d22206f3bf2b5f302e3db03767c 100644 --- a/port/tcpinput.c +++ b/port/tcpinput.c @@ -19,15 +19,13 @@ char *tcpstate[] = }; void -sndrst(Ipaddr source, Ipaddr dest, char tos, ushort length, Tcp *seg) +sndrst(Ipaddr source, Ipaddr dest, ushort length, Tcp *seg) { Block *hbp; Port tmp; char rflags; Tcphdr ph; - USED(tos); /* is this right??? */ - if(seg->flags & RST) return; @@ -85,7 +83,7 @@ tcpflushincoming(Ipconv *s) seg.seq = tcb->snd.ptr; seg.ack = tcb->last_ack = tcb->rcv.nxt; - sndrst(s->dst, Myip[Myself], 0, 0, &seg); + sndrst(s->dst, Myip[Myself], 0, &seg); localclose(s, 0); } @@ -130,7 +128,7 @@ tcpincoming(Ipifc *ifc, Ipconv *s, Tcp *segp, Ipaddr source) } void -tcp_input(Ipifc *ifc, Block *bp) +tcpinput(Ipifc *ifc, Block *bp) { Ipconv *s, **p, **etab; Ipconv *spec, *gen; @@ -198,7 +196,7 @@ tcp_input(Ipifc *ifc, Block *bp) } if(s == 0){ freeb(bp); - sndrst(source, dest, tos, length, &seg); + sndrst(source, dest, length, &seg); return; } } @@ -212,7 +210,7 @@ tcp_input(Ipifc *ifc, Block *bp) switch(tcb->state) { case Closed: freeb(bp); - sndrst(source, dest, tos, length, &seg); + sndrst(source, dest, length, &seg); goto done; case Listen: if(seg.flags & RST) { @@ -221,13 +219,13 @@ tcp_input(Ipifc *ifc, Block *bp) } if(seg.flags & ACK) { freeb(bp); - sndrst(source, dest, tos, length, &seg); + sndrst(source, dest, length, &seg); goto done; } if(seg.flags & SYN) { proc_syn(s, tos, &seg); - send_syn(tcb); - setstate(s, Syn_received); + tcpsndsyn(tcb); + tcpsetstate(s, Syn_received); if(length != 0 || (seg.flags & FIN)) break; freeb(bp); @@ -239,7 +237,7 @@ tcp_input(Ipifc *ifc, Block *bp) if(seg.flags & ACK) { if(!seq_within(seg.ack, tcb->iss+1, tcb->snd.nxt)) { freeb(bp); - sndrst(source, dest, tos, length, &seg); + sndrst(source, dest, length, &seg); goto done; } } @@ -253,7 +251,7 @@ tcp_input(Ipifc *ifc, Block *bp) if(seg.flags & ACK) if(PREC(tos) != PREC(tcb->tos)){ freeb(bp); - sndrst(source, dest, tos, length, &seg); + sndrst(source, dest, length, &seg); goto done; } @@ -261,10 +259,10 @@ tcp_input(Ipifc *ifc, Block *bp) proc_syn(s, tos, &seg); if(seg.flags & ACK){ update(s, &seg); - setstate(s, Established); + tcpsetstate(s, Established); } else - setstate(s, Syn_received); + tcpsetstate(s, Syn_received); if(length != 0 || (seg.flags & FIN)) break; @@ -291,7 +289,7 @@ tcp_input(Ipifc *ifc, Block *bp) if(s->readq == 0) if(tcb->state == Closed) { freeb(bp); - sndrst(source, dest, tos, length, &seg); + sndrst(source, dest, length, &seg); goto done; } @@ -309,7 +307,7 @@ tcp_input(Ipifc *ifc, Block *bp) if(seg.flags & RST) { if(tcb->state == Syn_received && !(tcb->flags & (CLONE|ACTIVE))) - setstate(s, Listen); + tcpsetstate(s, Listen); else localclose(s, Econrefused); @@ -317,9 +315,10 @@ tcp_input(Ipifc *ifc, Block *bp) goto done; } + /* This tos stuff should be removed */ if(PREC(tos) != PREC(tcb->tos) || (seg.flags & SYN)){ freeb(bp); - sndrst(source, dest, tos, length, &seg); + sndrst(source, dest, length, &seg); goto done; } @@ -330,16 +329,13 @@ tcp_input(Ipifc *ifc, Block *bp) switch(tcb->state) { case Syn_received: - if(seq_within(seg.ack, tcb->snd.una+1, tcb->snd.nxt)){ - update(s, &seg); - setstate(s, Established); - } - else { + if(!seq_within(seg.ack, tcb->snd.una+1, tcb->snd.nxt)){ freeb(bp); - sndrst(source, dest, tos, length, &seg); + sndrst(source, dest, length, &seg); goto done; } - break; + update(s, &seg); + tcpsetstate(s, Established); case Established: case Close_wait: update(s, &seg); @@ -347,7 +343,7 @@ tcp_input(Ipifc *ifc, Block *bp) case Finwait1: update(s, &seg); if(tcb->sndcnt == 0) - setstate(s, Finwait2); + tcpsetstate(s, Finwait2); break; case Finwait2: update(s, &seg); @@ -355,9 +351,9 @@ tcp_input(Ipifc *ifc, Block *bp) case Closing: update(s, &seg); if(tcb->sndcnt == 0) { - setstate(s, Time_wait); + tcpsetstate(s, Time_wait); tcb->timer.start = MSL2 * (1000 / MSPTICK); - start_timer(&tcb->timer); + tcpgo(&tcb->timer); } break; case Last_ack: @@ -369,7 +365,7 @@ tcp_input(Ipifc *ifc, Block *bp) } case Time_wait: tcb->flags |= FORCE; - start_timer(&tcb->timer); + tcpgo(&tcb->timer); } if((seg.flags&URG) && seg.up) { @@ -409,7 +405,7 @@ tcp_input(Ipifc *ifc, Block *bp) tcprcvwin(s); - start_timer(&tcb->acktimer); + tcpgo(&tcb->acktimer); if(tcb->max_snd <= tcb->rcv.nxt-tcb->last_ack) tcb->flags |= FORCE; @@ -418,7 +414,7 @@ tcp_input(Ipifc *ifc, Block *bp) /* no process to read the data, send a reset */ if(bp) freeb(bp); - sndrst(source, dest, tos, length, &seg); + sndrst(source, dest, length, &seg); goto done; } } @@ -430,35 +426,35 @@ tcp_input(Ipifc *ifc, Block *bp) case Syn_received: case Established: tcb->rcv.nxt++; - setstate(s, Close_wait); + tcpsetstate(s, Close_wait); break; case Finwait1: tcb->rcv.nxt++; if(tcb->sndcnt == 0) { - setstate(s, Time_wait); + tcpsetstate(s, Time_wait); tcb->timer.start = MSL2 * (1000/MSPTICK); - start_timer(&tcb->timer); + tcpgo(&tcb->timer); } else - setstate(s, Closing); + tcpsetstate(s, Closing); break; case Finwait2: tcb->rcv.nxt++; - setstate(s, Time_wait); + tcpsetstate(s, Time_wait); tcb->timer.start = MSL2 * (1000/MSPTICK); - start_timer(&tcb->timer); + tcpgo(&tcb->timer); break; case Close_wait: case Closing: case Last_ack: break; case Time_wait: - start_timer(&tcb->timer); + tcpgo(&tcb->timer); break; } } - while(tcb->reseq != 0) { + while(tcb->reseq) { if(seq_ge(tcb->rcv.nxt, tcb->reseq->seg.seq) == 0) break; @@ -470,7 +466,7 @@ tcp_input(Ipifc *ifc, Block *bp) break; } output: - tcp_output(s); + tcpoutput(s); done: qunlock(tcb); } @@ -521,7 +517,7 @@ update(Ipconv *s, Tcp *seg) /* Adjust the timers acorrding to the round trip time */ if(run_timer(&tcb->rtt_timer)) if(seq_ge(seg->ack, tcb->rttseq)) { - stop_timer(&tcb->rtt_timer); + tcphalt(&tcb->rtt_timer); if((tcb->flags&RETRAN) == 0) { tcb->backoff = 0; rtt = tcb->rtt_timer.start - tcb->rtt_timer.count; @@ -550,9 +546,9 @@ update(Ipconv *s, Tcp *seg) if(seq_gt(seg->ack, tcb->snd.up)) tcb->snd.up = seg->ack; - stop_timer(&tcb->timer); + tcphalt(&tcb->timer); if(tcb->snd.una != tcb->snd.nxt) - start_timer(&tcb->timer); + tcpgo(&tcb->timer); if(seq_lt(tcb->snd.ptr, tcb->snd.una)) tcb->snd.ptr = tcb->snd.una; @@ -595,7 +591,7 @@ proc_syn(Ipconv *s, char tos, Tcp *seg) /* Generate an initial sequence number and put a SYN on the send queue */ void -send_syn(Tcpctl *tcb) +tcpsndsyn(Tcpctl *tcb) { static int start; @@ -630,16 +626,16 @@ add_reseq(Tcpctl *tcb, char tos, Tcp *seg, Block *bp, ushort length) if(rp1 == 0 || seq_lt(seg->seq, rp1->seg.seq)) { rp->next = rp1; tcb->reseq = rp; - } - else { - for(;;){ - if(rp1->next == 0 || seq_lt(seg->seq, rp1->next->seg.seq)) { - rp->next = rp1->next; - rp1->next = rp; - break; - } - rp1 = rp1->next; + return; + } + + for(;;) { + if(rp1->next == 0 || seq_lt(seg->seq, rp1->next->seg.seq)) { + rp->next = rp1->next; + rp1->next = rp; + break; } + rp1 = rp1->next; } } @@ -648,7 +644,8 @@ get_reseq(Tcpctl *tcb, char *tos, Tcp *seg, Block **bp, ushort *length) { Reseq *rp; - if((rp = tcb->reseq) == 0) + rp = tcb->reseq; + if(rp == 0) return; tcb->reseq = rp->next; @@ -818,16 +815,13 @@ init_tcpctl(Ipconv *s) tcb->ssthresh = 65535; tcb->srtt = tcp_irtt; - /* Initialize timer intervals */ tcb->timer.start = tcb->srtt / MSPTICK; - tcb->timer.func = (void(*)(void*))tcp_timeout; - tcb->timer.arg = (void *)s; + tcb->timer.func = tcptimeout; + tcb->timer.arg = s; tcb->rtt_timer.start = MAX_TIME; - - /* Initialise ack timer */ tcb->acktimer.start = TCP_ACK / MSPTICK; - tcb->acktimer.func = (void(*)(void*))tcp_acktimer; - tcb->acktimer.arg = (void *)s; + tcb->acktimer.func = tcpacktimer; + tcb->acktimer.arg = s; } /* @@ -840,8 +834,8 @@ localclose(Ipconv *s, char reason[]) Tcpctl *tcb = &s->tcpctl; Block *bp; - stop_timer(&tcb->timer); - stop_timer(&tcb->rtt_timer); + tcphalt(&tcb->timer); + tcphalt(&tcb->rtt_timer); s->err = reason; /* flush receive queue */ @@ -857,7 +851,7 @@ localclose(Ipconv *s, char reason[]) tcb->reseq = 0; s->err = reason; - setstate(s, Closed); + tcpsetstate(s, Closed); } int @@ -899,14 +893,14 @@ seq_ge(int x, int y) } void -setstate(Ipconv *s, char newstate) +tcpsetstate(Ipconv *s, char newstate) { char oldstate; Tcpctl *tcb = &s->tcpctl; oldstate = tcb->state; tcb->state = newstate; - state_upcall(s, oldstate, newstate); + tcpxstate(s, oldstate, newstate); } Block * @@ -1004,7 +998,8 @@ ntohtcp(Tcp *tcph, Block **bpp) if(!*bpp) return -1; - for(optr = h->tcpopt, i = TCP_HDRSIZE; i < hdrlen;) { + optr = h->tcpopt; + for(i = TCP_HDRSIZE; i < hdrlen;) { switch(*optr++){ case EOL_KIND: return hdrlen; diff --git a/port/tcpoutput.c b/port/tcpoutput.c index 04e03dd53f820383fe4f7d9a57fa6a8a6108e81b..496315045df4ae4943442f18a612709fdd37e03f 100644 --- a/port/tcpoutput.c +++ b/port/tcpoutput.c @@ -7,13 +7,14 @@ #include "arp.h" #include "ipdat.h" -extern int tcpdbg; #define DPRINT if(tcpdbg) print -extern ushort tcp_mss; -int tcptimertype = 0; + +extern int tcpdbg; +extern ushort tcp_mss; + int tcptimertype; void -tcp_output(Ipconv *s) +tcpoutput(Ipconv *s) { Block *hbp,*dbp, *sndq; ushort ssize, dsize, usable, sent; @@ -30,7 +31,7 @@ tcp_output(Ipconv *s) return; } - for(;;){ + for(;;) { qlen = tcb->sndcnt; sent = tcb->snd.ptr - tcb->snd.una; sndq = tcb->sndq; @@ -40,16 +41,15 @@ tcp_output(Ipconv *s) if((tcb->flags & SYNACK) == 0) break; + /* Compute usable segment based on offered window and limit + * window probes to one + */ if(tcb->snd.wnd == 0){ - /* Allow only one closed-window probe at a time */ if(sent != 0) break; - /* Force a closed-window probe */ usable = 1; - } else { - /* usable window = offered window - unacked bytes in transit - * limited by the congestion window - */ + } + else { usable = MIN(tcb->snd.wnd,tcb->cwind) - sent; if(sent != 0) if(qlen - sent < tcb->mss) @@ -61,20 +61,18 @@ tcp_output(Ipconv *s) dsize = ssize; seg.up = 0; - DPRINT("tcp_out: ssize = %lux\n", ssize); if(ssize == 0) if((tcb->flags&FORCE) == 0) break; - /* Stop ack timer if one will be piggy backed on data */ - stop_timer(&tcb->acktimer); + tcphalt(&tcb->acktimer); tcb->flags &= ~FORCE; tcprcvwin(s); + /* By default we will generate an ack */ seg.source = s->psrc; seg.dest = s->pdst; - /* Every state except SYN_SENT */ seg.flags = ACK; seg.mss = 0; @@ -137,11 +135,11 @@ tcp_output(Ipconv *s) tcb->timer.start = backoff(tcb->backoff) * (2 * tcb->mdev + tcb->srtt + MSPTICK) / MSPTICK; if(!run_timer(&tcb->timer)) - start_timer(&tcb->timer); + tcpgo(&tcb->timer); /* If round trip timer isn't running, start it */ if(!run_timer(&tcb->rtt_timer)){ - start_timer(&tcb->rtt_timer); + tcpgo(&tcb->rtt_timer); tcb->rttseq = tcb->snd.ptr; } } @@ -165,12 +163,12 @@ tcprxmit(Ipconv *s) /* Shrink congestion window to 1 packet */ tcb->cwind = tcb->mss; - tcp_output(s); + tcpoutput(s); qunlock(tcb); } void -tcp_timeout(void *arg) +tcptimeout(void *arg) { Tcpctl *tcb; Ipconv *s; @@ -181,10 +179,11 @@ tcp_timeout(void *arg) switch(tcb->state){ default: tcb->backoff++; - if (tcb->backoff >= MAXBACKOFF) + if (tcb->backoff >= MAXBACKOFF) { localclose(s, Etimedout); - else - tcprxmit(s); + break; + } + tcprxmit(s); break; case Time_wait: @@ -207,14 +206,14 @@ backoff(int n) } void -tcp_acktimer(Ipconv *s) +tcpacktimer(Ipconv *s) { Tcpctl *tcb = &s->tcpctl; qlock(tcb); tcb->flags |= FORCE; tcprcvwin(s); - tcp_output(s); + tcpoutput(s); qunlock(tcb); } diff --git a/port/tcptimer.c b/port/tcptimer.c index 93da25b3c6a1548a093d137df93a111039099b13..3ad35033e46f2c345a44ddf5cf9cb3ee886adb68 100644 --- a/port/tcptimer.c +++ b/port/tcptimer.c @@ -7,12 +7,53 @@ #include "arp.h" #include "ipdat.h" -/* Head of running timer chain */ -Timer *timers; -QLock timerlock; -Rendez Tcpack; +static Timer *timers; /* List of active timers */ +static QLock tl; /* Protect timer list */ +static Rendez Tcpack; Rendez tcpflowr; +static void +deltimer(Timer *t) +{ + if(timers == t) + timers = t->next; + + if(t->next) + t->next->prev = t->prev; + + if(t->prev) + t->prev->next = t->next; +} + +/* + * Poke each tcp connection to recompute window size and + * acknowledgement timer + */ + +void +tcpflow(void *x) +{ + Ipifc *ifc; + Ipconv *cp, **p, **etab; + + ifc = x; + etab = &ifc->conv[Nipconv]; + + for(;;) { + sleep(&tcpflowr, return0, 0); + + for(p = ifc->conv; p < etab; p++) { + cp = *p; + if(cp == 0) + break; + if(cp->readq && cp->ref != 0 && !QFULL(cp->readq->next)) { + tcprcvwin(cp); + tcpacktimer(cp); + } + } + } +} + void tcpackproc(void *junk) { @@ -23,30 +64,18 @@ tcpackproc(void *junk) for(;;) { expired = 0; - qlock(&timerlock); + qlock(&tl); for(t = timers;t != 0; t = tp) { tp = t->next; - if(tp == t) - panic("Timer loop at %lux\n",(long)tp); - if(t->state == TIMER_RUN) if(--(t->count) == 0){ - - /* Delete from active timer list */ - if(timers == t) - timers = t->next; - if(t->next != 0) - t->next->prev = t->prev; - if(t->prev != 0) - t->prev->next = t->next; - + deltimer(t); t->state = TIMER_EXPIRE; - /* Put on head of expired timer list */ t->next = expired; expired = t; } } - qunlock(&timerlock); + qunlock(&tl); for(;;) { t = expired; @@ -58,76 +87,38 @@ tcpackproc(void *junk) if(t->func) (*t->func)(t->arg); } - tsleep(&Tcpack, return0, 0, MSPTICK); } } void -start_timer(Timer *t) +tcpgo(Timer *t) { - if(t == 0 || t->start == 0) return; - qlock(&timerlock); - + qlock(&tl); t->count = t->start; - if(t->state != TIMER_RUN){ + if(t->state != TIMER_RUN) { t->state = TIMER_RUN; - /* Put on head of active timer list */ t->prev = 0; t->next = timers; - if(t->next != 0) + if(t->next) t->next->prev = t; timers = t; } - qunlock(&timerlock); + qunlock(&tl); } void -stop_timer(Timer *t) +tcphalt(Timer *t) { if(t == 0) return; - qlock(&timerlock); - - if(t->state == TIMER_RUN){ - /* Delete from active timer list */ - if(timers == t) - timers = t->next; - if(t->next != 0) - t->next->prev = t->prev; - if(t->prev != 0) - t->prev->next = t->next; - } + qlock(&tl); + if(t->state == TIMER_RUN) + deltimer(t); t->state = TIMER_STOP; - - qunlock(&timerlock); -} - -void -tcpflow(void *x) -{ - Ipifc *ifc; - Ipconv *cp, **p, **etab; - - ifc = x; - etab = &ifc->conv[Nipconv]; - - for(;;) { - sleep(&tcpflowr, return0, 0); - - for(p = ifc->conv; p < etab; p++) { - cp = *p; - if(cp == 0) - break; - if(cp->readq && cp->ref != 0 && !QFULL(cp->readq->next)) { - tcprcvwin(cp); - tcp_acktimer(cp); - } - } - } + qunlock(&tl); } -