]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/ip/ethermedium.c
set router R-flag when sendra is active for neighbor advertisement
[plan9front.git] / sys / src / 9 / 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         /*
192          *  open arp conversation
193          */
194         snprint(addr, sizeof(addr), "%s!0x806", argv[2]);       /* ETARP */
195         achan = chandial(addr, nil, nil, nil);
196
197         /*
198          *  open ipv6 conversation
199          *
200          *  the dial will fail if the type is already open on
201          *  this device.
202          */
203         snprint(addr, sizeof(addr), "%s!0x86DD", argv[2]);      /* ETIP6 */
204         mchan6 = chandial(addr, nil, dir, &cchan6);
205
206         /*
207          *  make it non-blocking
208          */
209         devtab[cchan6->type]->write(cchan6, nbmsg, strlen(nbmsg), 0);
210
211         er = smalloc(sizeof(*er));
212         er->mchan4 = mchan4;
213         er->cchan4 = cchan4;
214         er->achan = achan;
215         er->mchan6 = mchan6;
216         er->cchan6 = cchan6;
217         er->f = ifc->conv->p->f;
218         ifc->arg = er;
219
220         free(buf);
221         poperror();
222
223         kproc("etherread4", etherread4, ifc);
224         kproc("recvarpproc", recvarpproc, ifc);
225         kproc("etherread6", etherread6, ifc);
226 }
227
228 /*
229  *  called with ifc wlock'd
230  */
231 static void
232 etherunbind(Ipifc *ifc)
233 {
234         Etherrock *er = ifc->arg;
235
236         if(er->read4p)
237                 postnote(er->read4p, 1, "unbind", 0);
238         if(er->read6p)
239                 postnote(er->read6p, 1, "unbind", 0);
240         if(er->arpp)
241                 postnote(er->arpp, 1, "unbind", 0);
242
243         /* wait for readers to die */
244         while(er->arpp != 0 || er->read4p != 0 || er->read6p != 0)
245                 tsleep(&up->sleep, return0, 0, 300);
246
247         if(er->mchan4 != nil)
248                 cclose(er->mchan4);
249         if(er->achan != nil)
250                 cclose(er->achan);
251         if(er->cchan4 != nil)
252                 cclose(er->cchan4);
253         if(er->mchan6 != nil)
254                 cclose(er->mchan6);
255         if(er->cchan6 != nil)
256                 cclose(er->cchan6);
257
258         free(er);
259 }
260
261 /*
262  *  called by ipoput with a single block to write with ifc rlock'd
263  */
264 static void
265 etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip)
266 {
267         Etherhdr *eh;
268         Arpent *a;
269         uchar mac[6];
270         Etherrock *er = ifc->arg;
271
272         /* get mac address of destination */
273         a = arpget(er->f->arp, bp, version, ifc, ip, mac);
274         if(a){
275                 /* check for broadcast or multicast */
276                 bp = multicastarp(er->f, a, ifc->m, mac);
277                 if(bp==nil){
278                         switch(version){
279                         case V4:
280                                 sendarp(ifc, a);
281                                 break;
282                         case V6:
283                                 resolveaddr6(ifc, a);
284                                 break;
285                         default:
286                                 panic("etherbwrite: version %d", version);
287                         }
288                         return;
289                 }
290         }
291
292         /* make it a single block with space for the ether header */
293         bp = padblock(bp, ifc->m->hsize);
294         if(BLEN(bp) < ifc->mintu)
295                 bp = adjustblock(bp, ifc->mintu);
296         eh = (Etherhdr*)bp->rp;
297
298         /* copy in mac addresses and ether type */
299         memmove(eh->s, ifc->mac, sizeof(eh->s));
300         memmove(eh->d, mac, sizeof(eh->d));
301
302         switch(version){
303         case V4:
304                 eh->t[0] = 0x08;
305                 eh->t[1] = 0x00;
306                 devtab[er->mchan4->type]->bwrite(er->mchan4, bp, 0);
307                 break;
308         case V6:
309                 eh->t[0] = 0x86;
310                 eh->t[1] = 0xDD;
311                 devtab[er->mchan6->type]->bwrite(er->mchan6, bp, 0);
312                 break;
313         default:
314                 panic("etherbwrite2: version %d", version);
315         }
316         ifc->out++;
317 }
318
319
320 /*
321  *  process to read from the ethernet
322  */
323 static void
324 etherread4(void *a)
325 {
326         Ipifc *ifc;
327         Block *bp;
328         Etherrock *er;
329
330         ifc = a;
331         er = ifc->arg;
332         er->read4p = up;        /* hide identity under a rock for unbind */
333         if(waserror()){
334                 er->read4p = 0;
335                 pexit("hangup", 1);
336         }
337         for(;;){
338                 bp = devtab[er->mchan4->type]->bread(er->mchan4, ifc->maxtu, 0);
339                 if(!canrlock(ifc)){
340                         freeb(bp);
341                         continue;
342                 }
343                 if(waserror()){
344                         runlock(ifc);
345                         nexterror();
346                 }
347                 ifc->in++;
348                 if(ifc->lifc == nil || BLEN(bp) <= ifc->m->hsize)
349                         freeb(bp);
350                 else {
351                         bp->rp += ifc->m->hsize;
352                         ipiput4(er->f, ifc, bp);
353                 }
354                 runlock(ifc);
355                 poperror();
356         }
357 }
358
359
360 /*
361  *  process to read from the ethernet, IPv6
362  */
363 static void
364 etherread6(void *a)
365 {
366         Ipifc *ifc;
367         Block *bp;
368         Etherrock *er;
369
370         ifc = a;
371         er = ifc->arg;
372         er->read6p = up;        /* hide identity under a rock for unbind */
373         if(waserror()){
374                 er->read6p = 0;
375                 pexit("hangup", 1);
376         }
377         for(;;){
378                 bp = devtab[er->mchan6->type]->bread(er->mchan6, ifc->maxtu, 0);
379                 if(!canrlock(ifc)){
380                         freeb(bp);
381                         continue;
382                 }
383                 if(waserror()){
384                         runlock(ifc);
385                         nexterror();
386                 }
387                 ifc->in++;
388                 if(ifc->lifc == nil || BLEN(bp) <= ifc->m->hsize)
389                         freeb(bp);
390                 else {
391                         bp->rp += ifc->m->hsize;
392                         ipiput6(er->f, ifc, bp);
393                 }
394                 runlock(ifc);
395                 poperror();
396         }
397 }
398
399 static void
400 etheraddmulti(Ipifc *ifc, uchar *a, uchar *)
401 {
402         uchar mac[6];
403         char buf[64];
404         Etherrock *er = ifc->arg;
405         int version;
406
407         version = multicastea(mac, a);
408         sprint(buf, "addmulti %E", mac);
409         switch(version){
410         case V4:
411                 devtab[er->cchan4->type]->write(er->cchan4, buf, strlen(buf), 0);
412                 break;
413         case V6:
414                 devtab[er->cchan6->type]->write(er->cchan6, buf, strlen(buf), 0);
415                 break;
416         default:
417                 panic("etheraddmulti: version %d", version);
418         }
419 }
420
421 static void
422 etherremmulti(Ipifc *ifc, uchar *a, uchar *)
423 {
424         uchar mac[6];
425         char buf[64];
426         Etherrock *er = ifc->arg;
427         int version;
428
429         version = multicastea(mac, a);
430         sprint(buf, "remmulti %E", mac);
431         switch(version){
432         case V4:
433                 devtab[er->cchan4->type]->write(er->cchan4, buf, strlen(buf), 0);
434                 break;
435         case V6:
436                 devtab[er->cchan6->type]->write(er->cchan6, buf, strlen(buf), 0);
437                 break;
438         default:
439                 panic("etherremmulti: version %d", version);
440         }
441 }
442
443 /*
444  *  send an ethernet arp
445  *  (only v4, v6 uses the neighbor discovery, rfc1970)
446  */
447 static void
448 sendarp(Ipifc *ifc, Arpent *a)
449 {
450         int n;
451         Block *bp;
452         Etherarp *e;
453         Etherrock *er = ifc->arg;
454
455         /* don't do anything if it's been less than a second since the last */
456         if(NOW - a->ctime < 1000){
457                 arprelease(er->f->arp, a);
458                 return;
459         }
460
461         /* remove all but the last message */
462         while((bp = a->hold) != nil){
463                 if(bp == a->last)
464                         break;
465                 a->hold = bp->list;
466                 freeblist(bp);
467         }
468
469         /* try to keep it around for a second more */
470         a->ctime = NOW;
471         arprelease(er->f->arp, a);
472
473         n = sizeof(Etherarp);
474         if(n < a->type->mintu)
475                 n = a->type->mintu;
476         bp = allocb(n);
477         memset(bp->rp, 0, n);
478         e = (Etherarp*)bp->rp;
479         memmove(e->tpa, a->ip+IPv4off, sizeof(e->tpa));
480         ipv4local(ifc, e->spa);
481         memmove(e->sha, ifc->mac, sizeof(e->sha));
482         memset(e->d, 0xff, sizeof(e->d));               /* ethernet broadcast */
483         memmove(e->s, ifc->mac, sizeof(e->s));
484
485         hnputs(e->type, ETARP);
486         hnputs(e->hrd, 1);
487         hnputs(e->pro, ETIP4);
488         e->hln = sizeof(e->sha);
489         e->pln = sizeof(e->spa);
490         hnputs(e->op, ARPREQUEST);
491         bp->wp += n;
492
493         devtab[er->achan->type]->bwrite(er->achan, bp, 0);
494 }
495
496 static void
497 resolveaddr6(Ipifc *ifc, Arpent *a)
498 {
499         int sflag;
500         Block *bp;
501         Etherrock *er = ifc->arg;
502         uchar ipsrc[IPaddrlen];
503
504         /* don't do anything if it's been less than a second since the last */
505         if(NOW - a->ctime < ReTransTimer){
506                 arprelease(er->f->arp, a);
507                 return;
508         }
509
510         /* remove all but the last message */
511         while((bp = a->hold) != nil){
512                 if(bp == a->last)
513                         break;
514                 a->hold = bp->list;
515                 freeblist(bp);
516         }
517
518         /* try to keep it around for a second more */
519         a->ctime = NOW;
520         a->rtime = NOW + ReTransTimer;
521         if(a->rxtsrem <= 0) {
522                 arprelease(er->f->arp, a);
523                 return;
524         }
525
526         a->rxtsrem--;
527         arprelease(er->f->arp, a);
528
529         if(sflag = ipv6anylocal(ifc, ipsrc))
530                 icmpns(er->f, ipsrc, sflag, a->ip, TARG_MULTI, ifc->mac);
531 }
532
533 /*
534  *  send a gratuitous arp to refresh arp caches
535  */
536 static void
537 sendgarp(Ipifc *ifc, uchar *ip)
538 {
539         int n;
540         Block *bp;
541         Etherarp *e;
542         Etherrock *er = ifc->arg;
543
544         /* don't arp for our initial non address */
545         if(ipcmp(ip, IPnoaddr) == 0)
546                 return;
547
548         n = sizeof(Etherarp);
549         if(n < ifc->m->mintu)
550                 n = ifc->m->mintu;
551         bp = allocb(n);
552         memset(bp->rp, 0, n);
553         e = (Etherarp*)bp->rp;
554         memmove(e->tpa, ip+IPv4off, sizeof(e->tpa));
555         memmove(e->spa, ip+IPv4off, sizeof(e->spa));
556         memmove(e->sha, ifc->mac, sizeof(e->sha));
557         memset(e->d, 0xff, sizeof(e->d));               /* ethernet broadcast */
558         memmove(e->s, ifc->mac, sizeof(e->s));
559
560         hnputs(e->type, ETARP);
561         hnputs(e->hrd, 1);
562         hnputs(e->pro, ETIP4);
563         e->hln = sizeof(e->sha);
564         e->pln = sizeof(e->spa);
565         hnputs(e->op, ARPREQUEST);
566         bp->wp += n;
567
568         devtab[er->achan->type]->bwrite(er->achan, bp, 0);
569 }
570
571 static void
572 recvarp(Ipifc *ifc)
573 {
574         int n;
575         Block *ebp, *rbp;
576         Etherarp *e, *r;
577         uchar ip[IPaddrlen];
578         static uchar eprinted[4];
579         Etherrock *er = ifc->arg;
580
581         ebp = devtab[er->achan->type]->bread(er->achan, ifc->maxtu, 0);
582         if(ebp == nil)
583                 return;
584
585         e = (Etherarp*)ebp->rp;
586         switch(nhgets(e->op)) {
587         default:
588                 break;
589
590         case ARPREPLY:
591                 /* check for machine using my ip address */
592                 v4tov6(ip, e->spa);
593                 if(iplocalonifc(ifc, ip) || ipproxyifc(er->f, ifc, ip)){
594                         if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0){
595                                 print("arprep: 0x%E/0x%E also has ip addr %V\n",
596                                         e->s, e->sha, e->spa);
597                                 break;
598                         }
599                 }
600
601                 /* make sure we're not entering broadcast addresses */
602                 if(ipcmp(ip, ipbroadcast) == 0 ||
603                         !memcmp(e->sha, etherbroadcast, sizeof(e->sha))){
604                         print("arprep: 0x%E/0x%E cannot register broadcast address %I\n",
605                                 e->s, e->sha, e->spa);
606                         break;
607                 }
608
609                 arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), 0);
610                 break;
611
612         case ARPREQUEST:
613                 /* don't answer arps till we know who we are */
614                 if(ifc->lifc == 0)
615                         break;
616
617                 /* check for machine using my ip or ether address */
618                 v4tov6(ip, e->spa);
619                 if(iplocalonifc(ifc, ip) || ipproxyifc(er->f, ifc, ip)){
620                         if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0){
621                                 if (memcmp(eprinted, e->spa, sizeof(e->spa))){
622                                         /* print only once */
623                                         print("arpreq: 0x%E also has ip addr %V\n", e->sha, e->spa);
624                                         memmove(eprinted, e->spa, sizeof(e->spa));
625                                 }
626                         }
627                 } else {
628                         if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) == 0){
629                                 print("arpreq: %V also has ether addr %E\n", e->spa, e->sha);
630                                 break;
631                         }
632                 }
633
634                 /* refresh what we know about sender */
635                 arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), 1);
636
637                 /* answer only requests for our address or systems we're proxying for */
638                 v4tov6(ip, e->tpa);
639                 if(!iplocalonifc(ifc, ip))
640                 if(!ipproxyifc(er->f, ifc, ip))
641                         break;
642
643                 n = sizeof(Etherarp);
644                 if(n < ifc->mintu)
645                         n = ifc->mintu;
646                 rbp = allocb(n);
647                 r = (Etherarp*)rbp->rp;
648                 memset(r, 0, sizeof(Etherarp));
649                 hnputs(r->type, ETARP);
650                 hnputs(r->hrd, 1);
651                 hnputs(r->pro, ETIP4);
652                 r->hln = sizeof(r->sha);
653                 r->pln = sizeof(r->spa);
654                 hnputs(r->op, ARPREPLY);
655                 memmove(r->tha, e->sha, sizeof(r->tha));
656                 memmove(r->tpa, e->spa, sizeof(r->tpa));
657                 memmove(r->sha, ifc->mac, sizeof(r->sha));
658                 memmove(r->spa, e->tpa, sizeof(r->spa));
659                 memmove(r->d, e->sha, sizeof(r->d));
660                 memmove(r->s, ifc->mac, sizeof(r->s));
661                 rbp->wp += n;
662
663                 devtab[er->achan->type]->bwrite(er->achan, rbp, 0);
664         }
665         freeb(ebp);
666 }
667
668 static void
669 recvarpproc(void *v)
670 {
671         Ipifc *ifc = v;
672         Etherrock *er = ifc->arg;
673
674         er->arpp = up;
675         if(waserror()){
676                 er->arpp = 0;
677                 pexit("hangup", 1);
678         }
679         for(;;)
680                 recvarp(ifc);
681 }
682
683 static int
684 multicastea(uchar *ea, uchar *ip)
685 {
686         int x;
687
688         switch(x = ipismulticast(ip)){
689         case V4:
690                 ea[0] = 0x01;
691                 ea[1] = 0x00;
692                 ea[2] = 0x5e;
693                 ea[3] = ip[13] & 0x7f;
694                 ea[4] = ip[14];
695                 ea[5] = ip[15];
696                 break;
697         case V6:
698                 ea[0] = 0x33;
699                 ea[1] = 0x33;
700                 ea[2] = ip[12];
701                 ea[3] = ip[13];
702                 ea[4] = ip[14];
703                 ea[5] = ip[15];
704                 break;
705         }
706         return x;
707 }
708
709 /*
710  *  fill in an arp entry for broadcast or multicast
711  *  addresses.  Return the first queued packet for the
712  *  IP address.
713  */
714 static Block*
715 multicastarp(Fs *f, Arpent *a, Medium *medium, uchar *mac)
716 {
717         /* is it broadcast? */
718         switch(ipforme(f, a->ip)){
719         case Runi:
720                 return nil;
721         case Rbcast:
722                 memset(mac, 0xff, 6);
723                 return arpresolve(f->arp, a, medium, mac);
724         default:
725                 break;
726         }
727
728         /* if multicast, fill in mac */
729         switch(multicastea(mac, a->ip)){
730         case V4:
731         case V6:
732                 return arpresolve(f->arp, a, medium, mac);
733         }
734
735         /* let arp take care of it */
736         return nil;
737 }
738
739 void
740 ethermediumlink(void)
741 {
742         addipmedium(&ethermedium);
743         addipmedium(&gbemedium);
744 }
745
746
747 static void
748 etherpref2addr(uchar *pref, uchar *ea)
749 {
750         pref[8] = ea[0] | 0x2;
751         pref[9] = ea[1];
752         pref[10] = ea[2];
753         pref[11] = 0xFF;
754         pref[12] = 0xFE;
755         pref[13] = ea[3];
756         pref[14] = ea[4];
757         pref[15] = ea[5];
758 }