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