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