]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/bitsy/devether.c
merge
[plan9front.git] / sys / src / 9 / bitsy / devether.c
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "io.h"
7 #include "ureg.h"
8 #include "../port/error.h"
9 #include "../port/netif.h"
10
11 #include "etherif.h"
12
13 static volatile Ether *etherxx[MaxEther];
14
15 static struct {
16         char*   type;
17         int     (*reset)(Ether*);
18 } cards[MaxEther+1];
19
20 void
21 addethercard(char* t, int (*r)(Ether*))
22 {
23         static int ncard;
24
25         if(ncard == MaxEther)
26                 panic("too many ether cards");
27         cards[ncard].type = t;
28         cards[ncard].reset = r;
29         ncard++;
30 }
31
32 void
33 etherpower(int on)
34 {
35         int i;
36         Ether *ether;
37         /* Power all ether cards on or off */
38
39 iprint("etherpower %d\n", on);
40         for (i = 0; i < MaxEther; i++){
41                 if ((ether = etherxx[i]) == nil)
42                         continue;
43                 if(on){
44                         if (ether->writer == 0){
45                                 print("etherpower: already powered up\n");
46                                 continue;
47                         }
48                         if (ether->power)
49                                 ether->power(ether, on);
50                         wunlock(ether);
51                         /* Unlock when power restored */
52                 }else{
53                         if (ether->writer != 0){
54                                 print("etherpower: already powered down\n");
55                                 continue;
56                         }
57                         /* Keep locked until power goes back on */
58                         wlock(ether);
59                         if (ether->power)
60                                 ether->power(ether, on);
61                 }
62         }
63 }
64
65 int
66 etherconfig(int on, char *spec, DevConf *cf)
67 {
68         Ether *ether;
69         int n, ctlrno;
70         char name[32], buf[128];
71         char *p, *e;
72
73         ctlrno = atoi(spec);
74         sprint(name, "ether%d", ctlrno);
75
76         if(on == 0)
77                 return -1;
78
79         if(etherxx[ctlrno] != nil)
80                 return -1;
81
82         ether = malloc(sizeof(Ether));
83         if(ether == nil)
84                 panic("etherconfig");
85         ether->DevConf = *cf;
86
87         for(n = 0; cards[n].type; n++){
88                 if(strcmp(cards[n].type, ether->type) != 0)
89                         continue;
90                 if(cards[n].reset(ether))
91                         break;
92
93                 if(ether->mbps >= 100){
94                         netifinit(ether, name, Ntypes, 256*1024);
95                         if(ether->oq == 0)
96                                 ether->oq = qopen(256*1024, Qmsg, 0, 0);
97                 }
98                 else{
99                         netifinit(ether, name, Ntypes, 65*1024);
100                         if(ether->oq == 0)
101                                 ether->oq = qopen(65*1024, Qmsg, 0, 0);
102                 }
103                 if(ether->oq == 0)
104                         panic("etherreset %s", name);
105                 ether->alen = Eaddrlen;
106                 memmove(ether->addr, ether->ea, Eaddrlen);
107                 memset(ether->bcast, 0xFF, Eaddrlen);
108                 ether->mbps = 10;
109                 ether->minmtu = ETHERMINTU;
110                 ether->maxmtu = ETHERMAXTU;
111
112                 if(ether->interrupt != nil)
113                         intrenable(cf->itype, cf->intnum, ether->interrupt, ether, name);
114
115                 p = buf;
116                 e = buf+sizeof(buf);
117                 p = seprint(p, e, "#l%d: %s: %dMbps port 0x%luX",
118                         ctlrno, ether->type, ether->mbps, ether->ports[0].port);
119                 if(ether->mem)
120                         p = seprint(p, e, " addr 0x%luX", PADDR(ether->mem));
121                 if(ether->ports[0].size)
122                         p = seprint(p, e, " size 0x%X", ether->ports[0].size);
123                 p = seprint(p, e, ": %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
124                         ether->ea[0], ether->ea[1], ether->ea[2],
125                         ether->ea[3], ether->ea[4], ether->ea[5]);
126                 seprint(p, e, "\n");
127                 pprint(buf);
128
129                 etherxx[ctlrno] = ether;
130                 return 0;
131         }
132
133         if (ether->type)
134                 free(ether->type);
135         free(ether);
136         return -1;
137 }
138
139 Chan*
140 etherattach(char* spec)
141 {
142         ulong ctlrno;
143         char *p;
144         Chan *chan;
145         Ether *ether;
146
147         ctlrno = 0;
148         if(spec && *spec){
149                 ctlrno = strtoul(spec, &p, 0);
150                 if((ctlrno == 0 && p == spec) || *p || (ctlrno >= MaxEther))
151                         error(Ebadarg);
152         }
153         if((ether = etherxx[ctlrno]) == 0)
154                 error(Enodev);
155         rlock(ether);
156         if(waserror()) {
157                 runlock(ether);
158                 nexterror();
159         }
160         chan = devattach('l', spec);
161         chan->dev = ctlrno;
162         if(ether->attach)
163                 ether->attach(ether);
164         poperror();
165         runlock(ether);
166         return chan;
167 }
168
169 static Walkqid*
170 etherwalk(Chan* chan, Chan* nchan, char** name, int nname)
171 {
172         Walkqid *q;
173         Ether *ether;
174
175         ether = etherxx[chan->dev];
176         rlock(ether);
177         if(waserror()) {
178                 runlock(ether);
179                 nexterror();
180         }
181         q = netifwalk(ether, chan, nchan, name, nname);
182         poperror();
183         runlock(ether);
184         return q;
185 }
186
187 static int
188 etherstat(Chan* chan, uchar* dp, int n)
189 {
190         int s;
191         Ether *ether;
192
193         ether = etherxx[chan->dev];
194         rlock(ether);
195         if(waserror()) {
196                 runlock(ether);
197                 nexterror();
198         }
199         s = netifstat(ether, chan, dp, n);
200         poperror();
201         runlock(ether);
202         return s;
203 }
204
205 static Chan*
206 etheropen(Chan* chan, int omode)
207 {
208         Chan *c;
209         Ether *ether;
210
211         ether = etherxx[chan->dev];
212         rlock(ether);
213         if(waserror()) {
214                 runlock(ether);
215                 nexterror();
216         }
217         c = netifopen(ether, chan, omode);
218         poperror();
219         runlock(ether);
220         return c;
221 }
222
223 static void
224 ethercreate(Chan*, char*, int, ulong)
225 {
226 }
227
228 static void
229 etherclose(Chan* chan)
230 {
231         Ether *ether;
232
233         ether = etherxx[chan->dev];
234         rlock(ether);
235         if(waserror()) {
236                 runlock(ether);
237                 nexterror();
238         }
239         netifclose(ether, chan);
240         poperror();
241         runlock(ether);
242 }
243
244 static long
245 etherread(Chan* chan, void* buf, long n, vlong off)
246 {
247         Ether *ether;
248         ulong offset = off;
249         long r;
250
251         ether = etherxx[chan->dev];
252         rlock(ether);
253         if(waserror()) {
254                 runlock(ether);
255                 nexterror();
256         }
257         if((chan->qid.type & QTDIR) == 0 && ether->ifstat){
258                 /*
259                  * With some controllers it is necessary to reach
260                  * into the chip to extract statistics.
261                  */
262                 if(NETTYPE(chan->qid.path) == Nifstatqid){
263                         r = ether->ifstat(ether, buf, n, offset);
264                         goto out;
265                 }
266                 if(NETTYPE(chan->qid.path) == Nstatqid)
267                         ether->ifstat(ether, buf, 0, offset);
268         }
269         r = netifread(ether, chan, buf, n, offset);
270 out:
271         poperror();
272         runlock(ether);
273         return r;
274 }
275
276 static Block*
277 etherbread(Chan* chan, long n, ulong offset)
278 {
279         Block *b;
280         Ether *ether;
281
282         ether = etherxx[chan->dev];
283         rlock(ether);
284         if(waserror()) {
285                 runlock(ether);
286                 nexterror();
287         }
288         b = netifbread(ether, chan, n, offset);
289         poperror();
290         runlock(ether);
291         return b;
292 }
293
294 static int
295 etherwstat(Chan* chan, uchar* dp, int n)
296 {
297         Ether *ether;
298         int r;
299
300         ether = etherxx[chan->dev];
301         rlock(ether);
302         if(waserror()) {
303                 runlock(ether);
304                 nexterror();
305         }
306         r = netifwstat(ether, chan, dp, n);
307         poperror();
308         runlock(ether);
309         return r;
310 }
311
312 static void
313 etherrtrace(Netfile* f, Etherpkt* pkt, int len)
314 {
315         int i, n;
316         Block *bp;
317
318         if(qwindow(f->in) <= 0)
319                 return;
320         if(len > 58)
321                 n = 58;
322         else
323                 n = len;
324         bp = iallocb(64);
325         if(bp == nil)
326                 return;
327         memmove(bp->wp, pkt->d, n);
328         i = TK2MS(MACHP(0)->ticks);
329         bp->wp[58] = len>>8;
330         bp->wp[59] = len;
331         bp->wp[60] = i>>24;
332         bp->wp[61] = i>>16;
333         bp->wp[62] = i>>8;
334         bp->wp[63] = i;
335         bp->wp += 64;
336         qpass(f->in, bp);
337 }
338
339 Block*
340 etheriq(Ether* ether, Block* bp, int fromwire)
341 {
342         Etherpkt *pkt;
343         ushort type;
344         int len, multi, tome, fromme;
345         Netfile **ep, *f, **fp, *fx;
346         Block *xbp;
347
348         ether->inpackets++;
349
350         pkt = (Etherpkt*)bp->rp;
351         len = BLEN(bp);
352         type = (pkt->type[0]<<8)|pkt->type[1];
353         fx = 0;
354         ep = &ether->f[Ntypes];
355
356         multi = pkt->d[0] & 1;
357         /* check for valid multicast addresses */
358         if(multi && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) && ether->prom == 0){
359                 if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
360                         if(fromwire){
361                                 freeb(bp);
362                                 bp = 0;
363                         }
364                         return bp;
365                 }
366         }
367
368         /* is it for me? */
369         tome = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
370         fromme = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0;
371
372         /*
373          * Multiplex the packet to all the connections which want it.
374          * If the packet is not to be used subsequently (fromwire != 0),
375          * attempt to simply pass it into one of the connections, thereby
376          * saving a copy of the data (usual case hopefully).
377          */
378         for(fp = ether->f; fp < ep; fp++){
379                 if(f = *fp)
380                 if(f->type == type || f->type < 0)
381                 if(tome || multi || f->prom){
382                         /* Don't want to hear bridged packets */
383                         if(f->bridge && !fromwire && !fromme)
384                                 continue;
385                         if(!f->headersonly){
386                                 if(fromwire && fx == 0)
387                                         fx = f;
388                                 else if(xbp = iallocb(len)){
389                                         memmove(xbp->wp, pkt, len);
390                                         xbp->wp += len;
391                                         qpass(f->in, xbp);
392                                 }
393                                 else
394                                         ether->soverflows++;
395                         }
396                         else
397                                 etherrtrace(f, pkt, len);
398                 }
399         }
400
401         if(fx){
402                 if(qpass(fx->in, bp) < 0)
403                         ether->soverflows++;
404                 return 0;
405         }
406         if(fromwire){
407                 freeb(bp);
408                 return 0;
409         }
410
411         return bp;
412 }
413
414 static int
415 etheroq(Ether* ether, Block* bp)
416 {
417         int len, loopback, s;
418         Etherpkt *pkt;
419
420         ether->outpackets++;
421
422         /*
423          * Check if the packet has to be placed back onto the input queue,
424          * i.e. if it's a loopback or broadcast packet or the interface is
425          * in promiscuous mode.
426          * If it's a loopback packet indicate to etheriq that the data isn't
427          * needed and return, etheriq will pass-on or free the block.
428          * To enable bridging to work, only packets that were originated
429          * by this interface are fed back.
430          */
431         pkt = (Etherpkt*)bp->rp;
432         len = BLEN(bp);
433         loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
434         if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom){
435                 s = splhi();
436                 etheriq(ether, bp, 0);
437                 splx(s);
438         }
439
440         if(!loopback){
441                 qbwrite(ether->oq, bp);
442                 ether->transmit(ether);
443         } else
444                 freeb(bp);
445
446         return len;
447 }
448
449 static long
450 etherwrite(Chan* chan, void* buf, long n, vlong)
451 {
452         Ether *ether;
453         Block *bp;
454         long l;
455
456         ether = etherxx[chan->dev];
457         rlock(ether);
458         if(waserror()) {
459                 runlock(ether);
460                 nexterror();
461         }
462         if(NETTYPE(chan->qid.path) != Ndataqid) {
463                 l = netifwrite(ether, chan, buf, n);
464                 if(l >= 0)
465                         goto out;
466                 if(n == sizeof("nonblocking")-1 && strncmp((char*)buf, "nonblocking", n) == 0){
467                         qnoblock(ether->oq, 1);
468                         goto out;
469                 }
470                 if(ether->ctl!=nil){
471                         l = ether->ctl(ether,buf,n);
472                         goto out;
473                 }
474                 error(Ebadctl);
475         }
476
477         if(n > ether->maxmtu)
478                 error(Etoobig);
479         if(n < ether->minmtu)
480                 error(Etoosmall);
481         bp = allocb(n);
482         memmove(bp->rp, buf, n);
483         memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
484         bp->wp += n;
485
486         l = etheroq(ether, bp);
487 out:
488         poperror();
489         runlock(ether);
490         return l;
491 }
492
493 static long
494 etherbwrite(Chan* chan, Block* bp, ulong)
495 {
496         Ether *ether;
497         long n;
498
499         n = BLEN(bp);
500         if(NETTYPE(chan->qid.path) != Ndataqid){
501                 if(waserror()) {
502                         freeb(bp);
503                         nexterror();
504                 }
505                 n = etherwrite(chan, bp->rp, n, 0);
506                 poperror();
507                 freeb(bp);
508                 return n;
509         }
510         ether = etherxx[chan->dev];
511         rlock(ether);
512         if(waserror()) {
513                 runlock(ether);
514                 nexterror();
515         }
516         if(n > ether->maxmtu){
517                 freeb(bp);
518                 error(Etoobig);
519         }
520         if(n < ether->minmtu){
521                 freeb(bp);
522                 error(Etoosmall);
523         }
524         n = etheroq(ether, bp);
525         poperror();
526         runlock(ether);
527         return n;
528 }
529
530 int
531 parseether(uchar *to, char *from)
532 {
533         char nip[4];
534         char *p;
535         int i;
536
537         p = from;
538         for(i = 0; i < 6; i++){
539                 if(*p == 0)
540                         return -1;
541                 nip[0] = *p++;
542                 if(*p == 0)
543                         return -1;
544                 nip[1] = *p++;
545                 nip[2] = 0;
546                 to[i] = strtoul(nip, 0, 16);
547                 if(*p == ':')
548                         p++;
549         }
550         return 0;
551 }
552
553 static void
554 etherreset(void)
555 {
556 }
557
558 #define POLY 0xedb88320
559
560 /* really slow 32 bit crc for ethers */
561 ulong
562 ethercrc(uchar *p, int len)
563 {
564         int i, j;
565         ulong crc, b;
566
567         crc = 0xffffffff;
568         for(i = 0; i < len; i++){
569                 b = *p++;
570                 for(j = 0; j < 8; j++){
571                         crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0);
572                         b >>= 1;
573                 }
574         }
575         return crc;
576 }
577
578 Dev etherdevtab = {
579         'l',
580         "ether",
581
582         etherreset,
583         devinit,
584         devshutdown,
585         etherattach,
586         etherwalk,
587         etherstat,
588         etheropen,
589         ethercreate,
590         etherclose,
591         etherread,
592         etherbread,
593         etherwrite,
594         etherbwrite,
595         devremove,
596         etherwstat,
597         etherpower,
598         etherconfig,
599 };