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