85481c53ac30b63652b09fb774d00d6a63c1c209
[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                 ptclcsum_finalize(bp, ether->netif.feat);
381                 qbwrite(ether->oq, bp);
382                 if (ether->transmit != NULL)
383                         ether->transmit(ether);
384         } else
385                 freeb(bp);
386
387         return len;
388 }
389
390 static long etherwrite(struct chan *chan, void *buf, long n, int64_t unused)
391 {
392         ERRSTACK(2);
393         struct ether *ether;
394         struct block *bp;
395         int onoff;
396         struct cmdbuf *cb;
397         long l;
398
399         ether = chan->aux;
400         rlock(&ether->rwlock);
401         if (waserror()) {
402                 runlock(&ether->rwlock);
403                 nexterror();
404         }
405         if (NETTYPE(chan->qid.path) != Ndataqid) {
406                 l = netifwrite(&ether->netif, chan, buf, n);
407                 if (l >= 0)
408                         goto out;
409                 cb = parsecmd(buf, n);
410                 if (strcmp(cb->f[0], "nonblocking") == 0) {
411                         if (cb->nf <= 1)
412                                 onoff = 1;
413                         else
414                                 onoff = atoi(cb->f[1]);
415                         if (ether->oq != NULL)
416                                 qnoblock(ether->oq, onoff);
417                         kfree(cb);
418                         goto out;
419                 }
420                 kfree(cb);
421                 if (ether->ctl != NULL) {
422                         l = ether->ctl(ether, buf, n);
423                         goto out;
424                 }
425                 error(Ebadctl);
426         }
427
428         if (n > ether->maxmtu)
429                 error(Etoobig);
430         if (n < ether->minmtu)
431                 error(Etoosmall);
432         bp = allocb(n);
433         if (waserror()) {
434                 freeb(bp);
435                 nexterror();
436         }
437         memmove(bp->rp, buf, n);
438         memmove(bp->rp + Eaddrlen, ether->ea, Eaddrlen);
439         bp->wp += n;
440         poperror();
441
442         l = etheroq(ether, bp);
443 out:
444         poperror();
445         runlock(&ether->rwlock);
446         return l;
447 }
448
449 static long etherbwrite(struct chan *chan, struct block *bp, uint32_t unused)
450 {
451         ERRSTACK(1);
452         struct ether *ether;
453         long n;
454
455         n = BLEN(bp);
456         if (NETTYPE(chan->qid.path) != Ndataqid) {
457                 if (waserror()) {
458                         freeb(bp);
459                         nexterror();
460                 }
461                 n = etherwrite(chan, bp->rp, n, 0);
462                 poperror();
463                 freeb(bp);
464                 return n;
465         }
466         ether = chan->aux;
467         rlock(&ether->rwlock);
468         if (waserror()) {
469                 runlock(&ether->rwlock);
470                 nexterror();
471         }
472         if (n > ether->maxmtu) {
473                 freeb(bp);
474                 error(Etoobig);
475         }
476         if (n < ether->minmtu) {
477                 freeb(bp);
478                 error(Etoosmall);
479         }
480         n = etheroq(ether, bp);
481         poperror();
482         runlock(&ether->rwlock);
483         return n;
484 }
485
486 static void nop(struct ether *unused)
487 {
488 }
489
490 static long vlanctl(struct ether *ether, void *buf, long n)
491 {
492         uint8_t ea[Eaddrlen];
493         struct ether *master;
494         struct cmdbuf *cb;
495         int i;
496
497         cb = parsecmd(buf, n);
498         if (cb->nf >= 2
499                 && strcmp(cb->f[0], "ea") == 0 && parseether(ea, cb->f[1]) == 0) {
500                 kfree(cb);
501                 memmove(ether->ea, ea, Eaddrlen);
502                 memmove(ether->netif.addr, ether->ea, Eaddrlen);
503                 return 0;
504         }
505         if (cb->nf == 1 && strcmp(cb->f[0], "disable") == 0) {
506                 master = ether->ctlr;
507                 qlock(&master->vlq);
508                 for (i = 0; i < ARRAY_SIZE(master->vlans); i++)
509                         if (master->vlans[i] == ether) {
510                                 ether->vlanid = 0;
511                                 master->nvlan--;
512                                 break;
513                         }
514                 qunlock(&master->vlq);
515                 kfree(cb);
516                 return 0;
517         }
518         kfree(cb);
519         error(Ebadctl);
520         return -1;      /* not reached */
521 }
522
523 static struct ether *vlanalloc(struct ether *ether, int id)
524 {
525         ERRSTACK(1);
526         struct ether *vlan;
527         int i, fid;
528         char name[KNAMELEN];
529
530         qlock(&ether->vlq);
531         if (waserror()) {
532                 qunlock(&ether->vlq);
533                 nexterror();
534         }
535         fid = -1;
536         for (i = 0; i < ARRAY_SIZE(ether->vlans); i++) {
537                 vlan = ether->vlans[i];
538                 if (vlan != NULL && vlan->vlanid == id) {
539                         poperror();
540                         qunlock(&ether->vlq);
541                         return vlan;
542                 }
543                 if (fid < 0 && (vlan == NULL || vlan->vlanid == 0))
544                         fid = i;
545         }
546         if (fid < 0)
547                 error(Enoifc);
548         snprintf(name, sizeof(name), "ether%d.%d", ether->ctlrno, id);
549         vlan = ether->vlans[fid];
550         if (vlan == NULL) {
551                 vlan = kzmalloc(sizeof(struct ether), 1);
552                 if (vlan == NULL)
553                         error(Enovmem);
554                 rwinit(&vlan->rwlock);
555                 qlock_init(&vlan->vlq);
556                 netifinit(&vlan->netif, name, Ntypes, ether->netif.limit);
557                 ether->vlans[fid] = vlan;       /* id is still zero, can't be matched */
558                 ether->nvlan++;
559         } else
560                 memmove(vlan->netif.name, name, KNAMELEN - 1);
561         vlan->attach = nop;
562         vlan->transmit = NULL;
563         vlan->ctl = vlanctl;
564         vlan->irq = -1;
565         vlan->netif.promiscuous = ether->netif.promiscuous;
566         vlan->netif.multicast = ether->netif.multicast;
567         vlan->netif.arg = vlan;
568         vlan->netif.mbps = ether->netif.mbps;
569         vlan->fullduplex = ether->fullduplex;
570         vlan->encry = ether->encry;
571         vlan->minmtu = ether->minmtu;
572         vlan->maxmtu = ether->maxmtu;
573         vlan->ctlrno = ether->ctlrno;
574         vlan->vlanid = id;
575         vlan->netif.alen = Eaddrlen;
576         memmove(vlan->netif.addr, ether->netif.addr, sizeof(vlan->netif.addr));
577         memmove(vlan->netif.bcast, ether->netif.bcast, sizeof(ether->netif.bcast));
578         vlan->oq = NULL;
579         vlan->ctlr = ether;
580         vlan->vlanid = id;
581         poperror();
582         qunlock(&ether->vlq);
583         return vlan;
584 }
585
586 static struct {
587         char *type;
588         int (*reset) (struct ether *);
589 } cards[MaxEther + 1];
590
591 void addethercard(char *t, int (*r) (struct ether *))
592 {
593         static int ncard;
594
595         if (ncard == MaxEther)
596                 panic("too many ether cards");
597         cards[ncard].type = t;
598         cards[ncard].reset = r;
599         ncard++;
600 }
601
602 int parseether(uint8_t * to, char *from)
603 {
604         char nip[4];
605         char *p;
606         int i;
607
608         p = from;
609         for (i = 0; i < Eaddrlen; i++) {
610                 if (*p == 0)
611                         return -1;
612                 nip[0] = *p++;
613                 if (*p == 0)
614                         return -1;
615                 nip[1] = *p++;
616                 nip[2] = 0;
617                 to[i] = strtoul(nip, 0, 16);
618                 if (*p == ':')
619                         p++;
620         }
621         return 0;
622 }
623
624 static void etherreset(void)
625 {
626         struct ether *ether;
627         int i, n, ctlrno, qsize;
628         char name[KNAMELEN], buf[128];
629
630         for (ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++) {
631                 if (ether == 0)
632                         ether = kzmalloc(sizeof(struct ether), 0);
633                 memset(ether, 0, sizeof(struct ether));
634                 rwinit(&ether->rwlock);
635                 qlock_init(&ether->vlq);
636                 ether->ctlrno = ctlrno;
637                 ether->netif.mbps = 10;
638                 ether->minmtu = ETHERMINTU;
639                 ether->maxmtu = ETHERMAXTU;
640                 /* looked like irq type, we don't have these yet */
641                 //ether->netif.itype = -1;
642
643                 /* TODO: looks like they expected some init to be done here.  at the
644                  * very least, ether->type is 0 right now, and needs to be set.  looking
645                  * around online, it seems to find out ether config settings, so that we
646                  * can set some flags in the opt parseing below. */
647                 //if(archether(ctlrno, ether) <= 0)
648                 //  continue;
649
650                 for (n = 0; cards[n].type; n++) {
651 #if 0
652                         if (cistrcmp(cards[n].type, ether->type))
653                                 continue;
654                         for (i = 0; i < ether->nopt; i++) {
655                                 if (cistrncmp(ether->opt[i], "ea=", 3) == 0) {
656                                         if (parseether(ether->ea, &ether->opt[i][3]) == -1)
657                                                 memset(ether->ea, 0, Eaddrlen);
658                                 } else if (cistrcmp(ether->opt[i], "fullduplex") == 0 ||
659                                                    cistrcmp(ether->opt[i], "10BASE-TFD") == 0)
660                                         ether->fullduplex = 1;
661                                 else if (cistrcmp(ether->opt[i], "100BASE-TXFD") == 0)
662                                         ether->mbps = 100;
663                         }
664 #endif
665                         if (cards[n].reset(ether))
666                                 continue;
667                         /* might be fucked a bit - reset() doesn't know the type.  might not
668                          * even matter, except for debugging. */
669                         ether->type = cards[n].type;
670                         snprintf(name, sizeof(name), "ether%d", ctlrno);
671
672                         i = snprintf(buf, sizeof(buf),
673                                                  "#l%d: %s: %dMbps port 0x%x irq %u", ctlrno,
674                                                  ether->type, ether->netif.mbps, ether->port,
675                                                  ether->irq);
676                         /* Looks like this is for printing MMIO addrs */
677 #if 0
678                         if (ether->mem)
679                                 i += snprintf(buf + i, sizeof(buf) - i, " addr 0x%lx",
680                                                           PADDR(ether->mem));
681                         if (ether->size)
682                                 i += snprintf(buf + i, sizeof(buf) - i, " size 0x%lx",
683                                                           ether->size);
684 #endif
685                         i += snprintf(buf + i, sizeof(buf) - i,
686                                                   ": %02.2x:%02.2x:%02.2x:%02.2x:%02.2x:%02.2x",
687                                                   ether->ea[0], ether->ea[1], ether->ea[2],
688                                                   ether->ea[3], ether->ea[4], ether->ea[5]);
689                         snprintf(buf + i, sizeof(buf) - i, "\n");
690                         printk(buf);
691
692                         switch (ether->netif.mbps) {
693
694                         case 1 ... 99:
695                                 qsize = 64 * 1024;
696                                 break;
697                         case 100 ... 999:
698                                 qsize = 256 * 1024;
699                                 break;
700                         case 1000 ... 9999:
701                                 qsize = 1024 * 1024;
702                                 break;
703                         default:
704                                 qsize = 8 * 1024 * 1024;
705                         }
706                         netifinit(&ether->netif, name, Ntypes, qsize);
707                         if (ether->oq == 0)
708                                 ether->oq = qopen(qsize, Qmsg, 0, 0);
709                         if (ether->oq == 0)
710                                 panic("etherreset %s", name);
711                         ether->netif.alen = Eaddrlen;
712                         memmove(ether->netif.addr, ether->ea, Eaddrlen);
713                         memset(ether->netif.bcast, 0xFF, Eaddrlen);
714
715                         etherxx[ctlrno] = ether;
716                         ether = 0;
717                         break;
718                 }
719         }
720         if (ether)
721                 kfree(ether);
722 }
723
724 static void etherpower(int on)
725 {
726         int i;
727         struct ether *ether;
728
729         /* TODO: fix etherpower.  locking and ether->readers are broken. */
730         warn("%s needs attention.  had a rough porting from inferno", __FUNCTION__);
731         for (i = 0; i < MaxEther; i++) {
732                 if ((ether = etherxx[i]) == NULL || ether->power == NULL)
733                         continue;
734                 if (on) {
735                         /* brho: not sure what they are doing.  there seem to be certain
736                          * assumptions about calling etherpower.  i think they are using
737                          * canrlock to see if the lock is currently writelocked.  and if it
738                          * was not lockable, they would assume they had the write lock and
739                          * could unlock.  this is super fucked up. */
740                         if (canrlock(&ether->rwlock)) {
741                                 runlock(&ether->rwlock);        // brho added this
742                                 continue;
743                         }
744                         if (ether->power != NULL)
745                                 ether->power(ether, on);
746                         wunlock(&ether->rwlock);
747                 } else {
748                         /* readers isn't in the ether struct...
749                            if(ether->readers)
750                            continue;
751                          */
752                         wlock(&ether->rwlock);
753                         if (ether->power != NULL)
754                                 ether->power(ether, on);
755                         /* Keep locked until power goes back on */
756                 }
757         }
758 }
759
760 #define ETHERPOLY 0xedb88320
761
762 /* really slow 32 bit crc for ethers */
763 uint32_t ethercrc(uint8_t * p, int len)
764 {
765         int i, j;
766         uint32_t crc, b;
767
768         crc = 0xffffffff;
769         for (i = 0; i < len; i++) {
770                 b = *p++;
771                 for (j = 0; j < 8; j++) {
772                         crc = (crc >> 1) ^ (((crc ^ b) & 1) ? ETHERPOLY : 0);
773                         b >>= 1;
774                 }
775         }
776         return crc;
777 }
778
779 struct dev etherdevtab __devtab = {
780         'l',
781         "ether",
782
783         etherreset,
784         devinit,
785         ethershutdown,
786         etherattach,
787         etherwalk,
788         etherstat,
789         etheropen,
790         devcreate,
791         etherclose,
792         etherread,
793         etherbread,
794         etherwrite,
795         etherbwrite,
796         devremove,
797         etherwstat,
798         etherpower,
799         devchaninfo,
800 };