xref: /plan9/sys/src/9/ip/ethermedium.c (revision db7ae7034f6930e84fdbcfbe73a0d57507a48945)
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 
195d82c6aeSDavid du Colombier static uchar ipbroadcast[IPaddrlen] = {
205d82c6aeSDavid du Colombier 	0xff,0xff,0xff,0xff,
215d82c6aeSDavid du Colombier 	0xff,0xff,0xff,0xff,
225d82c6aeSDavid du Colombier 	0xff,0xff,0xff,0xff,
235d82c6aeSDavid du Colombier 	0xff,0xff,0xff,0xff,
245d82c6aeSDavid du Colombier };
255d82c6aeSDavid du Colombier 
265d82c6aeSDavid du Colombier static uchar etherbroadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
275d82c6aeSDavid du Colombier 
283ff48bf5SDavid du Colombier static void	etherread4(void *a);
293ff48bf5SDavid du Colombier static void	etherread6(void *a);
307dd7cddfSDavid du Colombier static void	etherbind(Ipifc *ifc, int argc, char **argv);
317dd7cddfSDavid du Colombier static void	etherunbind(Ipifc *ifc);
327dd7cddfSDavid du Colombier static void	etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip);
337dd7cddfSDavid du Colombier static void	etheraddmulti(Ipifc *ifc, uchar *a, uchar *ia);
347dd7cddfSDavid du Colombier static void	etherremmulti(Ipifc *ifc, uchar *a, uchar *ia);
3559cc4ca5SDavid du Colombier static Block*	multicastarp(Fs *f, Arpent *a, Medium*, uchar *mac);
367dd7cddfSDavid du Colombier static void	sendarp(Ipifc *ifc, Arpent *a);
377dd7cddfSDavid du Colombier static void	sendgarp(Ipifc *ifc, uchar*);
387dd7cddfSDavid du Colombier static int	multicastea(uchar *ea, uchar *ip);
397dd7cddfSDavid du Colombier static void	recvarpproc(void*);
403ff48bf5SDavid du Colombier static void	resolveaddr6(Ipifc *ifc, Arpent *a);
413ff48bf5SDavid du Colombier static void	etherpref2addr(uchar *pref, uchar *ea);
427dd7cddfSDavid du Colombier 
437dd7cddfSDavid du Colombier Medium ethermedium =
447dd7cddfSDavid du Colombier {
457dd7cddfSDavid du Colombier .name=		"ether",
467dd7cddfSDavid du Colombier .hsize=		14,
473f695129SDavid du Colombier .mintu=		60,
483f695129SDavid du Colombier .maxtu=		1514,
497dd7cddfSDavid du Colombier .maclen=	6,
507dd7cddfSDavid du Colombier .bind=		etherbind,
517dd7cddfSDavid du Colombier .unbind=	etherunbind,
527dd7cddfSDavid du Colombier .bwrite=	etherbwrite,
537dd7cddfSDavid du Colombier .addmulti=	etheraddmulti,
547dd7cddfSDavid du Colombier .remmulti=	etherremmulti,
557dd7cddfSDavid du Colombier .ares=		arpenter,
567dd7cddfSDavid du Colombier .areg=		sendgarp,
573ff48bf5SDavid du Colombier .pref2addr=	etherpref2addr,
587dd7cddfSDavid du Colombier };
597dd7cddfSDavid du Colombier 
6059cc4ca5SDavid du Colombier Medium gbemedium =
6159cc4ca5SDavid du Colombier {
6259cc4ca5SDavid du Colombier .name=		"gbe",
6359cc4ca5SDavid du Colombier .hsize=		14,
643f695129SDavid du Colombier .mintu=		60,
653f695129SDavid du Colombier .maxtu=		9014,
6659cc4ca5SDavid du Colombier .maclen=	6,
6759cc4ca5SDavid du Colombier .bind=		etherbind,
6859cc4ca5SDavid du Colombier .unbind=	etherunbind,
6959cc4ca5SDavid du Colombier .bwrite=	etherbwrite,
7059cc4ca5SDavid du Colombier .addmulti=	etheraddmulti,
7159cc4ca5SDavid du Colombier .remmulti=	etherremmulti,
7259cc4ca5SDavid du Colombier .ares=		arpenter,
7359cc4ca5SDavid du Colombier .areg=		sendgarp,
743ff48bf5SDavid du Colombier .pref2addr=	etherpref2addr,
7559cc4ca5SDavid du Colombier };
7659cc4ca5SDavid du Colombier 
777dd7cddfSDavid du Colombier typedef struct	Etherrock Etherrock;
787dd7cddfSDavid du Colombier struct Etherrock
797dd7cddfSDavid du Colombier {
807dd7cddfSDavid du Colombier 	Fs	*f;		/* file system we belong to */
817dd7cddfSDavid du Colombier 	Proc	*arpp;		/* arp process */
823ff48bf5SDavid du Colombier 	Proc	*read4p;	/* reading process (v4)*/
833ff48bf5SDavid du Colombier 	Proc	*read6p;	/* reading process (v6)*/
843ff48bf5SDavid du Colombier 	Chan	*mchan4;	/* Data channel for v4 */
857dd7cddfSDavid du Colombier 	Chan	*achan;		/* Arp channel */
863ff48bf5SDavid du Colombier 	Chan	*cchan4;	/* Control channel for v4 */
873ff48bf5SDavid du Colombier 	Chan	*mchan6;	/* Data channel for v6 */
883ff48bf5SDavid du Colombier 	Chan	*cchan6;	/* Control channel for v6 */
897dd7cddfSDavid du Colombier };
907dd7cddfSDavid du Colombier 
917dd7cddfSDavid du Colombier /*
927dd7cddfSDavid du Colombier  *  ethernet arp request
937dd7cddfSDavid du Colombier  */
947dd7cddfSDavid du Colombier enum
957dd7cddfSDavid du Colombier {
967dd7cddfSDavid du Colombier 	ETARP		= 0x0806,
973ff48bf5SDavid du Colombier 	ETIP4		= 0x0800,
983ff48bf5SDavid du Colombier 	ETIP6		= 0x86DD,
997dd7cddfSDavid du Colombier 	ARPREQUEST	= 1,
1007dd7cddfSDavid du Colombier 	ARPREPLY	= 2,
1017dd7cddfSDavid du Colombier };
1023ff48bf5SDavid du Colombier 
1037dd7cddfSDavid du Colombier typedef struct Etherarp Etherarp;
1047dd7cddfSDavid du Colombier struct Etherarp
1057dd7cddfSDavid du Colombier {
1067dd7cddfSDavid du Colombier 	uchar	d[6];
1077dd7cddfSDavid du Colombier 	uchar	s[6];
1087dd7cddfSDavid du Colombier 	uchar	type[2];
1097dd7cddfSDavid du Colombier 	uchar	hrd[2];
1107dd7cddfSDavid du Colombier 	uchar	pro[2];
1117dd7cddfSDavid du Colombier 	uchar	hln;
1127dd7cddfSDavid du Colombier 	uchar	pln;
1137dd7cddfSDavid du Colombier 	uchar	op[2];
1147dd7cddfSDavid du Colombier 	uchar	sha[6];
1157dd7cddfSDavid du Colombier 	uchar	spa[4];
1167dd7cddfSDavid du Colombier 	uchar	tha[6];
1177dd7cddfSDavid du Colombier 	uchar	tpa[4];
1187dd7cddfSDavid du Colombier };
1197dd7cddfSDavid du Colombier 
1203ff48bf5SDavid du Colombier static char *nbmsg = "nonblocking";
1217dd7cddfSDavid du Colombier 
1227dd7cddfSDavid du Colombier /*
1237dd7cddfSDavid du Colombier  *  called to bind an IP ifc to an ethernet device
1247dd7cddfSDavid du Colombier  *  called with ifc wlock'd
1257dd7cddfSDavid du Colombier  */
1267dd7cddfSDavid du Colombier static void
1277dd7cddfSDavid du Colombier etherbind(Ipifc *ifc, int argc, char **argv)
1287dd7cddfSDavid du Colombier {
1293ff48bf5SDavid du Colombier 	Chan *mchan4, *cchan4, *achan, *mchan6, *cchan6, *schan;
1303ff48bf5SDavid du Colombier 	char addr[Maxpath];	//char addr[2*KNAMELEN];
1313ff48bf5SDavid du Colombier 	char dir[Maxpath];	//char dir[2*KNAMELEN];
1327dd7cddfSDavid du Colombier 	char *buf;
13380ee5cbfSDavid du Colombier 	int n;
1347dd7cddfSDavid du Colombier 	char *ptr;
1357dd7cddfSDavid du Colombier 	Etherrock *er;
1367dd7cddfSDavid du Colombier 
1377dd7cddfSDavid du Colombier 	if(argc < 2)
1387dd7cddfSDavid du Colombier 		error(Ebadarg);
1397dd7cddfSDavid du Colombier 
1403ff48bf5SDavid du Colombier 	mchan4 = cchan4 = achan = mchan6 = cchan6 = nil;
1417dd7cddfSDavid du Colombier 	buf = nil;
1427dd7cddfSDavid du Colombier 	if(waserror()){
1433ff48bf5SDavid du Colombier 		if(mchan4 != nil)
1443ff48bf5SDavid du Colombier 			cclose(mchan4);
1453ff48bf5SDavid du Colombier 		if(cchan4 != nil)
1463ff48bf5SDavid du Colombier 			cclose(cchan4);
1477dd7cddfSDavid du Colombier 		if(achan != nil)
1487dd7cddfSDavid du Colombier 			cclose(achan);
1493ff48bf5SDavid du Colombier 		if(mchan6 != nil)
1503ff48bf5SDavid du Colombier 			cclose(mchan6);
1513ff48bf5SDavid du Colombier 		if(cchan6 != nil)
1523ff48bf5SDavid du Colombier 			cclose(cchan6);
1537dd7cddfSDavid du Colombier 		if(buf != nil)
1547dd7cddfSDavid du Colombier 			free(buf);
1557dd7cddfSDavid du Colombier 		nexterror();
1567dd7cddfSDavid du Colombier 	}
1577dd7cddfSDavid du Colombier 
1587dd7cddfSDavid du Colombier 	/*
1593e76a0ddSDavid du Colombier 	 *  open ipv4 converstation
1607dd7cddfSDavid du Colombier 	 *
1617dd7cddfSDavid du Colombier 	 *  the dial will fail if the type is already open on
1627dd7cddfSDavid du Colombier 	 *  this device.
1637dd7cddfSDavid du Colombier 	 */
1647dd7cddfSDavid du Colombier 	snprint(addr, sizeof(addr), "%s!0x800", argv[2]);
1653ff48bf5SDavid du Colombier 	mchan4 = chandial(addr, nil, dir, &cchan4);
1663ff48bf5SDavid du Colombier 
1673ff48bf5SDavid du Colombier 	/*
1683ff48bf5SDavid du Colombier 	 *  make it non-blocking
1693ff48bf5SDavid du Colombier 	 */
1703ff48bf5SDavid du Colombier 	devtab[cchan4->type]->write(cchan4, nbmsg, strlen(nbmsg), 0);
1717dd7cddfSDavid du Colombier 
1727dd7cddfSDavid du Colombier 	/*
1733f695129SDavid du Colombier 	 *  get mac address and speed
1747dd7cddfSDavid du Colombier 	 */
1753432ceaeSDavid du Colombier 	snprint(addr, sizeof(addr), "%s/stats", argv[2]);
1767dd7cddfSDavid du Colombier 	buf = smalloc(512);
1773ff48bf5SDavid du Colombier 	schan = namec(addr, Aopen, OREAD, 0);
1783ff48bf5SDavid du Colombier 	if(waserror()){
1793ff48bf5SDavid du Colombier 		cclose(schan);
1803ff48bf5SDavid du Colombier 		nexterror();
1813ff48bf5SDavid du Colombier 	}
1823ff48bf5SDavid du Colombier 	n = devtab[schan->type]->read(schan, buf, 511, 0);
1833ff48bf5SDavid du Colombier 	cclose(schan);
1843ff48bf5SDavid du Colombier 	poperror();
1857dd7cddfSDavid du Colombier 	buf[n] = 0;
1867dd7cddfSDavid du Colombier 
1877dd7cddfSDavid du Colombier 	ptr = strstr(buf, "addr: ");
1887dd7cddfSDavid du Colombier 	if(!ptr)
1897dd7cddfSDavid du Colombier 		error(Eio);
1907dd7cddfSDavid du Colombier 	ptr += 6;
1917dd7cddfSDavid du Colombier 	parsemac(ifc->mac, ptr, 6);
1927dd7cddfSDavid du Colombier 
1933f695129SDavid du Colombier 	ptr = strstr(buf, "mbps: ");
1943f695129SDavid du Colombier 	if(ptr){
1953f695129SDavid du Colombier 		ptr += 6;
1963f695129SDavid du Colombier 		ifc->mbps = atoi(ptr);
1973f695129SDavid du Colombier 	} else
1983f695129SDavid du Colombier 		ifc->mbps = 100;
1993f695129SDavid du Colombier 
2007dd7cddfSDavid du Colombier 	/*
2017dd7cddfSDavid du Colombier  	 *  open arp conversation
2027dd7cddfSDavid du Colombier 	 */
2037dd7cddfSDavid du Colombier 	snprint(addr, sizeof(addr), "%s!0x806", argv[2]);
20480ee5cbfSDavid du Colombier 	achan = chandial(addr, nil, nil, nil);
2057dd7cddfSDavid du Colombier 
2063ff48bf5SDavid du Colombier 	/*
2073e76a0ddSDavid du Colombier 	 *  open ipv6 conversation
2083ff48bf5SDavid du Colombier 	 *
2093ff48bf5SDavid du Colombier 	 *  the dial will fail if the type is already open on
2103ff48bf5SDavid du Colombier 	 *  this device.
2113ff48bf5SDavid du Colombier 	 */
2123ff48bf5SDavid du Colombier 	snprint(addr, sizeof(addr), "%s!0x86DD", argv[2]);
2133ff48bf5SDavid du Colombier 	mchan6 = chandial(addr, nil, dir, &cchan6);
2143ff48bf5SDavid du Colombier 
2153ff48bf5SDavid du Colombier 	/*
2163ff48bf5SDavid du Colombier 	 *  make it non-blocking
2173ff48bf5SDavid du Colombier 	 */
2183ff48bf5SDavid du Colombier 	devtab[cchan6->type]->write(cchan6, nbmsg, strlen(nbmsg), 0);
2193ff48bf5SDavid du Colombier 
2207dd7cddfSDavid du Colombier 	er = smalloc(sizeof(*er));
2213ff48bf5SDavid du Colombier 	er->mchan4 = mchan4;
2223ff48bf5SDavid du Colombier 	er->cchan4 = cchan4;
2237dd7cddfSDavid du Colombier 	er->achan = achan;
2243ff48bf5SDavid du Colombier 	er->mchan6 = mchan6;
2253ff48bf5SDavid du Colombier 	er->cchan6 = cchan6;
2267dd7cddfSDavid du Colombier 	er->f = ifc->conv->p->f;
2277dd7cddfSDavid du Colombier 	ifc->arg = er;
2287dd7cddfSDavid du Colombier 
2297dd7cddfSDavid du Colombier 	free(buf);
2307dd7cddfSDavid du Colombier 	poperror();
2317dd7cddfSDavid du Colombier 
2323ff48bf5SDavid du Colombier 	kproc("etherread4", etherread4, ifc);
2337dd7cddfSDavid du Colombier 	kproc("recvarpproc", recvarpproc, ifc);
2343ff48bf5SDavid du Colombier 	kproc("etherread6", etherread6, ifc);
2357dd7cddfSDavid du Colombier }
2367dd7cddfSDavid du Colombier 
2377dd7cddfSDavid du Colombier /*
2387dd7cddfSDavid du Colombier  *  called with ifc wlock'd
2397dd7cddfSDavid du Colombier  */
2407dd7cddfSDavid du Colombier static void
2417dd7cddfSDavid du Colombier etherunbind(Ipifc *ifc)
2427dd7cddfSDavid du Colombier {
2437dd7cddfSDavid du Colombier 	Etherrock *er = ifc->arg;
2447dd7cddfSDavid du Colombier 
2453ff48bf5SDavid du Colombier 	if(er->read4p)
2463ff48bf5SDavid du Colombier 		postnote(er->read4p, 1, "unbind", 0);
2473ff48bf5SDavid du Colombier 	if(er->read6p)
2483ff48bf5SDavid du Colombier 		postnote(er->read6p, 1, "unbind", 0);
2497dd7cddfSDavid du Colombier 	if(er->arpp)
2507dd7cddfSDavid du Colombier 		postnote(er->arpp, 1, "unbind", 0);
2517dd7cddfSDavid du Colombier 
2527dd7cddfSDavid du Colombier 	/* wait for readers to die */
2533ff48bf5SDavid du Colombier 	while(er->arpp != 0 || er->read4p != 0 || er->read6p != 0)
2547dd7cddfSDavid du Colombier 		tsleep(&up->sleep, return0, 0, 300);
2557dd7cddfSDavid du Colombier 
2563ff48bf5SDavid du Colombier 	if(er->mchan4 != nil)
2573ff48bf5SDavid du Colombier 		cclose(er->mchan4);
2587dd7cddfSDavid du Colombier 	if(er->achan != nil)
2597dd7cddfSDavid du Colombier 		cclose(er->achan);
2603ff48bf5SDavid du Colombier 	if(er->cchan4 != nil)
2613ff48bf5SDavid du Colombier 		cclose(er->cchan4);
2623ff48bf5SDavid du Colombier 	if(er->mchan6 != nil)
2633ff48bf5SDavid du Colombier 		cclose(er->mchan6);
2643ff48bf5SDavid du Colombier 	if(er->cchan6 != nil)
2653ff48bf5SDavid du Colombier 		cclose(er->cchan6);
2667dd7cddfSDavid du Colombier 
2677dd7cddfSDavid du Colombier 	free(er);
2687dd7cddfSDavid du Colombier }
2697dd7cddfSDavid du Colombier 
2707dd7cddfSDavid du Colombier /*
2717dd7cddfSDavid du Colombier  *  called by ipoput with a single block to write with ifc rlock'd
2727dd7cddfSDavid du Colombier  */
2737dd7cddfSDavid du Colombier static void
2747dd7cddfSDavid du Colombier etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip)
2757dd7cddfSDavid du Colombier {
2767dd7cddfSDavid du Colombier 	Etherhdr *eh;
2777dd7cddfSDavid du Colombier 	Arpent *a;
2787dd7cddfSDavid du Colombier 	uchar mac[6];
2797dd7cddfSDavid du Colombier 	Etherrock *er = ifc->arg;
2807dd7cddfSDavid du Colombier 
2817dd7cddfSDavid du Colombier 	/* get mac address of destination */
2823ff48bf5SDavid du Colombier 	a = arpget(er->f->arp, bp, version, ifc, ip, mac);
2837dd7cddfSDavid du Colombier 	if(a){
2847dd7cddfSDavid du Colombier 		/* check for broadcast or multicast */
28559cc4ca5SDavid du Colombier 		bp = multicastarp(er->f, a, ifc->m, mac);
2867dd7cddfSDavid du Colombier 		if(bp==nil){
2873ff48bf5SDavid du Colombier 			switch(version){
2883ff48bf5SDavid du Colombier 			case V4:
2897dd7cddfSDavid du Colombier 				sendarp(ifc, a);
2903ff48bf5SDavid du Colombier 				break;
2913ff48bf5SDavid du Colombier 			case V6:
2923ff48bf5SDavid du Colombier 				resolveaddr6(ifc, a);
2933ff48bf5SDavid du Colombier 				break;
2943ff48bf5SDavid du Colombier 			default:
2953ff48bf5SDavid du Colombier 				panic("etherbwrite: version %d", version);
2963ff48bf5SDavid du Colombier 			}
2977dd7cddfSDavid du Colombier 			return;
2987dd7cddfSDavid du Colombier 		}
2997dd7cddfSDavid du Colombier 	}
3007dd7cddfSDavid du Colombier 
3017dd7cddfSDavid du Colombier 	/* make it a single block with space for the ether header */
3027dd7cddfSDavid du Colombier 	bp = padblock(bp, ifc->m->hsize);
3037dd7cddfSDavid du Colombier 	if(bp->next)
3047dd7cddfSDavid du Colombier 		bp = concatblock(bp);
3053f695129SDavid du Colombier 	if(BLEN(bp) < ifc->mintu)
3063f695129SDavid du Colombier 		bp = adjustblock(bp, ifc->mintu);
3077dd7cddfSDavid du Colombier 	eh = (Etherhdr*)bp->rp;
3087dd7cddfSDavid du Colombier 
3097dd7cddfSDavid du Colombier 	/* copy in mac addresses and ether type */
3107dd7cddfSDavid du Colombier 	memmove(eh->s, ifc->mac, sizeof(eh->s));
3117dd7cddfSDavid du Colombier 	memmove(eh->d, mac, sizeof(eh->d));
3123ff48bf5SDavid du Colombier 
3137dd7cddfSDavid du Colombier  	switch(version){
3147dd7cddfSDavid du Colombier 	case V4:
3157dd7cddfSDavid du Colombier 		eh->t[0] = 0x08;
3167dd7cddfSDavid du Colombier 		eh->t[1] = 0x00;
3173ff48bf5SDavid du Colombier 		devtab[er->mchan4->type]->bwrite(er->mchan4, bp, 0);
3187dd7cddfSDavid du Colombier 		break;
3197dd7cddfSDavid du Colombier 	case V6:
3207dd7cddfSDavid du Colombier 		eh->t[0] = 0x86;
3217dd7cddfSDavid du Colombier 		eh->t[1] = 0xDD;
3223ff48bf5SDavid du Colombier 		devtab[er->mchan6->type]->bwrite(er->mchan6, bp, 0);
3237dd7cddfSDavid du Colombier 		break;
3243ff48bf5SDavid du Colombier 	default:
3253ff48bf5SDavid du Colombier 		panic("etherbwrite2: version %d", version);
3267dd7cddfSDavid du Colombier 	}
3277dd7cddfSDavid du Colombier 	ifc->out++;
3287dd7cddfSDavid du Colombier }
3297dd7cddfSDavid du Colombier 
3303ff48bf5SDavid du Colombier 
3317dd7cddfSDavid du Colombier /*
3327dd7cddfSDavid du Colombier  *  process to read from the ethernet
3337dd7cddfSDavid du Colombier  */
3347dd7cddfSDavid du Colombier static void
3353ff48bf5SDavid du Colombier etherread4(void *a)
3367dd7cddfSDavid du Colombier {
3377dd7cddfSDavid du Colombier 	Ipifc *ifc;
3387dd7cddfSDavid du Colombier 	Block *bp;
3397dd7cddfSDavid du Colombier 	Etherrock *er;
3407dd7cddfSDavid du Colombier 
3417dd7cddfSDavid du Colombier 	ifc = a;
3427dd7cddfSDavid du Colombier 	er = ifc->arg;
3433ff48bf5SDavid du Colombier 	er->read4p = up;	/* hide identity under a rock for unbind */
3447dd7cddfSDavid du Colombier 	if(waserror()){
3453ff48bf5SDavid du Colombier 		er->read4p = 0;
3467dd7cddfSDavid du Colombier 		pexit("hangup", 1);
3477dd7cddfSDavid du Colombier 	}
3487dd7cddfSDavid du Colombier 	for(;;){
3493f695129SDavid du Colombier 		bp = devtab[er->mchan4->type]->bread(er->mchan4, ifc->maxtu, 0);
3507dd7cddfSDavid du Colombier 		if(!canrlock(ifc)){
3517dd7cddfSDavid du Colombier 			freeb(bp);
3527dd7cddfSDavid du Colombier 			continue;
3537dd7cddfSDavid du Colombier 		}
3547dd7cddfSDavid du Colombier 		if(waserror()){
3557dd7cddfSDavid du Colombier 			runlock(ifc);
3567dd7cddfSDavid du Colombier 			nexterror();
3577dd7cddfSDavid du Colombier 		}
3587dd7cddfSDavid du Colombier 		ifc->in++;
3597dd7cddfSDavid du Colombier 		bp->rp += ifc->m->hsize;
3607dd7cddfSDavid du Colombier 		if(ifc->lifc == nil)
3617dd7cddfSDavid du Colombier 			freeb(bp);
3627dd7cddfSDavid du Colombier 		else
3633ff48bf5SDavid du Colombier 			ipiput4(er->f, ifc, bp);
3643ff48bf5SDavid du Colombier 		runlock(ifc);
3653ff48bf5SDavid du Colombier 		poperror();
3663ff48bf5SDavid du Colombier 	}
3673ff48bf5SDavid du Colombier }
3683ff48bf5SDavid du Colombier 
3693ff48bf5SDavid du Colombier 
3703ff48bf5SDavid du Colombier /*
3713ff48bf5SDavid du Colombier  *  process to read from the ethernet, IPv6
3723ff48bf5SDavid du Colombier  */
3733ff48bf5SDavid du Colombier static void
3743ff48bf5SDavid du Colombier etherread6(void *a)
3753ff48bf5SDavid du Colombier {
3763ff48bf5SDavid du Colombier 	Ipifc *ifc;
3773ff48bf5SDavid du Colombier 	Block *bp;
3783ff48bf5SDavid du Colombier 	Etherrock *er;
3793ff48bf5SDavid du Colombier 
3803ff48bf5SDavid du Colombier 	ifc = a;
3813ff48bf5SDavid du Colombier 	er = ifc->arg;
3823ff48bf5SDavid du Colombier 	er->read6p = up;	/* hide identity under a rock for unbind */
3833ff48bf5SDavid du Colombier 	if(waserror()){
3843ff48bf5SDavid du Colombier 		er->read6p = 0;
3853ff48bf5SDavid du Colombier 		pexit("hangup", 1);
3863ff48bf5SDavid du Colombier 	}
3873ff48bf5SDavid du Colombier 	for(;;){
3883f695129SDavid du Colombier 		bp = devtab[er->mchan6->type]->bread(er->mchan6, ifc->maxtu, 0);
3893ff48bf5SDavid du Colombier 		if(!canrlock(ifc)){
3903ff48bf5SDavid du Colombier 			freeb(bp);
3913ff48bf5SDavid du Colombier 			continue;
3923ff48bf5SDavid du Colombier 		}
3933ff48bf5SDavid du Colombier 		if(waserror()){
3943ff48bf5SDavid du Colombier 			runlock(ifc);
3953ff48bf5SDavid du Colombier 			nexterror();
3963ff48bf5SDavid du Colombier 		}
3973ff48bf5SDavid du Colombier 		ifc->in++;
3983ff48bf5SDavid du Colombier 		bp->rp += ifc->m->hsize;
3993ff48bf5SDavid du Colombier 		if(ifc->lifc == nil)
4003ff48bf5SDavid du Colombier 			freeb(bp);
4013ff48bf5SDavid du Colombier 		else
4023ff48bf5SDavid du Colombier 			ipiput6(er->f, ifc, bp);
4037dd7cddfSDavid du Colombier 		runlock(ifc);
4047dd7cddfSDavid du Colombier 		poperror();
4057dd7cddfSDavid du Colombier 	}
4067dd7cddfSDavid du Colombier }
4077dd7cddfSDavid du Colombier 
4087dd7cddfSDavid du Colombier static void
4097dd7cddfSDavid du Colombier etheraddmulti(Ipifc *ifc, uchar *a, uchar *)
4107dd7cddfSDavid du Colombier {
4117dd7cddfSDavid du Colombier 	uchar mac[6];
4127dd7cddfSDavid du Colombier 	char buf[64];
4137dd7cddfSDavid du Colombier 	Etherrock *er = ifc->arg;
4143ff48bf5SDavid du Colombier 	int version;
4157dd7cddfSDavid du Colombier 
4163ff48bf5SDavid du Colombier 	version = multicastea(mac, a);
4177dd7cddfSDavid du Colombier 	sprint(buf, "addmulti %E", mac);
4183ff48bf5SDavid du Colombier 	switch(version){
4193ff48bf5SDavid du Colombier 	case V4:
4203ff48bf5SDavid du Colombier 		devtab[er->cchan4->type]->write(er->cchan4, buf, strlen(buf), 0);
4213ff48bf5SDavid du Colombier 		break;
4223ff48bf5SDavid du Colombier 	case V6:
4233ff48bf5SDavid du Colombier 		devtab[er->cchan6->type]->write(er->cchan6, buf, strlen(buf), 0);
4243ff48bf5SDavid du Colombier 		break;
4253ff48bf5SDavid du Colombier 	default:
4263ff48bf5SDavid du Colombier 		panic("etheraddmulti: version %d", version);
4273ff48bf5SDavid du Colombier 	}
4287dd7cddfSDavid du Colombier }
4297dd7cddfSDavid du Colombier 
4307dd7cddfSDavid du Colombier static void
4317dd7cddfSDavid du Colombier etherremmulti(Ipifc *ifc, uchar *a, uchar *)
4327dd7cddfSDavid du Colombier {
4337dd7cddfSDavid du Colombier 	uchar mac[6];
4347dd7cddfSDavid du Colombier 	char buf[64];
4357dd7cddfSDavid du Colombier 	Etherrock *er = ifc->arg;
4363ff48bf5SDavid du Colombier 	int version;
4377dd7cddfSDavid du Colombier 
4383ff48bf5SDavid du Colombier 	version = multicastea(mac, a);
4397dd7cddfSDavid du Colombier 	sprint(buf, "remmulti %E", mac);
4403ff48bf5SDavid du Colombier 	switch(version){
4413ff48bf5SDavid du Colombier 	case V4:
4423ff48bf5SDavid du Colombier 		devtab[er->cchan4->type]->write(er->cchan4, buf, strlen(buf), 0);
4433ff48bf5SDavid du Colombier 		break;
4443ff48bf5SDavid du Colombier 	case V6:
4453ff48bf5SDavid du Colombier 		devtab[er->cchan6->type]->write(er->cchan6, buf, strlen(buf), 0);
4463ff48bf5SDavid du Colombier 		break;
4473ff48bf5SDavid du Colombier 	default:
4483ff48bf5SDavid du Colombier 		panic("etherremmulti: version %d", version);
4493ff48bf5SDavid du Colombier 	}
4507dd7cddfSDavid du Colombier }
4517dd7cddfSDavid du Colombier 
4527dd7cddfSDavid du Colombier /*
4537dd7cddfSDavid du Colombier  *  send an ethernet arp
4547dd7cddfSDavid du Colombier  *  (only v4, v6 uses the neighbor discovery, rfc1970)
4557dd7cddfSDavid du Colombier  */
4567dd7cddfSDavid du Colombier static void
4577dd7cddfSDavid du Colombier sendarp(Ipifc *ifc, Arpent *a)
4587dd7cddfSDavid du Colombier {
4597dd7cddfSDavid du Colombier 	int n;
4607dd7cddfSDavid du Colombier 	Block *bp;
4617dd7cddfSDavid du Colombier 	Etherarp *e;
4627dd7cddfSDavid du Colombier 	Etherrock *er = ifc->arg;
4637dd7cddfSDavid du Colombier 
4647dd7cddfSDavid du Colombier 	/* don't do anything if it's been less than a second since the last */
465a6a9e072SDavid du Colombier 	if(NOW - a->ctime < 1000){
4667dd7cddfSDavid du Colombier 		arprelease(er->f->arp, a);
4677dd7cddfSDavid du Colombier 		return;
4687dd7cddfSDavid du Colombier 	}
4697dd7cddfSDavid du Colombier 
4707dd7cddfSDavid du Colombier 	/* remove all but the last message */
4717dd7cddfSDavid du Colombier 	while((bp = a->hold) != nil){
4727dd7cddfSDavid du Colombier 		if(bp == a->last)
4737dd7cddfSDavid du Colombier 			break;
4747dd7cddfSDavid du Colombier 		a->hold = bp->list;
4757dd7cddfSDavid du Colombier 		freeblist(bp);
4767dd7cddfSDavid du Colombier 	}
4777dd7cddfSDavid du Colombier 
4787dd7cddfSDavid du Colombier 	/* try to keep it around for a second more */
479a6a9e072SDavid du Colombier 	a->ctime = NOW;
4807dd7cddfSDavid du Colombier 	arprelease(er->f->arp, a);
4817dd7cddfSDavid du Colombier 
4827dd7cddfSDavid du Colombier 	n = sizeof(Etherarp);
4833f695129SDavid du Colombier 	if(n < a->type->mintu)
4843f695129SDavid du Colombier 		n = a->type->mintu;
4857dd7cddfSDavid du Colombier 	bp = allocb(n);
4867dd7cddfSDavid du Colombier 	memset(bp->rp, 0, n);
4877dd7cddfSDavid du Colombier 	e = (Etherarp*)bp->rp;
4887dd7cddfSDavid du Colombier 	memmove(e->tpa, a->ip+IPv4off, sizeof(e->tpa));
4897dd7cddfSDavid du Colombier 	ipv4local(ifc, e->spa);
4907dd7cddfSDavid du Colombier 	memmove(e->sha, ifc->mac, sizeof(e->sha));
4917dd7cddfSDavid du Colombier 	memset(e->d, 0xff, sizeof(e->d));		/* ethernet broadcast */
4927dd7cddfSDavid du Colombier 	memmove(e->s, ifc->mac, sizeof(e->s));
4937dd7cddfSDavid du Colombier 
4947dd7cddfSDavid du Colombier 	hnputs(e->type, ETARP);
4957dd7cddfSDavid du Colombier 	hnputs(e->hrd, 1);
4963ff48bf5SDavid du Colombier 	hnputs(e->pro, ETIP4);
4977dd7cddfSDavid du Colombier 	e->hln = sizeof(e->sha);
4987dd7cddfSDavid du Colombier 	e->pln = sizeof(e->spa);
4997dd7cddfSDavid du Colombier 	hnputs(e->op, ARPREQUEST);
5007dd7cddfSDavid du Colombier 	bp->wp += n;
5017dd7cddfSDavid du Colombier 
502*db7ae703SDavid du Colombier 	devtab[er->achan->type]->bwrite(er->achan, bp, 0);
5037dd7cddfSDavid du Colombier }
5047dd7cddfSDavid du Colombier 
5053ff48bf5SDavid du Colombier static void
5063ff48bf5SDavid du Colombier resolveaddr6(Ipifc *ifc, Arpent *a)
5073ff48bf5SDavid du Colombier {
5083ff48bf5SDavid du Colombier 	int sflag;
5093ff48bf5SDavid du Colombier 	Block *bp;
5103ff48bf5SDavid du Colombier 	Etherrock *er = ifc->arg;
5113ff48bf5SDavid du Colombier 	uchar ipsrc[IPaddrlen];
5123ff48bf5SDavid du Colombier 
5133ff48bf5SDavid du Colombier 	/* don't do anything if it's been less than a second since the last */
514a6a9e072SDavid du Colombier 	if(NOW - a->ctime < ReTransTimer){
5153ff48bf5SDavid du Colombier 		arprelease(er->f->arp, a);
5163ff48bf5SDavid du Colombier 		return;
5173ff48bf5SDavid du Colombier 	}
5183ff48bf5SDavid du Colombier 
5193ff48bf5SDavid du Colombier 	/* remove all but the last message */
5203ff48bf5SDavid du Colombier 	while((bp = a->hold) != nil){
5213ff48bf5SDavid du Colombier 		if(bp == a->last)
5223ff48bf5SDavid du Colombier 			break;
5233ff48bf5SDavid du Colombier 		a->hold = bp->list;
5243ff48bf5SDavid du Colombier 		freeblist(bp);
5253ff48bf5SDavid du Colombier 	}
5263ff48bf5SDavid du Colombier 
5273ff48bf5SDavid du Colombier 	/* try to keep it around for a second more */
528a6a9e072SDavid du Colombier 	a->ctime = NOW;
529a6a9e072SDavid du Colombier 	a->rtime = NOW + ReTransTimer;
5303ff48bf5SDavid du Colombier 	if(a->rxtsrem <= 0) {
5313ff48bf5SDavid du Colombier 		arprelease(er->f->arp, a);
5323ff48bf5SDavid du Colombier 		return;
5333ff48bf5SDavid du Colombier 	}
5343ff48bf5SDavid du Colombier 
5353ff48bf5SDavid du Colombier 	a->rxtsrem--;
5363ff48bf5SDavid du Colombier 	arprelease(er->f->arp, a);
5373ff48bf5SDavid du Colombier 
5383ff48bf5SDavid du Colombier 	if(sflag = ipv6anylocal(ifc, ipsrc))
5393ff48bf5SDavid du Colombier 		icmpns(er->f, ipsrc, sflag, a->ip, TARG_MULTI, ifc->mac);
5403ff48bf5SDavid du Colombier }
5413ff48bf5SDavid du Colombier 
5427dd7cddfSDavid du Colombier /*
5437dd7cddfSDavid du Colombier  *  send a gratuitous arp to refresh arp caches
5447dd7cddfSDavid du Colombier  */
5457dd7cddfSDavid du Colombier static void
5467dd7cddfSDavid du Colombier sendgarp(Ipifc *ifc, uchar *ip)
5477dd7cddfSDavid du Colombier {
5487dd7cddfSDavid du Colombier 	int n;
5497dd7cddfSDavid du Colombier 	Block *bp;
5507dd7cddfSDavid du Colombier 	Etherarp *e;
5517dd7cddfSDavid du Colombier 	Etherrock *er = ifc->arg;
5527dd7cddfSDavid du Colombier 
5537dd7cddfSDavid du Colombier 	/* don't arp for our initial non address */
5547dd7cddfSDavid du Colombier 	if(ipcmp(ip, IPnoaddr) == 0)
5557dd7cddfSDavid du Colombier 		return;
5567dd7cddfSDavid du Colombier 
5577dd7cddfSDavid du Colombier 	n = sizeof(Etherarp);
5583f695129SDavid du Colombier 	if(n < ifc->m->mintu)
5593f695129SDavid du Colombier 		n = ifc->m->mintu;
5607dd7cddfSDavid du Colombier 	bp = allocb(n);
5617dd7cddfSDavid du Colombier 	memset(bp->rp, 0, n);
5627dd7cddfSDavid du Colombier 	e = (Etherarp*)bp->rp;
5637dd7cddfSDavid du Colombier 	memmove(e->tpa, ip+IPv4off, sizeof(e->tpa));
5647dd7cddfSDavid du Colombier 	memmove(e->spa, ip+IPv4off, sizeof(e->spa));
5657dd7cddfSDavid du Colombier 	memmove(e->sha, ifc->mac, sizeof(e->sha));
5667dd7cddfSDavid du Colombier 	memset(e->d, 0xff, sizeof(e->d));		/* ethernet broadcast */
5677dd7cddfSDavid du Colombier 	memmove(e->s, ifc->mac, sizeof(e->s));
5687dd7cddfSDavid du Colombier 
5697dd7cddfSDavid du Colombier 	hnputs(e->type, ETARP);
5707dd7cddfSDavid du Colombier 	hnputs(e->hrd, 1);
5713ff48bf5SDavid du Colombier 	hnputs(e->pro, ETIP4);
5727dd7cddfSDavid du Colombier 	e->hln = sizeof(e->sha);
5737dd7cddfSDavid du Colombier 	e->pln = sizeof(e->spa);
5747dd7cddfSDavid du Colombier 	hnputs(e->op, ARPREQUEST);
5757dd7cddfSDavid du Colombier 	bp->wp += n;
5767dd7cddfSDavid du Colombier 
577*db7ae703SDavid du Colombier 	devtab[er->achan->type]->bwrite(er->achan, bp, 0);
5787dd7cddfSDavid du Colombier }
5797dd7cddfSDavid du Colombier 
5807dd7cddfSDavid du Colombier static void
5817dd7cddfSDavid du Colombier recvarp(Ipifc *ifc)
5827dd7cddfSDavid du Colombier {
5837dd7cddfSDavid du Colombier 	int n;
5847dd7cddfSDavid du Colombier 	Block *ebp, *rbp;
5857dd7cddfSDavid du Colombier 	Etherarp *e, *r;
5867dd7cddfSDavid du Colombier 	uchar ip[IPaddrlen];
587ef9eff0bSDavid du Colombier 	static uchar eprinted[4];
5887dd7cddfSDavid du Colombier 	Etherrock *er = ifc->arg;
5897dd7cddfSDavid du Colombier 
5903f695129SDavid du Colombier 	ebp = devtab[er->achan->type]->bread(er->achan, ifc->maxtu, 0);
591*db7ae703SDavid du Colombier 	if(ebp == nil)
5927dd7cddfSDavid du Colombier 		return;
5937dd7cddfSDavid du Colombier 
5947dd7cddfSDavid du Colombier 	e = (Etherarp*)ebp->rp;
5957dd7cddfSDavid du Colombier 	switch(nhgets(e->op)) {
5967dd7cddfSDavid du Colombier 	default:
5977dd7cddfSDavid du Colombier 		break;
5987dd7cddfSDavid du Colombier 
5997dd7cddfSDavid du Colombier 	case ARPREPLY:
6003ff48bf5SDavid du Colombier 		/* check for machine using my ip address */
6013ff48bf5SDavid du Colombier 		v4tov6(ip, e->spa);
6029a747e4fSDavid du Colombier 		if(iplocalonifc(ifc, ip) || ipproxyifc(er->f, ifc, ip)){
6039a747e4fSDavid du Colombier 			if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0){
6049a747e4fSDavid du Colombier 				print("arprep: 0x%E/0x%E also has ip addr %V\n",
6059a747e4fSDavid du Colombier 					e->s, e->sha, e->spa);
6069a747e4fSDavid du Colombier 				break;
6079a747e4fSDavid du Colombier 			}
6089a747e4fSDavid du Colombier 		}
6093ff48bf5SDavid du Colombier 
6105d82c6aeSDavid du Colombier 		/* make sure we're not entering broadcast addresses */
6115d82c6aeSDavid du Colombier 		if(ipcmp(ip, ipbroadcast) == 0 ||
6125d82c6aeSDavid du Colombier 			!memcmp(e->sha, etherbroadcast, sizeof(e->sha))){
6135d82c6aeSDavid du Colombier 			print("arprep: 0x%E/0x%E cannot register broadcast address %I\n",
6145d82c6aeSDavid du Colombier 				e->s, e->sha, e->spa);
6155d82c6aeSDavid du Colombier 			break;
6165d82c6aeSDavid du Colombier 		}
6175d82c6aeSDavid du Colombier 
6187dd7cddfSDavid du Colombier 		arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), 0);
6197dd7cddfSDavid du Colombier 		break;
6207dd7cddfSDavid du Colombier 
6217dd7cddfSDavid du Colombier 	case ARPREQUEST:
6227dd7cddfSDavid du Colombier 		/* don't answer arps till we know who we are */
6237dd7cddfSDavid du Colombier 		if(ifc->lifc == 0)
6247dd7cddfSDavid du Colombier 			break;
6257dd7cddfSDavid du Colombier 
6263ff48bf5SDavid du Colombier 		/* check for machine using my ip or ether address */
6277dd7cddfSDavid du Colombier 		v4tov6(ip, e->spa);
6287dd7cddfSDavid du Colombier 		if(iplocalonifc(ifc, ip) || ipproxyifc(er->f, ifc, ip)){
629ef9eff0bSDavid du Colombier 			if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0){
630ef9eff0bSDavid du Colombier 				if (memcmp(eprinted, e->spa, sizeof(e->spa))){
631ef9eff0bSDavid du Colombier 					/* print only once */
6323ff48bf5SDavid du Colombier 					print("arpreq: 0x%E also has ip addr %V\n", e->sha, e->spa);
633ef9eff0bSDavid du Colombier 					memmove(eprinted, e->spa, sizeof(e->spa));
634ef9eff0bSDavid du Colombier 				}
635ef9eff0bSDavid du Colombier 			}
6367dd7cddfSDavid du Colombier 		} else {
6377dd7cddfSDavid du Colombier 			if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) == 0){
6383ff48bf5SDavid du Colombier 				print("arpreq: %V also has ether addr %E\n", e->spa, e->sha);
6397dd7cddfSDavid du Colombier 				break;
6407dd7cddfSDavid du Colombier 			}
6417dd7cddfSDavid du Colombier 		}
6427dd7cddfSDavid du Colombier 
6437dd7cddfSDavid du Colombier 		/* refresh what we know about sender */
6447dd7cddfSDavid du Colombier 		arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), 1);
6457dd7cddfSDavid du Colombier 
6467dd7cddfSDavid du Colombier 		/* answer only requests for our address or systems we're proxying for */
6477dd7cddfSDavid du Colombier 		v4tov6(ip, e->tpa);
6487dd7cddfSDavid du Colombier 		if(!iplocalonifc(ifc, ip))
6497dd7cddfSDavid du Colombier 		if(!ipproxyifc(er->f, ifc, ip))
6507dd7cddfSDavid du Colombier 			break;
6517dd7cddfSDavid du Colombier 
6527dd7cddfSDavid du Colombier 		n = sizeof(Etherarp);
6533f695129SDavid du Colombier 		if(n < ifc->mintu)
6543f695129SDavid du Colombier 			n = ifc->mintu;
6557dd7cddfSDavid du Colombier 		rbp = allocb(n);
6567dd7cddfSDavid du Colombier 		r = (Etherarp*)rbp->rp;
6577dd7cddfSDavid du Colombier 		memset(r, 0, sizeof(Etherarp));
6587dd7cddfSDavid du Colombier 		hnputs(r->type, ETARP);
6597dd7cddfSDavid du Colombier 		hnputs(r->hrd, 1);
6603ff48bf5SDavid du Colombier 		hnputs(r->pro, ETIP4);
6617dd7cddfSDavid du Colombier 		r->hln = sizeof(r->sha);
6627dd7cddfSDavid du Colombier 		r->pln = sizeof(r->spa);
6637dd7cddfSDavid du Colombier 		hnputs(r->op, ARPREPLY);
6647dd7cddfSDavid du Colombier 		memmove(r->tha, e->sha, sizeof(r->tha));
6657dd7cddfSDavid du Colombier 		memmove(r->tpa, e->spa, sizeof(r->tpa));
6667dd7cddfSDavid du Colombier 		memmove(r->sha, ifc->mac, sizeof(r->sha));
6677dd7cddfSDavid du Colombier 		memmove(r->spa, e->tpa, sizeof(r->spa));
6687dd7cddfSDavid du Colombier 		memmove(r->d, e->sha, sizeof(r->d));
6697dd7cddfSDavid du Colombier 		memmove(r->s, ifc->mac, sizeof(r->s));
6707dd7cddfSDavid du Colombier 		rbp->wp += n;
6717dd7cddfSDavid du Colombier 
672*db7ae703SDavid du Colombier 		devtab[er->achan->type]->bwrite(er->achan, rbp, 0);
6737dd7cddfSDavid du Colombier 	}
6747dd7cddfSDavid du Colombier 	freeb(ebp);
6757dd7cddfSDavid du Colombier }
6767dd7cddfSDavid du Colombier 
6777dd7cddfSDavid du Colombier static void
6787dd7cddfSDavid du Colombier recvarpproc(void *v)
6797dd7cddfSDavid du Colombier {
6807dd7cddfSDavid du Colombier 	Ipifc *ifc = v;
6817dd7cddfSDavid du Colombier 	Etherrock *er = ifc->arg;
6827dd7cddfSDavid du Colombier 
6837dd7cddfSDavid du Colombier 	er->arpp = up;
6847dd7cddfSDavid du Colombier 	if(waserror()){
6857dd7cddfSDavid du Colombier 		er->arpp = 0;
6867dd7cddfSDavid du Colombier 		pexit("hangup", 1);
6877dd7cddfSDavid du Colombier 	}
6887dd7cddfSDavid du Colombier 	for(;;)
6897dd7cddfSDavid du Colombier 		recvarp(ifc);
6907dd7cddfSDavid du Colombier }
6917dd7cddfSDavid du Colombier 
6927dd7cddfSDavid du Colombier static int
6937dd7cddfSDavid du Colombier multicastea(uchar *ea, uchar *ip)
6947dd7cddfSDavid du Colombier {
6957dd7cddfSDavid du Colombier 	int x;
6967dd7cddfSDavid du Colombier 
6977dd7cddfSDavid du Colombier 	switch(x = ipismulticast(ip)){
6987dd7cddfSDavid du Colombier 	case V4:
6997dd7cddfSDavid du Colombier 		ea[0] = 0x01;
7007dd7cddfSDavid du Colombier 		ea[1] = 0x00;
7017dd7cddfSDavid du Colombier 		ea[2] = 0x5e;
7027dd7cddfSDavid du Colombier 		ea[3] = ip[13] & 0x7f;
7037dd7cddfSDavid du Colombier 		ea[4] = ip[14];
7047dd7cddfSDavid du Colombier 		ea[5] = ip[15];
7057dd7cddfSDavid du Colombier 		break;
7067dd7cddfSDavid du Colombier  	case V6:
7077dd7cddfSDavid du Colombier  		ea[0] = 0x33;
7087dd7cddfSDavid du Colombier  		ea[1] = 0x33;
7097dd7cddfSDavid du Colombier  		ea[2] = ip[12];
7107dd7cddfSDavid du Colombier 		ea[3] = ip[13];
7117dd7cddfSDavid du Colombier  		ea[4] = ip[14];
7127dd7cddfSDavid du Colombier  		ea[5] = ip[15];
7137dd7cddfSDavid du Colombier  		break;
7147dd7cddfSDavid du Colombier 	}
7157dd7cddfSDavid du Colombier 	return x;
7167dd7cddfSDavid du Colombier }
7177dd7cddfSDavid du Colombier 
7187dd7cddfSDavid du Colombier /*
7197dd7cddfSDavid du Colombier  *  fill in an arp entry for broadcast or multicast
7203ff48bf5SDavid du Colombier  *  addresses.  Return the first queued packet for the
7213ff48bf5SDavid du Colombier  *  IP address.
7227dd7cddfSDavid du Colombier  */
7237dd7cddfSDavid du Colombier static Block*
72459cc4ca5SDavid du Colombier multicastarp(Fs *f, Arpent *a, Medium *medium, uchar *mac)
7257dd7cddfSDavid du Colombier {
7267dd7cddfSDavid du Colombier 	/* is it broadcast? */
7277dd7cddfSDavid du Colombier 	switch(ipforme(f, a->ip)){
7287dd7cddfSDavid du Colombier 	case Runi:
7297dd7cddfSDavid du Colombier 		return nil;
7307dd7cddfSDavid du Colombier 	case Rbcast:
7317dd7cddfSDavid du Colombier 		memset(mac, 0xff, 6);
73259cc4ca5SDavid du Colombier 		return arpresolve(f->arp, a, medium, mac);
7337dd7cddfSDavid du Colombier 	default:
7347dd7cddfSDavid du Colombier 		break;
7357dd7cddfSDavid du Colombier 	}
7367dd7cddfSDavid du Colombier 
7377dd7cddfSDavid du Colombier 	/* if multicast, fill in mac */
7387dd7cddfSDavid du Colombier 	switch(multicastea(mac, a->ip)){
7397dd7cddfSDavid du Colombier 	case V4:
7407dd7cddfSDavid du Colombier 	case V6:
74159cc4ca5SDavid du Colombier 		return arpresolve(f->arp, a, medium, mac);
7427dd7cddfSDavid du Colombier 	}
7437dd7cddfSDavid du Colombier 
7447dd7cddfSDavid du Colombier 	/* let arp take care of it */
7457dd7cddfSDavid du Colombier 	return nil;
7467dd7cddfSDavid du Colombier }
7477dd7cddfSDavid du Colombier 
7487dd7cddfSDavid du Colombier void
7497dd7cddfSDavid du Colombier ethermediumlink(void)
7507dd7cddfSDavid du Colombier {
7517dd7cddfSDavid du Colombier 	addipmedium(&ethermedium);
75259cc4ca5SDavid du Colombier 	addipmedium(&gbemedium);
7537dd7cddfSDavid du Colombier }
7543ff48bf5SDavid du Colombier 
7553ff48bf5SDavid du Colombier 
7563ff48bf5SDavid du Colombier static void
7573ff48bf5SDavid du Colombier etherpref2addr(uchar *pref, uchar *ea)
7583ff48bf5SDavid du Colombier {
7593ff48bf5SDavid du Colombier 	pref[8] = ea[0] | 0x2;
7603ff48bf5SDavid du Colombier 	pref[9] = ea[1];
7613ff48bf5SDavid du Colombier 	pref[10] = ea[2];
7623ff48bf5SDavid du Colombier 	pref[11] = 0xFF;
7633ff48bf5SDavid du Colombier 	pref[12] = 0xFE;
7643ff48bf5SDavid du Colombier 	pref[13] = ea[3];
7653ff48bf5SDavid du Colombier 	pref[14] = ea[4];
7663ff48bf5SDavid du Colombier 	pref[15] = ea[5];
7673ff48bf5SDavid du Colombier }
768