vx32

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

devip.c (24957B)


      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 #include	"ip/ip.h"
      8 
      9 enum
     10 {
     11 	Qtopdir=	1,		/* top level directory */
     12 	Qtopbase,
     13 	Qarp=		Qtopbase,
     14 	Qbootp,
     15 	Qndb,
     16 	Qiproute,
     17 	Qipselftab,
     18 	Qlog,
     19 
     20 	Qprotodir,			/* directory for a protocol */
     21 	Qprotobase,
     22 	Qclone=		Qprotobase,
     23 	Qstats,
     24 
     25 	Qconvdir,			/* directory for a conversation */
     26 	Qconvbase,
     27 	Qctl=		Qconvbase,
     28 	Qdata,
     29 	Qerr,
     30 	Qlisten,
     31 	Qlocal,
     32 	Qremote,
     33 	Qstatus,
     34 	Qsnoop,
     35 
     36 	Logtype=	5,
     37 	Masktype=	(1<<Logtype)-1,
     38 	Logconv=	12,
     39 	Maskconv=	(1<<Logconv)-1,
     40 	Shiftconv=	Logtype,
     41 	Logproto=	8,
     42 	Maskproto=	(1<<Logproto)-1,
     43 	Shiftproto=	Logtype + Logconv,
     44 
     45 	Nfs=		128,
     46 };
     47 #define TYPE(x) 	( ((ulong)(x).path) & Masktype )
     48 #define CONV(x) 	( (((ulong)(x).path) >> Shiftconv) & Maskconv )
     49 #define PROTO(x) 	( (((ulong)(x).path) >> Shiftproto) & Maskproto )
     50 #define QID(p, c, y) 	( ((uint)(p)<<(Shiftproto)) | ((uint)(c)<<Shiftconv) | (y) )
     51 
     52 static char network[] = "network";
     53 
     54 QLock	fslock;
     55 Fs	*ipfs[Nfs];	/* attached fs's */
     56 Queue	*qlog;
     57 
     58 extern	void nullmediumlink(void);
     59 extern	void pktmediumlink(void);
     60 	long ndbwrite(Fs *f, char *a, ulong off, int n);
     61 
     62 static int
     63 ip3gen(Chan *c, int i, Dir *dp)
     64 {
     65 	Qid q;
     66 	Conv *cv;
     67 	char *p;
     68 
     69 	cv = ipfs[c->dev]->p[PROTO(c->qid)]->conv[CONV(c->qid)];
     70 	if(cv->owner == nil)
     71 		kstrdup(&cv->owner, eve);
     72 	mkqid(&q, QID(PROTO(c->qid), CONV(c->qid), i), 0, QTFILE);
     73 
     74 	switch(i) {
     75 	default:
     76 		return -1;
     77 	case Qctl:
     78 		devdir(c, q, "ctl", 0, cv->owner, cv->perm, dp);
     79 		return 1;
     80 	case Qdata:
     81 		devdir(c, q, "data", qlen(cv->rq), cv->owner, cv->perm, dp);
     82 		return 1;
     83 	case Qerr:
     84 		devdir(c, q, "err", qlen(cv->eq), cv->owner, cv->perm, dp);
     85 		return 1;
     86 	case Qlisten:
     87 		devdir(c, q, "listen", 0, cv->owner, cv->perm, dp);
     88 		return 1;
     89 	case Qlocal:
     90 		p = "local";
     91 		break;
     92 	case Qremote:
     93 		p = "remote";
     94 		break;
     95 	case Qsnoop:
     96 		if(strcmp(cv->p->name, "ipifc") != 0)
     97 			return -1;
     98 		devdir(c, q, "snoop", qlen(cv->sq), cv->owner, 0400, dp);
     99 		return 1;
    100 	case Qstatus:
    101 		p = "status";
    102 		break;
    103 	}
    104 	devdir(c, q, p, 0, cv->owner, 0444, dp);
    105 	return 1;
    106 }
    107 
    108 static int
    109 ip2gen(Chan *c, int i, Dir *dp)
    110 {
    111 	Qid q;
    112 
    113 	switch(i) {
    114 	case Qclone:
    115 		mkqid(&q, QID(PROTO(c->qid), 0, Qclone), 0, QTFILE);
    116 		devdir(c, q, "clone", 0, network, 0666, dp);
    117 		return 1;
    118 	case Qstats:
    119 		mkqid(&q, QID(PROTO(c->qid), 0, Qstats), 0, QTFILE);
    120 		devdir(c, q, "stats", 0, network, 0444, dp);
    121 		return 1;
    122 	}
    123 	return -1;
    124 }
    125 
    126 static int
    127 ip1gen(Chan *c, int i, Dir *dp)
    128 {
    129 	Qid q;
    130 	char *p;
    131 	int prot;
    132 	int len = 0;
    133 	Fs *f;
    134 	extern ulong	kerndate;
    135 
    136 	f = ipfs[c->dev];
    137 
    138 	prot = 0666;
    139 	mkqid(&q, QID(0, 0, i), 0, QTFILE);
    140 	switch(i) {
    141 	default:
    142 		return -1;
    143 	case Qarp:
    144 		p = "arp";
    145 		prot = 0664;
    146 		break;
    147 	case Qbootp:
    148 		p = "bootp";
    149 		break;
    150 	case Qndb:
    151 		p = "ndb";
    152 		len = strlen(f->ndb);
    153 		q.vers = f->ndbvers;
    154 		break;
    155 	case Qiproute:
    156 		p = "iproute";
    157 		prot = 0664;
    158 		break;
    159 	case Qipselftab:
    160 		p = "ipselftab";
    161 		prot = 0444;
    162 		break;
    163 	case Qlog:
    164 		p = "log";
    165 		break;
    166 	}
    167 	devdir(c, q, p, len, network, prot, dp);
    168 	if(i == Qndb && f->ndbmtime > kerndate)
    169 		dp->mtime = f->ndbmtime;
    170 	return 1;
    171 }
    172 
    173 static int
    174 ipgen(Chan *c, char* __ch, Dirtab* __dt, int __i, int s, Dir *dp)
    175 {
    176 	Qid q;
    177 	Conv *cv;
    178 	Fs *f;
    179 
    180 	f = ipfs[c->dev];
    181 
    182 	switch(TYPE(c->qid)) {
    183 	case Qtopdir:
    184 		if(s == DEVDOTDOT){
    185 			mkqid(&q, QID(0, 0, Qtopdir), 0, QTDIR);
    186 			sprint(up->genbuf, "#I%lud", c->dev);
    187 			devdir(c, q, up->genbuf, 0, network, 0555, dp);
    188 			return 1;
    189 		}
    190 		if(s < f->np) {
    191 			if(f->p[s]->connect == nil)
    192 				return 0;	/* protocol with no user interface */
    193 			mkqid(&q, QID(s, 0, Qprotodir), 0, QTDIR);
    194 			devdir(c, q, f->p[s]->name, 0, network, 0555, dp);
    195 			return 1;
    196 		}
    197 		s -= f->np;
    198 		return ip1gen(c, s+Qtopbase, dp);
    199 	case Qarp:
    200 	case Qbootp:
    201 	case Qndb:
    202 	case Qlog:
    203 	case Qiproute:
    204 	case Qipselftab:
    205 		return ip1gen(c, TYPE(c->qid), dp);
    206 	case Qprotodir:
    207 		if(s == DEVDOTDOT){
    208 			mkqid(&q, QID(0, 0, Qtopdir), 0, QTDIR);
    209 			sprint(up->genbuf, "#I%lud", c->dev);
    210 			devdir(c, q, up->genbuf, 0, network, 0555, dp);
    211 			return 1;
    212 		}
    213 		if(s < f->p[PROTO(c->qid)]->ac) {
    214 			cv = f->p[PROTO(c->qid)]->conv[s];
    215 			sprint(up->genbuf, "%d", s);
    216 			mkqid(&q, QID(PROTO(c->qid), s, Qconvdir), 0, QTDIR);
    217 			devdir(c, q, up->genbuf, 0, cv->owner, 0555, dp);
    218 			return 1;
    219 		}
    220 		s -= f->p[PROTO(c->qid)]->ac;
    221 		return ip2gen(c, s+Qprotobase, dp);
    222 	case Qclone:
    223 	case Qstats:
    224 		return ip2gen(c, TYPE(c->qid), dp);
    225 	case Qconvdir:
    226 		if(s == DEVDOTDOT){
    227 			s = PROTO(c->qid);
    228 			mkqid(&q, QID(s, 0, Qprotodir), 0, QTDIR);
    229 			devdir(c, q, f->p[s]->name, 0, network, 0555, dp);
    230 			return 1;
    231 		}
    232 		return ip3gen(c, s+Qconvbase, dp);
    233 	case Qctl:
    234 	case Qdata:
    235 	case Qerr:
    236 	case Qlisten:
    237 	case Qlocal:
    238 	case Qremote:
    239 	case Qstatus:
    240 	case Qsnoop:
    241 		return ip3gen(c, TYPE(c->qid), dp);
    242 	}
    243 	return -1;
    244 }
    245 
    246 static void
    247 ipreset(void)
    248 {
    249 	nullmediumlink();
    250 	pktmediumlink();
    251 
    252 	fmtinstall('i', eipfmt);
    253 	fmtinstall('I', eipfmt);
    254 	fmtinstall('E', eipfmt);
    255 	fmtinstall('V', eipfmt);
    256 	fmtinstall('M', eipfmt);
    257 }
    258 
    259 static Fs*
    260 ipgetfs(int dev)
    261 {
    262 	extern void (*ipprotoinit[])(Fs*);
    263 	Fs *f;
    264 	int i;
    265 
    266 	if(dev >= Nfs)
    267 		return nil;
    268 
    269 	qlock(&fslock);
    270 	if(ipfs[dev] == nil){
    271 		f = smalloc(sizeof(Fs));
    272 		ip_init(f);
    273 		arpinit(f);
    274 		netloginit(f);
    275 		for(i = 0; ipprotoinit[i]; i++)
    276 			ipprotoinit[i](f);
    277 		f->dev = dev;
    278 		ipfs[dev] = f;
    279 	}
    280 	qunlock(&fslock);
    281 
    282 	return ipfs[dev];
    283 }
    284 
    285 IPaux*
    286 newipaux(char *owner, char *tag)
    287 {
    288 	IPaux *a;
    289 	int n;
    290 
    291 	a = smalloc(sizeof(*a));
    292 	kstrdup(&a->owner, owner);
    293 	memset(a->tag, ' ', sizeof(a->tag));
    294 	n = strlen(tag);
    295 	if(n > sizeof(a->tag))
    296 		n = sizeof(a->tag);
    297 	memmove(a->tag, tag, n);
    298 	return a;
    299 }
    300 
    301 #define ATTACHER(c) (((IPaux*)((c)->aux))->owner)
    302 
    303 static Chan*
    304 ipattach(char* spec)
    305 {
    306 	Chan *c;
    307 	int dev;
    308 
    309 	dev = atoi(spec);
    310 	if(dev >= Nfs)
    311 		error("bad specification");
    312 
    313 	ipgetfs(dev);
    314 	c = devattach('I', spec);
    315 	mkqid(&c->qid, QID(0, 0, Qtopdir), 0, QTDIR);
    316 	c->dev = dev;
    317 
    318 	c->aux = newipaux(commonuser(), "none");
    319 
    320 	return c;
    321 }
    322 
    323 static Walkqid*
    324 ipwalk(Chan* c, Chan *nc, char **name, int nname)
    325 {
    326 	IPaux *a = c->aux;
    327 	Walkqid* w;
    328 
    329 	w = devwalk(c, nc, name, nname, nil, 0, ipgen);
    330 	if(w != nil && w->clone != nil)
    331 		w->clone->aux = newipaux(a->owner, a->tag);
    332 	return w;
    333 }
    334 
    335 
    336 static int
    337 ipstat(Chan* c, uchar* db, int n)
    338 {
    339 	return devstat(c, db, n, nil, 0, ipgen);
    340 }
    341 
    342 static int
    343 incoming(void* arg)
    344 {
    345 	Conv *conv;
    346 
    347 	conv = arg;
    348 	return conv->incall != nil;
    349 }
    350 
    351 static int m2p[] = {
    352 	[OREAD]		4,
    353 	[OWRITE]	2,
    354 	[ORDWR]		6
    355 };
    356 
    357 static Chan*
    358 ipopen(Chan* c, int omode)
    359 {
    360 	Conv *cv, *nc;
    361 	Proto *p;
    362 	int perm;
    363 	Fs *f;
    364 
    365 	perm = m2p[omode&3];
    366 
    367 	f = ipfs[c->dev];
    368 
    369 	switch(TYPE(c->qid)) {
    370 	default:
    371 		break;
    372 	case Qndb:
    373 		if(omode & (OWRITE|OTRUNC) && !iseve())
    374 			error(Eperm);
    375 		if((omode & (OWRITE|OTRUNC)) == (OWRITE|OTRUNC))
    376 			f->ndb[0] = 0;
    377 		break;
    378 	case Qlog:
    379 		netlogopen(f);
    380 		break;
    381 	case Qiproute:
    382 	case Qarp:
    383 		if(omode != OREAD && !iseve())
    384 			error(Eperm);
    385 		break;
    386 	case Qtopdir:
    387 	case Qprotodir:
    388 	case Qconvdir:
    389 	case Qstatus:
    390 	case Qremote:
    391 	case Qlocal:
    392 	case Qstats:
    393 	case Qbootp:
    394 	case Qipselftab:
    395 		if(omode != OREAD)
    396 			error(Eperm);
    397 		break;
    398 	case Qsnoop:
    399 		if(omode != OREAD)
    400 			error(Eperm);
    401 		p = f->p[PROTO(c->qid)];
    402 		cv = p->conv[CONV(c->qid)];
    403 		if(strcmp(ATTACHER(c), cv->owner) != 0 && !iseve())
    404 			error(Eperm);
    405 		incref(&cv->snoopers);
    406 		break;
    407 	case Qclone:
    408 		p = f->p[PROTO(c->qid)];
    409 		QLOCK(p);
    410 		if(waserror()){
    411 			QUNLOCK(p);
    412 			nexterror();
    413 		}
    414 		cv = Fsprotoclone(p, ATTACHER(c));
    415 		QUNLOCK(p);
    416 		poperror();
    417 		if(cv == nil) {
    418 			error(Enodev);
    419 			break;
    420 		}
    421 		mkqid(&c->qid, QID(p->x, cv->x, Qctl), 0, QTFILE);
    422 		break;
    423 	case Qdata:
    424 	case Qctl:
    425 	case Qerr:
    426 		p = f->p[PROTO(c->qid)];
    427 		QLOCK(p);
    428 		cv = p->conv[CONV(c->qid)];
    429 		QLOCK(cv);
    430 		if(waserror()) {
    431 			QUNLOCK(cv);
    432 			QUNLOCK(p);
    433 			nexterror();
    434 		}
    435 		if((perm & (cv->perm>>6)) != perm) {
    436 			if(strcmp(ATTACHER(c), cv->owner) != 0)
    437 				error(Eperm);
    438 		 	if((perm & cv->perm) != perm)
    439 				error(Eperm);
    440 
    441 		}
    442 		cv->inuse++;
    443 		if(cv->inuse == 1){
    444 			kstrdup(&cv->owner, ATTACHER(c));
    445 			cv->perm = 0660;
    446 		}
    447 		QUNLOCK(cv);
    448 		QUNLOCK(p);
    449 		poperror();
    450 		break;
    451 	case Qlisten:
    452 		cv = f->p[PROTO(c->qid)]->conv[CONV(c->qid)];
    453 		if((perm & (cv->perm>>6)) != perm) {
    454 			if(strcmp(ATTACHER(c), cv->owner) != 0)
    455 				error(Eperm);
    456 		 	if((perm & cv->perm) != perm)
    457 				error(Eperm);
    458 
    459 		}
    460 
    461 		if(cv->state != Announced)
    462 			error("not announced");
    463 
    464 		if(waserror()){
    465 			closeconv(cv);
    466 			nexterror();
    467 		}
    468 		QLOCK(cv);
    469 		cv->inuse++;
    470 		QUNLOCK(cv);
    471 
    472 		nc = nil;
    473 		while(nc == nil) {
    474 			/* give up if we got a hangup */
    475 			if(qisclosed(cv->rq))
    476 				error("listen hungup");
    477 
    478 			qlock(&cv->listenq);
    479 			if(waserror()) {
    480 				qunlock(&cv->listenq);
    481 				nexterror();
    482 			}
    483 
    484 			/* wait for a connect */
    485 			sleep(&cv->listenr, incoming, cv);
    486 
    487 			QLOCK(cv);
    488 			nc = cv->incall;
    489 			if(nc != nil){
    490 				cv->incall = nc->next;
    491 				mkqid(&c->qid, QID(PROTO(c->qid), nc->x, Qctl), 0, QTFILE);
    492 				kstrdup(&cv->owner, ATTACHER(c));
    493 			}
    494 			QUNLOCK(cv);
    495 
    496 			qunlock(&cv->listenq);
    497 			poperror();
    498 		}
    499 		closeconv(cv);
    500 		poperror();
    501 		break;
    502 	}
    503 	c->mode = openmode(omode);
    504 	c->flag |= COPEN;
    505 	c->offset = 0;
    506 	return c;
    507 }
    508 
    509 static void
    510 ipcreate(Chan* _, char* __, int ___, ulong ____)
    511 {
    512 	error(Eperm);
    513 }
    514 
    515 static void
    516 ipremove(Chan* _)
    517 {
    518 	error(Eperm);
    519 }
    520 
    521 static int
    522 ipwstat(Chan *c, uchar *dp, int n)
    523 {
    524 	Dir d;
    525 	Conv *cv;
    526 	Fs *f;
    527 	Proto *p;
    528 
    529 	f = ipfs[c->dev];
    530 	switch(TYPE(c->qid)) {
    531 	default:
    532 		error(Eperm);
    533 		break;
    534 	case Qctl:
    535 	case Qdata:
    536 		break;
    537 	}
    538 
    539 	n = convM2D(dp, n, &d, nil);
    540 	if(n > 0){
    541 		p = f->p[PROTO(c->qid)];
    542 		cv = p->conv[CONV(c->qid)];
    543 		if(!iseve() && strcmp(ATTACHER(c), cv->owner) != 0)
    544 			error(Eperm);
    545 		if(d.uid[0])
    546 			kstrdup(&cv->owner, d.uid);
    547 		cv->perm = d.mode & 0777;
    548 	}
    549 	return n;
    550 }
    551 
    552 void
    553 closeconv(Conv *cv)
    554 {
    555 	Conv *nc;
    556 	Ipmulti *mp;
    557 
    558 	QLOCK(cv);
    559 
    560 	if(--cv->inuse > 0) {
    561 		QUNLOCK(cv);
    562 		return;
    563 	}
    564 
    565 	/* close all incoming calls since no listen will ever happen */
    566 	for(nc = cv->incall; nc; nc = cv->incall){
    567 		cv->incall = nc->next;
    568 		closeconv(nc);
    569 	}
    570 	cv->incall = nil;
    571 
    572 	kstrdup(&cv->owner, network);
    573 	cv->perm = 0660;
    574 
    575 	while((mp = cv->multi) != nil)
    576 		ipifcremmulti(cv, mp->ma, mp->ia);
    577 
    578 	cv->r = nil;
    579 	cv->rgen = 0;
    580 	cv->p->close(cv);
    581 	cv->state = Idle;
    582 	QUNLOCK(cv);
    583 }
    584 
    585 static void
    586 ipclose(Chan* c)
    587 {
    588 	Fs *f;
    589 
    590 	f = ipfs[c->dev];
    591 	switch(TYPE(c->qid)) {
    592 	default:
    593 		break;
    594 	case Qlog:
    595 		if(c->flag & COPEN)
    596 			netlogclose(f);
    597 		break;
    598 	case Qdata:
    599 	case Qctl:
    600 	case Qerr:
    601 		if(c->flag & COPEN)
    602 			closeconv(f->p[PROTO(c->qid)]->conv[CONV(c->qid)]);
    603 		break;
    604 	case Qsnoop:
    605 		if(c->flag & COPEN)
    606 			decref(&f->p[PROTO(c->qid)]->conv[CONV(c->qid)]->snoopers);
    607 		break;
    608 	}
    609 	free(((IPaux*)c->aux)->owner);
    610 	free(c->aux);
    611 }
    612 
    613 enum
    614 {
    615 	Statelen=	32*1024,
    616 };
    617 
    618 static long
    619 ipread(Chan *ch, void *a, long n, vlong off)
    620 {
    621 	Conv *c;
    622 	Proto *x;
    623 	char *buf, *p;
    624 	long rv;
    625 	Fs *f;
    626 	ulong offset = off;
    627 
    628 	f = ipfs[ch->dev];
    629 
    630 	p = a;
    631 	switch(TYPE(ch->qid)) {
    632 	default:
    633 		error(Eperm);
    634 	case Qtopdir:
    635 	case Qprotodir:
    636 	case Qconvdir:
    637 		return devdirread(ch, a, n, 0, 0, ipgen);
    638 	case Qarp:
    639 		return arpread(f->arp, a, offset, n);
    640  	case Qbootp:
    641  		return bootpread(a, offset, n);
    642  	case Qndb:
    643 		return readstr(offset, a, n, f->ndb);
    644 	case Qiproute:
    645 		return routeread(f, a, offset, n);
    646 	case Qipselftab:
    647 		return ipselftabread(f, a, offset, n);
    648 	case Qlog:
    649 		return netlogread(f, a, offset, n);
    650 	case Qctl:
    651 		buf = smalloc(16);
    652 		sprint(buf, "%lud", CONV(ch->qid));
    653 		rv = readstr(offset, p, n, buf);
    654 		free(buf);
    655 		return rv;
    656 	case Qremote:
    657 		buf = smalloc(Statelen);
    658 		x = f->p[PROTO(ch->qid)];
    659 		c = x->conv[CONV(ch->qid)];
    660 		if(x->remote == nil) {
    661 			sprint(buf, "%I!%d\n", c->raddr, c->rport);
    662 		} else {
    663 			(*x->remote)(c, buf, Statelen-2);
    664 		}
    665 		rv = readstr(offset, p, n, buf);
    666 		free(buf);
    667 		return rv;
    668 	case Qlocal:
    669 		buf = smalloc(Statelen);
    670 		x = f->p[PROTO(ch->qid)];
    671 		c = x->conv[CONV(ch->qid)];
    672 		if(x->local == nil) {
    673 			sprint(buf, "%I!%d\n", c->laddr, c->lport);
    674 		} else {
    675 			(*x->local)(c, buf, Statelen-2);
    676 		}
    677 		rv = readstr(offset, p, n, buf);
    678 		free(buf);
    679 		return rv;
    680 	case Qstatus:
    681 		buf = smalloc(Statelen);
    682 		x = f->p[PROTO(ch->qid)];
    683 		c = x->conv[CONV(ch->qid)];
    684 		(*x->state)(c, buf, Statelen-2);
    685 		rv = readstr(offset, p, n, buf);
    686 		free(buf);
    687 		return rv;
    688 	case Qdata:
    689 		c = f->p[PROTO(ch->qid)]->conv[CONV(ch->qid)];
    690 		return qread(c->rq, a, n);
    691 	case Qerr:
    692 		c = f->p[PROTO(ch->qid)]->conv[CONV(ch->qid)];
    693 		return qread(c->eq, a, n);
    694 	case Qsnoop:
    695 		c = f->p[PROTO(ch->qid)]->conv[CONV(ch->qid)];
    696 		return qread(c->sq, a, n);
    697 	case Qstats:
    698 		x = f->p[PROTO(ch->qid)];
    699 		if(x->stats == nil)
    700 			error("stats not implemented");
    701 		buf = smalloc(Statelen);
    702 		(*x->stats)(x, buf, Statelen);
    703 		rv = readstr(offset, p, n, buf);
    704 		free(buf);
    705 		return rv;
    706 	}
    707 }
    708 
    709 static Block*
    710 ipbread(Chan* ch, long n, ulong offset)
    711 {
    712 	Conv *c;
    713 	Proto *x;
    714 	Fs *f;
    715 
    716 	switch(TYPE(ch->qid)){
    717 	case Qdata:
    718 		f = ipfs[ch->dev];
    719 		x = f->p[PROTO(ch->qid)];
    720 		c = x->conv[CONV(ch->qid)];
    721 		return qbread(c->rq, n);
    722 	default:
    723 		return devbread(ch, n, offset);
    724 	}
    725 }
    726 
    727 /*
    728  *  set local address to be that of the ifc closest to remote address
    729  */
    730 static void
    731 setladdr(Conv* c)
    732 {
    733 	findlocalip(c->p->f, c->laddr, c->raddr);
    734 }
    735 
    736 /*
    737  *  set a local port making sure the quad of raddr,rport,laddr,lport is unique
    738  */
    739 char*
    740 setluniqueport(Conv* c, int lport)
    741 {
    742 	Proto *p;
    743 	Conv *xp;
    744 	int x;
    745 
    746 	p = c->p;
    747 
    748 	QLOCK(p);
    749 	for(x = 0; x < p->nc; x++){
    750 		xp = p->conv[x];
    751 		if(xp == nil)
    752 			break;
    753 		if(xp == c)
    754 			continue;
    755 		if((xp->state == Connected || xp->state == Announced)
    756 		&& xp->lport == lport
    757 		&& xp->rport == c->rport
    758 		&& ipcmp(xp->raddr, c->raddr) == 0
    759 		&& ipcmp(xp->laddr, c->laddr) == 0){
    760 			QUNLOCK(p);
    761 			return "address in use";
    762 		}
    763 	}
    764 	c->lport = lport;
    765 	QUNLOCK(p);
    766 	return nil;
    767 }
    768 
    769 /*
    770  * is lport in use by anyone?
    771  */
    772 static int
    773 lportinuse(Proto *p, ushort lport)
    774 {
    775 	int x;
    776 
    777 	for(x = 0; x < p->nc && p->conv[x]; x++)
    778 		if(p->conv[x]->lport == lport)
    779 			return 1;
    780 	return 0;
    781 }
    782 
    783 /*
    784  *  pick a local port and set it
    785  */
    786 char *
    787 setlport(Conv* c)
    788 {
    789 	Proto *p;
    790 	int i, port;
    791 
    792 	p = c->p;
    793 	QLOCK(p);
    794 	if(c->restricted){
    795 		/* Restricted ports cycle between 600 and 1024. */
    796 		for(i=0; i<1024-600; i++){
    797 			if(p->nextrport >= 1024 || p->nextrport < 600)
    798 				p->nextrport = 600;
    799 			port = p->nextrport++;
    800 			if(!lportinuse(p, port))
    801 				goto chosen;
    802 		}
    803 	}else{
    804 		/*
    805 		 * Unrestricted ports are chosen randomly
    806 		 * between 2^15 and 2^16.  There are at most
    807 		 * 4*Nchan = 4096 ports in use at any given time,
    808 		 * so even in the worst case, a random probe has a
    809 		 * 1 - 4096/2^15 = 87% chance of success.
    810 		 * If 64 successive probes fail, there is a bug somewhere
    811 		 * (or a once in 10^58 event has happened, but that's
    812 		 * less likely than a venti collision).
    813 		 */
    814 		for(i=0; i<64; i++){
    815 			port = (1<<15) + nrand(1<<15);
    816 			if(!lportinuse(p, port))
    817 				goto chosen;
    818 		}
    819 	}
    820 	QUNLOCK(p);
    821 	return "no ports available";
    822 
    823 chosen:
    824 	c->lport = port;
    825 	QUNLOCK(p);
    826 	return nil;
    827 }
    828 
    829 /*
    830  *  set a local address and port from a string of the form
    831  *	[address!]port[!r]
    832  */
    833 char*
    834 setladdrport(Conv* c, char* str, int announcing)
    835 {
    836 	char *p;
    837 	char *rv;
    838 	ushort lport;
    839 	uchar addr[IPaddrlen];
    840 
    841 	/*
    842 	 *  ignore restricted part if it exists.  it's
    843 	 *  meaningless on local ports.
    844 	 */
    845 	p = strchr(str, '!');
    846 	if(p != nil){
    847 		*p++ = 0;
    848 		if(strcmp(p, "r") == 0)
    849 			p = nil;
    850 	}
    851 
    852 	c->lport = 0;
    853 	if(p == nil){
    854 		if(announcing)
    855 			ipmove(c->laddr, IPnoaddr);
    856 		else
    857 			setladdr(c);
    858 		p = str;
    859 	} else {
    860 		if(strcmp(str, "*") == 0)
    861 			ipmove(c->laddr, IPnoaddr);
    862 		else {
    863 			if(parseip(addr, str) == -1)
    864 				return Ebadip;
    865 			if(ipforme(c->p->f, addr))
    866 				ipmove(c->laddr, addr);
    867 			else
    868 				return "not a local IP address";
    869 		}
    870 	}
    871 
    872 	/* one process can get all connections */
    873 	if(announcing && strcmp(p, "*") == 0){
    874 		if(!iseve())
    875 			error(Eperm);
    876 		return setluniqueport(c, 0);
    877 	}
    878 
    879 	lport = atoi(p);
    880 	if(lport <= 0)
    881 		rv = setlport(c);
    882 	else
    883 		rv = setluniqueport(c, lport);
    884 	return rv;
    885 }
    886 
    887 static char*
    888 setraddrport(Conv* c, char* str)
    889 {
    890 	char *p;
    891 
    892 	p = strchr(str, '!');
    893 	if(p == nil)
    894 		return "malformed address";
    895 	*p++ = 0;
    896 	if (parseip(c->raddr, str) == -1)
    897 		return Ebadip;
    898 	c->rport = atoi(p);
    899 	p = strchr(p, '!');
    900 	if(p){
    901 		if(strstr(p, "!r") != nil)
    902 			c->restricted = 1;
    903 	}
    904 	return nil;
    905 }
    906 
    907 /*
    908  *  called by protocol connect routine to set addresses
    909  */
    910 char*
    911 Fsstdconnect(Conv *c, char *argv[], int argc)
    912 {
    913 	char *p;
    914 
    915 	switch(argc) {
    916 	default:
    917 		return "bad args to connect";
    918 	case 2:
    919 		p = setraddrport(c, argv[1]);
    920 		if(p != nil)
    921 			return p;
    922 		setladdr(c);
    923 		p = setlport(c);
    924 		if (p != nil)
    925 			return p;
    926 		break;
    927 	case 3:
    928 		p = setraddrport(c, argv[1]);
    929 		if(p != nil)
    930 			return p;
    931 		p = setladdrport(c, argv[2], 0);
    932 		if(p != nil)
    933 			return p;
    934 	}
    935 
    936 	if( (memcmp(c->raddr, v4prefix, IPv4off) == 0 &&
    937 		memcmp(c->laddr, v4prefix, IPv4off) == 0)
    938 		|| ipcmp(c->raddr, IPnoaddr) == 0)
    939 		c->ipversion = V4;
    940 	else
    941 		c->ipversion = V6;
    942 
    943 	return nil;
    944 }
    945 /*
    946  *  initiate connection and sleep till its set up
    947  */
    948 static int
    949 connected(void* a)
    950 {
    951 	return ((Conv*)a)->state == Connected;
    952 }
    953 static void
    954 connectctlmsg(Proto *x, Conv *c, Cmdbuf *cb)
    955 {
    956 	char *p;
    957 
    958 	if(c->state != 0)
    959 		error(Econinuse);
    960 	c->state = Connecting;
    961 	c->cerr[0] = '\0';
    962 	if(x->connect == nil)
    963 		error("connect not supported");
    964 	p = x->connect(c, cb->f, cb->nf);
    965 	if(p != nil)
    966 		error(p);
    967 
    968 	QUNLOCK(c);
    969 	if(waserror()){
    970 		QLOCK(c);
    971 		nexterror();
    972 	}
    973 	sleep(&c->cr, connected, c);
    974 	QLOCK(c);
    975 	poperror();
    976 
    977 	if(c->cerr[0] != '\0')
    978 		error(c->cerr);
    979 }
    980 
    981 /*
    982  *  called by protocol announce routine to set addresses
    983  */
    984 char*
    985 Fsstdannounce(Conv* c, char* argv[], int argc)
    986 {
    987 	memset(c->raddr, 0, sizeof(c->raddr));
    988 	c->rport = 0;
    989 	switch(argc){
    990 	default:
    991 		break;
    992 	case 2:
    993 		return setladdrport(c, argv[1], 1);
    994 	}
    995 	return "bad args to announce";
    996 }
    997 
    998 /*
    999  *  initiate announcement and sleep till its set up
   1000  */
   1001 static int
   1002 announced(void* a)
   1003 {
   1004 	return ((Conv*)a)->state == Announced;
   1005 }
   1006 static void
   1007 announcectlmsg(Proto *x, Conv *c, Cmdbuf *cb)
   1008 {
   1009 	char *p;
   1010 
   1011 	if(c->state != 0)
   1012 		error(Econinuse);
   1013 	c->state = Announcing;
   1014 	c->cerr[0] = '\0';
   1015 	if(x->announce == nil)
   1016 		error("announce not supported");
   1017 	p = x->announce(c, cb->f, cb->nf);
   1018 	if(p != nil)
   1019 		error(p);
   1020 
   1021 	QUNLOCK(c);
   1022 	if(waserror()){
   1023 		QLOCK(c);
   1024 		nexterror();
   1025 	}
   1026 	sleep(&c->cr, announced, c);
   1027 	QLOCK(c);
   1028 	poperror();
   1029 
   1030 	if(c->cerr[0] != '\0')
   1031 		error(c->cerr);
   1032 }
   1033 
   1034 /*
   1035  *  called by protocol bind routine to set addresses
   1036  */
   1037 char*
   1038 Fsstdbind(Conv* c, char* argv[], int argc)
   1039 {
   1040 	switch(argc){
   1041 	default:
   1042 		break;
   1043 	case 2:
   1044 		return setladdrport(c, argv[1], 0);
   1045 	}
   1046 	return "bad args to bind";
   1047 }
   1048 
   1049 static void
   1050 bindctlmsg(Proto *x, Conv *c, Cmdbuf *cb)
   1051 {
   1052 	char *p;
   1053 
   1054 	if(x->bind == nil)
   1055 		p = Fsstdbind(c, cb->f, cb->nf);
   1056 	else
   1057 		p = x->bind(c, cb->f, cb->nf);
   1058 	if(p != nil)
   1059 		error(p);
   1060 }
   1061 
   1062 static void
   1063 tosctlmsg(Conv *c, Cmdbuf *cb)
   1064 {
   1065 	if(cb->nf < 2)
   1066 		c->tos = 0;
   1067 	else
   1068 		c->tos = atoi(cb->f[1]);
   1069 }
   1070 
   1071 static void
   1072 ttlctlmsg(Conv *c, Cmdbuf *cb)
   1073 {
   1074 	if(cb->nf < 2)
   1075 		c->ttl = MAXTTL;
   1076 	else
   1077 		c->ttl = atoi(cb->f[1]);
   1078 }
   1079 
   1080 static long
   1081 ipwrite(Chan* ch, void *v, long n, vlong off)
   1082 {
   1083 	Conv *c;
   1084 	Proto *x;
   1085 	char *p;
   1086 	Cmdbuf *cb;
   1087 	uchar ia[IPaddrlen], ma[IPaddrlen];
   1088 	Fs *f;
   1089 	char *a;
   1090 	ulong offset = off;
   1091 
   1092 	a = v;
   1093 	f = ipfs[ch->dev];
   1094 
   1095 	switch(TYPE(ch->qid)){
   1096 	default:
   1097 		error(Eperm);
   1098 	case Qdata:
   1099 		x = f->p[PROTO(ch->qid)];
   1100 		c = x->conv[CONV(ch->qid)];
   1101 
   1102 		if(c->wq == nil)
   1103 			error(Eperm);
   1104 
   1105 		qwrite(c->wq, a, n);
   1106 		break;
   1107 	case Qarp:
   1108 		return arpwrite(f, a, n);
   1109 	case Qiproute:
   1110 		return routewrite(f, ch, a, n);
   1111 	case Qlog:
   1112 		netlogctl(f, a, n);
   1113 		return n;
   1114 	case Qndb:
   1115 		return ndbwrite(f, a, offset, n);
   1116 		break;
   1117 	case Qctl:
   1118 		x = f->p[PROTO(ch->qid)];
   1119 		c = x->conv[CONV(ch->qid)];
   1120 		cb = parsecmd(a, n);
   1121 
   1122 		QLOCK(c);
   1123 		if(waserror()) {
   1124 			QUNLOCK(c);
   1125 			free(cb);
   1126 			nexterror();
   1127 		}
   1128 		if(cb->nf < 1)
   1129 			error("short control request");
   1130 		if(strcmp(cb->f[0], "connect") == 0)
   1131 			connectctlmsg(x, c, cb);
   1132 		else if(strcmp(cb->f[0], "announce") == 0)
   1133 			announcectlmsg(x, c, cb);
   1134 		else if(strcmp(cb->f[0], "bind") == 0)
   1135 			bindctlmsg(x, c, cb);
   1136 		else if(strcmp(cb->f[0], "ttl") == 0)
   1137 			ttlctlmsg(c, cb);
   1138 		else if(strcmp(cb->f[0], "tos") == 0)
   1139 			tosctlmsg(c, cb);
   1140 		else if(strcmp(cb->f[0], "ignoreadvice") == 0)
   1141 			c->ignoreadvice = 1;
   1142 		else if(strcmp(cb->f[0], "addmulti") == 0){
   1143 			if(cb->nf < 2)
   1144 				error("addmulti needs interface address");
   1145 			if(cb->nf == 2){
   1146 				if(!ipismulticast(c->raddr))
   1147 					error("addmulti for a non multicast address");
   1148 				if (parseip(ia, cb->f[1]) == -1)
   1149 					error(Ebadip);
   1150 				ipifcaddmulti(c, c->raddr, ia);
   1151 			} else {
   1152 				if (parseip(ia, cb->f[1]) == -1 ||
   1153 				    parseip(ma, cb->f[2]) == -1)
   1154 					error(Ebadip);
   1155 				if(!ipismulticast(ma))
   1156 					error("addmulti for a non multicast address");
   1157 				ipifcaddmulti(c, ma, ia);
   1158 			}
   1159 		} else if(strcmp(cb->f[0], "remmulti") == 0){
   1160 			if(cb->nf < 2)
   1161 				error("remmulti needs interface address");
   1162 			if(!ipismulticast(c->raddr))
   1163 				error("remmulti for a non multicast address");
   1164 			if (parseip(ia, cb->f[1]) == -1)
   1165 				error(Ebadip);
   1166 			ipifcremmulti(c, c->raddr, ia);
   1167 		} else if(strcmp(cb->f[0], "maxfragsize") == 0){
   1168 			if(cb->nf < 2)
   1169 				error("maxfragsize needs size");
   1170 
   1171 			c->maxfragsize = (int)strtol(cb->f[1], nil, 0);
   1172 			
   1173 		} else if(x->ctl != nil) {
   1174 			p = x->ctl(c, cb->f, cb->nf);
   1175 			if(p != nil)
   1176 				error(p);
   1177 		} else
   1178 			error("unknown control request");
   1179 		QUNLOCK(c);
   1180 		free(cb);
   1181 		poperror();
   1182 	}
   1183 	return n;
   1184 }
   1185 
   1186 static long
   1187 ipbwrite(Chan* ch, Block* bp, ulong offset)
   1188 {
   1189 	Conv *c;
   1190 	Proto *x;
   1191 	Fs *f;
   1192 	int n;
   1193 
   1194 	switch(TYPE(ch->qid)){
   1195 	case Qdata:
   1196 		f = ipfs[ch->dev];
   1197 		x = f->p[PROTO(ch->qid)];
   1198 		c = x->conv[CONV(ch->qid)];
   1199 
   1200 		if(c->wq == nil)
   1201 			error(Eperm);
   1202 
   1203 		if(bp->next)
   1204 			bp = concatblock(bp);
   1205 		n = BLEN(bp);
   1206 		qbwrite(c->wq, bp);
   1207 		return n;
   1208 	default:
   1209 		return devbwrite(ch, bp, offset);
   1210 	}
   1211 }
   1212 
   1213 Dev ipdevtab = {
   1214 	'I',
   1215 	"ip",
   1216 
   1217 	ipreset,
   1218 	devinit,
   1219 	devshutdown,
   1220 	ipattach,
   1221 	ipwalk,
   1222 	ipstat,
   1223 	ipopen,
   1224 	ipcreate,
   1225 	ipclose,
   1226 	ipread,
   1227 	ipbread,
   1228 	ipwrite,
   1229 	ipbwrite,
   1230 	ipremove,
   1231 	ipwstat,
   1232 };
   1233 
   1234 int
   1235 Fsproto(Fs *f, Proto *p)
   1236 {
   1237 	if(f->np >= Maxproto)
   1238 		return -1;
   1239 
   1240 	p->f = f;
   1241 
   1242 	if(p->ipproto > 0){
   1243 		if(f->t2p[p->ipproto] != nil)
   1244 			return -1;
   1245 		f->t2p[p->ipproto] = p;
   1246 	}
   1247 
   1248 	p->qid.type = QTDIR;
   1249 	p->qid.path = QID(f->np, 0, Qprotodir);
   1250 	p->conv = malloc(sizeof(Conv*)*(p->nc+1));
   1251 	if(p->conv == nil)
   1252 		panic("Fsproto");
   1253 
   1254 	p->x = f->np;
   1255 	p->nextrport = 600;
   1256 	f->p[f->np++] = p;
   1257 
   1258 	return 0;
   1259 }
   1260 
   1261 /*
   1262  *  return true if this protocol is
   1263  *  built in
   1264  */
   1265 int
   1266 Fsbuiltinproto(Fs* f, uchar proto)
   1267 {
   1268 	return f->t2p[proto] != nil;
   1269 }
   1270 
   1271 /*
   1272  *  called with protocol locked
   1273  */
   1274 Conv*
   1275 Fsprotoclone(Proto *p, char *user)
   1276 {
   1277 	Conv *c, **pp, **ep;
   1278 
   1279 retry:
   1280 	c = nil;
   1281 	ep = &p->conv[p->nc];
   1282 	for(pp = p->conv; pp < ep; pp++) {
   1283 		c = *pp;
   1284 		if(c == nil){
   1285 			c = malloc(sizeof(Conv));
   1286 			if(c == nil)
   1287 				error(Enomem);
   1288 			QLOCK(c);
   1289 			c->p = p;
   1290 			c->x = pp - p->conv;
   1291 			if(p->ptclsize != 0){
   1292 				c->ptcl = malloc(p->ptclsize);
   1293 				if(c->ptcl == nil) {
   1294 					free(c);
   1295 					error(Enomem);
   1296 				}
   1297 			}
   1298 			*pp = c;
   1299 			p->ac++;
   1300 			c->eq = qopen(1024, Qmsg, 0, 0);
   1301 			(*p->create)(c);
   1302 			break;
   1303 		}
   1304 		if(CANQLOCK(c)){
   1305 			/*
   1306 			 *  make sure both processes and protocol
   1307 			 *  are done with this Conv
   1308 			 */
   1309 			if(c->inuse == 0 && (p->inuse == nil || (*p->inuse)(c) == 0))
   1310 				break;
   1311 
   1312 			QUNLOCK(c);
   1313 		}
   1314 	}
   1315 	if(pp >= ep) {
   1316 		if(p->gc != nil && (*p->gc)(p))
   1317 			goto retry;
   1318 		return nil;
   1319 	}
   1320 
   1321 	c->inuse = 1;
   1322 	kstrdup(&c->owner, user);
   1323 	c->perm = 0660;
   1324 	c->state = Idle;
   1325 	ipmove(c->laddr, IPnoaddr);
   1326 	ipmove(c->raddr, IPnoaddr);
   1327 	c->r = nil;
   1328 	c->rgen = 0;
   1329 	c->lport = 0;
   1330 	c->rport = 0;
   1331 	c->restricted = 0;
   1332 	c->maxfragsize = 0;
   1333 	c->ttl = MAXTTL;
   1334 	qreopen(c->rq);
   1335 	qreopen(c->wq);
   1336 	qreopen(c->eq);
   1337 
   1338 	QUNLOCK(c);
   1339 	return c;
   1340 }
   1341 
   1342 int
   1343 Fsconnected(Conv* c, char* msg)
   1344 {
   1345 	if(msg != nil && *msg != '\0')
   1346 		strncpy(c->cerr, msg, ERRMAX-1);
   1347 
   1348 	switch(c->state){
   1349 
   1350 	case Announcing:
   1351 		c->state = Announced;
   1352 		break;
   1353 
   1354 	case Connecting:
   1355 		c->state = Connected;
   1356 		break;
   1357 	}
   1358 
   1359 	wakeup(&c->cr);
   1360 	return 0;
   1361 }
   1362 
   1363 Proto*
   1364 Fsrcvpcol(Fs* f, uchar proto)
   1365 {
   1366 	if(f->ipmux)
   1367 		return f->ipmux;
   1368 	else
   1369 		return f->t2p[proto];
   1370 }
   1371 
   1372 Proto*
   1373 Fsrcvpcolx(Fs *f, uchar proto)
   1374 {
   1375 	return f->t2p[proto];
   1376 }
   1377 
   1378 /*
   1379  *  called with protocol locked
   1380  */
   1381 Conv*
   1382 Fsnewcall(Conv *c, uchar *raddr, ushort rport, uchar *laddr, ushort lport, uchar version)
   1383 {
   1384 	Conv *nc;
   1385 	Conv **l;
   1386 	int i;
   1387 
   1388 	QLOCK(c);
   1389 	i = 0;
   1390 	for(l = &c->incall; *l; l = &(*l)->next)
   1391 		i++;
   1392 	if(i >= Maxincall) {
   1393 		QUNLOCK(c);
   1394 		return nil;
   1395 	}
   1396 
   1397 	/* find a free conversation */
   1398 	nc = Fsprotoclone(c->p, network);
   1399 	if(nc == nil) {
   1400 		QUNLOCK(c);
   1401 		return nil;
   1402 	}
   1403 	ipmove(nc->raddr, raddr);
   1404 	nc->rport = rport;
   1405 	ipmove(nc->laddr, laddr);
   1406 	nc->lport = lport;
   1407 	nc->next = nil;
   1408 	*l = nc;
   1409 	nc->state = Connected;
   1410 	nc->ipversion = version;
   1411 
   1412 	QUNLOCK(c);
   1413 
   1414 	wakeup(&c->listenr);
   1415 
   1416 	return nc;
   1417 }
   1418 
   1419 long
   1420 ndbwrite(Fs *f, char *a, ulong off, int n)
   1421 {
   1422 	if(off > strlen(f->ndb))
   1423 		error(Eio);
   1424 	if(off+n >= sizeof(f->ndb))
   1425 		error(Eio);
   1426 	memmove(f->ndb+off, a, n);
   1427 	f->ndb[off+n] = 0;
   1428 	f->ndbvers++;
   1429 	f->ndbmtime = seconds();
   1430 	return n;
   1431 }
   1432 
   1433 ulong
   1434 scalednconv(void)
   1435 {
   1436 	if(cpuserver && conf.npage*BY2PG >= 128*MB)
   1437 		return Nchans*4;
   1438 	return Nchans;
   1439 }