xref: /plan9/sys/src/9/ip/ethermedium.c (revision 3432ceae96058d5ba10cbd0086cd176f7049f3d3)
17dd7cddfSDavid du Colombier #include "u.h"
27dd7cddfSDavid du Colombier #include "../port/lib.h"
37dd7cddfSDavid du Colombier #include "mem.h"
47dd7cddfSDavid du Colombier #include "dat.h"
57dd7cddfSDavid du Colombier #include "fns.h"
67dd7cddfSDavid du Colombier #include "../port/error.h"
77dd7cddfSDavid du Colombier 
87dd7cddfSDavid du Colombier #include "ip.h"
93ff48bf5SDavid du Colombier #include "ipv6.h"
107dd7cddfSDavid du Colombier 
117dd7cddfSDavid du Colombier typedef struct Etherhdr Etherhdr;
127dd7cddfSDavid du Colombier struct Etherhdr
137dd7cddfSDavid du Colombier {
147dd7cddfSDavid du Colombier 	uchar	d[6];
157dd7cddfSDavid du Colombier 	uchar	s[6];
167dd7cddfSDavid du Colombier 	uchar	t[2];
177dd7cddfSDavid du Colombier };
187dd7cddfSDavid du Colombier 
193ff48bf5SDavid du Colombier static void	etherread4(void *a);
203ff48bf5SDavid du Colombier static void	etherread6(void *a);
217dd7cddfSDavid du Colombier static void	etherbind(Ipifc *ifc, int argc, char **argv);
227dd7cddfSDavid du Colombier static void	etherunbind(Ipifc *ifc);
237dd7cddfSDavid du Colombier static void	etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip);
247dd7cddfSDavid du Colombier static void	etheraddmulti(Ipifc *ifc, uchar *a, uchar *ia);
257dd7cddfSDavid du Colombier static void	etherremmulti(Ipifc *ifc, uchar *a, uchar *ia);
2659cc4ca5SDavid du Colombier static Block*	multicastarp(Fs *f, Arpent *a, Medium*, uchar *mac);
277dd7cddfSDavid du Colombier static void	sendarp(Ipifc *ifc, Arpent *a);
287dd7cddfSDavid du Colombier static void	sendgarp(Ipifc *ifc, uchar*);
297dd7cddfSDavid du Colombier static int	multicastea(uchar *ea, uchar *ip);
307dd7cddfSDavid du Colombier static void	recvarpproc(void*);
313ff48bf5SDavid du Colombier static void	resolveaddr6(Ipifc *ifc, Arpent *a);
323ff48bf5SDavid du Colombier static void	etherpref2addr(uchar *pref, uchar *ea);
337dd7cddfSDavid du Colombier 
347dd7cddfSDavid du Colombier Medium ethermedium =
357dd7cddfSDavid du Colombier {
367dd7cddfSDavid du Colombier .name=		"ether",
377dd7cddfSDavid du Colombier .hsize=		14,
383f695129SDavid du Colombier .mintu=		60,
393f695129SDavid du Colombier .maxtu=		1514,
407dd7cddfSDavid du Colombier .maclen=	6,
417dd7cddfSDavid du Colombier .bind=		etherbind,
427dd7cddfSDavid du Colombier .unbind=	etherunbind,
437dd7cddfSDavid du Colombier .bwrite=	etherbwrite,
447dd7cddfSDavid du Colombier .addmulti=	etheraddmulti,
457dd7cddfSDavid du Colombier .remmulti=	etherremmulti,
467dd7cddfSDavid du Colombier .ares=		arpenter,
477dd7cddfSDavid du Colombier .areg=		sendgarp,
483ff48bf5SDavid du Colombier .pref2addr=	etherpref2addr,
497dd7cddfSDavid du Colombier };
507dd7cddfSDavid du Colombier 
5159cc4ca5SDavid du Colombier Medium gbemedium =
5259cc4ca5SDavid du Colombier {
5359cc4ca5SDavid du Colombier .name=		"gbe",
5459cc4ca5SDavid du Colombier .hsize=		14,
553f695129SDavid du Colombier .mintu=		60,
563f695129SDavid du Colombier .maxtu=		9014,
5759cc4ca5SDavid du Colombier .maclen=	6,
5859cc4ca5SDavid du Colombier .bind=		etherbind,
5959cc4ca5SDavid du Colombier .unbind=	etherunbind,
6059cc4ca5SDavid du Colombier .bwrite=	etherbwrite,
6159cc4ca5SDavid du Colombier .addmulti=	etheraddmulti,
6259cc4ca5SDavid du Colombier .remmulti=	etherremmulti,
6359cc4ca5SDavid du Colombier .ares=		arpenter,
6459cc4ca5SDavid du Colombier .areg=		sendgarp,
653ff48bf5SDavid du Colombier .pref2addr=	etherpref2addr,
6659cc4ca5SDavid du Colombier };
6759cc4ca5SDavid du Colombier 
687dd7cddfSDavid du Colombier typedef struct	Etherrock Etherrock;
697dd7cddfSDavid du Colombier struct Etherrock
707dd7cddfSDavid du Colombier {
717dd7cddfSDavid du Colombier 	Fs	*f;		/* file system we belong to */
727dd7cddfSDavid du Colombier 	Proc	*arpp;		/* arp process */
733ff48bf5SDavid du Colombier 	Proc	*read4p;	/* reading process (v4)*/
743ff48bf5SDavid du Colombier 	Proc	*read6p;	/* reading process (v6)*/
753ff48bf5SDavid du Colombier 	Chan	*mchan4;	/* Data channel for v4 */
767dd7cddfSDavid du Colombier 	Chan	*achan;		/* Arp channel */
773ff48bf5SDavid du Colombier 	Chan	*cchan4;	/* Control channel for v4 */
783ff48bf5SDavid du Colombier 	Chan	*mchan6;	/* Data channel for v6 */
793ff48bf5SDavid du Colombier 	Chan	*cchan6;	/* Control channel for v6 */
807dd7cddfSDavid du Colombier };
817dd7cddfSDavid du Colombier 
827dd7cddfSDavid du Colombier /*
837dd7cddfSDavid du Colombier  *  ethernet arp request
847dd7cddfSDavid du Colombier  */
857dd7cddfSDavid du Colombier enum
867dd7cddfSDavid du Colombier {
877dd7cddfSDavid du Colombier 	ETARP		= 0x0806,
883ff48bf5SDavid du Colombier 	ETIP4		= 0x0800,
893ff48bf5SDavid du Colombier 	ETIP6		= 0x86DD,
907dd7cddfSDavid du Colombier 	ARPREQUEST	= 1,
917dd7cddfSDavid du Colombier 	ARPREPLY	= 2,
927dd7cddfSDavid du Colombier };
933ff48bf5SDavid du Colombier 
947dd7cddfSDavid du Colombier typedef struct Etherarp Etherarp;
957dd7cddfSDavid du Colombier struct Etherarp
967dd7cddfSDavid du Colombier {
977dd7cddfSDavid du Colombier 	uchar	d[6];
987dd7cddfSDavid du Colombier 	uchar	s[6];
997dd7cddfSDavid du Colombier 	uchar	type[2];
1007dd7cddfSDavid du Colombier 	uchar	hrd[2];
1017dd7cddfSDavid du Colombier 	uchar	pro[2];
1027dd7cddfSDavid du Colombier 	uchar	hln;
1037dd7cddfSDavid du Colombier 	uchar	pln;
1047dd7cddfSDavid du Colombier 	uchar	op[2];
1057dd7cddfSDavid du Colombier 	uchar	sha[6];
1067dd7cddfSDavid du Colombier 	uchar	spa[4];
1077dd7cddfSDavid du Colombier 	uchar	tha[6];
1087dd7cddfSDavid du Colombier 	uchar	tpa[4];
1097dd7cddfSDavid du Colombier };
1107dd7cddfSDavid du Colombier 
1113ff48bf5SDavid du Colombier static char *nbmsg = "nonblocking";
1127dd7cddfSDavid du Colombier 
1137dd7cddfSDavid du Colombier /*
1147dd7cddfSDavid du Colombier  *  called to bind an IP ifc to an ethernet device
1157dd7cddfSDavid du Colombier  *  called with ifc wlock'd
1167dd7cddfSDavid du Colombier  */
1177dd7cddfSDavid du Colombier static void
1187dd7cddfSDavid du Colombier etherbind(Ipifc *ifc, int argc, char **argv)
1197dd7cddfSDavid du Colombier {
1203ff48bf5SDavid du Colombier 	Chan *mchan4, *cchan4, *achan, *mchan6, *cchan6, *schan;
1213ff48bf5SDavid du Colombier 	char addr[Maxpath];	//char addr[2*KNAMELEN];
1223ff48bf5SDavid du Colombier 	char dir[Maxpath];	//char dir[2*KNAMELEN];
1237dd7cddfSDavid du Colombier 	char *buf;
12480ee5cbfSDavid du Colombier 	int n;
1257dd7cddfSDavid du Colombier 	char *ptr;
1267dd7cddfSDavid du Colombier 	Etherrock *er;
1277dd7cddfSDavid du Colombier 
1287dd7cddfSDavid du Colombier 	if(argc < 2)
1297dd7cddfSDavid du Colombier 		error(Ebadarg);
1307dd7cddfSDavid du Colombier 
1313ff48bf5SDavid du Colombier 	mchan4 = cchan4 = achan = mchan6 = cchan6 = nil;
1327dd7cddfSDavid du Colombier 	buf = nil;
1337dd7cddfSDavid du Colombier 	if(waserror()){
1343ff48bf5SDavid du Colombier 		if(mchan4 != nil)
1353ff48bf5SDavid du Colombier 			cclose(mchan4);
1363ff48bf5SDavid du Colombier 		if(cchan4 != nil)
1373ff48bf5SDavid du Colombier 			cclose(cchan4);
1387dd7cddfSDavid du Colombier 		if(achan != nil)
1397dd7cddfSDavid du Colombier 			cclose(achan);
1403ff48bf5SDavid du Colombier 		if(mchan6 != nil)
1413ff48bf5SDavid du Colombier 			cclose(mchan6);
1423ff48bf5SDavid du Colombier 		if(cchan6 != nil)
1433ff48bf5SDavid du Colombier 			cclose(cchan6);
1447dd7cddfSDavid du Colombier 		if(buf != nil)
1457dd7cddfSDavid du Colombier 			free(buf);
1467dd7cddfSDavid du Colombier 		nexterror();
1477dd7cddfSDavid du Colombier 	}
1487dd7cddfSDavid du Colombier 
1497dd7cddfSDavid du Colombier 	/*
1503ff48bf5SDavid du Colombier 	 *  open ip converstation
1517dd7cddfSDavid du Colombier 	 *
1527dd7cddfSDavid du Colombier 	 *  the dial will fail if the type is already open on
1537dd7cddfSDavid du Colombier 	 *  this device.
1547dd7cddfSDavid du Colombier 	 */
1557dd7cddfSDavid du Colombier 	snprint(addr, sizeof(addr), "%s!0x800", argv[2]);
1563ff48bf5SDavid du Colombier 	mchan4 = chandial(addr, nil, dir, &cchan4);
1573ff48bf5SDavid du Colombier 
1583ff48bf5SDavid du Colombier 	/*
1593ff48bf5SDavid du Colombier 	 *  make it non-blocking
1603ff48bf5SDavid du Colombier 	 */
1613ff48bf5SDavid du Colombier 	devtab[cchan4->type]->write(cchan4, nbmsg, strlen(nbmsg), 0);
1627dd7cddfSDavid du Colombier 
1637dd7cddfSDavid du Colombier 	/*
1643f695129SDavid du Colombier 	 *  get mac address and speed
1657dd7cddfSDavid du Colombier 	 */
166*3432ceaeSDavid du Colombier 	snprint(addr, sizeof(addr), "%s/stats", argv[2]);
1677dd7cddfSDavid du Colombier 	buf = smalloc(512);
1683ff48bf5SDavid du Colombier 	schan = namec(addr, Aopen, OREAD, 0);
1693ff48bf5SDavid du Colombier 	if(waserror()){
1703ff48bf5SDavid du Colombier 		cclose(schan);
1713ff48bf5SDavid du Colombier 		nexterror();
1723ff48bf5SDavid du Colombier 	}
1733ff48bf5SDavid du Colombier 	n = devtab[schan->type]->read(schan, buf, 511, 0);
1743ff48bf5SDavid du Colombier 	cclose(schan);
1753ff48bf5SDavid du Colombier 	poperror();
1767dd7cddfSDavid du Colombier 	buf[n] = 0;
1777dd7cddfSDavid du Colombier 
1787dd7cddfSDavid du Colombier 	ptr = strstr(buf, "addr: ");
1797dd7cddfSDavid du Colombier 	if(!ptr)
1807dd7cddfSDavid du Colombier 		error(Eio);
1817dd7cddfSDavid du Colombier 	ptr += 6;
1827dd7cddfSDavid du Colombier 	parsemac(ifc->mac, ptr, 6);
1837dd7cddfSDavid du Colombier 
1843f695129SDavid du Colombier 	ptr = strstr(buf, "mbps: ");
1853f695129SDavid du Colombier 	if(ptr){
1863f695129SDavid du Colombier 		ptr += 6;
1873f695129SDavid du Colombier 		ifc->mbps = atoi(ptr);
1883f695129SDavid du Colombier 	} else
1893f695129SDavid du Colombier 		ifc->mbps = 100;
1903f695129SDavid du Colombier 
1917dd7cddfSDavid du Colombier 	/*
1927dd7cddfSDavid du Colombier  	 *  open arp conversation
1937dd7cddfSDavid du Colombier 	 */
1947dd7cddfSDavid du Colombier 	snprint(addr, sizeof(addr), "%s!0x806", argv[2]);
19580ee5cbfSDavid du Colombier 	achan = chandial(addr, nil, nil, nil);
1967dd7cddfSDavid du Colombier 
1973ff48bf5SDavid du Colombier 	/*
1983ff48bf5SDavid du Colombier 	 *  open ip conversation
1993ff48bf5SDavid du Colombier 	 *
2003ff48bf5SDavid du Colombier 	 *  the dial will fail if the type is already open on
2013ff48bf5SDavid du Colombier 	 *  this device.
2023ff48bf5SDavid du Colombier 	 */
2033ff48bf5SDavid du Colombier 	snprint(addr, sizeof(addr), "%s!0x86DD", argv[2]);
2043ff48bf5SDavid du Colombier 	mchan6 = chandial(addr, nil, dir, &cchan6);
2053ff48bf5SDavid du Colombier 
2063ff48bf5SDavid du Colombier 	/*
2073ff48bf5SDavid du Colombier 	 *  make it non-blocking
2083ff48bf5SDavid du Colombier 	 */
2093ff48bf5SDavid du Colombier 	devtab[cchan6->type]->write(cchan6, nbmsg, strlen(nbmsg), 0);
2103ff48bf5SDavid du Colombier 
2117dd7cddfSDavid du Colombier 	er = smalloc(sizeof(*er));
2123ff48bf5SDavid du Colombier 	er->mchan4 = mchan4;
2133ff48bf5SDavid du Colombier 	er->cchan4 = cchan4;
2147dd7cddfSDavid du Colombier 	er->achan = achan;
2153ff48bf5SDavid du Colombier 	er->mchan6 = mchan6;
2163ff48bf5SDavid du Colombier 	er->cchan6 = cchan6;
2177dd7cddfSDavid du Colombier 	er->f = ifc->conv->p->f;
2187dd7cddfSDavid du Colombier 	ifc->arg = er;
2197dd7cddfSDavid du Colombier 
2207dd7cddfSDavid du Colombier 	free(buf);
2217dd7cddfSDavid du Colombier 	poperror();
2227dd7cddfSDavid du Colombier 
2233ff48bf5SDavid du Colombier 	kproc("etherread4", etherread4, ifc);
2247dd7cddfSDavid du Colombier 	kproc("recvarpproc", recvarpproc, ifc);
2253ff48bf5SDavid du Colombier 	kproc("etherread6", etherread6, ifc);
2267dd7cddfSDavid du Colombier }
2277dd7cddfSDavid du Colombier 
2287dd7cddfSDavid du Colombier /*
2297dd7cddfSDavid du Colombier  *  called with ifc wlock'd
2307dd7cddfSDavid du Colombier  */
2317dd7cddfSDavid du Colombier static void
2327dd7cddfSDavid du Colombier etherunbind(Ipifc *ifc)
2337dd7cddfSDavid du Colombier {
2347dd7cddfSDavid du Colombier 	Etherrock *er = ifc->arg;
2357dd7cddfSDavid du Colombier 
2363ff48bf5SDavid du Colombier 	if(er->read4p)
2373ff48bf5SDavid du Colombier 		postnote(er->read4p, 1, "unbind", 0);
2383ff48bf5SDavid du Colombier 	if(er->read6p)
2393ff48bf5SDavid du Colombier 		postnote(er->read6p, 1, "unbind", 0);
2407dd7cddfSDavid du Colombier 	if(er->arpp)
2417dd7cddfSDavid du Colombier 		postnote(er->arpp, 1, "unbind", 0);
2427dd7cddfSDavid du Colombier 
2437dd7cddfSDavid du Colombier 	/* wait for readers to die */
2443ff48bf5SDavid du Colombier 	while(er->arpp != 0 || er->read4p != 0 || er->read6p != 0)
2457dd7cddfSDavid du Colombier 		tsleep(&up->sleep, return0, 0, 300);
2467dd7cddfSDavid du Colombier 
2473ff48bf5SDavid du Colombier 	if(er->mchan4 != nil)
2483ff48bf5SDavid du Colombier 		cclose(er->mchan4);
2497dd7cddfSDavid du Colombier 	if(er->achan != nil)
2507dd7cddfSDavid du Colombier 		cclose(er->achan);
2513ff48bf5SDavid du Colombier 	if(er->cchan4 != nil)
2523ff48bf5SDavid du Colombier 		cclose(er->cchan4);
2533ff48bf5SDavid du Colombier 	if(er->mchan6 != nil)
2543ff48bf5SDavid du Colombier 		cclose(er->mchan6);
2553ff48bf5SDavid du Colombier 	if(er->cchan6 != nil)
2563ff48bf5SDavid du Colombier 		cclose(er->cchan6);
2577dd7cddfSDavid du Colombier 
2587dd7cddfSDavid du Colombier 	free(er);
2597dd7cddfSDavid du Colombier }
2607dd7cddfSDavid du Colombier 
2617dd7cddfSDavid du Colombier /*
2627dd7cddfSDavid du Colombier  *  called by ipoput with a single block to write with ifc rlock'd
2637dd7cddfSDavid du Colombier  */
2647dd7cddfSDavid du Colombier static void
2657dd7cddfSDavid du Colombier etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip)
2667dd7cddfSDavid du Colombier {
2677dd7cddfSDavid du Colombier 	Etherhdr *eh;
2687dd7cddfSDavid du Colombier 	Arpent *a;
2697dd7cddfSDavid du Colombier 	uchar mac[6];
2707dd7cddfSDavid du Colombier 	Etherrock *er = ifc->arg;
2717dd7cddfSDavid du Colombier 
2727dd7cddfSDavid du Colombier 	/* get mac address of destination */
2733ff48bf5SDavid du Colombier 	a = arpget(er->f->arp, bp, version, ifc, ip, mac);
2747dd7cddfSDavid du Colombier 	if(a){
2757dd7cddfSDavid du Colombier 		/* check for broadcast or multicast */
27659cc4ca5SDavid du Colombier 		bp = multicastarp(er->f, a, ifc->m, mac);
2777dd7cddfSDavid du Colombier 		if(bp==nil){
2783ff48bf5SDavid du Colombier 			switch(version){
2793ff48bf5SDavid du Colombier 			case V4:
2807dd7cddfSDavid du Colombier 				sendarp(ifc, a);
2813ff48bf5SDavid du Colombier 				break;
2823ff48bf5SDavid du Colombier 			case V6:
2833ff48bf5SDavid du Colombier 				resolveaddr6(ifc, a);
2843ff48bf5SDavid du Colombier 				break;
2853ff48bf5SDavid du Colombier 			default:
2863ff48bf5SDavid du Colombier 				panic("etherbwrite: version %d", version);
2873ff48bf5SDavid du Colombier 			}
2887dd7cddfSDavid du Colombier 			return;
2897dd7cddfSDavid du Colombier 		}
2907dd7cddfSDavid du Colombier 	}
2917dd7cddfSDavid du Colombier 
2927dd7cddfSDavid du Colombier 	/* make it a single block with space for the ether header */
2937dd7cddfSDavid du Colombier 	bp = padblock(bp, ifc->m->hsize);
2947dd7cddfSDavid du Colombier 	if(bp->next)
2957dd7cddfSDavid du Colombier 		bp = concatblock(bp);
2963f695129SDavid du Colombier 	if(BLEN(bp) < ifc->mintu)
2973f695129SDavid du Colombier 		bp = adjustblock(bp, ifc->mintu);
2987dd7cddfSDavid du Colombier 	eh = (Etherhdr*)bp->rp;
2997dd7cddfSDavid du Colombier 
3007dd7cddfSDavid du Colombier 	/* copy in mac addresses and ether type */
3017dd7cddfSDavid du Colombier 	memmove(eh->s, ifc->mac, sizeof(eh->s));
3027dd7cddfSDavid du Colombier 	memmove(eh->d, mac, sizeof(eh->d));
3033ff48bf5SDavid du Colombier 
3047dd7cddfSDavid du Colombier  	switch(version){
3057dd7cddfSDavid du Colombier 	case V4:
3067dd7cddfSDavid du Colombier 		eh->t[0] = 0x08;
3077dd7cddfSDavid du Colombier 		eh->t[1] = 0x00;
3083ff48bf5SDavid du Colombier 		devtab[er->mchan4->type]->bwrite(er->mchan4, bp, 0);
3097dd7cddfSDavid du Colombier 		break;
3107dd7cddfSDavid du Colombier 	case V6:
3117dd7cddfSDavid du Colombier 		eh->t[0] = 0x86;
3127dd7cddfSDavid du Colombier 		eh->t[1] = 0xDD;
3133ff48bf5SDavid du Colombier 		devtab[er->mchan6->type]->bwrite(er->mchan6, bp, 0);
3147dd7cddfSDavid du Colombier 		break;
3153ff48bf5SDavid du Colombier 	default:
3163ff48bf5SDavid du Colombier 		panic("etherbwrite2: version %d", version);
3177dd7cddfSDavid du Colombier 	}
3187dd7cddfSDavid du Colombier 	ifc->out++;
3197dd7cddfSDavid du Colombier }
3207dd7cddfSDavid du Colombier 
3213ff48bf5SDavid du Colombier 
3227dd7cddfSDavid du Colombier /*
3237dd7cddfSDavid du Colombier  *  process to read from the ethernet
3247dd7cddfSDavid du Colombier  */
3257dd7cddfSDavid du Colombier static void
3263ff48bf5SDavid du Colombier etherread4(void *a)
3277dd7cddfSDavid du Colombier {
3287dd7cddfSDavid du Colombier 	Ipifc *ifc;
3297dd7cddfSDavid du Colombier 	Block *bp;
3307dd7cddfSDavid du Colombier 	Etherrock *er;
3317dd7cddfSDavid du Colombier 
3327dd7cddfSDavid du Colombier 	ifc = a;
3337dd7cddfSDavid du Colombier 	er = ifc->arg;
3343ff48bf5SDavid du Colombier 	er->read4p = up;	/* hide identity under a rock for unbind */
3357dd7cddfSDavid du Colombier 	if(waserror()){
3363ff48bf5SDavid du Colombier 		er->read4p = 0;
3377dd7cddfSDavid du Colombier 		pexit("hangup", 1);
3387dd7cddfSDavid du Colombier 	}
3397dd7cddfSDavid du Colombier 	for(;;){
3403f695129SDavid du Colombier 		bp = devtab[er->mchan4->type]->bread(er->mchan4, ifc->maxtu, 0);
3417dd7cddfSDavid du Colombier 		if(!canrlock(ifc)){
3427dd7cddfSDavid du Colombier 			freeb(bp);
3437dd7cddfSDavid du Colombier 			continue;
3447dd7cddfSDavid du Colombier 		}
3457dd7cddfSDavid du Colombier 		if(waserror()){
3467dd7cddfSDavid du Colombier 			runlock(ifc);
3477dd7cddfSDavid du Colombier 			nexterror();
3487dd7cddfSDavid du Colombier 		}
3497dd7cddfSDavid du Colombier 		ifc->in++;
3507dd7cddfSDavid du Colombier 		bp->rp += ifc->m->hsize;
3517dd7cddfSDavid du Colombier 		if(ifc->lifc == nil)
3527dd7cddfSDavid du Colombier 			freeb(bp);
3537dd7cddfSDavid du Colombier 		else
3543ff48bf5SDavid du Colombier 			ipiput4(er->f, ifc, bp);
3553ff48bf5SDavid du Colombier 		runlock(ifc);
3563ff48bf5SDavid du Colombier 		poperror();
3573ff48bf5SDavid du Colombier 	}
3583ff48bf5SDavid du Colombier }
3593ff48bf5SDavid du Colombier 
3603ff48bf5SDavid du Colombier 
3613ff48bf5SDavid du Colombier /*
3623ff48bf5SDavid du Colombier  *  process to read from the ethernet, IPv6
3633ff48bf5SDavid du Colombier  */
3643ff48bf5SDavid du Colombier static void
3653ff48bf5SDavid du Colombier etherread6(void *a)
3663ff48bf5SDavid du Colombier {
3673ff48bf5SDavid du Colombier 	Ipifc *ifc;
3683ff48bf5SDavid du Colombier 	Block *bp;
3693ff48bf5SDavid du Colombier 	Etherrock *er;
3703ff48bf5SDavid du Colombier 
3713ff48bf5SDavid du Colombier 	ifc = a;
3723ff48bf5SDavid du Colombier 	er = ifc->arg;
3733ff48bf5SDavid du Colombier 	er->read6p = up;	/* hide identity under a rock for unbind */
3743ff48bf5SDavid du Colombier 	if(waserror()){
3753ff48bf5SDavid du Colombier 		er->read6p = 0;
3763ff48bf5SDavid du Colombier 		pexit("hangup", 1);
3773ff48bf5SDavid du Colombier 	}
3783ff48bf5SDavid du Colombier 	for(;;){
3793f695129SDavid du Colombier 		bp = devtab[er->mchan6->type]->bread(er->mchan6, ifc->maxtu, 0);
3803ff48bf5SDavid du Colombier 		if(!canrlock(ifc)){
3813ff48bf5SDavid du Colombier 			freeb(bp);
3823ff48bf5SDavid du Colombier 			continue;
3833ff48bf5SDavid du Colombier 		}
3843ff48bf5SDavid du Colombier 		if(waserror()){
3853ff48bf5SDavid du Colombier 			runlock(ifc);
3863ff48bf5SDavid du Colombier 			nexterror();
3873ff48bf5SDavid du Colombier 		}
3883ff48bf5SDavid du Colombier 		ifc->in++;
3893ff48bf5SDavid du Colombier 		bp->rp += ifc->m->hsize;
3903ff48bf5SDavid du Colombier 		if(ifc->lifc == nil)
3913ff48bf5SDavid du Colombier 			freeb(bp);
3923ff48bf5SDavid du Colombier 		else
3933ff48bf5SDavid du Colombier 			ipiput6(er->f, ifc, bp);
3947dd7cddfSDavid du Colombier 		runlock(ifc);
3957dd7cddfSDavid du Colombier 		poperror();
3967dd7cddfSDavid du Colombier 	}
3977dd7cddfSDavid du Colombier }
3987dd7cddfSDavid du Colombier 
3997dd7cddfSDavid du Colombier static void
4007dd7cddfSDavid du Colombier etheraddmulti(Ipifc *ifc, uchar *a, uchar *)
4017dd7cddfSDavid du Colombier {
4027dd7cddfSDavid du Colombier 	uchar mac[6];
4037dd7cddfSDavid du Colombier 	char buf[64];
4047dd7cddfSDavid du Colombier 	Etherrock *er = ifc->arg;
4053ff48bf5SDavid du Colombier 	int version;
4067dd7cddfSDavid du Colombier 
4073ff48bf5SDavid du Colombier 	version = multicastea(mac, a);
4087dd7cddfSDavid du Colombier 	sprint(buf, "addmulti %E", mac);
4093ff48bf5SDavid du Colombier 	switch(version){
4103ff48bf5SDavid du Colombier 	case V4:
4113ff48bf5SDavid du Colombier 		devtab[er->cchan4->type]->write(er->cchan4, buf, strlen(buf), 0);
4123ff48bf5SDavid du Colombier 		break;
4133ff48bf5SDavid du Colombier 	case V6:
4143ff48bf5SDavid du Colombier 		devtab[er->cchan6->type]->write(er->cchan6, buf, strlen(buf), 0);
4153ff48bf5SDavid du Colombier 		break;
4163ff48bf5SDavid du Colombier 	default:
4173ff48bf5SDavid du Colombier 		panic("etheraddmulti: version %d", version);
4183ff48bf5SDavid du Colombier 	}
4197dd7cddfSDavid du Colombier }
4207dd7cddfSDavid du Colombier 
4217dd7cddfSDavid du Colombier static void
4227dd7cddfSDavid du Colombier etherremmulti(Ipifc *ifc, uchar *a, uchar *)
4237dd7cddfSDavid du Colombier {
4247dd7cddfSDavid du Colombier 	uchar mac[6];
4257dd7cddfSDavid du Colombier 	char buf[64];
4267dd7cddfSDavid du Colombier 	Etherrock *er = ifc->arg;
4273ff48bf5SDavid du Colombier 	int version;
4287dd7cddfSDavid du Colombier 
4293ff48bf5SDavid du Colombier 	version = multicastea(mac, a);
4307dd7cddfSDavid du Colombier 	sprint(buf, "remmulti %E", mac);
4313ff48bf5SDavid du Colombier 	switch(version){
4323ff48bf5SDavid du Colombier 	case V4:
4333ff48bf5SDavid du Colombier 		devtab[er->cchan4->type]->write(er->cchan4, buf, strlen(buf), 0);
4343ff48bf5SDavid du Colombier 		break;
4353ff48bf5SDavid du Colombier 	case V6:
4363ff48bf5SDavid du Colombier 		devtab[er->cchan6->type]->write(er->cchan6, buf, strlen(buf), 0);
4373ff48bf5SDavid du Colombier 		break;
4383ff48bf5SDavid du Colombier 	default:
4393ff48bf5SDavid du Colombier 		panic("etherremmulti: version %d", version);
4403ff48bf5SDavid du Colombier 	}
4417dd7cddfSDavid du Colombier }
4427dd7cddfSDavid du Colombier 
4437dd7cddfSDavid du Colombier /*
4447dd7cddfSDavid du Colombier  *  send an ethernet arp
4457dd7cddfSDavid du Colombier  *  (only v4, v6 uses the neighbor discovery, rfc1970)
4467dd7cddfSDavid du Colombier  */
4477dd7cddfSDavid du Colombier static void
4487dd7cddfSDavid du Colombier sendarp(Ipifc *ifc, Arpent *a)
4497dd7cddfSDavid du Colombier {
4507dd7cddfSDavid du Colombier 	int n;
4517dd7cddfSDavid du Colombier 	Block *bp;
4527dd7cddfSDavid du Colombier 	Etherarp *e;
4537dd7cddfSDavid du Colombier 	Etherrock *er = ifc->arg;
4547dd7cddfSDavid du Colombier 
4557dd7cddfSDavid du Colombier 	/* don't do anything if it's been less than a second since the last */
456a6a9e072SDavid du Colombier 	if(NOW - a->ctime < 1000){
4577dd7cddfSDavid du Colombier 		arprelease(er->f->arp, a);
4587dd7cddfSDavid du Colombier 		return;
4597dd7cddfSDavid du Colombier 	}
4607dd7cddfSDavid du Colombier 
4617dd7cddfSDavid du Colombier 	/* remove all but the last message */
4627dd7cddfSDavid du Colombier 	while((bp = a->hold) != nil){
4637dd7cddfSDavid du Colombier 		if(bp == a->last)
4647dd7cddfSDavid du Colombier 			break;
4657dd7cddfSDavid du Colombier 		a->hold = bp->list;
4667dd7cddfSDavid du Colombier 		freeblist(bp);
4677dd7cddfSDavid du Colombier 	}
4687dd7cddfSDavid du Colombier 
4697dd7cddfSDavid du Colombier 	/* try to keep it around for a second more */
470a6a9e072SDavid du Colombier 	a->ctime = NOW;
4717dd7cddfSDavid du Colombier 	arprelease(er->f->arp, a);
4727dd7cddfSDavid du Colombier 
4737dd7cddfSDavid du Colombier 	n = sizeof(Etherarp);
4743f695129SDavid du Colombier 	if(n < a->type->mintu)
4753f695129SDavid du Colombier 		n = a->type->mintu;
4767dd7cddfSDavid du Colombier 	bp = allocb(n);
4777dd7cddfSDavid du Colombier 	memset(bp->rp, 0, n);
4787dd7cddfSDavid du Colombier 	e = (Etherarp*)bp->rp;
4797dd7cddfSDavid du Colombier 	memmove(e->tpa, a->ip+IPv4off, sizeof(e->tpa));
4807dd7cddfSDavid du Colombier 	ipv4local(ifc, e->spa);
4817dd7cddfSDavid du Colombier 	memmove(e->sha, ifc->mac, sizeof(e->sha));
4827dd7cddfSDavid du Colombier 	memset(e->d, 0xff, sizeof(e->d));		/* ethernet broadcast */
4837dd7cddfSDavid du Colombier 	memmove(e->s, ifc->mac, sizeof(e->s));
4847dd7cddfSDavid du Colombier 
4857dd7cddfSDavid du Colombier 	hnputs(e->type, ETARP);
4867dd7cddfSDavid du Colombier 	hnputs(e->hrd, 1);
4873ff48bf5SDavid du Colombier 	hnputs(e->pro, ETIP4);
4887dd7cddfSDavid du Colombier 	e->hln = sizeof(e->sha);
4897dd7cddfSDavid du Colombier 	e->pln = sizeof(e->spa);
4907dd7cddfSDavid du Colombier 	hnputs(e->op, ARPREQUEST);
4917dd7cddfSDavid du Colombier 	bp->wp += n;
4927dd7cddfSDavid du Colombier 
4937dd7cddfSDavid du Colombier 	n = devtab[er->achan->type]->bwrite(er->achan, bp, 0);
4947dd7cddfSDavid du Colombier 	if(n < 0)
4957dd7cddfSDavid du Colombier 		print("arp: send: %r\n");
4967dd7cddfSDavid du Colombier }
4977dd7cddfSDavid du Colombier 
4983ff48bf5SDavid du Colombier static void
4993ff48bf5SDavid du Colombier resolveaddr6(Ipifc *ifc, Arpent *a)
5003ff48bf5SDavid du Colombier {
5013ff48bf5SDavid du Colombier 	int sflag;
5023ff48bf5SDavid du Colombier 	Block *bp;
5033ff48bf5SDavid du Colombier 	Etherrock *er = ifc->arg;
5043ff48bf5SDavid du Colombier 	uchar ipsrc[IPaddrlen];
5053ff48bf5SDavid du Colombier 
5063ff48bf5SDavid du Colombier 	/* don't do anything if it's been less than a second since the last */
507a6a9e072SDavid du Colombier 	if(NOW - a->ctime < ReTransTimer){
5083ff48bf5SDavid du Colombier 		arprelease(er->f->arp, a);
5093ff48bf5SDavid du Colombier 		return;
5103ff48bf5SDavid du Colombier 	}
5113ff48bf5SDavid du Colombier 
5123ff48bf5SDavid du Colombier 	/* remove all but the last message */
5133ff48bf5SDavid du Colombier 	while((bp = a->hold) != nil){
5143ff48bf5SDavid du Colombier 		if(bp == a->last)
5153ff48bf5SDavid du Colombier 			break;
5163ff48bf5SDavid du Colombier 		a->hold = bp->list;
5173ff48bf5SDavid du Colombier 		freeblist(bp);
5183ff48bf5SDavid du Colombier 	}
5193ff48bf5SDavid du Colombier 
5203ff48bf5SDavid du Colombier 	/* try to keep it around for a second more */
521a6a9e072SDavid du Colombier 	a->ctime = NOW;
522a6a9e072SDavid du Colombier 	a->rtime = NOW + ReTransTimer;
5233ff48bf5SDavid du Colombier 	if(a->rxtsrem <= 0) {
5243ff48bf5SDavid du Colombier 		arprelease(er->f->arp, a);
5253ff48bf5SDavid du Colombier 		return;
5263ff48bf5SDavid du Colombier 	}
5273ff48bf5SDavid du Colombier 
5283ff48bf5SDavid du Colombier 	a->rxtsrem--;
5293ff48bf5SDavid du Colombier 	arprelease(er->f->arp, a);
5303ff48bf5SDavid du Colombier 
5313ff48bf5SDavid du Colombier 	if(sflag = ipv6anylocal(ifc, ipsrc))
5323ff48bf5SDavid du Colombier 		icmpns(er->f, ipsrc, sflag, a->ip, TARG_MULTI, ifc->mac);
5333ff48bf5SDavid du Colombier }
5343ff48bf5SDavid du Colombier 
5357dd7cddfSDavid du Colombier /*
5367dd7cddfSDavid du Colombier  *  send a gratuitous arp to refresh arp caches
5377dd7cddfSDavid du Colombier  */
5387dd7cddfSDavid du Colombier static void
5397dd7cddfSDavid du Colombier sendgarp(Ipifc *ifc, uchar *ip)
5407dd7cddfSDavid du Colombier {
5417dd7cddfSDavid du Colombier 	int n;
5427dd7cddfSDavid du Colombier 	Block *bp;
5437dd7cddfSDavid du Colombier 	Etherarp *e;
5447dd7cddfSDavid du Colombier 	Etherrock *er = ifc->arg;
5457dd7cddfSDavid du Colombier 
5467dd7cddfSDavid du Colombier 	/* don't arp for our initial non address */
5477dd7cddfSDavid du Colombier 	if(ipcmp(ip, IPnoaddr) == 0)
5487dd7cddfSDavid du Colombier 		return;
5497dd7cddfSDavid du Colombier 
5507dd7cddfSDavid du Colombier 	n = sizeof(Etherarp);
5513f695129SDavid du Colombier 	if(n < ifc->m->mintu)
5523f695129SDavid du Colombier 		n = ifc->m->mintu;
5537dd7cddfSDavid du Colombier 	bp = allocb(n);
5547dd7cddfSDavid du Colombier 	memset(bp->rp, 0, n);
5557dd7cddfSDavid du Colombier 	e = (Etherarp*)bp->rp;
5567dd7cddfSDavid du Colombier 	memmove(e->tpa, ip+IPv4off, sizeof(e->tpa));
5577dd7cddfSDavid du Colombier 	memmove(e->spa, ip+IPv4off, sizeof(e->spa));
5587dd7cddfSDavid du Colombier 	memmove(e->sha, ifc->mac, sizeof(e->sha));
5597dd7cddfSDavid du Colombier 	memset(e->d, 0xff, sizeof(e->d));		/* ethernet broadcast */
5607dd7cddfSDavid du Colombier 	memmove(e->s, ifc->mac, sizeof(e->s));
5617dd7cddfSDavid du Colombier 
5627dd7cddfSDavid du Colombier 	hnputs(e->type, ETARP);
5637dd7cddfSDavid du Colombier 	hnputs(e->hrd, 1);
5643ff48bf5SDavid du Colombier 	hnputs(e->pro, ETIP4);
5657dd7cddfSDavid du Colombier 	e->hln = sizeof(e->sha);
5667dd7cddfSDavid du Colombier 	e->pln = sizeof(e->spa);
5677dd7cddfSDavid du Colombier 	hnputs(e->op, ARPREQUEST);
5687dd7cddfSDavid du Colombier 	bp->wp += n;
5697dd7cddfSDavid du Colombier 
5707dd7cddfSDavid du Colombier 	n = devtab[er->achan->type]->bwrite(er->achan, bp, 0);
5717dd7cddfSDavid du Colombier 	if(n < 0)
5727dd7cddfSDavid du Colombier 		print("garp: send: %r\n");
5737dd7cddfSDavid du Colombier }
5747dd7cddfSDavid du Colombier 
5757dd7cddfSDavid du Colombier static void
5767dd7cddfSDavid du Colombier recvarp(Ipifc *ifc)
5777dd7cddfSDavid du Colombier {
5787dd7cddfSDavid du Colombier 	int n;
5797dd7cddfSDavid du Colombier 	Block *ebp, *rbp;
5807dd7cddfSDavid du Colombier 	Etherarp *e, *r;
5817dd7cddfSDavid du Colombier 	uchar ip[IPaddrlen];
582ef9eff0bSDavid du Colombier 	static uchar eprinted[4];
5837dd7cddfSDavid du Colombier 	Etherrock *er = ifc->arg;
5847dd7cddfSDavid du Colombier 
5853f695129SDavid du Colombier 	ebp = devtab[er->achan->type]->bread(er->achan, ifc->maxtu, 0);
5867dd7cddfSDavid du Colombier 	if(ebp == nil) {
5877dd7cddfSDavid du Colombier 		print("arp: rcv: %r\n");
5887dd7cddfSDavid du Colombier 		return;
5897dd7cddfSDavid du Colombier 	}
5907dd7cddfSDavid du Colombier 
5917dd7cddfSDavid du Colombier 	e = (Etherarp*)ebp->rp;
5927dd7cddfSDavid du Colombier 	switch(nhgets(e->op)) {
5937dd7cddfSDavid du Colombier 	default:
5947dd7cddfSDavid du Colombier 		break;
5957dd7cddfSDavid du Colombier 
5967dd7cddfSDavid du Colombier 	case ARPREPLY:
5973ff48bf5SDavid du Colombier 		/* check for machine using my ip address */
5983ff48bf5SDavid du Colombier 		v4tov6(ip, e->spa);
5999a747e4fSDavid du Colombier 		if(iplocalonifc(ifc, ip) || ipproxyifc(er->f, ifc, ip)){
6009a747e4fSDavid du Colombier 			if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0){
6019a747e4fSDavid du Colombier 				print("arprep: 0x%E/0x%E also has ip addr %V\n",
6029a747e4fSDavid du Colombier 					e->s, e->sha, e->spa);
6039a747e4fSDavid du Colombier 				break;
6049a747e4fSDavid du Colombier 			}
6059a747e4fSDavid du Colombier 		}
6063ff48bf5SDavid du Colombier 
6077dd7cddfSDavid du Colombier 		arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), 0);
6087dd7cddfSDavid du Colombier 		break;
6097dd7cddfSDavid du Colombier 
6107dd7cddfSDavid du Colombier 	case ARPREQUEST:
6117dd7cddfSDavid du Colombier 		/* don't answer arps till we know who we are */
6127dd7cddfSDavid du Colombier 		if(ifc->lifc == 0)
6137dd7cddfSDavid du Colombier 			break;
6147dd7cddfSDavid du Colombier 
6153ff48bf5SDavid du Colombier 		/* check for machine using my ip or ether address */
6167dd7cddfSDavid du Colombier 		v4tov6(ip, e->spa);
6177dd7cddfSDavid du Colombier 		if(iplocalonifc(ifc, ip) || ipproxyifc(er->f, ifc, ip)){
618ef9eff0bSDavid du Colombier 			if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0){
619ef9eff0bSDavid du Colombier 				if (memcmp(eprinted, e->spa, sizeof(e->spa))){
620ef9eff0bSDavid du Colombier 					/* print only once */
6213ff48bf5SDavid du Colombier 					print("arpreq: 0x%E also has ip addr %V\n", e->sha, e->spa);
622ef9eff0bSDavid du Colombier 					memmove(eprinted, e->spa, sizeof(e->spa));
623ef9eff0bSDavid du Colombier 				}
624ef9eff0bSDavid du Colombier 			}
6257dd7cddfSDavid du Colombier 		} else {
6267dd7cddfSDavid du Colombier 			if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) == 0){
6273ff48bf5SDavid du Colombier 				print("arpreq: %V also has ether addr %E\n", e->spa, e->sha);
6287dd7cddfSDavid du Colombier 				break;
6297dd7cddfSDavid du Colombier 			}
6307dd7cddfSDavid du Colombier 		}
6317dd7cddfSDavid du Colombier 
6327dd7cddfSDavid du Colombier 		/* refresh what we know about sender */
6337dd7cddfSDavid du Colombier 		arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), 1);
6347dd7cddfSDavid du Colombier 
6357dd7cddfSDavid du Colombier 		/* answer only requests for our address or systems we're proxying for */
6367dd7cddfSDavid du Colombier 		v4tov6(ip, e->tpa);
6377dd7cddfSDavid du Colombier 		if(!iplocalonifc(ifc, ip))
6387dd7cddfSDavid du Colombier 		if(!ipproxyifc(er->f, ifc, ip))
6397dd7cddfSDavid du Colombier 			break;
6407dd7cddfSDavid du Colombier 
6417dd7cddfSDavid du Colombier 		n = sizeof(Etherarp);
6423f695129SDavid du Colombier 		if(n < ifc->mintu)
6433f695129SDavid du Colombier 			n = ifc->mintu;
6447dd7cddfSDavid du Colombier 		rbp = allocb(n);
6457dd7cddfSDavid du Colombier 		r = (Etherarp*)rbp->rp;
6467dd7cddfSDavid du Colombier 		memset(r, 0, sizeof(Etherarp));
6477dd7cddfSDavid du Colombier 		hnputs(r->type, ETARP);
6487dd7cddfSDavid du Colombier 		hnputs(r->hrd, 1);
6493ff48bf5SDavid du Colombier 		hnputs(r->pro, ETIP4);
6507dd7cddfSDavid du Colombier 		r->hln = sizeof(r->sha);
6517dd7cddfSDavid du Colombier 		r->pln = sizeof(r->spa);
6527dd7cddfSDavid du Colombier 		hnputs(r->op, ARPREPLY);
6537dd7cddfSDavid du Colombier 		memmove(r->tha, e->sha, sizeof(r->tha));
6547dd7cddfSDavid du Colombier 		memmove(r->tpa, e->spa, sizeof(r->tpa));
6557dd7cddfSDavid du Colombier 		memmove(r->sha, ifc->mac, sizeof(r->sha));
6567dd7cddfSDavid du Colombier 		memmove(r->spa, e->tpa, sizeof(r->spa));
6577dd7cddfSDavid du Colombier 		memmove(r->d, e->sha, sizeof(r->d));
6587dd7cddfSDavid du Colombier 		memmove(r->s, ifc->mac, sizeof(r->s));
6597dd7cddfSDavid du Colombier 		rbp->wp += n;
6607dd7cddfSDavid du Colombier 
6617dd7cddfSDavid du Colombier 		n = devtab[er->achan->type]->bwrite(er->achan, rbp, 0);
6627dd7cddfSDavid du Colombier 		if(n < 0)
6637dd7cddfSDavid du Colombier 			print("arp: write: %r\n");
6647dd7cddfSDavid du Colombier 	}
6657dd7cddfSDavid du Colombier 	freeb(ebp);
6667dd7cddfSDavid du Colombier }
6677dd7cddfSDavid du Colombier 
6687dd7cddfSDavid du Colombier static void
6697dd7cddfSDavid du Colombier recvarpproc(void *v)
6707dd7cddfSDavid du Colombier {
6717dd7cddfSDavid du Colombier 	Ipifc *ifc = v;
6727dd7cddfSDavid du Colombier 	Etherrock *er = ifc->arg;
6737dd7cddfSDavid du Colombier 
6747dd7cddfSDavid du Colombier 	er->arpp = up;
6757dd7cddfSDavid du Colombier 	if(waserror()){
6767dd7cddfSDavid du Colombier 		er->arpp = 0;
6777dd7cddfSDavid du Colombier 		pexit("hangup", 1);
6787dd7cddfSDavid du Colombier 	}
6797dd7cddfSDavid du Colombier 	for(;;)
6807dd7cddfSDavid du Colombier 		recvarp(ifc);
6817dd7cddfSDavid du Colombier }
6827dd7cddfSDavid du Colombier 
6837dd7cddfSDavid du Colombier static int
6847dd7cddfSDavid du Colombier multicastea(uchar *ea, uchar *ip)
6857dd7cddfSDavid du Colombier {
6867dd7cddfSDavid du Colombier 	int x;
6877dd7cddfSDavid du Colombier 
6887dd7cddfSDavid du Colombier 	switch(x = ipismulticast(ip)){
6897dd7cddfSDavid du Colombier 	case V4:
6907dd7cddfSDavid du Colombier 		ea[0] = 0x01;
6917dd7cddfSDavid du Colombier 		ea[1] = 0x00;
6927dd7cddfSDavid du Colombier 		ea[2] = 0x5e;
6937dd7cddfSDavid du Colombier 		ea[3] = ip[13] & 0x7f;
6947dd7cddfSDavid du Colombier 		ea[4] = ip[14];
6957dd7cddfSDavid du Colombier 		ea[5] = ip[15];
6967dd7cddfSDavid du Colombier 		break;
6977dd7cddfSDavid du Colombier  	case V6:
6987dd7cddfSDavid du Colombier  		ea[0] = 0x33;
6997dd7cddfSDavid du Colombier  		ea[1] = 0x33;
7007dd7cddfSDavid du Colombier  		ea[2] = ip[12];
7017dd7cddfSDavid du Colombier 		ea[3] = ip[13];
7027dd7cddfSDavid du Colombier  		ea[4] = ip[14];
7037dd7cddfSDavid du Colombier  		ea[5] = ip[15];
7047dd7cddfSDavid du Colombier  		break;
7057dd7cddfSDavid du Colombier 	}
7067dd7cddfSDavid du Colombier 	return x;
7077dd7cddfSDavid du Colombier }
7087dd7cddfSDavid du Colombier 
7097dd7cddfSDavid du Colombier /*
7107dd7cddfSDavid du Colombier  *  fill in an arp entry for broadcast or multicast
7113ff48bf5SDavid du Colombier  *  addresses.  Return the first queued packet for the
7123ff48bf5SDavid du Colombier  *  IP address.
7137dd7cddfSDavid du Colombier  */
7147dd7cddfSDavid du Colombier static Block*
71559cc4ca5SDavid du Colombier multicastarp(Fs *f, Arpent *a, Medium *medium, uchar *mac)
7167dd7cddfSDavid du Colombier {
7177dd7cddfSDavid du Colombier 	/* is it broadcast? */
7187dd7cddfSDavid du Colombier 	switch(ipforme(f, a->ip)){
7197dd7cddfSDavid du Colombier 	case Runi:
7207dd7cddfSDavid du Colombier 		return nil;
7217dd7cddfSDavid du Colombier 	case Rbcast:
7227dd7cddfSDavid du Colombier 		memset(mac, 0xff, 6);
72359cc4ca5SDavid du Colombier 		return arpresolve(f->arp, a, medium, mac);
7247dd7cddfSDavid du Colombier 	default:
7257dd7cddfSDavid du Colombier 		break;
7267dd7cddfSDavid du Colombier 	}
7277dd7cddfSDavid du Colombier 
7287dd7cddfSDavid du Colombier 	/* if multicast, fill in mac */
7297dd7cddfSDavid du Colombier 	switch(multicastea(mac, a->ip)){
7307dd7cddfSDavid du Colombier 	case V4:
7317dd7cddfSDavid du Colombier 	case V6:
73259cc4ca5SDavid du Colombier 		return arpresolve(f->arp, a, medium, mac);
7337dd7cddfSDavid du Colombier 	}
7347dd7cddfSDavid du Colombier 
7357dd7cddfSDavid du Colombier 	/* let arp take care of it */
7367dd7cddfSDavid du Colombier 	return nil;
7377dd7cddfSDavid du Colombier }
7387dd7cddfSDavid du Colombier 
7397dd7cddfSDavid du Colombier void
7407dd7cddfSDavid du Colombier ethermediumlink(void)
7417dd7cddfSDavid du Colombier {
7427dd7cddfSDavid du Colombier 	addipmedium(&ethermedium);
74359cc4ca5SDavid du Colombier 	addipmedium(&gbemedium);
7447dd7cddfSDavid du Colombier }
7453ff48bf5SDavid du Colombier 
7463ff48bf5SDavid du Colombier 
7473ff48bf5SDavid du Colombier static void
7483ff48bf5SDavid du Colombier etherpref2addr(uchar *pref, uchar *ea)
7493ff48bf5SDavid du Colombier {
7503ff48bf5SDavid du Colombier 	pref[8]  = ea[0] | 0x2;
7513ff48bf5SDavid du Colombier 	pref[9]  = ea[1];
7523ff48bf5SDavid du Colombier 	pref[10] = ea[2];
7533ff48bf5SDavid du Colombier 	pref[11] = 0xFF;
7543ff48bf5SDavid du Colombier 	pref[12] = 0xFE;
7553ff48bf5SDavid du Colombier 	pref[13] = ea[3];
7563ff48bf5SDavid du Colombier 	pref[14] = ea[4];
7573ff48bf5SDavid du Colombier 	pref[15] = ea[5];
7583ff48bf5SDavid du Colombier }
759