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