From 3b4bfba9c73b08a8490c4749c254445fdadc6b1c Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Fri, 17 Mar 2000 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 2000-03-17 --- ip/rudp.c | 101 +++++++++++++++++++++++++++++++++++++++--------- pc/ether82557.c | 39 ++++++++++++++++++- 2 files changed, 120 insertions(+), 20 deletions(-) diff --git a/ip/rudp.c b/ip/rudp.c index 3a6e6400539de751791ccff8aaa9355874d7b09e..8feeb41ab4a5d2aa1af9f127c2b399894e3c1bff 100644 --- a/ip/rudp.c +++ b/ip/rudp.c @@ -37,8 +37,11 @@ enum Rudptickms = 50, Rudpmaxxmit = 10, Maxunacked = 100, + }; +#define Hangupgen 0xffffffff /* used only in hangup messages */ + typedef struct Udphdr Udphdr; struct Udphdr { @@ -100,6 +103,8 @@ struct Rudphdr typedef struct Reliable Reliable; struct Reliable { + Ref; + Reliable *next; uchar addr[IPaddrlen]; /* always V6 when put here */ @@ -121,7 +126,6 @@ struct Reliable ulong ackrcvd; /* last msg for which ack was rcvd */ /* flow control */ - QLock lock; Rendez vous; int blocked; }; @@ -176,9 +180,11 @@ struct Rudpcb /* * local functions */ -void relsendack(Conv *, Reliable *); +void relsendack(Conv *, Reliable *, int); int reliput(Conv *, Block *, uchar *, ushort); Reliable *relstate(Rudpcb *, uchar *, ushort, char *from); +void relput(Reliable *); +void relforget(Conv *, uchar *, int, int); void relackproc(void *); void relackq(Reliable *, Block *); void relhangup(Conv *, Reliable *); @@ -263,7 +269,7 @@ rudpclose(Conv *c) qlock(ucb); for(r = ucb->r; r; r = r->next){ if(r->acksent != r->rcvseq) - relsendack(c, r); + relsendack(c, r, 0); } qunlock(ucb); @@ -280,7 +286,7 @@ rudpclose(Conv *c) qlock(ucb); for(r = ucb->r; r; r = nr){ if(r->acksent != r->rcvseq) - relsendack(c, r); + relsendack(c, r, 0); nr = r->next; relhangup(c, r); free(r); @@ -429,7 +435,6 @@ rudpkick(Conv *c, int) hnputs(uh->udpcksum, ptclcsum(bp, UDP_IPHDR, dlen+UDP_RHDRSIZE)); relackq(r, bp); - qunlock(ucb); upriv->ustats.rudpOutDatagrams++; @@ -439,13 +444,13 @@ rudpkick(Conv *c, int) doipoput(c, f, bp, 0, c->ttl, c->tos); /* flow control of sorts */ - qlock(&r->lock); if(UNACKED(r) > Maxunacked){ r->blocked = 1; sleep(&r->vous, flow, r); r->blocked = 0; } - qunlock(&r->lock); + relput(r); + qunlock(ucb); } void @@ -615,6 +620,7 @@ char* rudpctl(Conv *c, char **f, int n) { Rudpcb *ucb; + uchar ip[IPaddrlen]; int x; ucb = (Rudpcb*)c->ptcl; @@ -627,6 +633,15 @@ rudpctl(Conv *c, char **f, int n) } else if(strcmp(f[0], "headers") == 0){ ucb->headers = 6; return nil; + } else if(strcmp(f[0], "hangup") == 0){ + if(n < 3) + return "bad syntax"; + parseip(ip, f[1]); + x = atoi(f[2]); + qlock(ucb); + relforget(c, ip, x, 1); + qunlock(ucb); + return nil; } else if(strcmp(f[0], "randdrop") == 0){ x = 10; /* default is 10% */ if(n > 1) @@ -764,7 +779,7 @@ loop: relrexmit(c, r); } if(r->acksent != r->rcvseq) - relsendack(c, r); + relsendack(c, r, 0); } qunlock(ucb); } @@ -798,6 +813,8 @@ relstate(Rudpcb *ucb, uchar *addr, ushort port, char *from) memmove(r->addr, addr, IPaddrlen); r->port = port; r->unacked = 0; + if(generation == Hangupgen) + generation++; r->sndgen = generation++; r->sndseq = 0; r->ackrcvd = 0; @@ -806,11 +823,41 @@ relstate(Rudpcb *ucb, uchar *addr, ushort port, char *from) r->acksent = 0; r->xmits = 0; r->timeout = 0; + r->ref = 0; + incref(r); /* one reference for being in the list */ } - + incref(r); return r; } +void +relput(Reliable *r) +{ + if(decref(r) == 0) + free(r); +} + +void +relforget(Conv *c, uchar *ip, int port, int originator) +{ + Rudpcb *ucb; + Reliable *r, **l; + + ucb = (Rudpcb*)c->ptcl; + + l = &ucb->r; + for(r = *l; r; r = *l){ + if(ipcmp(ip, r->addr) == 0 && port == r->port){ + *l = r->next; + if(originator) + relsendack(c, r, 1); + relhangup(c, r); + relput(r); /* remove from the list */ + break; + } + l = &r->next; + } +} /* * process a rcvd reliable packet. return -1 if not to be passed to user process, @@ -826,6 +873,7 @@ reliput(Conv *c, Block *bp, uchar *addr, ushort port) Reliable *r; Rudphdr *rh; ulong seq, ack, sgen, agen, ackreal; + int rv = -1; /* get fields */ uh = (Udphdr*)(bp->rp); @@ -837,20 +885,27 @@ reliput(Conv *c, Block *bp, uchar *addr, ushort port) upriv = c->p->priv; ucb = (Rudpcb*)c->ptcl; + qlock(ucb); r = relstate(ucb, addr, port, "input"); - DPRINT("rcvd %lud/%lud, %lud/%lud, r->sndgen = %lud\n", seq, sgen, ack, agen, r->sndgen); /* if acking an incorrect generation, ignore */ if(ack && agen != r->sndgen) - return -1; + goto out; + + /* Look for a hangup */ + if(sgen == Hangupgen) { + if(agen == r->sndgen) + relforget(c, addr, port, 0); + goto out; + } /* make sure we're not talking to a new remote side */ if(r->rcvgen != sgen){ if(seq != 0 && seq != 1) - return -1; + goto out; /* new connection */ if(r->rcvgen != 0){ @@ -893,22 +948,26 @@ reliput(Conv *c, Block *bp, uchar *addr, ushort port) /* no message or input queue full */ if(seq == 0 || qfull(c->rq)) - return -1; + goto out; /* refuse out of order delivery */ if(seq != NEXTSEQ(r->rcvseq)){ - relsendack(c, r); /* tell him we got it already */ + relsendack(c, r, 0); /* tell him we got it already */ upriv->orders++; DPRINT("out of sequence %lud not %lud\n", seq, NEXTSEQ(r->rcvseq)); - return -1; + goto out; } r->rcvseq = seq; - return 0; + rv = 0; +out: + relput(r); + qunlock(ucb); + return rv; } void -relsendack(Conv *c, Reliable *r) +relsendack(Conv *c, Reliable *r, int hangup) { Udphdr *uh; Block *bp; @@ -939,7 +998,10 @@ relsendack(Conv *c, Reliable *r) v6tov4(uh->udpsrc, c->laddr); hnputs(uh->udplen, ptcllen); - hnputl(rh->relsgen, r->sndgen); + if(hangup) + hnputl(rh->relsgen, Hangupgen); + else + hnputl(rh->relsgen, r->sndgen); hnputl(rh->relseq, 0); hnputl(rh->relagen, r->rcvgen); hnputl(rh->relack, r->rcvseq); @@ -955,6 +1017,7 @@ relsendack(Conv *c, Reliable *r) doipoput(c, f, bp, 0, c->ttl, c->tos); } + /* * called with ucb locked (and c locked if user initiated close) */ @@ -980,6 +1043,8 @@ relhangup(Conv *c, Reliable *r) r->rcvgen = 0; r->rcvseq = 0; r->acksent = 0; + if(generation == Hangupgen) + generation++; r->sndgen = generation++; r->sndseq = 0; r->ackrcvd = 0; diff --git a/pc/ether82557.c b/pc/ether82557.c index 3c1605096cc1413e3d7a6576b73822e319fcdee7..05db27d85dff2d2500291b5b8eaedaf6356756d9 100644 --- a/pc/ether82557.c +++ b/pc/ether82557.c @@ -928,6 +928,33 @@ static char* mediatable[9] = { "100BASE-FXFD", }; +static int +scanphy(Ctlr* ctlr) +{ + int i, oui, x; + + for(i = 0; i < 32; i++){ + if((oui = miir(ctlr, i, 2)) == -1 || oui == 0 || oui == 0xFFFF) + continue; + oui <<= 6; + x = miir(ctlr, i, 3); + oui |= x>>10; + //print("phy%d: oui %uX reg1 %uX\n", i, oui, miir(ctlr, i, 1)); + + ctlr->eeprom[6] = i; + if(oui == 0xAA00) + ctlr->eeprom[6] |= 0x07<<8; + else if(oui == 0x80017){ + if(x & 0x01) + ctlr->eeprom[6] |= 0x0A<<8; + else + ctlr->eeprom[6] |= 0x04<<8; + } + return i; + } + return -1; +} + static int reset(Ether* ether) { @@ -1009,11 +1036,19 @@ reset(Ether* ether) * Eeprom[6] indicates whether there is a PHY and whether * it's not 10Mb-only, in which case use the given PHY address * to set any PHY specific options and determine the speed. + * Unfortunately, sometimes the EEPROM is blank except for + * the ether address and checksum; in this case look at the + * controller type and if 0 scan for the first PHY and try to + * use that. * If no PHY, assume 82503 (serial) operation. */ - if((ctlr->eeprom[6] & 0x1F00) && !(ctlr->eeprom[6] & 0x8000)){ + if((ctlr->eeprom[6] & 0x1F00) && !(ctlr->eeprom[6] & 0x8000)) phyaddr = ctlr->eeprom[6] & 0x00FF; - + else if(!(ctlr->eeprom[5] & 0xFF00)) + phyaddr = scanphy(ctlr); + else + phyaddr = -1; + if(phyaddr >= 0){ /* * Resolve the highest common ability of the two * link partners. In descending order: