xref: /plan9/sys/src/9/ip/ethermedium.c (revision 3e76a0dd495fe64826c593282484242759e1c6b9)
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 	n = devtab[er->achan->type]->bwrite(er->achan, bp, 0);
503 	if(n < 0)
504 		print("arp: send: %r\n");
505 }
506 
507 static void
508 resolveaddr6(Ipifc *ifc, Arpent *a)
509 {
510 	int sflag;
511 	Block *bp;
512 	Etherrock *er = ifc->arg;
513 	uchar ipsrc[IPaddrlen];
514 
515 	/* don't do anything if it's been less than a second since the last */
516 	if(NOW - a->ctime < ReTransTimer){
517 		arprelease(er->f->arp, a);
518 		return;
519 	}
520 
521 	/* remove all but the last message */
522 	while((bp = a->hold) != nil){
523 		if(bp == a->last)
524 			break;
525 		a->hold = bp->list;
526 		freeblist(bp);
527 	}
528 
529 	/* try to keep it around for a second more */
530 	a->ctime = NOW;
531 	a->rtime = NOW + ReTransTimer;
532 	if(a->rxtsrem <= 0) {
533 		arprelease(er->f->arp, a);
534 		return;
535 	}
536 
537 	a->rxtsrem--;
538 	arprelease(er->f->arp, a);
539 
540 	if(sflag = ipv6anylocal(ifc, ipsrc))
541 		icmpns(er->f, ipsrc, sflag, a->ip, TARG_MULTI, ifc->mac);
542 }
543 
544 /*
545  *  send a gratuitous arp to refresh arp caches
546  */
547 static void
548 sendgarp(Ipifc *ifc, uchar *ip)
549 {
550 	int n;
551 	Block *bp;
552 	Etherarp *e;
553 	Etherrock *er = ifc->arg;
554 
555 	/* don't arp for our initial non address */
556 	if(ipcmp(ip, IPnoaddr) == 0)
557 		return;
558 
559 	n = sizeof(Etherarp);
560 	if(n < ifc->m->mintu)
561 		n = ifc->m->mintu;
562 	bp = allocb(n);
563 	memset(bp->rp, 0, n);
564 	e = (Etherarp*)bp->rp;
565 	memmove(e->tpa, ip+IPv4off, sizeof(e->tpa));
566 	memmove(e->spa, ip+IPv4off, sizeof(e->spa));
567 	memmove(e->sha, ifc->mac, sizeof(e->sha));
568 	memset(e->d, 0xff, sizeof(e->d));		/* ethernet broadcast */
569 	memmove(e->s, ifc->mac, sizeof(e->s));
570 
571 	hnputs(e->type, ETARP);
572 	hnputs(e->hrd, 1);
573 	hnputs(e->pro, ETIP4);
574 	e->hln = sizeof(e->sha);
575 	e->pln = sizeof(e->spa);
576 	hnputs(e->op, ARPREQUEST);
577 	bp->wp += n;
578 
579 	n = devtab[er->achan->type]->bwrite(er->achan, bp, 0);
580 	if(n < 0)
581 		print("garp: send: %r\n");
582 }
583 
584 static void
585 recvarp(Ipifc *ifc)
586 {
587 	int n;
588 	Block *ebp, *rbp;
589 	Etherarp *e, *r;
590 	uchar ip[IPaddrlen];
591 	static uchar eprinted[4];
592 	Etherrock *er = ifc->arg;
593 
594 	ebp = devtab[er->achan->type]->bread(er->achan, ifc->maxtu, 0);
595 	if(ebp == nil) {
596 		print("arp: rcv: %r\n");
597 		return;
598 	}
599 
600 	e = (Etherarp*)ebp->rp;
601 	switch(nhgets(e->op)) {
602 	default:
603 		break;
604 
605 	case ARPREPLY:
606 		/* check for machine using my ip address */
607 		v4tov6(ip, e->spa);
608 		if(iplocalonifc(ifc, ip) || ipproxyifc(er->f, ifc, ip)){
609 			if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0){
610 				print("arprep: 0x%E/0x%E also has ip addr %V\n",
611 					e->s, e->sha, e->spa);
612 				break;
613 			}
614 		}
615 
616 		/* make sure we're not entering broadcast addresses */
617 		if(ipcmp(ip, ipbroadcast) == 0 ||
618 			!memcmp(e->sha, etherbroadcast, sizeof(e->sha))){
619 			print("arprep: 0x%E/0x%E cannot register broadcast address %I\n",
620 				e->s, e->sha, e->spa);
621 			break;
622 		}
623 
624 		arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), 0);
625 		break;
626 
627 	case ARPREQUEST:
628 		/* don't answer arps till we know who we are */
629 		if(ifc->lifc == 0)
630 			break;
631 
632 		/* check for machine using my ip or ether address */
633 		v4tov6(ip, e->spa);
634 		if(iplocalonifc(ifc, ip) || ipproxyifc(er->f, ifc, ip)){
635 			if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0){
636 				if (memcmp(eprinted, e->spa, sizeof(e->spa))){
637 					/* print only once */
638 					print("arpreq: 0x%E also has ip addr %V\n", e->sha, e->spa);
639 					memmove(eprinted, e->spa, sizeof(e->spa));
640 				}
641 			}
642 		} else {
643 			if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) == 0){
644 				print("arpreq: %V also has ether addr %E\n", e->spa, e->sha);
645 				break;
646 			}
647 		}
648 
649 		/* refresh what we know about sender */
650 		arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), 1);
651 
652 		/* answer only requests for our address or systems we're proxying for */
653 		v4tov6(ip, e->tpa);
654 		if(!iplocalonifc(ifc, ip))
655 		if(!ipproxyifc(er->f, ifc, ip))
656 			break;
657 
658 		n = sizeof(Etherarp);
659 		if(n < ifc->mintu)
660 			n = ifc->mintu;
661 		rbp = allocb(n);
662 		r = (Etherarp*)rbp->rp;
663 		memset(r, 0, sizeof(Etherarp));
664 		hnputs(r->type, ETARP);
665 		hnputs(r->hrd, 1);
666 		hnputs(r->pro, ETIP4);
667 		r->hln = sizeof(r->sha);
668 		r->pln = sizeof(r->spa);
669 		hnputs(r->op, ARPREPLY);
670 		memmove(r->tha, e->sha, sizeof(r->tha));
671 		memmove(r->tpa, e->spa, sizeof(r->tpa));
672 		memmove(r->sha, ifc->mac, sizeof(r->sha));
673 		memmove(r->spa, e->tpa, sizeof(r->spa));
674 		memmove(r->d, e->sha, sizeof(r->d));
675 		memmove(r->s, ifc->mac, sizeof(r->s));
676 		rbp->wp += n;
677 
678 		n = devtab[er->achan->type]->bwrite(er->achan, rbp, 0);
679 		if(n < 0)
680 			print("arp: write: %r\n");
681 	}
682 	freeb(ebp);
683 }
684 
685 static void
686 recvarpproc(void *v)
687 {
688 	Ipifc *ifc = v;
689 	Etherrock *er = ifc->arg;
690 
691 	er->arpp = up;
692 	if(waserror()){
693 		er->arpp = 0;
694 		pexit("hangup", 1);
695 	}
696 	for(;;)
697 		recvarp(ifc);
698 }
699 
700 static int
701 multicastea(uchar *ea, uchar *ip)
702 {
703 	int x;
704 
705 	switch(x = ipismulticast(ip)){
706 	case V4:
707 		ea[0] = 0x01;
708 		ea[1] = 0x00;
709 		ea[2] = 0x5e;
710 		ea[3] = ip[13] & 0x7f;
711 		ea[4] = ip[14];
712 		ea[5] = ip[15];
713 		break;
714  	case V6:
715  		ea[0] = 0x33;
716  		ea[1] = 0x33;
717  		ea[2] = ip[12];
718 		ea[3] = ip[13];
719  		ea[4] = ip[14];
720  		ea[5] = ip[15];
721  		break;
722 	}
723 	return x;
724 }
725 
726 /*
727  *  fill in an arp entry for broadcast or multicast
728  *  addresses.  Return the first queued packet for the
729  *  IP address.
730  */
731 static Block*
732 multicastarp(Fs *f, Arpent *a, Medium *medium, uchar *mac)
733 {
734 	/* is it broadcast? */
735 	switch(ipforme(f, a->ip)){
736 	case Runi:
737 		return nil;
738 	case Rbcast:
739 		memset(mac, 0xff, 6);
740 		return arpresolve(f->arp, a, medium, mac);
741 	default:
742 		break;
743 	}
744 
745 	/* if multicast, fill in mac */
746 	switch(multicastea(mac, a->ip)){
747 	case V4:
748 	case V6:
749 		return arpresolve(f->arp, a, medium, mac);
750 	}
751 
752 	/* let arp take care of it */
753 	return nil;
754 }
755 
756 void
757 ethermediumlink(void)
758 {
759 	addipmedium(&ethermedium);
760 	addipmedium(&gbemedium);
761 }
762 
763 
764 static void
765 etherpref2addr(uchar *pref, uchar *ea)
766 {
767 	pref[8]  = ea[0] | 0x2;
768 	pref[9]  = ea[1];
769 	pref[10] = ea[2];
770 	pref[11] = 0xFF;
771 	pref[12] = 0xFE;
772 	pref[13] = ea[3];
773 	pref[14] = ea[4];
774 	pref[15] = ea[5];
775 }
776