FreeBSD/Linux Kernel Cross Reference
sys/pc/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
12 #include "etherif.h"
13
14 static Ether *etherxx[MaxEther];
15
16 Chan*
17 etherattach(char* spec)
18 {
19 ulong 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 || (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*
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
51 etherstat(Chan* chan, uchar* dp, int n)
52 {
53 return netifstat(etherxx[chan->dev], chan, dp, n);
54 }
55
56 static Chan*
57 etheropen(Chan* chan, int omode)
58 {
59 return netifopen(etherxx[chan->dev], chan, omode);
60 }
61
62 static void
63 ethercreate(Chan*, char*, int, ulong)
64 {
65 }
66
67 static void
68 etherclose(Chan* chan)
69 {
70 netifclose(etherxx[chan->dev], chan);
71 }
72
73 static long
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*
95 etherbread(Chan* chan, long n, ulong offset)
96 {
97 return netifbread(etherxx[chan->dev], chan, n, offset);
98 }
99
100 static int
101 etherwstat(Chan* chan, uchar* dp, int n)
102 {
103 return netifwstat(etherxx[chan->dev], chan, dp, n);
104 }
105
106 static void
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*
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 && ether->prom == 0){
153 if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
154 if(fromwire){
155 freeb(bp);
156 bp = 0;
157 }
158 return bp;
159 }
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)
174 if(f->type == type || f->type < 0)
175 if(tome || multi || f->prom){
176 /* Don't want to hear bridged packets */
177 if(f->bridge && !fromwire && !fromme)
178 continue;
179 if(!f->headersonly){
180 if(fromwire && fx == 0)
181 fx = f;
182 else if(xbp = iallocb(len)){
183 memmove(xbp->wp, pkt, len);
184 xbp->wp += len;
185 if(qpass(f->in, xbp) < 0) {
186 print("soverflow for f->in\n");
187 ether->soverflows++;
188 }
189 }
190 else {
191 print("soverflow iallocb\n");
192 ether->soverflows++;
193 }
194 }
195 else
196 etherrtrace(f, pkt, len);
197 }
198 }
199
200 if(fx){
201 if(qpass(fx->in, bp) < 0) {
202 print("soverflow for fx->in\n");
203 ether->soverflows++;
204 }
205 return 0;
206 }
207 if(fromwire){
208 freeb(bp);
209 return 0;
210 }
211
212 return bp;
213 }
214
215 static int
216 etheroq(Ether* ether, Block* bp)
217 {
218 int len, loopback, s;
219 Etherpkt *pkt;
220
221 ether->outpackets++;
222
223 /*
224 * Check if the packet has to be placed back onto the input queue,
225 * i.e. if it's a loopback or broadcast packet or the interface is
226 * in promiscuous mode.
227 * If it's a loopback packet indicate to etheriq that the data isn't
228 * needed and return, etheriq will pass-on or free the block.
229 * To enable bridging to work, only packets that were originated
230 * by this interface are fed back.
231 */
232 pkt = (Etherpkt*)bp->rp;
233 len = BLEN(bp);
234 loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
235 if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom){
236 s = splhi();
237 etheriq(ether, bp, 0);
238 splx(s);
239 }
240
241 if(!loopback){
242 if(qfull(ether->oq))
243 print("etheroq: WARNING: ether->oq full!\n");
244 qbwrite(ether->oq, bp);
245 if(ether->transmit != nil)
246 ether->transmit(ether);
247 } else
248 freeb(bp);
249
250 return len;
251 }
252
253 static long
254 etherwrite(Chan* chan, void* buf, long n, vlong)
255 {
256 Ether *ether;
257 Block *bp;
258 int nn, onoff;
259 Cmdbuf *cb;
260
261 ether = etherxx[chan->dev];
262 if(NETTYPE(chan->qid.path) != Ndataqid) {
263 nn = netifwrite(ether, chan, buf, n);
264 if(nn >= 0)
265 return nn;
266 cb = parsecmd(buf, n);
267 if(cb->f[0] && strcmp(cb->f[0], "nonblocking") == 0){
268 if(cb->nf <= 1)
269 onoff = 1;
270 else
271 onoff = atoi(cb->f[1]);
272 qnoblock(ether->oq, onoff);
273 free(cb);
274 return n;
275 }
276 free(cb);
277 if(ether->ctl!=nil)
278 return ether->ctl(ether,buf,n);
279
280 error(Ebadctl);
281 }
282
283 if(n > ether->maxmtu)
284 error(Etoobig);
285 if(n < ether->minmtu)
286 error(Etoosmall);
287
288 bp = allocb(n);
289 if(waserror()){
290 freeb(bp);
291 nexterror();
292 }
293 memmove(bp->rp, buf, n);
294 memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
295 poperror();
296 bp->wp += n;
297
298 return etheroq(ether, bp);
299 }
300
301 static long
302 etherbwrite(Chan* chan, Block* bp, ulong)
303 {
304 Ether *ether;
305 long n;
306
307 n = BLEN(bp);
308 if(NETTYPE(chan->qid.path) != Ndataqid){
309 if(waserror()) {
310 freeb(bp);
311 nexterror();
312 }
313 n = etherwrite(chan, bp->rp, n, 0);
314 poperror();
315 freeb(bp);
316 return n;
317 }
318 ether = etherxx[chan->dev];
319
320 if(n > ether->maxmtu){
321 freeb(bp);
322 error(Etoobig);
323 }
324 if(n < ether->minmtu){
325 freeb(bp);
326 error(Etoosmall);
327 }
328
329 return etheroq(ether, bp);
330 }
331
332 static struct {
333 char* type;
334 int (*reset)(Ether*);
335 } cards[MaxEther+1];
336
337 void
338 addethercard(char* t, int (*r)(Ether*))
339 {
340 static int ncard;
341
342 if(ncard == MaxEther)
343 panic("too many ether cards");
344 cards[ncard].type = t;
345 cards[ncard].reset = r;
346 ncard++;
347 }
348
349 int
350 parseether(uchar *to, char *from)
351 {
352 char nip[4];
353 char *p;
354 int i;
355
356 p = from;
357 for(i = 0; i < Eaddrlen; i++){
358 if(*p == 0)
359 return -1;
360 nip[0] = *p++;
361 if(*p == 0)
362 return -1;
363 nip[1] = *p++;
364 nip[2] = 0;
365 to[i] = strtoul(nip, 0, 16);
366 if(*p == ':')
367 p++;
368 }
369 return 0;
370 }
371
372 static Ether*
373 etherprobe(int cardno, int ctlrno)
374 {
375 int i, lg;
376 ulong mb, bsz;
377 Ether *ether;
378 char buf[128], name[32];
379
380 ether = malloc(sizeof(Ether));
381 memset(ether, 0, sizeof(Ether));
382 ether->ctlrno = ctlrno;
383 ether->tbdf = BUSUNKNOWN;
384 ether->mbps = 10;
385 ether->minmtu = ETHERMINTU;
386 ether->maxmtu = ETHERMAXTU;
387
388 if(cardno < 0){
389 if(isaconfig("ether", ctlrno, ether) == 0){
390 free(ether);
391 return nil;
392 }
393 for(cardno = 0; cards[cardno].type; cardno++){
394 if(cistrcmp(cards[cardno].type, ether->type))
395 continue;
396 for(i = 0; i < ether->nopt; i++){
397 if(strncmp(ether->opt[i], "ea=", 3))
398 continue;
399 if(parseether(ether->ea, ðer->opt[i][3]))
400 memset(ether->ea, 0, Eaddrlen);
401 }
402 break;
403 }
404 }
405
406 if(cardno >= MaxEther || cards[cardno].type == nil){
407 free(ether);
408 return nil;
409 }
410 if(cards[cardno].reset(ether) < 0){
411 free(ether);
412 return nil;
413 }
414
415 /*
416 * IRQ2 doesn't really exist, it's used to gang the interrupt
417 * controllers together. A device set to IRQ2 will appear on
418 * the second interrupt controller as IRQ9.
419 */
420 if(ether->irq == 2)
421 ether->irq = 9;
422 snprint(name, sizeof(name), "ether%d", ctlrno);
423
424 /*
425 * If ether->irq is <0, it is a hack to indicate no interrupt
426 * used by ethersink.
427 */
428 if(ether->irq >= 0)
429 intrenable(ether->irq, ether->interrupt, ether, ether->tbdf, name);
430
431 i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %d",
432 ctlrno, cards[cardno].type, ether->mbps, ether->port, ether->irq);
433 if(ether->mem)
434 i += sprint(buf+i, " addr 0x%luX", ether->mem);
435 if(ether->size)
436 i += sprint(buf+i, " size 0x%luX", ether->size);
437 i += sprint(buf+i, ": %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
438 ether->ea[0], ether->ea[1], ether->ea[2],
439 ether->ea[3], ether->ea[4], ether->ea[5]);
440 sprint(buf+i, "\n");
441 print(buf);
442
443 /* compute log10(ether->mbps) into lg */
444 for(lg = 0, mb = ether->mbps; mb >= 10; lg++)
445 mb /= 10;
446 if (lg > 0)
447 lg--;
448 if (lg > 14) /* 2^(14+17) = 2ⁱ */
449 lg = 14;
450 /* allocate larger output queues for higher-speed interfaces */
451 bsz = 1UL << (lg + 17); /* 2ⁱ⁷ = 128K, bsz = 2ⁿ × 128K */
452 while (bsz > mainmem->maxsize / 8 && bsz > 128*1024)
453 bsz /= 2;
454
455 netifinit(ether, name, Ntypes, bsz);
456 if(ether->oq == nil) {
457 ether->oq = qopen(bsz, Qmsg, 0, 0);
458 ether->limit = bsz;
459 }
460 if(ether->oq == nil)
461 panic("etherreset %s: can't allocate output queue of %ld bytes",
462 name, bsz);
463 ether->alen = Eaddrlen;
464 memmove(ether->addr, ether->ea, Eaddrlen);
465 memset(ether->bcast, 0xFF, Eaddrlen);
466
467 return ether;
468 }
469
470 static void
471 fakeintrs(void)
472 {
473 int ctlrno;
474 Ether *ether;
475
476 for(ctlrno = 0; ctlrno < MaxEther; ctlrno++) {
477 ether = etherxx[ctlrno];
478 if (ether && ether->interrupt)
479 ether->interrupt(nil, ether);
480 }
481 }
482
483 /* terrible temporary hack for 82575 */
484 static void
485 startfakeintrs(void)
486 {
487 static int first = 1;
488
489 if (first) {
490 addclock0link(fakeintrs, 1);
491 first = 0;
492 }
493 }
494
495 static void
496 etherreset(void)
497 {
498 Ether *ether;
499 int cardno, ctlrno;
500
501 if (getconf("*fakeintrs") != nil)
502 startfakeintrs();
503 for(ctlrno = 0; ctlrno < MaxEther; ctlrno++){
504 if((ether = etherprobe(-1, ctlrno)) == nil)
505 continue;
506 etherxx[ctlrno] = ether;
507 }
508
509 if(getconf("*noetherprobe"))
510 return;
511
512 cardno = ctlrno = 0;
513 while(cards[cardno].type != nil && ctlrno < MaxEther){
514 if(etherxx[ctlrno] != nil){
515 ctlrno++;
516 continue;
517 }
518 if((ether = etherprobe(cardno, ctlrno)) == nil){
519 cardno++;
520 continue;
521 }
522 etherxx[ctlrno] = ether;
523 ctlrno++;
524 }
525 }
526
527 static void
528 ethershutdown(void)
529 {
530 Ether *ether;
531 int i;
532
533 for(i = 0; i < MaxEther; i++){
534 ether = etherxx[i];
535 if(ether == nil)
536 continue;
537 if(ether->shutdown == nil) {
538 print("#l%d: no shutdown fuction\n", i);
539 continue;
540 }
541 (*ether->shutdown)(ether);
542 }
543 }
544
545
546 #define POLY 0xedb88320
547
548 /* really slow 32 bit crc for ethers */
549 ulong
550 ethercrc(uchar *p, int len)
551 {
552 int i, j;
553 ulong crc, b;
554
555 crc = 0xffffffff;
556 for(i = 0; i < len; i++){
557 b = *p++;
558 for(j = 0; j < 8; j++){
559 crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0);
560 b >>= 1;
561 }
562 }
563 return crc;
564 }
565
566 Dev etherdevtab = {
567 'l',
568 "ether",
569
570 etherreset,
571 devinit,
572 ethershutdown,
573 etherattach,
574 etherwalk,
575 etherstat,
576 etheropen,
577 ethercreate,
578 etherclose,
579 etherread,
580 etherbread,
581 etherwrite,
582 etherbwrite,
583 devremove,
584 etherwstat,
585 };
Cache object: b12c0e17eef8d9e87c4f6b12f8844845
|