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