vx32

Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log | Files | Refs

ipifc.c (34075B)


      1 #include "u.h"
      2 #include "lib.h"
      3 #include "mem.h"
      4 #include "dat.h"
      5 #include "fns.h"
      6 #include "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	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) ( (ulong)(((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 	QLOCK(f->ipifc);
   1233 	r = v6lookup(f, remote, nil);
   1234  	version = (memcmp(remote, v4prefix, IPv4off) == 0)? V4: V6;
   1235 
   1236 	if(r != nil){
   1237 		ifc = r->ifc;
   1238 		if(r->type & Rv4)
   1239 			v4tov6(gate, r->v4.gate);
   1240 		else {
   1241 			ipmove(gate, r->v6.gate);
   1242 			ipmove(local, v6Unspecified);
   1243 		}
   1244 
   1245 		switch(version) {
   1246 		case V4:
   1247 			/* find ifc address closest to the gateway to use */
   1248 			for(lifc = ifc->lifc; lifc; lifc = lifc->next){
   1249 				maskip(gate, lifc->mask, gnet);
   1250 				if(ipcmp(gnet, lifc->net) == 0){
   1251 					ipmove(local, lifc->local);
   1252 					goto out;
   1253 				}
   1254 			}
   1255 			break;
   1256 		case V6:
   1257 			/* find ifc address with scope matching the destination */
   1258 			atyper = v6addrtype(remote);
   1259 			deprecated = 0;
   1260 			for(lifc = ifc->lifc; lifc; lifc = lifc->next){
   1261 				atypel = v6addrtype(lifc->local);
   1262 				/* prefer appropriate scope */
   1263 				if((atypel > atype && atype < atyper) ||
   1264 				   (atypel < atype && atype > atyper)){
   1265 					ipmove(local, lifc->local);
   1266 					deprecated = !v6addrcurr(lifc);
   1267 					atype = atypel;
   1268 				} else if(atypel == atype){
   1269 					/* avoid deprecated addresses */
   1270 					if(deprecated && v6addrcurr(lifc)){
   1271 						ipmove(local, lifc->local);
   1272 						atype = atypel;
   1273 						deprecated = 0;
   1274 					}
   1275 				}
   1276 				if(atype == atyper && !deprecated)
   1277 					goto out;
   1278 			}
   1279 			if(atype >= atyper)
   1280 				goto out;
   1281 			break;
   1282 		default:
   1283 			panic("findlocalip: version %d", version);
   1284 		}
   1285 	}
   1286 
   1287 	switch(version){
   1288 	case V4:
   1289 		findprimaryipv4(f, local);
   1290 		break;
   1291 	case V6:
   1292 		findprimaryipv6(f, local);
   1293 		break;
   1294 	default:
   1295 		panic("findlocalip2: version %d", version);
   1296 	}
   1297 
   1298 out:
   1299 	QUNLOCK(f->ipifc);
   1300 }
   1301 
   1302 /*
   1303  *  return first v4 address associated with an interface
   1304  */
   1305 int
   1306 ipv4local(Ipifc *ifc, uchar *addr)
   1307 {
   1308 	Iplifc *lifc;
   1309 
   1310 	for(lifc = ifc->lifc; lifc; lifc = lifc->next){
   1311 		if(isv4(lifc->local)){
   1312 			memmove(addr, lifc->local+IPv4off, IPv4addrlen);
   1313 			return 1;
   1314 		}
   1315 	}
   1316 	return 0;
   1317 }
   1318 
   1319 /*
   1320  *  return first v6 address associated with an interface
   1321  */
   1322 int
   1323 ipv6local(Ipifc *ifc, uchar *addr)
   1324 {
   1325 	Iplifc *lifc;
   1326 
   1327 	for(lifc = ifc->lifc; lifc; lifc = lifc->next){
   1328 		if(!isv4(lifc->local) && !(lifc->tentative)){
   1329 			ipmove(addr, lifc->local);
   1330 			return 1;
   1331 		}
   1332 	}
   1333 	return 0;
   1334 }
   1335 
   1336 int
   1337 ipv6anylocal(Ipifc *ifc, uchar *addr)
   1338 {
   1339 	Iplifc *lifc;
   1340 
   1341 	for(lifc = ifc->lifc; lifc; lifc = lifc->next){
   1342 		if(!isv4(lifc->local)){
   1343 			ipmove(addr, lifc->local);
   1344 			return SRC_UNI;
   1345 		}
   1346 	}
   1347 	return SRC_UNSPEC;
   1348 }
   1349 
   1350 /*
   1351  *  see if this address is bound to the interface
   1352  */
   1353 Iplifc*
   1354 iplocalonifc(Ipifc *ifc, uchar *ip)
   1355 {
   1356 	Iplifc *lifc;
   1357 
   1358 	for(lifc = ifc->lifc; lifc; lifc = lifc->next)
   1359 		if(ipcmp(ip, lifc->local) == 0)
   1360 			return lifc;
   1361 	return nil;
   1362 }
   1363 
   1364 
   1365 /*
   1366  *  See if we're proxying for this address on this interface
   1367  */
   1368 int
   1369 ipproxyifc(Fs *f, Ipifc *ifc, uchar *ip)
   1370 {
   1371 	Route *r;
   1372 	uchar net[IPaddrlen];
   1373 	Iplifc *lifc;
   1374 
   1375 	/* see if this is a direct connected pt to pt address */
   1376 	r = v6lookup(f, ip, nil);
   1377 	if(r == nil || (r->type & (Rifc|Rproxy)) != (Rifc|Rproxy))
   1378 		return 0;
   1379 
   1380 	/* see if this is on the right interface */
   1381 	for(lifc = ifc->lifc; lifc; lifc = lifc->next){
   1382 		maskip(ip, lifc->mask, net);
   1383 		if(ipcmp(net, lifc->remote) == 0)
   1384 			return 1;
   1385 	}
   1386 	return 0;
   1387 }
   1388 
   1389 /*
   1390  *  return multicast version if any
   1391  */
   1392 int
   1393 ipismulticast(uchar *ip)
   1394 {
   1395 	if(isv4(ip)){
   1396 		if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
   1397 			return V4;
   1398 	}
   1399 	else if(ip[0] == 0xff)
   1400 		return V6;
   1401 	return 0;
   1402 }
   1403 int
   1404 ipisbm(uchar *ip)
   1405 {
   1406 	if(isv4(ip)){
   1407 		if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
   1408 			return V4;
   1409 		else if(ipcmp(ip, IPv4bcast) == 0)
   1410 			return V4;
   1411 	}
   1412 	else if(ip[0] == 0xff)
   1413 		return V6;
   1414 	return 0;
   1415 }
   1416 
   1417 
   1418 /*
   1419  *  add a multicast address to an interface, called with c->car locked
   1420  */
   1421 void
   1422 ipifcaddmulti(Conv *c, uchar *ma, uchar *ia)
   1423 {
   1424 	Ipifc *ifc;
   1425 	Iplifc *lifc;
   1426 	Conv **p;
   1427 	Ipmulti *multi, **l;
   1428 	Fs *f;
   1429 
   1430 	f = c->p->f;
   1431 
   1432 	for(l = &c->multi; *l; l = &(*l)->next)
   1433 		if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0)
   1434 			return;		/* it's already there */
   1435 
   1436 	multi = *l = smalloc(sizeof(*multi));
   1437 	ipmove(multi->ma, ma);
   1438 	ipmove(multi->ia, ia);
   1439 	multi->next = nil;
   1440 
   1441 	for(p = f->ipifc->conv; *p; p++){
   1442 		if((*p)->inuse == 0)
   1443 			continue;
   1444 		ifc = (Ipifc*)(*p)->ptcl;
   1445 		if(waserror()){
   1446 			WUNLOCK(ifc);
   1447 			nexterror();
   1448 		}
   1449 		WLOCK(ifc);
   1450 		for(lifc = ifc->lifc; lifc; lifc = lifc->next)
   1451 			if(ipcmp(ia, lifc->local) == 0)
   1452 				addselfcache(f, ifc, lifc, ma, Rmulti);
   1453 		WUNLOCK(ifc);
   1454 		poperror();
   1455 	}
   1456 }
   1457 
   1458 
   1459 /*
   1460  *  remove a multicast address from an interface, called with c->car locked
   1461  */
   1462 void
   1463 ipifcremmulti(Conv *c, uchar *ma, uchar *ia)
   1464 {
   1465 	Ipmulti *multi, **l;
   1466 	Iplifc *lifc;
   1467 	Conv **p;
   1468 	Ipifc *ifc;
   1469 	Fs *f;
   1470 
   1471 	f = c->p->f;
   1472 
   1473 	for(l = &c->multi; *l; l = &(*l)->next)
   1474 		if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0)
   1475 			break;
   1476 
   1477 	multi = *l;
   1478 	if(multi == nil)
   1479 		return; 	/* we don't have it open */
   1480 
   1481 	*l = multi->next;
   1482 
   1483 	for(p = f->ipifc->conv; *p; p++){
   1484 		if((*p)->inuse == 0)
   1485 			continue;
   1486 
   1487 		ifc = (Ipifc*)(*p)->ptcl;
   1488 		if(waserror()){
   1489 			WUNLOCK(ifc);
   1490 			nexterror();
   1491 		}
   1492 		WLOCK(ifc);
   1493 		for(lifc = ifc->lifc; lifc; lifc = lifc->next)
   1494 			if(ipcmp(ia, lifc->local) == 0)
   1495 				remselfcache(f, ifc, lifc, ma);
   1496 		WUNLOCK(ifc);
   1497 		poperror();
   1498 	}
   1499 
   1500 	free(multi);
   1501 }
   1502 
   1503 /*
   1504  *  make lifc's join and leave multicast groups
   1505  */
   1506 static char*
   1507 ipifcjoinmulti(Ipifc *ifc, char **argv, int argc)
   1508 {
   1509 	return nil;
   1510 }
   1511 
   1512 static char*
   1513 ipifcleavemulti(Ipifc *ifc, char **argv, int argc)
   1514 {
   1515 	return nil;
   1516 }
   1517 
   1518 static void
   1519 ipifcregisterproxy(Fs *f, Ipifc *ifc, uchar *ip)
   1520 {
   1521 	Conv **cp, **e;
   1522 	Ipifc *nifc;
   1523 	Iplifc *lifc;
   1524 	Medium *m;
   1525 	uchar net[IPaddrlen];
   1526 
   1527 	/* register the address on any network that will proxy for us */
   1528 	e = &f->ipifc->conv[f->ipifc->nc];
   1529 
   1530 	if(!isv4(ip)) {				/* V6 */
   1531 		for(cp = f->ipifc->conv; cp < e; cp++){
   1532 			if(*cp == nil || (nifc = (Ipifc*)(*cp)->ptcl) == ifc)
   1533 				continue;
   1534 			RLOCK(nifc);
   1535 			m = nifc->m;
   1536 			if(m == nil || m->addmulti == nil) {
   1537 				RUNLOCK(nifc);
   1538 				continue;
   1539 			}
   1540 			for(lifc = nifc->lifc; lifc; lifc = lifc->next){
   1541 				maskip(ip, lifc->mask, net);
   1542 				if(ipcmp(net, lifc->remote) == 0) {
   1543 					/* add solicited-node multicast addr */
   1544 					ipv62smcast(net, ip);
   1545 					addselfcache(f, nifc, lifc, net, Rmulti);
   1546 					arpenter(f, V6, ip, nifc->mac, 6, 0);
   1547 					// (*m->addmulti)(nifc, net, ip);
   1548 					break;
   1549 				}
   1550 			}
   1551 			RUNLOCK(nifc);
   1552 		}
   1553 	}
   1554 	else {					/* V4 */
   1555 		for(cp = f->ipifc->conv; cp < e; cp++){
   1556 			if(*cp == nil || (nifc = (Ipifc*)(*cp)->ptcl) == ifc)
   1557 				continue;
   1558 			RLOCK(nifc);
   1559 			m = nifc->m;
   1560 			if(m == nil || m->areg == nil){
   1561 				RUNLOCK(nifc);
   1562 				continue;
   1563 			}
   1564 			for(lifc = nifc->lifc; lifc; lifc = lifc->next){
   1565 				maskip(ip, lifc->mask, net);
   1566 				if(ipcmp(net, lifc->remote) == 0){
   1567 					(*m->areg)(nifc, ip);
   1568 					break;
   1569 				}
   1570 			}
   1571 			RUNLOCK(nifc);
   1572 		}
   1573 	}
   1574 }
   1575 
   1576 
   1577 /* added for new v6 mesg types */
   1578 static void
   1579 adddefroute6(Fs *f, uchar *gate, int force)
   1580 {
   1581 	Route *r;
   1582 
   1583 	r = v6lookup(f, v6Unspecified, nil);
   1584 	/*
   1585 	 * route entries generated by all other means take precedence
   1586 	 * over router announcements.
   1587 	 */
   1588 	if (r && !force && strcmp(r->tag, "ra") != 0)
   1589 		return;
   1590 
   1591 	v6delroute(f, v6Unspecified, v6Unspecified, 1);
   1592 	v6addroute(f, "ra", v6Unspecified, v6Unspecified, gate, 0);
   1593 }
   1594 
   1595 enum {
   1596 	Ngates = 3,
   1597 };
   1598 
   1599 char*
   1600 ipifcadd6(Ipifc *ifc, char**argv, int argc)
   1601 {
   1602 	int plen = 64;
   1603 	long origint = NOW / 1000, preflt = ~0L, validlt = ~0L;
   1604 	char addr[40], preflen[6];
   1605 	char *params[3];
   1606 	uchar autoflag = 1, onlink = 1;
   1607 	uchar prefix[IPaddrlen];
   1608 	Iplifc *lifc;
   1609 
   1610 	switch(argc) {
   1611 	case 7:
   1612 		preflt = atoi(argv[6]);
   1613 		/* fall through */
   1614 	case 6:
   1615 		validlt = atoi(argv[5]);
   1616 		/* fall through */
   1617 	case 5:
   1618 		autoflag = atoi(argv[4]);
   1619 		/* fall through */
   1620 	case 4:
   1621 		onlink = atoi(argv[3]);
   1622 		/* fall through */
   1623 	case 3:
   1624 		plen = atoi(argv[2]);
   1625 		/* fall through */
   1626 	case 2:
   1627 		break;
   1628 	default:
   1629 		return Ebadarg;
   1630 	}
   1631 
   1632 	if (parseip(prefix, argv[1]) != 6 || validlt < preflt || plen < 0 ||
   1633 	    plen > 64 || islinklocal(prefix))
   1634 		return Ebadarg;
   1635 
   1636 	lifc = smalloc(sizeof(Iplifc));
   1637 	lifc->onlink = (onlink != 0);
   1638 	lifc->autoflag = (autoflag != 0);
   1639 	lifc->validlt = validlt;
   1640 	lifc->preflt = preflt;
   1641 	lifc->origint = origint;
   1642 
   1643 	/* issue "add" ctl msg for v6 link-local addr and prefix len */
   1644 	if(!ifc->m->pref2addr)
   1645 		return Ebadarg;
   1646 	ifc->m->pref2addr(prefix, ifc->mac);	/* mac → v6 link-local addr */
   1647 	sprint(addr, "%I", prefix);
   1648 	sprint(preflen, "/%d", plen);
   1649 	params[0] = "add";
   1650 	params[1] = addr;
   1651 	params[2] = preflen;
   1652 
   1653 	return ipifcadd(ifc, params, 3, 0, lifc);
   1654 }