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