Use rendez for sleep/wakeup/etc
[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);
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         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 #warning "pexit"
375                 //      pexit("hangup", 1);
376         }
377         for(;;){
378                 bp = devtab[er->mchan4->type]->bread(er->mchan4, ifc->maxtu, 0);
379                 if(!canrlock(&ifc->rwlock)){
380                         freeb(bp);
381                         continue;
382                 }
383                 if(waserror()){
384                         runlock(&ifc->rwlock);
385                         nexterror();
386                 }
387                 ifc->in++;
388                 bp->rp += ifc->m->hsize;
389                 if(ifc->lifc == NULL)
390                         freeb(bp);
391                 else
392                         ipiput4(er->f, ifc, bp);
393                 runlock(&ifc->rwlock);
394                 poperror();
395         }
396 }
397
398
399 /*
400  *  process to read from the ethernet, IPv6
401  */
402 static void
403 etherread6(void *a)
404 {
405         ERRSTACK(2);
406         struct Ipifc *ifc;
407         struct block *bp;
408         Etherrock *er;
409
410         ifc = a;
411         er = ifc->arg;
412         er->read6p = current;   /* hide identity under a rock for unbind */
413         if(waserror()){
414                 er->read6p = 0;
415                 //      pexit("hangup", 1);
416         }
417         for(;;){
418                 bp = devtab[er->mchan6->type]->bread(er->mchan6, ifc->maxtu, 0);
419                 if(!canrlock(&ifc->rwlock)){
420                         freeb(bp);
421                         continue;
422                 }
423                 if(waserror()){
424                         runlock(&ifc->rwlock);
425                         nexterror();
426                 }
427                 ifc->in++;
428                 bp->rp += ifc->m->hsize;
429                 if(ifc->lifc == NULL)
430                         freeb(bp);
431                 else
432                         ipiput6(er->f, ifc, bp);
433                 runlock(&ifc->rwlock);
434                 poperror();
435         }
436 }
437
438 static void
439 etheraddmulti(struct Ipifc *ifc, uint8_t *a, uint8_t *unused)
440 {
441         uint8_t mac[6];
442         char buf[64];
443         Etherrock *er = ifc->arg;
444         int version;
445
446         version = multicastea(mac, a);
447         snprintf(buf, sizeof(buf), "addmulti %E", mac);
448         switch(version){
449         case V4:
450                 devtab[er->cchan4->type]->write(er->cchan4, buf, strlen(buf), 0);
451                 break;
452         case V6:
453                 devtab[er->cchan6->type]->write(er->cchan6, buf, strlen(buf), 0);
454                 break;
455         default:
456                 panic("etheraddmulti: version %d", version);
457         }
458 }
459
460 static void
461 etherremmulti(struct Ipifc *ifc, uint8_t *a, uint8_t *unused)
462 {
463         uint8_t mac[6];
464         char buf[64];
465         Etherrock *er = ifc->arg;
466         int version;
467
468         version = multicastea(mac, a);
469         snprintf(buf, sizeof(buf), "remmulti %E", mac);
470         switch(version){
471         case V4:
472                 devtab[er->cchan4->type]->write(er->cchan4, buf, strlen(buf), 0);
473                 break;
474         case V6:
475                 devtab[er->cchan6->type]->write(er->cchan6, buf, strlen(buf), 0);
476                 break;
477         default:
478                 panic("etherremmulti: version %d", version);
479         }
480 }
481
482 /*
483  *  send an ethernet arp
484  *  (only v4, v6 uses the neighbor discovery, rfc1970)
485  */
486 static void
487 sendarp(struct Ipifc *ifc, struct arpent *a)
488 {
489         int n;
490         struct block *bp;
491         Etherarp *e;
492         Etherrock *er = ifc->arg;
493
494         /* don't do anything if it's been less than a second since the last */
495         if(NOW - a->ctime < 1000){
496                 arprelease(er->f->arp, a);
497                 return;
498         }
499
500         /* remove all but the last message */
501         while((bp = a->hold) != NULL){
502                 if(bp == a->last)
503                         break;
504                 a->hold = bp->list;
505                 freeblist(bp);
506         }
507
508         /* try to keep it around for a second more */
509         a->ctime = NOW;
510         arprelease(er->f->arp, a);
511
512         n = sizeof(Etherarp);
513         if(n < a->type->mintu)
514                 n = a->type->mintu;
515         bp = allocb(n);
516         memset(bp->rp, 0, n);
517         e = (Etherarp*)bp->rp;
518         memmove(e->tpa, a->ip+IPv4off, sizeof(e->tpa));
519         ipv4local(ifc, e->spa);
520         memmove(e->sha, ifc->mac, sizeof(e->sha));
521         memset(e->d, 0xff, sizeof(e->d));               /* ethernet broadcast */
522         memmove(e->s, ifc->mac, sizeof(e->s));
523
524         hnputs(e->type, ETARP);
525         hnputs(e->hrd, 1);
526         hnputs(e->pro, ETIP4);
527         e->hln = sizeof(e->sha);
528         e->pln = sizeof(e->spa);
529         hnputs(e->op, ARPREQUEST);
530         bp->wp += n;
531
532         n = devtab[er->achan->type]->bwrite(er->achan, bp, 0);
533         if(n < 0)
534                 printd("arp: send: %r\n");
535 }
536
537 static void
538 resolveaddr6(struct Ipifc *ifc, struct arpent *a)
539 {
540         int sflag;
541         struct block *bp;
542         Etherrock *er = ifc->arg;
543         uint8_t ipsrc[IPaddrlen];
544
545         /* don't do anything if it's been less than a second since the last */
546         if(NOW - a->ctime < ReTransTimer){
547                 arprelease(er->f->arp, a);
548                 return;
549         }
550
551         /* remove all but the last message */
552         while((bp = a->hold) != NULL){
553                 if(bp == a->last)
554                         break;
555                 a->hold = bp->list;
556                 freeblist(bp);
557         }
558
559         /* try to keep it around for a second more */
560         a->ctime = NOW;
561         a->rtime = NOW + ReTransTimer;
562         if(a->rxtsrem <= 0) {
563                 arprelease(er->f->arp, a);
564                 return;
565         }
566
567         a->rxtsrem--;
568         arprelease(er->f->arp, a);
569
570         if((sflag = ipv6anylocal(ifc, ipsrc)) )
571                 icmpns(er->f, ipsrc, sflag, a->ip, TARG_MULTI, ifc->mac);
572 }
573
574 /*
575  *  send a gratuitous arp to refresh arp caches
576  */
577 static void
578 sendgarp(struct Ipifc *ifc, uint8_t *ip)
579 {
580         int n;
581         struct block *bp;
582         Etherarp *e;
583         Etherrock *er = ifc->arg;
584
585         /* don't arp for our initial non address */
586         if(ipcmp(ip, IPnoaddr) == 0)
587                 return;
588
589         n = sizeof(Etherarp);
590         if(n < ifc->m->mintu)
591                 n = ifc->m->mintu;
592         bp = allocb(n);
593         memset(bp->rp, 0, n);
594         e = (Etherarp*)bp->rp;
595         memmove(e->tpa, ip+IPv4off, sizeof(e->tpa));
596         memmove(e->spa, ip+IPv4off, sizeof(e->spa));
597         memmove(e->sha, ifc->mac, sizeof(e->sha));
598         memset(e->d, 0xff, sizeof(e->d));               /* ethernet broadcast */
599         memmove(e->s, ifc->mac, sizeof(e->s));
600
601         hnputs(e->type, ETARP);
602         hnputs(e->hrd, 1);
603         hnputs(e->pro, ETIP4);
604         e->hln = sizeof(e->sha);
605         e->pln = sizeof(e->spa);
606         hnputs(e->op, ARPREQUEST);
607         bp->wp += n;
608
609         n = devtab[er->achan->type]->bwrite(er->achan, bp, 0);
610         if(n < 0)
611                 printd("garp: send: %r\n");
612 }
613
614 static void
615 recvarp(struct Ipifc *ifc)
616 {
617         int n;
618         struct block *ebp, *rbp;
619         Etherarp *e, *r;
620         uint8_t ip[IPaddrlen];
621         static uint8_t eprinted[4];
622         Etherrock *er = ifc->arg;
623
624         ebp = devtab[er->achan->type]->bread(er->achan, ifc->maxtu, 0);
625         if(ebp == NULL) {
626                 printd("arp: rcv: %r\n");
627                 return;
628         }
629
630         e = (Etherarp*)ebp->rp;
631         switch(nhgets(e->op)) {
632         default:
633                 break;
634
635         case ARPREPLY:
636                 /* check for machine using my ip address */
637                 v4tov6(ip, e->spa);
638                 if(iplocalonifc(ifc, ip) || ipproxyifc(er->f, ifc, ip)){
639                         if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0){
640                                 printd("arprep: 0x%E/0x%E also has ip addr %V\n",
641                                         e->s, e->sha, e->spa);
642                                 break;
643                         }
644                 }
645
646                 /* make sure we're not entering broadcast addresses */
647                 if(ipcmp(ip, ipbroadcast) == 0 ||
648                         !memcmp(e->sha, etherbroadcast, sizeof(e->sha))){
649                         printd("arprep: 0x%E/0x%E cannot register broadcast address %I\n",
650                                 e->s, e->sha, e->spa);
651                         break;
652                 }
653
654                 arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), 0);
655                 break;
656
657         case ARPREQUEST:
658                 /* don't answer arps till we know who we are */
659                 if(ifc->lifc == 0)
660                         break;
661
662                 /* check for machine using my ip or ether address */
663                 v4tov6(ip, e->spa);
664                 if(iplocalonifc(ifc, ip) || ipproxyifc(er->f, ifc, ip)){
665                         if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0){
666                                 if (memcmp(eprinted, e->spa, sizeof(e->spa))){
667                                         /* print only once */
668                                         printd("arpreq: 0x%E also has ip addr %V\n", e->sha, e->spa);
669                                         memmove(eprinted, e->spa, sizeof(e->spa));
670                                 }
671                         }
672                 } else {
673                         if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) == 0){
674                                 printd("arpreq: %V also has ether addr %E\n", e->spa, e->sha);
675                                 break;
676                         }
677                 }
678
679                 /* refresh what we know about sender */
680                 arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), 1);
681
682                 /* answer only requests for our address or systems we're proxying for */
683                 v4tov6(ip, e->tpa);
684                 if(!iplocalonifc(ifc, ip))
685                 if(!ipproxyifc(er->f, ifc, ip))
686                         break;
687
688                 n = sizeof(Etherarp);
689                 if(n < ifc->mintu)
690                         n = ifc->mintu;
691                 rbp = allocb(n);
692                 r = (Etherarp*)rbp->rp;
693                 memset(r, 0, sizeof(Etherarp));
694                 hnputs(r->type, ETARP);
695                 hnputs(r->hrd, 1);
696                 hnputs(r->pro, ETIP4);
697                 r->hln = sizeof(r->sha);
698                 r->pln = sizeof(r->spa);
699                 hnputs(r->op, ARPREPLY);
700                 memmove(r->tha, e->sha, sizeof(r->tha));
701                 memmove(r->tpa, e->spa, sizeof(r->tpa));
702                 memmove(r->sha, ifc->mac, sizeof(r->sha));
703                 memmove(r->spa, e->tpa, sizeof(r->spa));
704                 memmove(r->d, e->sha, sizeof(r->d));
705                 memmove(r->s, ifc->mac, sizeof(r->s));
706                 rbp->wp += n;
707
708                 n = devtab[er->achan->type]->bwrite(er->achan, rbp, 0);
709                 if(n < 0)
710                         printd("arp: write: %r\n");
711         }
712         freeb(ebp);
713 }
714
715 static void
716 recvarpproc(void *v)
717 {
718         ERRSTACK(2);
719         struct Ipifc *ifc = v;
720         Etherrock *er = ifc->arg;
721
722         er->arpp = current;
723         if(waserror()){
724                 er->arpp = 0;
725                 //      pexit("hangup", 1);
726         }
727         for(;;)
728                 recvarp(ifc);
729 }
730
731 static int
732 multicastea(uint8_t *ea, uint8_t *ip)
733 {
734         int x;
735
736         switch(x = ipismulticast(ip)){
737         case V4:
738                 ea[0] = 0x01;
739                 ea[1] = 0x00;
740                 ea[2] = 0x5e;
741                 ea[3] = ip[13] & 0x7f;
742                 ea[4] = ip[14];
743                 ea[5] = ip[15];
744                 break;
745         case V6:
746                 ea[0] = 0x33;
747                 ea[1] = 0x33;
748                 ea[2] = ip[12];
749                 ea[3] = ip[13];
750                 ea[4] = ip[14];
751                 ea[5] = ip[15];
752                 break;
753         }
754         return x;
755 }
756
757 /*
758  *  fill in an arp entry for broadcast or multicast
759  *  addresses.  Return the first queued packet for the
760  *  IP address.
761  */
762 static struct block*
763 multicastarp(struct Fs *f,
764              struct arpent *a, struct medium *medium, uint8_t *mac)
765 {
766         /* is it broadcast? */
767         switch(ipforme(f, a->ip)){
768         case Runi:
769                 return NULL;
770         case Rbcast:
771                 memset(mac, 0xff, 6);
772                 return arpresolve(f->arp, a, medium, mac);
773         default:
774                 break;
775         }
776
777         /* if multicast, fill in mac */
778         switch(multicastea(mac, a->ip)){
779         case V4:
780         case V6:
781                 return arpresolve(f->arp, a, medium, mac);
782         }
783
784         /* let arp take care of it */
785         return NULL;
786 }
787
788 void
789 ethermediumlink(void)
790 {
791         addipmedium(&ethermedium);
792         addipmedium(&gbemedium);
793 }
794
795
796 static void 
797 etherpref2addr(uint8_t *pref, uint8_t *ea)
798 {
799         pref[8]  = ea[0] | 0x2;
800         pref[9]  = ea[1];
801         pref[10] = ea[2];
802         pref[11] = 0xFF;
803         pref[12] = 0xFE;
804         pref[13] = ea[3];
805         pref[14] = ea[4];
806         pref[15] = ea[5];
807 }