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