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