vx32

Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log | Files | Refs

ethermedium.c (15413B)


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