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