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 &&
155 ether->prom == 0){
156 if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
157 if(fromwire){
158 freeb(bp);
159 bp = 0;
160 }
161 return bp;
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) != nil && (f->type == type || f->type < 0) &&
176 (tome || multi || f->prom)){
177 /* Don't want to hear bridged packets */
178 if(f->bridge && !fromwire && !fromme)
179 continue;
180 if(!f->headersonly){
181 if(fromwire && fx == 0)
182 fx = f;
183 else if(xbp = iallocb(len)){
184 memmove(xbp->wp, pkt, len);
185 xbp->wp += len;
186 if(qpass(f->in, xbp) < 0)
187 ether->soverflows++;
188 }
189 else
190 ether->soverflows++;
191 }
192 else
193 etherrtrace(f, pkt, len);
194 }
195 }
196
197 if(fx){
198 if(qpass(fx->in, bp) < 0)
199 ether->soverflows++;
200 return 0;
201 }
202 if(fromwire){
203 freeb(bp);
204 return 0;
205 }
206 return bp;
207 }
208
209 static int
etheroq(Ether * ether,Block * bp)210 etheroq(Ether* ether, Block* bp)
211 {
212 int len, loopback, s;
213 Etherpkt *pkt;
214
215 ether->outpackets++;
216
217 /*
218 * Check if the packet has to be placed back onto the input queue,
219 * i.e. if it's a loopback or broadcast packet or the interface is
220 * in promiscuous mode.
221 * If it's a loopback packet indicate to etheriq that the data isn't
222 * needed and return, etheriq will pass-on or free the block.
223 * To enable bridging to work, only packets that were originated
224 * by this interface are fed back.
225 */
226 pkt = (Etherpkt*)bp->rp;
227 len = BLEN(bp);
228 loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
229 if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom){
230 s = splhi();
231 etheriq(ether, bp, 0);
232 splx(s);
233 }
234
235 if(!loopback){
236 qbwrite(ether->oq, bp);
237 if(ether->transmit != nil)
238 ether->transmit(ether);
239 } else
240 freeb(bp);
241
242 return len;
243 }
244
245 static long
etherwrite(Chan * chan,void * buf,long n,vlong)246 etherwrite(Chan* chan, void* buf, long n, vlong)
247 {
248 Ether *ether;
249 Block *bp;
250 int nn, onoff;
251 Cmdbuf *cb;
252
253 ether = etherxx[chan->dev];
254 if(NETTYPE(chan->qid.path) != Ndataqid) {
255 nn = netifwrite(ether, chan, buf, n);
256 if(nn >= 0)
257 return nn;
258 cb = parsecmd(buf, n);
259 if(cb->f[0] && strcmp(cb->f[0], "nonblocking") == 0){
260 if(cb->nf <= 1)
261 onoff = 1;
262 else
263 onoff = atoi(cb->f[1]);
264 qnoblock(ether->oq, onoff);
265 free(cb);
266 return n;
267 }
268 free(cb);
269 if(ether->ctl!=nil)
270 return ether->ctl(ether,buf,n);
271
272 error(Ebadctl);
273 }
274
275 if(n > ether->maxmtu)
276 error(Etoobig);
277 if(n < ether->minmtu)
278 error(Etoosmall);
279
280 bp = allocb(n);
281 if(waserror()){
282 freeb(bp);
283 nexterror();
284 }
285 memmove(bp->rp, buf, n);
286 memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
287 poperror();
288 bp->wp += n;
289
290 return etheroq(ether, bp);
291 }
292
293 static long
etherbwrite(Chan * chan,Block * bp,ulong)294 etherbwrite(Chan* chan, Block* bp, ulong)
295 {
296 Ether *ether;
297 long n;
298
299 n = BLEN(bp);
300 if(NETTYPE(chan->qid.path) != Ndataqid){
301 if(waserror()) {
302 freeb(bp);
303 nexterror();
304 }
305 n = etherwrite(chan, bp->rp, n, 0);
306 poperror();
307 freeb(bp);
308 return n;
309 }
310 ether = etherxx[chan->dev];
311
312 if(n > ether->maxmtu){
313 freeb(bp);
314 error(Etoobig);
315 }
316 if(n < ether->minmtu){
317 freeb(bp);
318 error(Etoosmall);
319 }
320
321 return etheroq(ether, bp);
322 }
323
324 static struct {
325 char* type;
326 int (*reset)(Ether*);
327 } cards[MaxEther+1];
328
329 void
addethercard(char * t,int (* r)(Ether *))330 addethercard(char* t, int (*r)(Ether*))
331 {
332 static int ncard;
333
334 if(ncard == MaxEther)
335 panic("too many ether cards");
336 cards[ncard].type = t;
337 cards[ncard].reset = r;
338 ncard++;
339 }
340
341 int
parseether(uchar * to,char * from)342 parseether(uchar *to, char *from)
343 {
344 char nip[4];
345 char *p;
346 int i;
347
348 p = from;
349 for(i = 0; i < Eaddrlen; i++){
350 if(*p == 0)
351 return -1;
352 nip[0] = *p++;
353 if(*p == 0)
354 return -1;
355 nip[1] = *p++;
356 nip[2] = 0;
357 to[i] = strtoul(nip, 0, 16);
358 if(*p == ':')
359 p++;
360 }
361 return 0;
362 }
363
364 static void
etherreset(void)365 etherreset(void)
366 {
367 Ether *ether;
368 int i, n, ctlrno;
369 char name[KNAMELEN], buf[128];
370
371 for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){
372 if(ether == 0)
373 ether = malloc(sizeof(Ether));
374 memset(ether, 0, sizeof(Ether));
375 ether->ctlrno = ctlrno;
376 ether->mbps = 10;
377 ether->minmtu = ETHERMINTU;
378 ether->maxmtu = ETHERMAXTU;
379
380 if(archether(ctlrno, ether) <= 0)
381 continue;
382
383 if(isaconfig("ether", ctlrno, ether) == 0){
384 // free(ether);
385 // return nil;
386 continue;
387 }
388 for(n = 0; cards[n].type; n++){
389 if(cistrcmp(cards[n].type, ether->type))
390 continue;
391 for(i = 0; i < ether->nopt; i++)
392 if(cistrncmp(ether->opt[i], "ea=", 3) == 0){
393 if(parseether(ether->ea,
394 ðer->opt[i][3]) == -1)
395 memset(ether->ea, 0, Eaddrlen);
396 } else if(cistrcmp(ether->opt[i],
397 "100BASE-TXFD") == 0)
398 ether->mbps = 100;
399 if(cards[n].reset(ether))
400 break;
401 snprint(name, sizeof(name), "ether%d", ctlrno);
402
403 if(ether->interrupt != nil && ether->irq >= 0)
404 intrenable(ether->irq, ether->interrupt,
405 ether, 0, name);
406
407 i = snprint(buf, sizeof buf,
408 "#l%d: %s: %dMbps port %#lux irq %d",
409 ctlrno, ether->type, ether->mbps, ether->port,
410 ether->irq);
411 if(ether->mem)
412 i += snprint(buf+i, sizeof buf - i,
413 " addr %#lux", PADDR(ether->mem));
414 if(ether->size)
415 i += snprint(buf+i, sizeof buf - i,
416 " size %#luX", ether->size);
417 i += snprint(buf+i, sizeof buf - i,
418 ": %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
419 ether->ea[0], ether->ea[1], ether->ea[2],
420 ether->ea[3], ether->ea[4], ether->ea[5]);
421 snprint(buf+i, sizeof buf - i, "\n");
422 iprint("%s", buf); /* it may be too early for print */
423
424 if(ether->mbps >= 1000)
425 netifinit(ether, name, Ntypes, 4*1024*1024);
426 else if(ether->mbps >= 100)
427 netifinit(ether, name, Ntypes, 1024*1024);
428 else
429 netifinit(ether, name, Ntypes, 65*1024);
430 if(ether->oq == 0)
431 ether->oq = qopen(ether->limit, Qmsg, 0, 0);
432 if(ether->oq == 0)
433 panic("etherreset %s", name);
434 ether->alen = Eaddrlen;
435 memmove(ether->addr, ether->ea, Eaddrlen);
436 memset(ether->bcast, 0xFF, Eaddrlen);
437
438 etherxx[ctlrno] = ether;
439 ether = 0;
440 break;
441 }
442 }
443 if(ether)
444 free(ether);
445 }
446
447 static void
ethershutdown(void)448 ethershutdown(void)
449 {
450 Ether *ether;
451 int i;
452
453 for(i = 0; i < MaxEther; i++){
454 ether = etherxx[i];
455 if(ether == nil)
456 continue;
457 if(ether->shutdown == nil) {
458 print("#l%d: no shutdown function\n", i);
459 continue;
460 }
461 (*ether->shutdown)(ether);
462 }
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