FreeBSD/Linux Kernel Cross Reference
sys/ip/ethermedium.c
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "../port/error.h"
7
8 #include "../port/netif.h"
9 #include "ip.h"
10 #include "ipv6.h"
11
12 typedef struct Etherhdr Etherhdr;
13 struct Etherhdr
14 {
15 uchar d[6];
16 uchar s[6];
17 uchar t[2];
18 };
19
20 static uchar ipbroadcast[IPaddrlen] = {
21 0xff,0xff,0xff,0xff,
22 0xff,0xff,0xff,0xff,
23 0xff,0xff,0xff,0xff,
24 0xff,0xff,0xff,0xff,
25 };
26
27 static uchar etherbroadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
28
29 static void etherread4(void *a);
30 static void etherread6(void *a);
31 static void etherbind(Ipifc *ifc, int argc, char **argv);
32 static void etherunbind(Ipifc *ifc);
33 static void etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip);
34 static void etheraddmulti(Ipifc *ifc, uchar *a, uchar *ia);
35 static void etherremmulti(Ipifc *ifc, uchar *a, uchar *ia);
36 static Block* multicastarp(Fs *f, Arpent *a, Medium*, uchar *mac);
37 static void sendarp(Ipifc *ifc, Arpent *a);
38 static void sendgarp(Ipifc *ifc, uchar*);
39 static int multicastea(uchar *ea, uchar *ip);
40 static void recvarpproc(void*);
41 static void resolveaddr6(Ipifc *ifc, Arpent *a);
42 static void etherpref2addr(uchar *pref, uchar *ea);
43
44 Medium ethermedium =
45 {
46 .name= "ether",
47 .hsize= 14,
48 .mintu= 60,
49 .maxtu= 1514,
50 .maclen= 6,
51 .bind= etherbind,
52 .unbind= etherunbind,
53 .bwrite= etherbwrite,
54 .addmulti= etheraddmulti,
55 .remmulti= etherremmulti,
56 .ares= arpenter,
57 .areg= sendgarp,
58 .pref2addr= etherpref2addr,
59 };
60
61 Medium gbemedium =
62 {
63 .name= "gbe",
64 .hsize= 14,
65 .mintu= 60,
66 .maxtu= 9014,
67 .maclen= 6,
68 .bind= etherbind,
69 .unbind= etherunbind,
70 .bwrite= etherbwrite,
71 .addmulti= etheraddmulti,
72 .remmulti= etherremmulti,
73 .ares= arpenter,
74 .areg= sendgarp,
75 .pref2addr= etherpref2addr,
76 };
77
78 typedef struct Etherrock Etherrock;
79 struct Etherrock
80 {
81 Fs *f; /* file system we belong to */
82 Proc *arpp; /* arp process */
83 Proc *read4p; /* reading process (v4)*/
84 Proc *read6p; /* reading process (v6)*/
85 Chan *mchan4; /* Data channel for v4 */
86 Chan *achan; /* Arp channel */
87 Chan *cchan4; /* Control channel for v4 */
88 Chan *mchan6; /* Data channel for v6 */
89 Chan *cchan6; /* Control channel for v6 */
90 };
91
92 /*
93 * ethernet arp request
94 */
95 enum
96 {
97 ARPREQUEST = 1,
98 ARPREPLY = 2,
99 };
100
101 typedef struct Etherarp Etherarp;
102 struct Etherarp
103 {
104 uchar d[6];
105 uchar s[6];
106 uchar type[2];
107 uchar hrd[2];
108 uchar pro[2];
109 uchar hln;
110 uchar pln;
111 uchar op[2];
112 uchar sha[6];
113 uchar spa[4];
114 uchar tha[6];
115 uchar tpa[4];
116 };
117
118 static char *nbmsg = "nonblocking";
119
120 /*
121 * called to bind an IP ifc to an ethernet device
122 * called with ifc wlock'd
123 */
124 static void
125 etherbind(Ipifc *ifc, int argc, char **argv)
126 {
127 Chan *mchan4, *cchan4, *achan, *mchan6, *cchan6, *schan;
128 char addr[Maxpath]; //char addr[2*KNAMELEN];
129 char dir[Maxpath]; //char dir[2*KNAMELEN];
130 char *buf;
131 int n;
132 char *ptr;
133 Etherrock *er;
134
135 if(argc < 2)
136 error(Ebadarg);
137
138 mchan4 = cchan4 = achan = mchan6 = cchan6 = nil;
139 buf = nil;
140 if(waserror()){
141 if(mchan4 != nil)
142 cclose(mchan4);
143 if(cchan4 != nil)
144 cclose(cchan4);
145 if(achan != nil)
146 cclose(achan);
147 if(mchan6 != nil)
148 cclose(mchan6);
149 if(cchan6 != nil)
150 cclose(cchan6);
151 if(buf != nil)
152 free(buf);
153 nexterror();
154 }
155
156 /*
157 * open ipv4 conversation
158 *
159 * the dial will fail if the type is already open on
160 * this device.
161 */
162 snprint(addr, sizeof(addr), "%s!0x800", argv[2]); /* ETIP4 */
163 mchan4 = chandial(addr, nil, dir, &cchan4);
164
165 /*
166 * make it non-blocking
167 */
168 devtab[cchan4->type]->write(cchan4, nbmsg, strlen(nbmsg), 0);
169
170 /*
171 * get mac address and speed
172 */
173 snprint(addr, sizeof(addr), "%s/stats", argv[2]);
174 buf = smalloc(512);
175 schan = namec(addr, Aopen, OREAD, 0);
176 if(waserror()){
177 cclose(schan);
178 nexterror();
179 }
180 n = devtab[schan->type]->read(schan, buf, 511, 0);
181 cclose(schan);
182 poperror();
183 buf[n] = 0;
184
185 ptr = strstr(buf, "addr: ");
186 if(!ptr)
187 error(Eio);
188 ptr += 6;
189 parsemac(ifc->mac, ptr, 6);
190
191 ptr = strstr(buf, "mbps: ");
192 if(ptr){
193 ptr += 6;
194 ifc->mbps = atoi(ptr);
195 } else
196 ifc->mbps = 100;
197
198 /*
199 * open arp conversation
200 */
201 snprint(addr, sizeof(addr), "%s!0x806", argv[2]); /* ETARP */
202 achan = chandial(addr, nil, nil, nil);
203
204 /*
205 * open ipv6 conversation
206 *
207 * the dial will fail if the type is already open on
208 * this device.
209 */
210 snprint(addr, sizeof(addr), "%s!0x86DD", argv[2]); /* ETIP6 */
211 mchan6 = chandial(addr, nil, dir, &cchan6);
212
213 /*
214 * make it non-blocking
215 */
216 devtab[cchan6->type]->write(cchan6, nbmsg, strlen(nbmsg), 0);
217
218 er = smalloc(sizeof(*er));
219 er->mchan4 = mchan4;
220 er->cchan4 = cchan4;
221 er->achan = achan;
222 er->mchan6 = mchan6;
223 er->cchan6 = cchan6;
224 er->f = ifc->conv->p->f;
225 ifc->arg = er;
226
227 free(buf);
228 poperror();
229
230 kproc("etherread4", etherread4, ifc);
231 kproc("recvarpproc", recvarpproc, ifc);
232 kproc("etherread6", etherread6, ifc);
233 }
234
235 /*
236 * called with ifc wlock'd
237 */
238 static void
239 etherunbind(Ipifc *ifc)
240 {
241 Etherrock *er = ifc->arg;
242
243 if(er->read4p)
244 postnote(er->read4p, 1, "unbind", 0);
245 if(er->read6p)
246 postnote(er->read6p, 1, "unbind", 0);
247 if(er->arpp)
248 postnote(er->arpp, 1, "unbind", 0);
249
250 /* wait for readers to die */
251 while(er->arpp != 0 || er->read4p != 0 || er->read6p != 0)
252 tsleep(&up->sleep, return0, 0, 300);
253
254 if(er->mchan4 != nil)
255 cclose(er->mchan4);
256 if(er->achan != nil)
257 cclose(er->achan);
258 if(er->cchan4 != nil)
259 cclose(er->cchan4);
260 if(er->mchan6 != nil)
261 cclose(er->mchan6);
262 if(er->cchan6 != nil)
263 cclose(er->cchan6);
264
265 free(er);
266 }
267
268 /*
269 * called by ipoput with a single block to write with ifc rlock'd
270 */
271 static void
272 etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip)
273 {
274 Etherhdr *eh;
275 Arpent *a;
276 uchar mac[6];
277 Etherrock *er = ifc->arg;
278
279 /* get mac address of destination */
280 a = arpget(er->f->arp, bp, version, ifc, ip, mac);
281 if(a){
282 /* check for broadcast or multicast */
283 bp = multicastarp(er->f, a, ifc->m, mac);
284 if(bp==nil){
285 switch(version){
286 case V4:
287 sendarp(ifc, a);
288 break;
289 case V6:
290 resolveaddr6(ifc, a);
291 break;
292 default:
293 panic("etherbwrite: version %d", version);
294 }
295 return;
296 }
297 }
298
299 /* make it a single block with space for the ether header */
300 bp = padblock(bp, ifc->m->hsize);
301 if(bp->next)
302 bp = concatblock(bp);
303 if(BLEN(bp) < ifc->mintu)
304 bp = adjustblock(bp, ifc->mintu);
305 eh = (Etherhdr*)bp->rp;
306
307 /* copy in mac addresses and ether type */
308 memmove(eh->s, ifc->mac, sizeof(eh->s));
309 memmove(eh->d, mac, sizeof(eh->d));
310
311 switch(version){
312 case V4:
313 eh->t[0] = 0x08;
314 eh->t[1] = 0x00;
315 devtab[er->mchan4->type]->bwrite(er->mchan4, bp, 0);
316 break;
317 case V6:
318 eh->t[0] = 0x86;
319 eh->t[1] = 0xDD;
320 devtab[er->mchan6->type]->bwrite(er->mchan6, bp, 0);
321 break;
322 default:
323 panic("etherbwrite2: version %d", version);
324 }
325 ifc->out++;
326 }
327
328
329 /*
330 * process to read from the ethernet
331 */
332 static void
333 etherread4(void *a)
334 {
335 Ipifc *ifc;
336 Block *bp;
337 Etherrock *er;
338
339 ifc = a;
340 er = ifc->arg;
341 er->read4p = up; /* hide identity under a rock for unbind */
342 if(waserror()){
343 er->read4p = 0;
344 pexit("hangup", 1);
345 }
346 for(;;){
347 bp = devtab[er->mchan4->type]->bread(er->mchan4, ifc->maxtu, 0);
348 if(!canrlock(ifc)){
349 freeb(bp);
350 continue;
351 }
352 if(waserror()){
353 runlock(ifc);
354 nexterror();
355 }
356 ifc->in++;
357 bp->rp += ifc->m->hsize;
358 if(ifc->lifc == nil)
359 freeb(bp);
360 else
361 ipiput4(er->f, ifc, bp);
362 runlock(ifc);
363 poperror();
364 }
365 }
366
367
368 /*
369 * process to read from the ethernet, IPv6
370 */
371 static void
372 etherread6(void *a)
373 {
374 Ipifc *ifc;
375 Block *bp;
376 Etherrock *er;
377
378 ifc = a;
379 er = ifc->arg;
380 er->read6p = up; /* hide identity under a rock for unbind */
381 if(waserror()){
382 er->read6p = 0;
383 pexit("hangup", 1);
384 }
385 for(;;){
386 bp = devtab[er->mchan6->type]->bread(er->mchan6, ifc->maxtu, 0);
387 if(!canrlock(ifc)){
388 freeb(bp);
389 continue;
390 }
391 if(waserror()){
392 runlock(ifc);
393 nexterror();
394 }
395 ifc->in++;
396 bp->rp += ifc->m->hsize;
397 if(ifc->lifc == nil)
398 freeb(bp);
399 else
400 ipiput6(er->f, ifc, bp);
401 runlock(ifc);
402 poperror();
403 }
404 }
405
406 static void
407 etheraddmulti(Ipifc *ifc, uchar *a, uchar *)
408 {
409 uchar mac[6];
410 char buf[64];
411 Etherrock *er = ifc->arg;
412 int version;
413
414 version = multicastea(mac, a);
415 sprint(buf, "addmulti %E", mac);
416 switch(version){
417 case V4:
418 devtab[er->cchan4->type]->write(er->cchan4, buf, strlen(buf), 0);
419 break;
420 case V6:
421 devtab[er->cchan6->type]->write(er->cchan6, buf, strlen(buf), 0);
422 break;
423 default:
424 panic("etheraddmulti: version %d", version);
425 }
426 }
427
428 static void
429 etherremmulti(Ipifc *ifc, uchar *a, uchar *)
430 {
431 uchar mac[6];
432 char buf[64];
433 Etherrock *er = ifc->arg;
434 int version;
435
436 version = multicastea(mac, a);
437 sprint(buf, "remmulti %E", mac);
438 switch(version){
439 case V4:
440 devtab[er->cchan4->type]->write(er->cchan4, buf, strlen(buf), 0);
441 break;
442 case V6:
443 devtab[er->cchan6->type]->write(er->cchan6, buf, strlen(buf), 0);
444 break;
445 default:
446 panic("etherremmulti: version %d", version);
447 }
448 }
449
450 /*
451 * send an ethernet arp
452 * (only v4, v6 uses the neighbor discovery, rfc1970)
453 */
454 static void
455 sendarp(Ipifc *ifc, Arpent *a)
456 {
457 int n;
458 Block *bp;
459 Etherarp *e;
460 Etherrock *er = ifc->arg;
461
462 /* don't do anything if it's been less than a second since the last */
463 if(NOW - a->ctime < 1000){
464 arprelease(er->f->arp, a);
465 return;
466 }
467
468 /* remove all but the last message */
469 while((bp = a->hold) != nil){
470 if(bp == a->last)
471 break;
472 a->hold = bp->list;
473 freeblist(bp);
474 }
475
476 /* try to keep it around for a second more */
477 a->ctime = NOW;
478 arprelease(er->f->arp, a);
479
480 n = sizeof(Etherarp);
481 if(n < a->type->mintu)
482 n = a->type->mintu;
483 bp = allocb(n);
484 memset(bp->rp, 0, n);
485 e = (Etherarp*)bp->rp;
486 memmove(e->tpa, a->ip+IPv4off, sizeof(e->tpa));
487 ipv4local(ifc, e->spa);
488 memmove(e->sha, ifc->mac, sizeof(e->sha));
489 memset(e->d, 0xff, sizeof(e->d)); /* ethernet broadcast */
490 memmove(e->s, ifc->mac, sizeof(e->s));
491
492 hnputs(e->type, ETARP);
493 hnputs(e->hrd, 1);
494 hnputs(e->pro, ETIP4);
495 e->hln = sizeof(e->sha);
496 e->pln = sizeof(e->spa);
497 hnputs(e->op, ARPREQUEST);
498 bp->wp += n;
499
500 devtab[er->achan->type]->bwrite(er->achan, bp, 0);
501 }
502
503 static void
504 resolveaddr6(Ipifc *ifc, Arpent *a)
505 {
506 int sflag;
507 Block *bp;
508 Etherrock *er = ifc->arg;
509 uchar ipsrc[IPaddrlen];
510
511 /* don't do anything if it's been less than a second since the last */
512 if(NOW - a->ctime < ReTransTimer){
513 arprelease(er->f->arp, a);
514 return;
515 }
516
517 /* remove all but the last message */
518 while((bp = a->hold) != nil){
519 if(bp == a->last)
520 break;
521 a->hold = bp->list;
522 freeblist(bp);
523 }
524
525 /* try to keep it around for a second more */
526 a->ctime = NOW;
527 a->rtime = NOW + ReTransTimer;
528 if(a->rxtsrem <= 0) {
529 arprelease(er->f->arp, a);
530 return;
531 }
532
533 a->rxtsrem--;
534 arprelease(er->f->arp, a);
535
536 if(sflag = ipv6anylocal(ifc, ipsrc))
537 icmpns(er->f, ipsrc, sflag, a->ip, TARG_MULTI, ifc->mac);
538 }
539
540 /*
541 * send a gratuitous arp to refresh arp caches
542 */
543 static void
544 sendgarp(Ipifc *ifc, uchar *ip)
545 {
546 int n;
547 Block *bp;
548 Etherarp *e;
549 Etherrock *er = ifc->arg;
550
551 /* don't arp for our initial non address */
552 if(ipcmp(ip, IPnoaddr) == 0)
553 return;
554
555 n = sizeof(Etherarp);
556 if(n < ifc->m->mintu)
557 n = ifc->m->mintu;
558 bp = allocb(n);
559 memset(bp->rp, 0, n);
560 e = (Etherarp*)bp->rp;
561 memmove(e->tpa, ip+IPv4off, sizeof(e->tpa));
562 memmove(e->spa, ip+IPv4off, sizeof(e->spa));
563 memmove(e->sha, ifc->mac, sizeof(e->sha));
564 memset(e->d, 0xff, sizeof(e->d)); /* ethernet broadcast */
565 memmove(e->s, ifc->mac, sizeof(e->s));
566
567 hnputs(e->type, ETARP);
568 hnputs(e->hrd, 1);
569 hnputs(e->pro, ETIP4);
570 e->hln = sizeof(e->sha);
571 e->pln = sizeof(e->spa);
572 hnputs(e->op, ARPREQUEST);
573 bp->wp += n;
574
575 devtab[er->achan->type]->bwrite(er->achan, bp, 0);
576 }
577
578 static void
579 recvarp(Ipifc *ifc)
580 {
581 int n;
582 Block *ebp, *rbp;
583 Etherarp *e, *r;
584 uchar ip[IPaddrlen];
585 static uchar eprinted[4];
586 Etherrock *er = ifc->arg;
587
588 ebp = devtab[er->achan->type]->bread(er->achan, ifc->maxtu, 0);
589 if(ebp == nil)
590 return;
591
592 e = (Etherarp*)ebp->rp;
593 switch(nhgets(e->op)) {
594 default:
595 break;
596
597 case ARPREPLY:
598 /* check for machine using my ip address */
599 v4tov6(ip, e->spa);
600 if(iplocalonifc(ifc, ip) || ipproxyifc(er->f, ifc, ip)){
601 if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0){
602 print("arprep: 0x%E/0x%E also has ip addr %V\n",
603 e->s, e->sha, e->spa);
604 break;
605 }
606 }
607
608 /* make sure we're not entering broadcast addresses */
609 if(ipcmp(ip, ipbroadcast) == 0 ||
610 !memcmp(e->sha, etherbroadcast, sizeof(e->sha))){
611 print("arprep: 0x%E/0x%E cannot register broadcast address %I\n",
612 e->s, e->sha, e->spa);
613 break;
614 }
615
616 arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), 0);
617 break;
618
619 case ARPREQUEST:
620 /* don't answer arps till we know who we are */
621 if(ifc->lifc == 0)
622 break;
623
624 /* check for machine using my ip or ether address */
625 v4tov6(ip, e->spa);
626 if(iplocalonifc(ifc, ip) || ipproxyifc(er->f, ifc, ip)){
627 if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0){
628 if (memcmp(eprinted, e->spa, sizeof(e->spa))){
629 /* print only once */
630 print("arpreq: 0x%E also has ip addr %V\n", e->sha, e->spa);
631 memmove(eprinted, e->spa, sizeof(e->spa));
632 }
633 }
634 } else {
635 if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) == 0){
636 print("arpreq: %V also has ether addr %E\n", e->spa, e->sha);
637 break;
638 }
639 }
640
641 /* refresh what we know about sender */
642 arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), 1);
643
644 /* answer only requests for our address or systems we're proxying for */
645 v4tov6(ip, e->tpa);
646 if(!iplocalonifc(ifc, ip))
647 if(!ipproxyifc(er->f, ifc, ip))
648 break;
649
650 n = sizeof(Etherarp);
651 if(n < ifc->mintu)
652 n = ifc->mintu;
653 rbp = allocb(n);
654 r = (Etherarp*)rbp->rp;
655 memset(r, 0, sizeof(Etherarp));
656 hnputs(r->type, ETARP);
657 hnputs(r->hrd, 1);
658 hnputs(r->pro, ETIP4);
659 r->hln = sizeof(r->sha);
660 r->pln = sizeof(r->spa);
661 hnputs(r->op, ARPREPLY);
662 memmove(r->tha, e->sha, sizeof(r->tha));
663 memmove(r->tpa, e->spa, sizeof(r->tpa));
664 memmove(r->sha, ifc->mac, sizeof(r->sha));
665 memmove(r->spa, e->tpa, sizeof(r->spa));
666 memmove(r->d, e->sha, sizeof(r->d));
667 memmove(r->s, ifc->mac, sizeof(r->s));
668 rbp->wp += n;
669
670 devtab[er->achan->type]->bwrite(er->achan, rbp, 0);
671 }
672 freeb(ebp);
673 }
674
675 static void
676 recvarpproc(void *v)
677 {
678 Ipifc *ifc = v;
679 Etherrock *er = ifc->arg;
680
681 er->arpp = up;
682 if(waserror()){
683 er->arpp = 0;
684 pexit("hangup", 1);
685 }
686 for(;;)
687 recvarp(ifc);
688 }
689
690 static int
691 multicastea(uchar *ea, uchar *ip)
692 {
693 int x;
694
695 switch(x = ipismulticast(ip)){
696 case V4:
697 ea[0] = 0x01;
698 ea[1] = 0x00;
699 ea[2] = 0x5e;
700 ea[3] = ip[13] & 0x7f;
701 ea[4] = ip[14];
702 ea[5] = ip[15];
703 break;
704 case V6:
705 ea[0] = 0x33;
706 ea[1] = 0x33;
707 ea[2] = ip[12];
708 ea[3] = ip[13];
709 ea[4] = ip[14];
710 ea[5] = ip[15];
711 break;
712 }
713 return x;
714 }
715
716 /*
717 * fill in an arp entry for broadcast or multicast
718 * addresses. Return the first queued packet for the
719 * IP address.
720 */
721 static Block*
722 multicastarp(Fs *f, Arpent *a, Medium *medium, uchar *mac)
723 {
724 /* is it broadcast? */
725 switch(ipforme(f, a->ip)){
726 case Runi:
727 return nil;
728 case Rbcast:
729 memset(mac, 0xff, 6);
730 return arpresolve(f->arp, a, medium, mac);
731 default:
732 break;
733 }
734
735 /* if multicast, fill in mac */
736 switch(multicastea(mac, a->ip)){
737 case V4:
738 case V6:
739 return arpresolve(f->arp, a, medium, mac);
740 }
741
742 /* let arp take care of it */
743 return nil;
744 }
745
746 void
747 ethermediumlink(void)
748 {
749 addipmedium(ðermedium);
750 addipmedium(&gbemedium);
751 }
752
753
754 static void
755 etherpref2addr(uchar *pref, uchar *ea)
756 {
757 pref[8] = ea[0] | 0x2;
758 pref[9] = ea[1];
759 pref[10] = ea[2];
760 pref[11] = 0xFF;
761 pref[12] = 0xFE;
762 pref[13] = ea[3];
763 pref[14] = ea[4];
764 pref[15] = ea[5];
765 }
Cache object: 225c10b60428100626851aa003da7e6d
|