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