]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/port/devether.c
kernel: massive pci code rewrite
[plan9front.git] / sys / src / 9 / port / 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 "pool.h"
8 #include "ureg.h"
9 #include "../port/error.h"
10 #include "../port/netif.h"
11 #include "../port/etherif.h"
12
13 extern int eipfmt(Fmt*);
14 extern ushort ipcsum(uchar *);
15
16 static Ether *etherxx[MaxEther];
17 static Ether *etherprobe(int cardno, int ctlrno, char *conf);
18
19 Chan*
20 etherattach(char* spec)
21 {
22         ulong ctlrno;
23         char *conf;
24         Chan *chan;
25
26         ctlrno = 0;
27         if(*spec){
28                 ctlrno = strtoul(spec, &conf, 10);
29                 if(ctlrno >= MaxEther)
30                         error(Enodev);
31                 if(conf == spec)
32                         error(Ebadspec);
33                 if(*conf){
34                         if(*conf != ':')
35                                 error(Ebadspec);
36                         *conf++ = 0;
37                         if(!iseve())
38                                 error(Enoattach);
39                         if(etherxx[ctlrno] != nil)
40                                 error(Einuse);
41                         etherxx[ctlrno] = etherprobe(-1, ctlrno, conf);
42                 }
43         }
44         if(etherxx[ctlrno] == nil)
45                 error(Enodev);
46         chan = devattach('l', spec);
47         if(waserror()){
48                 chanfree(chan);
49                 nexterror();
50         }
51         chan->dev = ctlrno;
52         if(etherxx[ctlrno]->attach)
53                 etherxx[ctlrno]->attach(etherxx[ctlrno]);
54         poperror();
55         return chan;
56 }
57
58 static Walkqid*
59 etherwalk(Chan* chan, Chan* nchan, char** name, int nname)
60 {
61         return netifwalk(etherxx[chan->dev], chan, nchan, name, nname);
62 }
63
64 static int
65 etherstat(Chan* chan, uchar* dp, int n)
66 {
67         return netifstat(etherxx[chan->dev], chan, dp, n);
68 }
69
70 static Chan*
71 etheropen(Chan* chan, int omode)
72 {
73         return netifopen(etherxx[chan->dev], chan, omode);
74 }
75
76 static Chan*
77 ethercreate(Chan*, char*, int, ulong)
78 {
79         error(Eperm);
80         return 0;
81 }
82
83 static void
84 etherclose(Chan* chan)
85 {
86         Ether *ether = etherxx[chan->dev];
87
88         if(NETTYPE(chan->qid.path) == Ndataqid && ether->f[NETID(chan->qid.path)]->bridge)
89                 memset(ether->mactab, 0, sizeof(ether->mactab));
90
91         netifclose(ether, chan);
92 }
93
94 static long
95 etherread(Chan* chan, void* buf, long n, vlong off)
96 {
97         Ether *ether;
98         ulong offset = off;
99
100         ether = etherxx[chan->dev];
101         if((chan->qid.type & QTDIR) == 0 && ether->ifstat){
102                 /*
103                  * With some controllers it is necessary to reach
104                  * into the chip to extract statistics.
105                  */
106                 if(NETTYPE(chan->qid.path) == Nifstatqid)
107                         return ether->ifstat(ether, buf, n, offset);
108                 else if(NETTYPE(chan->qid.path) == Nstatqid)
109                         ether->ifstat(ether, buf, 0, offset);
110         }
111
112         return netifread(ether, chan, buf, n, offset);
113 }
114
115 static Block*
116 etherbread(Chan* chan, long n, ulong offset)
117 {
118         return netifbread(etherxx[chan->dev], chan, n, offset);
119 }
120
121 static int
122 etherwstat(Chan* chan, uchar* dp, int n)
123 {
124         return netifwstat(etherxx[chan->dev], chan, dp, n);
125 }
126
127 static void
128 etherrtrace(Netfile* f, Etherpkt* pkt, int len)
129 {
130         Block *bp;
131
132         if(qwindow(f->in) <= 0)
133                 return;
134         bp = iallocb(64);
135         if(bp == nil)
136                 return;
137         memmove(bp->wp, pkt, len < 64 ? len : 64);
138         if(f->type != -2){
139                 u32int ms = TK2MS(MACHP(0)->ticks);
140                 bp->wp[58] = len>>8;
141                 bp->wp[59] = len;
142                 bp->wp[60] = ms>>24;
143                 bp->wp[61] = ms>>16;
144                 bp->wp[62] = ms>>8;
145                 bp->wp[63] = ms;
146         }
147         bp->wp += 64;
148         qpass(f->in, bp);
149 }
150
151 static Macent*
152 macent(Ether *ether, uchar *ea)
153 {
154         u32int h = (ea[0] | ea[1]<<8 | ea[2]<<16 | ea[3]<<24) ^ (ea[4] | ea[5]<<8);
155         return &ether->mactab[h % nelem(ether->mactab)];
156 }
157
158 /*
159  * Multiplex the packet to all the connections which want it.
160  * If the packet is not to be used subsequently (tome || from == nil),
161  * attempt to simply pass it into one of the connections, thereby
162  * saving a copy of the data (usual case hopefully).
163  */
164 static Block*
165 ethermux(Ether *ether, Block *bp, Netfile **from)
166 {
167         Block *xbp;
168         Etherpkt *pkt;
169         Netfile *f, *x, **fp;
170         int len, multi, tome, port, type, dispose;
171
172         len = BLEN(bp);
173         if(len < ETHERHDRSIZE)
174                 goto Drop;
175         pkt = (Etherpkt*)bp->rp;
176         if(!(multi = pkt->d[0] & 1)){
177                 tome = memcmp(pkt->d, ether->ea, Eaddrlen) == 0;
178                 if(!tome && from != nil && ether->prom == 0)
179                         return bp;
180         } else {
181                 tome = 0;
182                 if(from == nil && ether->prom == 0
183                 && memcmp(pkt->d, ether->bcast, Eaddrlen) != 0
184                 && !activemulti(ether, pkt->d, Eaddrlen))
185                         goto Drop;
186         }
187
188         port = -1;
189         if(ether->prom){
190                 if((from == nil || (*from)->bridge) && (pkt->s[0] & 1) == 0){
191                         Macent *t = macent(ether, pkt->s);
192                         t->port = from == nil ? 0 : 1+(from - ether->f);
193                         memmove(t->ea, pkt->s, Eaddrlen);
194                 }
195                 if(!tome && !multi){
196                         Macent *t = macent(ether, pkt->d);
197                         if(memcmp(t->ea, pkt->d, Eaddrlen) == 0)
198                                 port = t->port;
199                 }
200         }
201
202         x = nil;
203         type = (pkt->type[0]<<8)|pkt->type[1];
204         dispose = tome || from == nil || port > 0;
205
206         for(fp = ether->f; fp < &ether->f[Ntypes]; fp++){
207                 if((f = *fp) == nil)
208                         continue;
209                 if(f->type != type && f->type >= 0)
210                         continue;
211                 if(!tome && !multi && !f->prom)
212                         continue;
213                 if(f->bridge){
214                         if(tome || fp == from)
215                                 continue;
216                         if(port >= 0 && port != 1+(fp - ether->f))
217                                 continue;
218                 }
219                 if(f->headersonly || f->type == -2){
220                         etherrtrace(f, pkt, len);
221                         continue;
222                 }
223                 if(dispose && x == nil)
224                         x = f;
225                 else if((xbp = iallocb(len)) != nil){
226                         memmove(xbp->wp, pkt, len);
227                         xbp->wp += len;
228                         xbp->flag = bp->flag;
229                         if(qpass(f->in, xbp) < 0)
230                                 ether->soverflows++;
231                 } else
232                         ether->soverflows++;
233         }
234         if(x != nil){
235                 if(qpass(x->in, bp) < 0)
236                         ether->soverflows++;
237                 return nil;
238         }
239
240         if(dispose){
241 Drop:           freeb(bp);
242                 return nil;
243         }
244         return bp;
245 }
246
247 void
248 etheriq(Ether* ether, Block* bp)
249 {
250         ether->inpackets++;
251         ethermux(ether, bp, nil);
252 }
253
254 static void
255 etheroq(Ether* ether, Block* bp, Netfile **from)
256 {
257         if((*from)->bridge == 0)
258                 memmove(((Etherpkt*)bp->rp)->s, ether->ea, Eaddrlen);
259
260         bp = ethermux(ether, bp, from);
261         if(bp == nil)
262                 return;
263
264         ether->outpackets++;
265         qbwrite(ether->oq, bp);
266         if(ether->transmit != nil)
267                 ether->transmit(ether);
268 }
269
270 static long
271 etherwrite(Chan* chan, void* buf, long n, vlong)
272 {
273         Ether *ether = etherxx[chan->dev];
274         Block *bp;
275         int nn, onoff;
276         Cmdbuf *cb;
277
278         if(NETTYPE(chan->qid.path) != Ndataqid) {
279                 nn = netifwrite(ether, chan, buf, n);
280                 if(nn >= 0)
281                         return nn;
282                 cb = parsecmd(buf, n);
283                 if(cb->f[0] && strcmp(cb->f[0], "nonblocking") == 0){
284                         if(cb->nf <= 1)
285                                 onoff = 1;
286                         else
287                                 onoff = atoi(cb->f[1]);
288                         qnoblock(ether->oq, onoff);
289                         free(cb);
290                         return n;
291                 }
292                 free(cb);
293                 if(ether->ctl!=nil)
294                         return ether->ctl(ether,buf,n);
295
296                 error(Ebadctl);
297         }
298
299         if(n > ether->maxmtu)
300                 error(Etoobig);
301         if(n < ether->minmtu)
302                 error(Etoosmall);
303
304         bp = allocb(n);
305         if(waserror()){
306                 freeb(bp);
307                 nexterror();
308         }
309         memmove(bp->rp, buf, n);
310         poperror();
311         bp->wp += n;
312
313         etheroq(ether, bp, &ether->f[NETID(chan->qid.path)]);
314         return n;
315 }
316
317 static long
318 etherbwrite(Chan* chan, Block* bp, ulong)
319 {
320         Ether *ether;
321         long n = BLEN(bp);
322
323         if(NETTYPE(chan->qid.path) != Ndataqid){
324                 if(waserror()) {
325                         freeb(bp);
326                         nexterror();
327                 }
328                 n = etherwrite(chan, bp->rp, n, 0);
329                 poperror();
330                 freeb(bp);
331                 return n;
332         }
333
334         ether = etherxx[chan->dev];
335         if(n > ether->maxmtu){
336                 freeb(bp);
337                 error(Etoobig);
338         }
339         if(n < ether->minmtu){
340                 freeb(bp);
341                 error(Etoosmall);
342         }
343         etheroq(ether, bp, &ether->f[NETID(chan->qid.path)]);
344         return n;
345 }
346
347 static struct {
348         char*   type;
349         int     (*reset)(Ether*);
350 } cards[MaxEther+1];
351
352 void
353 addethercard(char* t, int (*r)(Ether*))
354 {
355         static int ncard;
356
357         if(ncard == MaxEther)
358                 panic("too many ether cards");
359         cards[ncard].type = t;
360         cards[ncard].reset = r;
361         ncard++;
362 }
363
364 static Ether*
365 etherprobe(int cardno, int ctlrno, char *conf)
366 {
367         int i, lg;
368         ulong mb, bsz;
369         Ether *ether;
370
371         ether = malloc(sizeof(Ether));
372         if(ether == nil){
373                 print("etherprobe: no memory for Ether\n");
374                 return nil;
375         }
376         memset(ether, 0, sizeof(Ether));
377         ether->tbdf = BUSUNKNOWN;
378         ether->irq = -1;
379         ether->ctlrno = ctlrno;
380         ether->mbps = 10;
381         ether->minmtu = ETHERMINTU;
382         ether->maxmtu = ETHERMAXTU;
383
384         if(cardno < 0){
385                 if(conf != nil){
386                         kstrdup(&ether->type, conf);
387                         ether->nopt = tokenize(ether->type, ether->opt, nelem(ether->opt));
388                         if(ether->nopt < 1)
389                                 goto Nope;
390                         memmove(&ether->opt[0], &ether->opt[1], --ether->nopt*sizeof(ether->opt[0]));
391                 } else if(isaconfig("ether", ctlrno, ether) == 0)
392                         goto Nope;
393
394                 for(cardno = 0; cards[cardno].type != nil; cardno++)
395                         if(cistrcmp(cards[cardno].type, ether->type) == 0)
396                                 break;
397                 if(cards[cardno].type == nil)
398                         goto Nope;
399
400                 for(i = 0; i < ether->nopt; i++){
401                         if(strncmp(ether->opt[i], "ea=", 3) == 0){
402                                 if(parseether(ether->ea, &ether->opt[i][3]))
403                                         memset(ether->ea, 0, Eaddrlen);
404                         }
405                 }
406         }
407         if(cardno >= MaxEther || cards[cardno].type == nil)
408                 goto Nope;
409         snprint(ether->name, sizeof(ether->name), "ether%d", ctlrno);
410         if(cards[cardno].reset(ether) < 0){
411 Nope:
412                 if(conf != nil) free(ether->type);      /* see kstrdup() above */
413                 free(ether);
414                 return nil;
415         }
416         ether->type = cards[cardno].type;
417
418         print("#l%d: %s: %dMbps port 0x%lluX irq %d ea %E\n",
419                 ctlrno, ether->type, ether->mbps, (uvlong)ether->port, ether->irq, ether->ea);
420
421         /* compute log10(ether->mbps) into lg */
422         for(lg = 0, mb = ether->mbps; mb >= 10; lg++)
423                 mb /= 10;
424         if (lg > 0)
425                 lg--;
426         if (lg > 14)                    /* 2^(14+17) = 2³¹ */
427                 lg = 14;
428         /* allocate larger output queues for higher-speed interfaces */
429         bsz = 1UL << (lg + 17);         /* 2¹⁷ = 128K, bsz = 2ⁿ × 128K */
430         while (bsz > mainmem->maxsize / 8 && bsz > 128*1024)
431                 bsz /= 2;
432
433         netifinit(ether, ether->name, Ntypes, bsz);
434         if(ether->oq == nil) {
435                 ether->oq = qopen(bsz, Qmsg, 0, 0);
436                 ether->limit = bsz;
437         }
438         if(ether->oq == nil)
439                 panic("etherreset %s: can't allocate output queue of %ld bytes", ether->name, bsz);
440
441         ether->alen = Eaddrlen;
442         memmove(ether->addr, ether->ea, Eaddrlen);
443         memset(ether->bcast, 0xFF, Eaddrlen);
444
445         return ether;
446 }
447
448 static void netconsole(int);
449
450 static void
451 etherreset(void)
452 {
453         Ether *ether;
454         int cardno, ctlrno;
455
456         fmtinstall('E', eipfmt);
457
458         for(ctlrno = 0; ctlrno < MaxEther; ctlrno++){
459                 if((ether = etherprobe(-1, ctlrno, nil)) == nil)
460                         continue;
461                 etherxx[ctlrno] = ether;
462         }
463
464         if(getconf("*noetherprobe") == nil){
465                 cardno = ctlrno = 0;
466                 while(cards[cardno].type != nil && ctlrno < MaxEther){
467                         if(etherxx[ctlrno] != nil){
468                                 ctlrno++;
469                                 continue;
470                         }
471                         if((ether = etherprobe(cardno, ctlrno, nil)) == nil){
472                                 cardno++;
473                                 continue;
474                         }
475                         etherxx[ctlrno] = ether;
476                         ctlrno++;
477                 }
478         }
479
480         netconsole(1);
481 }
482
483 static void
484 ethershutdown(void)
485 {
486         Ether *ether;
487         int i;
488
489         netconsole(0);
490
491         for(i = 0; i < MaxEther; i++){
492                 ether = etherxx[i];
493                 if(ether == nil)
494                         continue;
495                 if(ether->shutdown == nil) {
496                         print("#l%d: no shutdown function\n", i);
497                         continue;
498                 }
499                 (*ether->shutdown)(ether);
500         }
501 }
502
503
504 #define POLY 0xedb88320
505
506 /* really slow 32 bit crc for ethers */
507 ulong
508 ethercrc(uchar *p, int len)
509 {
510         int i, j;
511         ulong crc, b;
512
513         crc = 0xffffffff;
514         for(i = 0; i < len; i++){
515                 b = *p++;
516                 for(j = 0; j < 8; j++){
517                         crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0);
518                         b >>= 1;
519                 }
520         }
521         return crc;
522 }
523
524 Dev etherdevtab = {
525         'l',
526         "ether",
527
528         etherreset,
529         devinit,
530         ethershutdown,
531         etherattach,
532         etherwalk,
533         etherstat,
534         etheropen,
535         ethercreate,
536         etherclose,
537         etherread,
538         etherbread,
539         etherwrite,
540         etherbwrite,
541         devremove,
542         etherwstat,
543 };
544
545 enum { PktHdr = 42 };
546 typedef struct Netconsole Netconsole;
547 struct Netconsole {
548         char buf[512];
549         int n;
550         Lock;
551         Ether *ether;
552 };
553 static Netconsole *netcons;
554
555 static void
556 netconsputc(Uart *, int c)
557 {
558         char *p;
559         u16int cs;
560
561         ilock(netcons);
562         netcons->buf[netcons->n++] = c;
563         if(c != '\n' && netcons->n < sizeof(netcons->buf)){
564                 iunlock(netcons);
565                 return;
566         }
567         p = netcons->buf;
568         p[16] = netcons->n - 14 >> 8;
569         p[17] = netcons->n - 14;
570         p[24] = 0;
571         p[25] = 0;
572         cs = ipcsum((uchar*) p + 14);
573         p[24] = cs >> 8;
574         p[25] = cs;
575         p[38] = netcons->n - 34 >> 8;
576         p[39] = netcons->n - 34;
577         memmove(p+Eaddrlen, netcons->ether->ea, Eaddrlen);
578         qiwrite(netcons->ether->oq, p, netcons->n);
579         netcons->n = PktHdr;
580         iunlock(netcons);
581         if(netcons->ether->transmit != nil)
582                 netcons->ether->transmit(netcons->ether);
583 }
584
585 static PhysUart netconsphys = { .putc = netconsputc };
586 static Uart netconsuart = { .phys = &netconsphys };
587
588 static void
589 netconsole(int on)
590 {
591         char *p;
592         char *r;
593         int i;
594         int srcport, devno, dstport;
595         u8int srcip[4], dstip[4];
596         u64int dstmac;
597         Netconsole *nc;
598
599         if(!on){
600                 if(consuart == &netconsuart)
601                         consuart = nil;
602                 return;
603         }
604
605         if((p = getconf("console")) == nil || strncmp(p, "net ", 4) != 0)
606                 return;
607
608         p += 4;
609         for(i = 0; i < 4; i++){
610                 srcip[i] = strtol(p, &r, 0);
611                 p = r + 1;
612                 if(i == 3) break;
613                 if(*r != '.') goto err;
614         }
615         if(*r == '!'){
616                 srcport = strtol(p, &r, 0);
617                 p = r + 1;
618         }else
619                 srcport = 6665;
620         if(*r == '/'){
621                 devno = strtol(p, &r, 0);
622                 p = r + 1;
623         }else
624                 devno = 0;
625         if(*r != ',') goto err;
626         for(i = 0; i < 4; i++){
627                 dstip[i] = strtol(p, &r, 0);
628                 p = r + 1;
629                 if(i == 3) break;
630                 if(*r != '.') goto err;
631         }
632         if(*r == '!'){
633                 dstport = strtol(p, &r, 0);
634                 p = r + 1;
635         }else
636                 dstport = 6666;
637         if(*r == '/'){
638                 dstmac = strtoull(p, &r, 16);
639                 if(r - p != 12) goto err;
640         }else
641                 dstmac = ((uvlong)-1) >> 16;
642         if(*r != 0) goto err;
643         
644         if(devno >= MaxEther || etherxx[devno] == nil){
645                 print("netconsole: no device #l%d\n", devno);
646                 return;
647         }
648         
649         nc = malloc(sizeof(Netconsole));
650         if(nc == nil){
651                 print("netconsole: out of memory");
652                 return;
653         }
654         memset(nc, 0, sizeof(Netconsole));
655         nc->ether = etherxx[devno];
656         
657         uchar header[PktHdr] = {
658                 /* 0 */ dstmac >> 40, dstmac >> 32, dstmac >> 24, dstmac >> 16, dstmac >> 8, dstmac >> 0,
659                 /* 6 */ 0, 0, 0, 0, 0, 0,
660                 /* 12 */ 0x08, 0x00,
661                 /* 14 */ 0x45, 0x00,
662                 /* 16 */ 0x00, 0x00, /* total length */
663                 /* 18 */ 0x00, 0x00, 0x00, 0x00,
664                 /* 22 */ 64, /* ttl */
665                 /* 23 */ 0x11, /* protocol */
666                 /* 24 */ 0x00, 0x00, /* checksum */
667                 /* 26 */ srcip[0], srcip[1], srcip[2], srcip[3],
668                 /* 30 */ dstip[0], dstip[1], dstip[2], dstip[3],
669                 /* 34 */ srcport >> 8, srcport, dstport >> 8, dstport,
670                 /* 38 */ 0x00, 0x00, /* length */
671                 /* 40 */ 0x00, 0x00 /* checksum */
672         };
673         
674         memmove(nc->buf, header, PktHdr);
675         nc->n = PktHdr;
676         
677         netcons = nc;
678         consuart = &netconsuart;
679         return;
680
681 err:
682         print("netconsole: invalid string %#q\n", getconf("console"));
683         print("netconsole: usage: srcip[!srcport][/srcdev],dstip[!dstport][/dstmac]\n");
684 }