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