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*
etherattach(char * spec)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*
etherwalk(Chan * chan,Chan * nchan,char ** name,int nname)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
etherstat(Chan * chan,uchar * dp,int n)53 etherstat(Chan* chan, uchar* dp, int n)
54 {
55 return netifstat(etherxx[chan->dev], chan, dp, n);
56 }
57
58 static Chan*
etheropen(Chan * chan,int omode)59 etheropen(Chan* chan, int omode)
60 {
61 return netifopen(etherxx[chan->dev], chan, omode);
62 }
63
64 static void
ethercreate(Chan *,char *,int,ulong)65 ethercreate(Chan*, char*, int, ulong)
66 {
67 }
68
69 static void
etherclose(Chan * chan)70 etherclose(Chan* chan)
71 {
72 netifclose(etherxx[chan->dev], chan);
73 }
74
75 static long
etherread(Chan * chan,void * buf,long n,vlong off)76 etherread(Chan* chan, void* buf, long n, vlong off)
77 {
78 Ether *ether;
79 ulong offset = off;
80
81 ether = etherxx[chan->dev];
82 if((chan->qid.type & QTDIR) == 0 && ether->ifstat){
83 /*
84 * With some controllers it is necessary to reach
85 * into the chip to extract statistics.
86 */
87 if(NETTYPE(chan->qid.path) == Nifstatqid)
88 return ether->ifstat(ether, buf, n, offset);
89 else if(NETTYPE(chan->qid.path) == Nstatqid)
90 ether->ifstat(ether, buf, 0, offset);
91 }
92
93 return netifread(ether, chan, buf, n, offset);
94 }
95
96 static Block*
etherbread(Chan * chan,long n,ulong offset)97 etherbread(Chan* chan, long n, ulong offset)
98 {
99 return netifbread(etherxx[chan->dev], chan, n, offset);
100 }
101
102 static int
etherwstat(Chan * chan,uchar * dp,int n)103 etherwstat(Chan* chan, uchar* dp, int n)
104 {
105 return netifwstat(etherxx[chan->dev], chan, dp, n);
106 }
107
108 static void
etherrtrace(Netfile * f,Etherpkt * pkt,int len)109 etherrtrace(Netfile* f, Etherpkt* pkt, int len)
110 {
111 int i, n;
112 Block *bp;
113
114 if(qwindow(f->in) <= 0)
115 return;
116 if(len > 58)
117 n = 58;
118 else
119 n = len;
120 bp = iallocb(64);
121 if(bp == nil)
122 return;
123 memmove(bp->wp, pkt->d, n);
124 i = TK2MS(MACHP(0)->ticks);
125 bp->wp[58] = len>>8;
126 bp->wp[59] = len;
127 bp->wp[60] = i>>24;
128 bp->wp[61] = i>>16;
129 bp->wp[62] = i>>8;
130 bp->wp[63] = i;
131 bp->wp += 64;
132 qpass(f->in, bp);
133 }
134
135 Block*
etheriq(Ether * ether,Block * bp,int fromwire)136 etheriq(Ether* ether, Block* bp, int fromwire)
137 {
138 Etherpkt *pkt;
139 ushort type;
140 int len, multi, tome, fromme;
141 Netfile **ep, *f, **fp, *fx;
142 Block *xbp;
143
144 ether->inpackets++;
145
146 pkt = (Etherpkt*)bp->rp;
147 len = BLEN(bp);
148 type = (pkt->type[0]<<8)|pkt->type[1];
149 fx = 0;
150 ep = ðer->f[Ntypes];
151
152 multi = pkt->d[0] & 1;
153 /* check for valid multicast addresses */
154 if(multi && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) != 0 && ether->prom == 0){
155 if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
156 if(fromwire){
157 freeb(bp);
158 bp = 0;
159 }
160 return bp;
161 }
162 }
163
164 /* is it for me? */
165 tome = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
166 fromme = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0;
167
168 /*
169 * Multiplex the packet to all the connections which want it.
170 * If the packet is not to be used subsequently (fromwire != 0),
171 * attempt to simply pass it into one of the connections, thereby
172 * saving a copy of the data (usual case hopefully).
173 */
174 for(fp = ether->f; fp < ep; fp++){
175 if(f = *fp)
176 if(f->type == type || f->type < 0)
177 if(tome || multi || f->prom){
178 /* Don't want to hear bridged packets */
179 if(f->bridge && !fromwire && !fromme)
180 continue;
181 if(!f->headersonly){
182 if(fromwire && fx == 0)
183 fx = f;
184 else if(xbp = iallocb(len)){
185 memmove(xbp->wp, pkt, len);
186 xbp->wp += len;
187 if(qpass(f->in, xbp) < 0)
188 ether->soverflows++;
189 }
190 else
191 ether->soverflows++;
192 }
193 else
194 etherrtrace(f, pkt, len);
195 }
196 }
197
198 if(fx){
199 if(qpass(fx->in, bp) < 0)
200 ether->soverflows++;
201 return 0;
202 }
203 if(fromwire){
204 freeb(bp);
205 return 0;
206 }
207
208 return bp;
209 }
210
211 static int
etheroq(Ether * ether,Block * bp)212 etheroq(Ether* ether, Block* bp)
213 {
214 int len, loopback, s;
215 Etherpkt *pkt;
216
217 ether->outpackets++;
218
219 /*
220 * Check if the packet has to be placed back onto the input queue,
221 * i.e. if it's a loopback or broadcast packet or the interface is
222 * in promiscuous mode.
223 * If it's a loopback packet indicate to etheriq that the data isn't
224 * needed and return, etheriq will pass-on or free the block.
225 * To enable bridging to work, only packets that were originated
226 * by this interface are fed back.
227 */
228 pkt = (Etherpkt*)bp->rp;
229 len = BLEN(bp);
230 loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
231 if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom){
232 s = splhi();
233 etheriq(ether, bp, 0);
234 splx(s);
235 }
236
237 if(!loopback){
238 qbwrite(ether->oq, bp);
239 if(ether->transmit != nil)
240 ether->transmit(ether);
241 } else
242 freeb(bp);
243
244 return len;
245 }
246
247 static long
etherwrite(Chan * chan,void * buf,long n,vlong)248 etherwrite(Chan* chan, void* buf, long n, vlong)
249 {
250 Ether *ether;
251 Block *bp;
252 int nn, onoff;
253 Cmdbuf *cb;
254
255 ether = etherxx[chan->dev];
256 if(NETTYPE(chan->qid.path) != Ndataqid) {
257 nn = netifwrite(ether, chan, buf, n);
258 if(nn >= 0)
259 return nn;
260 cb = parsecmd(buf, n);
261 if(strcmp(cb->f[0], "nonblocking") == 0){
262 if(cb->nf <= 1)
263 onoff = 1;
264 else
265 onoff = atoi(cb->f[1]);
266 qnoblock(ether->oq, onoff);
267 free(cb);
268 return n;
269 }
270 free(cb);
271 if(ether->ctl!=nil)
272 return ether->ctl(ether,buf,n);
273
274 error(Ebadctl);
275 }
276
277 if(n > ether->maxmtu)
278 error(Etoobig);
279 if(n < ether->minmtu)
280 error(Etoosmall);
281
282 bp = allocb(n);
283 if(waserror()){
284 freeb(bp);
285 nexterror();
286 }
287 memmove(bp->rp, buf, n);
288 memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
289 poperror();
290 bp->wp += n;
291
292 return etheroq(ether, bp);
293 }
294
295 static long
etherbwrite(Chan * chan,Block * bp,ulong)296 etherbwrite(Chan* chan, Block* bp, ulong)
297 {
298 Ether *ether;
299 long n;
300
301 n = BLEN(bp);
302 if(NETTYPE(chan->qid.path) != Ndataqid){
303 if(waserror()) {
304 freeb(bp);
305 nexterror();
306 }
307 n = etherwrite(chan, bp->rp, n, 0);
308 poperror();
309 freeb(bp);
310 return n;
311 }
312 ether = etherxx[chan->dev];
313
314 if(n > ether->maxmtu){
315 freeb(bp);
316 error(Etoobig);
317 }
318 if(n < ether->minmtu){
319 freeb(bp);
320 error(Etoosmall);
321 }
322
323 return etheroq(ether, bp);
324 }
325
326 static struct {
327 char* type;
328 int (*reset)(Ether*);
329 } cards[MaxEther+1];
330
331 void
addethercard(char * t,int (* r)(Ether *))332 addethercard(char* t, int (*r)(Ether*))
333 {
334 static int ncard;
335
336 if(ncard == MaxEther)
337 panic("too many ether cards");
338 cards[ncard].type = t;
339 cards[ncard].reset = r;
340 ncard++;
341 }
342
343 int
parseether(uchar * to,char * from)344 parseether(uchar *to, char *from)
345 {
346 char nip[4];
347 char *p;
348 int i;
349
350 p = from;
351 for(i = 0; i < Eaddrlen; i++){
352 if(*p == 0)
353 return -1;
354 nip[0] = *p++;
355 if(*p == 0)
356 return -1;
357 nip[1] = *p++;
358 nip[2] = 0;
359 to[i] = strtoul(nip, 0, 16);
360 if(*p == ':')
361 p++;
362 }
363 return 0;
364 }
365
366 static void
etherreset(void)367 etherreset(void)
368 {
369 Ether *ether;
370 int i, n, ctlrno;
371 char name[KNAMELEN], buf[128];
372
373 for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){
374 if(ether == 0)
375 ether = malloc(sizeof(Ether));
376 if(ether == 0)
377 panic("etherreset: no memory");
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, ðer->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
ethershutdown(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
ethercrc(uchar * p,int len)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
dumpoq(Queue * oq)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
dumpnetif(Netif * netif)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 };
531