Fixes MAC addr formatting
[akaros.git] / kern / drivers / dev / ether.c
1 // INFERNO
2 #include <vfs.h>
3 #include <kfs.h>
4 #include <slab.h>
5 #include <kmalloc.h>
6 #include <kref.h>
7 #include <string.h>
8 #include <stdio.h>
9 #include <assert.h>
10 #include <error.h>
11 #include <cpio.h>
12 #include <pmap.h>
13 #include <smp.h>
14 #include <ip.h>
15
16 #include <vfs.h>
17 #include <kfs.h>
18 #include <slab.h>
19 #include <kmalloc.h>
20 #include <kref.h>
21 #include <string.h>
22 #include <stdio.h>
23 #include <assert.h>
24 #include <error.h>
25 #include <cpio.h>
26 #include <pmap.h>
27 #include <smp.h>
28 #include <ip.h>
29
30 enum {
31         Type8021Q=      0x8100, /* value of type field for 802.1[pQ] tags */
32 };
33
34 static struct ether *etherxx[MaxEther]; /* real controllers */
35 static struct ether*    vlanalloc(struct ether*, int);
36 static void     vlanoq(struct ether*, struct block*);
37
38 struct chan*
39 etherattach(char* spec)
40 {
41         ERRSTACK(1);
42         uint32_t ctlrno;
43         char *p;
44         struct chan *chan;
45         struct ether *ether, *vlan;
46         int vlanid;
47
48         ctlrno = 0;
49         vlanid = 0;
50         if(spec && *spec){
51                 ctlrno = strtoul(spec, &p, 0);
52                 /* somebody interpret this for me. */
53                 if (((ctlrno == 0) && (p == spec)) ||
54                     (ctlrno >= MaxEther) ||
55                     ((*p) && (*p != '.')))
56                         error(Ebadarg);
57                 if(*p == '.'){  /* vlan */
58                         vlanid = strtoul(p+1, &p, 0);
59                         if(vlanid <= 0 || vlanid > 0xFFF || *p)
60                                 error(Ebadarg);
61                 }
62         }
63         if((ether = etherxx[ctlrno]) == 0)
64                 error(Enodev);
65         rlock(&ether->rwlock);
66         if(waserror()){
67                 runlock(&ether->rwlock);
68                 nexterror();
69         }
70         if(vlanid){
71                 if(ether->maxmtu < ETHERMAXTU+4)
72                         error("interface cannot support 802.1 tags");
73                 vlan = vlanalloc(ether, vlanid);
74                 chan = devattach('l', spec);
75                 chan->dev = ctlrno  + (vlanid<<8);
76                 chan->aux = vlan;
77                 poperror();
78                 runlock(&ether->rwlock);
79                 return chan;
80         }
81         chan = devattach('l', spec);
82         chan->dev = ctlrno;
83         chan->aux = ether;
84         if(ether->attach)
85                 ether->attach(ether);
86         poperror();
87         runlock(&ether->rwlock);
88         return chan;
89 }
90
91 static void
92 ethershutdown(void)
93 {
94         struct ether *ether;
95         int i;
96
97         for(i=0; i<MaxEther; i++){
98                 ether = etherxx[i];
99                 if(ether != NULL && ether->detach != NULL)
100                         ether->detach(ether);
101         }
102 }
103
104 static struct walkqid*
105 etherwalk(struct chan* chan, struct chan *nchan, char **name, int nname)
106 {
107         ERRSTACK(1);
108         struct walkqid *wq;
109         struct ether *ether;
110
111         ether = chan->aux;
112         rlock(&ether->rwlock);
113         if(waserror()) {
114                 runlock(&ether->rwlock);
115                 nexterror();
116         }
117         wq = netifwalk(&ether->netif, chan, nchan, name, nname);
118         if(wq && wq->clone != NULL && wq->clone != chan)
119                 wq->clone->aux = ether;
120         poperror();
121         runlock(&ether->rwlock);
122         return wq;
123 }
124
125 static int
126 etherstat(struct chan* chan, uint8_t* dp, int n)
127 {
128         ERRSTACK(1);
129         int s;
130         struct ether *ether;
131
132         ether = chan->aux;
133         rlock(&ether->rwlock);
134         if(waserror()) {
135                 runlock(&ether->rwlock);
136                 nexterror();
137         }
138         s = netifstat(&ether->netif, chan, dp, n);
139         poperror();
140         runlock(&ether->rwlock);
141         return s;
142 }
143
144 static struct chan*
145 etheropen(struct chan* chan, int omode)
146 {
147         ERRSTACK(1);
148         struct chan *c;
149         struct ether *ether;
150
151         ether = chan->aux;
152         rlock(&ether->rwlock);
153         if(waserror()) {
154                 runlock(&ether->rwlock);
155                 nexterror();
156         }
157         c = netifopen(&ether->netif, chan, omode);
158         poperror();
159         runlock(&ether->rwlock);
160         return c;
161 }
162
163 static void
164 etherclose(struct chan* chan)
165 {
166         ERRSTACK(1);
167         struct ether *ether;
168
169         ether = chan->aux;
170         rlock(&ether->rwlock);
171         if(waserror()) {
172                 runlock(&ether->rwlock);
173                 nexterror();
174         }
175         netifclose(&ether->netif, chan);
176         poperror();
177         runlock(&ether->rwlock);
178 }
179
180 static long
181 etherread(struct chan* chan, void* buf, long n, int64_t off)
182 {
183         ERRSTACK(1);
184         struct ether *ether;
185         uint32_t offset = off;
186         long r;
187
188         ether = chan->aux;
189         rlock(&ether->rwlock);
190         if(waserror()) {
191                 runlock(&ether->rwlock);
192                 nexterror();
193         }
194         if((chan->qid.type & QTDIR) == 0 && ether->ifstat){
195                 /*
196                  * With some controllers it is necessary to reach
197                  * into the chip to extract statistics.
198                  */
199                 if(NETTYPE(chan->qid.path) == Nifstatqid){
200                         r = ether->ifstat(ether, buf, n, offset);
201                         goto out;
202                 }
203                 if(NETTYPE(chan->qid.path) == Nstatqid)
204                         ether->ifstat(ether, buf, 0, offset);
205         }
206         r = netifread(&ether->netif, chan, buf, n, offset);
207 out:
208         poperror();
209         runlock(&ether->rwlock);
210         return r;
211 }
212
213 static struct block*
214 etherbread(struct chan* chan, long n, uint32_t offset)
215 {
216         ERRSTACK(1);
217         struct block *b;
218         struct ether *ether;
219
220         ether = chan->aux;
221         rlock(&ether->rwlock);
222         if(waserror()) {
223                 runlock(&ether->rwlock);
224                 nexterror();
225         }
226         b = netifbread(&ether->netif, chan, n, offset);
227         poperror();
228         runlock(&ether->rwlock);
229         return b;
230 }
231
232 static int
233 etherwstat(struct chan* chan, uint8_t* dp, int n)
234 {
235         ERRSTACK(1);
236         struct ether *ether;
237         int r;
238
239         ether = chan->aux;
240         rlock(&ether->rwlock);
241         if(waserror()) {
242                 runlock(&ether->rwlock);
243                 nexterror();
244         }
245         r = netifwstat(&ether->netif, chan, dp, n);
246         poperror();
247         runlock(&ether->rwlock);
248         return r;
249 }
250
251 static void
252 etherrtrace(struct netfile* f, struct etherpkt* pkt, int len)
253 {
254         int i, n;
255         struct block *bp;
256
257         if(qwindow(f->in) <= 0)
258                 return;
259         if(len > 58)
260                 n = 58;
261         else
262                 n = len;
263         bp = iallocb(64);
264         if(bp == NULL)
265                 return;
266         memmove(bp->wp, pkt->d, n);
267         i = milliseconds();
268         bp->wp[58] = len>>8;
269         bp->wp[59] = len;
270         bp->wp[60] = i>>24;
271         bp->wp[61] = i>>16;
272         bp->wp[62] = i>>8;
273         bp->wp[63] = i;
274         bp->wp += 64;
275         qpass(f->in, bp);
276 }
277
278 struct block*
279 etheriq(struct ether* ether, struct block* bp, int fromwire)
280 {
281         struct etherpkt *pkt;
282         uint16_t type;
283         int len, multi, tome, fromme, vlanid, i;
284         struct netfile **ep, *f, **fp, *fx;
285         struct block *xbp;
286         struct ether *vlan;
287
288         ether->netif.inpackets++;
289
290         pkt = (struct etherpkt*)bp->rp;
291         len = BLEN(bp);
292         type = (pkt->type[0]<<8)|pkt->type[1];
293         if(type == Type8021Q && ether->nvlan){
294                 vlanid = nhgets(bp->rp+2*Eaddrlen+2) & 0xFFF;
295                 if(vlanid){
296                         for(i = 0; i < ARRAY_SIZE(ether->vlans); i++){
297                                 vlan = ether->vlans[i];
298                                 if(vlan != NULL && vlan->vlanid == vlanid){
299                                         memmove(bp->rp+4, bp->rp, 2*Eaddrlen);
300                                         bp->rp += 4;
301                                         return etheriq(vlan, bp, fromwire);
302                                 }
303                         }
304                         /* allow normal type handling to accept or discard it */
305                 }
306         }
307
308         fx = 0;
309         ep = &ether->netif.f[Ntypes];
310
311         multi = pkt->d[0] & 1;
312         /* check for valid multcast addresses */
313         if(multi && memcmp(pkt->d, ether->netif.bcast, sizeof(pkt->d)) != 0 && ether->netif.prom == 0){
314                 if(!activemulti(&ether->netif, pkt->d, sizeof(pkt->d))){
315                         if(fromwire){
316                                 freeb(bp);
317                                 bp = 0;
318                         }
319                         return bp;
320                 }
321         }
322
323         /* is it for me? */
324         tome = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
325         fromme = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0;
326
327         /*
328          * Multiplex the packet to all the connections which want it.
329          * If the packet is not to be used subsequently (fromwire != 0),
330          * attempt to simply pass it into one of the connections, thereby
331          * saving a copy of the data (usual case hopefully).
332          */
333         for(fp = ether->netif.f; fp < ep; fp++){
334                 if((f = *fp) && (f->type == type || f->type < 0))
335                 if(tome || multi || f->prom){
336                         /* Don't want to hear bridged packets */
337                         if(f->bridge && !fromwire && !fromme)
338                                 continue;
339                         if(!f->headersonly){
340                                 if(fromwire && fx == 0)
341                                         fx = f;
342                                 else if((xbp = iallocb(len))){
343                                         memmove(xbp->wp, pkt, len);
344                                         xbp->wp += len;
345                                         if(qpass(f->in, xbp) < 0)
346                                                 ether->netif.soverflows++;
347                                 }
348                                 else
349                                         ether->netif.soverflows++;
350                         }
351                         else
352                                 etherrtrace(f, pkt, len);
353                 }
354         }
355
356         if(fx){
357                 if(qpass(fx->in, bp) < 0)
358                         ether->netif.soverflows++;
359                 return 0;
360         }
361         if(fromwire){
362                 freeb(bp);
363                 return 0;
364         }
365
366         return bp;
367 }
368
369 static int
370 etheroq(struct ether* ether, struct block* bp)
371 {
372         int len, loopback;
373         struct etherpkt *pkt;
374         int8_t irq_state = 0;
375
376         ether->netif.outpackets++;
377
378         /*
379          * Check if the packet has to be placed back onto the input queue,
380          * i.e. if it's a loopback or broadcast packet or the interface is
381          * in promiscuous mode.
382          * If it's a loopback packet indicate to etheriq that the data isn't
383          * needed and return, etheriq will pass-on or free the block.
384          * To enable bridging to work, only packets that were originated
385          * by this interface are fed back.
386          */
387         pkt = (struct etherpkt*)bp->rp;
388         len = BLEN(bp);
389         loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
390         if(loopback || memcmp(pkt->d, ether->netif.bcast, sizeof(pkt->d)) == 0 || ether->netif.prom){
391                 disable_irqsave(&irq_state);
392                 etheriq(ether, bp, 0);
393                 enable_irqsave(&irq_state);
394         }
395
396         if(!loopback){
397                 if(ether->vlanid){
398                         /* add tag */
399                         bp = padblock(bp, 2+2);
400                         memmove(bp->rp, bp->rp+4, 2*Eaddrlen);
401                         hnputs(bp->rp+2*Eaddrlen, Type8021Q);
402                         hnputs(bp->rp+2*Eaddrlen+2, ether->vlanid & 0xFFF);     /* prio:3 0:1 vid:12 */
403                         ether = ether->ctlr;
404                 }
405                 qbwrite(ether->oq, bp);
406                 if(ether->transmit != NULL)
407                         ether->transmit(ether);
408         }else
409                 freeb(bp);
410
411         return len;
412 }
413
414 static long
415 etherwrite(struct chan* chan, void* buf, long n, int64_t unused)
416 {
417         ERRSTACK(2);
418         struct ether *ether;
419         struct block *bp;
420         int onoff;
421         struct cmdbuf *cb;
422         long l;
423
424         ether = chan->aux;
425         rlock(&ether->rwlock);
426         if(waserror()) {
427                 runlock(&ether->rwlock);
428                 nexterror();
429         }
430         if(NETTYPE(chan->qid.path) != Ndataqid) {
431                 l = netifwrite(&ether->netif, chan, buf, n);
432                 if(l >= 0)
433                         goto out;
434                 cb = parsecmd(buf, n);
435                 if(strcmp(cb->f[0], "nonblocking") == 0){
436                         if(cb->nf <= 1)
437                                 onoff = 1;
438                         else
439                                 onoff = atoi(cb->f[1]);
440                         if(ether->oq != NULL)
441                                 qnoblock(ether->oq, onoff);
442                         kfree(cb);
443                         goto out;
444                 }
445                 kfree(cb);
446                 if(ether->ctl!=NULL){
447                         l = ether->ctl(ether,buf,n);
448                         goto out;
449                 }
450                 error(Ebadctl);
451         }
452
453         if(n > ether->maxmtu)
454                 error(Etoobig);
455         if(n < ether->minmtu)
456                 error(Etoosmall);
457         bp = allocb(n);
458         if(waserror()){
459                 freeb(bp);
460                 nexterror();
461         }
462         memmove(bp->rp, buf, n);
463         memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
464         bp->wp += n;
465         poperror();
466
467         l = etheroq(ether, bp);
468 out:
469         poperror();
470         runlock(&ether->rwlock);
471         return l;
472 }
473
474 static long
475 etherbwrite(struct chan* chan, struct block* bp, uint32_t unused)
476 {
477         ERRSTACK(1);
478         struct ether *ether;
479         long n;
480
481         n = BLEN(bp);
482         if(NETTYPE(chan->qid.path) != Ndataqid){
483                 if(waserror()) {
484                         freeb(bp);
485                         nexterror();
486                 }
487                 n = etherwrite(chan, bp->rp, n, 0);
488                 poperror();
489                 freeb(bp);
490                 return n;
491         }
492         ether = chan->aux;
493         rlock(&ether->rwlock);
494         if(waserror()) {
495                 runlock(&ether->rwlock);
496                 nexterror();
497         }
498         if(n > ether->maxmtu){
499                 freeb(bp);
500                 error(Etoobig);
501         }
502         if(n < ether->minmtu){
503                 freeb(bp);
504                 error(Etoosmall);
505         }
506         n = etheroq(ether, bp);
507         poperror();
508         runlock(&ether->rwlock);
509         return n;
510 }
511
512 static void
513 nop(struct ether*unused)
514 {
515 }
516
517 static long
518 vlanctl(struct ether *ether, void *buf, long n)
519 {
520         uint8_t ea[Eaddrlen];
521         struct ether *master;
522         struct cmdbuf *cb;
523         int i;
524
525         cb = parsecmd(buf, n);
526         if(cb->nf >= 2
527         && strcmp(cb->f[0], "ea")==0
528         && parseether(ea, cb->f[1]) == 0){
529                 kfree(cb);
530                 memmove(ether->ea, ea, Eaddrlen);
531                 memmove(ether->netif.addr, ether->ea, Eaddrlen);
532                 return 0;
533         }
534         if(cb->nf == 1 && strcmp(cb->f[0], "disable") == 0){
535                 master = ether->ctlr;
536                 qlock(&master->vlq);
537                 for(i = 0; i < ARRAY_SIZE(master->vlans); i++)
538                         if(master->vlans[i] == ether){
539                                 ether->vlanid = 0;
540                                 master->nvlan--;
541                                 break;
542                         }
543                 qunlock(&master->vlq);
544                 kfree(cb);
545                 return 0;
546         }
547         kfree(cb);
548         error(Ebadctl);
549         return -1;      /* not reached */
550 }
551
552 static struct ether*
553 vlanalloc(struct ether *ether, int id)
554 {
555         ERRSTACK(1);
556         struct ether *vlan;
557         int i, fid;
558         char name[KNAMELEN];
559
560         qlock(&ether->vlq);
561         if(waserror()){
562                 qunlock(&ether->vlq);
563                 nexterror();
564         }
565         fid = -1;
566         for(i = 0; i < ARRAY_SIZE(ether->vlans); i++){
567                 vlan = ether->vlans[i];
568                 if(vlan != NULL && vlan->vlanid == id){
569                         poperror();
570                         qunlock(&ether->vlq);
571                         return vlan;
572                 }
573                 if(fid < 0 && (vlan == NULL || vlan->vlanid == 0))
574                         fid = i;
575         }
576         if(fid < 0)
577                 error(Enoifc);
578         snprintf(name, sizeof(name), "ether%d.%d", ether->ctlrno, id);
579         vlan = ether->vlans[fid];
580         if(vlan == NULL){
581                 vlan = kzmalloc(sizeof(struct ether), 1);
582                 if(vlan == NULL)
583                         error(Enovmem);
584                 rwinit(&vlan->rwlock);
585                 qlock_init(&vlan->vlq);
586                 netifinit(&vlan->netif, name, Ntypes, ether->netif.limit);
587                 ether->vlans[fid] = vlan;       /* id is still zero, can't be matched */
588                 ether->nvlan++;
589         }else
590                 memmove(vlan->netif.name, name, KNAMELEN-1);
591         vlan->attach = nop;
592         vlan->transmit = NULL;
593         vlan->ctl = vlanctl;
594         vlan->irq = -1;
595         vlan->netif.promiscuous = ether->netif.promiscuous;
596         vlan->netif.multicast = ether->netif.multicast;
597         vlan->netif.arg = vlan;
598         vlan->netif.mbps = ether->netif.mbps;
599         vlan->fullduplex = ether->fullduplex;
600         vlan->encry = ether->encry;
601         vlan->minmtu = ether->minmtu;
602         vlan->maxmtu = ether->maxmtu;
603         vlan->ctlrno = ether->ctlrno;
604         vlan->vlanid = id;
605         vlan->netif.alen = Eaddrlen;
606         memmove(vlan->netif.addr, ether->netif.addr, sizeof(vlan->netif.addr));
607         memmove(vlan->netif.bcast, ether->netif.bcast, sizeof(ether->netif.bcast));
608         vlan->oq = NULL;
609         vlan->ctlr = ether;
610         vlan->vlanid = id;
611         poperror();
612         qunlock(&ether->vlq);
613         return vlan;
614 }
615
616 static struct {
617         char*   type;
618         int     (*reset)(struct ether*);
619 } cards[MaxEther+1];
620
621 void
622 addethercard(char* t, int (*r)(struct ether*))
623 {
624         static int ncard;
625
626         if(ncard == MaxEther)
627                 panic("too many ether cards");
628         cards[ncard].type = t;
629         cards[ncard].reset = r;
630         ncard++;
631 }
632
633 int
634 parseether(uint8_t *to, char *from)
635 {
636         char nip[4];
637         char *p;
638         int i;
639
640         p = from;
641         for(i = 0; i < Eaddrlen; i++){
642                 if(*p == 0)
643                         return -1;
644                 nip[0] = *p++;
645                 if(*p == 0)
646                         return -1;
647                 nip[1] = *p++;
648                 nip[2] = 0;
649                 to[i] = strtoul(nip, 0, 16);
650                 if(*p == ':')
651                         p++;
652         }
653         return 0;
654 }
655
656 static void
657 etherreset(void)
658 {
659         struct ether *ether;
660         int i, n, ctlrno;
661         char name[KNAMELEN], buf[128];
662
663         for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){
664                 if(ether == 0)
665                         ether = kzmalloc(sizeof(struct ether), 0);
666                 memset(ether, 0, sizeof(struct ether));
667                 rwinit(&ether->rwlock);
668                 qlock_init(&ether->vlq);
669                 ether->ctlrno = ctlrno;
670                 ether->netif.mbps = 10;
671                 ether->minmtu = ETHERMINTU;
672                 ether->maxmtu = ETHERMAXTU;
673                 /* looked like irq type, we don't have these yet */
674                 //ether->netif.itype = -1;
675
676                 /* TODO: looks like they expected some init to be done here.  at the
677                  * very least, ether->type is 0 right now, and needs to be set.  looking
678                  * around online, it seems to find out ether config settings, so that we
679                  * can set some flags in the opt parseing below. */
680                 //if(archether(ctlrno, ether) <= 0)
681                 //      continue;
682
683                 for(n = 0; cards[n].type; n++){
684                         #if 0
685                         if(cistrcmp(cards[n].type, ether->type))
686                                 continue;
687                         for(i = 0; i < ether->nopt; i++){
688                                 if(cistrncmp(ether->opt[i], "ea=", 3) == 0){
689                                         if(parseether(ether->ea, &ether->opt[i][3]) == -1)
690                                                 memset(ether->ea, 0, Eaddrlen);
691                                 }else if(cistrcmp(ether->opt[i], "fullduplex") == 0 ||
692                                         cistrcmp(ether->opt[i], "10BASE-TFD") == 0)
693                                         ether->fullduplex = 1;
694                                 else if(cistrcmp(ether->opt[i], "100BASE-TXFD") == 0)
695                                         ether->mbps = 100;
696                         }
697                         #endif
698                         if(cards[n].reset(ether))
699                                 break;
700                         /* might be fucked a bit - reset() doesn't know the type.  might not
701                          * even matter, except for debugging. */
702                         ether->type = cards[n].type;
703                         snprintf(name, sizeof(name), "ether%d", ctlrno);
704
705                         if(ether->interrupt != NULL)
706                                 register_dev_irq(ether->irq, ether->interrupt, ether);
707
708                         i = snprintf(buf, sizeof(buf),
709                                      "#l%d: %s: %dMbps port 0x%x irq %u", ctlrno,
710                                      ether->type, ether->netif.mbps, ether->port,
711                                      ether->irq);
712                         /* Looks like this is for printing MMIO addrs */
713                         #if 0
714                         if(ether->mem)
715                                 i += snprintf(buf + i, sizeof(buf) - i, " addr 0x%lx",
716                                               PADDR(ether->mem));
717                         if(ether->size)
718                                 i += snprintf(buf + i, sizeof(buf) - i, " size 0x%lx",
719                                               ether->size);
720                         #endif
721                         i += snprintf(buf + i, sizeof(buf) - i,
722                                       ": %02.2x:%02.2x:%02.2x:%02.2x:%02.2x:%02.2x",
723                                       ether->ea[0], ether->ea[1], ether->ea[2],
724                                       ether->ea[3], ether->ea[4], ether->ea[5]);
725                         snprintf(buf + i, sizeof(buf) - i, "\n");
726                         printk(buf);
727
728                         if(ether->netif.mbps == 100){
729                                 netifinit(&ether->netif, name, Ntypes, 256*1024);
730                                 if(ether->oq == 0)
731                                         ether->oq = qopen(256*1024, Qmsg, 0, 0);
732                         }
733                         else{
734                                 netifinit(&ether->netif, name, Ntypes, 64*1024);
735                                 if(ether->oq == 0)
736                                         ether->oq = qopen(64*1024, Qmsg, 0, 0);
737                         }
738                         if(ether->oq == 0)
739                                 panic("etherreset %s", name);
740                         ether->netif.alen = Eaddrlen;
741                         memmove(ether->netif.addr, ether->ea, Eaddrlen);
742                         memset(ether->netif.bcast, 0xFF, Eaddrlen);
743
744                         etherxx[ctlrno] = ether;
745                         ether = 0;
746                         break;
747                 }
748         }
749         if(ether)
750                 kfree(ether);
751 }
752
753 static void
754 etherpower(int on)
755 {
756         int i;
757         struct ether *ether;
758
759         /* TODO: fix etherpower.  locking and ether->readers are broken. */
760         warn("%s needs attention.  had a rough porting from inferno", __FUNCTION__);
761         for(i = 0; i < MaxEther; i++){
762                 if((ether = etherxx[i]) == NULL || ether->power == NULL)
763                         continue;
764                 if(on){
765                         /* brho: not sure what they are doing.  there seem to be certain
766                          * assumptions about calling etherpower.  i think they are using
767                          * canrlock to see if the lock is currently writelocked.  and if it
768                          * was not lockable, they would assume they had the write lock and
769                          * could unlock.  this is super fucked up. */
770                         if(canrlock(&ether->rwlock)) {
771                                 runlock(&ether->rwlock);        // brho added this
772                                 continue;
773                         }
774                         if(ether->power != NULL)
775                                 ether->power(ether, on);
776                         wunlock(&ether->rwlock);
777                 }else{
778                         /* readers isn't in the ether struct...
779                         if(ether->readers)
780                                 continue;
781                         */
782                         wlock(&ether->rwlock);
783                         if(ether->power != NULL)
784                                 ether->power(ether, on);
785                         /* Keep locked until power goes back on */
786                 }
787         }
788 }
789
790 #define ETHERPOLY 0xedb88320
791
792 /* really slow 32 bit crc for ethers */
793 uint32_t
794 ethercrc(uint8_t *p, int len)
795 {
796         int i, j;
797         uint32_t crc, b;
798
799         crc = 0xffffffff;
800         for(i = 0; i < len; i++){
801                 b = *p++;
802                 for(j = 0; j < 8; j++){
803                         crc = (crc>>1) ^ (((crc^b) & 1) ? ETHERPOLY : 0);
804                         b >>= 1;
805                 }
806         }
807         return crc;
808 }
809
810 struct dev etherdevtab __devtab = {
811         'l',
812         "ether",
813
814         etherreset,
815         devinit,
816         ethershutdown,
817         etherattach,
818         etherwalk,
819         etherstat,
820         etheropen,
821         devcreate,
822         etherclose,
823         etherread,
824         etherbread,
825         etherwrite,
826         etherbwrite,
827         devremove,
828         etherwstat,
829         etherpower,
830 };