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