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