xref: /plan9/sys/src/9/ip/ethermedium.c (revision 4e3613ab15c331a9ada113286cc0f2a35bc0373d)
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 
8ac020a8fSDavid du Colombier #include "../port/netif.h"
97dd7cddfSDavid du Colombier #include "ip.h"
103ff48bf5SDavid du Colombier #include "ipv6.h"
117dd7cddfSDavid du Colombier 
127dd7cddfSDavid du Colombier typedef struct Etherhdr Etherhdr;
137dd7cddfSDavid du Colombier struct Etherhdr
147dd7cddfSDavid du Colombier {
157dd7cddfSDavid du Colombier 	uchar	d[6];
167dd7cddfSDavid du Colombier 	uchar	s[6];
177dd7cddfSDavid du Colombier 	uchar	t[2];
187dd7cddfSDavid du Colombier };
197dd7cddfSDavid du Colombier 
205d82c6aeSDavid du Colombier static uchar ipbroadcast[IPaddrlen] = {
215d82c6aeSDavid du Colombier 	0xff,0xff,0xff,0xff,
225d82c6aeSDavid du Colombier 	0xff,0xff,0xff,0xff,
235d82c6aeSDavid du Colombier 	0xff,0xff,0xff,0xff,
245d82c6aeSDavid du Colombier 	0xff,0xff,0xff,0xff,
255d82c6aeSDavid du Colombier };
265d82c6aeSDavid du Colombier 
275d82c6aeSDavid du Colombier static uchar etherbroadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
285d82c6aeSDavid du Colombier 
293ff48bf5SDavid du Colombier static void	etherread4(void *a);
303ff48bf5SDavid du Colombier static void	etherread6(void *a);
317dd7cddfSDavid du Colombier static void	etherbind(Ipifc *ifc, int argc, char **argv);
327dd7cddfSDavid du Colombier static void	etherunbind(Ipifc *ifc);
337dd7cddfSDavid du Colombier static void	etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip);
347dd7cddfSDavid du Colombier static void	etheraddmulti(Ipifc *ifc, uchar *a, uchar *ia);
357dd7cddfSDavid du Colombier static void	etherremmulti(Ipifc *ifc, uchar *a, uchar *ia);
3659cc4ca5SDavid du Colombier static Block*	multicastarp(Fs *f, Arpent *a, Medium*, uchar *mac);
377dd7cddfSDavid du Colombier static void	sendarp(Ipifc *ifc, Arpent *a);
387dd7cddfSDavid du Colombier static void	sendgarp(Ipifc *ifc, uchar*);
397dd7cddfSDavid du Colombier static int	multicastea(uchar *ea, uchar *ip);
407dd7cddfSDavid du Colombier static void	recvarpproc(void*);
413ff48bf5SDavid du Colombier static void	resolveaddr6(Ipifc *ifc, Arpent *a);
423ff48bf5SDavid du Colombier static void	etherpref2addr(uchar *pref, uchar *ea);
437dd7cddfSDavid du Colombier 
447dd7cddfSDavid du Colombier Medium ethermedium =
457dd7cddfSDavid du Colombier {
467dd7cddfSDavid du Colombier .name=		"ether",
477dd7cddfSDavid du Colombier .hsize=		14,
483f695129SDavid du Colombier .mintu=		60,
493f695129SDavid du Colombier .maxtu=		1514,
507dd7cddfSDavid du Colombier .maclen=	6,
517dd7cddfSDavid du Colombier .bind=		etherbind,
527dd7cddfSDavid du Colombier .unbind=	etherunbind,
537dd7cddfSDavid du Colombier .bwrite=	etherbwrite,
547dd7cddfSDavid du Colombier .addmulti=	etheraddmulti,
557dd7cddfSDavid du Colombier .remmulti=	etherremmulti,
567dd7cddfSDavid du Colombier .ares=		arpenter,
577dd7cddfSDavid du Colombier .areg=		sendgarp,
583ff48bf5SDavid du Colombier .pref2addr=	etherpref2addr,
597dd7cddfSDavid du Colombier };
607dd7cddfSDavid du Colombier 
6159cc4ca5SDavid du Colombier Medium gbemedium =
6259cc4ca5SDavid du Colombier {
6359cc4ca5SDavid du Colombier .name=		"gbe",
6459cc4ca5SDavid du Colombier .hsize=		14,
653f695129SDavid du Colombier .mintu=		60,
663f695129SDavid du Colombier .maxtu=		9014,
6759cc4ca5SDavid du Colombier .maclen=	6,
6859cc4ca5SDavid du Colombier .bind=		etherbind,
6959cc4ca5SDavid du Colombier .unbind=	etherunbind,
7059cc4ca5SDavid du Colombier .bwrite=	etherbwrite,
7159cc4ca5SDavid du Colombier .addmulti=	etheraddmulti,
7259cc4ca5SDavid du Colombier .remmulti=	etherremmulti,
7359cc4ca5SDavid du Colombier .ares=		arpenter,
7459cc4ca5SDavid du Colombier .areg=		sendgarp,
753ff48bf5SDavid du Colombier .pref2addr=	etherpref2addr,
7659cc4ca5SDavid du Colombier };
7759cc4ca5SDavid du Colombier 
787dd7cddfSDavid du Colombier typedef struct	Etherrock Etherrock;
797dd7cddfSDavid du Colombier struct Etherrock
807dd7cddfSDavid du Colombier {
817dd7cddfSDavid du Colombier 	Fs	*f;		/* file system we belong to */
827dd7cddfSDavid du Colombier 	Proc	*arpp;		/* arp process */
833ff48bf5SDavid du Colombier 	Proc	*read4p;	/* reading process (v4)*/
843ff48bf5SDavid du Colombier 	Proc	*read6p;	/* reading process (v6)*/
853ff48bf5SDavid du Colombier 	Chan	*mchan4;	/* Data channel for v4 */
867dd7cddfSDavid du Colombier 	Chan	*achan;		/* Arp channel */
873ff48bf5SDavid du Colombier 	Chan	*cchan4;	/* Control channel for v4 */
883ff48bf5SDavid du Colombier 	Chan	*mchan6;	/* Data channel for v6 */
893ff48bf5SDavid du Colombier 	Chan	*cchan6;	/* Control channel for v6 */
907dd7cddfSDavid du Colombier };
917dd7cddfSDavid du Colombier 
927dd7cddfSDavid du Colombier /*
937dd7cddfSDavid du Colombier  *  ethernet arp request
947dd7cddfSDavid du Colombier  */
957dd7cddfSDavid du Colombier enum
967dd7cddfSDavid du Colombier {
977dd7cddfSDavid du Colombier 	ARPREQUEST	= 1,
987dd7cddfSDavid du Colombier 	ARPREPLY	= 2,
997dd7cddfSDavid du Colombier };
1003ff48bf5SDavid du Colombier 
1017dd7cddfSDavid du Colombier typedef struct Etherarp Etherarp;
1027dd7cddfSDavid du Colombier struct Etherarp
1037dd7cddfSDavid du Colombier {
1047dd7cddfSDavid du Colombier 	uchar	d[6];
1057dd7cddfSDavid du Colombier 	uchar	s[6];
1067dd7cddfSDavid du Colombier 	uchar	type[2];
1077dd7cddfSDavid du Colombier 	uchar	hrd[2];
1087dd7cddfSDavid du Colombier 	uchar	pro[2];
1097dd7cddfSDavid du Colombier 	uchar	hln;
1107dd7cddfSDavid du Colombier 	uchar	pln;
1117dd7cddfSDavid du Colombier 	uchar	op[2];
1127dd7cddfSDavid du Colombier 	uchar	sha[6];
1137dd7cddfSDavid du Colombier 	uchar	spa[4];
1147dd7cddfSDavid du Colombier 	uchar	tha[6];
1157dd7cddfSDavid du Colombier 	uchar	tpa[4];
1167dd7cddfSDavid du Colombier };
1177dd7cddfSDavid du Colombier 
1183ff48bf5SDavid du Colombier static char *nbmsg = "nonblocking";
1197dd7cddfSDavid du Colombier 
1207dd7cddfSDavid du Colombier /*
1217dd7cddfSDavid du Colombier  *  called to bind an IP ifc to an ethernet device
1227dd7cddfSDavid du Colombier  *  called with ifc wlock'd
1237dd7cddfSDavid du Colombier  */
1247dd7cddfSDavid du Colombier static void
etherbind(Ipifc * ifc,int argc,char ** argv)1257dd7cddfSDavid du Colombier etherbind(Ipifc *ifc, int argc, char **argv)
1267dd7cddfSDavid du Colombier {
1273ff48bf5SDavid du Colombier 	Chan *mchan4, *cchan4, *achan, *mchan6, *cchan6, *schan;
1283ff48bf5SDavid du Colombier 	char addr[Maxpath];	//char addr[2*KNAMELEN];
1293ff48bf5SDavid du Colombier 	char dir[Maxpath];	//char dir[2*KNAMELEN];
1307dd7cddfSDavid du Colombier 	char *buf;
13180ee5cbfSDavid du Colombier 	int n;
1327dd7cddfSDavid du Colombier 	char *ptr;
1337dd7cddfSDavid du Colombier 	Etherrock *er;
1347dd7cddfSDavid du Colombier 
1357dd7cddfSDavid du Colombier 	if(argc < 2)
1367dd7cddfSDavid du Colombier 		error(Ebadarg);
1377dd7cddfSDavid du Colombier 
1383ff48bf5SDavid du Colombier 	mchan4 = cchan4 = achan = mchan6 = cchan6 = nil;
1397dd7cddfSDavid du Colombier 	buf = nil;
1407dd7cddfSDavid du Colombier 	if(waserror()){
1413ff48bf5SDavid du Colombier 		if(mchan4 != nil)
1423ff48bf5SDavid du Colombier 			cclose(mchan4);
1433ff48bf5SDavid du Colombier 		if(cchan4 != nil)
1443ff48bf5SDavid du Colombier 			cclose(cchan4);
1457dd7cddfSDavid du Colombier 		if(achan != nil)
1467dd7cddfSDavid du Colombier 			cclose(achan);
1473ff48bf5SDavid du Colombier 		if(mchan6 != nil)
1483ff48bf5SDavid du Colombier 			cclose(mchan6);
1493ff48bf5SDavid du Colombier 		if(cchan6 != nil)
1503ff48bf5SDavid du Colombier 			cclose(cchan6);
1517dd7cddfSDavid du Colombier 		if(buf != nil)
1527dd7cddfSDavid du Colombier 			free(buf);
1537dd7cddfSDavid du Colombier 		nexterror();
1547dd7cddfSDavid du Colombier 	}
1557dd7cddfSDavid du Colombier 
1567dd7cddfSDavid du Colombier 	/*
157ac020a8fSDavid du Colombier 	 *  open ipv4 conversation
1587dd7cddfSDavid du Colombier 	 *
1597dd7cddfSDavid du Colombier 	 *  the dial will fail if the type is already open on
1607dd7cddfSDavid du Colombier 	 *  this device.
1617dd7cddfSDavid du Colombier 	 */
162ac020a8fSDavid du Colombier 	snprint(addr, sizeof(addr), "%s!0x800", argv[2]);	/* ETIP4 */
1633ff48bf5SDavid du Colombier 	mchan4 = chandial(addr, nil, dir, &cchan4);
1643ff48bf5SDavid du Colombier 
1653ff48bf5SDavid du Colombier 	/*
1663ff48bf5SDavid du Colombier 	 *  make it non-blocking
1673ff48bf5SDavid du Colombier 	 */
1683ff48bf5SDavid du Colombier 	devtab[cchan4->type]->write(cchan4, nbmsg, strlen(nbmsg), 0);
1697dd7cddfSDavid du Colombier 
1707dd7cddfSDavid du Colombier 	/*
1713f695129SDavid du Colombier 	 *  get mac address and speed
1727dd7cddfSDavid du Colombier 	 */
1733432ceaeSDavid du Colombier 	snprint(addr, sizeof(addr), "%s/stats", argv[2]);
1747dd7cddfSDavid du Colombier 	buf = smalloc(512);
1753ff48bf5SDavid du Colombier 	schan = namec(addr, Aopen, OREAD, 0);
1763ff48bf5SDavid du Colombier 	if(waserror()){
1773ff48bf5SDavid du Colombier 		cclose(schan);
1783ff48bf5SDavid du Colombier 		nexterror();
1793ff48bf5SDavid du Colombier 	}
1803ff48bf5SDavid du Colombier 	n = devtab[schan->type]->read(schan, buf, 511, 0);
1813ff48bf5SDavid du Colombier 	cclose(schan);
1823ff48bf5SDavid du Colombier 	poperror();
1837dd7cddfSDavid du Colombier 	buf[n] = 0;
1847dd7cddfSDavid du Colombier 
1857dd7cddfSDavid du Colombier 	ptr = strstr(buf, "addr: ");
1867dd7cddfSDavid du Colombier 	if(!ptr)
1877dd7cddfSDavid du Colombier 		error(Eio);
1887dd7cddfSDavid du Colombier 	ptr += 6;
1897dd7cddfSDavid du Colombier 	parsemac(ifc->mac, ptr, 6);
1907dd7cddfSDavid du Colombier 
1913f695129SDavid du Colombier 	ptr = strstr(buf, "mbps: ");
1923f695129SDavid du Colombier 	if(ptr){
1933f695129SDavid du Colombier 		ptr += 6;
1943f695129SDavid du Colombier 		ifc->mbps = atoi(ptr);
1953f695129SDavid du Colombier 	} else
1963f695129SDavid du Colombier 		ifc->mbps = 100;
1973f695129SDavid du Colombier 
1987dd7cddfSDavid du Colombier 	/*
1997dd7cddfSDavid du Colombier  	 *  open arp conversation
2007dd7cddfSDavid du Colombier 	 */
201ac020a8fSDavid du Colombier 	snprint(addr, sizeof(addr), "%s!0x806", argv[2]);	/* ETARP */
20280ee5cbfSDavid du Colombier 	achan = chandial(addr, nil, nil, nil);
2037dd7cddfSDavid du Colombier 
2043ff48bf5SDavid du Colombier 	/*
2053e76a0ddSDavid du Colombier 	 *  open ipv6 conversation
2063ff48bf5SDavid du Colombier 	 *
2073ff48bf5SDavid du Colombier 	 *  the dial will fail if the type is already open on
2083ff48bf5SDavid du Colombier 	 *  this device.
2093ff48bf5SDavid du Colombier 	 */
210ac020a8fSDavid du Colombier 	snprint(addr, sizeof(addr), "%s!0x86DD", argv[2]);	/* ETIP6 */
2113ff48bf5SDavid du Colombier 	mchan6 = chandial(addr, nil, dir, &cchan6);
2123ff48bf5SDavid du Colombier 
2133ff48bf5SDavid du Colombier 	/*
2143ff48bf5SDavid du Colombier 	 *  make it non-blocking
2153ff48bf5SDavid du Colombier 	 */
2163ff48bf5SDavid du Colombier 	devtab[cchan6->type]->write(cchan6, nbmsg, strlen(nbmsg), 0);
2173ff48bf5SDavid du Colombier 
2187dd7cddfSDavid du Colombier 	er = smalloc(sizeof(*er));
2193ff48bf5SDavid du Colombier 	er->mchan4 = mchan4;
2203ff48bf5SDavid du Colombier 	er->cchan4 = cchan4;
2217dd7cddfSDavid du Colombier 	er->achan = achan;
2223ff48bf5SDavid du Colombier 	er->mchan6 = mchan6;
2233ff48bf5SDavid du Colombier 	er->cchan6 = cchan6;
2247dd7cddfSDavid du Colombier 	er->f = ifc->conv->p->f;
2257dd7cddfSDavid du Colombier 	ifc->arg = er;
2267dd7cddfSDavid du Colombier 
2277dd7cddfSDavid du Colombier 	free(buf);
2287dd7cddfSDavid du Colombier 	poperror();
2297dd7cddfSDavid du Colombier 
2303ff48bf5SDavid du Colombier 	kproc("etherread4", etherread4, ifc);
2317dd7cddfSDavid du Colombier 	kproc("recvarpproc", recvarpproc, ifc);
2323ff48bf5SDavid du Colombier 	kproc("etherread6", etherread6, ifc);
2337dd7cddfSDavid du Colombier }
2347dd7cddfSDavid du Colombier 
2357dd7cddfSDavid du Colombier /*
2367dd7cddfSDavid du Colombier  *  called with ifc wlock'd
2377dd7cddfSDavid du Colombier  */
2387dd7cddfSDavid du Colombier static void
etherunbind(Ipifc * ifc)2397dd7cddfSDavid du Colombier etherunbind(Ipifc *ifc)
2407dd7cddfSDavid du Colombier {
2417dd7cddfSDavid du Colombier 	Etherrock *er = ifc->arg;
2427dd7cddfSDavid du Colombier 
2433ff48bf5SDavid du Colombier 	if(er->read4p)
2443ff48bf5SDavid du Colombier 		postnote(er->read4p, 1, "unbind", 0);
2453ff48bf5SDavid du Colombier 	if(er->read6p)
2463ff48bf5SDavid du Colombier 		postnote(er->read6p, 1, "unbind", 0);
2477dd7cddfSDavid du Colombier 	if(er->arpp)
2487dd7cddfSDavid du Colombier 		postnote(er->arpp, 1, "unbind", 0);
2497dd7cddfSDavid du Colombier 
2507dd7cddfSDavid du Colombier 	/* wait for readers to die */
2513ff48bf5SDavid du Colombier 	while(er->arpp != 0 || er->read4p != 0 || er->read6p != 0)
2527dd7cddfSDavid du Colombier 		tsleep(&up->sleep, return0, 0, 300);
2537dd7cddfSDavid du Colombier 
2543ff48bf5SDavid du Colombier 	if(er->mchan4 != nil)
2553ff48bf5SDavid du Colombier 		cclose(er->mchan4);
2567dd7cddfSDavid du Colombier 	if(er->achan != nil)
2577dd7cddfSDavid du Colombier 		cclose(er->achan);
2583ff48bf5SDavid du Colombier 	if(er->cchan4 != nil)
2593ff48bf5SDavid du Colombier 		cclose(er->cchan4);
2603ff48bf5SDavid du Colombier 	if(er->mchan6 != nil)
2613ff48bf5SDavid du Colombier 		cclose(er->mchan6);
2623ff48bf5SDavid du Colombier 	if(er->cchan6 != nil)
2633ff48bf5SDavid du Colombier 		cclose(er->cchan6);
2647dd7cddfSDavid du Colombier 
2657dd7cddfSDavid du Colombier 	free(er);
2667dd7cddfSDavid du Colombier }
2677dd7cddfSDavid du Colombier 
2687dd7cddfSDavid du Colombier /*
2697dd7cddfSDavid du Colombier  *  called by ipoput with a single block to write with ifc rlock'd
2707dd7cddfSDavid du Colombier  */
2717dd7cddfSDavid du Colombier static void
etherbwrite(Ipifc * ifc,Block * bp,int version,uchar * ip)2727dd7cddfSDavid du Colombier etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip)
2737dd7cddfSDavid du Colombier {
2747dd7cddfSDavid du Colombier 	Etherhdr *eh;
2757dd7cddfSDavid du Colombier 	Arpent *a;
2767dd7cddfSDavid du Colombier 	uchar mac[6];
2777dd7cddfSDavid du Colombier 	Etherrock *er = ifc->arg;
2787dd7cddfSDavid du Colombier 
2797dd7cddfSDavid du Colombier 	/* get mac address of destination */
2803ff48bf5SDavid du Colombier 	a = arpget(er->f->arp, bp, version, ifc, ip, mac);
2817dd7cddfSDavid du Colombier 	if(a){
2827dd7cddfSDavid du Colombier 		/* check for broadcast or multicast */
28359cc4ca5SDavid du Colombier 		bp = multicastarp(er->f, a, ifc->m, mac);
2847dd7cddfSDavid du Colombier 		if(bp==nil){
2853ff48bf5SDavid du Colombier 			switch(version){
2863ff48bf5SDavid du Colombier 			case V4:
2877dd7cddfSDavid du Colombier 				sendarp(ifc, a);
2883ff48bf5SDavid du Colombier 				break;
2893ff48bf5SDavid du Colombier 			case V6:
2903ff48bf5SDavid du Colombier 				resolveaddr6(ifc, a);
2913ff48bf5SDavid du Colombier 				break;
2923ff48bf5SDavid du Colombier 			default:
2933ff48bf5SDavid du Colombier 				panic("etherbwrite: version %d", version);
2943ff48bf5SDavid du Colombier 			}
2957dd7cddfSDavid du Colombier 			return;
2967dd7cddfSDavid du Colombier 		}
2977dd7cddfSDavid du Colombier 	}
2987dd7cddfSDavid du Colombier 
2997dd7cddfSDavid du Colombier 	/* make it a single block with space for the ether header */
3007dd7cddfSDavid du Colombier 	bp = padblock(bp, ifc->m->hsize);
3017dd7cddfSDavid du Colombier 	if(bp->next)
3027dd7cddfSDavid du Colombier 		bp = concatblock(bp);
3033f695129SDavid du Colombier 	if(BLEN(bp) < ifc->mintu)
3043f695129SDavid du Colombier 		bp = adjustblock(bp, ifc->mintu);
3057dd7cddfSDavid du Colombier 	eh = (Etherhdr*)bp->rp;
3067dd7cddfSDavid du Colombier 
3077dd7cddfSDavid du Colombier 	/* copy in mac addresses and ether type */
3087dd7cddfSDavid du Colombier 	memmove(eh->s, ifc->mac, sizeof(eh->s));
3097dd7cddfSDavid du Colombier 	memmove(eh->d, mac, sizeof(eh->d));
3103ff48bf5SDavid du Colombier 
3117dd7cddfSDavid du Colombier  	switch(version){
3127dd7cddfSDavid du Colombier 	case V4:
3137dd7cddfSDavid du Colombier 		eh->t[0] = 0x08;
3147dd7cddfSDavid du Colombier 		eh->t[1] = 0x00;
3153ff48bf5SDavid du Colombier 		devtab[er->mchan4->type]->bwrite(er->mchan4, bp, 0);
3167dd7cddfSDavid du Colombier 		break;
3177dd7cddfSDavid du Colombier 	case V6:
3187dd7cddfSDavid du Colombier 		eh->t[0] = 0x86;
3197dd7cddfSDavid du Colombier 		eh->t[1] = 0xDD;
3203ff48bf5SDavid du Colombier 		devtab[er->mchan6->type]->bwrite(er->mchan6, bp, 0);
3217dd7cddfSDavid du Colombier 		break;
3223ff48bf5SDavid du Colombier 	default:
3233ff48bf5SDavid du Colombier 		panic("etherbwrite2: version %d", version);
3247dd7cddfSDavid du Colombier 	}
3257dd7cddfSDavid du Colombier 	ifc->out++;
3267dd7cddfSDavid du Colombier }
3277dd7cddfSDavid du Colombier 
3283ff48bf5SDavid du Colombier 
3297dd7cddfSDavid du Colombier /*
3307dd7cddfSDavid du Colombier  *  process to read from the ethernet
3317dd7cddfSDavid du Colombier  */
3327dd7cddfSDavid du Colombier static void
etherread4(void * a)3333ff48bf5SDavid du Colombier etherread4(void *a)
3347dd7cddfSDavid du Colombier {
3357dd7cddfSDavid du Colombier 	Ipifc *ifc;
3367dd7cddfSDavid du Colombier 	Block *bp;
3377dd7cddfSDavid du Colombier 	Etherrock *er;
3387dd7cddfSDavid du Colombier 
3397dd7cddfSDavid du Colombier 	ifc = a;
3407dd7cddfSDavid du Colombier 	er = ifc->arg;
3413ff48bf5SDavid du Colombier 	er->read4p = up;	/* hide identity under a rock for unbind */
3427dd7cddfSDavid du Colombier 	if(waserror()){
3433ff48bf5SDavid du Colombier 		er->read4p = 0;
3447dd7cddfSDavid du Colombier 		pexit("hangup", 1);
3457dd7cddfSDavid du Colombier 	}
3467dd7cddfSDavid du Colombier 	for(;;){
3473f695129SDavid du Colombier 		bp = devtab[er->mchan4->type]->bread(er->mchan4, ifc->maxtu, 0);
3487dd7cddfSDavid du Colombier 		if(!canrlock(ifc)){
3497dd7cddfSDavid du Colombier 			freeb(bp);
3507dd7cddfSDavid du Colombier 			continue;
3517dd7cddfSDavid du Colombier 		}
3527dd7cddfSDavid du Colombier 		if(waserror()){
3537dd7cddfSDavid du Colombier 			runlock(ifc);
3547dd7cddfSDavid du Colombier 			nexterror();
3557dd7cddfSDavid du Colombier 		}
3567dd7cddfSDavid du Colombier 		ifc->in++;
3577dd7cddfSDavid du Colombier 		bp->rp += ifc->m->hsize;
3587dd7cddfSDavid du Colombier 		if(ifc->lifc == nil)
3597dd7cddfSDavid du Colombier 			freeb(bp);
3607dd7cddfSDavid du Colombier 		else
3613ff48bf5SDavid du Colombier 			ipiput4(er->f, ifc, bp);
3623ff48bf5SDavid du Colombier 		runlock(ifc);
3633ff48bf5SDavid du Colombier 		poperror();
3643ff48bf5SDavid du Colombier 	}
3653ff48bf5SDavid du Colombier }
3663ff48bf5SDavid du Colombier 
3673ff48bf5SDavid du Colombier 
3683ff48bf5SDavid du Colombier /*
3693ff48bf5SDavid du Colombier  *  process to read from the ethernet, IPv6
3703ff48bf5SDavid du Colombier  */
3713ff48bf5SDavid du Colombier static void
etherread6(void * a)3723ff48bf5SDavid du Colombier etherread6(void *a)
3733ff48bf5SDavid du Colombier {
3743ff48bf5SDavid du Colombier 	Ipifc *ifc;
3753ff48bf5SDavid du Colombier 	Block *bp;
3763ff48bf5SDavid du Colombier 	Etherrock *er;
3773ff48bf5SDavid du Colombier 
3783ff48bf5SDavid du Colombier 	ifc = a;
3793ff48bf5SDavid du Colombier 	er = ifc->arg;
3803ff48bf5SDavid du Colombier 	er->read6p = up;	/* hide identity under a rock for unbind */
3813ff48bf5SDavid du Colombier 	if(waserror()){
3823ff48bf5SDavid du Colombier 		er->read6p = 0;
3833ff48bf5SDavid du Colombier 		pexit("hangup", 1);
3843ff48bf5SDavid du Colombier 	}
3853ff48bf5SDavid du Colombier 	for(;;){
3863f695129SDavid du Colombier 		bp = devtab[er->mchan6->type]->bread(er->mchan6, ifc->maxtu, 0);
3873ff48bf5SDavid du Colombier 		if(!canrlock(ifc)){
3883ff48bf5SDavid du Colombier 			freeb(bp);
3893ff48bf5SDavid du Colombier 			continue;
3903ff48bf5SDavid du Colombier 		}
3913ff48bf5SDavid du Colombier 		if(waserror()){
3923ff48bf5SDavid du Colombier 			runlock(ifc);
3933ff48bf5SDavid du Colombier 			nexterror();
3943ff48bf5SDavid du Colombier 		}
3953ff48bf5SDavid du Colombier 		ifc->in++;
3963ff48bf5SDavid du Colombier 		bp->rp += ifc->m->hsize;
3973ff48bf5SDavid du Colombier 		if(ifc->lifc == nil)
3983ff48bf5SDavid du Colombier 			freeb(bp);
3993ff48bf5SDavid du Colombier 		else
4003ff48bf5SDavid du Colombier 			ipiput6(er->f, ifc, bp);
4017dd7cddfSDavid du Colombier 		runlock(ifc);
4027dd7cddfSDavid du Colombier 		poperror();
4037dd7cddfSDavid du Colombier 	}
4047dd7cddfSDavid du Colombier }
4057dd7cddfSDavid du Colombier 
4067dd7cddfSDavid du Colombier static void
etheraddmulti(Ipifc * ifc,uchar * a,uchar *)4077dd7cddfSDavid du Colombier etheraddmulti(Ipifc *ifc, uchar *a, uchar *)
4087dd7cddfSDavid du Colombier {
4097dd7cddfSDavid du Colombier 	uchar mac[6];
4107dd7cddfSDavid du Colombier 	char buf[64];
4117dd7cddfSDavid du Colombier 	Etherrock *er = ifc->arg;
4123ff48bf5SDavid du Colombier 	int version;
4137dd7cddfSDavid du Colombier 
4143ff48bf5SDavid du Colombier 	version = multicastea(mac, a);
415*4e3613abSDavid du Colombier 	snprint(buf, sizeof buf, "addmulti %E", mac);
4163ff48bf5SDavid du Colombier 	switch(version){
4173ff48bf5SDavid du Colombier 	case V4:
4183ff48bf5SDavid du Colombier 		devtab[er->cchan4->type]->write(er->cchan4, buf, strlen(buf), 0);
4193ff48bf5SDavid du Colombier 		break;
4203ff48bf5SDavid du Colombier 	case V6:
4213ff48bf5SDavid du Colombier 		devtab[er->cchan6->type]->write(er->cchan6, buf, strlen(buf), 0);
4223ff48bf5SDavid du Colombier 		break;
4233ff48bf5SDavid du Colombier 	default:
4243ff48bf5SDavid du Colombier 		panic("etheraddmulti: version %d", version);
4253ff48bf5SDavid du Colombier 	}
4267dd7cddfSDavid du Colombier }
4277dd7cddfSDavid du Colombier 
4287dd7cddfSDavid du Colombier static void
etherremmulti(Ipifc * ifc,uchar * a,uchar *)4297dd7cddfSDavid du Colombier etherremmulti(Ipifc *ifc, uchar *a, uchar *)
4307dd7cddfSDavid du Colombier {
4317dd7cddfSDavid du Colombier 	uchar mac[6];
4327dd7cddfSDavid du Colombier 	char buf[64];
4337dd7cddfSDavid du Colombier 	Etherrock *er = ifc->arg;
4343ff48bf5SDavid du Colombier 	int version;
4357dd7cddfSDavid du Colombier 
4363ff48bf5SDavid du Colombier 	version = multicastea(mac, a);
437*4e3613abSDavid du Colombier 	snprint(buf, sizeof buf, "remmulti %E", mac);
4383ff48bf5SDavid du Colombier 	switch(version){
4393ff48bf5SDavid du Colombier 	case V4:
4403ff48bf5SDavid du Colombier 		devtab[er->cchan4->type]->write(er->cchan4, buf, strlen(buf), 0);
4413ff48bf5SDavid du Colombier 		break;
4423ff48bf5SDavid du Colombier 	case V6:
4433ff48bf5SDavid du Colombier 		devtab[er->cchan6->type]->write(er->cchan6, buf, strlen(buf), 0);
4443ff48bf5SDavid du Colombier 		break;
4453ff48bf5SDavid du Colombier 	default:
4463ff48bf5SDavid du Colombier 		panic("etherremmulti: version %d", version);
4473ff48bf5SDavid du Colombier 	}
4487dd7cddfSDavid du Colombier }
4497dd7cddfSDavid du Colombier 
4507dd7cddfSDavid du Colombier /*
4517dd7cddfSDavid du Colombier  *  send an ethernet arp
4527dd7cddfSDavid du Colombier  *  (only v4, v6 uses the neighbor discovery, rfc1970)
4537dd7cddfSDavid du Colombier  */
4547dd7cddfSDavid du Colombier static void
sendarp(Ipifc * ifc,Arpent * a)4557dd7cddfSDavid du Colombier sendarp(Ipifc *ifc, Arpent *a)
4567dd7cddfSDavid du Colombier {
4577dd7cddfSDavid du Colombier 	int n;
4587dd7cddfSDavid du Colombier 	Block *bp;
4597dd7cddfSDavid du Colombier 	Etherarp *e;
4607dd7cddfSDavid du Colombier 	Etherrock *er = ifc->arg;
4617dd7cddfSDavid du Colombier 
4627dd7cddfSDavid du Colombier 	/* don't do anything if it's been less than a second since the last */
463a6a9e072SDavid du Colombier 	if(NOW - a->ctime < 1000){
4647dd7cddfSDavid du Colombier 		arprelease(er->f->arp, a);
4657dd7cddfSDavid du Colombier 		return;
4667dd7cddfSDavid du Colombier 	}
4677dd7cddfSDavid du Colombier 
4687dd7cddfSDavid du Colombier 	/* remove all but the last message */
4697dd7cddfSDavid du Colombier 	while((bp = a->hold) != nil){
4707dd7cddfSDavid du Colombier 		if(bp == a->last)
4717dd7cddfSDavid du Colombier 			break;
4727dd7cddfSDavid du Colombier 		a->hold = bp->list;
4737dd7cddfSDavid du Colombier 		freeblist(bp);
4747dd7cddfSDavid du Colombier 	}
4757dd7cddfSDavid du Colombier 
4767dd7cddfSDavid du Colombier 	/* try to keep it around for a second more */
477a6a9e072SDavid du Colombier 	a->ctime = NOW;
4787dd7cddfSDavid du Colombier 	arprelease(er->f->arp, a);
4797dd7cddfSDavid du Colombier 
4807dd7cddfSDavid du Colombier 	n = sizeof(Etherarp);
4813f695129SDavid du Colombier 	if(n < a->type->mintu)
4823f695129SDavid du Colombier 		n = a->type->mintu;
4837dd7cddfSDavid du Colombier 	bp = allocb(n);
4847dd7cddfSDavid du Colombier 	memset(bp->rp, 0, n);
4857dd7cddfSDavid du Colombier 	e = (Etherarp*)bp->rp;
4867dd7cddfSDavid du Colombier 	memmove(e->tpa, a->ip+IPv4off, sizeof(e->tpa));
4877dd7cddfSDavid du Colombier 	ipv4local(ifc, e->spa);
4887dd7cddfSDavid du Colombier 	memmove(e->sha, ifc->mac, sizeof(e->sha));
4897dd7cddfSDavid du Colombier 	memset(e->d, 0xff, sizeof(e->d));		/* ethernet broadcast */
4907dd7cddfSDavid du Colombier 	memmove(e->s, ifc->mac, sizeof(e->s));
4917dd7cddfSDavid du Colombier 
4927dd7cddfSDavid du Colombier 	hnputs(e->type, ETARP);
4937dd7cddfSDavid du Colombier 	hnputs(e->hrd, 1);
4943ff48bf5SDavid du Colombier 	hnputs(e->pro, ETIP4);
4957dd7cddfSDavid du Colombier 	e->hln = sizeof(e->sha);
4967dd7cddfSDavid du Colombier 	e->pln = sizeof(e->spa);
4977dd7cddfSDavid du Colombier 	hnputs(e->op, ARPREQUEST);
4987dd7cddfSDavid du Colombier 	bp->wp += n;
4997dd7cddfSDavid du Colombier 
500db7ae703SDavid du Colombier 	devtab[er->achan->type]->bwrite(er->achan, bp, 0);
5017dd7cddfSDavid du Colombier }
5027dd7cddfSDavid du Colombier 
5033ff48bf5SDavid du Colombier static void
resolveaddr6(Ipifc * ifc,Arpent * a)5043ff48bf5SDavid du Colombier resolveaddr6(Ipifc *ifc, Arpent *a)
5053ff48bf5SDavid du Colombier {
5063ff48bf5SDavid du Colombier 	int sflag;
5073ff48bf5SDavid du Colombier 	Block *bp;
5083ff48bf5SDavid du Colombier 	Etherrock *er = ifc->arg;
5093ff48bf5SDavid du Colombier 	uchar ipsrc[IPaddrlen];
5103ff48bf5SDavid du Colombier 
5113ff48bf5SDavid du Colombier 	/* don't do anything if it's been less than a second since the last */
512a6a9e072SDavid du Colombier 	if(NOW - a->ctime < ReTransTimer){
5133ff48bf5SDavid du Colombier 		arprelease(er->f->arp, a);
5143ff48bf5SDavid du Colombier 		return;
5153ff48bf5SDavid du Colombier 	}
5163ff48bf5SDavid du Colombier 
5173ff48bf5SDavid du Colombier 	/* remove all but the last message */
5183ff48bf5SDavid du Colombier 	while((bp = a->hold) != nil){
5193ff48bf5SDavid du Colombier 		if(bp == a->last)
5203ff48bf5SDavid du Colombier 			break;
5213ff48bf5SDavid du Colombier 		a->hold = bp->list;
5223ff48bf5SDavid du Colombier 		freeblist(bp);
5233ff48bf5SDavid du Colombier 	}
5243ff48bf5SDavid du Colombier 
5253ff48bf5SDavid du Colombier 	/* try to keep it around for a second more */
526a6a9e072SDavid du Colombier 	a->ctime = NOW;
527a6a9e072SDavid du Colombier 	a->rtime = NOW + ReTransTimer;
5283ff48bf5SDavid du Colombier 	if(a->rxtsrem <= 0) {
5293ff48bf5SDavid du Colombier 		arprelease(er->f->arp, a);
5303ff48bf5SDavid du Colombier 		return;
5313ff48bf5SDavid du Colombier 	}
5323ff48bf5SDavid du Colombier 
5333ff48bf5SDavid du Colombier 	a->rxtsrem--;
5343ff48bf5SDavid du Colombier 	arprelease(er->f->arp, a);
5353ff48bf5SDavid du Colombier 
5363ff48bf5SDavid du Colombier 	if(sflag = ipv6anylocal(ifc, ipsrc))
5373ff48bf5SDavid du Colombier 		icmpns(er->f, ipsrc, sflag, a->ip, TARG_MULTI, ifc->mac);
5383ff48bf5SDavid du Colombier }
5393ff48bf5SDavid du Colombier 
5407dd7cddfSDavid du Colombier /*
5417dd7cddfSDavid du Colombier  *  send a gratuitous arp to refresh arp caches
5427dd7cddfSDavid du Colombier  */
5437dd7cddfSDavid du Colombier static void
sendgarp(Ipifc * ifc,uchar * ip)5447dd7cddfSDavid du Colombier sendgarp(Ipifc *ifc, uchar *ip)
5457dd7cddfSDavid du Colombier {
5467dd7cddfSDavid du Colombier 	int n;
5477dd7cddfSDavid du Colombier 	Block *bp;
5487dd7cddfSDavid du Colombier 	Etherarp *e;
5497dd7cddfSDavid du Colombier 	Etherrock *er = ifc->arg;
5507dd7cddfSDavid du Colombier 
5517dd7cddfSDavid du Colombier 	/* don't arp for our initial non address */
5527dd7cddfSDavid du Colombier 	if(ipcmp(ip, IPnoaddr) == 0)
5537dd7cddfSDavid du Colombier 		return;
5547dd7cddfSDavid du Colombier 
5557dd7cddfSDavid du Colombier 	n = sizeof(Etherarp);
5563f695129SDavid du Colombier 	if(n < ifc->m->mintu)
5573f695129SDavid du Colombier 		n = ifc->m->mintu;
5587dd7cddfSDavid du Colombier 	bp = allocb(n);
5597dd7cddfSDavid du Colombier 	memset(bp->rp, 0, n);
5607dd7cddfSDavid du Colombier 	e = (Etherarp*)bp->rp;
5617dd7cddfSDavid du Colombier 	memmove(e->tpa, ip+IPv4off, sizeof(e->tpa));
5627dd7cddfSDavid du Colombier 	memmove(e->spa, ip+IPv4off, sizeof(e->spa));
5637dd7cddfSDavid du Colombier 	memmove(e->sha, ifc->mac, sizeof(e->sha));
5647dd7cddfSDavid du Colombier 	memset(e->d, 0xff, sizeof(e->d));		/* ethernet broadcast */
5657dd7cddfSDavid du Colombier 	memmove(e->s, ifc->mac, sizeof(e->s));
5667dd7cddfSDavid du Colombier 
5677dd7cddfSDavid du Colombier 	hnputs(e->type, ETARP);
5687dd7cddfSDavid du Colombier 	hnputs(e->hrd, 1);
5693ff48bf5SDavid du Colombier 	hnputs(e->pro, ETIP4);
5707dd7cddfSDavid du Colombier 	e->hln = sizeof(e->sha);
5717dd7cddfSDavid du Colombier 	e->pln = sizeof(e->spa);
5727dd7cddfSDavid du Colombier 	hnputs(e->op, ARPREQUEST);
5737dd7cddfSDavid du Colombier 	bp->wp += n;
5747dd7cddfSDavid du Colombier 
575db7ae703SDavid du Colombier 	devtab[er->achan->type]->bwrite(er->achan, bp, 0);
5767dd7cddfSDavid du Colombier }
5777dd7cddfSDavid du Colombier 
5787dd7cddfSDavid du Colombier static void
recvarp(Ipifc * ifc)5797dd7cddfSDavid du Colombier recvarp(Ipifc *ifc)
5807dd7cddfSDavid du Colombier {
5817dd7cddfSDavid du Colombier 	int n;
5827dd7cddfSDavid du Colombier 	Block *ebp, *rbp;
5837dd7cddfSDavid du Colombier 	Etherarp *e, *r;
5847dd7cddfSDavid du Colombier 	uchar ip[IPaddrlen];
585ef9eff0bSDavid du Colombier 	static uchar eprinted[4];
5867dd7cddfSDavid du Colombier 	Etherrock *er = ifc->arg;
5877dd7cddfSDavid du Colombier 
5883f695129SDavid du Colombier 	ebp = devtab[er->achan->type]->bread(er->achan, ifc->maxtu, 0);
589db7ae703SDavid du Colombier 	if(ebp == nil)
5907dd7cddfSDavid du Colombier 		return;
5917dd7cddfSDavid du Colombier 
5927dd7cddfSDavid du Colombier 	e = (Etherarp*)ebp->rp;
5937dd7cddfSDavid du Colombier 	switch(nhgets(e->op)) {
5947dd7cddfSDavid du Colombier 	default:
5957dd7cddfSDavid du Colombier 		break;
5967dd7cddfSDavid du Colombier 
5977dd7cddfSDavid du Colombier 	case ARPREPLY:
5983ff48bf5SDavid du Colombier 		/* check for machine using my ip address */
5993ff48bf5SDavid du Colombier 		v4tov6(ip, e->spa);
6009a747e4fSDavid du Colombier 		if(iplocalonifc(ifc, ip) || ipproxyifc(er->f, ifc, ip)){
6019a747e4fSDavid du Colombier 			if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0){
6029a747e4fSDavid du Colombier 				print("arprep: 0x%E/0x%E also has ip addr %V\n",
6039a747e4fSDavid du Colombier 					e->s, e->sha, e->spa);
6049a747e4fSDavid du Colombier 				break;
6059a747e4fSDavid du Colombier 			}
6069a747e4fSDavid du Colombier 		}
6073ff48bf5SDavid du Colombier 
6085d82c6aeSDavid du Colombier 		/* make sure we're not entering broadcast addresses */
6095d82c6aeSDavid du Colombier 		if(ipcmp(ip, ipbroadcast) == 0 ||
6105d82c6aeSDavid du Colombier 			!memcmp(e->sha, etherbroadcast, sizeof(e->sha))){
6115d82c6aeSDavid du Colombier 			print("arprep: 0x%E/0x%E cannot register broadcast address %I\n",
6125d82c6aeSDavid du Colombier 				e->s, e->sha, e->spa);
6135d82c6aeSDavid du Colombier 			break;
6145d82c6aeSDavid du Colombier 		}
6155d82c6aeSDavid du Colombier 
6167dd7cddfSDavid du Colombier 		arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), 0);
6177dd7cddfSDavid du Colombier 		break;
6187dd7cddfSDavid du Colombier 
6197dd7cddfSDavid du Colombier 	case ARPREQUEST:
6207dd7cddfSDavid du Colombier 		/* don't answer arps till we know who we are */
6217dd7cddfSDavid du Colombier 		if(ifc->lifc == 0)
6227dd7cddfSDavid du Colombier 			break;
6237dd7cddfSDavid du Colombier 
6243ff48bf5SDavid du Colombier 		/* check for machine using my ip or ether address */
6257dd7cddfSDavid du Colombier 		v4tov6(ip, e->spa);
6267dd7cddfSDavid du Colombier 		if(iplocalonifc(ifc, ip) || ipproxyifc(er->f, ifc, ip)){
627ef9eff0bSDavid du Colombier 			if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0){
628ef9eff0bSDavid du Colombier 				if (memcmp(eprinted, e->spa, sizeof(e->spa))){
629ef9eff0bSDavid du Colombier 					/* print only once */
6303ff48bf5SDavid du Colombier 					print("arpreq: 0x%E also has ip addr %V\n", e->sha, e->spa);
631ef9eff0bSDavid du Colombier 					memmove(eprinted, e->spa, sizeof(e->spa));
632ef9eff0bSDavid du Colombier 				}
633ef9eff0bSDavid du Colombier 			}
6347dd7cddfSDavid du Colombier 		} else {
6357dd7cddfSDavid du Colombier 			if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) == 0){
6363ff48bf5SDavid du Colombier 				print("arpreq: %V also has ether addr %E\n", e->spa, e->sha);
6377dd7cddfSDavid du Colombier 				break;
6387dd7cddfSDavid du Colombier 			}
6397dd7cddfSDavid du Colombier 		}
6407dd7cddfSDavid du Colombier 
6417dd7cddfSDavid du Colombier 		/* refresh what we know about sender */
6427dd7cddfSDavid du Colombier 		arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), 1);
6437dd7cddfSDavid du Colombier 
6447dd7cddfSDavid du Colombier 		/* answer only requests for our address or systems we're proxying for */
6457dd7cddfSDavid du Colombier 		v4tov6(ip, e->tpa);
6467dd7cddfSDavid du Colombier 		if(!iplocalonifc(ifc, ip))
6477dd7cddfSDavid du Colombier 		if(!ipproxyifc(er->f, ifc, ip))
6487dd7cddfSDavid du Colombier 			break;
6497dd7cddfSDavid du Colombier 
6507dd7cddfSDavid du Colombier 		n = sizeof(Etherarp);
6513f695129SDavid du Colombier 		if(n < ifc->mintu)
6523f695129SDavid du Colombier 			n = ifc->mintu;
6537dd7cddfSDavid du Colombier 		rbp = allocb(n);
6547dd7cddfSDavid du Colombier 		r = (Etherarp*)rbp->rp;
6557dd7cddfSDavid du Colombier 		memset(r, 0, sizeof(Etherarp));
6567dd7cddfSDavid du Colombier 		hnputs(r->type, ETARP);
6577dd7cddfSDavid du Colombier 		hnputs(r->hrd, 1);
6583ff48bf5SDavid du Colombier 		hnputs(r->pro, ETIP4);
6597dd7cddfSDavid du Colombier 		r->hln = sizeof(r->sha);
6607dd7cddfSDavid du Colombier 		r->pln = sizeof(r->spa);
6617dd7cddfSDavid du Colombier 		hnputs(r->op, ARPREPLY);
6627dd7cddfSDavid du Colombier 		memmove(r->tha, e->sha, sizeof(r->tha));
6637dd7cddfSDavid du Colombier 		memmove(r->tpa, e->spa, sizeof(r->tpa));
6647dd7cddfSDavid du Colombier 		memmove(r->sha, ifc->mac, sizeof(r->sha));
6657dd7cddfSDavid du Colombier 		memmove(r->spa, e->tpa, sizeof(r->spa));
6667dd7cddfSDavid du Colombier 		memmove(r->d, e->sha, sizeof(r->d));
6677dd7cddfSDavid du Colombier 		memmove(r->s, ifc->mac, sizeof(r->s));
6687dd7cddfSDavid du Colombier 		rbp->wp += n;
6697dd7cddfSDavid du Colombier 
670db7ae703SDavid du Colombier 		devtab[er->achan->type]->bwrite(er->achan, rbp, 0);
6717dd7cddfSDavid du Colombier 	}
6727dd7cddfSDavid du Colombier 	freeb(ebp);
6737dd7cddfSDavid du Colombier }
6747dd7cddfSDavid du Colombier 
6757dd7cddfSDavid du Colombier static void
recvarpproc(void * v)6767dd7cddfSDavid du Colombier recvarpproc(void *v)
6777dd7cddfSDavid du Colombier {
6787dd7cddfSDavid du Colombier 	Ipifc *ifc = v;
6797dd7cddfSDavid du Colombier 	Etherrock *er = ifc->arg;
6807dd7cddfSDavid du Colombier 
6817dd7cddfSDavid du Colombier 	er->arpp = up;
6827dd7cddfSDavid du Colombier 	if(waserror()){
6837dd7cddfSDavid du Colombier 		er->arpp = 0;
6847dd7cddfSDavid du Colombier 		pexit("hangup", 1);
6857dd7cddfSDavid du Colombier 	}
6867dd7cddfSDavid du Colombier 	for(;;)
6877dd7cddfSDavid du Colombier 		recvarp(ifc);
6887dd7cddfSDavid du Colombier }
6897dd7cddfSDavid du Colombier 
6907dd7cddfSDavid du Colombier static int
multicastea(uchar * ea,uchar * ip)6917dd7cddfSDavid du Colombier multicastea(uchar *ea, uchar *ip)
6927dd7cddfSDavid du Colombier {
6937dd7cddfSDavid du Colombier 	int x;
6947dd7cddfSDavid du Colombier 
6957dd7cddfSDavid du Colombier 	switch(x = ipismulticast(ip)){
6967dd7cddfSDavid du Colombier 	case V4:
6977dd7cddfSDavid du Colombier 		ea[0] = 0x01;
6987dd7cddfSDavid du Colombier 		ea[1] = 0x00;
6997dd7cddfSDavid du Colombier 		ea[2] = 0x5e;
7007dd7cddfSDavid du Colombier 		ea[3] = ip[13] & 0x7f;
7017dd7cddfSDavid du Colombier 		ea[4] = ip[14];
7027dd7cddfSDavid du Colombier 		ea[5] = ip[15];
7037dd7cddfSDavid du Colombier 		break;
7047dd7cddfSDavid du Colombier  	case V6:
7057dd7cddfSDavid du Colombier  		ea[0] = 0x33;
7067dd7cddfSDavid du Colombier  		ea[1] = 0x33;
7077dd7cddfSDavid du Colombier  		ea[2] = ip[12];
7087dd7cddfSDavid du Colombier 		ea[3] = ip[13];
7097dd7cddfSDavid du Colombier  		ea[4] = ip[14];
7107dd7cddfSDavid du Colombier  		ea[5] = ip[15];
7117dd7cddfSDavid du Colombier  		break;
7127dd7cddfSDavid du Colombier 	}
7137dd7cddfSDavid du Colombier 	return x;
7147dd7cddfSDavid du Colombier }
7157dd7cddfSDavid du Colombier 
7167dd7cddfSDavid du Colombier /*
7177dd7cddfSDavid du Colombier  *  fill in an arp entry for broadcast or multicast
7183ff48bf5SDavid du Colombier  *  addresses.  Return the first queued packet for the
7193ff48bf5SDavid du Colombier  *  IP address.
7207dd7cddfSDavid du Colombier  */
7217dd7cddfSDavid du Colombier static Block*
multicastarp(Fs * f,Arpent * a,Medium * medium,uchar * mac)72259cc4ca5SDavid du Colombier multicastarp(Fs *f, Arpent *a, Medium *medium, uchar *mac)
7237dd7cddfSDavid du Colombier {
7247dd7cddfSDavid du Colombier 	/* is it broadcast? */
7257dd7cddfSDavid du Colombier 	switch(ipforme(f, a->ip)){
7267dd7cddfSDavid du Colombier 	case Runi:
7277dd7cddfSDavid du Colombier 		return nil;
7287dd7cddfSDavid du Colombier 	case Rbcast:
7297dd7cddfSDavid du Colombier 		memset(mac, 0xff, 6);
73059cc4ca5SDavid du Colombier 		return arpresolve(f->arp, a, medium, mac);
7317dd7cddfSDavid du Colombier 	default:
7327dd7cddfSDavid du Colombier 		break;
7337dd7cddfSDavid du Colombier 	}
7347dd7cddfSDavid du Colombier 
7357dd7cddfSDavid du Colombier 	/* if multicast, fill in mac */
7367dd7cddfSDavid du Colombier 	switch(multicastea(mac, a->ip)){
7377dd7cddfSDavid du Colombier 	case V4:
7387dd7cddfSDavid du Colombier 	case V6:
73959cc4ca5SDavid du Colombier 		return arpresolve(f->arp, a, medium, mac);
7407dd7cddfSDavid du Colombier 	}
7417dd7cddfSDavid du Colombier 
7427dd7cddfSDavid du Colombier 	/* let arp take care of it */
7437dd7cddfSDavid du Colombier 	return nil;
7447dd7cddfSDavid du Colombier }
7457dd7cddfSDavid du Colombier 
7467dd7cddfSDavid du Colombier void
ethermediumlink(void)7477dd7cddfSDavid du Colombier ethermediumlink(void)
7487dd7cddfSDavid du Colombier {
7497dd7cddfSDavid du Colombier 	addipmedium(&ethermedium);
75059cc4ca5SDavid du Colombier 	addipmedium(&gbemedium);
7517dd7cddfSDavid du Colombier }
7523ff48bf5SDavid du Colombier 
7533ff48bf5SDavid du Colombier 
7543ff48bf5SDavid du Colombier static void
etherpref2addr(uchar * pref,uchar * ea)7553ff48bf5SDavid du Colombier etherpref2addr(uchar *pref, uchar *ea)
7563ff48bf5SDavid du Colombier {
7573ff48bf5SDavid du Colombier 	pref[8] = ea[0] | 0x2;
7583ff48bf5SDavid du Colombier 	pref[9] = ea[1];
7593ff48bf5SDavid du Colombier 	pref[10] = ea[2];
7603ff48bf5SDavid du Colombier 	pref[11] = 0xFF;
7613ff48bf5SDavid du Colombier 	pref[12] = 0xFE;
7623ff48bf5SDavid du Colombier 	pref[13] = ea[3];
7633ff48bf5SDavid du Colombier 	pref[14] = ea[4];
7643ff48bf5SDavid du Colombier 	pref[15] = ea[5];
7653ff48bf5SDavid du Colombier }
766