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