Use linker functions for NIC and medium pre-init
[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(1);
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                 error("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                 error("can't open ether stats: %s", get_cur_errbuf());
193
194         buf = kzmalloc(512, 0);
195         n = sysread(fd, buf, 511);
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         ktask("etherread4", etherread4, ifc);
257         ktask("recvarpproc", recvarpproc, ifc);
258         ktask("etherread6", etherread6, ifc);
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         udelay_sched(300 * 1000);
282
283         if(er->mchan4 != NULL)
284                 cclose(er->mchan4);
285         if(er->achan != NULL)
286                 cclose(er->achan);
287         if(er->cchan4 != NULL)
288                 cclose(er->cchan4);
289         if(er->mchan6 != NULL)
290                 cclose(er->mchan6);
291         if(er->cchan6 != NULL)
292                 cclose(er->cchan6);
293
294         kfree(er);
295 }
296
297 /*
298  *  called by ipoput with a single block to write with ifc rlock'd
299  */
300 static void
301 etherbwrite(struct Ipifc *ifc, struct block *bp, int version, uint8_t *ip)
302 {
303         Etherhdr *eh;
304         struct arpent *a;
305         uint8_t mac[6];
306         Etherrock *er = ifc->arg;
307
308         /* get mac address of destination */
309         a = arpget(er->f->arp, bp, version, ifc, ip, mac);
310         if(a){
311                 /* check for broadcast or multicast */
312                 bp = multicastarp(er->f, a, ifc->m, mac);
313                 if(bp==NULL){
314                         switch(version){
315                         case V4:
316                                 sendarp(ifc, a);
317                                 break;
318                         case V6: 
319                                 resolveaddr6(ifc, a);
320                                 break;
321                         default:
322                                 panic("etherbwrite: version %d", version);
323                         }
324                         return;
325                 }
326         }
327
328         /* make it a single block with space for the ether header */
329         bp = padblock(bp, ifc->m->hsize);
330         if(bp->next)
331                 bp = concatblock(bp);
332         if(BLEN(bp) < ifc->mintu)
333                 bp = adjustblock(bp, ifc->mintu);
334         eh = (Etherhdr*)bp->rp;
335
336         /* copy in mac addresses and ether type */
337         memmove(eh->s, ifc->mac, sizeof(eh->s));
338         memmove(eh->d, mac, sizeof(eh->d));
339
340         switch(version){
341         case V4:
342                 eh->t[0] = 0x08;
343                 eh->t[1] = 0x00;
344                 devtab[er->mchan4->type].bwrite(er->mchan4, bp, 0);
345                 break;
346         case V6:
347                 eh->t[0] = 0x86;
348                 eh->t[1] = 0xDD;
349                 devtab[er->mchan6->type].bwrite(er->mchan6, bp, 0);
350                 break;
351         default:
352                 panic("etherbwrite2: version %d", version);
353         }
354         ifc->out++;
355 }
356
357
358 /*
359  *  process to read from the ethernet
360  */
361 static void
362 etherread4(void *a)
363 {
364         ERRSTACK(2);
365         struct Ipifc *ifc;
366         struct block *bp;
367         Etherrock *er;
368
369         ifc = a;
370         er = ifc->arg;
371         er->read4p = current;   /* hide identity under a rock for unbind */
372         if(waserror()){
373                 er->read4p = 0;
374                 poperror();
375                 warn("etherread4 returns, probably unexpectedly\n");
376                 return;
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         poperror();
398 }
399
400
401 /*
402  *  process to read from the ethernet, IPv6
403  */
404 static void
405 etherread6(void *a)
406 {
407         ERRSTACK(2);
408         struct Ipifc *ifc;
409         struct block *bp;
410         Etherrock *er;
411
412         ifc = a;
413         er = ifc->arg;
414         er->read6p = current;   /* hide identity under a rock for unbind */
415         if(waserror()){
416                 er->read6p = 0;
417                 warn("etherread6 returns, probably unexpectedly\n");
418                 poperror();
419                 return;
420         }
421         for(;;){
422                 bp = devtab[er->mchan6->type].bread(er->mchan6, ifc->maxtu, 0);
423                 if(!canrlock(&ifc->rwlock)){
424                         freeb(bp);
425                         continue;
426                 }
427                 if(waserror()){
428                         runlock(&ifc->rwlock);
429                         nexterror();
430                 }
431                 ifc->in++;
432                 bp->rp += ifc->m->hsize;
433                 if(ifc->lifc == NULL)
434                         freeb(bp);
435                 else
436                         ipiput6(er->f, ifc, bp);
437                 runlock(&ifc->rwlock);
438                 poperror();
439         }
440         poperror();
441 }
442
443 static void
444 etheraddmulti(struct Ipifc *ifc, uint8_t *a, uint8_t *unused)
445 {
446         uint8_t mac[6];
447         char buf[64];
448         Etherrock *er = ifc->arg;
449         int version;
450
451         version = multicastea(mac, a);
452         snprintf(buf, sizeof(buf), "addmulti %E", mac);
453         switch(version){
454         case V4:
455                 devtab[er->cchan4->type].write(er->cchan4, buf, strlen(buf), 0);
456                 break;
457         case V6:
458                 devtab[er->cchan6->type].write(er->cchan6, buf, strlen(buf), 0);
459                 break;
460         default:
461                 panic("etheraddmulti: version %d", version);
462         }
463 }
464
465 static void
466 etherremmulti(struct Ipifc *ifc, uint8_t *a, uint8_t *unused)
467 {
468         uint8_t mac[6];
469         char buf[64];
470         Etherrock *er = ifc->arg;
471         int version;
472
473         version = multicastea(mac, a);
474         snprintf(buf, sizeof(buf), "remmulti %E", mac);
475         switch(version){
476         case V4:
477                 devtab[er->cchan4->type].write(er->cchan4, buf, strlen(buf), 0);
478                 break;
479         case V6:
480                 devtab[er->cchan6->type].write(er->cchan6, buf, strlen(buf), 0);
481                 break;
482         default:
483                 panic("etherremmulti: version %d", version);
484         }
485 }
486
487 /*
488  *  send an ethernet arp
489  *  (only v4, v6 uses the neighbor discovery, rfc1970)
490  */
491 static void
492 sendarp(struct Ipifc *ifc, struct arpent *a)
493 {
494         int n;
495         struct block *bp;
496         Etherarp *e;
497         Etherrock *er = ifc->arg;
498
499         /* don't do anything if it's been less than a second since the last */
500         if(NOW - a->ctime < 1000){
501                 arprelease(er->f->arp, a);
502                 return;
503         }
504
505         /* remove all but the last message */
506         while((bp = a->hold) != NULL){
507                 if(bp == a->last)
508                         break;
509                 a->hold = bp->list;
510                 freeblist(bp);
511         }
512
513         /* try to keep it around for a second more */
514         a->ctime = NOW;
515         arprelease(er->f->arp, a);
516
517         n = sizeof(Etherarp);
518         if(n < a->type->mintu)
519                 n = a->type->mintu;
520         bp = allocb(n);
521         memset(bp->rp, 0, n);
522         e = (Etherarp*)bp->rp;
523         memmove(e->tpa, a->ip+IPv4off, sizeof(e->tpa));
524         ipv4local(ifc, e->spa);
525         memmove(e->sha, ifc->mac, sizeof(e->sha));
526         memset(e->d, 0xff, sizeof(e->d));               /* ethernet broadcast */
527         memmove(e->s, ifc->mac, sizeof(e->s));
528
529         hnputs(e->type, ETARP);
530         hnputs(e->hrd, 1);
531         hnputs(e->pro, ETIP4);
532         e->hln = sizeof(e->sha);
533         e->pln = sizeof(e->spa);
534         hnputs(e->op, ARPREQUEST);
535         bp->wp += n;
536
537         n = devtab[er->achan->type].bwrite(er->achan, bp, 0);
538         if(n < 0)
539                 printd("arp: send: %r\n");
540 }
541
542 static void
543 resolveaddr6(struct Ipifc *ifc, struct arpent *a)
544 {
545         int sflag;
546         struct block *bp;
547         Etherrock *er = ifc->arg;
548         uint8_t ipsrc[IPaddrlen];
549
550         /* don't do anything if it's been less than a second since the last */
551         if(NOW - a->ctime < ReTransTimer){
552                 arprelease(er->f->arp, a);
553                 return;
554         }
555
556         /* remove all but the last message */
557         while((bp = a->hold) != NULL){
558                 if(bp == a->last)
559                         break;
560                 a->hold = bp->list;
561                 freeblist(bp);
562         }
563
564         /* try to keep it around for a second more */
565         a->ctime = NOW;
566         a->rtime = NOW + ReTransTimer;
567         if(a->rxtsrem <= 0) {
568                 arprelease(er->f->arp, a);
569                 return;
570         }
571
572         a->rxtsrem--;
573         arprelease(er->f->arp, a);
574
575         if((sflag = ipv6anylocal(ifc, ipsrc)) )
576                 icmpns(er->f, ipsrc, sflag, a->ip, TARG_MULTI, ifc->mac);
577 }
578
579 /*
580  *  send a gratuitous arp to refresh arp caches
581  */
582 static void
583 sendgarp(struct Ipifc *ifc, uint8_t *ip)
584 {
585         int n;
586         struct block *bp;
587         Etherarp *e;
588         Etherrock *er = ifc->arg;
589
590         /* don't arp for our initial non address */
591         if(ipcmp(ip, IPnoaddr) == 0)
592                 return;
593
594         n = sizeof(Etherarp);
595         if(n < ifc->m->mintu)
596                 n = ifc->m->mintu;
597         bp = allocb(n);
598         memset(bp->rp, 0, n);
599         e = (Etherarp*)bp->rp;
600         memmove(e->tpa, ip+IPv4off, sizeof(e->tpa));
601         memmove(e->spa, ip+IPv4off, sizeof(e->spa));
602         memmove(e->sha, ifc->mac, sizeof(e->sha));
603         memset(e->d, 0xff, sizeof(e->d));               /* ethernet broadcast */
604         memmove(e->s, ifc->mac, sizeof(e->s));
605
606         hnputs(e->type, ETARP);
607         hnputs(e->hrd, 1);
608         hnputs(e->pro, ETIP4);
609         e->hln = sizeof(e->sha);
610         e->pln = sizeof(e->spa);
611         hnputs(e->op, ARPREQUEST);
612         bp->wp += n;
613
614         n = devtab[er->achan->type].bwrite(er->achan, bp, 0);
615         if(n < 0)
616                 printd("garp: send: %r\n");
617 }
618
619 static void
620 recvarp(struct Ipifc *ifc)
621 {
622         int n;
623         struct block *ebp, *rbp;
624         Etherarp *e, *r;
625         uint8_t ip[IPaddrlen];
626         static uint8_t eprinted[4];
627         Etherrock *er = ifc->arg;
628
629         ebp = devtab[er->achan->type].bread(er->achan, ifc->maxtu, 0);
630         if(ebp == NULL) {
631                 printd("arp: rcv: %r\n");
632                 return;
633         }
634
635         e = (Etherarp*)ebp->rp;
636         switch(nhgets(e->op)) {
637         default:
638                 break;
639
640         case ARPREPLY:
641                 /* check for machine using my ip address */
642                 v4tov6(ip, e->spa);
643                 if(iplocalonifc(ifc, ip) || ipproxyifc(er->f, ifc, ip)){
644                         if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0){
645                                 printd("arprep: 0x%E/0x%E also has ip addr %V\n",
646                                         e->s, e->sha, e->spa);
647                                 break;
648                         }
649                 }
650
651                 /* make sure we're not entering broadcast addresses */
652                 if(ipcmp(ip, ipbroadcast) == 0 ||
653                         !memcmp(e->sha, etherbroadcast, sizeof(e->sha))){
654                         printd("arprep: 0x%E/0x%E cannot register broadcast address %I\n",
655                                 e->s, e->sha, e->spa);
656                         break;
657                 }
658
659                 arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), 0);
660                 break;
661
662         case ARPREQUEST:
663                 /* don't answer arps till we know who we are */
664                 if(ifc->lifc == 0)
665                         break;
666
667                 /* check for machine using my ip or ether address */
668                 v4tov6(ip, e->spa);
669                 if(iplocalonifc(ifc, ip) || ipproxyifc(er->f, ifc, ip)){
670                         if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0){
671                                 if (memcmp(eprinted, e->spa, sizeof(e->spa))){
672                                         /* print only once */
673                                         printd("arpreq: 0x%E also has ip addr %V\n", e->sha, e->spa);
674                                         memmove(eprinted, e->spa, sizeof(e->spa));
675                                 }
676                         }
677                 } else {
678                         if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) == 0){
679                                 printd("arpreq: %V also has ether addr %E\n", e->spa, e->sha);
680                                 break;
681                         }
682                 }
683
684                 /* refresh what we know about sender */
685                 arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), 1);
686
687                 /* answer only requests for our address or systems we're proxying for */
688                 v4tov6(ip, e->tpa);
689                 if(!iplocalonifc(ifc, ip))
690                 if(!ipproxyifc(er->f, ifc, ip))
691                         break;
692
693                 n = sizeof(Etherarp);
694                 if(n < ifc->mintu)
695                         n = ifc->mintu;
696                 rbp = allocb(n);
697                 r = (Etherarp*)rbp->rp;
698                 memset(r, 0, sizeof(Etherarp));
699                 hnputs(r->type, ETARP);
700                 hnputs(r->hrd, 1);
701                 hnputs(r->pro, ETIP4);
702                 r->hln = sizeof(r->sha);
703                 r->pln = sizeof(r->spa);
704                 hnputs(r->op, ARPREPLY);
705                 memmove(r->tha, e->sha, sizeof(r->tha));
706                 memmove(r->tpa, e->spa, sizeof(r->tpa));
707                 memmove(r->sha, ifc->mac, sizeof(r->sha));
708                 memmove(r->spa, e->tpa, sizeof(r->spa));
709                 memmove(r->d, e->sha, sizeof(r->d));
710                 memmove(r->s, ifc->mac, sizeof(r->s));
711                 rbp->wp += n;
712
713                 n = devtab[er->achan->type].bwrite(er->achan, rbp, 0);
714                 if(n < 0)
715                         printd("arp: write: %r\n");
716         }
717         freeb(ebp);
718 }
719
720 static void
721 recvarpproc(void *v)
722 {
723         ERRSTACK(1);
724         struct Ipifc *ifc = v;
725         Etherrock *er = ifc->arg;
726
727         er->arpp = current;
728         if(waserror()){
729                 er->arpp = 0;
730                 warn("recvarpproc returns, probably unexpectedly\n");
731                 poperror();
732                 return;
733         }
734         for(;;)
735                 recvarp(ifc);
736         poperror();
737 }
738
739 static int
740 multicastea(uint8_t *ea, uint8_t *ip)
741 {
742         int x;
743
744         switch(x = ipismulticast(ip)){
745         case V4:
746                 ea[0] = 0x01;
747                 ea[1] = 0x00;
748                 ea[2] = 0x5e;
749                 ea[3] = ip[13] & 0x7f;
750                 ea[4] = ip[14];
751                 ea[5] = ip[15];
752                 break;
753         case V6:
754                 ea[0] = 0x33;
755                 ea[1] = 0x33;
756                 ea[2] = ip[12];
757                 ea[3] = ip[13];
758                 ea[4] = ip[14];
759                 ea[5] = ip[15];
760                 break;
761         }
762         return x;
763 }
764
765 /*
766  *  fill in an arp entry for broadcast or multicast
767  *  addresses.  Return the first queued packet for the
768  *  IP address.
769  */
770 static struct block*
771 multicastarp(struct Fs *f,
772              struct arpent *a, struct medium *medium, uint8_t *mac)
773 {
774         /* is it broadcast? */
775         switch(ipforme(f, a->ip)){
776         case Runi:
777                 return NULL;
778         case Rbcast:
779                 memset(mac, 0xff, 6);
780                 return arpresolve(f->arp, a, medium, mac);
781         default:
782                 break;
783         }
784
785         /* if multicast, fill in mac */
786         switch(multicastea(mac, a->ip)){
787         case V4:
788         case V6:
789                 return arpresolve(f->arp, a, medium, mac);
790         }
791
792         /* let arp take care of it */
793         return NULL;
794 }
795
796 linker_func_4(ethermediumlink)
797 {
798         addipmedium(&ethermedium);
799         addipmedium(&gbemedium);
800 }
801
802
803 static void 
804 etherpref2addr(uint8_t *pref, uint8_t *ea)
805 {
806         pref[8]  = ea[0] | 0x2;
807         pref[9]  = ea[1];
808         pref[10] = ea[2];
809         pref[11] = 0xFF;
810         pref[12] = 0xFE;
811         pref[13] = ea[3];
812         pref[14] = ea[4];
813         pref[15] = ea[5];
814 }