Implement TSO
[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 #ifdef CONFIG_RISCV
255 #warning "Potentially unaligned ethernet addrs!"
256 #endif
257
258 static inline int eaddrcmp(uint8_t *x, uint8_t *y)
259 {
260         uint16_t *a = (uint16_t *)x;
261         uint16_t *b = (uint16_t *)y;
262
263         return (a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2]);
264 }
265
266 struct block *etheriq(struct ether *ether, struct block *bp, int fromwire)
267 {
268         struct etherpkt *pkt;
269         uint16_t type;
270         int len, multi, tome, fromme, vlanid, i;
271         struct netfile **ep, *f, **fp, *fx;
272         struct block *xbp;
273         struct ether *vlan;
274
275         ether->netif.inpackets++;
276
277         pkt = (struct etherpkt *)bp->rp;
278         len = BLEN(bp);
279         type = (pkt->type[0] << 8) | pkt->type[1];
280         if (type == Type8021Q && ether->nvlan) {
281                 vlanid = nhgets(bp->rp + 2 * Eaddrlen + 2) & 0xFFF;
282                 if (vlanid) {
283                         for (i = 0; i < ARRAY_SIZE(ether->vlans); i++) {
284                                 vlan = ether->vlans[i];
285                                 if (vlan != NULL && vlan->vlanid == vlanid) {
286                                         memmove(bp->rp + 4, bp->rp, 2 * Eaddrlen);
287                                         bp->rp += 4;
288                                         return etheriq(vlan, bp, fromwire);
289                                 }
290                         }
291                         /* allow normal type handling to accept or discard it */
292                 }
293         }
294
295         fx = 0;
296         ep = &ether->netif.f[Ntypes];
297
298         multi = pkt->d[0] & 1;
299         /* check for valid multcast addresses */
300         if (multi && eaddrcmp(pkt->d, ether->netif.bcast) != 0
301                 && ether->netif.prom == 0) {
302                 if (!activemulti(&ether->netif, pkt->d, sizeof(pkt->d))) {
303                         if (fromwire) {
304                                 freeb(bp);
305                                 bp = 0;
306                         }
307                         return bp;
308                 }
309         }
310
311         /* is it for me? */
312         tome = eaddrcmp(pkt->d, ether->ea) == 0;
313         fromme = eaddrcmp(pkt->s, ether->ea) == 0;
314
315         /*
316          * Multiplex the packet to all the connections which want it.
317          * If the packet is not to be used subsequently (fromwire != 0),
318          * attempt to simply pass it into one of the connections, thereby
319          * saving a copy of the data (usual case hopefully).
320          */
321         for (fp = ether->netif.f; fp < ep; fp++) {
322                 if ((f = *fp) && (f->type == type || f->type < 0))
323                         if (tome || multi || f->prom) {
324                                 /* Don't want to hear bridged packets */
325                                 if (f->bridge && !fromwire && !fromme)
326                                         continue;
327                                 if (!f->headersonly) {
328                                         if (fromwire && fx == 0)
329                                                 fx = f;
330                                         else if ((xbp = iallocb(len))) {
331                                                 memmove(xbp->wp, pkt, len);
332                                                 xbp->wp += len;
333                                                 if (qpass(f->in, xbp) < 0)
334                                                         ether->netif.soverflows++;
335                                         } else
336                                                 ether->netif.soverflows++;
337                                 } else
338                                         etherrtrace(f, pkt, len);
339                         }
340         }
341
342         if (fx) {
343                 if (qpass(fx->in, bp) < 0)
344                         ether->netif.soverflows++;
345                 return 0;
346         }
347         if (fromwire) {
348                 freeb(bp);
349                 return 0;
350         }
351
352         return bp;
353 }
354
355 static int etheroq(struct ether *ether, struct block *bp)
356 {
357         int len, loopback;
358         struct etherpkt *pkt;
359         int8_t irq_state = 0;
360
361         ether->netif.outpackets++;
362
363         if (!(ether->netif.feat & NETF_SG))
364                 bp = linearizeblock(bp);
365         /*
366          * Check if the packet has to be placed back onto the input queue,
367          * i.e. if it's a loopback or broadcast packet or the interface is
368          * in promiscuous mode.
369          * If it's a loopback packet indicate to etheriq that the data isn't
370          * needed and return, etheriq will pass-on or free the block.
371          * To enable bridging to work, only packets that were originated
372          * by this interface are fed back.
373          */
374         pkt = (struct etherpkt *)bp->rp;
375         len = BLEN(bp);
376         loopback = eaddrcmp(pkt->d, ether->ea) == 0;
377         if (loopback || eaddrcmp(pkt->d, ether->netif.bcast) == 0
378                 || ether->netif.prom) {
379                 disable_irqsave(&irq_state);
380                 etheriq(ether, bp, 0);
381                 enable_irqsave(&irq_state);
382         }
383
384         if (!loopback) {
385                 if (ether->vlanid) {
386                         /* add tag */
387                         bp = padblock(bp, 2 + 2);
388                         memmove(bp->rp, bp->rp + 4, 2 * Eaddrlen);
389                         hnputs(bp->rp + 2 * Eaddrlen, Type8021Q);
390                         hnputs(bp->rp + 2 * Eaddrlen + 2, ether->vlanid & 0xFFF);       /* prio:3 0:1 vid:12 */
391                         ether = ether->ctlr;
392                 }
393
394                 if ((ether->netif.feat & NETF_PADMIN) == 0 && BLEN(bp) < ether->minmtu)
395                         bp = adjustblock(bp, ether->minmtu);
396
397                 ptclcsum_finalize(bp, ether->netif.feat);
398                 qbwrite(ether->oq, bp);
399                 if (ether->transmit != NULL)
400                         ether->transmit(ether);
401         } else
402                 freeb(bp);
403
404         return len;
405 }
406
407 static long etherwrite(struct chan *chan, void *buf, long n, int64_t unused)
408 {
409         ERRSTACK(2);
410         struct ether *ether;
411         struct block *bp;
412         int onoff;
413         struct cmdbuf *cb;
414         long l;
415
416         ether = chan->aux;
417         rlock(&ether->rwlock);
418         if (waserror()) {
419                 runlock(&ether->rwlock);
420                 nexterror();
421         }
422         if (NETTYPE(chan->qid.path) != Ndataqid) {
423                 l = netifwrite(&ether->netif, chan, buf, n);
424                 if (l >= 0)
425                         goto out;
426                 cb = parsecmd(buf, n);
427                 if (strcmp(cb->f[0], "nonblocking") == 0) {
428                         if (cb->nf <= 1)
429                                 onoff = 1;
430                         else
431                                 onoff = atoi(cb->f[1]);
432                         if (ether->oq != NULL)
433                                 qnoblock(ether->oq, onoff);
434                         kfree(cb);
435                         goto out;
436                 }
437                 kfree(cb);
438                 if (ether->ctl != NULL) {
439                         l = ether->ctl(ether, buf, n);
440                         goto out;
441                 }
442                 error(Ebadctl);
443         }
444
445         if (n > ether->maxmtu)
446                 error(Etoobig);
447         bp = allocb(n);
448         if (waserror()) {
449                 freeb(bp);
450                 nexterror();
451         }
452         memmove(bp->rp, buf, n);
453         memmove(bp->rp + Eaddrlen, ether->ea, Eaddrlen);
454         bp->wp += n;
455         poperror();
456
457         l = etheroq(ether, bp);
458 out:
459         poperror();
460         runlock(&ether->rwlock);
461         return l;
462 }
463
464 static long etherbwrite(struct chan *chan, struct block *bp, uint32_t unused)
465 {
466         ERRSTACK(1);
467         struct ether *ether;
468         long n;
469
470         n = BLEN(bp);
471         if (NETTYPE(chan->qid.path) != Ndataqid) {
472                 if (waserror()) {
473                         freeb(bp);
474                         nexterror();
475                 }
476                 n = etherwrite(chan, bp->rp, n, 0);
477                 poperror();
478                 freeb(bp);
479                 return n;
480         }
481         ether = chan->aux;
482         rlock(&ether->rwlock);
483         if (waserror()) {
484                 runlock(&ether->rwlock);
485                 nexterror();
486         }
487         if (n > ether->maxmtu && (bp->flag & Btso) == 0) {
488                 freeb(bp);
489                 error(Etoobig);
490         }
491         n = etheroq(ether, bp);
492         poperror();
493         runlock(&ether->rwlock);
494         return n;
495 }
496
497 static void nop(struct ether *unused)
498 {
499 }
500
501 static long vlanctl(struct ether *ether, void *buf, long n)
502 {
503         uint8_t ea[Eaddrlen];
504         struct ether *master;
505         struct cmdbuf *cb;
506         int i;
507
508         cb = parsecmd(buf, n);
509         if (cb->nf >= 2
510                 && strcmp(cb->f[0], "ea") == 0 && parseether(ea, cb->f[1]) == 0) {
511                 kfree(cb);
512                 memmove(ether->ea, ea, Eaddrlen);
513                 memmove(ether->netif.addr, ether->ea, Eaddrlen);
514                 return 0;
515         }
516         if (cb->nf == 1 && strcmp(cb->f[0], "disable") == 0) {
517                 master = ether->ctlr;
518                 qlock(&master->vlq);
519                 for (i = 0; i < ARRAY_SIZE(master->vlans); i++)
520                         if (master->vlans[i] == ether) {
521                                 ether->vlanid = 0;
522                                 master->nvlan--;
523                                 break;
524                         }
525                 qunlock(&master->vlq);
526                 kfree(cb);
527                 return 0;
528         }
529         kfree(cb);
530         error(Ebadctl);
531         return -1;      /* not reached */
532 }
533
534 static struct ether *vlanalloc(struct ether *ether, int id)
535 {
536         ERRSTACK(1);
537         struct ether *vlan;
538         int i, fid;
539         char name[KNAMELEN];
540
541         qlock(&ether->vlq);
542         if (waserror()) {
543                 qunlock(&ether->vlq);
544                 nexterror();
545         }
546         fid = -1;
547         for (i = 0; i < ARRAY_SIZE(ether->vlans); i++) {
548                 vlan = ether->vlans[i];
549                 if (vlan != NULL && vlan->vlanid == id) {
550                         poperror();
551                         qunlock(&ether->vlq);
552                         return vlan;
553                 }
554                 if (fid < 0 && (vlan == NULL || vlan->vlanid == 0))
555                         fid = i;
556         }
557         if (fid < 0)
558                 error(Enoifc);
559         snprintf(name, sizeof(name), "ether%d.%d", ether->ctlrno, id);
560         vlan = ether->vlans[fid];
561         if (vlan == NULL) {
562                 vlan = kzmalloc(sizeof(struct ether), 1);
563                 if (vlan == NULL)
564                         error(Enovmem);
565                 rwinit(&vlan->rwlock);
566                 qlock_init(&vlan->vlq);
567                 netifinit(&vlan->netif, name, Ntypes, ether->netif.limit);
568                 ether->vlans[fid] = vlan;       /* id is still zero, can't be matched */
569                 ether->nvlan++;
570         } else
571                 memmove(vlan->netif.name, name, KNAMELEN - 1);
572         vlan->attach = nop;
573         vlan->transmit = NULL;
574         vlan->ctl = vlanctl;
575         vlan->irq = -1;
576         vlan->netif.promiscuous = ether->netif.promiscuous;
577         vlan->netif.multicast = ether->netif.multicast;
578         vlan->netif.arg = vlan;
579         vlan->netif.mbps = ether->netif.mbps;
580         vlan->fullduplex = ether->fullduplex;
581         vlan->encry = ether->encry;
582         vlan->minmtu = ether->minmtu;
583         vlan->maxmtu = ether->maxmtu;
584         vlan->ctlrno = ether->ctlrno;
585         vlan->vlanid = id;
586         vlan->netif.alen = Eaddrlen;
587         memmove(vlan->netif.addr, ether->netif.addr, sizeof(vlan->netif.addr));
588         memmove(vlan->netif.bcast, ether->netif.bcast, sizeof(ether->netif.bcast));
589         vlan->oq = NULL;
590         vlan->ctlr = ether;
591         vlan->vlanid = id;
592         poperror();
593         qunlock(&ether->vlq);
594         return vlan;
595 }
596
597 static struct {
598         char *type;
599         int (*reset) (struct ether *);
600 } cards[MaxEther + 1];
601
602 void addethercard(char *t, int (*r) (struct ether *))
603 {
604         static int ncard;
605
606         if (ncard == MaxEther)
607                 panic("too many ether cards");
608         cards[ncard].type = t;
609         cards[ncard].reset = r;
610         ncard++;
611 }
612
613 int parseether(uint8_t * to, char *from)
614 {
615         char nip[4];
616         char *p;
617         int i;
618
619         p = from;
620         for (i = 0; i < Eaddrlen; i++) {
621                 if (*p == 0)
622                         return -1;
623                 nip[0] = *p++;
624                 if (*p == 0)
625                         return -1;
626                 nip[1] = *p++;
627                 nip[2] = 0;
628                 to[i] = strtoul(nip, 0, 16);
629                 if (*p == ':')
630                         p++;
631         }
632         return 0;
633 }
634
635 static void etherreset(void)
636 {
637         struct ether *ether;
638         int i, n, ctlrno, qsize;
639         char name[KNAMELEN], buf[128];
640
641         for (ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++) {
642                 if (ether == 0)
643                         ether = kzmalloc(sizeof(struct ether), 0);
644                 memset(ether, 0, sizeof(struct ether));
645                 rwinit(&ether->rwlock);
646                 qlock_init(&ether->vlq);
647                 ether->ctlrno = ctlrno;
648                 ether->netif.mbps = 10;
649                 ether->minmtu = ETHERMINTU;
650                 ether->maxmtu = ETHERMAXTU;
651                 /* looked like irq type, we don't have these yet */
652                 //ether->netif.itype = -1;
653
654                 /* TODO: looks like they expected some init to be done here.  at the
655                  * very least, ether->type is 0 right now, and needs to be set.  looking
656                  * around online, it seems to find out ether config settings, so that we
657                  * can set some flags in the opt parseing below. */
658                 //if(archether(ctlrno, ether) <= 0)
659                 //  continue;
660
661                 for (n = 0; cards[n].type; n++) {
662 #if 0
663                         if (cistrcmp(cards[n].type, ether->type))
664                                 continue;
665                         for (i = 0; i < ether->nopt; i++) {
666                                 if (cistrncmp(ether->opt[i], "ea=", 3) == 0) {
667                                         if (parseether(ether->ea, &ether->opt[i][3]) == -1)
668                                                 memset(ether->ea, 0, Eaddrlen);
669                                 } else if (cistrcmp(ether->opt[i], "fullduplex") == 0 ||
670                                                    cistrcmp(ether->opt[i], "10BASE-TFD") == 0)
671                                         ether->fullduplex = 1;
672                                 else if (cistrcmp(ether->opt[i], "100BASE-TXFD") == 0)
673                                         ether->mbps = 100;
674                         }
675 #endif
676                         if (cards[n].reset(ether))
677                                 continue;
678                         /* might be fucked a bit - reset() doesn't know the type.  might not
679                          * even matter, except for debugging. */
680                         ether->type = cards[n].type;
681                         snprintf(name, sizeof(name), "ether%d", ctlrno);
682
683                         i = snprintf(buf, sizeof(buf),
684                                                  "#l%d: %s: %dMbps port 0x%x irq %u", ctlrno,
685                                                  ether->type, ether->netif.mbps, ether->port,
686                                                  ether->irq);
687                         /* Looks like this is for printing MMIO addrs */
688 #if 0
689                         if (ether->mem)
690                                 i += snprintf(buf + i, sizeof(buf) - i, " addr 0x%lx",
691                                                           PADDR(ether->mem));
692                         if (ether->size)
693                                 i += snprintf(buf + i, sizeof(buf) - i, " size 0x%lx",
694                                                           ether->size);
695 #endif
696                         i += snprintf(buf + i, sizeof(buf) - i,
697                                                   ": %02.2x:%02.2x:%02.2x:%02.2x:%02.2x:%02.2x",
698                                                   ether->ea[0], ether->ea[1], ether->ea[2],
699                                                   ether->ea[3], ether->ea[4], ether->ea[5]);
700                         snprintf(buf + i, sizeof(buf) - i, "\n");
701                         printk(buf);
702
703                         switch (ether->netif.mbps) {
704
705                         case 1 ... 99:
706                                 qsize = 64 * 1024;
707                                 break;
708                         case 100 ... 999:
709                                 qsize = 256 * 1024;
710                                 break;
711                         case 1000 ... 9999:
712                                 qsize = 1024 * 1024;
713                                 break;
714                         default:
715                                 qsize = 8 * 1024 * 1024;
716                         }
717                         netifinit(&ether->netif, name, Ntypes, qsize);
718                         if (ether->oq == 0)
719                                 ether->oq = qopen(qsize, Qmsg, 0, 0);
720                         if (ether->oq == 0)
721                                 panic("etherreset %s", name);
722                         ether->netif.alen = Eaddrlen;
723                         memmove(ether->netif.addr, ether->ea, Eaddrlen);
724                         memset(ether->netif.bcast, 0xFF, Eaddrlen);
725
726                         etherxx[ctlrno] = ether;
727                         ether = 0;
728                         break;
729                 }
730         }
731         if (ether)
732                 kfree(ether);
733 }
734
735 static void etherpower(int on)
736 {
737         int i;
738         struct ether *ether;
739
740         /* TODO: fix etherpower.  locking and ether->readers are broken. */
741         warn("%s needs attention.  had a rough porting from inferno", __FUNCTION__);
742         for (i = 0; i < MaxEther; i++) {
743                 if ((ether = etherxx[i]) == NULL || ether->power == NULL)
744                         continue;
745                 if (on) {
746                         /* brho: not sure what they are doing.  there seem to be certain
747                          * assumptions about calling etherpower.  i think they are using
748                          * canrlock to see if the lock is currently writelocked.  and if it
749                          * was not lockable, they would assume they had the write lock and
750                          * could unlock.  this is super fucked up. */
751                         if (canrlock(&ether->rwlock)) {
752                                 runlock(&ether->rwlock);        // brho added this
753                                 continue;
754                         }
755                         if (ether->power != NULL)
756                                 ether->power(ether, on);
757                         wunlock(&ether->rwlock);
758                 } else {
759                         /* readers isn't in the ether struct...
760                            if(ether->readers)
761                            continue;
762                          */
763                         wlock(&ether->rwlock);
764                         if (ether->power != NULL)
765                                 ether->power(ether, on);
766                         /* Keep locked until power goes back on */
767                 }
768         }
769 }
770
771 #define ETHERPOLY 0xedb88320
772
773 /* really slow 32 bit crc for ethers */
774 uint32_t ethercrc(uint8_t * p, int len)
775 {
776         int i, j;
777         uint32_t crc, b;
778
779         crc = 0xffffffff;
780         for (i = 0; i < len; i++) {
781                 b = *p++;
782                 for (j = 0; j < 8; j++) {
783                         crc = (crc >> 1) ^ (((crc ^ b) & 1) ? ETHERPOLY : 0);
784                         b >>= 1;
785                 }
786         }
787         return crc;
788 }
789
790 struct dev etherdevtab __devtab = {
791         'l',
792         "ether",
793
794         etherreset,
795         devinit,
796         ethershutdown,
797         etherattach,
798         etherwalk,
799         etherstat,
800         etheropen,
801         devcreate,
802         etherclose,
803         etherread,
804         etherbread,
805         etherwrite,
806         etherbwrite,
807         devremove,
808         etherwstat,
809         etherpower,
810         devchaninfo,
811 };