xref: /plan9/sys/src/9/ip/ipifc.c (revision c1dd2601e42f5138f07719cdf2819a51c0f6f850)
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "../port/error.h"
7 
8 #include "ip.h"
9 #include "ipv6.h"
10 
11 #define DPRINT if(0)print
12 
13 enum {
14 	Maxmedia	= 32,
15 	Nself		= Maxmedia*5,
16 	NHASH		= 1<<6,
17 	NCACHE		= 256,
18 	QMAX		= 192*1024-1,
19 	Maxv6repr	= (128/(4*4))*(4+1), /* limit of xxxx:xxxx:⋯ notation */
20 };
21 
22 Medium *media[Maxmedia] = { 0 };
23 
24 /*
25  *  cache of local addresses (addresses we answer to)
26  */
27 struct Ipself
28 {
29 	uchar	a[IPaddrlen];
30 	Ipself	*hnext;		/* next address in the hash table */
31 	Iplink	*link;		/* binding twixt Ipself and Ipifc */
32 	ulong	expire;
33 	uchar	type;		/* type of address */
34 	int	ref;
35 	Ipself	*next;		/* free list */
36 };
37 
38 struct Ipselftab
39 {
40 	QLock;
41 	int	inited;
42 	int	acceptall;	/* true if an interface has the null address */
43 	Ipself	*hash[NHASH];	/* hash chains */
44 };
45 
46 /*
47  *  Multicast addresses are chained onto a Chan so that
48  *  we can remove them when the Chan is closed.
49  */
50 typedef struct Ipmcast Ipmcast;
51 struct Ipmcast
52 {
53 	Ipmcast	*next;
54 	uchar	ma[IPaddrlen];	/* multicast address */
55 	uchar	ia[IPaddrlen];	/* interface address */
56 };
57 
58 /* quick hash for ip addresses */
59 #define hashipa(a) ( ( ((a)[IPaddrlen-2]<<8) | (a)[IPaddrlen-1] )%NHASH )
60 
61 static char tifc[] = "ifc ";
62 
63 static void	addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type);
64 static void	remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a);
65 static char*	ipifcjoinmulti(Ipifc *ifc, char **argv, int argc);
66 static char*	ipifcleavemulti(Ipifc *ifc, char **argv, int argc);
67 static void	ipifcregisterproxy(Fs*, Ipifc*, uchar*);
68 static char*	ipifcremlifc(Ipifc*, Iplifc*);
69 
70 /*
71  *  link in a new medium
72  */
73 void
addipmedium(Medium * med)74 addipmedium(Medium *med)
75 {
76 	int i;
77 
78 	for(i = 0; i < nelem(media)-1; i++)
79 		if(media[i] == nil){
80 			media[i] = med;
81 			break;
82 		}
83 }
84 
85 /*
86  *  find the medium with this name
87  */
88 Medium*
ipfindmedium(char * name)89 ipfindmedium(char *name)
90 {
91 	Medium **mp;
92 
93 	for(mp = media; *mp != nil; mp++)
94 		if(strcmp((*mp)->name, name) == 0)
95 			break;
96 	return *mp;
97 }
98 
99 /*
100  *  attach a device (or pkt driver) to the interface.
101  *  called with c locked
102  */
103 static char*
ipifcbind(Conv * c,char ** argv,int argc)104 ipifcbind(Conv *c, char **argv, int argc)
105 {
106 	Ipifc *ifc;
107 	Medium *m;
108 
109 	if(argc < 2)
110 		return Ebadarg;
111 
112 	ifc = (Ipifc*)c->ptcl;
113 
114 	/* bind the device to the interface */
115 	m = ipfindmedium(argv[1]);
116 	if(m == nil)
117 		return "unknown interface type";
118 
119 	wlock(ifc);
120 	if(ifc->m != nil){
121 		wunlock(ifc);
122 		return "interface already bound";
123 	}
124 	if(waserror()){
125 		wunlock(ifc);
126 		nexterror();
127 	}
128 
129 	/* do medium specific binding */
130 	(*m->bind)(ifc, argc, argv);
131 
132 	/* set the bound device name */
133 	if(argc > 2)
134 		strncpy(ifc->dev, argv[2], sizeof(ifc->dev));
135 	else
136 		snprint(ifc->dev, sizeof ifc->dev, "%s%d", m->name, c->x);
137 	ifc->dev[sizeof(ifc->dev)-1] = 0;
138 
139 	/* set up parameters */
140 	ifc->m = m;
141 	ifc->mintu = ifc->m->mintu;
142 	ifc->maxtu = ifc->m->maxtu;
143 	if(ifc->m->unbindonclose == 0)
144 		ifc->conv->inuse++;
145 	ifc->rp.mflag = 0;		/* default not managed */
146 	ifc->rp.oflag = 0;
147 	ifc->rp.maxraint = 600000;	/* millisecs */
148 	ifc->rp.minraint = 200000;
149 	ifc->rp.linkmtu = 0;		/* no mtu sent */
150 	ifc->rp.reachtime = 0;
151 	ifc->rp.rxmitra = 0;
152 	ifc->rp.ttl = MAXTTL;
153 	ifc->rp.routerlt = 3 * ifc->rp.maxraint;
154 
155 	/* any ancillary structures (like routes) no longer pertain */
156 	ifc->ifcid++;
157 
158 	/* reopen all the queues closed by a previous unbind */
159 	qreopen(c->rq);
160 	qreopen(c->eq);
161 	qreopen(c->sq);
162 
163 	wunlock(ifc);
164 	poperror();
165 
166 	return nil;
167 }
168 
169 /*
170  *  detach a device from an interface, close the interface
171  *  called with ifc->conv closed
172  */
173 static char*
ipifcunbind(Ipifc * ifc)174 ipifcunbind(Ipifc *ifc)
175 {
176 	char *err;
177 
178 	if(waserror()){
179 		wunlock(ifc);
180 		nexterror();
181 	}
182 	wlock(ifc);
183 
184 	/* dissociate routes */
185 	if(ifc->m != nil && ifc->m->unbindonclose == 0)
186 		ifc->conv->inuse--;
187 	ifc->ifcid++;
188 
189 	/* disassociate logical interfaces (before zeroing ifc->arg) */
190 	while(ifc->lifc){
191 		err = ipifcremlifc(ifc, ifc->lifc);
192 		/*
193 		 * note: err non-zero means lifc not found,
194 		 * which can't happen in this case.
195 		 */
196 		if(err)
197 			error(err);
198 	}
199 
200 	/* disassociate device */
201 	if(ifc->m && ifc->m->unbind)
202 		(*ifc->m->unbind)(ifc);
203 	memset(ifc->dev, 0, sizeof(ifc->dev));
204 	ifc->arg = nil;
205 	ifc->reassemble = 0;
206 
207 	/* close queues to stop queuing of packets */
208 	qclose(ifc->conv->rq);
209 	qclose(ifc->conv->wq);
210 	qclose(ifc->conv->sq);
211 
212 	ifc->m = nil;
213 	wunlock(ifc);
214 	poperror();
215 	return nil;
216 }
217 
218 char sfixedformat[] = "device %s maxtu %d sendra %d recvra %d mflag %d oflag"
219 " %d maxraint %d minraint %d linkmtu %d reachtime %d rxmitra %d ttl %d routerlt"
220 " %d pktin %lud pktout %lud errin %lud errout %lud\n";
221 
222 char slineformat[] = "	%-40I %-10M %-40I %-12lud %-12lud\n";
223 
224 static int
ipifcstate(Conv * c,char * state,int n)225 ipifcstate(Conv *c, char *state, int n)
226 {
227 	Ipifc *ifc;
228 	Iplifc *lifc;
229 	int m;
230 
231 	ifc = (Ipifc*)c->ptcl;
232 	m = snprint(state, n, sfixedformat,
233 		ifc->dev, ifc->maxtu, ifc->sendra6, ifc->recvra6,
234 		ifc->rp.mflag, ifc->rp.oflag, ifc->rp.maxraint,
235 		ifc->rp.minraint, ifc->rp.linkmtu, ifc->rp.reachtime,
236 		ifc->rp.rxmitra, ifc->rp.ttl, ifc->rp.routerlt,
237 		ifc->in, ifc->out, ifc->inerr, ifc->outerr);
238 
239 	rlock(ifc);
240 	for(lifc = ifc->lifc; lifc && n > m; lifc = lifc->next)
241 		m += snprint(state+m, n - m, slineformat, lifc->local,
242 			lifc->mask, lifc->remote, lifc->validlt, lifc->preflt);
243 	if(ifc->lifc == nil)
244 		m += snprint(state+m, n - m, "\n");
245 	runlock(ifc);
246 	return m;
247 }
248 
249 static int
ipifclocal(Conv * c,char * state,int n)250 ipifclocal(Conv *c, char *state, int n)
251 {
252 	Ipifc *ifc;
253 	Iplifc *lifc;
254 	Iplink *link;
255 	int m;
256 
257 	ifc = (Ipifc*)c->ptcl;
258 	m = 0;
259 
260 	rlock(ifc);
261 	for(lifc = ifc->lifc; lifc; lifc = lifc->next){
262 		m += snprint(state+m, n - m, "%-40.40I ->", lifc->local);
263 		for(link = lifc->link; link; link = link->lifclink)
264 			m += snprint(state+m, n - m, " %-40.40I", link->self->a);
265 		m += snprint(state+m, n - m, "\n");
266 	}
267 	runlock(ifc);
268 	return m;
269 }
270 
271 static int
ipifcinuse(Conv * c)272 ipifcinuse(Conv *c)
273 {
274 	Ipifc *ifc;
275 
276 	ifc = (Ipifc*)c->ptcl;
277 	return ifc->m != nil;
278 }
279 
280 /*
281  *  called when a process writes to an interface's 'data'
282  */
283 static void
ipifckick(void * x)284 ipifckick(void *x)
285 {
286 	Conv *c = x;
287 	Block *bp;
288 	Ipifc *ifc;
289 
290 	bp = qget(c->wq);
291 	if(bp == nil)
292 		return;
293 
294 	ifc = (Ipifc*)c->ptcl;
295 	if(!canrlock(ifc)){
296 		freeb(bp);
297 		return;
298 	}
299 	if(waserror()){
300 		runlock(ifc);
301 		nexterror();
302 	}
303 	if(ifc->m == nil || ifc->m->pktin == nil)
304 		freeb(bp);
305 	else
306 		(*ifc->m->pktin)(c->p->f, ifc, bp);
307 	runlock(ifc);
308 	poperror();
309 }
310 
311 /*
312  *  called when a new ipifc structure is created
313  */
314 static void
ipifccreate(Conv * c)315 ipifccreate(Conv *c)
316 {
317 	Ipifc *ifc;
318 
319 	c->rq = qopen(QMAX, 0, 0, 0);
320 	c->sq = qopen(QMAX, 0, 0, 0);
321 	c->wq = qopen(QMAX, Qkick, ipifckick, c);
322 	ifc = (Ipifc*)c->ptcl;
323 	ifc->conv = c;
324 	ifc->unbinding = 0;
325 	ifc->m = nil;
326 	ifc->reassemble = 0;
327 }
328 
329 /*
330  *  called after last close of ipifc data or ctl
331  *  called with c locked, we must unlock
332  */
333 static void
ipifcclose(Conv * c)334 ipifcclose(Conv *c)
335 {
336 	Ipifc *ifc;
337 	Medium *m;
338 
339 	ifc = (Ipifc*)c->ptcl;
340 	m = ifc->m;
341 	if(m && m->unbindonclose)
342 		ipifcunbind(ifc);
343 }
344 
345 /*
346  *  change an interface's mtu
347  */
348 char*
ipifcsetmtu(Ipifc * ifc,char ** argv,int argc)349 ipifcsetmtu(Ipifc *ifc, char **argv, int argc)
350 {
351 	int mtu;
352 
353 	if(argc < 2 || ifc->m == nil)
354 		return Ebadarg;
355 	mtu = strtoul(argv[1], 0, 0);
356 	if(mtu < ifc->m->mintu || mtu > ifc->m->maxtu)
357 		return Ebadarg;
358 	ifc->maxtu = mtu;
359 	return nil;
360 }
361 
362 /*
363  *  add an address to an interface.
364  */
365 char*
ipifcadd(Ipifc * ifc,char ** argv,int argc,int tentative,Iplifc * lifcp)366 ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp)
367 {
368 	int i, type, mtu, sendnbrdisc = 0;
369 	uchar ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen];
370 	uchar bcast[IPaddrlen], net[IPaddrlen];
371 	Iplifc *lifc, **l;
372 	Fs *f;
373 
374 	if(ifc->m == nil)
375 		return "ipifc not yet bound to device";
376 
377 	f = ifc->conv->p->f;
378 
379 	type = Rifc;
380 	memset(ip, 0, IPaddrlen);
381 	memset(mask, 0, IPaddrlen);
382 	memset(rem, 0, IPaddrlen);
383 	switch(argc){
384 	case 6:
385 		if(strcmp(argv[5], "proxy") == 0)
386 			type |= Rproxy;
387 		/* fall through */
388 	case 5:
389 		mtu = strtoul(argv[4], 0, 0);
390 		if(mtu >= ifc->m->mintu && mtu <= ifc->m->maxtu)
391 			ifc->maxtu = mtu;
392 		/* fall through */
393 	case 4:
394 		if (parseip(ip, argv[1]) == -1 || parseip(rem, argv[3]) == -1)
395 			return Ebadip;
396 		parseipmask(mask, argv[2]);
397 		maskip(rem, mask, net);
398 		break;
399 	case 3:
400 		if (parseip(ip, argv[1]) == -1)
401 			return Ebadip;
402 		parseipmask(mask, argv[2]);
403 		maskip(ip, mask, rem);
404 		maskip(rem, mask, net);
405 		break;
406 	case 2:
407 		if (parseip(ip, argv[1]) == -1)
408 			return Ebadip;
409 		memmove(mask, defmask(ip), IPaddrlen);
410 		maskip(ip, mask, rem);
411 		maskip(rem, mask, net);
412 		break;
413 	default:
414 		return Ebadarg;
415 	}
416 	if(isv4(ip))
417 		tentative = 0;
418 	wlock(ifc);
419 
420 	/* ignore if this is already a local address for this ifc */
421 	for(lifc = ifc->lifc; lifc; lifc = lifc->next) {
422 		if(ipcmp(lifc->local, ip) == 0) {
423 			if(lifc->tentative != tentative)
424 				lifc->tentative = tentative;
425 			if(lifcp) {
426 				lifc->onlink = lifcp->onlink;
427 				lifc->autoflag = lifcp->autoflag;
428 				lifc->validlt = lifcp->validlt;
429 				lifc->preflt = lifcp->preflt;
430 				lifc->origint = lifcp->origint;
431 			}
432 			goto out;
433 		}
434 	}
435 
436 	/* add the address to the list of logical ifc's for this ifc */
437 	lifc = smalloc(sizeof(Iplifc));
438 	ipmove(lifc->local, ip);
439 	ipmove(lifc->mask, mask);
440 	ipmove(lifc->remote, rem);
441 	ipmove(lifc->net, net);
442 	lifc->tentative = tentative;
443 	if(lifcp) {
444 		lifc->onlink = lifcp->onlink;
445 		lifc->autoflag = lifcp->autoflag;
446 		lifc->validlt = lifcp->validlt;
447 		lifc->preflt = lifcp->preflt;
448 		lifc->origint = lifcp->origint;
449 	} else {		/* default values */
450 		lifc->onlink = lifc->autoflag = 1;
451 		lifc->validlt = lifc->preflt = ~0L;
452 		lifc->origint = NOW / 1000;
453 	}
454 	lifc->next = nil;
455 
456 	for(l = &ifc->lifc; *l; l = &(*l)->next)
457 		;
458 	*l = lifc;
459 
460 	/* check for point-to-point interface */
461 	if(ipcmp(ip, v6loopback)) /* skip v6 loopback, it's a special address */
462 	if(ipcmp(mask, IPallbits) == 0)
463 		type |= Rptpt;
464 
465 	/* add local routes */
466 	if(isv4(ip))
467 		v4addroute(f, tifc, rem+IPv4off, mask+IPv4off, rem+IPv4off, type);
468 	else
469 		v6addroute(f, tifc, rem, mask, rem, type);
470 
471 	addselfcache(f, ifc, lifc, ip, Runi);
472 
473 	if((type & (Rproxy|Rptpt)) == (Rproxy|Rptpt)){
474 		ipifcregisterproxy(f, ifc, rem);
475 		goto out;
476 	}
477 
478 	if(isv4(ip) || ipcmp(ip, IPnoaddr) == 0) {
479 		/* add subnet directed broadcast address to the self cache */
480 		for(i = 0; i < IPaddrlen; i++)
481 			bcast[i] = (ip[i] & mask[i]) | ~mask[i];
482 		addselfcache(f, ifc, lifc, bcast, Rbcast);
483 
484 		/* add subnet directed network address to the self cache */
485 		for(i = 0; i < IPaddrlen; i++)
486 			bcast[i] = (ip[i] & mask[i]) & mask[i];
487 		addselfcache(f, ifc, lifc, bcast, Rbcast);
488 
489 		/* add network directed broadcast address to the self cache */
490 		memmove(mask, defmask(ip), IPaddrlen);
491 		for(i = 0; i < IPaddrlen; i++)
492 			bcast[i] = (ip[i] & mask[i]) | ~mask[i];
493 		addselfcache(f, ifc, lifc, bcast, Rbcast);
494 
495 		/* add network directed network address to the self cache */
496 		memmove(mask, defmask(ip), IPaddrlen);
497 		for(i = 0; i < IPaddrlen; i++)
498 			bcast[i] = (ip[i] & mask[i]) & mask[i];
499 		addselfcache(f, ifc, lifc, bcast, Rbcast);
500 
501 		addselfcache(f, ifc, lifc, IPv4bcast, Rbcast);
502 	}
503 	else {
504 		if(ipcmp(ip, v6loopback) == 0) {
505 			/* add node-local mcast address */
506 			addselfcache(f, ifc, lifc, v6allnodesN, Rmulti);
507 
508 			/* add route for all node multicast */
509 			v6addroute(f, tifc, v6allnodesN, v6allnodesNmask,
510 				v6allnodesN, Rmulti);
511 		}
512 
513 		/* add all nodes multicast address */
514 		addselfcache(f, ifc, lifc, v6allnodesL, Rmulti);
515 
516 		/* add route for all nodes multicast */
517 		v6addroute(f, tifc, v6allnodesL, v6allnodesLmask, v6allnodesL,
518 			Rmulti);
519 
520 		/* add solicited-node multicast address */
521 		ipv62smcast(bcast, ip);
522 		addselfcache(f, ifc, lifc, bcast, Rmulti);
523 
524 		sendnbrdisc = 1;
525 	}
526 
527 	/* register the address on this network for address resolution */
528 	if(isv4(ip) && ifc->m->areg != nil)
529 		(*ifc->m->areg)(ifc, ip);
530 
531 out:
532 	wunlock(ifc);
533 	if(tentative && sendnbrdisc)
534 		icmpns(f, 0, SRC_UNSPEC, ip, TARG_MULTI, ifc->mac);
535 	return nil;
536 }
537 
538 /*
539  *  remove a logical interface from an ifc
540  *  always called with ifc wlock'd
541  */
542 static char*
ipifcremlifc(Ipifc * ifc,Iplifc * lifc)543 ipifcremlifc(Ipifc *ifc, Iplifc *lifc)
544 {
545 	Iplifc **l;
546 	Fs *f;
547 
548 	f = ifc->conv->p->f;
549 
550 	/*
551 	 *  find address on this interface and remove from chain.
552 	 *  for pt to pt we actually specify the remote address as the
553 	 *  addresss to remove.
554 	 */
555 	for(l = &ifc->lifc; *l != nil && *l != lifc; l = &(*l)->next)
556 		;
557 	if(*l == nil)
558 		return "address not on this interface";
559 	*l = lifc->next;
560 
561 	/* disassociate any addresses */
562 	while(lifc->link)
563 		remselfcache(f, ifc, lifc, lifc->link->self->a);
564 
565 	/* remove the route for this logical interface */
566 	if(isv4(lifc->local))
567 		v4delroute(f, lifc->remote+IPv4off, lifc->mask+IPv4off, 1);
568 	else {
569 		v6delroute(f, lifc->remote, lifc->mask, 1);
570 		if(ipcmp(lifc->local, v6loopback) == 0)
571 			/* remove route for all node multicast */
572 			v6delroute(f, v6allnodesN, v6allnodesNmask, 1);
573 		else if(memcmp(lifc->local, v6linklocal, v6llpreflen) == 0)
574 			/* remove route for all link multicast */
575 			v6delroute(f, v6allnodesL, v6allnodesLmask, 1);
576 	}
577 
578 	free(lifc);
579 	return nil;
580 }
581 
582 /*
583  *  remove an address from an interface.
584  *  called with c->car locked
585  */
586 char*
ipifcrem(Ipifc * ifc,char ** argv,int argc)587 ipifcrem(Ipifc *ifc, char **argv, int argc)
588 {
589 	char *rv;
590 	uchar ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen];
591 	Iplifc *lifc;
592 
593 	if(argc < 3)
594 		return Ebadarg;
595 
596 	if (parseip(ip, argv[1]) == -1)
597 		return Ebadip;
598 	parseipmask(mask, argv[2]);
599 	if(argc < 4)
600 		maskip(ip, mask, rem);
601 	else
602 		if (parseip(rem, argv[3]) == -1)
603 			return Ebadip;
604 
605 	wlock(ifc);
606 
607 	/*
608 	 *  find address on this interface and remove from chain.
609 	 *  for pt to pt we actually specify the remote address as the
610 	 *  addresss to remove.
611 	 */
612 	for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next) {
613 		if (memcmp(ip, lifc->local, IPaddrlen) == 0
614 		&& memcmp(mask, lifc->mask, IPaddrlen) == 0
615 		&& memcmp(rem, lifc->remote, IPaddrlen) == 0)
616 			break;
617 	}
618 
619 	rv = ipifcremlifc(ifc, lifc);
620 	wunlock(ifc);
621 	return rv;
622 }
623 
624 /*
625  * distribute routes to active interfaces like the
626  * TRIP linecards
627  */
628 void
ipifcaddroute(Fs * f,int vers,uchar * addr,uchar * mask,uchar * gate,int type)629 ipifcaddroute(Fs *f, int vers, uchar *addr, uchar *mask, uchar *gate, int type)
630 {
631 	Medium *m;
632 	Conv **cp, **e;
633 	Ipifc *ifc;
634 
635 	e = &f->ipifc->conv[f->ipifc->nc];
636 	for(cp = f->ipifc->conv; cp < e; cp++){
637 		if(*cp != nil) {
638 			ifc = (Ipifc*)(*cp)->ptcl;
639 			m = ifc->m;
640 			if(m && m->addroute)
641 				m->addroute(ifc, vers, addr, mask, gate, type);
642 		}
643 	}
644 }
645 
646 void
ipifcremroute(Fs * f,int vers,uchar * addr,uchar * mask)647 ipifcremroute(Fs *f, int vers, uchar *addr, uchar *mask)
648 {
649 	Medium *m;
650 	Conv **cp, **e;
651 	Ipifc *ifc;
652 
653 	e = &f->ipifc->conv[f->ipifc->nc];
654 	for(cp = f->ipifc->conv; cp < e; cp++){
655 		if(*cp != nil) {
656 			ifc = (Ipifc*)(*cp)->ptcl;
657 			m = ifc->m;
658 			if(m && m->remroute)
659 				m->remroute(ifc, vers, addr, mask);
660 		}
661 	}
662 }
663 
664 /*
665  *  associate an address with the interface.  This wipes out any previous
666  *  addresses.  This is a macro that means, remove all the old interfaces
667  *  and add a new one.
668  */
669 static char*
ipifcconnect(Conv * c,char ** argv,int argc)670 ipifcconnect(Conv* c, char **argv, int argc)
671 {
672 	char *err;
673 	Ipifc *ifc;
674 
675 	ifc = (Ipifc*)c->ptcl;
676 
677 	if(ifc->m == nil)
678 		 return "ipifc not yet bound to device";
679 
680 	if(waserror()){
681 		wunlock(ifc);
682 		nexterror();
683 	}
684 	wlock(ifc);
685 	while(ifc->lifc){
686 		err = ipifcremlifc(ifc, ifc->lifc);
687 		if(err)
688 			error(err);
689 	}
690 	wunlock(ifc);
691 	poperror();
692 
693 	err = ipifcadd(ifc, argv, argc, 0, nil);
694 	if(err)
695 		return err;
696 
697 	Fsconnected(c, nil);
698 	return nil;
699 }
700 
701 char*
ipifcra6(Ipifc * ifc,char ** argv,int argc)702 ipifcra6(Ipifc *ifc, char **argv, int argc)
703 {
704 	int i, argsleft, vmax = ifc->rp.maxraint, vmin = ifc->rp.minraint;
705 
706 	argsleft = argc - 1;
707 	i = 1;
708 
709 	if(argsleft % 2 != 0)
710 		return Ebadarg;
711 
712 	while (argsleft > 1) {
713 		if(strcmp(argv[i], "recvra") == 0)
714 			ifc->recvra6 = (atoi(argv[i+1]) != 0);
715 		else if(strcmp(argv[i], "sendra") == 0)
716 			ifc->sendra6 = (atoi(argv[i+1]) != 0);
717 		else if(strcmp(argv[i], "mflag") == 0)
718 			ifc->rp.mflag = (atoi(argv[i+1]) != 0);
719 		else if(strcmp(argv[i], "oflag") == 0)
720 			ifc->rp.oflag = (atoi(argv[i+1]) != 0);
721 		else if(strcmp(argv[i], "maxraint") == 0)
722 			ifc->rp.maxraint = atoi(argv[i+1]);
723 		else if(strcmp(argv[i], "minraint") == 0)
724 			ifc->rp.minraint = atoi(argv[i+1]);
725 		else if(strcmp(argv[i], "linkmtu") == 0)
726 			ifc->rp.linkmtu = atoi(argv[i+1]);
727 		else if(strcmp(argv[i], "reachtime") == 0)
728 			ifc->rp.reachtime = atoi(argv[i+1]);
729 		else if(strcmp(argv[i], "rxmitra") == 0)
730 			ifc->rp.rxmitra = atoi(argv[i+1]);
731 		else if(strcmp(argv[i], "ttl") == 0)
732 			ifc->rp.ttl = atoi(argv[i+1]);
733 		else if(strcmp(argv[i], "routerlt") == 0)
734 			ifc->rp.routerlt = atoi(argv[i+1]);
735 		else
736 			return Ebadarg;
737 
738 		argsleft -= 2;
739 		i += 2;
740 	}
741 
742 	/* consistency check */
743 	if(ifc->rp.maxraint < ifc->rp.minraint) {
744 		ifc->rp.maxraint = vmax;
745 		ifc->rp.minraint = vmin;
746 		return Ebadarg;
747 	}
748 	return nil;
749 }
750 
751 /*
752  *  non-standard control messages.
753  *  called with c->car locked.
754  */
755 static char*
ipifcctl(Conv * c,char ** argv,int argc)756 ipifcctl(Conv* c, char**argv, int argc)
757 {
758 	Ipifc *ifc;
759 	int i;
760 
761 	ifc = (Ipifc*)c->ptcl;
762 	if(strcmp(argv[0], "add") == 0)
763 		return ipifcadd(ifc, argv, argc, 0, nil);
764 	else if(strcmp(argv[0], "try") == 0)
765 		return ipifcadd(ifc, argv, argc, 1, nil);
766 	else if(strcmp(argv[0], "remove") == 0)
767 		return ipifcrem(ifc, argv, argc);
768 	else if(strcmp(argv[0], "unbind") == 0)
769 		return ipifcunbind(ifc);
770 	else if(strcmp(argv[0], "joinmulti") == 0)
771 		return ipifcjoinmulti(ifc, argv, argc);
772 	else if(strcmp(argv[0], "leavemulti") == 0)
773 		return ipifcleavemulti(ifc, argv, argc);
774 	else if(strcmp(argv[0], "mtu") == 0)
775 		return ipifcsetmtu(ifc, argv, argc);
776 	else if(strcmp(argv[0], "reassemble") == 0){
777 		ifc->reassemble = 1;
778 		return nil;
779 	}
780 	else if(strcmp(argv[0], "iprouting") == 0){
781 		i = 1;
782 		if(argc > 1)
783 			i = atoi(argv[1]);
784 		iprouting(c->p->f, i);
785 		return nil;
786 	}
787 	else if(strcmp(argv[0], "add6") == 0)
788 		return ipifcadd6(ifc, argv, argc);
789 	else if(strcmp(argv[0], "ra6") == 0)
790 		return ipifcra6(ifc, argv, argc);
791 	return "unsupported ctl";
792 }
793 
794 int
ipifcstats(Proto * ipifc,char * buf,int len)795 ipifcstats(Proto *ipifc, char *buf, int len)
796 {
797 	return ipstats(ipifc->f, buf, len);
798 }
799 
800 void
ipifcinit(Fs * f)801 ipifcinit(Fs *f)
802 {
803 	Proto *ipifc;
804 
805 	ipifc = smalloc(sizeof(Proto));
806 	ipifc->name = "ipifc";
807 	ipifc->connect = ipifcconnect;
808 	ipifc->announce = nil;
809 	ipifc->bind = ipifcbind;
810 	ipifc->state = ipifcstate;
811 	ipifc->create = ipifccreate;
812 	ipifc->close = ipifcclose;
813 	ipifc->rcv = nil;
814 	ipifc->ctl = ipifcctl;
815 	ipifc->advise = nil;
816 	ipifc->stats = ipifcstats;
817 	ipifc->inuse = ipifcinuse;
818 	ipifc->local = ipifclocal;
819 	ipifc->ipproto = -1;
820 	ipifc->nc = Maxmedia;
821 	ipifc->ptclsize = sizeof(Ipifc);
822 
823 	f->ipifc = ipifc;	/* hack for ipifcremroute, findipifc, ... */
824 	f->self = smalloc(sizeof(Ipselftab));	/* hack for ipforme */
825 
826 	Fsproto(f, ipifc);
827 }
828 
829 /*
830  *  add to self routing cache
831  *	called with c->car locked
832  */
833 static void
addselfcache(Fs * f,Ipifc * ifc,Iplifc * lifc,uchar * a,int type)834 addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type)
835 {
836 	Ipself *p;
837 	Iplink *lp;
838 	int h;
839 
840 	qlock(f->self);
841 
842 	/* see if the address already exists */
843 	h = hashipa(a);
844 	for(p = f->self->hash[h]; p; p = p->next)
845 		if(memcmp(a, p->a, IPaddrlen) == 0)
846 			break;
847 
848 	/* allocate a local address and add to hash chain */
849 	if(p == nil){
850 		p = smalloc(sizeof(*p));
851 		ipmove(p->a, a);
852 		p->type = type;
853 		p->next = f->self->hash[h];
854 		f->self->hash[h] = p;
855 
856 		/* if the null address, accept all packets */
857 		if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
858 			f->self->acceptall = 1;
859 	}
860 
861 	/* look for a link for this lifc */
862 	for(lp = p->link; lp; lp = lp->selflink)
863 		if(lp->lifc == lifc)
864 			break;
865 
866 	/* allocate a lifc-to-local link and link to both */
867 	if(lp == nil){
868 		lp = smalloc(sizeof(*lp));
869 		lp->ref = 1;
870 		lp->lifc = lifc;
871 		lp->self = p;
872 		lp->selflink = p->link;
873 		p->link = lp;
874 		lp->lifclink = lifc->link;
875 		lifc->link = lp;
876 
877 		/* add to routing table */
878 		if(isv4(a))
879 			v4addroute(f, tifc, a+IPv4off, IPallbits+IPv4off,
880 				a+IPv4off, type);
881 		else
882 			v6addroute(f, tifc, a, IPallbits, a, type);
883 
884 		if((type & Rmulti) && ifc->m->addmulti != nil)
885 			(*ifc->m->addmulti)(ifc, a, lifc->local);
886 	} else
887 		lp->ref++;
888 
889 	qunlock(f->self);
890 }
891 
892 /*
893  *  These structures are unlinked from their chains while
894  *  other threads may be using them.  To avoid excessive locking,
895  *  just put them aside for a while before freeing them.
896  *	called with f->self locked
897  */
898 static Iplink *freeiplink;
899 static Ipself *freeipself;
900 
901 static void
iplinkfree(Iplink * p)902 iplinkfree(Iplink *p)
903 {
904 	Iplink **l, *np;
905 	ulong now = NOW;
906 
907 	l = &freeiplink;
908 	for(np = *l; np; np = *l){
909 		if(np->expire > now){
910 			*l = np->next;
911 			free(np);
912 			continue;
913 		}
914 		l = &np->next;
915 	}
916 	p->expire = now + 5000;	/* give other threads 5 secs to get out */
917 	p->next = nil;
918 	*l = p;
919 }
920 
921 static void
ipselffree(Ipself * p)922 ipselffree(Ipself *p)
923 {
924 	Ipself **l, *np;
925 	ulong now = NOW;
926 
927 	l = &freeipself;
928 	for(np = *l; np; np = *l){
929 		if(np->expire > now){
930 			*l = np->next;
931 			free(np);
932 			continue;
933 		}
934 		l = &np->next;
935 	}
936 	p->expire = now + 5000;	/* give other threads 5 secs to get out */
937 	p->next = nil;
938 	*l = p;
939 }
940 
941 /*
942  *  Decrement reference for this address on this link.
943  *  Unlink from selftab if this is the last ref.
944  *	called with c->car locked
945  */
946 static void
remselfcache(Fs * f,Ipifc * ifc,Iplifc * lifc,uchar * a)947 remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a)
948 {
949 	Ipself *p, **l;
950 	Iplink *link, **l_self, **l_lifc;
951 
952 	qlock(f->self);
953 
954 	/* find the unique selftab entry */
955 	l = &f->self->hash[hashipa(a)];
956 	for(p = *l; p; p = *l){
957 		if(ipcmp(p->a, a) == 0)
958 			break;
959 		l = &p->next;
960 	}
961 
962 	if(p == nil)
963 		goto out;
964 
965 	/*
966 	 *  walk down links from an ifc looking for one
967 	 *  that matches the selftab entry
968 	 */
969 	l_lifc = &lifc->link;
970 	for(link = *l_lifc; link; link = *l_lifc){
971 		if(link->self == p)
972 			break;
973 		l_lifc = &link->lifclink;
974 	}
975 
976 	if(link == nil)
977 		goto out;
978 
979 	/*
980 	 *  walk down the links from the selftab looking for
981 	 *  the one we just found
982 	 */
983 	l_self = &p->link;
984 	for(link = *l_self; link; link = *l_self){
985 		if(link == *l_lifc)
986 			break;
987 		l_self = &link->selflink;
988 	}
989 
990 	if(link == nil)
991 		panic("remselfcache");
992 
993 	if(--(link->ref) != 0)
994 		goto out;
995 
996 	if((p->type & Rmulti) && ifc->m->remmulti != nil)
997 		(*ifc->m->remmulti)(ifc, a, lifc->local);
998 
999 	/* ref == 0, remove from both chains and free the link */
1000 	*l_lifc = link->lifclink;
1001 	*l_self = link->selflink;
1002 	iplinkfree(link);
1003 
1004 	if(p->link != nil)
1005 		goto out;
1006 
1007 	/* remove from routing table */
1008 	if(isv4(a))
1009 		v4delroute(f, a+IPv4off, IPallbits+IPv4off, 1);
1010 	else
1011 		v6delroute(f, a, IPallbits, 1);
1012 
1013 	/* no more links, remove from hash and free */
1014 	*l = p->next;
1015 	ipselffree(p);
1016 
1017 	/* if IPnoaddr, forget */
1018 	if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
1019 		f->self->acceptall = 0;
1020 
1021 out:
1022 	qunlock(f->self);
1023 }
1024 
1025 static char *stformat = "%-44.44I %2.2d %4.4s\n";
1026 enum
1027 {
1028 	Nstformat= 41,
1029 };
1030 
1031 long
ipselftabread(Fs * f,char * cp,ulong offset,int n)1032 ipselftabread(Fs *f, char *cp, ulong offset, int n)
1033 {
1034 	int i, m, nifc, off;
1035 	Ipself *p;
1036 	Iplink *link;
1037 	char state[8];
1038 
1039 	m = 0;
1040 	off = offset;
1041 	qlock(f->self);
1042 	for(i = 0; i < NHASH && m < n; i++){
1043 		for(p = f->self->hash[i]; p != nil && m < n; p = p->next){
1044 			nifc = 0;
1045 			for(link = p->link; link; link = link->selflink)
1046 				nifc++;
1047 			routetype(p->type, state);
1048 			m += snprint(cp + m, n - m, stformat, p->a, nifc, state);
1049 			if(off > 0){
1050 				off -= m;
1051 				m = 0;
1052 			}
1053 		}
1054 	}
1055 	qunlock(f->self);
1056 	return m;
1057 }
1058 
1059 int
iptentative(Fs * f,uchar * addr)1060 iptentative(Fs *f, uchar *addr)
1061 {
1062  	Ipself *p;
1063 
1064 	p = f->self->hash[hashipa(addr)];
1065 	for(; p; p = p->next){
1066 		if(ipcmp(addr, p->a) == 0)
1067 			return p->link->lifc->tentative;
1068 	}
1069 	return 0;
1070 }
1071 
1072 /*
1073  *  returns
1074  *	0		- no match
1075  *	Runi
1076  *	Rbcast
1077  *	Rmcast
1078  */
1079 int
ipforme(Fs * f,uchar * addr)1080 ipforme(Fs *f, uchar *addr)
1081 {
1082 	Ipself *p;
1083 
1084 	p = f->self->hash[hashipa(addr)];
1085 	for(; p; p = p->next){
1086 		if(ipcmp(addr, p->a) == 0)
1087 			return p->type;
1088 	}
1089 
1090 	/* hack to say accept anything */
1091 	if(f->self->acceptall)
1092 		return Runi;
1093 	return 0;
1094 }
1095 
1096 /*
1097  *  find the ifc on same net as the remote system.  If none,
1098  *  return nil.
1099  */
1100 Ipifc*
findipifc(Fs * f,uchar * remote,int type)1101 findipifc(Fs *f, uchar *remote, int type)
1102 {
1103 	Ipifc *ifc, *x;
1104 	Iplifc *lifc;
1105 	Conv **cp, **e;
1106 	uchar gnet[IPaddrlen], xmask[IPaddrlen];
1107 
1108 	x = nil;
1109 	memset(xmask, 0, IPaddrlen);
1110 
1111 	/* find most specific match */
1112 	e = &f->ipifc->conv[f->ipifc->nc];
1113 	for(cp = f->ipifc->conv; cp < e; cp++){
1114 		if(*cp == 0)
1115 			continue;
1116 		ifc = (Ipifc*)(*cp)->ptcl;
1117 		for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1118 			maskip(remote, lifc->mask, gnet);
1119 			if(ipcmp(gnet, lifc->net) == 0){
1120 				if(x == nil || ipcmp(lifc->mask, xmask) > 0){
1121 					x = ifc;
1122 					ipmove(xmask, lifc->mask);
1123 				}
1124 			}
1125 		}
1126 	}
1127 	if(x != nil)
1128 		return x;
1129 
1130 	/* for now for broadcast and multicast, just use first interface */
1131 	if(type & (Rbcast|Rmulti)){
1132 		for(cp = f->ipifc->conv; cp < e; cp++){
1133 			if(*cp == 0)
1134 				continue;
1135 			ifc = (Ipifc*)(*cp)->ptcl;
1136 			if(ifc->lifc != nil)
1137 				return ifc;
1138 		}
1139 	}
1140 	return nil;
1141 }
1142 
1143 enum {
1144 	unknownv6,		/* UGH */
1145 //	multicastv6,
1146 	unspecifiedv6,
1147 	linklocalv6,
1148 	globalv6,
1149 };
1150 
1151 int
v6addrtype(uchar * addr)1152 v6addrtype(uchar *addr)
1153 {
1154 	if(isv4(addr) || ipcmp(addr, IPnoaddr) == 0)
1155 		return unknownv6;
1156 	else if(islinklocal(addr) ||
1157 	    isv6mcast(addr) && (addr[1] & 0xF) <= Link_local_scop)
1158 		return linklocalv6;
1159 	else
1160 		return globalv6;
1161 }
1162 
1163 #define v6addrcurr(lifc) ((lifc)->preflt == ~0L || \
1164 			(lifc)->origint + (lifc)->preflt >= NOW/1000)
1165 
1166 static void
findprimaryipv6(Fs * f,uchar * local)1167 findprimaryipv6(Fs *f, uchar *local)
1168 {
1169 	int atype, atypel;
1170 	Conv **cp, **e;
1171 	Ipifc *ifc;
1172 	Iplifc *lifc;
1173 
1174 	ipmove(local, v6Unspecified);
1175 	atype = unspecifiedv6;
1176 
1177 	/*
1178 	 * find "best" (global > link local > unspecified)
1179 	 * local address; address must be current.
1180 	 */
1181 	e = &f->ipifc->conv[f->ipifc->nc];
1182 	for(cp = f->ipifc->conv; cp < e; cp++){
1183 		if(*cp == 0)
1184 			continue;
1185 		ifc = (Ipifc*)(*cp)->ptcl;
1186 		for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1187 			atypel = v6addrtype(lifc->local);
1188 			if(atypel > atype && v6addrcurr(lifc)) {
1189 				ipmove(local, lifc->local);
1190 				atype = atypel;
1191 				if(atype == globalv6)
1192 					return;
1193 			}
1194 		}
1195 	}
1196 }
1197 
1198 /*
1199  *  returns first ip address configured
1200  */
1201 static void
findprimaryipv4(Fs * f,uchar * local)1202 findprimaryipv4(Fs *f, uchar *local)
1203 {
1204 	Conv **cp, **e;
1205 	Ipifc *ifc;
1206 	Iplifc *lifc;
1207 
1208 	/* find first ifc local address */
1209 	e = &f->ipifc->conv[f->ipifc->nc];
1210 	for(cp = f->ipifc->conv; cp < e; cp++){
1211 		if(*cp == 0)
1212 			continue;
1213 		ifc = (Ipifc*)(*cp)->ptcl;
1214 		if((lifc = ifc->lifc) != nil){
1215 			ipmove(local, lifc->local);
1216 			return;
1217 		}
1218 	}
1219 }
1220 
1221 /*
1222  *  find the local address 'closest' to the remote system, copy it to
1223  *  local and return the ifc for that address
1224  */
1225 void
findlocalip(Fs * f,uchar * local,uchar * remote)1226 findlocalip(Fs *f, uchar *local, uchar *remote)
1227 {
1228 	int version, atype = unspecifiedv6, atypel = unknownv6;
1229 	int atyper, deprecated;
1230 	uchar gate[IPaddrlen], gnet[IPaddrlen];
1231 	Ipifc *ifc;
1232 	Iplifc *lifc;
1233 	Route *r;
1234 
1235 	USED(atype);
1236 	USED(atypel);
1237 	qlock(f->ipifc);
1238 	r = v6lookup(f, remote, nil);
1239  	version = (memcmp(remote, v4prefix, IPv4off) == 0)? V4: V6;
1240 
1241 	if(r != nil){
1242 		ifc = r->ifc;
1243 		if(r->type & Rv4)
1244 			v4tov6(gate, r->v4.gate);
1245 		else {
1246 			ipmove(gate, r->v6.gate);
1247 			ipmove(local, v6Unspecified);
1248 		}
1249 
1250 		switch(version) {
1251 		case V4:
1252 			/* find ifc address closest to the gateway to use */
1253 			for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1254 				maskip(gate, lifc->mask, gnet);
1255 				if(ipcmp(gnet, lifc->net) == 0){
1256 					ipmove(local, lifc->local);
1257 					goto out;
1258 				}
1259 			}
1260 			break;
1261 		case V6:
1262 			/* find ifc address with scope matching the destination */
1263 			atyper = v6addrtype(remote);
1264 			deprecated = 0;
1265 			for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1266 				atypel = v6addrtype(lifc->local);
1267 				/* prefer appropriate scope */
1268 				if(atypel > atype && atype < atyper ||
1269 				   atypel < atype && atype > atyper){
1270 					ipmove(local, lifc->local);
1271 					deprecated = !v6addrcurr(lifc);
1272 					atype = atypel;
1273 				} else if(atypel == atype){
1274 					/* avoid deprecated addresses */
1275 					if(deprecated && v6addrcurr(lifc)){
1276 						ipmove(local, lifc->local);
1277 						atype = atypel;
1278 						deprecated = 0;
1279 					}
1280 				}
1281 				if(atype == atyper && !deprecated)
1282 					goto out;
1283 			}
1284 			if(atype >= atyper)
1285 				goto out;
1286 			break;
1287 		default:
1288 			panic("findlocalip: version %d", version);
1289 		}
1290 	}
1291 
1292 	switch(version){
1293 	case V4:
1294 		findprimaryipv4(f, local);
1295 		break;
1296 	case V6:
1297 		findprimaryipv6(f, local);
1298 		break;
1299 	default:
1300 		panic("findlocalip2: version %d", version);
1301 	}
1302 
1303 out:
1304 	qunlock(f->ipifc);
1305 }
1306 
1307 /*
1308  *  return first v4 address associated with an interface
1309  */
1310 int
ipv4local(Ipifc * ifc,uchar * addr)1311 ipv4local(Ipifc *ifc, uchar *addr)
1312 {
1313 	Iplifc *lifc;
1314 
1315 	for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1316 		if(isv4(lifc->local)){
1317 			memmove(addr, lifc->local+IPv4off, IPv4addrlen);
1318 			return 1;
1319 		}
1320 	}
1321 	return 0;
1322 }
1323 
1324 /*
1325  *  return first v6 address associated with an interface
1326  */
1327 int
ipv6local(Ipifc * ifc,uchar * addr)1328 ipv6local(Ipifc *ifc, uchar *addr)
1329 {
1330 	Iplifc *lifc;
1331 
1332 	for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1333 		if(!isv4(lifc->local) && !(lifc->tentative)){
1334 			ipmove(addr, lifc->local);
1335 			return 1;
1336 		}
1337 	}
1338 	return 0;
1339 }
1340 
1341 int
ipv6anylocal(Ipifc * ifc,uchar * addr)1342 ipv6anylocal(Ipifc *ifc, uchar *addr)
1343 {
1344 	Iplifc *lifc;
1345 
1346 	for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1347 		if(!isv4(lifc->local)){
1348 			ipmove(addr, lifc->local);
1349 			return SRC_UNI;
1350 		}
1351 	}
1352 	return SRC_UNSPEC;
1353 }
1354 
1355 /*
1356  *  see if this address is bound to the interface
1357  */
1358 Iplifc*
iplocalonifc(Ipifc * ifc,uchar * ip)1359 iplocalonifc(Ipifc *ifc, uchar *ip)
1360 {
1361 	Iplifc *lifc;
1362 
1363 	for(lifc = ifc->lifc; lifc; lifc = lifc->next)
1364 		if(ipcmp(ip, lifc->local) == 0)
1365 			return lifc;
1366 	return nil;
1367 }
1368 
1369 
1370 /*
1371  *  See if we're proxying for this address on this interface
1372  */
1373 int
ipproxyifc(Fs * f,Ipifc * ifc,uchar * ip)1374 ipproxyifc(Fs *f, Ipifc *ifc, uchar *ip)
1375 {
1376 	Route *r;
1377 	uchar net[IPaddrlen];
1378 	Iplifc *lifc;
1379 
1380 	/* see if this is a direct connected pt to pt address */
1381 	r = v6lookup(f, ip, nil);
1382 	if(r == nil || (r->type & (Rifc|Rproxy)) != (Rifc|Rproxy))
1383 		return 0;
1384 
1385 	/* see if this is on the right interface */
1386 	for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1387 		maskip(ip, lifc->mask, net);
1388 		if(ipcmp(net, lifc->remote) == 0)
1389 			return 1;
1390 	}
1391 	return 0;
1392 }
1393 
1394 /*
1395  *  return multicast version if any
1396  */
1397 int
ipismulticast(uchar * ip)1398 ipismulticast(uchar *ip)
1399 {
1400 	if(isv4(ip)){
1401 		if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
1402 			return V4;
1403 	}
1404 	else if(ip[0] == 0xff)
1405 		return V6;
1406 	return 0;
1407 }
1408 int
ipisbm(uchar * ip)1409 ipisbm(uchar *ip)
1410 {
1411 	if(isv4(ip)){
1412 		if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
1413 			return V4;
1414 		else if(ipcmp(ip, IPv4bcast) == 0)
1415 			return V4;
1416 	}
1417 	else if(ip[0] == 0xff)
1418 		return V6;
1419 	return 0;
1420 }
1421 
1422 
1423 /*
1424  *  add a multicast address to an interface, called with c->car locked
1425  */
1426 void
ipifcaddmulti(Conv * c,uchar * ma,uchar * ia)1427 ipifcaddmulti(Conv *c, uchar *ma, uchar *ia)
1428 {
1429 	Ipifc *ifc;
1430 	Iplifc *lifc;
1431 	Conv **p;
1432 	Ipmulti *multi, **l;
1433 	Fs *f;
1434 
1435 	f = c->p->f;
1436 
1437 	for(l = &c->multi; *l; l = &(*l)->next)
1438 		if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0)
1439 			return;		/* it's already there */
1440 
1441 	multi = *l = smalloc(sizeof(*multi));
1442 	ipmove(multi->ma, ma);
1443 	ipmove(multi->ia, ia);
1444 	multi->next = nil;
1445 
1446 	for(p = f->ipifc->conv; *p; p++){
1447 		if((*p)->inuse == 0)
1448 			continue;
1449 		ifc = (Ipifc*)(*p)->ptcl;
1450 		if(waserror()){
1451 			wunlock(ifc);
1452 			nexterror();
1453 		}
1454 		wlock(ifc);
1455 		for(lifc = ifc->lifc; lifc; lifc = lifc->next)
1456 			if(ipcmp(ia, lifc->local) == 0)
1457 				addselfcache(f, ifc, lifc, ma, Rmulti);
1458 		wunlock(ifc);
1459 		poperror();
1460 	}
1461 }
1462 
1463 
1464 /*
1465  *  remove a multicast address from an interface, called with c->car locked
1466  */
1467 void
ipifcremmulti(Conv * c,uchar * ma,uchar * ia)1468 ipifcremmulti(Conv *c, uchar *ma, uchar *ia)
1469 {
1470 	Ipmulti *multi, **l;
1471 	Iplifc *lifc;
1472 	Conv **p;
1473 	Ipifc *ifc;
1474 	Fs *f;
1475 
1476 	f = c->p->f;
1477 
1478 	for(l = &c->multi; *l; l = &(*l)->next)
1479 		if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0)
1480 			break;
1481 
1482 	multi = *l;
1483 	if(multi == nil)
1484 		return; 	/* we don't have it open */
1485 
1486 	*l = multi->next;
1487 
1488 	for(p = f->ipifc->conv; *p; p++){
1489 		if((*p)->inuse == 0)
1490 			continue;
1491 
1492 		ifc = (Ipifc*)(*p)->ptcl;
1493 		if(waserror()){
1494 			wunlock(ifc);
1495 			nexterror();
1496 		}
1497 		wlock(ifc);
1498 		for(lifc = ifc->lifc; lifc; lifc = lifc->next)
1499 			if(ipcmp(ia, lifc->local) == 0)
1500 				remselfcache(f, ifc, lifc, ma);
1501 		wunlock(ifc);
1502 		poperror();
1503 	}
1504 
1505 	free(multi);
1506 }
1507 
1508 /*
1509  *  make lifc's join and leave multicast groups
1510  */
1511 static char*
ipifcjoinmulti(Ipifc * ifc,char ** argv,int argc)1512 ipifcjoinmulti(Ipifc *ifc, char **argv, int argc)
1513 {
1514 	USED(ifc, argv, argc);
1515 	return nil;
1516 }
1517 
1518 static char*
ipifcleavemulti(Ipifc * ifc,char ** argv,int argc)1519 ipifcleavemulti(Ipifc *ifc, char **argv, int argc)
1520 {
1521 	USED(ifc, argv, argc);
1522 	return nil;
1523 }
1524 
1525 static void
ipifcregisterproxy(Fs * f,Ipifc * ifc,uchar * ip)1526 ipifcregisterproxy(Fs *f, Ipifc *ifc, uchar *ip)
1527 {
1528 	Conv **cp, **e;
1529 	Ipifc *nifc;
1530 	Iplifc *lifc;
1531 	Medium *m;
1532 	uchar net[IPaddrlen];
1533 
1534 	/* register the address on any network that will proxy for us */
1535 	e = &f->ipifc->conv[f->ipifc->nc];
1536 
1537 	if(!isv4(ip)) {				/* V6 */
1538 		for(cp = f->ipifc->conv; cp < e; cp++){
1539 			if(*cp == nil || (nifc = (Ipifc*)(*cp)->ptcl) == ifc)
1540 				continue;
1541 			rlock(nifc);
1542 			m = nifc->m;
1543 			if(m == nil || m->addmulti == nil) {
1544 				runlock(nifc);
1545 				continue;
1546 			}
1547 			for(lifc = nifc->lifc; lifc; lifc = lifc->next){
1548 				maskip(ip, lifc->mask, net);
1549 				if(ipcmp(net, lifc->remote) == 0) {
1550 					/* add solicited-node multicast addr */
1551 					ipv62smcast(net, ip);
1552 					addselfcache(f, nifc, lifc, net, Rmulti);
1553 					arpenter(f, V6, ip, nifc->mac, 6, 0);
1554 					// (*m->addmulti)(nifc, net, ip);
1555 					break;
1556 				}
1557 			}
1558 			runlock(nifc);
1559 		}
1560 	}
1561 	else {					/* V4 */
1562 		for(cp = f->ipifc->conv; cp < e; cp++){
1563 			if(*cp == nil || (nifc = (Ipifc*)(*cp)->ptcl) == ifc)
1564 				continue;
1565 			rlock(nifc);
1566 			m = nifc->m;
1567 			if(m == nil || m->areg == nil){
1568 				runlock(nifc);
1569 				continue;
1570 			}
1571 			for(lifc = nifc->lifc; lifc; lifc = lifc->next){
1572 				maskip(ip, lifc->mask, net);
1573 				if(ipcmp(net, lifc->remote) == 0){
1574 					(*m->areg)(nifc, ip);
1575 					break;
1576 				}
1577 			}
1578 			runlock(nifc);
1579 		}
1580 	}
1581 }
1582 
1583 
1584 /* added for new v6 mesg types */
1585 static void
adddefroute6(Fs * f,uchar * gate,int force)1586 adddefroute6(Fs *f, uchar *gate, int force)
1587 {
1588 	Route *r;
1589 
1590 	r = v6lookup(f, v6Unspecified, nil);
1591 	/*
1592 	 * route entries generated by all other means take precedence
1593 	 * over router announcements.
1594 	 */
1595 	if (r && !force && strcmp(r->tag, "ra") != 0)
1596 		return;
1597 
1598 	v6delroute(f, v6Unspecified, v6Unspecified, 1);
1599 	v6addroute(f, "ra", v6Unspecified, v6Unspecified, gate, 0);
1600 }
1601 
1602 enum {
1603 	Ngates = 3,
1604 };
1605 
1606 char*
ipifcadd6(Ipifc * ifc,char ** argv,int argc)1607 ipifcadd6(Ipifc *ifc, char**argv, int argc)
1608 {
1609 	int plen = 64;
1610 	long origint = NOW / 1000, preflt = ~0L, validlt = ~0L;
1611 	char addr[Maxv6repr], preflen[6];
1612 	char *params[3];
1613 	uchar autoflag = 1, onlink = 1;
1614 	uchar prefix[IPaddrlen];
1615 	Iplifc *lifc;
1616 
1617 	switch(argc) {
1618 	case 7:
1619 		preflt = atoi(argv[6]);
1620 		/* fall through */
1621 	case 6:
1622 		validlt = atoi(argv[5]);
1623 		/* fall through */
1624 	case 5:
1625 		autoflag = atoi(argv[4]);
1626 		/* fall through */
1627 	case 4:
1628 		onlink = atoi(argv[3]);
1629 		/* fall through */
1630 	case 3:
1631 		plen = atoi(argv[2]);
1632 		/* fall through */
1633 	case 2:
1634 		break;
1635 	default:
1636 		return Ebadarg;
1637 	}
1638 
1639 	if (parseip(prefix, argv[1]) != 6)
1640 		return "bad ipv6 address";
1641 	if (validlt < preflt)
1642 		return "valid ipv6 lifetime less than preferred lifetime";
1643 	if (plen < 0)
1644 		return "negative ipv6 prefix length";
1645 	/* i think that this length limit is bogus - geoff */
1646 //	if (plen > 64)
1647 //		return "ipv6 prefix length greater than 64;
1648 	if (islinklocal(prefix))
1649 		return "ipv6 prefix is link-local";
1650 
1651 	lifc = smalloc(sizeof(Iplifc));
1652 	lifc->onlink = (onlink != 0);
1653 	lifc->autoflag = (autoflag != 0);
1654 	lifc->validlt = validlt;
1655 	lifc->preflt = preflt;
1656 	lifc->origint = origint;
1657 
1658 	/* issue "add" ctl msg for v6 link-local addr and prefix len */
1659 	if(!ifc->m->pref2addr)
1660 		return "no pref2addr on interface";
1661 	ifc->m->pref2addr(prefix, ifc->mac);	/* mac → v6 link-local addr */
1662 	snprint(addr, sizeof addr, "%I", prefix);
1663 	snprint(preflen, sizeof preflen, "/%d", plen);
1664 	params[0] = "add";
1665 	params[1] = addr;
1666 	params[2] = preflen;
1667 
1668 	return ipifcadd(ifc, params, 3, 0, lifc);
1669 }
1670