@@ 2,7 2,11 @@
* Western Digital ethernet adapter
* BUGS:
* no more than one controller
+ * TODO:
* fix for different controller types
+ * output
+ * deal with stalling and restarting output on input overflow
+ * fix magic ring constants
*/
#include "u.h"
#include "../port/lib.h"
@@ 131,26 135,24 @@ static Ctlr ctlr[Nctlr];
static void
etheroput(Queue *q, Block *bp)
{
- Ctlr *c;
+ Ctlr *cp;
int len, n;
- Pktype *t;
+ Pktype *pp;
Etherpkt *p;
Block *nbp;
-panic("etheroput\n");
-#ifdef notdef
- c = ((Pktype *)q->ptr)->ctlr;
+ cp = ((Pktype *)q->ptr)->ctlr;
if(bp->type == M_CTL){
- t = q->ptr;
+ pp = q->ptr;
if(streamparse("connect", bp))
- t->type = strtol((char *)bp->rptr, 0, 0);
+ pp->type = strtol((char *)bp->rptr, 0, 0);
else if(streamparse("promiscuous", bp)) {
- t->prom = 1;
- qlock(c);
- c->prom++;
- if(c->prom == 1)
- outb(c->iobase+Rcr, 0x14); /* PRO|AB */
- qunlock(c);
+ pp->prom = 1;
+ qlock(cp);
+ cp->prom++;
+ if(cp->prom == 1)
+ outb(cp->iobase+Rcr, 0x14); /* PRO|AB */
+ qunlock(cp);
}
freeb(bp);
return;
@@ 160,33 162,30 @@ panic("etheroput\n");
* give packet a local address, return upstream if destined for
* this machine.
*/
- if(BLEN(bp) < ETHERHDRSIZE){
- bp = pullup(bp, ETHERHDRSIZE);
- if(bp == 0)
- return;
- }
+ if(BLEN(bp) < ETHERHDRSIZE && (bp = pullup(bp, ETHERHDRSIZE)) == 0)
+ return;
p = (Etherpkt *)bp->rptr;
- memmove(p->s, c->ea, sizeof(c->ea));
- if(memcmp(c->ea, p->d, sizeof(c->ea)) == 0){
+ memmove(p->s, cp->ea, sizeof(cp->ea));
+ if(memcmp(cp->ea, p->d, sizeof(cp->ea)) == 0){
len = blen(bp);
- bp = expandb(bp, len >= ETHERMINTU ? len: ETHERMINTU);
- if(bp){
- putq(&c->rq, bp);
- wakeup(&c->rr);
+ if (bp = expandb(bp, len >= ETHERMINTU ? len: ETHERMINTU)){
+ putq(&cp->rq, bp);
+ wakeup(&cp->rr);
}
return;
}
- if(memcmp(c->ba, p->d, sizeof(c->ba)) == 0){
+ if(memcmp(cp->ba, p->d, sizeof(cp->ba)) == 0){
len = blen(bp);
nbp = copyb(bp, len);
- nbp = expandb(nbp, len >= ETHERMINTU ? len: ETHERMINTU);
- if(nbp){
+ if(nbp = expandb(nbp, len >= ETHERMINTU ? len: ETHERMINTU)){
nbp->wptr = nbp->rptr+len;
- putq(&c->rq, nbp);
- wakeup(&c->rr);
+ putq(&cp->rq, nbp);
+ wakeup(&cp->rr);
}
}
+panic("etheroput\n");
+#ifdef notdef
/*
* only one transmitter at a time
*/
@@ 509,6 508,18 @@ etherup(Ctlr *cp, Etherpkt *p, int len)
}
}
+static void
+printpkt(uchar bnry, ushort len, Etherpkt *p)
+{
+ int i;
+
+ print("%.2ux: %.4d d(%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux)s(%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux)t(%.2ux %.2ux)\n",
+ bnry, len,
+ p->d[0], p->d[1], p->d[2], p->d[3], p->d[4], p->d[5],
+ p->s[0], p->s[1], p->s[2], p->s[3], p->s[4], p->s[5],
+ p->type[0], p->type[1]);
+}
+
static int
isinput(void *arg)
{
@@ 534,17 545,34 @@ etherkproc(void *arg)
cp->kproc = 1;
for(;;){
sleep(&cp->rr, isinput, cp);
+ /*
+ * process any internal loopback packets
+ */
while(bp = getq(&cp->rq)){
cp->inpackets++;
etherup(cp, (Etherpkt*)bp->rptr, BLEN(bp));
freeb(bp);
}
-#ifdef foo
- bnry = inb(cp->iobase+Bnry);
- while(bnry != cp->curr){
- rp = &((Ring *)RAMbase)[bnry];
- }
-#endif
+ /*
+ * process any received packets
+ */
+ bnry = inb(cp->iobase+Bnry);
+ while(bnry != cp->curr){
+ rp = &((Ring*)RAMbase)[bnry];
+printpkt(bnry, rp->len, (Etherpkt*)rp->data);
+ cp->inpackets++;
+ etherup(cp, (Etherpkt*)rp->data, rp->len-4);
+ bnry = rp->next;
+ outb(cp->iobase+Bnry, bnry);
+ }
+ /*
+ * if we idled input because of overflow,
+ * restart
+ */
+ if(cp->ovw){
+ cp->ovw = 0;
+ outb(cp->iobase+Tcr, 0);
+ }
}
}
@@ 79,10 79,43 @@ reset(Ipaddr source, Ipaddr dest, char tos, ushort length, Tcp *seg)
PUTNEXT(Ipoutput, hbp);
}
+Ipconv*
+tcpincoming(Ipconv *ipc, Ipconv *s, Tcp *segp, Ipaddr source)
+{
+ Ipconv *new;
+
+ if(s->curlog >= s->backlog)
+ return 0;
+
+ new = ipincoming(ipc, s);
+ if(new == 0)
+ return 0;
+
+ qlock(s);
+ s->curlog++;
+ qunlock(s);
+ new->psrc = segp->dest;
+ new->pdst = segp->source;
+ new->dst = source;
+ memmove(&new->tcpctl, &s->tcpctl, sizeof(Tcpctl));
+ new->tcpctl.flags &= ~CLONE;
+ new->tcpctl.timer.arg = new;
+ new->tcpctl.timer.state = TIMER_STOP;
+ new->tcpctl.acktimer.arg = new;
+ new->tcpctl.acktimer.state = TIMER_STOP;
+ new->newcon = 1;
+ new->ipinterface = s->ipinterface;
+
+ s->ipinterface->ref++;
+ wakeup(&s->listenr);
+ return new;
+}
+
void
tcp_input(Ipconv *ipc, Block *bp)
{
- Ipconv *s, *e, *new;
+ Ipconv *s, *e;
+ Ipconv *spec, *gen;
Tcpctl *tcb;
Tcphdr *h;
Tcp seg;
@@ 117,48 150,40 @@ tcp_input(Ipconv *ipc, Block *bp)
/* Look for a connection, failing that attempt to establish a listen */
s = ip_conn(ipc, seg.dest, seg.source, source, IP_TCPPROTO);
if (s == 0) {
- if((seg.flags & SYN) == 0)
- goto clear;
-
- e = &ipc[conf.ip];
- for(s = ipc; s < e; s++) {
- if(s->tcpctl.state == Listen)
- if(s->pdst == 0)
- if(s->dst == 0) {
- if(s->curlog >= s->backlog)
- goto clear;
-
- new = ipincoming(ipc, s);
- if(new == 0)
- goto clear;
-
- qlock(s);
- s->curlog++;
- qunlock(s);
- new->psrc = seg.dest;
- new->pdst = seg.source;
- new->dst = source;
- memmove(&new->tcpctl, &s->tcpctl, sizeof(Tcpctl));
- new->tcpctl.flags &= ~CLONE;
- new->tcpctl.timer.arg = new;
- new->tcpctl.timer.state = TIMER_STOP;
- new->tcpctl.acktimer.arg = new;
- new->tcpctl.acktimer.state = TIMER_STOP;
- new->newcon = 1;
- new->ipinterface = s->ipinterface;
-
- s->ipinterface->ref++;
- wakeup(&s->listenr);
- s = new;
- goto process;
+ if(seg.flags & SYN){
+ /*
+ * find a listener specific to this port (spec) or,
+ * failing that, a general one (gen)
+ */
+ spec = 0;
+ gen = 0;
+ e = &ipc[conf.ip];
+ for(s = ipc; s < e; s++) {
+ if(s->tcpctl.state == Listen)
+ if(s->pdst == 0)
+ if(s->dst == 0) {
+ if(s->psrc == seg.dest){
+ spec = s;
+ break;
+ }
+ if(s->psrc == 0)
+ gen = s;
+ }
}
+ if(spec)
+ s = tcpincoming(ipc, spec, &seg, source);
+ else if(gen)
+ s = tcpincoming(ipc, gen, &seg, source);
+ else
+ s = 0;
+ }
+ if(s == 0){
+ freeb(bp);
+ reset(source, dest, tos, length, &seg);
+ return;
}
- clear:
- freeb(bp);
- reset(source, dest, tos, length, &seg);
- return;
}
-process:
+
/* The rest of the input state machine is run with the control block
* locked
*/