plan 9 kernel history: overview | file list | diff list

1999/1001/port/devsdp.c (diff list | history)

1999/0824/sys/src/9/port/devsdp.c:9,151999/0901/sys/src/9/port/devsdp.c:9,16 (short | long)
1999/0824    
#include	<libcrypt.h> 
 
typedef struct Sdp		Sdp; 
typedef struct Port 	Port; 
1999/0901    
typedef struct Conv 	Conv; 
typedef struct OneWay OneWay; 
1999/0824    
 
enum 
{ 
1999/0824/sys/src/9/port/devsdp.c:20,721999/0901/sys/src/9/port/devsdp.c:21,94
1999/0824    
	Qstats, 
	Qlog, 
 
	Qportdir,			/* directory for a protocol */ 
1999/0901    
	Qconvdir,			/* directory per conversation */ 
1999/0824    
	Qctl, 
	Qdata,				/* reliable control channel */ 
	Qpacket,			/* unreliable packet channel */ 
	Qerr, 
	Qlisten, 
	Qlocal, 
	Qremote, 
	Qstatus, 
 
	MaxQ, 
 
	Maxport=	256,		// power of 2 
1999/0901    
	Maxconv=	256,		// power of 2 
1999/0824    
	Nfs=		4,			// number of file systems 
}; 
 
#define TYPE(x) 	((x).path & 0xff) 
#define PORT(x) 	(((x).path >> 8)&(Maxport-1)) 
1999/0901    
#define CONV(x) 	(((x).path >> 8)&(Maxconv-1)) 
1999/0824    
#define QID(x, y) 	(((x)<<8) | (y)) 
 
struct Port { 
1999/0901    
struct OneWay 
{ 
	ulong	seqwrap;	// number of wraps of the sequence number 
	ulong	seq; 
	ulong	window;		// for replay attacks 
 
	char	*calg; 
	void	*cstate;	// state cipher 
	int		civlen;		// in bytes 
	int		(*cipher)(OneWay*, uchar *buf, int len); 
 
	char	*aalg; 
	void	*astate;	// auth state 
	int		alen;		// auth data length in bytes 
	int		(*auth)(OneWay*, uchar *buf, int len, uchar *hash); 
}; 
 
struct Conv { 
	QLock; 
 
1999/0824    
	int	id; 
	Sdp	*sdp; 
	int	ref; 
	int	closed; 
1999/0901    
 
	Chan chan;	// packet channel 
 
	char	user[NAMELEN];		/* protections */ 
	int	perm; 
	int	inuse; 
	int	length; 
	int	state; 
 
	OneWay	in; 
	OneWay	out; 
1999/0824    
}; 
 
struct Sdp { 
	QLock; 
	Log; 
	int	nport; 
	Port	*port[Maxport]; 
1999/0901    
	int	nconv; 
	Conv	*conv[Maxconv]; 
1999/0824    
}; 
 
static Dirtab sdpdirtab[]={ 
	"ctl",		{Qctl},	0,	0666, 
	"stats",	{Qstats},	0,	0444, 
	"log",		{Qlog},		0,	0666, 
1999/0901    
	"clone",	{Qclone},		0,	0666, 
1999/0824    
}; 
 
static Dirtab portdirtab[]={ 
1999/0901    
static Dirtab convdirtab[]={ 
1999/0824    
	"ctl",		{Qctl},	0,	0666, 
	"data",		{Qdata},	0,	0666, 
	"packet",	{Qpacket},	0,	0666, 
	"listen",	{Qlisten},	0,	0666, 
	"local",	{Qlocal},	0,	0444, 
	"remote",	{Qlocal},	0,	0444, 
	"status",	{Qstatus},	0,	0444, 
}; 
 
1999/0824/sys/src/9/port/devsdp.c:94,991999/0901/sys/src/9/port/devsdp.c:116,122
1999/0824    
static Sdp sdptab[Nfs]; 
 
static int sdpgen(Chan *c, Dirtab*, int, int s, Dir *dp); 
1999/0901    
static Conv *sdpclone(Sdp *sdp); 
1999/0824    
 
static void 
sdpinit(void) 
1999/0824/sys/src/9/port/devsdp.c:107,1141999/0901/sys/src/9/port/devsdp.c:130,137
1999/0824    
		dirtab[TYPE(dt->qid)] = dt; 
	} 
 
	for(i=0; i<nelem(portdirtab); i++) { 
		dt = portdirtab + i; 
1999/0901    
	for(i=0; i<nelem(convdirtab); i++) { 
		dt = convdirtab + i; 
1999/0824    
		dirtab[TYPE(dt->qid)] = dt; 
	} 
} 
1999/0824/sys/src/9/port/devsdp.c:123,1291999/0901/sys/src/9/port/devsdp.c:146,152
1999/0824    
	if(dev<0 || dev >= Nfs) 
		error("bad specification"); 
 
	c = devattach('B', spec); 
1999/0901    
	c = devattach('T', spec); 
1999/0824    
	c->qid = (Qid){QID(0, Qtopdir)|CHDIR, 0}; 
	c->dev = dev; 
 
1999/0824/sys/src/9/port/devsdp.c:139,1451999/0901/sys/src/9/port/devsdp.c:162,168
1999/0824    
		case Qsdpdir: 
			c->qid = (Qid){CHDIR|Qtopdir, 0}; 
			break; 
		case Qportdir: 
1999/0901    
		case Qconvdir: 
1999/0824    
			c->qid = (Qid){CHDIR|Qsdpdir, 0}; 
			break; 
		default: 
1999/0824/sys/src/9/port/devsdp.c:158,1821999/0901/sys/src/9/port/devsdp.c:181,205
1999/0824    
} 
 
static Chan* 
sdpopen(Chan* c, int omode) 
1999/0901    
sdpopen(Chan* ch, int omode) 
1999/0824    
{ 
	int perm; 
	Sdp *sdp; 
1999/0901    
	Conv *c; 
1999/0824    
 
	omode &= 3; 
	perm = m2p[omode]; 
	USED(perm); 
 
	sdp = sdptab + c->dev; 
1999/0901    
	sdp = sdptab + ch->dev; 
1999/0824    
 
	switch(TYPE(c->qid)) { 
1999/0901    
	switch(TYPE(ch->qid)) { 
1999/0824    
	default: 
		break; 
	case Qtopdir: 
	case Qsdpdir: 
	case Qportdir: 
1999/0901    
	case Qconvdir: 
1999/0824    
	case Qstatus: 
	case Qlocal: 
	case Qstats: 
		if(omode != OREAD) 
			error(Eperm); 
1999/0824/sys/src/9/port/devsdp.c:184,1941999/0901/sys/src/9/port/devsdp.c:207,223
1999/0824    
	case Qlog: 
		logopen(sdp); 
		break; 
1999/0901    
	case Qclone: 
		c = sdpclone(sdp); 
		if(c == nil) 
			error(Enodev); 
		ch->qid.path = QID(c->id, Qctl); 
		break; 
1999/0824    
	} 
	c->mode = openmode(omode); 
	c->flag |= COPEN; 
	c->offset = 0; 
	return c; 
1999/0901    
	ch->mode = openmode(omode); 
	ch->flag |= COPEN; 
	ch->offset = 0; 
	return ch; 
1999/0824    
} 
 
static void 
1999/0824/sys/src/9/port/devsdp.c:205,2301999/0901/sys/src/9/port/devsdp.c:234,259
1999/0824    
} 
 
static long 
sdpread(Chan *c, void *a, long n, vlong off) 
1999/0901    
sdpread(Chan *ch, void *a, long n, vlong off) 
1999/0824    
{ 
	char buf[256]; 
	Sdp *sdp = sdptab + c->dev; 
	Port *port; 
1999/0901    
	Sdp *sdp = sdptab + ch->dev; 
	Conv *c; 
1999/0824    
 
	USED(off); 
	switch(TYPE(c->qid)) { 
1999/0901    
	switch(TYPE(ch->qid)) { 
1999/0824    
	default: 
		error(Eperm); 
	case Qtopdir: 
	case Qsdpdir: 
	case Qportdir: 
		return devdirread(c, a, n, 0, 0, sdpgen); 
1999/0901    
	case Qconvdir: 
		return devdirread(ch, a, n, 0, 0, sdpgen); 
1999/0824    
	case Qlog: 
		return logread(sdp, a, off, n); 
	case Qstatus: 
		qlock(sdp); 
		port = sdp->port[PORT(c->qid)]; 
		if(port == 0) 
1999/0901    
		c = sdp->conv[CONV(ch->qid)]; 
		if(c == 0) 
1999/0824    
			strcpy(buf, "unbound\n"); 
		else { 
		} 
1999/0824/sys/src/9/port/devsdp.c:231,2501999/0901/sys/src/9/port/devsdp.c:260,281
1999/0824    
		n = readstr(off, a, n, buf); 
		qunlock(sdp); 
		return n; 
1999/0901    
	case Qctl: 
		sprint(buf, "%lud", CONV(ch->qid)); 
		return readstr(off, a, n, buf); 
1999/0824    
	} 
                 
} 
 
static long 
sdpwrite(Chan *c, void *a, long n, vlong off) 
1999/0901    
sdpwrite(Chan *ch, void *a, long n, vlong off) 
1999/0824    
{ 
	Sdp *sdp = sdptab + c->dev; 
1999/0901    
	Sdp *sdp = sdptab + ch->dev; 
1999/0824    
	Cmdbuf *cb; 
	char *arg0; 
	char *p; 
	 
	USED(off); 
	switch(TYPE(c->qid)) { 
1999/0901    
	switch(TYPE(ch->qid)) { 
1999/0824    
	default: 
		error(Eperm); 
	case Qctl: 
1999/0824/sys/src/9/port/devsdp.c:258,2631999/0901/sys/src/9/port/devsdp.c:289,295
1999/0824    
		if(cb->nf == 0) 
			error("short write"); 
		arg0 = cb->f[0]; 
1999/0901    
print("cmd = %s\n", arg0); 
1999/0824    
		if(strcmp(arg0, "xxx") == 0) { 
			print("xxx\n"); 
		} else 
1999/0824/sys/src/9/port/devsdp.c:309,3281999/0901/sys/src/9/port/devsdp.c:341,401
1999/0824    
			return 1; 
		} 
		s -= nelem(sdpdirtab); 
		if(s >= sdp->nport) 
1999/0901    
		if(s >= sdp->nconv) 
1999/0824    
			return -1; 
		qid = (Qid){QID(s,Qportdir)|CHDIR, 0}; 
1999/0901    
		qid = (Qid){QID(s,Qconvdir)|CHDIR, 0}; 
1999/0824    
		snprint(buf, sizeof(buf), "%d", s); 
		devdir(c, qid, buf, 0, eve, 0555, dp); 
		return 1; 
	case Qportdir: 
		if(s>=nelem(portdirtab)) 
1999/0901    
	case Qconvdir: 
		if(s>=nelem(convdirtab)) 
1999/0824    
			return -1; 
		dt = portdirtab+s; 
		qid = (Qid){QID(PORT(c->qid),TYPE(dt->qid)),0}; 
1999/0901    
		dt = convdirtab+s; 
		qid = (Qid){QID(CONV(c->qid),TYPE(dt->qid)),0}; 
1999/0824    
		devdir(c, qid, dt->name, dt->length, eve, dt->perm, dp); 
		return 1; 
	} 
1999/0901    
} 
 
static Conv* 
sdpclone(Sdp *sdp) 
{ 
	Conv *c, **pp, **ep; 
 
	c = nil; 
	ep = sdp->conv + nelem(sdp->conv); 
	for(pp = sdp->conv; pp < ep; pp++) { 
		c = *pp; 
		if(c == nil){ 
			c = malloc(sizeof(Conv)); 
			if(c == nil) 
				error(Enomem); 
			qlock(c); 
			c->sdp = sdp; 
			c->id = pp - sdp->conv; 
			*pp = c; 
			sdp->nconv++; 
			break; 
		} 
		if(canqlock(c)){ 
			if(c->inuse == 0) 
				break; 
 
			qunlock(c); 
		} 
	} 
 
	if(pp >= ep) { 
		return nil; 
	} 
 
	c->inuse = 1; 
	strncpy(c->user, up->user, sizeof(c->user)); 
	c->perm = 0660; 
	c->state = 0; 
 
	qunlock(c); 
	return c; 
1999/0824    
} 
 
 
1999/0901/sys/src/9/port/devsdp.c:8,161999/0902/sys/src/9/port/devsdp.c:8,17 (short | long)
1999/0824    
 
#include	<libcrypt.h> 
 
typedef struct Sdp		Sdp; 
1999/0901    
typedef struct Conv 	Conv; 
typedef struct OneWay OneWay; 
1999/0902    
typedef struct Sdp Sdp; 
typedef struct Conv Conv; 
typedef struct Out Out; 
typedef struct In In; 
1999/0824    
 
enum 
{ 
1999/0901/sys/src/9/port/devsdp.c:23,301999/0902/sys/src/9/port/devsdp.c:24,31
1999/0824    
 
1999/0901    
	Qconvdir,			/* directory per conversation */ 
1999/0824    
	Qctl, 
	Qdata,				/* reliable control channel */ 
	Qpacket,			/* unreliable packet channel */ 
1999/0902    
	Qdata,				/* unreliable packet channel */ 
	Qcontrol,			/* reliable control channel */ 
1999/0824    
	Qstatus, 
 
	MaxQ, 
1999/0901/sys/src/9/port/devsdp.c:37,751999/0902/sys/src/9/port/devsdp.c:38,109
1999/0901    
#define CONV(x) 	(((x).path >> 8)&(Maxconv-1)) 
1999/0824    
#define QID(x, y) 	(((x)<<8) | (y)) 
 
1999/0901    
struct OneWay 
1999/0902    
struct Out 
1999/0901    
{ 
	ulong	seqwrap;	// number of wraps of the sequence number 
	ulong	seq; 
	ulong	window;		// for replay attacks 
 
	char	*calg; 
	void	*cstate;	// state cipher 
	int		civlen;		// in bytes 
	int		(*cipher)(OneWay*, uchar *buf, int len); 
1999/0902    
	Block	*controlpkt;		// control channel 
	ulong	*controlseq; 
	ulong	controltimeout;		// timeout when it will be resent 
	int		controlretries; 
1999/0901    
 
	char	*aalg; 
	void	*astate;	// auth state 
	int		alen;		// auth data length in bytes 
	int		(*auth)(OneWay*, uchar *buf, int len, uchar *hash); 
1999/0902    
	void	*cipherstate;	// state cipher 
	int		ivlen;			// in bytes 
	int		(*encrypt)(Out*, uchar *buf, int len); 
 
	void	*authstate;		// auth state 
	int		authlen;		// auth data length in bytes 
	int		(*auth)(Out*, uchar *buf, int len); 
 
	void	*compstate; 
	int		(*comp)(Out*, uchar *dst, uchar *src, int n); 
1999/0901    
}; 
 
1999/0902    
struct In 
{ 
	ulong	seqwrap;	// number of wraps of the sequence number 
	ulong	seq; 
	ulong	window; 
 
	Block	*controlpkt; 
	ulong	controlseq; 
 
	void	*cipherstate;	// state cipher 
	int		ivlen;			// in bytes 
	int		(*decrypt)(In*, uchar *buf, int len); 
 
	void	*authstate;		// auth state 
	int		authlen;		// auth data length in bytes 
	int		(*auth)(In*, uchar *buf, int len); 
 
	void	*uncompstate; 
	int		(*uncomp)(In*, uchar *dst, uchar *src, int n); 
}; 
 
enum { 
	CClosed, 
	COpening, 
	COpen, 
	CClosing, 
}; 
 
1999/0901    
struct Conv { 
	QLock; 
                 
1999/0824    
	int	id; 
1999/0902    
	int ref; 
1999/0824    
	Sdp	*sdp; 
1999/0901    
 
	Chan chan;	// packet channel 
1999/0902    
	int state; 
	ulong session; 
1999/0901    
 
1999/0902    
	Chan *chan;	// packet channel 
 
1999/0901    
	char	user[NAMELEN];		/* protections */ 
	int	perm; 
	int	inuse; 
	int	length; 
	int	state; 
 
	OneWay	in; 
	OneWay	out; 
1999/0902    
	In	in; 
	Out	out; 
1999/0824    
}; 
 
struct Sdp { 
1999/0901/sys/src/9/port/devsdp.c:76,821999/0902/sys/src/9/port/devsdp.c:110,116
1999/0824    
	QLock; 
	Log; 
1999/0901    
	int	nconv; 
	Conv	*conv[Maxconv]; 
1999/0902    
	Conv *conv[Maxconv]; 
1999/0824    
}; 
 
static Dirtab sdpdirtab[]={ 
1999/0901/sys/src/9/port/devsdp.c:88,941999/0902/sys/src/9/port/devsdp.c:122,128
1999/0901    
static Dirtab convdirtab[]={ 
1999/0824    
	"ctl",		{Qctl},	0,	0666, 
	"data",		{Qdata},	0,	0666, 
	"packet",	{Qpacket},	0,	0666, 
1999/0902    
	"control",	{Qcontrol},	0,	0666, 
1999/0824    
	"status",	{Qstatus},	0,	0444, 
}; 
 
1999/0901/sys/src/9/port/devsdp.c:199,2051999/0902/sys/src/9/port/devsdp.c:233,238
1999/0824    
	case Qtopdir: 
	case Qsdpdir: 
1999/0901    
	case Qconvdir: 
1999/0824    
	case Qstatus: 
	case Qstats: 
		if(omode != OREAD) 
			error(Eperm); 
1999/0901/sys/src/9/port/devsdp.c:213,2181999/0902/sys/src/9/port/devsdp.c:246,268
1999/0901    
			error(Enodev); 
		ch->qid.path = QID(c->id, Qctl); 
		break; 
1999/0902    
	case Qdata: 
	case Qctl: 
	case Qstatus: 
	case Qcontrol: 
		c = sdp->conv[CONV(ch->qid)]; 
		qlock(c); 
		if(waserror()) { 
			qunlock(c); 
			nexterror(); 
		} 
		if((perm & (c->perm>>6)) != perm) 
		if(strcmp(up->user, c->user) != 0 || (perm & c->perm) != perm) 
				error(Eperm); 
		c->ref++; 
		qunlock(c); 
		poperror(); 
		break; 
1999/0824    
	} 
1999/0901    
	ch->mode = openmode(omode); 
	ch->flag |= COPEN; 
1999/0901/sys/src/9/port/devsdp.c:221,2331999/0902/sys/src/9/port/devsdp.c:271,283
1999/0824    
} 
 
static void 
sdpclose(Chan* c) 
1999/0902    
sdpclose(Chan* ch) 
1999/0824    
{ 
	Sdp *sdp  = sdptab + c->dev; 
1999/0902    
	Sdp *sdp  = sdptab + ch->dev; 
1999/0824    
 
	switch(TYPE(c->qid)) { 
1999/0902    
	switch(TYPE(ch->qid)) { 
1999/0824    
	case Qlog: 
		if(c->flag & COPEN) 
1999/0902    
		if(ch->flag & COPEN) 
1999/0824    
			logclose(sdp); 
		break; 
	} 
1999/0901/sys/src/9/port/devsdp.c:238,2431999/0902/sys/src/9/port/devsdp.c:288,294
1999/0824    
{ 
	char buf[256]; 
1999/0901    
	Sdp *sdp = sdptab + ch->dev; 
1999/0902    
	char *s; 
1999/0901    
	Conv *c; 
1999/0824    
 
	USED(off); 
1999/0901/sys/src/9/port/devsdp.c:251,2641999/0902/sys/src/9/port/devsdp.c:302,327
1999/0824    
	case Qlog: 
		return logread(sdp, a, off, n); 
	case Qstatus: 
		qlock(sdp); 
1999/0901    
		c = sdp->conv[CONV(ch->qid)]; 
		if(c == 0) 
1999/0824    
			strcpy(buf, "unbound\n"); 
		else { 
1999/0902    
		qlock(c); 
		switch(c->state) { 
		default: 
			panic("unknown state"); 
		case CClosed: 
			s = "closed"; 
			break; 
		case COpening: 
			s = "opening"; 
			break; 
		case COpen: 
			s = "open"; 
			break; 
		case CClosing: 
			s = "closing"; 
			break; 
1999/0824    
		} 
		n = readstr(off, a, n, buf); 
		qunlock(sdp); 
1999/0902    
		n = readstr(off, a, n, s); 
		qunlock(c); 
1999/0824    
		return n; 
1999/0901    
	case Qctl: 
		sprint(buf, "%lud", CONV(ch->qid)); 
1999/0901/sys/src/9/port/devsdp.c:364,3691999/0902/sys/src/9/port/devsdp.c:427,437
1999/0901    
 
	c = nil; 
	ep = sdp->conv + nelem(sdp->conv); 
1999/0902    
	qlock(sdp); 
	if(waserror()) { 
		qunlock(sdp); 
		nexterror(); 
	} 
1999/0901    
	for(pp = sdp->conv; pp < ep; pp++) { 
		c = *pp; 
		if(c == nil){ 
1999/0901/sys/src/9/port/devsdp.c:378,4031999/0902/sys/src/9/port/devsdp.c:446,493
1999/0901    
			break; 
		} 
		if(canqlock(c)){ 
			if(c->inuse == 0) 
1999/0902    
			if(c->state == CClosed) 
1999/0901    
				break; 
                 
			qunlock(c); 
		} 
	} 
1999/0902    
	poperror(); 
	qunlock(sdp); 
1999/0901    
 
	if(pp >= ep) { 
1999/0902    
	if(pp >= ep) 
1999/0901    
		return nil; 
	} 
 
	c->inuse = 1; 
1999/0902    
	c->ref++; 
	c->state = COpening; 
 
1999/0901    
	strncpy(c->user, up->user, sizeof(c->user)); 
	c->perm = 0660; 
	c->state = 0; 
                 
	qunlock(c); 
1999/0902    
 
1999/0901    
	return c; 
1999/0824    
} 
 
1999/0902    
static void 
sdpconvfree(Conv *c) 
{ 
	qlock(c); 
	c->ref--; 
	if(c->ref < 0) 
		panic("convfree: bad ref"); 
	if(c->ref > 0) { 
		qunlock(c); 
		return; 
	} 
 
	memset(&c->in, 0, sizeof(c->in)); 
	memset(&c->out, 0, sizeof(c->out)); 
 
	if(c->chan) { 
		cclose(c->chan); 
		c->chan = 0; 
	} 
	qunlock(c); 
} 
1999/0824    
 
Dev sdpdevtab = { 
	'T', 
1999/0902/sys/src/9/port/devsdp.c:12,171999/0906/sys/src/9/port/devsdp.c:12,18 (short | long)
1999/0902    
typedef struct Conv Conv; 
typedef struct Out Out; 
typedef struct In In; 
1999/0906    
typedef struct ConPkt ConPkt; 
1999/0824    
 
enum 
{ 
1999/0902/sys/src/9/port/devsdp.c:32,371999/0906/sys/src/9/port/devsdp.c:33,39
1999/0824    
 
1999/0901    
	Maxconv=	256,		// power of 2 
1999/0824    
	Nfs=		4,			// number of file systems 
1999/0906    
	Maxretries=	4, 
1999/0824    
}; 
 
#define TYPE(x) 	((x).path & 0xff) 
1999/0902/sys/src/9/port/devsdp.c:45,521999/0906/sys/src/9/port/devsdp.c:47,52
1999/0901    
 
1999/0902    
	Block	*controlpkt;		// control channel 
	ulong	*controlseq; 
	ulong	controltimeout;		// timeout when it will be resent 
	int		controlretries; 
1999/0901    
 
1999/0902    
	void	*cipherstate;	// state cipher 
	int		ivlen;			// in bytes 
1999/0902/sys/src/9/port/devsdp.c:82,1071999/0906/sys/src/9/port/devsdp.c:82,119
1999/0902    
}; 
 
enum { 
	CClosed, 
1999/0906    
	CInit, 
1999/0902    
	COpening, 
	COpen, 
	CClosing, 
1999/0906    
	CClosed, 
1999/0902    
}; 
 
1999/0901    
struct Conv { 
	QLock; 
1999/0824    
	int	id; 
1999/0902    
	int ref; 
1999/0906    
	int ref;	// number of times the conv is opened 
1999/0824    
	Sdp	*sdp; 
1999/0901    
 
1999/0902    
	int state; 
	ulong session; 
1999/0906    
	int dataopen; 
1999/0901    
 
1999/0906    
	Proc *readproc; 
 
	ulong	timeout; 
	int		retries; 
 
	// the following pair uniquely define conversation on this port 
	ulong dialid; 
	ulong acceptid; 
 
1999/0902    
	Chan *chan;	// packet channel 
 
1999/0901    
	char	user[NAMELEN];		/* protections */ 
	int	perm; 
 
1999/0906    
	int drop; 
 
1999/0902    
	In	in; 
	Out	out; 
1999/0824    
}; 
1999/0902/sys/src/9/port/devsdp.c:109,1181999/0906/sys/src/9/port/devsdp.c:121,158
1999/0824    
struct Sdp { 
	QLock; 
	Log; 
1999/0906    
	Rendez	vous;			/* used by sdpackproc */ 
1999/0901    
	int	nconv; 
1999/0902    
	Conv *conv[Maxconv]; 
1999/0906    
	int ackproc; 
1999/0824    
}; 
 
1999/0906    
enum { 
	TConnect, 
	TControl, 
	TControlAck, 
	TData, 
	TThwackC, 
	TThwackU, 
}; 
 
enum { 
	ConOpen, 
	ConOpenAck, 
	ConOpenNack, 
	ConClose, 
	ConCloseAck, 
}; 
 
struct ConPkt 
{ 
	uchar type;		// always zero = connection packet 
	uchar op; 
	uchar pad[2]; 
	uchar dialid[4]; 
	uchar acceptid[4]; 
}; 
 
1999/0824    
static Dirtab sdpdirtab[]={ 
	"stats",	{Qstats},	0,	0444, 
	"log",		{Qlog},		0,	0666, 
1999/0902/sys/src/9/port/devsdp.c:151,1561999/0906/sys/src/9/port/devsdp.c:191,199
1999/0824    
 
static int sdpgen(Chan *c, Dirtab*, int, int s, Dir *dp); 
1999/0901    
static Conv *sdpclone(Sdp *sdp); 
1999/0906    
static void convsetstate(Conv *c, int state); 
static void sendconnect(Conv *c, int op, ulong dialid, ulong acceptid); 
static void sdpackproc(void *a); 
1999/0824    
 
static void 
sdpinit(void) 
1999/0902/sys/src/9/port/devsdp.c:168,1731999/0906/sys/src/9/port/devsdp.c:211,217
1999/0901    
		dt = convdirtab + i; 
1999/0824    
		dirtab[TYPE(dt->qid)] = dt; 
	} 
1999/0906    
 
1999/0824    
} 
 
static Chan* 
1999/0902/sys/src/9/port/devsdp.c:175,1801999/0906/sys/src/9/port/devsdp.c:219,227
1999/0824    
{ 
	Chan *c; 
	int dev; 
1999/0906    
	char buf[100]; 
	Sdp *sdp; 
	int start; 
1999/0824    
 
	dev = atoi(spec); 
	if(dev<0 || dev >= Nfs) 
1999/0902/sys/src/9/port/devsdp.c:184,1891999/0906/sys/src/9/port/devsdp.c:231,247
1999/0824    
	c->qid = (Qid){QID(0, Qtopdir)|CHDIR, 0}; 
	c->dev = dev; 
 
1999/0906    
	sdp = sdptab + dev; 
	qlock(sdp); 
	start = sdp->ackproc == 0; 
	sdp->ackproc = 1; 
	qunlock(sdp); 
 
	if(start) { 
		snprint(buf, sizeof(buf), "sdpackproc%d", dev); 
		kproc(buf, sdpackproc, sdp); 
	} 
	 
1999/0824    
	return c; 
} 
 
1999/0902/sys/src/9/port/devsdp.c:336,3411999/0906/sys/src/9/port/devsdp.c:394,400
1999/0824    
	Cmdbuf *cb; 
	char *arg0; 
	char *p; 
1999/0906    
	Conv *c; 
1999/0824    
	 
	USED(off); 
1999/0901    
	switch(TYPE(ch->qid)) { 
1999/0902/sys/src/9/port/devsdp.c:342,3511999/0906/sys/src/9/port/devsdp.c:401,412
1999/0824    
	default: 
		error(Eperm); 
	case Qctl: 
1999/0906    
		c = sdp->conv[CONV(ch->qid)]; 
print("Qctl write : conv->id = %d\n", c->id); 
1999/0824    
		cb = parsecmd(a, n); 
		qlock(sdp); 
1999/0906    
		qlock(c); 
1999/0824    
		if(waserror()) { 
			qunlock(sdp); 
1999/0906    
			qunlock(c); 
1999/0824    
			free(cb); 
			nexterror(); 
		} 
1999/0902/sys/src/9/port/devsdp.c:353,3641999/0906/sys/src/9/port/devsdp.c:414,442
1999/0824    
			error("short write"); 
		arg0 = cb->f[0]; 
1999/0901    
print("cmd = %s\n", arg0); 
1999/0824    
		if(strcmp(arg0, "xxx") == 0) { 
			print("xxx\n"); 
1999/0906    
		if(strcmp(arg0, "chan") == 0) { 
			if(cb->nf != 2) 
				error("usage: chan file"); 
			if(c->chan != nil) 
				error("chan already set"); 
			c->chan = namec(cb->f[1], Aopen, ORDWR, 0); 
		} else if(strcmp(arg0, "accept") == 0) { 
			if(cb->nf != 2) 
				error("usage: accect id"); 
			c->dialid = atoi(cb->f[1]); 
			convsetstate(c, COpen); 
		} else if(strcmp(arg0, "dial") == 0) { 
			if(cb->nf != 1) 
				error("usage: dial"); 
			convsetstate(c, COpening); 
		} else if(strcmp(arg0, "drop") == 0) { 
			if(cb->nf != 2) 
				error("usage: drop permil"); 
			c->drop = atoi(cb->f[1]); 
1999/0824    
		} else 
			error("unknown control request"); 
		poperror(); 
		qunlock(sdp); 
1999/0906    
		qunlock(c); 
1999/0824    
		free(cb); 
		return n; 
	case Qlog: 
1999/0902/sys/src/9/port/devsdp.c:458,4641999/0906/sys/src/9/port/devsdp.c:536,542
1999/0901    
		return nil; 
 
1999/0902    
	c->ref++; 
	c->state = COpening; 
1999/0906    
	c->state = CInit; 
1999/0902    
 
1999/0901    
	strncpy(c->user, up->user, sizeof(c->user)); 
	c->perm = 0660; 
1999/0902/sys/src/9/port/devsdp.c:467,4921999/0906/sys/src/9/port/devsdp.c:545,614
1999/0901    
	return c; 
1999/0824    
} 
 
1999/0906    
// assume c is locked 
static int 
convretry(Conv *c) 
{ 
	c->retries++; 
	if(c->retries > Maxretries) { 
print("convretry: giving up\n"); 
		convsetstate(c, CClosed); 
		return 0; 
	} 
	c->timeout = TK2SEC(m->ticks) + (1<<c->retries); 
	return 1; 
} 
 
1999/0902    
static void 
sdpconvfree(Conv *c) 
1999/0906    
convtimer(Conv *c, ulong sec) 
1999/0902    
{ 
1999/0906    
	if(c->timeout == 0 || c->timeout > sec) 
		return; 
1999/0902    
	qlock(c); 
	c->ref--; 
	if(c->ref < 0) 
		panic("convfree: bad ref"); 
	if(c->ref > 0) { 
1999/0906    
	if(waserror()) { 
1999/0902    
		qunlock(c); 
		return; 
1999/0906    
		nexterror(); 
1999/0902    
	} 
1999/0906    
	switch(c->state) { 
	case COpening: 
print("COpening timeout\n"); 
		if(convretry(c)) 
			sendconnect(c, ConOpen, c->dialid, 0); 
		break; 
	case COpen: 
		// check for control packet 
		break; 
	case CClosing: 
print("CClosing timeout\n"); 
		if(convretry(c)) 
			sendconnect(c, ConClose, c->dialid, c->acceptid); 
		break; 
	} 
	qunlock(c); 
} 
1999/0902    
 
	memset(&c->in, 0, sizeof(c->in)); 
	memset(&c->out, 0, sizeof(c->out)); 
 
	if(c->chan) { 
		cclose(c->chan); 
		c->chan = 0; 
1999/0906    
static void 
sdpackproc(void *a) 
{ 
	Sdp *sdp = a; 
	ulong sec; 
	int i; 
	Conv *c; 
 
	for(;;) { 
		tsleep(&sdp->vous, return0, 0, 1000); 
		sec = TK2SEC(m->ticks); 
		qlock(sdp); 
		for(i=0; i<sdp->nconv; i++) { 
			c = sdp->conv[i]; 
			if(!waserror()) { 
				convtimer(c, sec); 
				poperror(); 
			} 
		} 
		qunlock(sdp); 
1999/0902    
	} 
	qunlock(c); 
} 
1999/0824    
 
Dev sdpdevtab = { 
1999/0902/sys/src/9/port/devsdp.c:509,5111999/0906/sys/src/9/port/devsdp.c:631,692
1999/0824    
	devremove, 
	devwstat, 
}; 
1999/0906    
 
// assume hold lock on c 
static void 
convsetstate(Conv *c, int state) 
{ 
	switch(state) { 
	default: 
		panic("setstate: bad state: %d", state); 
	case COpening: 
		if(c->state != CInit) 
			error("convsetstate: illegal transition"); 
		c->dialid = (rand()<<16) + rand(); 
		c->timeout = TK2SEC(m->ticks) + 2; 
		c->retries = 0; 
		sendconnect(c, ConOpen, c->dialid, 0); 
		break; 
	case COpen: 
		switch(c->state) { 
		default: 
			error("convsetstate: illegal transition"); 
		case CInit: 
			c->acceptid = (rand()<<16) + rand(); 
			sendconnect(c, ConOpenAck, c->dialid, c->acceptid); 
			break; 
		case COpening: 
			break; 
		} 
		// setup initial key and auth method 
		break; 
	case CClosing: 
		c->timeout = TK2SEC(m->ticks) + 2; 
		c->retries = 0; 
		break; 
	case CClosed: 
		break; 
	} 
	c->state = state; 
} 
 
static void 
sendconnect(Conv *c, int op, ulong dialid, ulong acceptid) 
{ 
	ConPkt con; 
 
	if(c->chan == nil) { 
print("chan = nil\n"); 
		error("no channel attached"); 
	} 
	memset(&con, 0, sizeof(con)); 
	con.type = TConnect; 
	con.op = op; 
	hnputl(con.dialid, dialid); 
	hnputl(con.acceptid, acceptid); 
 
	// simulated errors 
	if(c->drop && c->drop > nrand(c->drop)) 
		return; 
	devtab[c->chan->type]->write(c->chan, &con, sizeof(con), 0); 
} 
1999/0906/sys/src/9/port/devsdp.c:8,181999/0907/sys/src/9/port/devsdp.c:8,21 (short | long)
1999/0824    
 
#include	<libcrypt.h> 
 
1999/0907    
/* 
 * sdp - secure datagram protocol 
 */ 
 
1999/0902    
typedef struct Sdp Sdp; 
typedef struct Conv Conv; 
typedef struct Out Out; 
typedef struct In In; 
1999/0906    
typedef struct ConPkt ConPkt; 
1999/0907    
typedef struct OneWay OneWay; 
typedef struct ConnectPkt ConnectPkt; 
1999/0824    
 
enum 
{ 
1999/0906/sys/src/9/port/devsdp.c:31,391999/0907/sys/src/9/port/devsdp.c:34,43
1999/0824    
 
	MaxQ, 
 
1999/0901    
	Maxconv=	256,		// power of 2 
1999/0824    
	Nfs=		4,			// number of file systems 
1999/0907    
	Maxconv= 256,		// power of 2 
	Nfs= 4,				// number of file systems 
1999/0906    
	Maxretries=	4, 
1999/0907    
	KeyLength= 32, 
1999/0824    
}; 
 
#define TYPE(x) 	((x).path & 0xff) 
1999/0906/sys/src/9/port/devsdp.c:40,861999/0907/sys/src/9/port/devsdp.c:44,73
1999/0901    
#define CONV(x) 	(((x).path >> 8)&(Maxconv-1)) 
1999/0824    
#define QID(x, y) 	(((x)<<8) | (y)) 
 
1999/0902    
struct Out 
1999/0907    
struct OneWay 
1999/0901    
{ 
	ulong	seqwrap;	// number of wraps of the sequence number 
	ulong	seq; 
1999/0907    
	ulong	window; 
1999/0901    
 
1999/0907    
	Rendez	controlready; 
1999/0902    
	Block	*controlpkt;		// control channel 
	ulong	*controlseq; 
1999/0907    
	ulong	controlseq; 
1999/0901    
 
1999/0902    
	void	*cipherstate;	// state cipher 
	int		ivlen;			// in bytes 
	int		(*encrypt)(Out*, uchar *buf, int len); 
1999/0907    
	int		cipherivlen;	// initial vector length 
	int		cipherblklen;	// block length 
	int		(*cipher)(OneWay*, uchar *buf, int len); 
1999/0902    
 
	void	*authstate;		// auth state 
	int		authlen;		// auth data length in bytes 
	int		(*auth)(Out*, uchar *buf, int len); 
1999/0907    
	int		(*auth)(OneWay*, uchar *buf, int len); 
1999/0902    
 
	void	*compstate; 
	int		(*comp)(Out*, uchar *dst, uchar *src, int n); 
1999/0907    
	int		(*comp)(OneWay*, uchar *dst, uchar *src, int n); 
1999/0901    
}; 
 
1999/0902    
struct In 
{ 
	ulong	seqwrap;	// number of wraps of the sequence number 
	ulong	seq; 
	ulong	window; 
                 
	Block	*controlpkt; 
	ulong	controlseq; 
                 
	void	*cipherstate;	// state cipher 
	int		ivlen;			// in bytes 
	int		(*decrypt)(In*, uchar *buf, int len); 
                 
	void	*authstate;		// auth state 
	int		authlen;		// auth data length in bytes 
	int		(*auth)(In*, uchar *buf, int len); 
                 
	void	*uncompstate; 
	int		(*uncomp)(In*, uchar *dst, uchar *src, int n); 
}; 
                 
1999/0907    
// conv states 
1999/0902    
enum { 
1999/0906    
	CInit, 
1999/0902    
	COpening, 
1999/0906/sys/src/9/port/devsdp.c:98,1041999/0907/sys/src/9/port/devsdp.c:85,90
1999/0902    
	int state; 
1999/0906    
	int dataopen; 
1999/0901    
 
1999/0906    
	Proc *readproc; 
 
	ulong	timeout; 
	int		retries; 
1999/0906/sys/src/9/port/devsdp.c:107,1211999/0907/sys/src/9/port/devsdp.c:93,111
1999/0906    
	ulong dialid; 
	ulong acceptid; 
 
1999/0907    
	Proc *readproc; 
	QLock readlk; 
1999/0902    
	Chan *chan;	// packet channel 
 
1999/0901    
	char	user[NAMELEN];		/* protections */ 
1999/0907    
	char owner[NAMELEN];		/* protections */ 
1999/0901    
	int	perm; 
 
1999/0907    
	uchar	masterkey[KeyLength]; 
 
1999/0906    
	int drop; 
 
1999/0902    
	In	in; 
	Out	out; 
1999/0907    
	OneWay	in; 
	OneWay	out; 
1999/0824    
}; 
 
struct Sdp { 
1999/0906/sys/src/9/port/devsdp.c:144,1501999/0907/sys/src/9/port/devsdp.c:134,140
1999/0906    
	ConCloseAck, 
}; 
 
struct ConPkt 
1999/0907    
struct ConnectPkt 
1999/0906    
{ 
	uchar type;		// always zero = connection packet 
	uchar op; 
1999/0906/sys/src/9/port/devsdp.c:153,1581999/0907/sys/src/9/port/devsdp.c:143,149
1999/0906    
	uchar acceptid[4]; 
}; 
 
1999/0907    
 
1999/0824    
static Dirtab sdpdirtab[]={ 
	"stats",	{Qstats},	0,	0444, 
	"log",		{Qlog},		0,	0666, 
1999/0906/sys/src/9/port/devsdp.c:192,2001999/0907/sys/src/9/port/devsdp.c:183,200
1999/0824    
static int sdpgen(Chan *c, Dirtab*, int, int s, Dir *dp); 
1999/0901    
static Conv *sdpclone(Sdp *sdp); 
1999/0906    
static void convsetstate(Conv *c, int state); 
static void sendconnect(Conv *c, int op, ulong dialid, ulong acceptid); 
static void sdpackproc(void *a); 
1999/0907    
static void onewaycleanup(OneWay *ow); 
static int readready(void *a); 
static int controlread(); 
static Block *conviput(Conv *c, Block *b, int control); 
static void conviput2(Conv *c, Block *b); 
static Block *readcontrol(Conv *c, int n); 
static Block *readdata(Conv *c, int n); 
static void convoput(Conv *c, int type, Block *b); 
static void convoput2(Conv *c, int op, ulong dialid, ulong acceptid); 
1999/0824    
 
1999/0907    
 
1999/0824    
static void 
sdpinit(void) 
{ 
1999/0906/sys/src/9/port/devsdp.c:315,3231999/0907/sys/src/9/port/devsdp.c:315,325
1999/0902    
			nexterror(); 
		} 
		if((perm & (c->perm>>6)) != perm) 
		if(strcmp(up->user, c->user) != 0 || (perm & c->perm) != perm) 
1999/0907    
		if(strcmp(up->user, c->owner) != 0 || (perm & c->perm) != perm) 
1999/0902    
				error(Eperm); 
		c->ref++; 
1999/0907    
		if(TYPE(ch->qid) == Qdata) 
			c->dataopen++; 
1999/0902    
		qunlock(c); 
		poperror(); 
		break; 
1999/0906/sys/src/9/port/devsdp.c:332,3371999/0907/sys/src/9/port/devsdp.c:334,340
1999/0902    
sdpclose(Chan* ch) 
1999/0824    
{ 
1999/0902    
	Sdp *sdp  = sdptab + ch->dev; 
1999/0907    
	Conv *c; 
1999/0824    
 
1999/0902    
	switch(TYPE(ch->qid)) { 
1999/0824    
	case Qlog: 
1999/0906/sys/src/9/port/devsdp.c:338,3431999/0907/sys/src/9/port/devsdp.c:341,380
1999/0902    
		if(ch->flag & COPEN) 
1999/0824    
			logclose(sdp); 
		break; 
1999/0907    
	case Qdata: 
	case Qctl: 
	case Qstatus: 
	case Qcontrol: 
		if(!(ch->flag & COPEN)) 
			break; 
		c = sdp->conv[CONV(ch->qid)]; 
		qlock(c); 
		if(waserror()) { 
			qunlock(c); 
			nexterror(); 
		} 
		c->ref--; 
		if(TYPE(ch->qid) == Qdata) { 
			c->dataopen--; 
			if(c->dataopen == 0) 
				wakeup(&c->in.controlready); 
		} 
 
		if(c->ref == 0) { 
			switch(c->state) { 
			default: 
				convsetstate(c, CClosed); 
				break; 
			case COpen: 
				convsetstate(c, CClosing); 
				break; 
			case CClosing: 
				break; 
			} 
		} 
		qunlock(c); 
		poperror(); 
		break; 
1999/0824    
	} 
} 
 
1999/0906/sys/src/9/port/devsdp.c:348,3531999/0907/sys/src/9/port/devsdp.c:385,391
1999/0901    
	Sdp *sdp = sdptab + ch->dev; 
1999/0902    
	char *s; 
1999/0901    
	Conv *c; 
1999/0907    
	Block *b; 
1999/0824    
 
	USED(off); 
1999/0901    
	switch(TYPE(ch->qid)) { 
1999/0906/sys/src/9/port/devsdp.c:384,3921999/0907/sys/src/9/port/devsdp.c:422,458
1999/0901    
	case Qctl: 
		sprint(buf, "%lud", CONV(ch->qid)); 
		return readstr(off, a, n, buf); 
1999/0907    
	case Qcontrol: 
		b = readcontrol(sdp->conv[CONV(ch->qid)], n); 
		if(b == nil) 
			return 0; 
		if(BLEN(b) < n) 
			n = BLEN(b); 
		memmove(a, b->rp, n); 
		freeb(b); 
		return n; 
	case Qdata: 
		b = readdata(sdp->conv[CONV(ch->qid)], n); 
		if(b == nil) 
			return 0; 
		if(BLEN(b) < n) 
			n = BLEN(b); 
		memmove(a, b->rp, n); 
		freeb(b); 
		return n; 
1999/0824    
	} 
} 
 
1999/0907    
static Block* 
sdpbread(Chan* ch, long n, ulong offset) 
{ 
	Sdp *sdp = sdptab + ch->dev; 
 
	if(TYPE(ch->qid) != Qdata) 
		return devbread(ch, n, offset); 
	return readdata(sdp->conv[CONV(ch->qid)], n); 
} 
 
1999/0824    
static long 
1999/0901    
sdpwrite(Chan *ch, void *a, long n, vlong off) 
1999/0824    
{ 
1999/0906/sys/src/9/port/devsdp.c:538,5441999/0907/sys/src/9/port/devsdp.c:604,610
1999/0902    
	c->ref++; 
1999/0906    
	c->state = CInit; 
1999/0902    
 
1999/0901    
	strncpy(c->user, up->user, sizeof(c->user)); 
1999/0907    
	strncpy(c->owner, up->user, sizeof(c->owner)); 
1999/0901    
	c->perm = 0660; 
	qunlock(c); 
1999/0902    
 
1999/0906/sys/src/9/port/devsdp.c:573,5791999/0907/sys/src/9/port/devsdp.c:639,645
1999/0906    
	case COpening: 
print("COpening timeout\n"); 
		if(convretry(c)) 
			sendconnect(c, ConOpen, c->dialid, 0); 
1999/0907    
			convoput2(c, ConOpen, c->dialid, 0); 
1999/0906    
		break; 
	case COpen: 
		// check for control packet 
1999/0906/sys/src/9/port/devsdp.c:581,5871999/0907/sys/src/9/port/devsdp.c:647,653
1999/0906    
	case CClosing: 
print("CClosing timeout\n"); 
		if(convretry(c)) 
			sendconnect(c, ConClose, c->dialid, c->acceptid); 
1999/0907    
			convoput2(c, ConClose, c->dialid, c->acceptid); 
1999/0906    
		break; 
	} 
	qunlock(c); 
1999/0906/sys/src/9/port/devsdp.c:636,6411999/0907/sys/src/9/port/devsdp.c:702,710
1999/0906    
static void 
convsetstate(Conv *c, int state) 
{ 
1999/0907    
 
print("convsetstate %d -> %d\n", c->state, state); 
 
1999/0906    
	switch(state) { 
	default: 
		panic("setstate: bad state: %d", state); 
1999/0906/sys/src/9/port/devsdp.c:645,6511999/0907/sys/src/9/port/devsdp.c:714,720
1999/0906    
		c->dialid = (rand()<<16) + rand(); 
		c->timeout = TK2SEC(m->ticks) + 2; 
		c->retries = 0; 
		sendconnect(c, ConOpen, c->dialid, 0); 
1999/0907    
		convoput2(c, ConOpen, c->dialid, 0); 
1999/0906    
		break; 
	case COpen: 
		switch(c->state) { 
1999/0906/sys/src/9/port/devsdp.c:653,6591999/0907/sys/src/9/port/devsdp.c:722,728
1999/0906    
			error("convsetstate: illegal transition"); 
		case CInit: 
			c->acceptid = (rand()<<16) + rand(); 
			sendconnect(c, ConOpenAck, c->dialid, c->acceptid); 
1999/0907    
			convoput2(c, ConOpenAck, c->dialid, c->acceptid); 
1999/0906    
			break; 
		case COpening: 
			break; 
1999/0906/sys/src/9/port/devsdp.c:661,6701999/0907/sys/src/9/port/devsdp.c:730,758
1999/0906    
		// setup initial key and auth method 
		break; 
	case CClosing: 
1999/0907    
		convoput2(c, ConClose, c->dialid, c->acceptid); 
1999/0906    
		c->timeout = TK2SEC(m->ticks) + 2; 
		c->retries = 0; 
		break; 
	case CClosed: 
1999/0907    
		if(c->readproc) 
			postnote(c->readproc, 1, "interrupt", 0); 
		if(c->ref) 
			break; 
		if(c->chan) {	 
			cclose(c->chan); 
			c->chan = nil; 
		} 
		strcpy(c->owner, "network"); 
		c->perm = 0660; 
		c->dialid = 0; 
		c->acceptid = 0; 
		c->timeout = 0; 
		c->retries = 0; 
		c->drop = 0; 
		memset(c->masterkey, 0, sizeof(c->masterkey)); 
		onewaycleanup(&c->in); 
		onewaycleanup(&c->out); 
1999/0906    
		break; 
	} 
	c->state = state; 
1999/0906/sys/src/9/port/devsdp.c:671,6801999/0907/sys/src/9/port/devsdp.c:759,960
1999/0906    
} 
 
static void 
sendconnect(Conv *c, int op, ulong dialid, ulong acceptid) 
1999/0907    
onewaycleanup(OneWay *ow) 
1999/0906    
{ 
	ConPkt con; 
1999/0907    
	if(ow->controlpkt) 
		freeb(ow->controlpkt); 
	if(ow->authstate) 
		free(ow->authstate); 
	if(ow->cipherstate) 
		free(ow->cipherstate); 
	if(ow->compstate) 
		free(ow->compstate); 
	memset(ow, 0, sizeof(OneWay)); 
} 
1999/0906    
 
1999/0907    
 
static Block * 
convreadblock(Conv *c, int n) 
{ 
	Block *b; 
 
	qlock(&c->readlk); 
	if(waserror()) { 
		c->readproc = nil; 
		qunlock(&c->readlk); 
		nexterror(); 
	} 
	qlock(c); 
	if(c->state == CClosed) { 
		qunlock(c); 
		poperror(); 
		qunlock(&c->readlk); 
		return 0; 
	} 
	c->readproc = up; 
	qunlock(c); 
 
	b = devtab[c->chan->type]->bread(c->chan, n, 0); 
	c->readproc = nil; 
	poperror(); 
	qunlock(&c->readlk); 
 
	return b; 
} 
 
 
// assume we hold lock for c 
static Block * 
conviput(Conv *c, Block *b, int control) 
{ 
	int type; 
	ulong seq, cseq; 
 
	if(BLEN(b) < 4) { 
		freeb(b); 
		return nil; 
	} 
	 
	type = b->rp[0]; 
	if(type == TConnect) { 
		conviput2(c, b); 
		return nil; 
	} 
 
	seq = (b->rp[1]<<16) + (b->rp[2]<<8) + b->rp[3]; 
	b->rp += 4; 
 
	USED(seq); 
	// auth 
	// decrypt 
 
	// ok the packet is good 
 
	switch(type) { 
	case TControl: 
		if(BLEN(b) <= 4) 
			break; 
		cseq = nhgetl(b->rp); 
		if(cseq == c->in.controlseq) { 
			// duplicate control packet 
			// send ack 
			b->wp = b->rp + 4; 
			convoput(c, TControlAck, b); 
			return nil; 
		} 
 
		if(cseq != c->in.controlseq+1) 
			break; 
	 
		c->in.controlseq = cseq; 
		b->rp += 4; 
		if(control) 
			return b; 
		c->in.controlpkt = b; 
		wakeup(&c->in.controlready); 
		return nil; 
	case TControlAck: 
		if(BLEN(b) != 4) 
			break; 
		cseq = nhgetl(b->rp); 
		if(cseq != c->out.controlseq) 
			break; 
		freeb(b); 
		freeb(c->out.controlpkt); 
		c->out.controlpkt = 0; 
		wakeup(&c->out.controlready); 
		return nil; 
	case TData: 
		if(control) 
			break; 
		return b; 
	} 
print("droping packet %d n=%ld\n", type, BLEN(b)); 
	freeb(b); 
	return nil; 
} 
 
// assume hold conv lock 
static void 
conviput2(Conv *c, Block *b) 
{ 
	ConnectPkt *con; 
	ulong dialid; 
	ulong acceptid; 
 
	if(BLEN(b) != sizeof(ConnectPkt)) { 
		freeb(b); 
		return; 
	} 
	con = (ConnectPkt*)b->rp; 
	dialid = nhgetl(con->dialid); 
	acceptid = nhgetl(con->acceptid); 
 
print("conviput2: %d %uld %uld\n", con->op, dialid, acceptid); 
	switch(con->op) { 
	case ConOpen: 
		if(c->state != COpen || dialid != c->dialid || acceptid != c->acceptid) 
			convoput2(c, ConOpenNack, dialid, acceptid); 
		else 
			convoput2(c, ConOpenAck, dialid, acceptid); 
		break; 
	case ConOpenAck: 
		if(c->state != COpening || dialid != c->dialid) 
			break; 
		c->acceptid = acceptid; 
		convsetstate(c, COpen); 
		break; 
	case ConOpenNack: 
		if(c->state != COpening || dialid != c->dialid) 
			break; 
		convsetstate(c, CClosed); 
		break; 
	case ConClose: 
		if(dialid != c->dialid || acceptid != c->acceptid) 
			break; 
		convsetstate(c, CClosed); 
		break; 
	case ConCloseAck: 
		if(c->state != CClosing || dialid != c->dialid || acceptid != c->acceptid) 
			break; 
		convsetstate(c, CClosed); 
		break; 
	} 
} 
 
// assume hold conv lock 
static void 
convoput(Conv *c, int type, Block *b) 
{ 
	// try and compress 
 
	/* Make space to fit sdp header */ 
	b = padblock(b, 4 + c->out.cipherivlen); 
	b->rp[0] = type; 
	c->out.seq++; 
	if(c->out.seq == (1<<24)) { 
		c->out.seq = 0; 
		c->out.seqwrap++; 
	} 
	b->rp[1] = c->out.seq>>16; 
	b->rp[2] = c->out.seq>>8; 
	b->rp[3] = c->out.seq; 
	 
	// encrypt 
	// auth 
 
	// simulated errors 
	if(c->drop && c->drop > nrand(c->drop)) 
		return; 
	devtab[c->chan->type]->bwrite(c->chan, b, 0); 
} 
 
// assume hold conv lock 
static void 
convoput2(Conv *c, int op, ulong dialid, ulong acceptid) 
{ 
	ConnectPkt con; 
 
1999/0906    
	if(c->chan == nil) { 
print("chan = nil\n"); 
		error("no channel attached"); 
1999/0906/sys/src/9/port/devsdp.c:689,6921999/0907/sys/src/9/port/devsdp.c:969,1052
1999/0906    
	if(c->drop && c->drop > nrand(c->drop)) 
		return; 
	devtab[c->chan->type]->write(c->chan, &con, sizeof(con), 0); 
1999/0907    
} 
 
static int 
readready(void *a) 
{ 
	Conv *c = a; 
 
	return (c->state == CClosed) || c->in.controlpkt != nil || c->dataopen == 0; 
} 
 
static Block * 
readcontrol(Conv *c, int n) 
{ 
	Block *b; 
 
	for(;;) { 
		qlock(c); 
		if(c->state == CClosed || c->state == CInit) { 
			qunlock(c); 
			return nil; 
		} 
 
		if(c->in.controlpkt != nil) { 
			b = c->in.controlpkt; 
			c->in.controlpkt = nil; 
			qunlock(c); 
			return b; 
		} 
		qunlock(c); 
 
		// hack - this is to avoid gating onto the 
		// read which will in general result in excessive 
		// context switches. 
		// The assumed behavior is that the client will read 
		// from the control channel until the session is authenticated 
		// at which point it will open the data channel and 
		// start reading on that.  After the data channel is opened, 
		// read on the channel are required for packets to 
		// be delivered to the control channel 
 
		if(c->dataopen) { 
			sleep(&c->in.controlready, readready, c); 
		} else { 
			b = convreadblock(c, n); 
			if(b == nil) 
				return nil; 
			qlock(c); 
			if(waserror()) { 
				qunlock(c); 
				return nil; 
			} 
			b = conviput(c, b, 1); 
			poperror(); 
			qunlock(c); 
			if(b != nil) 
				return b; 
		} 
	} 
} 
 
static Block * 
readdata(Conv *c, int n) 
{ 
	Block *b; 
 
	for(;;) { 
		b = convreadblock(c, n); 
		if(b == nil) 
			return nil; 
		qlock(c); 
		if(waserror()) { 
			qunlock(c); 
			return nil; 
		} 
		b = conviput(c, b, 0); 
		poperror(); 
		qunlock(c); 
		if(b != nil) 
			return b; 
	} 
1999/0906    
} 
1999/0907/sys/src/9/port/devsdp.c:179,1841999/0908/sys/src/9/port/devsdp.c:179,191 (short | long)
1999/0824    
 
static Dirtab	*dirtab[MaxQ]; 
static Sdp sdptab[Nfs]; 
1999/0908    
static char *convstatename[] = { 
	[CInit] "Init", 
	[COpening] "Opening", 
	[COpen] "Open", 
	[CClosing] "Closing", 
	[CClosed] "Closed", 
}; 
1999/0824    
 
static int sdpgen(Chan *c, Dirtab*, int, int s, Dir *dp); 
1999/0901    
static Conv *sdpclone(Sdp *sdp); 
1999/0907/sys/src/9/port/devsdp.c:318,3231999/0908/sys/src/9/port/devsdp.c:325,331
1999/0907    
		if(strcmp(up->user, c->owner) != 0 || (perm & c->perm) != perm) 
1999/0902    
				error(Eperm); 
		c->ref++; 
1999/0908    
print(c->ref = %d\n", c->ref); 
1999/0907    
		if(TYPE(ch->qid) == Qdata) 
			c->dataopen++; 
1999/0902    
		qunlock(c); 
1999/0907/sys/src/9/port/devsdp.c:359,3651999/0908/sys/src/9/port/devsdp.c:367,373
1999/0907    
			if(c->dataopen == 0) 
				wakeup(&c->in.controlready); 
		} 
                 
1999/0908    
print("close c->ref = %d\n", c->ref); 
1999/0907    
		if(c->ref == 0) { 
			switch(c->state) { 
			default: 
1999/0907/sys/src/9/port/devsdp.c:703,7091999/0908/sys/src/9/port/devsdp.c:711,717
1999/0906    
convsetstate(Conv *c, int state) 
{ 
1999/0907    
 
print("convsetstate %d -> %d\n", c->state, state); 
1999/0908    
print("convsetstate %s -> %s\n", convstatename[c->state], convstatename[state]); 
1999/0907    
 
1999/0906    
	switch(state) { 
	default: 
1999/0908/sys/src/9/port/devsdp.c:36,421999/0909/sys/src/9/port/devsdp.c:36,43 (short | long)
1999/0824    
 
1999/0907    
	Maxconv= 256,		// power of 2 
	Nfs= 4,				// number of file systems 
1999/0906    
	Maxretries=	4, 
1999/0909    
	MaxRetries=	8, 
	KeepAlive = 60,		// keep alive in seconds 
1999/0907    
	KeyLength= 32, 
1999/0824    
}; 
 
1999/0908/sys/src/9/port/devsdp.c:70,761999/0909/sys/src/9/port/devsdp.c:71,78
1999/0907    
// conv states 
1999/0902    
enum { 
1999/0906    
	CInit, 
1999/0902    
	COpening, 
1999/0909    
	CDial, 
	CAccept, 
1999/0902    
	COpen, 
	CClosing, 
1999/0906    
	CClosed, 
1999/0908/sys/src/9/port/devsdp.c:127,1371999/0909/sys/src/9/port/devsdp.c:129,139
1999/0906    
}; 
 
enum { 
	ConOpen, 
1999/0909    
	ConOpenRequest, 
1999/0906    
	ConOpenAck, 
	ConOpenNack, 
	ConClose, 
	ConCloseAck, 
1999/0909    
	ConReset, 
1999/0906    
}; 
 
1999/0907    
struct ConnectPkt 
1999/0908/sys/src/9/port/devsdp.c:181,1871999/0909/sys/src/9/port/devsdp.c:183,190
1999/0824    
static Sdp sdptab[Nfs]; 
1999/0908    
static char *convstatename[] = { 
	[CInit] "Init", 
	[COpening] "Opening", 
1999/0909    
	[CDial] "Dial", 
	[CAccept] "Accept", 
1999/0908    
	[COpen] "Open", 
	[CClosing] "Closing", 
	[CClosed] "Closed", 
1999/0908/sys/src/9/port/devsdp.c:325,3311999/0909/sys/src/9/port/devsdp.c:328,333
1999/0907    
		if(strcmp(up->user, c->owner) != 0 || (perm & c->perm) != perm) 
1999/0902    
				error(Eperm); 
		c->ref++; 
1999/0908    
print(c->ref = %d\n", c->ref); 
1999/0907    
		if(TYPE(ch->qid) == Qdata) 
			c->dataopen++; 
1999/0902    
		qunlock(c); 
1999/0908/sys/src/9/port/devsdp.c:373,3781999/0909/sys/src/9/port/devsdp.c:375,381
1999/0907    
			default: 
				convsetstate(c, CClosed); 
				break; 
1999/0909    
			case CAccept: 
1999/0907    
			case COpen: 
				convsetstate(c, CClosing); 
				break; 
1999/0908/sys/src/9/port/devsdp.c:391,3971999/0909/sys/src/9/port/devsdp.c:394,399
1999/0824    
{ 
	char buf[256]; 
1999/0901    
	Sdp *sdp = sdptab + ch->dev; 
1999/0902    
	char *s; 
1999/0901    
	Conv *c; 
1999/0907    
	Block *b; 
1999/0824    
 
1999/0908/sys/src/9/port/devsdp.c:408,4301999/0909/sys/src/9/port/devsdp.c:410,416
1999/0824    
	case Qstatus: 
1999/0901    
		c = sdp->conv[CONV(ch->qid)]; 
1999/0902    
		qlock(c); 
		switch(c->state) { 
		default: 
			panic("unknown state"); 
		case CClosed: 
			s = "closed"; 
			break; 
		case COpening: 
			s = "opening"; 
			break; 
		case COpen: 
			s = "open"; 
			break; 
		case CClosing: 
			s = "closing"; 
			break; 
1999/0824    
		} 
1999/0902    
		n = readstr(off, a, n, s); 
1999/0909    
		n = readstr(off, a, n, convstatename[c->state]); 
1999/0902    
		qunlock(c); 
1999/0824    
		return n; 
1999/0901    
	case Qctl: 
1999/0908/sys/src/9/port/devsdp.c:498,5081999/0909/sys/src/9/port/devsdp.c:484,494
1999/0906    
			if(cb->nf != 2) 
				error("usage: accect id"); 
			c->dialid = atoi(cb->f[1]); 
			convsetstate(c, COpen); 
1999/0909    
			convsetstate(c, CAccept); 
1999/0906    
		} else if(strcmp(arg0, "dial") == 0) { 
			if(cb->nf != 1) 
				error("usage: dial"); 
			convsetstate(c, COpening); 
1999/0909    
			convsetstate(c, CDial); 
1999/0906    
		} else if(strcmp(arg0, "drop") == 0) { 
			if(cb->nf != 2) 
				error("usage: drop permil"); 
1999/0908/sys/src/9/port/devsdp.c:620,6351999/0909/sys/src/9/port/devsdp.c:606,630
1999/0824    
} 
 
1999/0906    
// assume c is locked 
1999/0909    
static void 
convretryinit(Conv *c) 
{ 
	c->retries = 0; 
	// +2 to avoid rounding effects. 
	c->timeout = TK2SEC(m->ticks) + 2; 
}; 
 
// assume c is locked 
1999/0906    
static int 
convretry(Conv *c) 
{ 
	c->retries++; 
	if(c->retries > Maxretries) { 
1999/0909    
	if(c->retries > MaxRetries) { 
1999/0906    
print("convretry: giving up\n"); 
		convsetstate(c, CClosed); 
		return 0; 
	} 
	c->timeout = TK2SEC(m->ticks) + (1<<c->retries); 
1999/0909    
	c->timeout = TK2SEC(m->ticks) + (c->retries+1); 
1999/0906    
	return 1; 
} 
 
1999/0908/sys/src/9/port/devsdp.c:643,6591999/0909/sys/src/9/port/devsdp.c:638,657
1999/0902    
		qunlock(c); 
1999/0906    
		nexterror(); 
1999/0902    
	} 
1999/0909    
print("convtimer: %s\n", convstatename[c->state]); 
1999/0906    
	switch(c->state) { 
	case COpening: 
print("COpening timeout\n"); 
1999/0909    
	case CDial: 
1999/0906    
		if(convretry(c)) 
1999/0907    
			convoput2(c, ConOpen, c->dialid, 0); 
1999/0909    
			convoput2(c, ConOpenRequest, c->dialid, 0); 
1999/0906    
		break; 
1999/0909    
	case CAccept: 
		if(convretry(c)) 
			convoput2(c, ConOpenAck, c->dialid, c->acceptid); 
		break; 
1999/0906    
	case COpen: 
		// check for control packet 
1999/0909    
		// check for control packet and keepalive 
1999/0906    
		break; 
	case CClosing: 
print("CClosing timeout\n"); 
		if(convretry(c)) 
1999/0907    
			convoput2(c, ConClose, c->dialid, c->acceptid); 
1999/0906    
		break; 
1999/0908/sys/src/9/port/devsdp.c:716,7461999/0909/sys/src/9/port/devsdp.c:714,743
1999/0906    
	switch(state) { 
	default: 
		panic("setstate: bad state: %d", state); 
	case COpening: 
		if(c->state != CInit) 
			error("convsetstate: illegal transition"); 
1999/0909    
	case CDial: 
		assert(c->state == CInit); 
1999/0906    
		c->dialid = (rand()<<16) + rand(); 
		c->timeout = TK2SEC(m->ticks) + 2; 
		c->retries = 0; 
1999/0907    
		convoput2(c, ConOpen, c->dialid, 0); 
1999/0909    
		convretryinit(c); 
		convoput2(c, ConOpenRequest, c->dialid, 0); 
1999/0906    
		break; 
1999/0909    
	case CAccept: 
		assert(c->state == CInit); 
		c->acceptid = (rand()<<16) + rand(); 
		convretryinit(c); 
		convoput2(c, ConOpenAck, c->dialid, c->acceptid); 
		break; 
1999/0906    
	case COpen: 
		switch(c->state) { 
		default: 
			error("convsetstate: illegal transition"); 
		case CInit: 
			c->acceptid = (rand()<<16) + rand(); 
1999/0909    
		assert(c->state == CDial || c->state == CAccept); 
		if(c->state == CDial) { 
			convretryinit(c); 
1999/0907    
			convoput2(c, ConOpenAck, c->dialid, c->acceptid); 
1999/0906    
			break; 
		case COpening: 
			break; 
		} 
		// setup initial key and auth method 
		break; 
	case CClosing: 
1999/0909    
		assert(c->state == COpen); 
		convretryinit(c); 
1999/0907    
		convoput2(c, ConClose, c->dialid, c->acceptid); 
1999/0906    
		c->timeout = TK2SEC(m->ticks) + 2; 
		c->retries = 0; 
		break; 
	case CClosed: 
1999/0907    
		if(c->readproc) 
1999/0908/sys/src/9/port/devsdp.c:900,9311999/0909/sys/src/9/port/devsdp.c:897,955
1999/0907    
 
print("conviput2: %d %uld %uld\n", con->op, dialid, acceptid); 
	switch(con->op) { 
	case ConOpen: 
		if(c->state != COpen || dialid != c->dialid || acceptid != c->acceptid) 
			convoput2(c, ConOpenNack, dialid, acceptid); 
		else 
			convoput2(c, ConOpenAck, dialid, acceptid); 
1999/0909    
	case ConOpenRequest: 
		switch(c->state) { 
		default: 
			convoput2(c, ConReset, dialid, acceptid); 
			break; 
		case CInit: 
			c->dialid = dialid; 
			convsetstate(c, CAccept); 
			break; 
		case CAccept: 
		case COpen: 
			if(dialid != c->dialid || acceptid != c->acceptid) 
				convoput2(c, ConReset, dialid, acceptid); 
			break; 
		} 
1999/0907    
		break; 
	case ConOpenAck: 
		if(c->state != COpening || dialid != c->dialid) 
1999/0909    
		switch(c->state) { 
		case CDial: 
			if(dialid != c->dialid) { 
				convoput2(c, ConReset, dialid, acceptid); 
				break; 
			} 
			c->acceptid = acceptid; 
			convsetstate(c, COpen); 
1999/0907    
			break; 
		c->acceptid = acceptid; 
		convsetstate(c, COpen); 
1999/0909    
		case CAccept: 
			if(dialid != c->dialid || acceptid != c->acceptid) { 
				convoput2(c, ConReset, dialid, acceptid); 
				break; 
			} 
			convsetstate(c, COpen); 
		} 
1999/0907    
		break; 
	case ConOpenNack: 
		if(c->state != COpening || dialid != c->dialid) 
			break; 
		convsetstate(c, CClosed); 
		break; 
	case ConClose: 
		if(dialid != c->dialid || acceptid != c->acceptid) 
1999/0909    
		convoput2(c, ConCloseAck, dialid, acceptid); 
		// fall though 
	case ConReset: 
		switch(c->state) { 
		case CDial: 
			if(dialid == c->dialid) 
				convsetstate(c, CClosed); 
1999/0907    
			break; 
		convsetstate(c, CClosed); 
		break; 
	case ConCloseAck: 
		if(c->state != CClosing || dialid != c->dialid || acceptid != c->acceptid) 
1999/0909    
		case CAccept: 
		case COpen: 
		case CClosing: 
			if(dialid == c->dialid && acceptid == c->acceptid) 
				convsetstate(c, CClosed); 
1999/0907    
			break; 
		convsetstate(c, CClosed); 
1999/0909    
		} 
	case ConCloseAck: 
		if(c->state == CClosing && dialid == c->dialid && acceptid == c->acceptid) 
			convsetstate(c, CClosed); 
1999/0907    
		break; 
	} 
} 
1999/0909/sys/src/9/port/devsdp.c:74,801999/0910/sys/src/9/port/devsdp.c:74,81 (short | long)
1999/0909    
	CDial, 
	CAccept, 
1999/0902    
	COpen, 
	CClosing, 
1999/0910    
	CLocalClose, 
	CRemoteClose, 
1999/0906    
	CClosed, 
1999/0902    
}; 
 
1999/0909/sys/src/9/port/devsdp.c:86,931999/0910/sys/src/9/port/devsdp.c:87,94
1999/0901    
 
1999/0902    
	int state; 
1999/0906    
	int dataopen; 
1999/0910    
	int reader;		// reader proc has been started 
1999/0901    
 
1999/0906    
                 
	ulong	timeout; 
	int		retries; 
 
1999/0909/sys/src/9/port/devsdp.c:95,1031999/0910/sys/src/9/port/devsdp.c:96,106
1999/0906    
	ulong dialid; 
	ulong acceptid; 
 
1999/0910    
	QLock readlk;		// protects readproc 
1999/0907    
	Proc *readproc; 
	QLock readlk; 
1999/0910    
 
1999/0902    
	Chan *chan;	// packet channel 
1999/0910    
	char *channame; 
1999/0902    
 
1999/0907    
	char owner[NAMELEN];		/* protections */ 
1999/0901    
	int	perm; 
1999/0909/sys/src/9/port/devsdp.c:131,1381999/0910/sys/src/9/port/devsdp.c:134,141
1999/0906    
enum { 
1999/0909    
	ConOpenRequest, 
1999/0906    
	ConOpenAck, 
1999/0910    
	ConOpenAckAck, 
1999/0906    
	ConClose, 
	ConCloseAck, 
1999/0909    
	ConReset, 
1999/0906    
}; 
 
1999/0909/sys/src/9/port/devsdp.c:186,1921999/0910/sys/src/9/port/devsdp.c:189,196
1999/0909    
	[CDial] "Dial", 
	[CAccept] "Accept", 
1999/0908    
	[COpen] "Open", 
	[CClosing] "Closing", 
1999/0910    
	[CLocalClose] "LocalClose", 
	[CRemoteClose] "RemoteClose", 
1999/0908    
	[CClosed] "Closed", 
}; 
1999/0824    
 
1999/0909/sys/src/9/port/devsdp.c:203,2081999/0910/sys/src/9/port/devsdp.c:207,213
1999/0907    
static Block *readdata(Conv *c, int n); 
static void convoput(Conv *c, int type, Block *b); 
static void convoput2(Conv *c, int op, ulong dialid, ulong acceptid); 
1999/0910    
static void convreader(void *a); 
1999/0824    
 
1999/0907    
 
1999/0824    
static void 
1999/0909/sys/src/9/port/devsdp.c:328,3351999/0910/sys/src/9/port/devsdp.c:333,344
1999/0907    
		if(strcmp(up->user, c->owner) != 0 || (perm & c->perm) != perm) 
1999/0902    
				error(Eperm); 
		c->ref++; 
1999/0907    
		if(TYPE(ch->qid) == Qdata) 
1999/0910    
		if(TYPE(ch->qid) == Qdata) { 
			if(c->dataopen == 0) 
			if(c->readproc != nil) 
				postnote(c->readproc, 1, "interrupt", 0); 
1999/0907    
			c->dataopen++; 
1999/0910    
		} 
1999/0902    
		qunlock(c); 
		poperror(); 
		break; 
1999/0909/sys/src/9/port/devsdp.c:377,3861999/0910/sys/src/9/port/devsdp.c:386,395
1999/0907    
				break; 
1999/0909    
			case CAccept: 
1999/0907    
			case COpen: 
				convsetstate(c, CClosing); 
1999/0910    
				convsetstate(c, CLocalClose); 
1999/0907    
				break; 
			case CClosing: 
				break; 
1999/0910    
			case CLocalClose: 
				panic("local close already happened"); 
1999/0907    
			} 
		} 
		qunlock(c); 
1999/0909/sys/src/9/port/devsdp.c:474,4931999/0910/sys/src/9/port/devsdp.c:483,504
1999/0824    
			error("short write"); 
		arg0 = cb->f[0]; 
1999/0901    
print("cmd = %s\n", arg0); 
1999/0906    
		if(strcmp(arg0, "chan") == 0) { 
1999/0910    
		if(strcmp(arg0, "accept") == 0) { 
1999/0906    
			if(cb->nf != 2) 
				error("usage: chan file"); 
1999/0910    
				error("usage: accect file"); 
1999/0906    
			if(c->chan != nil) 
				error("chan already set"); 
1999/0910    
				error("already connected"); 
1999/0906    
			c->chan = namec(cb->f[1], Aopen, ORDWR, 0); 
		} else if(strcmp(arg0, "accept") == 0) { 
			if(cb->nf != 2) 
				error("usage: accect id"); 
			c->dialid = atoi(cb->f[1]); 
1999/0909    
			convsetstate(c, CAccept); 
1999/0910    
			c->channame = malloc(strlen(cb->f[1])+1); 
			strcpy(c->channame, cb->f[1]); 
1999/0906    
		} else if(strcmp(arg0, "dial") == 0) { 
			if(cb->nf != 1) 
				error("usage: dial"); 
1999/0910    
			if(cb->nf != 2) 
				error("usage: accect file"); 
			if(c->chan != nil) 
				error("already connected"); 
			c->chan = namec(cb->f[1], Aopen, ORDWR, 0); 
			c->channame = malloc(strlen(cb->f[1])+1); 
			strcpy(c->channame, cb->f[1]); 
1999/0909    
			convsetstate(c, CDial); 
1999/0906    
		} else if(strcmp(arg0, "drop") == 0) { 
			if(cb->nf != 2) 
1999/0909/sys/src/9/port/devsdp.c:584,5901999/0910/sys/src/9/port/devsdp.c:595,601
1999/0901    
			break; 
		} 
		if(canqlock(c)){ 
1999/0902    
			if(c->state == CClosed) 
1999/0910    
			if(c->state == CClosed && c->reader == 0) 
1999/0901    
				break; 
			qunlock(c); 
		} 
1999/0909/sys/src/9/port/devsdp.c:597,6031999/0910/sys/src/9/port/devsdp.c:608,617
1999/0901    
 
1999/0902    
	c->ref++; 
1999/0906    
	c->state = CInit; 
1999/0902    
                 
1999/0910    
	if(!waserror()) { 
		kproc("convreader", convreader, c); 
		c->reader = 1; 
	} 
1999/0907    
	strncpy(c->owner, up->user, sizeof(c->owner)); 
1999/0901    
	c->perm = 0660; 
	qunlock(c); 
1999/0909/sys/src/9/port/devsdp.c:647,6571999/0910/sys/src/9/port/devsdp.c:661,673
1999/0909    
	case CAccept: 
		if(convretry(c)) 
			convoput2(c, ConOpenAck, c->dialid, c->acceptid); 
1999/0910    
		else 
			convoput2(c, ConReset, c->dialid, c->acceptid); 
1999/0909    
		break; 
1999/0906    
	case COpen: 
1999/0909    
		// check for control packet and keepalive 
1999/0906    
		break; 
	case CClosing: 
1999/0910    
	case CLocalClose: 
1999/0906    
		if(convretry(c)) 
1999/0907    
			convoput2(c, ConClose, c->dialid, c->acceptid); 
1999/0906    
		break; 
1999/0909/sys/src/9/port/devsdp.c:730,7441999/0910/sys/src/9/port/devsdp.c:746,763
1999/0909    
		assert(c->state == CDial || c->state == CAccept); 
		if(c->state == CDial) { 
			convretryinit(c); 
1999/0907    
			convoput2(c, ConOpenAck, c->dialid, c->acceptid); 
1999/0910    
			convoput2(c, ConOpenAckAck, c->dialid, c->acceptid); 
1999/0906    
		} 
		// setup initial key and auth method 
		break; 
	case CClosing: 
1999/0909    
		assert(c->state == COpen); 
1999/0910    
	case CLocalClose: 
		assert(c->state == CAccept || c->state == COpen); 
1999/0909    
		convretryinit(c); 
1999/0907    
		convoput2(c, ConClose, c->dialid, c->acceptid); 
1999/0906    
		break; 
1999/0910    
	case CRemoteClose: 
		convoput2(c, ConReset, c->dialid, c->acceptid); 
		break; 
1999/0906    
	case CClosed: 
1999/0907    
		if(c->readproc) 
			postnote(c->readproc, 1, "interrupt", 0); 
1999/0909/sys/src/9/port/devsdp.c:748,7531999/0910/sys/src/9/port/devsdp.c:767,776
1999/0907    
			cclose(c->chan); 
			c->chan = nil; 
		} 
1999/0910    
		if(c->channame) { 
			free(c->channame); 
			c->channame = nil; 
		} 
1999/0907    
		strcpy(c->owner, "network"); 
		c->perm = 0660; 
		c->dialid = 0; 
1999/0909/sys/src/9/port/devsdp.c:778,8131999/0910/sys/src/9/port/devsdp.c:801,808
1999/0907    
} 
1999/0906    
 
1999/0907    
 
static Block * 
convreadblock(Conv *c, int n) 
{ 
	Block *b; 
 
	qlock(&c->readlk); 
	if(waserror()) { 
		c->readproc = nil; 
		qunlock(&c->readlk); 
		nexterror(); 
	} 
	qlock(c); 
	if(c->state == CClosed) { 
		qunlock(c); 
		poperror(); 
		qunlock(&c->readlk); 
		return 0; 
	} 
	c->readproc = up; 
	qunlock(c); 
 
	b = devtab[c->chan->type]->bread(c->chan, n, 0); 
	c->readproc = nil; 
	poperror(); 
	qunlock(&c->readlk); 
                 
	return b; 
} 
                 
                 
// assume we hold lock for c 
static Block * 
conviput(Conv *c, Block *b, int control) 
1999/0909/sys/src/9/port/devsdp.c:853,8601999/0910/sys/src/9/port/devsdp.c:848,853
1999/0907    
	 
		c->in.controlseq = cseq; 
		b->rp += 4; 
		if(control) 
			return b; 
		c->in.controlpkt = b; 
		wakeup(&c->in.controlready); 
		return nil; 
1999/0909/sys/src/9/port/devsdp.c:895,9571999/0910/sys/src/9/port/devsdp.c:888,983
1999/0907    
	dialid = nhgetl(con->dialid); 
	acceptid = nhgetl(con->acceptid); 
 
print("conviput2: %d %uld %uld\n", con->op, dialid, acceptid); 
1999/0910    
	switch(c->state) { 
	default: 
		panic("unknown state: %d", c->state); 
	case CInit: 
		break; 
	case CDial: 
		if(dialid != c->dialid) 
			goto Reset; 
		break; 
	case CAccept: 
	case COpen: 
	case CLocalClose: 
	case CRemoteClose: 
		if(dialid != c->dialid || acceptid != c->acceptid) 
			goto Reset; 
		break; 
	case CClosed: 
		goto Reset; 
	} 
 
 
print("conviput2: %s: %d %uld %uld\n", convstatename[c->state], con->op, dialid, acceptid); 
1999/0907    
	switch(con->op) { 
1999/0909    
	case ConOpenRequest: 
		switch(c->state) { 
		default: 
			convoput2(c, ConReset, dialid, acceptid); 
			break; 
		case CInit: 
			c->dialid = dialid; 
			convsetstate(c, CAccept); 
			break; 
1999/0910    
			return; 
1999/0909    
		case CAccept: 
		case COpen: 
			if(dialid != c->dialid || acceptid != c->acceptid) 
				convoput2(c, ConReset, dialid, acceptid); 
			break; 
1999/0910    
			// duplicate ConOpenRequest that we ignore 
			return; 
1999/0909    
		} 
1999/0907    
		break; 
	case ConOpenAck: 
1999/0909    
		switch(c->state) { 
		case CDial: 
			if(dialid != c->dialid) { 
				convoput2(c, ConReset, dialid, acceptid); 
				break; 
			} 
			c->acceptid = acceptid; 
			convsetstate(c, COpen); 
1999/0907    
			break; 
1999/0910    
			return; 
		case COpen: 
			// duplicate that we have to ack 
			convoput2(c, ConOpenAckAck, acceptid, dialid); 
			return; 
		} 
		break; 
	case ConOpenAckAck: 
		switch(c->state) { 
1999/0909    
		case CAccept: 
			if(dialid != c->dialid || acceptid != c->acceptid) { 
				convoput2(c, ConReset, dialid, acceptid); 
				break; 
			} 
			convsetstate(c, COpen); 
1999/0910    
			return; 
		case COpen: 
			// duplicate that we ignore 
			return; 
1999/0909    
		} 
1999/0907    
		break; 
	case ConClose: 
1999/0909    
		convoput2(c, ConCloseAck, dialid, acceptid); 
		// fall though 
	case ConReset: 
1999/0910    
		convoput2(c, ConReset, dialid, acceptid); 
1999/0909    
		switch(c->state) { 
1999/0910    
		case CInit: 
1999/0909    
		case CDial: 
			if(dialid == c->dialid) 
				convsetstate(c, CClosed); 
1999/0907    
			break; 
1999/0909    
		case CAccept: 
1999/0910    
		case CLocalClose: 
			convsetstate(c, CClosed); 
			return; 
1999/0909    
		case COpen: 
		case CClosing: 
			if(dialid == c->dialid && acceptid == c->acceptid) 
				convsetstate(c, CClosed); 
1999/0907    
			break; 
1999/0910    
			convsetstate(c, CRemoteClose); 
			return; 
		case CRemoteClose: 
			return; 
1999/0909    
		} 
	case ConCloseAck: 
		if(c->state == CClosing && dialid == c->dialid && acceptid == c->acceptid) 
1999/0910    
		return; 
	case ConReset: 
		switch(c->state) { 
		case CInit: 
		case CDial: 
		case CAccept: 
		case COpen: 
		case CLocalClose: 
1999/0909    
			convsetstate(c, CClosed); 
1999/0907    
		break; 
1999/0910    
			return; 
		case CRemoteClose: 
			return; 
		} 
		return; 
1999/0907    
	} 
1999/0910    
Reset: 
	// invalid connection message - reset to sender 
	convoput2(c, ConReset, dialid, acceptid); 
1999/0907    
} 
 
// assume hold conv lock 
1999/0909/sys/src/9/port/devsdp.c:1003,10141999/0910/sys/src/9/port/devsdp.c:1029,1073
1999/0906    
	devtab[c->chan->type]->write(c->chan, &con, sizeof(con), 0); 
1999/0907    
} 
 
1999/0910    
static Block * 
convreadblock(Conv *c, int n) 
{ 
	Block *b; 
	Chan *ch = nil; 
 
	qlock(&c->readlk); 
	if(waserror()) { 
		c->readproc = nil; 
		if(ch) 
			cclose(ch); 
		qunlock(&c->readlk); 
		nexterror(); 
	} 
	qlock(c); 
	if(c->state == CClosed) { 
		qunlock(c); 
		error("closed"); 
	} 
	c->readproc = up; 
	ch = c->chan; 
	incref(ch); 
	qunlock(c); 
 
	b = devtab[ch->type]->bread(ch, n, 0); 
	c->readproc = nil; 
	cclose(ch); 
	poperror(); 
	qunlock(&c->readlk); 
 
	return b; 
} 
 
1999/0907    
static int 
readready(void *a) 
{ 
	Conv *c = a; 
 
	return (c->state == CClosed) || c->in.controlpkt != nil || c->dataopen == 0; 
1999/0910    
	return (c->state == CClosed) || c->in.controlpkt != nil; 
1999/0907    
} 
 
static Block * 
1999/0909/sys/src/9/port/devsdp.c:1016,10241999/0910/sys/src/9/port/devsdp.c:1075,1084
1999/0907    
{ 
	Block *b; 
 
1999/0910    
	USED(n); 
1999/0907    
	for(;;) { 
		qlock(c); 
		if(c->state == CClosed || c->state == CInit) { 
1999/0910    
		if(c->state == CInit || c->state == CClosed) { 
1999/0907    
			qunlock(c); 
			return nil; 
		} 
1999/0909/sys/src/9/port/devsdp.c:1031,10641999/0910/sys/src/9/port/devsdp.c:1091,1099
1999/0907    
		} 
		qunlock(c); 
 
		// hack - this is to avoid gating onto the 
		// read which will in general result in excessive 
		// context switches. 
		// The assumed behavior is that the client will read 
		// from the control channel until the session is authenticated 
		// at which point it will open the data channel and 
		// start reading on that.  After the data channel is opened, 
		// read on the channel are required for packets to 
		// be delivered to the control channel 
                 
		if(c->dataopen) { 
			sleep(&c->in.controlready, readready, c); 
		} else { 
			b = convreadblock(c, n); 
			if(b == nil) 
				return nil; 
			qlock(c); 
			if(waserror()) { 
				qunlock(c); 
				return nil; 
			} 
			b = conviput(c, b, 1); 
			poperror(); 
			qunlock(c); 
			if(b != nil) 
				return b; 
		} 
1999/0910    
		sleep(&c->in.controlready, readready, c); 
1999/0907    
	} 
1999/0910    
	return 0; 
1999/0907    
} 
 
static Block * 
1999/0909/sys/src/9/port/devsdp.c:1068,10751999/0910/sys/src/9/port/devsdp.c:1103,1108
1999/0907    
 
	for(;;) { 
		b = convreadblock(c, n); 
		if(b == nil) 
			return nil; 
		qlock(c); 
		if(waserror()) { 
			qunlock(c); 
1999/0909/sys/src/9/port/devsdp.c:1081,10841999/0910/sys/src/9/port/devsdp.c:1114,1147
1999/0907    
		if(b != nil) 
			return b; 
	} 
1999/0910    
} 
 
static void 
convreader(void *a) 
{ 
	Conv *c = a; 
	Block *b; 
 
	qlock(c); 
	assert(c->reader == 1); 
	while(c->dataopen == 0) { 
		qunlock(c); 
		b = nil; 
		if(!waserror()) { 
			b = convreadblock(c, 2000); 
			poperror(); 
		} 
		qlock(c); 
		if(b == nil) { 
			convsetstate(c, CClosed); 
			break; 
		} 
		if(!waserror()) { 
			conviput(c, b, 1); 
			poperror(); 
		} 
	} 
	c->reader = 0; 
	qunlock(c); 
	pexit("hangup", 1); 
1999/0906    
} 
1999/0910/sys/src/9/port/devsdp.c:36,421999/0914/sys/src/9/port/devsdp.c:36,42 (short | long)
1999/0824    
 
1999/0907    
	Maxconv= 256,		// power of 2 
	Nfs= 4,				// number of file systems 
1999/0909    
	MaxRetries=	8, 
1999/0914    
	MaxRetries=	4, 
1999/0909    
	KeepAlive = 60,		// keep alive in seconds 
1999/0907    
	KeyLength= 32, 
1999/0824    
}; 
1999/0910/sys/src/9/port/devsdp.c:203,2131999/0914/sys/src/9/port/devsdp.c:203,215
1999/0907    
static int controlread(); 
static Block *conviput(Conv *c, Block *b, int control); 
static void conviput2(Conv *c, Block *b); 
1999/0914    
static void writecontrol(Conv *c, void *p, int n); 
1999/0907    
static Block *readcontrol(Conv *c, int n); 
static Block *readdata(Conv *c, int n); 
static void convoput(Conv *c, int type, Block *b); 
static void convoput2(Conv *c, int op, ulong dialid, ulong acceptid); 
1999/0910    
static void convreader(void *a); 
1999/0914    
static void convopenchan(Conv *c, char *path); 
1999/0824    
 
1999/0907    
 
1999/0824    
static void 
1999/0910/sys/src/9/port/devsdp.c:378,3841999/0914/sys/src/9/port/devsdp.c:380,385
1999/0907    
			if(c->dataopen == 0) 
				wakeup(&c->in.controlready); 
		} 
1999/0908    
print("close c->ref = %d\n", c->ref); 
1999/0907    
		if(c->ref == 0) { 
			switch(c->state) { 
			default: 
1999/0910/sys/src/9/port/devsdp.c:429,4341999/0914/sys/src/9/port/devsdp.c:430,436
1999/0907    
		b = readcontrol(sdp->conv[CONV(ch->qid)], n); 
		if(b == nil) 
			return 0; 
1999/0914    
print("readcontrol asked %ld got %ld\n", n, BLEN(b)); 
1999/0907    
		if(BLEN(b) < n) 
			n = BLEN(b); 
		memmove(a, b->rp, n); 
1999/0910/sys/src/9/port/devsdp.c:435,4401999/0914/sys/src/9/port/devsdp.c:437,443
1999/0907    
		freeb(b); 
		return n; 
	case Qdata: 
1999/0914    
print("readdata\n"); 
1999/0907    
		b = readdata(sdp->conv[CONV(ch->qid)], n); 
		if(b == nil) 
			return 0; 
1999/0910/sys/src/9/port/devsdp.c:456,4611999/0914/sys/src/9/port/devsdp.c:459,465
1999/0907    
	return readdata(sdp->conv[CONV(ch->qid)], n); 
} 
 
1999/0914    
 
1999/0824    
static long 
1999/0901    
sdpwrite(Chan *ch, void *a, long n, vlong off) 
1999/0824    
{ 
1999/0910/sys/src/9/port/devsdp.c:471,4771999/0914/sys/src/9/port/devsdp.c:475,480
1999/0824    
		error(Eperm); 
	case Qctl: 
1999/0906    
		c = sdp->conv[CONV(ch->qid)]; 
print("Qctl write : conv->id = %d\n", c->id); 
1999/0824    
		cb = parsecmd(a, n); 
1999/0906    
		qlock(c); 
1999/0824    
		if(waserror()) { 
1999/0910/sys/src/9/port/devsdp.c:482,5041999/0914/sys/src/9/port/devsdp.c:485,498
1999/0824    
		if(cb->nf == 0) 
			error("short write"); 
		arg0 = cb->f[0]; 
1999/0901    
print("cmd = %s\n", arg0); 
1999/0910    
		if(strcmp(arg0, "accept") == 0) { 
1999/0906    
			if(cb->nf != 2) 
1999/0910    
				error("usage: accect file"); 
1999/0906    
			if(c->chan != nil) 
1999/0910    
				error("already connected"); 
1999/0906    
			c->chan = namec(cb->f[1], Aopen, ORDWR, 0); 
1999/0910    
			c->channame = malloc(strlen(cb->f[1])+1); 
			strcpy(c->channame, cb->f[1]); 
1999/0914    
			convopenchan(c, cb->f[1]); 
1999/0906    
		} else if(strcmp(arg0, "dial") == 0) { 
1999/0910    
			if(cb->nf != 2) 
				error("usage: accect file"); 
			if(c->chan != nil) 
				error("already connected"); 
			c->chan = namec(cb->f[1], Aopen, ORDWR, 0); 
			c->channame = malloc(strlen(cb->f[1])+1); 
			strcpy(c->channame, cb->f[1]); 
1999/0914    
			convopenchan(c, cb->f[1]); 
1999/0909    
			convsetstate(c, CDial); 
1999/0906    
		} else if(strcmp(arg0, "drop") == 0) { 
			if(cb->nf != 2) 
1999/0910/sys/src/9/port/devsdp.c:517,5221999/0914/sys/src/9/port/devsdp.c:511,520
1999/0824    
		if(p != nil) 
			error(p); 
		return n; 
1999/0914    
	case Qcontrol: 
print("writecontrol %ld\n", n); 
		writecontrol(sdp->conv[CONV(ch->qid)], a, n); 
		return n; 
1999/0824    
	} 
} 
 
1999/0910/sys/src/9/port/devsdp.c:608,6171999/0914/sys/src/9/port/devsdp.c:606,611
1999/0901    
 
1999/0902    
	c->ref++; 
1999/0906    
	c->state = CInit; 
1999/0910    
	if(!waserror()) { 
		kproc("convreader", convreader, c); 
		c->reader = 1; 
	} 
1999/0907    
	strncpy(c->owner, up->user, sizeof(c->owner)); 
1999/0901    
	c->perm = 0660; 
	qunlock(c); 
1999/0910/sys/src/9/port/devsdp.c:630,6401999/0914/sys/src/9/port/devsdp.c:624,637
1999/0909    
 
// assume c is locked 
1999/0906    
static int 
convretry(Conv *c) 
1999/0914    
convretry(Conv *c, int reset) 
1999/0906    
{ 
	c->retries++; 
1999/0914    
print("convretry: %s: %d\n", convstatename[c->state], c->retries); 
1999/0909    
	if(c->retries > MaxRetries) { 
1999/0906    
print("convretry: giving up\n"); 
1999/0914    
		if(reset) 
			convoput2(c, ConReset, c->dialid, c->acceptid); 
1999/0906    
		convsetstate(c, CClosed); 
		return 0; 
	} 
1999/0910/sys/src/9/port/devsdp.c:645,6501999/0914/sys/src/9/port/devsdp.c:642,649
1999/0902    
static void 
1999/0906    
convtimer(Conv *c, ulong sec) 
1999/0902    
{ 
1999/0914    
	Block *b; 
 
1999/0906    
	if(c->timeout == 0 || c->timeout > sec) 
		return; 
1999/0902    
	qlock(c); 
1999/0910/sys/src/9/port/devsdp.c:652,6771999/0914/sys/src/9/port/devsdp.c:651,685
1999/0902    
		qunlock(c); 
1999/0906    
		nexterror(); 
1999/0902    
	} 
1999/0909    
print("convtimer: %s\n", convstatename[c->state]); 
1999/0906    
	switch(c->state) { 
1999/0909    
	case CDial: 
1999/0906    
		if(convretry(c)) 
1999/0914    
		if(convretry(c, 1)) 
1999/0909    
			convoput2(c, ConOpenRequest, c->dialid, 0); 
1999/0906    
		break; 
1999/0909    
	case CAccept: 
		if(convretry(c)) 
1999/0914    
		if(convretry(c, 1)) 
1999/0909    
			convoput2(c, ConOpenAck, c->dialid, c->acceptid); 
1999/0910    
		else 
			convoput2(c, ConReset, c->dialid, c->acceptid); 
1999/0909    
		break; 
1999/0906    
	case COpen: 
1999/0909    
		// check for control packet and keepalive 
1999/0914    
		b = c->out.controlpkt; 
		if(b != nil) { 
			if(convretry(c, 1)) 
				convoput(c, TControl, copyblock(b, blocklen(b))); 
		} else { 
			c->timeout = 0; 
		} 
		// keepalive 
1999/0906    
		break; 
1999/0910    
	case CLocalClose: 
1999/0906    
		if(convretry(c)) 
1999/0914    
		if(convretry(c, 0)) 
1999/0907    
			convoput2(c, ConClose, c->dialid, c->acceptid); 
1999/0906    
		break; 
1999/0914    
	case CRemoteClose: 
	case CClosed: 
		c->timeout = 0; 
		break; 
1999/0906    
	} 
1999/0914    
	poperror(); 
1999/0906    
	qunlock(c); 
} 
1999/0902    
 
1999/0910/sys/src/9/port/devsdp.c:756,7641999/0914/sys/src/9/port/devsdp.c:764,774
1999/0907    
		convoput2(c, ConClose, c->dialid, c->acceptid); 
1999/0906    
		break; 
1999/0910    
	case CRemoteClose: 
1999/0914    
		wakeup(&c->in.controlready); 
1999/0910    
		convoput2(c, ConReset, c->dialid, c->acceptid); 
		break; 
1999/0906    
	case CClosed: 
1999/0914    
		wakeup(&c->in.controlready); 
1999/0907    
		if(c->readproc) 
			postnote(c->readproc, 1, "interrupt", 0); 
		if(c->ref) 
1999/0910/sys/src/9/port/devsdp.c:801,8061999/0914/sys/src/9/port/devsdp.c:811,836
1999/0907    
} 
1999/0906    
 
1999/0907    
 
1999/0914    
// assumes conv is locked 
static void 
convopenchan(Conv *c, char *path) 
{ 
	if(c->chan != nil) 
		error("already connected"); 
	c->chan = namec(path, Aopen, ORDWR, 0); 
	c->channame = malloc(strlen(path)+1); 
	strcpy(c->channame, path); 
	if(waserror()) { 
		cclose(c->chan); 
		c->chan = nil; 
		free(c->channame); 
		c->channame = nil; 
		nexterror(); 
	} 
	kproc("convreader", convreader, c); 
	c->reader = 1; 
	poperror(); 
} 
1999/0907    
 
 
// assume we hold lock for c 
1999/0910/sys/src/9/port/devsdp.c:825,8301999/0914/sys/src/9/port/devsdp.c:855,861
1999/0907    
	b->rp += 4; 
 
	USED(seq); 
1999/0914    
print("coniput seq=%ulx\n", seq); 
1999/0907    
	// auth 
	// decrypt 
 
1999/0910/sys/src/9/port/devsdp.c:836,8541999/0914/sys/src/9/port/devsdp.c:867,889
1999/0907    
			break; 
		cseq = nhgetl(b->rp); 
		if(cseq == c->in.controlseq) { 
1999/0914    
print("duplicate control packet: %ulx\n", cseq); 
1999/0907    
			// duplicate control packet 
			// send ack 
			b->wp = b->rp + 4; 
			convoput(c, TControlAck, b); 
1999/0914    
			if(c->in.controlpkt == nil) { 
				// send ack 
				b->wp = b->rp + 4; 
				convoput(c, TControlAck, b); 
			} else 
				freeb(b); 
1999/0907    
			return nil; 
		} 
 
		if(cseq != c->in.controlseq+1) 
			break; 
	                 
		c->in.controlseq = cseq; 
		b->rp += 4; 
		c->in.controlpkt = b; 
1999/0914    
print("recv %ld size=%ld\n", cseq, BLEN(b)); 
1999/0907    
		wakeup(&c->in.controlready); 
		return nil; 
	case TControlAck: 
1999/0910/sys/src/9/port/devsdp.c:855,8651999/0914/sys/src/9/port/devsdp.c:890,901
1999/0907    
		if(BLEN(b) != 4) 
			break; 
		cseq = nhgetl(b->rp); 
1999/0914    
print("ControlAck expected %ulx got %ulx\n", c->out.controlseq, cseq); 
1999/0907    
		if(cseq != c->out.controlseq) 
			break; 
		freeb(b); 
		freeb(c->out.controlpkt); 
		c->out.controlpkt = 0; 
1999/0914    
		c->out.controlpkt = nil; 
1999/0907    
		wakeup(&c->out.controlready); 
		return nil; 
	case TData: 
1999/0910/sys/src/9/port/devsdp.c:888,8931999/0914/sys/src/9/port/devsdp.c:924,931
1999/0907    
	dialid = nhgetl(con->dialid); 
	acceptid = nhgetl(con->acceptid); 
 
1999/0914    
print("conviput2: %s: %d %uld %uld\n", convstatename[c->state], con->op, dialid, acceptid); 
 
1999/0910    
	switch(c->state) { 
	default: 
		panic("unknown state: %d", c->state); 
1999/0910/sys/src/9/port/devsdp.c:909,9151999/0914/sys/src/9/port/devsdp.c:947,952
1999/0910    
	} 
 
 
print("conviput2: %s: %d %uld %uld\n", convstatename[c->state], con->op, dialid, acceptid); 
1999/0907    
	switch(con->op) { 
1999/0909    
	case ConOpenRequest: 
		switch(c->state) { 
1999/0910/sys/src/9/port/devsdp.c:977,9821999/0914/sys/src/9/port/devsdp.c:1014,1020
1999/0907    
	} 
1999/0910    
Reset: 
	// invalid connection message - reset to sender 
1999/0914    
print("invalid conviput2 - sending reset\n"); 
1999/0910    
	convoput2(c, ConReset, dialid, acceptid); 
1999/0907    
} 
 
1999/0910/sys/src/9/port/devsdp.c:1067,10731999/0914/sys/src/9/port/devsdp.c:1105,1111
1999/0907    
{ 
	Conv *c = a; 
 
1999/0910    
	return (c->state == CClosed) || c->in.controlpkt != nil; 
1999/0914    
	return c->in.controlpkt != nil || (c->state == CClosed) || (c->state == CRemoteClose); 
1999/0907    
} 
 
static Block * 
1999/0910/sys/src/9/port/devsdp.c:1076,11011999/0914/sys/src/9/port/devsdp.c:1114,1193
1999/0907    
	Block *b; 
 
1999/0910    
	USED(n); 
1999/0914    
	qlock(c); 
1999/0907    
	for(;;) { 
		qlock(c); 
1999/0910    
		if(c->state == CInit || c->state == CClosed) { 
1999/0907    
			qunlock(c); 
			return nil; 
1999/0914    
print("readcontrol: return error - state = %s\n", convstatename[c->state]); 
			error("conversation closed"); 
1999/0907    
		} 
 
		if(c->in.controlpkt != nil) { 
			b = c->in.controlpkt; 
			c->in.controlpkt = nil; 
1999/0914    
		if(c->in.controlpkt != nil) 
			break; 
 
		if(c->state == CRemoteClose) { 
1999/0907    
			qunlock(c); 
			return b; 
1999/0914    
print("readcontrol: return nil - state = %s\n", convstatename[c->state]); 
			return nil; 
1999/0907    
		} 
		qunlock(c); 
                 
1999/0910    
		sleep(&c->in.controlready, readready, c); 
1999/0914    
		qlock(c); 
1999/0907    
	} 
1999/0910    
	return 0; 
1999/0914    
 
	// send ack 
	b = allocb(4); 
	hnputl(b->wp, c->in.controlseq); 
	b->wp += 4;	 
	convoput(c, TControlAck, b); 
 
	b = c->in.controlpkt; 
	c->in.controlpkt = nil; 
	qunlock(c); 
	return b; 
1999/0907    
} 
 
1999/0914    
 
static int 
writeready(void *a) 
{ 
	Conv *c = a; 
 
	return c->out.controlpkt == nil || (c->state == CClosed) || (c->state == CRemoteClose); 
} 
 
static void 
writecontrol(Conv *c, void *p, int n) 
{ 
	Block *b; 
 
	qlock(c); 
	for(;;) { 
		if(c->state == CInit || c->state == CClosed || c->state == CRemoteClose) { 
			qunlock(c); 
print("writecontrol: return error - state = %s\n", convstatename[c->state]); 
			error("conversation closed"); 
		} 
 
		if(c->state == COpen && c->out.controlpkt == nil) 
			break; 
 
		qunlock(c); 
		sleep(&c->out.controlready, writeready, c); 
		qlock(c); 
	} 
	b = allocb(4+n); 
	c->out.controlseq++; 
	hnputl(b->wp, c->out.controlseq); 
	memmove(b->wp+4, p, n); 
	b->wp += 4+n; 
	c->out.controlpkt = b; 
	convretryinit(c); 
print("send %ld size=%ld\n", c->out.controlseq, BLEN(b));	 
	convoput(c, TControl, copyblock(b, blocklen(b))); 
	qunlock(c); 
} 
 
1999/0907    
static Block * 
readdata(Conv *c, int n) 
{ 
1999/0910/sys/src/9/port/devsdp.c:1122,11271999/0914/sys/src/9/port/devsdp.c:1214,1220
1999/0910    
	Conv *c = a; 
	Block *b; 
 
1999/0914    
print("convreader\n"); 
1999/0910    
	qlock(c); 
	assert(c->reader == 1); 
	while(c->dataopen == 0) { 
1999/0910/sys/src/9/port/devsdp.c:1141,11461999/0914/sys/src/9/port/devsdp.c:1234,1240
1999/0910    
			poperror(); 
		} 
	} 
1999/0914    
print("convreader exiting\n"); 
1999/0910    
	c->reader = 0; 
	qunlock(c); 
	pexit("hangup", 1); 
1999/0914/sys/src/9/port/devsdp.c:51,561999/0915/sys/src/9/port/devsdp.c:51,57 (short | long)
1999/0901    
	ulong	seq; 
1999/0907    
	ulong	window; 
1999/0901    
 
1999/0915    
	QLock	controllk; 
1999/0907    
	Rendez	controlready; 
1999/0902    
	Block	*controlpkt;		// control channel 
1999/0907    
	ulong	controlseq; 
1999/0914/sys/src/9/port/devsdp.c:206,2111999/0915/sys/src/9/port/devsdp.c:207,213
1999/0914    
static void writecontrol(Conv *c, void *p, int n); 
1999/0907    
static Block *readcontrol(Conv *c, int n); 
static Block *readdata(Conv *c, int n); 
1999/0915    
static long writedata(Conv *c, Block *b); 
1999/0907    
static void convoput(Conv *c, int type, Block *b); 
static void convoput2(Conv *c, int op, ulong dialid, ulong acceptid); 
1999/0910    
static void convreader(void *a); 
1999/0914/sys/src/9/port/devsdp.c:377,3841999/0915/sys/src/9/port/devsdp.c:379,388
1999/0907    
		c->ref--; 
		if(TYPE(ch->qid) == Qdata) { 
			c->dataopen--; 
			if(c->dataopen == 0) 
				wakeup(&c->in.controlready); 
1999/0915    
			if(c->dataopen == 0 && c->reader == 0) { 
				kproc("convreader", convreader, c); 
				c->reader = 1; 
			} 
1999/0907    
		} 
		if(c->ref == 0) { 
			switch(c->state) { 
1999/0914/sys/src/9/port/devsdp.c:468,4731999/0915/sys/src/9/port/devsdp.c:472,478
1999/0824    
	char *arg0; 
	char *p; 
1999/0906    
	Conv *c; 
1999/0915    
	Block *b; 
1999/0824    
	 
	USED(off); 
1999/0901    
	switch(TYPE(ch->qid)) { 
1999/0914/sys/src/9/port/devsdp.c:515,5231999/0915/sys/src/9/port/devsdp.c:520,543
1999/0914    
print("writecontrol %ld\n", n); 
		writecontrol(sdp->conv[CONV(ch->qid)], a, n); 
		return n; 
1999/0915    
	case Qdata: 
		b = allocb(n); 
		memmove(b->wp, a, n); 
		b->wp += n; 
		return writedata(sdp->conv[CONV(ch->qid)], b); 
1999/0824    
	} 
} 
 
1999/0915    
long 
sdpbwrite(Chan *ch, Block *bp, ulong offset) 
{ 
	Sdp *sdp = sdptab + ch->dev; 
 
	if(TYPE(ch->qid) != Qdata) 
		return devbwrite(ch, bp, offset); 
	return writedata(sdp->conv[CONV(ch->qid)], bp); 
} 
 
1999/0824    
static int 
sdpgen(Chan *c, Dirtab*, int, int s, Dir *dp) 
{ 
1999/0914/sys/src/9/port/devsdp.c:769,7821999/0915/sys/src/9/port/devsdp.c:789,804
1999/0910    
		break; 
1999/0906    
	case CClosed: 
1999/0914    
		wakeup(&c->in.controlready); 
1999/0915    
		wakeup(&c->out.controlready); 
1999/0907    
		if(c->readproc) 
			postnote(c->readproc, 1, "interrupt", 0); 
		if(c->ref) 
			break; 
1999/0915    
print("CClosed -> ref = %d\n", c->ref); 
1999/0907    
		if(c->chan) {	 
			cclose(c->chan); 
			c->chan = nil; 
		} 
1999/0915    
		if(c->ref) 
			break; 
1999/0910    
		if(c->channame) { 
			free(c->channame); 
			c->channame = nil; 
1999/0914/sys/src/9/port/devsdp.c:815,8211999/0915/sys/src/9/port/devsdp.c:837,843
1999/0914    
static void 
convopenchan(Conv *c, char *path) 
{ 
	if(c->chan != nil) 
1999/0915    
	if(c->state != CInit || c->chan != nil) 
1999/0914    
		error("already connected"); 
	c->chan = namec(path, Aopen, ORDWR, 0); 
	c->channame = malloc(strlen(path)+1); 
1999/0914/sys/src/9/port/devsdp.c:1042,10471999/0915/sys/src/9/port/devsdp.c:1064,1070
1999/0907    
	// simulated errors 
	if(c->drop && c->drop > nrand(c->drop)) 
		return; 
1999/0915    
print("convoput\n"); 
1999/0907    
	devtab[c->chan->type]->bwrite(c->chan, b, 0); 
} 
 
1999/0914/sys/src/9/port/devsdp.c:1114,11201999/0915/sys/src/9/port/devsdp.c:1137,1150
1999/0907    
	Block *b; 
 
1999/0910    
	USED(n); 
1999/0914    
	qlock(c); 
1999/0915    
 
	qlock(&c->in.controllk); 
	if(waserror()) { 
		qunlock(&c->in.controllk); 
		nexterror(); 
	} 
	qlock(c);	// this lock is not held during the sleep below 
 
1999/0907    
	for(;;) { 
1999/0910    
		if(c->state == CInit || c->state == CClosed) { 
1999/0907    
			qunlock(c); 
1999/0914/sys/src/9/port/devsdp.c:1128,11331999/0915/sys/src/9/port/devsdp.c:1158,1164
1999/0914    
		if(c->state == CRemoteClose) { 
1999/0907    
			qunlock(c); 
1999/0914    
print("readcontrol: return nil - state = %s\n", convstatename[c->state]); 
1999/0915    
			poperror(); 
1999/0914    
			return nil; 
1999/0907    
		} 
		qunlock(c); 
1999/0914/sys/src/9/port/devsdp.c:1144,11491999/0915/sys/src/9/port/devsdp.c:1175,1182
1999/0914    
	b = c->in.controlpkt; 
	c->in.controlpkt = nil; 
	qunlock(c); 
1999/0915    
	poperror(); 
	qunlock(&c->in.controllk); 
1999/0914    
	return b; 
1999/0907    
} 
 
1999/0914/sys/src/9/port/devsdp.c:1161,11671999/0915/sys/src/9/port/devsdp.c:1194,1206
1999/0914    
{ 
	Block *b; 
 
	qlock(c); 
1999/0915    
 
	qlock(&c->out.controllk); 
	if(waserror()) { 
		qunlock(&c->out.controllk); 
		nexterror(); 
	} 
	qlock(c);	// this lock is not held in the sleep below 
1999/0914    
	for(;;) { 
		if(c->state == CInit || c->state == CClosed || c->state == CRemoteClose) { 
			qunlock(c); 
1999/0914/sys/src/9/port/devsdp.c:1186,11911999/0915/sys/src/9/port/devsdp.c:1225,1232
1999/0914    
print("send %ld size=%ld\n", c->out.controlseq, BLEN(b));	 
	convoput(c, TControl, copyblock(b, blocklen(b))); 
	qunlock(c); 
1999/0915    
	poperror(); 
	qunlock(&c->out.controllk); 
1999/0914    
} 
 
1999/0907    
static Block * 
1999/0914/sys/src/9/port/devsdp.c:1208,12131999/0915/sys/src/9/port/devsdp.c:1249,1278
1999/0907    
	} 
1999/0910    
} 
 
1999/0915    
static long 
writedata(Conv *c, Block *b) 
{ 
	int n; 
 
	qlock(c); 
print("writedata %ulx state=%s\n", b, convstatename[c->state]); 
	if(waserror()) { 
		qunlock(c); 
		nexterror(); 
	} 
 
	if(c->state != COpen) { 
		freeb(b); 
		error("conversation not open"); 
	} 
 
	n = BLEN(b); 
	convoput(c, TData, b); 
	poperror(); 
	qunlock(c); 
	return n; 
} 
 
1999/0910    
static void 
convreader(void *a) 
{ 
1999/0914/sys/src/9/port/devsdp.c:1217,12231999/0915/sys/src/9/port/devsdp.c:1282,1288
1999/0914    
print("convreader\n"); 
1999/0910    
	qlock(c); 
	assert(c->reader == 1); 
	while(c->dataopen == 0) { 
1999/0915    
	while(c->dataopen == 0 && c->state != CClosed) { 
1999/0910    
		qunlock(c); 
		b = nil; 
		if(!waserror()) { 
1999/0914/sys/src/9/port/devsdp.c:1226,12351999/0915/sys/src/9/port/devsdp.c:1291,1305
1999/0910    
		} 
		qlock(c); 
		if(b == nil) { 
			convsetstate(c, CClosed); 
			break; 
		} 
		if(!waserror()) { 
1999/0915    
print("up->error = %s\n", up->error); 
			if(strcmp(up->error, Eintr) != 0) { 
				if(!waserror()) { 
					convsetstate(c, CClosed); 
					poperror(); 
				} 
				break; 
			} 
		} else if(!waserror()) { 
1999/0910    
			conviput(c, b, 1); 
			poperror(); 
		} 
1999/0915/sys/src/9/port/devsdp.c:15,211999/0929/sys/src/9/port/devsdp.c:15,23 (short | long)
1999/0902    
typedef struct Sdp Sdp; 
typedef struct Conv Conv; 
1999/0907    
typedef struct OneWay OneWay; 
1999/0929    
typedef struct Stats Stats; 
1999/0907    
typedef struct ConnectPkt ConnectPkt; 
1999/0929    
typedef struct AckPkt AckPkt; 
1999/0824    
 
enum 
{ 
1999/0915/sys/src/9/port/devsdp.c:23,291999/0929/sys/src/9/port/devsdp.c:25,30
1999/0824    
 
	Qsdpdir,			/* sdp directory */ 
	Qclone, 
	Qstats, 
	Qlog, 
 
1999/0901    
	Qconvdir,			/* directory per conversation */ 
1999/0915/sys/src/9/port/devsdp.c:31,361999/0929/sys/src/9/port/devsdp.c:32,39
1999/0902    
	Qdata,				/* unreliable packet channel */ 
	Qcontrol,			/* reliable control channel */ 
1999/0824    
	Qstatus, 
1999/0929    
	Qstats, 
	Qrstats, 
1999/0824    
 
	MaxQ, 
 
1999/0915/sys/src/9/port/devsdp.c:45,521999/0929/sys/src/9/port/devsdp.c:48,75
1999/0901    
#define CONV(x) 	(((x).path >> 8)&(Maxconv-1)) 
1999/0824    
#define QID(x, y) 	(((x)<<8) | (y)) 
 
1999/0929    
struct Stats 
{ 
	ulong	outPackets; 
	ulong	outDataPackets; 
	ulong	outDataBytes; 
	ulong	outCompDataBytes; 
	ulong	outCompBytes; 
	ulong	inPackets; 
	ulong	inDataPackets; 
	ulong	inDataBytes; 
	ulong	inCompDataBytes; 
	ulong	inMissing; 
	ulong	inDup; 
	ulong	inReorder; 
	ulong	inBadAuth; 
	ulong	inBadSeq; 
}; 
 
1999/0907    
struct OneWay 
1999/0901    
{ 
1999/0929    
	Rendez	statsready; 
 
1999/0901    
	ulong	seqwrap;	// number of wraps of the sequence number 
	ulong	seq; 
1999/0907    
	ulong	window; 
1999/0915/sys/src/9/port/devsdp.c:90,951999/0929/sys/src/9/port/devsdp.c:113,121
1999/0906    
	int dataopen; 
1999/0910    
	int reader;		// reader proc has been started 
1999/0901    
 
1999/0929    
	Stats	lstats; 
	Stats	rstats; 
 
1999/0906    
	ulong	timeout; 
	int		retries; 
 
1999/0915/sys/src/9/port/devsdp.c:149,1571999/0929/sys/src/9/port/devsdp.c:175,200
1999/0906    
	uchar acceptid[4]; 
}; 
 
1999/0929    
struct AckPkt 
{ 
	uchar	cseq[4]; 
	uchar	outPackets[4]; 
	uchar	outDataPackets[4]; 
	uchar	outDataBytes[4]; 
	uchar	outCompDataBytes[4]; 
	uchar	inPackets[4]; 
	uchar	inDataPackets[4]; 
	uchar	inDataBytes[4]; 
	uchar	inCompDataBytes[4]; 
	uchar	inMissing[4]; 
	uchar	inDup[4]; 
	uchar	inReorder[4]; 
	uchar	inBadAuth[4]; 
	uchar	inBadSeq[4]; 
}; 
1999/0907    
 
1999/0929    
 
1999/0824    
static Dirtab sdpdirtab[]={ 
	"stats",	{Qstats},	0,	0444, 
	"log",		{Qlog},		0,	0666, 
1999/0901    
	"clone",	{Qclone},		0,	0666, 
1999/0824    
}; 
1999/0915/sys/src/9/port/devsdp.c:161,1661999/0929/sys/src/9/port/devsdp.c:204,211
1999/0824    
	"data",		{Qdata},	0,	0666, 
1999/0902    
	"control",	{Qcontrol},	0,	0666, 
1999/0824    
	"status",	{Qstatus},	0,	0444, 
1999/0929    
	"stats",	{Qstats},	0,	0444, 
	"rstats",	{Qrstats},	0,	0444, 
1999/0824    
}; 
 
static int m2p[] = { 
1999/0915/sys/src/9/port/devsdp.c:204,2101999/0929/sys/src/9/port/devsdp.c:249,255
1999/0907    
static int controlread(); 
static Block *conviput(Conv *c, Block *b, int control); 
static void conviput2(Conv *c, Block *b); 
1999/0914    
static void writecontrol(Conv *c, void *p, int n); 
1999/0929    
static void writecontrol(Conv *c, void *p, int n, int wait); 
1999/0907    
static Block *readcontrol(Conv *c, int n); 
static Block *readdata(Conv *c, int n); 
1999/0915    
static long writedata(Conv *c, Block *b); 
1999/0915/sys/src/9/port/devsdp.c:212,2191999/0929/sys/src/9/port/devsdp.c:257,264
1999/0907    
static void convoput2(Conv *c, int op, ulong dialid, ulong acceptid); 
1999/0910    
static void convreader(void *a); 
1999/0914    
static void convopenchan(Conv *c, char *path); 
1999/0929    
static void convstats(Conv *c, int local, char *buf, int n); 
1999/0824    
 
1999/0907    
                 
1999/0824    
static void 
sdpinit(void) 
{ 
1999/0915/sys/src/9/port/devsdp.c:310,3161999/0929/sys/src/9/port/devsdp.c:355,360
1999/0824    
	case Qtopdir: 
	case Qsdpdir: 
1999/0901    
	case Qconvdir: 
1999/0824    
	case Qstats: 
		if(omode != OREAD) 
			error(Eperm); 
		break; 
1999/0915/sys/src/9/port/devsdp.c:327,3321999/0929/sys/src/9/port/devsdp.c:371,378
1999/0902    
	case Qctl: 
	case Qstatus: 
	case Qcontrol: 
1999/0929    
	case Qstats: 
	case Qrstats: 
1999/0902    
		c = sdp->conv[CONV(ch->qid)]; 
		qlock(c); 
		if(waserror()) { 
1999/0915/sys/src/9/port/devsdp.c:407,4151999/0929/sys/src/9/port/devsdp.c:453,463
1999/0901    
sdpread(Chan *ch, void *a, long n, vlong off) 
1999/0824    
{ 
	char buf[256]; 
1999/0929    
	char *s; 
1999/0901    
	Sdp *sdp = sdptab + ch->dev; 
	Conv *c; 
1999/0907    
	Block *b; 
1999/0929    
	int rv; 
1999/0824    
 
	USED(off); 
1999/0901    
	switch(TYPE(ch->qid)) { 
1999/0915/sys/src/9/port/devsdp.c:450,4551999/0929/sys/src/9/port/devsdp.c:498,511
1999/0907    
		memmove(a, b->rp, n); 
		freeb(b); 
		return n; 
1999/0929    
	case Qstats: 
	case Qrstats: 
		c = sdp->conv[CONV(ch->qid)]; 
		s = smalloc(1000); 
		convstats(c, TYPE(ch->qid) == Qstats, s, 1000); 
		rv = readstr(off, a, n, s); 
		free(s); 
		return rv; 
1999/0824    
	} 
} 
 
1999/0915/sys/src/9/port/devsdp.c:518,5241999/0929/sys/src/9/port/devsdp.c:574,580
1999/0824    
		return n; 
1999/0914    
	case Qcontrol: 
print("writecontrol %ld\n", n); 
		writecontrol(sdp->conv[CONV(ch->qid)], a, n); 
1999/0929    
		writecontrol(sdp->conv[CONV(ch->qid)], a, n, 0); 
1999/0914    
		return n; 
1999/0915    
	case Qdata: 
		b = allocb(n); 
1999/0915/sys/src/9/port/devsdp.c:854,8601999/0929/sys/src/9/port/devsdp.c:910,979
1999/0914    
	poperror(); 
} 
1999/0907    
 
1999/0929    
static void 
convstats(Conv *c, int local, char *buf, int n) 
{ 
	Stats *stats; 
	char *p, *ep; 
1999/0907    
 
1999/0929    
	qlock(c); 
	if(local) { 
		stats = &c->lstats; 
	} else { 
		if(!waserror()) { 
			writecontrol(c, 0, 0, 1); 
			poperror(); 
		} 
		stats = &c->rstats; 
	} 
	p = buf; 
	ep = buf + n; 
	p += snprint(p, ep-p, "outPackets: %ld\n", stats->outPackets); 
	p += snprint(p, ep-p, "outDataPackets: %ld\n", stats->outDataPackets); 
	p += snprint(p, ep-p, "outDataBytes: %ld\n", stats->outDataBytes); 
	p += snprint(p, ep-p, "outCompDataBytes: %ld\n", stats->outCompDataBytes); 
	p += snprint(p, ep-p, "inPackets: %ld\n", stats->inPackets); 
	p += snprint(p, ep-p, "inDataPackets: %ld\n", stats->inDataPackets); 
	p += snprint(p, ep-p, "inCompDataBytes: %ld\n", stats->inCompDataBytes); 
	p += snprint(p, ep-p, "inMissing: %ld\n", stats->inMissing); 
	p += snprint(p, ep-p, "inDup: %ld\n", stats->inDup); 
	p += snprint(p, ep-p, "inReorder: %ld\n", stats->inReorder); 
	p += snprint(p, ep-p, "inBadAuth: %ld\n", stats->inBadAuth); 
	p += snprint(p, ep-p, "inBadSeq: %ld\n", stats->inBadSeq); 
	USED(p); 
	qunlock(c); 
} 
 
// c is locked 
static void 
convack(Conv *c) 
{ 
	Block *b; 
	AckPkt *ack; 
	Stats *s; 
 
	b = allocb(sizeof(AckPkt)); 
	ack = (Ack)b->wp; 
	b->wp += sizeof(AckPkt); 
	s = &c->lstats; 
	hnputl(ack->cseq, c->in.controlseq); 
	hnputl(ack->outPackets, s->outPackets); 
	hnputl(ack->outDataPackets, s->outDataPackets); 
	hnputl(ack->outDataBytes, s->outDataBytes); 
	hnputl(ack->outCompDataBytes, s->outCompDataBytes); 
	hnputl(ack->inPackets, s->inPackets); 
	hnputl(ack->inDataPackets, s->inDataPackets); 
	hnputl(ack->inDataBytes, s->inDataBytes); 
	hnputl(ack->inCompDataBytes, s->inCompDataBytes); 
	hnputl(ack->inMissing, s->inMissing); 
	hnputl(ack->inDup, s->inDup); 
	hnputl(ack->inReorder, s->inReorder); 
	hnputl(ack->inBadAuth, s->inBadAuth); 
	hnputl(ack->inBadSeq, s->inBadSeq); 
	convoput(c, TControlAck, b); 
} 
 
 
1999/0907    
// assume we hold lock for c 
static Block * 
conviput(Conv *c, Block *b, int control) 
1999/0915/sys/src/9/port/devsdp.c:861,8671999/0929/sys/src/9/port/devsdp.c:980,989
1999/0907    
{ 
	int type; 
	ulong seq, cseq; 
1999/0929    
	AckPkt *ack; 
1999/0907    
 
1999/0929    
	c->lstat.inPackets++; 
 
1999/0907    
	if(BLEN(b) < 4) { 
		freeb(b); 
		return nil; 
1999/0915/sys/src/9/port/devsdp.c:885,9021999/0929/sys/src/9/port/devsdp.c:1007,1021
1999/0907    
 
	switch(type) { 
	case TControl: 
		if(BLEN(b) <= 4) 
1999/0929    
		if(BLEN(b) < 4) 
1999/0907    
			break; 
		cseq = nhgetl(b->rp); 
		if(cseq == c->in.controlseq) { 
1999/0914    
print("duplicate control packet: %ulx\n", cseq); 
1999/0907    
			// duplicate control packet 
1999/0914    
			if(c->in.controlpkt == nil) { 
				// send ack 
				b->wp = b->rp + 4; 
				convoput(c, TControlAck, b); 
			} else 
				freeb(b); 
1999/0929    
			freeb(b); 
			if(c->in.controlpkt == nil) 
				convack(c); 
1999/0907    
			return nil; 
		} 
 
1999/0915/sys/src/9/port/devsdp.c:904,9201999/0929/sys/src/9/port/devsdp.c:1023,1059
1999/0907    
			break; 
		c->in.controlseq = cseq; 
		b->rp += 4; 
		c->in.controlpkt = b; 
1999/0929    
		if(BLEN(b) == 0) { 
			// just a ping 
			freeb(b); 
			convack(c); 
		} else { 
			c->in.controlpkt = b; 
1999/0914    
print("recv %ld size=%ld\n", cseq, BLEN(b)); 
1999/0907    
		wakeup(&c->in.controlready); 
1999/0929    
			wakeup(&c->in.controlready); 
		} 
1999/0907    
		return nil; 
	case TControlAck: 
		if(BLEN(b) != 4) 
1999/0929    
		if(BLEN(b) != sizeof(AckPkt)) 
1999/0907    
			break; 
		cseq = nhgetl(b->rp); 
1999/0929    
		ack = (AckPkt*)(b->rp); 
		cseq = nhgetl(ack->cseq); 
1999/0914    
print("ControlAck expected %ulx got %ulx\n", c->out.controlseq, cseq); 
1999/0907    
		if(cseq != c->out.controlseq) 
			break; 
1999/0929    
		c->rstat.outPackets = nhgetl(ack->outPackets); 
		c->rstat.outDataPackets = nhgetl(ack->outDataPackets); 
		c->rstat.outDataBytes = nhgetl(ack->outDataBytes); 
		c->rstat.outCompDataBytes = nhgetl(ack->outCompDataBytes); 
		c->rstat.inPackets = nhgetl(ack->inPackets); 
		c->rstat.inDataPackets = nhgetl(ack->inDataPackets); 
		c->rstat.inDataBytes = nhgetl(ack->inDataBytes); 
		c->rstat.inCompDataBytes = nhgetl(ack->inCompDataBytes); 
		c->rstat.inMissing = nhgetl(ack->inMissing); 
		c->rstat.inDup = nhgetl(ack->inDup); 
		c->rstat.inReorder = nhgetl(ack->inReorder); 
		c->rstat.inBadAuth = nhgetl(ack->inBadAuth); 
		c->rstat.inBadSeq = nhgetl(ack->inBadSeq); 
1999/0907    
		freeb(b); 
		freeb(c->out.controlpkt); 
1999/0914    
		c->out.controlpkt = nil; 
1999/0915/sys/src/9/port/devsdp.c:921,9261999/0929/sys/src/9/port/devsdp.c:1060,1068
1999/0907    
		wakeup(&c->out.controlready); 
		return nil; 
	case TData: 
1999/0929    
		c->lstats.inDataPackets++; 
		c->lstats.inDataBytes += BLEN(b); 
		c->lstats.inCompDataBytes += BLEN(b); 
1999/0907    
		if(control) 
			break; 
		return b; 
1999/0915/sys/src/9/port/devsdp.c:1045,10511999/0929/sys/src/9/port/devsdp.c:1187,1193
1999/0907    
convoput(Conv *c, int type, Block *b) 
{ 
	// try and compress 
                 
1999/0929    
	c->lstats.outPackets++; 
1999/0907    
	/* Make space to fit sdp header */ 
	b = padblock(b, 4 + c->out.cipherivlen); 
	b->rp[0] = type; 
1999/0915/sys/src/9/port/devsdp.c:1074,10791999/0929/sys/src/9/port/devsdp.c:1216,1222
1999/0907    
{ 
	ConnectPkt con; 
 
1999/0929    
	c->lstats.outPackets++; 
1999/0906    
	if(c->chan == nil) { 
print("chan = nil\n"); 
		error("no channel attached"); 
1999/0915/sys/src/9/port/devsdp.c:1166,11761999/0929/sys/src/9/port/devsdp.c:1309,1315
1999/0914    
		qlock(c); 
1999/0907    
	} 
1999/0914    
 
	// send ack 
	b = allocb(4); 
	hnputl(b->wp, c->in.controlseq); 
	b->wp += 4;	 
	convoput(c, TControlAck, b); 
1999/0929    
	convack(c); 
1999/0914    
 
	b = c->in.controlpkt; 
	c->in.controlpkt = nil; 
1999/0915/sys/src/9/port/devsdp.c:1189,12091999/0929/sys/src/9/port/devsdp.c:1328,1339
1999/0914    
	return c->out.controlpkt == nil || (c->state == CClosed) || (c->state == CRemoteClose); 
} 
 
1999/0929    
// c is locked 
1999/0914    
static void 
writecontrol(Conv *c, void *p, int n) 
1999/0929    
writewait(Conv *c) 
1999/0914    
{ 
	Block *b; 
                 
1999/0915    
                 
	qlock(&c->out.controllk); 
	if(waserror()) { 
		qunlock(&c->out.controllk); 
		nexterror(); 
	} 
	qlock(c);	// this lock is not held in the sleep below 
1999/0914    
	for(;;) { 
		if(c->state == CInit || c->state == CClosed || c->state == CRemoteClose) { 
			qunlock(c); 
print("writecontrol: return error - state = %s\n", convstatename[c->state]); 
			error("conversation closed"); 
		} 
1999/0915/sys/src/9/port/devsdp.c:1212,12201999/0929/sys/src/9/port/devsdp.c:1342,1371
1999/0914    
			break; 
 
		qunlock(c); 
1999/0929    
		if(waserror()) { 
			qlock(c); 
			nexterror(); 
		} 
1999/0914    
		sleep(&c->out.controlready, writeready, c); 
1999/0929    
		poperror(); 
1999/0914    
		qlock(c); 
	} 
1999/0929    
} 
 
static void 
writecontrol(Conv *c, void *p, int n, int wait) 
{ 
	Block *b; 
 
 
	qlock(&c->out.controllk); 
	qlock(c); 
	if(waserror()) { 
		qunlock(c); 
		qunlock(&c->out.controllk); 
		nexterror(); 
	} 
	writewait(c); 
1999/0914    
	b = allocb(4+n); 
	c->out.controlseq++; 
	hnputl(b->wp, c->out.controlseq); 
1999/0915/sys/src/9/port/devsdp.c:1224,12311999/0929/sys/src/9/port/devsdp.c:1375,1384
1999/0914    
	convretryinit(c); 
print("send %ld size=%ld\n", c->out.controlseq, BLEN(b));	 
	convoput(c, TControl, copyblock(b, blocklen(b))); 
	qunlock(c); 
1999/0929    
	if(wait) 
		writewait(c); 
1999/0915    
	poperror(); 
1999/0929    
	qunlock(c); 
1999/0915    
	qunlock(&c->out.controllk); 
1999/0914    
} 
 
1999/0915/sys/src/9/port/devsdp.c:1267,12721999/0929/sys/src/9/port/devsdp.c:1420,1428
1999/0915    
	} 
 
	n = BLEN(b); 
1999/0929    
	c->outDataPackets++; 
	c->outDataBytes += n; 
	c->outCompDataBytes += n; 
1999/0915    
	convoput(c, TData, b); 
	poperror(); 
	qunlock(c); 
1999/0929/sys/src/9/port/devsdp.c:489,4951999/0930/sys/src/9/port/devsdp.c:489,494 (short | long)
1999/0907    
		freeb(b); 
		return n; 
	case Qdata: 
1999/0914    
print("readdata\n"); 
1999/0907    
		b = readdata(sdp->conv[CONV(ch->qid)], n); 
		if(b == nil) 
			return 0; 
1999/0929/sys/src/9/port/devsdp.c:916,9221999/0930/sys/src/9/port/devsdp.c:915,920
1999/0929    
	Stats *stats; 
	char *p, *ep; 
1999/0907    
 
1999/0929    
	qlock(c); 
	if(local) { 
		stats = &c->lstats; 
	} else { 
1999/0929/sys/src/9/port/devsdp.c:926,9311999/0930/sys/src/9/port/devsdp.c:924,931
1999/0929    
		} 
		stats = &c->rstats; 
	} 
1999/0930    
 
	qlock(c); 
1999/0929    
	p = buf; 
	ep = buf + n; 
	p += snprint(p, ep-p, "outPackets: %ld\n", stats->outPackets); 
1999/0929/sys/src/9/port/devsdp.c:934,9391999/0930/sys/src/9/port/devsdp.c:934,940
1999/0929    
	p += snprint(p, ep-p, "outCompDataBytes: %ld\n", stats->outCompDataBytes); 
	p += snprint(p, ep-p, "inPackets: %ld\n", stats->inPackets); 
	p += snprint(p, ep-p, "inDataPackets: %ld\n", stats->inDataPackets); 
1999/0930    
	p += snprint(p, ep-p, "inDataBytes: %ld\n", stats->inDataBytes); 
1999/0929    
	p += snprint(p, ep-p, "inCompDataBytes: %ld\n", stats->inCompDataBytes); 
	p += snprint(p, ep-p, "inMissing: %ld\n", stats->inMissing); 
	p += snprint(p, ep-p, "inDup: %ld\n", stats->inDup); 
1999/0929/sys/src/9/port/devsdp.c:953,9591999/0930/sys/src/9/port/devsdp.c:954,960
1999/0929    
	Stats *s; 
 
	b = allocb(sizeof(AckPkt)); 
	ack = (Ack)b->wp; 
1999/0930    
	ack = (AckPkt*)b->wp; 
1999/0929    
	b->wp += sizeof(AckPkt); 
	s = &c->lstats; 
	hnputl(ack->cseq, c->in.controlseq); 
1999/0929/sys/src/9/port/devsdp.c:982,9881999/0930/sys/src/9/port/devsdp.c:983,989
1999/0907    
	ulong seq, cseq; 
1999/0929    
	AckPkt *ack; 
1999/0907    
 
1999/0929    
	c->lstat.inPackets++; 
1999/0930    
	c->lstats.inPackets++; 
1999/0929    
 
1999/0907    
	if(BLEN(b) < 4) { 
		freeb(b); 
1999/0929/sys/src/9/port/devsdp.c:999,10051999/0930/sys/src/9/port/devsdp.c:1000,1006
1999/0907    
	b->rp += 4; 
 
	USED(seq); 
1999/0914    
print("coniput seq=%ulx\n", seq); 
1999/0930    
if(0) print("coniput seq=%ulx\n", seq); 
1999/0907    
	// auth 
	// decrypt 
 
1999/0929/sys/src/9/port/devsdp.c:1029,10351999/0930/sys/src/9/port/devsdp.c:1030,1036
1999/0929    
			convack(c); 
		} else { 
			c->in.controlpkt = b; 
1999/0914    
print("recv %ld size=%ld\n", cseq, BLEN(b)); 
1999/0930    
if(0) print("recv %ld size=%ld\n", cseq, BLEN(b)); 
1999/0929    
			wakeup(&c->in.controlready); 
		} 
1999/0907    
		return nil; 
1999/0929/sys/src/9/port/devsdp.c:1038,10591999/0930/sys/src/9/port/devsdp.c:1039,1061
1999/0907    
			break; 
1999/0929    
		ack = (AckPkt*)(b->rp); 
		cseq = nhgetl(ack->cseq); 
1999/0930    
		if(cseq != c->out.controlseq) { 
1999/0914    
print("ControlAck expected %ulx got %ulx\n", c->out.controlseq, cseq); 
1999/0907    
		if(cseq != c->out.controlseq) 
			break; 
1999/0929    
		c->rstat.outPackets = nhgetl(ack->outPackets); 
		c->rstat.outDataPackets = nhgetl(ack->outDataPackets); 
		c->rstat.outDataBytes = nhgetl(ack->outDataBytes); 
		c->rstat.outCompDataBytes = nhgetl(ack->outCompDataBytes); 
		c->rstat.inPackets = nhgetl(ack->inPackets); 
		c->rstat.inDataPackets = nhgetl(ack->inDataPackets); 
		c->rstat.inDataBytes = nhgetl(ack->inDataBytes); 
		c->rstat.inCompDataBytes = nhgetl(ack->inCompDataBytes); 
		c->rstat.inMissing = nhgetl(ack->inMissing); 
		c->rstat.inDup = nhgetl(ack->inDup); 
		c->rstat.inReorder = nhgetl(ack->inReorder); 
		c->rstat.inBadAuth = nhgetl(ack->inBadAuth); 
		c->rstat.inBadSeq = nhgetl(ack->inBadSeq); 
1999/0930    
		} 
		c->rstats.outPackets = nhgetl(ack->outPackets); 
		c->rstats.outDataPackets = nhgetl(ack->outDataPackets); 
		c->rstats.outDataBytes = nhgetl(ack->outDataBytes); 
		c->rstats.outCompDataBytes = nhgetl(ack->outCompDataBytes); 
		c->rstats.inPackets = nhgetl(ack->inPackets); 
		c->rstats.inDataPackets = nhgetl(ack->inDataPackets); 
		c->rstats.inDataBytes = nhgetl(ack->inDataBytes); 
		c->rstats.inCompDataBytes = nhgetl(ack->inCompDataBytes); 
		c->rstats.inMissing = nhgetl(ack->inMissing); 
		c->rstats.inDup = nhgetl(ack->inDup); 
		c->rstats.inReorder = nhgetl(ack->inReorder); 
		c->rstats.inBadAuth = nhgetl(ack->inBadAuth); 
		c->rstats.inBadSeq = nhgetl(ack->inBadSeq); 
1999/0907    
		freeb(b); 
		freeb(c->out.controlpkt); 
1999/0914    
		c->out.controlpkt = nil; 
1999/0929/sys/src/9/port/devsdp.c:1182,11871999/0930/sys/src/9/port/devsdp.c:1184,1206
1999/0910    
	convoput2(c, ConReset, dialid, acceptid); 
1999/0907    
} 
 
1999/0930    
// c is locked 
static void 
convwriteblock(Conv *c, Block *b) 
{ 
	// simulated errors 
	if(c->drop && c->drop > nrand(c->drop)) 
		return; 
 
	if(waserror()) { 
		convsetstate(c, CClosed); 
		nexterror(); 
	} 
	devtab[c->chan->type]->bwrite(c->chan, b, 0); 
	poperror(); 
} 
 
 
1999/0907    
// assume hold conv lock 
static void 
convoput(Conv *c, int type, Block *b) 
1999/0929/sys/src/9/port/devsdp.c:1202,12131999/0930/sys/src/9/port/devsdp.c:1221,1228
1999/0907    
	 
	// encrypt 
	// auth 
                 
	// simulated errors 
	if(c->drop && c->drop > nrand(c->drop)) 
		return; 
1999/0915    
print("convoput\n"); 
1999/0907    
	devtab[c->chan->type]->bwrite(c->chan, b, 0); 
1999/0930    
	 
	convwriteblock(c, b); 
1999/0907    
} 
 
// assume hold conv lock 
1999/0929/sys/src/9/port/devsdp.c:1214,12201999/0930/sys/src/9/port/devsdp.c:1229,1236
1999/0907    
static void 
convoput2(Conv *c, int op, ulong dialid, ulong acceptid) 
{ 
	ConnectPkt con; 
1999/0930    
	Block *b; 
	ConnectPkt *con; 
1999/0907    
 
1999/0929    
	c->lstats.outPackets++; 
1999/0906    
	if(c->chan == nil) { 
1999/0929/sys/src/9/port/devsdp.c:1221,12361999/0930/sys/src/9/port/devsdp.c:1237,1251
1999/0906    
print("chan = nil\n"); 
		error("no channel attached"); 
	} 
	memset(&con, 0, sizeof(con)); 
	con.type = TConnect; 
	con.op = op; 
	hnputl(con.dialid, dialid); 
	hnputl(con.acceptid, acceptid); 
1999/0930    
	b = allocb(sizeof(ConnectPkt)); 
	con = (ConnectPkt*)b->wp; 
	b->wp += sizeof(ConnectPkt); 
	con->type = TConnect; 
	con->op = op; 
	hnputl(con->dialid, dialid); 
	hnputl(con->acceptid, acceptid); 
1999/0906    
 
	// simulated errors 
	if(c->drop && c->drop > nrand(c->drop)) 
		return; 
	devtab[c->chan->type]->write(c->chan, &con, sizeof(con), 0); 
1999/0930    
	convwriteblock(c, b); 
1999/0907    
} 
 
1999/0910    
static Block * 
1999/0929/sys/src/9/port/devsdp.c:1375,13821999/0930/sys/src/9/port/devsdp.c:1390,1399
1999/0914    
	convretryinit(c); 
print("send %ld size=%ld\n", c->out.controlseq, BLEN(b));	 
	convoput(c, TControl, copyblock(b, blocklen(b))); 
1999/0929    
	if(wait) 
1999/0930    
	if(wait) { 
print("writecontrol wait!\n"); 
1999/0929    
		writewait(c); 
1999/0930    
	} 
1999/0915    
	poperror(); 
1999/0929    
	qunlock(c); 
1999/0915    
	qunlock(&c->out.controllk); 
1999/0929/sys/src/9/port/devsdp.c:1389,13941999/0930/sys/src/9/port/devsdp.c:1406,1413
1999/0907    
 
	for(;;) { 
		b = convreadblock(c, n); 
1999/0930    
		if(b == nil) 
			return nil; 
1999/0907    
		qlock(c); 
		if(waserror()) { 
			qunlock(c); 
1999/0929/sys/src/9/port/devsdp.c:1408,14141999/0930/sys/src/9/port/devsdp.c:1427,1432
1999/0915    
	int n; 
 
	qlock(c); 
print("writedata %ulx state=%s\n", b, convstatename[c->state]); 
	if(waserror()) { 
		qunlock(c); 
		nexterror(); 
1999/0929/sys/src/9/port/devsdp.c:1420,14281999/0930/sys/src/9/port/devsdp.c:1438,1446
1999/0915    
	} 
 
	n = BLEN(b); 
1999/0929    
	c->outDataPackets++; 
	c->outDataBytes += n; 
	c->outCompDataBytes += n; 
1999/0930    
	c->lstats.outDataPackets++; 
	c->lstats.outDataBytes += n; 
	c->lstats.outCompDataBytes += n; 
1999/0915    
	convoput(c, TData, b); 
	poperror(); 
	qunlock(c); 
1999/0930/sys/src/9/port/devsdp.c:7,121999/1001/sys/src/9/port/devsdp.c:7,13 (short | long)
1999/0824    
#include "../port/error.h" 
 
#include	<libcrypt.h> 
1999/1001    
#include "../port/thwack.h" 
1999/0824    
 
1999/0907    
/* 
 * sdp - secure datagram protocol 
1999/0930/sys/src/9/port/devsdp.c:18,231999/1001/sys/src/9/port/devsdp.c:19,25
1999/0929    
typedef struct Stats Stats; 
1999/0907    
typedef struct ConnectPkt ConnectPkt; 
1999/0929    
typedef struct AckPkt AckPkt; 
1999/1001    
typedef struct Algorithm Algorithm; 
1999/0824    
 
enum 
{ 
1999/0930/sys/src/9/port/devsdp.c:39,471999/1001/sys/src/9/port/devsdp.c:41,51
1999/0824    
 
1999/0907    
	Maxconv= 256,		// power of 2 
	Nfs= 4,				// number of file systems 
1999/0914    
	MaxRetries=	4, 
1999/1001    
	MaxRetries=	8, 
1999/0909    
	KeepAlive = 60,		// keep alive in seconds 
1999/0907    
	KeyLength= 32, 
1999/1001    
	SeqMax = (1<<24), 
	SeqWindow = 32, 
1999/0824    
}; 
 
#define TYPE(x) 	((x).path & 0xff) 
1999/0930/sys/src/9/port/devsdp.c:115,1211999/1001/sys/src/9/port/devsdp.c:119,126
1999/0901    
 
1999/0929    
	Stats	lstats; 
	Stats	rstats; 
                 
1999/1001    
	 
	ulong	lastrecv;	// time last packet was received  
1999/0906    
	ulong	timeout; 
	int		retries; 
 
1999/0930/sys/src/9/port/devsdp.c:133,1381999/1001/sys/src/9/port/devsdp.c:138,146
1999/0901    
	int	perm; 
 
1999/0907    
	uchar	masterkey[KeyLength]; 
1999/1001    
	char *authname; 
	char *ciphername; 
	char *compname; 
1999/0907    
 
1999/0906    
	int drop; 
 
1999/0930/sys/src/9/port/devsdp.c:193,1981999/1001/sys/src/9/port/devsdp.c:201,212
1999/0929    
	uchar	inBadSeq[4]; 
}; 
1999/0907    
 
1999/1001    
struct Algorithm 
{ 
	char 	*name; 
	int		keylen;		// in bytes 
	void	(*init)(Conv*, char* name, int keylen); 
}; 
1999/0929    
 
1999/0824    
static Dirtab sdpdirtab[]={ 
	"log",		{Qlog},		0,	0666, 
1999/0930/sys/src/9/port/devsdp.c:208,2131999/1001/sys/src/9/port/devsdp.c:222,252
1999/0929    
	"rstats",	{Qrstats},	0,	0444, 
1999/0824    
}; 
 
1999/1001    
#ifdef XXX 
static Algorithm cipheralg[] = 
{ 
	"null",			0,	nullcipherinit, 
	"des_56_cbc",	7,	descipherinit, 
	"rc4_128",		16,	rc4cipherinit, 
	nil,			0,	nil, 
}; 
 
static Algorithm authalg[] = 
{ 
	"null",			0,	nullauthinit, 
	"hmac_sha_96",	16,	shaauthinit, 
	"hmac_md5_96",	16,	md5authinit, 
	nil,			0,	nil, 
}; 
 
static Algorithm compalg[] = 
{ 
	"null",			0,	nullcompinit, 
	"thwack",		0,	thwackcompinit, 
	nil,			0,	nil, 
}; 
#endif 
 
1999/0824    
static int m2p[] = { 
	[OREAD]		4, 
	[OWRITE]	2, 
1999/0930/sys/src/9/port/devsdp.c:572,5781999/1001/sys/src/9/port/devsdp.c:611,616
1999/0824    
			error(p); 
		return n; 
1999/0914    
	case Qcontrol: 
print("writecontrol %ld\n", n); 
1999/0929    
		writecontrol(sdp->conv[CONV(ch->qid)], a, n, 0); 
1999/0914    
		return n; 
1999/0915    
	case Qdata: 
1999/0930/sys/src/9/port/devsdp.c:660,6651999/1001/sys/src/9/port/devsdp.c:698,704
1999/0901    
			c = malloc(sizeof(Conv)); 
			if(c == nil) 
				error(Enomem); 
1999/1001    
			memset(c, 0, sizeof(Conv)); 
1999/0901    
			qlock(c); 
			c->sdp = sdp; 
			c->id = pp - sdp->conv; 
1999/0930/sys/src/9/port/devsdp.c:681,6861999/1001/sys/src/9/port/devsdp.c:720,730
1999/0901    
 
1999/0902    
	c->ref++; 
1999/0906    
	c->state = CInit; 
1999/1001    
	c->in.window = ~0; 
	c->in.compstate = malloc(sizeof(Unthwack)); 
	unthwackinit(c->in.compstate); 
	c->out.compstate = malloc(sizeof(Thwack)); 
	thwackinit(c->out.compstate); 
1999/0907    
	strncpy(c->owner, up->user, sizeof(c->owner)); 
1999/0901    
	c->perm = 0660; 
	qunlock(c); 
1999/0930/sys/src/9/port/devsdp.c:719,7251999/1001/sys/src/9/port/devsdp.c:763,769
1999/0902    
{ 
1999/0914    
	Block *b; 
 
1999/0906    
	if(c->timeout == 0 || c->timeout > sec) 
1999/1001    
	if(c->timeout > sec) 
1999/0906    
		return; 
1999/0902    
	qlock(c); 
1999/0906    
	if(waserror()) { 
1999/0930/sys/src/9/port/devsdp.c:740,7491999/1001/sys/src/9/port/devsdp.c:784,810
1999/0914    
		if(b != nil) { 
			if(convretry(c, 1)) 
				convoput(c, TControl, copyblock(b, blocklen(b))); 
		} else { 
			c->timeout = 0; 
1999/1001    
			break; 
1999/0914    
		} 
		// keepalive 
1999/1001    
 
		c->timeout = c->lastrecv + KeepAlive; 
		if(c->timeout > sec) 
			break; 
		// keepalive - randomly spaced between KeepAlive and 2*KeepAlive 
		if(c->timeout + KeepAlive > sec && nrand(c->lastrecv + 2*KeepAlive - sec) > 0) 
			break; 
print("sending keep alive: %ld\n", sec - c->lastrecv); 
		// can not use writecontrol 
		b = allocb(4); 
		c->out.controlseq++; 
		hnputl(b->wp, c->out.controlseq); 
		b->wp += 4; 
		c->out.controlpkt = b; 
		convretryinit(c); 
		if(!waserror()) { 
			convoput(c, TControl, copyblock(b, blocklen(b))); 
			poperror(); 
		} 
1999/0906    
		break; 
1999/0910    
	case CLocalClose: 
1999/0914    
		if(convretry(c, 0)) 
1999/0930/sys/src/9/port/devsdp.c:751,7571999/1001/sys/src/9/port/devsdp.c:812,818
1999/0906    
		break; 
1999/0914    
	case CRemoteClose: 
	case CClosed: 
		c->timeout = 0; 
1999/1001    
		c->timeout = ~0; 
1999/0914    
		break; 
1999/0906    
	} 
1999/0914    
	poperror(); 
1999/0930/sys/src/9/port/devsdp.c:858,8731999/1001/sys/src/9/port/devsdp.c:919,948
1999/0910    
			free(c->channame); 
			c->channame = nil; 
		} 
1999/0907    
		strcpy(c->owner, "network"); 
1999/1001    
		if(c->ciphername) { 
			free(c->ciphername); 
			c->ciphername = nil; 
		} 
		if(c->authname) { 
			free(c->authname); 
			c->authname = nil; 
		} 
			if(c->compname) { 
			free(c->compname); 
			c->compname = nil; 
		} 
	strcpy(c->owner, "network"); 
1999/0907    
		c->perm = 0660; 
		c->dialid = 0; 
		c->acceptid = 0; 
		c->timeout = 0; 
1999/1001    
		c->timeout = ~0; 
1999/0907    
		c->retries = 0; 
		c->drop = 0; 
		memset(c->masterkey, 0, sizeof(c->masterkey)); 
		onewaycleanup(&c->in); 
		onewaycleanup(&c->out); 
1999/1001    
		memset(&c->lstats, 0, sizeof(Stats)); 
		memset(&c->rstats, 0, sizeof(Stats)); 
1999/0906    
		break; 
	} 
	c->state = state; 
1999/0930/sys/src/9/port/devsdp.c:979,9871999/1001/sys/src/9/port/devsdp.c:1054,1065
1999/0907    
static Block * 
conviput(Conv *c, Block *b, int control) 
{ 
	int type; 
	ulong seq, cseq; 
1999/1001    
	int type, n; 
	ulong seq, seqwrap, cseq; 
	long seqdiff; 
1999/0929    
	AckPkt *ack; 
1999/1001    
	ulong mseq, mask; 
	Block *bb; 
1999/0907    
 
1999/0930    
	c->lstats.inPackets++; 
1999/0929    
 
1999/0930/sys/src/9/port/devsdp.c:999,10101999/1001/sys/src/9/port/devsdp.c:1077,1134
1999/0907    
	seq = (b->rp[1]<<16) + (b->rp[2]<<8) + b->rp[3]; 
	b->rp += 4; 
 
	USED(seq); 
1999/1001    
	seqwrap = c->in.seqwrap; 
	seqdiff = seq - c->in.seq; 
	if(seqdiff < -(SeqMax*3/4)) { 
		seqwrap++; 
		seqdiff += SeqMax; 
	} else if(seqdiff > SeqMax*3/4) { 
		seqwrap--; 
		seqdiff -= SeqMax; 
	} 
 
	if(seqdiff <= 0) { 
		if(seqdiff <= -SeqWindow) { 
print("old sequence number: %ld (%ld %ld)\n", seq, c->in.seqwrap, seqdiff); 
			c->lstats.inBadSeq++; 
			freeb(b); 
			return nil; 
		} 
 
		if(c->in.window & (1<<-seqdiff)) { 
print("dup sequence number: %ld (%ld %ld)\n", seq, c->in.seqwrap, seqdiff); 
			c->lstats.inDup++; 
			freeb(b); 
			return nil; 
		} 
 
		c->lstats.inReorder++; 
	} 
 
	// ok the sequence number looks ok 
1999/0930    
if(0) print("coniput seq=%ulx\n", seq); 
1999/0907    
	// auth 
	// decrypt 
 
	// ok the packet is good 
1999/1001    
	if(seqdiff > 0) { 
		while(seqdiff > 0 && c->in.window != 0) { 
			if((c->in.window & (1<<(SeqWindow-1))) == 0) { 
print("missing packet: %ld\n", seq - seqdiff); 
				c->lstats.inMissing++; 
			} 
			c->in.window <<= 1; 
			seqdiff--; 
		} 
		if(seqdiff > 0) { 
print("missing packets: %ld-%ld\n", seq - SeqWindow - seqdiff+1, seq-SeqWindow); 
			c->lstats.inMissing += seqdiff; 
		} 
		c->in.seq = seq; 
		c->in.seqwrap = seqwrap; 
		c->in.window |= 1; 
	} 
	c->lastrecv = TK2SEC(m->ticks); 
1999/0907    
 
	switch(type) { 
	case TControl: 
1999/0930/sys/src/9/port/devsdp.c:1059,10641999/1001/sys/src/9/port/devsdp.c:1183,1189
1999/0907    
		freeb(b); 
		freeb(c->out.controlpkt); 
1999/0914    
		c->out.controlpkt = nil; 
1999/1001    
		c->timeout = c->lastrecv + KeepAlive; 
1999/0907    
		wakeup(&c->out.controlready); 
		return nil; 
	case TData: 
1999/0930/sys/src/9/port/devsdp.c:1068,10731999/1001/sys/src/9/port/devsdp.c:1193,1227
1999/0907    
		if(control) 
			break; 
		return b; 
1999/1001    
	case TThwackU: 
		c->lstats.inDataPackets++; 
		c->lstats.inCompDataBytes += BLEN(b); 
		mask = b->rp[0]; 
		mseq = (b->rp[1]<<16) | (b->rp[2]<<8) | b->rp[3]; 
		b->rp += 4; 
		thwackack(c->out.compstate, mseq, mask); 
		c->lstats.inDataBytes += BLEN(b); 
		if(control) 
			break; 
		return b; 
	case TThwackC: 
		c->lstats.inDataPackets++; 
		c->lstats.inCompDataBytes += BLEN(b); 
		bb = b; 
		b = allocb(ThwMaxBlock); 
		n = unthwack(c->in.compstate, b->wp, ThwMaxBlock, bb->rp, BLEN(bb), seq); 
		freeb(bb); 
		if(n < 0) 
			break; 
		b->wp += n; 
		mask = b->rp[0]; 
		mseq = (b->rp[1]<<16) | (b->rp[2]<<8) | b->rp[3]; 
		thwackack(c->out.compstate, mseq, mask); 
		b->rp += 4; 
		c->lstats.inDataBytes += BLEN(b); 
		if(control) 
			break; 
		return b; 
1999/0907    
	} 
print("droping packet %d n=%ld\n", type, BLEN(b)); 
	freeb(b); 
1999/0930/sys/src/9/port/devsdp.c:1112,11181999/1001/sys/src/9/port/devsdp.c:1266,1271
1999/0910    
		goto Reset; 
	} 
 
                 
1999/0907    
	switch(con->op) { 
1999/0909    
	case ConOpenRequest: 
		switch(c->state) { 
1999/0930/sys/src/9/port/devsdp.c:1189,11951999/1001/sys/src/9/port/devsdp.c:1342,1348
1999/0930    
convwriteblock(Conv *c, Block *b) 
{ 
	// simulated errors 
	if(c->drop && c->drop > nrand(c->drop)) 
1999/1001    
	if(c->drop && nrand(c->drop) == 0) 
1999/0930    
		return; 
 
	if(waserror()) { 
1999/0930/sys/src/9/port/devsdp.c:1388,13991999/1001/sys/src/9/port/devsdp.c:1541,1549
1999/0914    
	b->wp += 4+n; 
	c->out.controlpkt = b; 
	convretryinit(c); 
print("send %ld size=%ld\n", c->out.controlseq, BLEN(b));	 
	convoput(c, TControl, copyblock(b, blocklen(b))); 
1999/0930    
	if(wait) { 
print("writecontrol wait!\n"); 
1999/1001    
	if(wait) 
1999/0929    
		writewait(c); 
1999/0930    
	} 
1999/0915    
	poperror(); 
1999/0929    
	qunlock(c); 
1999/0915    
	qunlock(&c->out.controllk); 
1999/0930/sys/src/9/port/devsdp.c:1424,14301999/1001/sys/src/9/port/devsdp.c:1574,1582
1999/0915    
static long 
writedata(Conv *c, Block *b) 
{ 
	int n; 
1999/1001    
	int n, nn; 
	ulong seq; 
	Block *bb; 
1999/0915    
 
	qlock(c); 
	if(waserror()) { 
1999/0930/sys/src/9/port/devsdp.c:1440,14471999/1001/sys/src/9/port/devsdp.c:1592,1627
1999/0915    
	n = BLEN(b); 
1999/0930    
	c->lstats.outDataPackets++; 
	c->lstats.outDataBytes += n; 
	c->lstats.outCompDataBytes += n; 
1999/0915    
	convoput(c, TData, b); 
1999/1001    
 
	if(0) { 
		c->lstats.outCompDataBytes += n; 
		convoput(c, TData, b); 
		poperror(); 
		qunlock(c); 
		return n; 
	} 
	b = padblock(b, 4); 
	b->rp[0] = (c->in.window>>1) & 0xff; 
	b->rp[1] = c->in.seq>>16; 
	b->rp[2] = c->in.seq>>8; 
	b->rp[3] = c->in.seq; 
 
	// must generate same value as convoput 
	seq = (c->out.seq + 1) & (SeqMax-1); 
 
	bb = allocb(BLEN(b)); 
	nn = thwack(c->out.compstate, bb->wp, b->rp, BLEN(b), seq); 
	if(nn < 0) { 
		c->lstats.outCompDataBytes += BLEN(b); 
		convoput(c, TThwackU, b); 
		freeb(bb); 
	} else { 
		c->lstats.outCompDataBytes += nn; 
		bb->wp += nn; 
		convoput(c, TThwackC, bb); 
		freeb(b); 
	} 
 
1999/0915    
	poperror(); 
	qunlock(c); 
	return n; 
1999/1001/sys/src/9/port/devsdp.c:17,231999/1015/sys/src/9/port/devsdp.c:17,22 (short | long)
1999/0902    
typedef struct Conv Conv; 
1999/0907    
typedef struct OneWay OneWay; 
1999/0929    
typedef struct Stats Stats; 
1999/0907    
typedef struct ConnectPkt ConnectPkt; 
1999/0929    
typedef struct AckPkt AckPkt; 
1999/1001    
typedef struct Algorithm Algorithm; 
1999/0824    
 
1999/1001/sys/src/9/port/devsdp.c:43,491999/1015/sys/src/9/port/devsdp.c:42,48
1999/0907    
	Nfs= 4,				// number of file systems 
1999/1001    
	MaxRetries=	8, 
1999/0909    
	KeepAlive = 60,		// keep alive in seconds 
1999/0907    
	KeyLength= 32, 
1999/1015    
	SecretLength= 32,	// a secret per direction 
1999/1001    
	SeqMax = (1<<24), 
	SeqWindow = 32, 
1999/0824    
}; 
1999/1001/sys/src/9/port/devsdp.c:78,831999/1015/sys/src/9/port/devsdp.c:77,84
1999/0901    
	ulong	seq; 
1999/0907    
	ulong	window; 
1999/0901    
 
1999/1015    
	uchar	secret[SecretLength]; 
 
1999/0915    
	QLock	controllk; 
1999/0907    
	Rendez	controlready; 
1999/0902    
	Block	*controlpkt;		// control channel 
1999/1001/sys/src/9/port/devsdp.c:93,991999/1015/sys/src/9/port/devsdp.c:94,100
1999/0907    
	int		(*auth)(OneWay*, uchar *buf, int len); 
1999/0902    
 
	void	*compstate; 
1999/0907    
	int		(*comp)(OneWay*, uchar *dst, uchar *src, int n); 
1999/1015    
	int		(*comp)(OneWay*, int subtype, Block **); 
1999/0901    
}; 
 
1999/0907    
// conv states 
1999/1001/sys/src/9/port/devsdp.c:137,1431999/1015/sys/src/9/port/devsdp.c:138,143
1999/0907    
	char owner[NAMELEN];		/* protections */ 
1999/0901    
	int	perm; 
 
1999/0907    
	uchar	masterkey[KeyLength]; 
1999/1001    
	char *authname; 
	char *ciphername; 
	char *compname; 
1999/1001/sys/src/9/port/devsdp.c:160,1721999/1015/sys/src/9/port/devsdp.c:160,175
1999/0906    
enum { 
	TConnect, 
	TControl, 
	TControlAck, 
	TData, 
	TThwackC, 
	TThwackU, 
1999/1015    
	TCompData, 
1999/0906    
}; 
 
enum { 
1999/1015    
	ControlMesg, 
	ControlAck, 
}; 
 
enum { 
1999/0909    
	ConOpenRequest, 
1999/0906    
	ConOpenAck, 
1999/0910    
	ConOpenAckAck, 
1999/1001/sys/src/9/port/devsdp.c:174,1881999/1015/sys/src/9/port/devsdp.c:177,182
1999/0909    
	ConReset, 
1999/0906    
}; 
 
1999/0907    
struct ConnectPkt 
1999/0906    
{ 
	uchar type;		// always zero = connection packet 
	uchar op; 
	uchar pad[2]; 
	uchar dialid[4]; 
	uchar acceptid[4]; 
}; 
                 
1999/0929    
struct AckPkt 
{ 
	uchar	cseq[4]; 
1999/1001/sys/src/9/port/devsdp.c:222,2521999/1015/sys/src/9/port/devsdp.c:216,221
1999/0929    
	"rstats",	{Qrstats},	0,	0444, 
1999/0824    
}; 
 
1999/1001    
#ifdef XXX 
static Algorithm cipheralg[] = 
{ 
	"null",			0,	nullcipherinit, 
	"des_56_cbc",	7,	descipherinit, 
	"rc4_128",		16,	rc4cipherinit, 
	nil,			0,	nil, 
}; 
                 
static Algorithm authalg[] = 
{ 
	"null",			0,	nullauthinit, 
	"hmac_sha_96",	16,	shaauthinit, 
	"hmac_md5_96",	16,	md5authinit, 
	nil,			0,	nil, 
}; 
                 
static Algorithm compalg[] = 
{ 
	"null",			0,	nullcompinit, 
	"thwack",		0,	thwackcompinit, 
	nil,			0,	nil, 
}; 
#endif 
                 
1999/0824    
static int m2p[] = { 
	[OREAD]		4, 
	[OWRITE]	2, 
1999/1001/sys/src/9/port/devsdp.c:287,3031999/1015/sys/src/9/port/devsdp.c:256,310
1999/0907    
static int readready(void *a); 
static int controlread(); 
static Block *conviput(Conv *c, Block *b, int control); 
static void conviput2(Conv *c, Block *b); 
1999/1015    
static void conviconnect(Conv *c, int op, Block *b); 
static void convicontrol(Conv *c, int op, Block *b); 
static Block *convicomp(Conv *c, int op, Block *b); 
1999/0929    
static void writecontrol(Conv *c, void *p, int n, int wait); 
1999/0907    
static Block *readcontrol(Conv *c, int n); 
static Block *readdata(Conv *c, int n); 
1999/0915    
static long writedata(Conv *c, Block *b); 
1999/0907    
static void convoput(Conv *c, int type, Block *b); 
static void convoput2(Conv *c, int op, ulong dialid, ulong acceptid); 
1999/1015    
static void convoput(Conv *c, int type, int subtype, Block *b); 
static void convoconnect(Conv *c, int op, ulong dialid, ulong acceptid); 
1999/0910    
static void convreader(void *a); 
1999/0914    
static void convopenchan(Conv *c, char *path); 
1999/0929    
static void convstats(Conv *c, int local, char *buf, int n); 
1999/0824    
 
1999/1015    
static void setalg(Conv *c, char *name, Algorithm *tab); 
static void setsecret(OneWay *cc, char *secret); 
 
static void nullcipherinit(Conv*c, char *name, int keylen); 
static void descipherinit(Conv*c, char *name, int keylen); 
static void rc4cipherinit(Conv*c, char *name, int keylen); 
static void nullauthinit(Conv*c, char *name, int keylen); 
static void shaauthinit(Conv*c, char *name, int keylen); 
static void md5authinit(Conv*c, char *name, int keylen); 
static void nullcompinit(Conv*c, char *name, int keylen); 
static void thwackcompinit(Conv*c, char *name, int keylen); 
 
static Algorithm cipheralg[] = 
{ 
	"null",			0,	nullcipherinit, 
	"des_56_cbc",	7,	descipherinit, 
	"rc4_128",		16,	rc4cipherinit, 
	nil,			0,	nil, 
}; 
 
static Algorithm authalg[] = 
{ 
	"null",			0,	nullauthinit, 
	"hmac_sha_96",	16,	shaauthinit, 
	"hmac_md5_96",	16,	md5authinit, 
	nil,			0,	nil, 
}; 
 
static Algorithm compalg[] = 
{ 
	"null",			0,	nullcompinit, 
	"thwack",		0,	thwackcompinit, 
	nil,			0,	nil, 
}; 
 
 
1999/0824    
static void 
sdpinit(void) 
{ 
1999/1001/sys/src/9/port/devsdp.c:597,6021999/1015/sys/src/9/port/devsdp.c:604,629
1999/0906    
			if(cb->nf != 2) 
				error("usage: drop permil"); 
			c->drop = atoi(cb->f[1]); 
1999/1015    
		} else if(strcmp(arg0, "cipher") == 0) { 
			if(cb->nf != 2) 
				error("usage: cipher alg"); 
			setalg(c, cb->f[1], cipheralg); 
		} else if(strcmp(arg0, "auth") == 0) { 
			if(cb->nf != 2) 
				error("usage: auth alg"); 
			setalg(c, cb->f[1], authalg); 
		} else if(strcmp(arg0, "comp") == 0) { 
			if(cb->nf != 2) 
				error("usage: comp alg"); 
			setalg(c, cb->f[1], compalg); 
		} else if(strcmp(arg0, "insecret") == 0) { 
			if(cb->nf != 2) 
				error("usage: insecret secret"); 
			setsecret(&c->in, cb->f[1]); 
		} else if(strcmp(arg0, "outsecret") == 0) { 
			if(cb->nf != 2) 
				error("usage: outsecret secret"); 
			setsecret(&c->out, cb->f[1]); 
1999/0824    
		} else 
			error("unknown control request"); 
		poperror(); 
1999/1001/sys/src/9/port/devsdp.c:739,7451999/1015/sys/src/9/port/devsdp.c:766,772
1999/0909    
	c->retries = 0; 
	// +2 to avoid rounding effects. 
	c->timeout = TK2SEC(m->ticks) + 2; 
}; 
1999/1015    
} 
1999/0909    
 
// assume c is locked 
1999/0906    
static int 
1999/1001/sys/src/9/port/devsdp.c:750,7561999/1015/sys/src/9/port/devsdp.c:777,783
1999/0909    
	if(c->retries > MaxRetries) { 
1999/0906    
print("convretry: giving up\n"); 
1999/0914    
		if(reset) 
			convoput2(c, ConReset, c->dialid, c->acceptid); 
1999/1015    
			convoconnect(c, ConReset, c->dialid, c->acceptid); 
1999/0906    
		convsetstate(c, CClosed); 
		return 0; 
	} 
1999/1001/sys/src/9/port/devsdp.c:773,7891999/1015/sys/src/9/port/devsdp.c:800,816
1999/0906    
	switch(c->state) { 
1999/0909    
	case CDial: 
1999/0914    
		if(convretry(c, 1)) 
1999/0909    
			convoput2(c, ConOpenRequest, c->dialid, 0); 
1999/1015    
			convoconnect(c, ConOpenRequest, c->dialid, 0); 
1999/0906    
		break; 
1999/0909    
	case CAccept: 
1999/0914    
		if(convretry(c, 1)) 
1999/0909    
			convoput2(c, ConOpenAck, c->dialid, c->acceptid); 
1999/1015    
			convoconnect(c, ConOpenAck, c->dialid, c->acceptid); 
1999/0909    
		break; 
1999/0906    
	case COpen: 
1999/0914    
		b = c->out.controlpkt; 
		if(b != nil) { 
			if(convretry(c, 1)) 
				convoput(c, TControl, copyblock(b, blocklen(b))); 
1999/1015    
				convoput(c, TControl, ControlMesg, copyblock(b, blocklen(b))); 
1999/1001    
			break; 
1999/0914    
		} 
1999/1001    
 
1999/1001/sys/src/9/port/devsdp.c:802,8141999/1015/sys/src/9/port/devsdp.c:829,841
1999/1001    
		c->out.controlpkt = b; 
		convretryinit(c); 
		if(!waserror()) { 
			convoput(c, TControl, copyblock(b, blocklen(b))); 
1999/1015    
			convoput(c, TControl, ControlMesg, copyblock(b, blocklen(b))); 
1999/1001    
			poperror(); 
		} 
1999/0906    
		break; 
1999/0910    
	case CLocalClose: 
1999/0914    
		if(convretry(c, 0)) 
1999/0907    
			convoput2(c, ConClose, c->dialid, c->acceptid); 
1999/1015    
			convoconnect(c, ConClose, c->dialid, c->acceptid); 
1999/0906    
		break; 
1999/0914    
	case CRemoteClose: 
	case CClosed: 
1999/1001/sys/src/9/port/devsdp.c:878,9071999/1015/sys/src/9/port/devsdp.c:905,943
1999/0909    
		assert(c->state == CInit); 
1999/0906    
		c->dialid = (rand()<<16) + rand(); 
1999/0909    
		convretryinit(c); 
		convoput2(c, ConOpenRequest, c->dialid, 0); 
1999/1015    
		convoconnect(c, ConOpenRequest, c->dialid, 0); 
1999/0906    
		break; 
1999/0909    
	case CAccept: 
		assert(c->state == CInit); 
		c->acceptid = (rand()<<16) + rand(); 
		convretryinit(c); 
		convoput2(c, ConOpenAck, c->dialid, c->acceptid); 
1999/1015    
		convoconnect(c, ConOpenAck, c->dialid, c->acceptid); 
1999/0909    
		break; 
1999/0906    
	case COpen: 
1999/0909    
		assert(c->state == CDial || c->state == CAccept); 
		if(c->state == CDial) { 
			convretryinit(c); 
1999/0910    
			convoput2(c, ConOpenAckAck, c->dialid, c->acceptid); 
1999/1015    
			convoconnect(c, ConOpenAckAck, c->dialid, c->acceptid); 
			hnputl(c->in.secret, c->acceptid); 
			hnputl(c->in.secret+4, c->dialid); 
			hnputl(c->out.secret, c->dialid); 
			hnputl(c->out.secret+4, c->acceptid); 
		} else { 
			hnputl(c->in.secret, c->dialid); 
			hnputl(c->in.secret+4, c->acceptid); 
			hnputl(c->out.secret, c->acceptid); 
			hnputl(c->out.secret+4, c->dialid); 
1999/0906    
		} 
		// setup initial key and auth method 
1999/1015    
		md5authinit(c, "hmac_md5_96", 16); 
1999/0906    
		break; 
1999/0910    
	case CLocalClose: 
		assert(c->state == CAccept || c->state == COpen); 
1999/0909    
		convretryinit(c); 
1999/0907    
		convoput2(c, ConClose, c->dialid, c->acceptid); 
1999/1015    
		convoconnect(c, ConClose, c->dialid, c->acceptid); 
1999/0906    
		break; 
1999/0910    
	case CRemoteClose: 
1999/0914    
		wakeup(&c->in.controlready); 
1999/0910    
		convoput2(c, ConReset, c->dialid, c->acceptid); 
1999/1015    
		convoconnect(c, ConReset, c->dialid, c->acceptid); 
1999/0910    
		break; 
1999/0906    
	case CClosed: 
1999/0914    
		wakeup(&c->in.controlready); 
1999/1001/sys/src/9/port/devsdp.c:938,9441999/1015/sys/src/9/port/devsdp.c:974,979
1999/1001    
		c->timeout = ~0; 
1999/0907    
		c->retries = 0; 
		c->drop = 0; 
		memset(c->masterkey, 0, sizeof(c->masterkey)); 
		onewaycleanup(&c->in); 
		onewaycleanup(&c->out); 
1999/1001    
		memset(&c->lstats, 0, sizeof(Stats)); 
1999/1001/sys/src/9/port/devsdp.c:1046,10521999/1015/sys/src/9/port/devsdp.c:1081,1087
1999/0929    
	hnputl(ack->inReorder, s->inReorder); 
	hnputl(ack->inBadAuth, s->inBadAuth); 
	hnputl(ack->inBadSeq, s->inBadSeq); 
	convoput(c, TControlAck, b); 
1999/1015    
	convoput(c, TControl, ControlAck, b); 
1999/0929    
} 
 
 
1999/1001/sys/src/9/port/devsdp.c:1054,10651999/1015/sys/src/9/port/devsdp.c:1089,1097
1999/0907    
static Block * 
conviput(Conv *c, Block *b, int control) 
{ 
1999/1001    
	int type, n; 
	ulong seq, seqwrap, cseq; 
1999/1015    
	int type, subtype; 
	ulong seq, seqwrap; 
1999/1001    
	long seqdiff; 
1999/0929    
	AckPkt *ack; 
1999/1001    
	ulong mseq, mask; 
	Block *bb; 
1999/0907    
 
1999/0930    
	c->lstats.inPackets++; 
1999/0929    
 
1999/1001/sys/src/9/port/devsdp.c:1068,10811999/1015/sys/src/9/port/devsdp.c:1100,1115
1999/0907    
		return nil; 
	} 
	 
	type = b->rp[0]; 
1999/1015    
	type = b->rp[0] >> 4; 
	subtype = type & 0xf; 
	b->rp += 1; 
1999/0907    
	if(type == TConnect) { 
		conviput2(c, b); 
1999/1015    
		conviconnect(c, subtype, b); 
1999/0907    
		return nil; 
	} 
 
	seq = (b->rp[1]<<16) + (b->rp[2]<<8) + b->rp[3]; 
	b->rp += 4; 
1999/1015    
	seq = (b->rp[0]<<16) + (b->rp[1]<<8) + b->rp[2]; 
	b->rp += 3; 
1999/0907    
 
1999/1001    
	seqwrap = c->in.seqwrap; 
	seqdiff = seq - c->in.seq; 
1999/1001/sys/src/9/port/devsdp.c:1107,11131999/1015/sys/src/9/port/devsdp.c:1141,1156
1999/1001    
 
	// ok the sequence number looks ok 
1999/0930    
if(0) print("coniput seq=%ulx\n", seq); 
1999/0907    
	// auth 
1999/1015    
	if(c->in.auth != 0) { 
		if(!(*c->in.auth)(&c->in, b->rp-4, BLEN(b)+4)) { 
print("bad auth\n"); 
			c->lstats.inBadAuth++; 
			freeb(b); 
			return nil; 
		} 
		b->wp -= c->in.authlen; 
	} 
 
1999/0907    
	// decrypt 
 
	// ok the packet is good 
1999/1001/sys/src/9/port/devsdp.c:1132,12271999/1015/sys/src/9/port/devsdp.c:1175,1198
1999/0907    
 
	switch(type) { 
	case TControl: 
1999/0929    
		if(BLEN(b) < 4) 
1999/0907    
			break; 
		cseq = nhgetl(b->rp); 
		if(cseq == c->in.controlseq) { 
1999/0914    
print("duplicate control packet: %ulx\n", cseq); 
1999/0907    
			// duplicate control packet 
1999/0929    
			freeb(b); 
			if(c->in.controlpkt == nil) 
				convack(c); 
1999/0907    
			return nil; 
		} 
                 
		if(cseq != c->in.controlseq+1) 
			break; 
		c->in.controlseq = cseq; 
		b->rp += 4; 
1999/0929    
		if(BLEN(b) == 0) { 
			// just a ping 
			freeb(b); 
			convack(c); 
		} else { 
			c->in.controlpkt = b; 
1999/0930    
if(0) print("recv %ld size=%ld\n", cseq, BLEN(b)); 
1999/0929    
			wakeup(&c->in.controlready); 
		} 
1999/1015    
		convicontrol(c, subtype, b); 
1999/0907    
		return nil; 
	case TControlAck: 
1999/0929    
		if(BLEN(b) != sizeof(AckPkt)) 
1999/0907    
			break; 
1999/0929    
		ack = (AckPkt*)(b->rp); 
		cseq = nhgetl(ack->cseq); 
1999/0930    
		if(cseq != c->out.controlseq) { 
1999/0914    
print("ControlAck expected %ulx got %ulx\n", c->out.controlseq, cseq); 
1999/0907    
			break; 
1999/0930    
		} 
		c->rstats.outPackets = nhgetl(ack->outPackets); 
		c->rstats.outDataPackets = nhgetl(ack->outDataPackets); 
		c->rstats.outDataBytes = nhgetl(ack->outDataBytes); 
		c->rstats.outCompDataBytes = nhgetl(ack->outCompDataBytes); 
		c->rstats.inPackets = nhgetl(ack->inPackets); 
		c->rstats.inDataPackets = nhgetl(ack->inDataPackets); 
		c->rstats.inDataBytes = nhgetl(ack->inDataBytes); 
		c->rstats.inCompDataBytes = nhgetl(ack->inCompDataBytes); 
		c->rstats.inMissing = nhgetl(ack->inMissing); 
		c->rstats.inDup = nhgetl(ack->inDup); 
		c->rstats.inReorder = nhgetl(ack->inReorder); 
		c->rstats.inBadAuth = nhgetl(ack->inBadAuth); 
		c->rstats.inBadSeq = nhgetl(ack->inBadSeq); 
1999/0907    
		freeb(b); 
		freeb(c->out.controlpkt); 
1999/0914    
		c->out.controlpkt = nil; 
1999/1001    
		c->timeout = c->lastrecv + KeepAlive; 
1999/0907    
		wakeup(&c->out.controlready); 
		return nil; 
	case TData: 
1999/0929    
		c->lstats.inDataPackets++; 
		c->lstats.inDataBytes += BLEN(b); 
		c->lstats.inCompDataBytes += BLEN(b); 
1999/0907    
		if(control) 
			break; 
		return b; 
1999/1001    
	case TThwackU: 
1999/1015    
	case TCompData: 
1999/1001    
		c->lstats.inDataPackets++; 
		c->lstats.inCompDataBytes += BLEN(b); 
		mask = b->rp[0]; 
		mseq = (b->rp[1]<<16) | (b->rp[2]<<8) | b->rp[3]; 
		b->rp += 4; 
		thwackack(c->out.compstate, mseq, mask); 
1999/1015    
		b = convicomp(c, subtype, b); 
		if(b == nil); 
			return nil; 
1999/1001    
		c->lstats.inDataBytes += BLEN(b); 
		if(control) 
			break; 
		return b; 
	case TThwackC: 
		c->lstats.inDataPackets++; 
		c->lstats.inCompDataBytes += BLEN(b); 
		bb = b; 
		b = allocb(ThwMaxBlock); 
		n = unthwack(c->in.compstate, b->wp, ThwMaxBlock, bb->rp, BLEN(bb), seq); 
		freeb(bb); 
		if(n < 0) 
			break; 
		b->wp += n; 
		mask = b->rp[0]; 
		mseq = (b->rp[1]<<16) | (b->rp[2]<<8) | b->rp[3]; 
		thwackack(c->out.compstate, mseq, mask); 
		b->rp += 4; 
		c->lstats.inDataBytes += BLEN(b); 
		if(control) 
			break; 
		return b; 
1999/0907    
	} 
print("droping packet %d n=%ld\n", type, BLEN(b)); 
	freeb(b); 
1999/1001/sys/src/9/port/devsdp.c:1230,12501999/1015/sys/src/9/port/devsdp.c:1201,1220
1999/0907    
 
// assume hold conv lock 
static void 
conviput2(Conv *c, Block *b) 
1999/1015    
conviconnect(Conv *c, int subtype, Block *b) 
1999/0907    
{ 
	ConnectPkt *con; 
	ulong dialid; 
	ulong acceptid; 
 
	if(BLEN(b) != sizeof(ConnectPkt)) { 
1999/1015    
	if(BLEN(b) != 8) { 
1999/0907    
		freeb(b); 
		return; 
	} 
	con = (ConnectPkt*)b->rp; 
	dialid = nhgetl(con->dialid); 
	acceptid = nhgetl(con->acceptid); 
1999/1015    
	dialid = nhgetl(b->rp); 
	acceptid = nhgetl(b->rp + 4); 
	freeb(b); 
1999/0907    
 
1999/0914    
print("conviput2: %s: %d %uld %uld\n", convstatename[c->state], con->op, dialid, acceptid); 
1999/1015    
print("conviconnect: %s: %d %uld %uld\n", convstatename[c->state], subtype, dialid, acceptid); 
1999/0914    
 
1999/0910    
	switch(c->state) { 
	default: 
1999/1001/sys/src/9/port/devsdp.c:1259,12651999/1015/sys/src/9/port/devsdp.c:1229,1236
1999/0910    
	case COpen: 
	case CLocalClose: 
	case CRemoteClose: 
		if(dialid != c->dialid || acceptid != c->acceptid) 
1999/1015    
		if(dialid != c->dialid 
		|| subtype != ConOpenRequest && acceptid != c->acceptid) 
1999/0910    
			goto Reset; 
		break; 
	case CClosed: 
1999/1001/sys/src/9/port/devsdp.c:1266,12721999/1015/sys/src/9/port/devsdp.c:1237,1243
1999/0910    
		goto Reset; 
	} 
 
1999/0907    
	switch(con->op) { 
1999/1015    
	switch(subtype) { 
1999/0909    
	case ConOpenRequest: 
		switch(c->state) { 
		case CInit: 
1999/1001/sys/src/9/port/devsdp.c:1287,12931999/1015/sys/src/9/port/devsdp.c:1258,1264
1999/0910    
			return; 
		case COpen: 
			// duplicate that we have to ack 
			convoput2(c, ConOpenAckAck, acceptid, dialid); 
1999/1015    
			convoconnect(c, ConOpenAckAck, acceptid, dialid); 
1999/0910    
			return; 
		} 
		break; 
1999/1001/sys/src/9/port/devsdp.c:1302,13081999/1015/sys/src/9/port/devsdp.c:1273,1279
1999/0909    
		} 
1999/0907    
		break; 
	case ConClose: 
1999/0910    
		convoput2(c, ConReset, dialid, acceptid); 
1999/1015    
		convoconnect(c, ConReset, dialid, acceptid); 
1999/0909    
		switch(c->state) { 
1999/0910    
		case CInit: 
1999/0909    
		case CDial: 
1999/1001/sys/src/9/port/devsdp.c:1316,13221999/1015/sys/src/9/port/devsdp.c:1287,1293
1999/0910    
		case CRemoteClose: 
			return; 
1999/0909    
		} 
1999/0910    
		return; 
1999/1015    
		break; 
1999/0910    
	case ConReset: 
		switch(c->state) { 
		case CInit: 
1999/1001/sys/src/9/port/devsdp.c:1329,13421999/1015/sys/src/9/port/devsdp.c:1300,1390
1999/0910    
		case CRemoteClose: 
			return; 
		} 
		return; 
1999/1015    
		break; 
1999/0907    
	} 
1999/0910    
Reset: 
	// invalid connection message - reset to sender 
1999/0914    
print("invalid conviput2 - sending reset\n"); 
1999/0910    
	convoput2(c, ConReset, dialid, acceptid); 
1999/1015    
print("invalid conviconnect - sending reset\n"); 
	convoconnect(c, ConReset, dialid, acceptid); 
1999/0907    
} 
 
1999/1015    
static void 
convicontrol(Conv *c, int subtype, Block *b) 
{ 
	ulong cseq; 
	AckPkt *ack; 
 
	if(BLEN(b) < 4) 
		return; 
	cseq = nhgetl(b->rp); 
	 
	switch(subtype){ 
	case ControlMesg: 
		if(cseq == c->in.controlseq) { 
print("duplicate control packet: %ulx\n", cseq); 
			// duplicate control packet 
			freeb(b); 
			if(c->in.controlpkt == nil) 
				convack(c); 
			return; 
		} 
 
		if(cseq != c->in.controlseq+1) 
			return; 
		c->in.controlseq = cseq; 
		b->rp += 4; 
		if(BLEN(b) == 0) { 
			// just a ping 
			freeb(b); 
			convack(c); 
		} else { 
			c->in.controlpkt = b; 
if(0) print("recv %ld size=%ld\n", cseq, BLEN(b)); 
			wakeup(&c->in.controlready); 
		} 
		return; 
	case ControlAck: 
		if(cseq != c->out.controlseq) { 
print("ControlAck expected %ulx got %ulx\n", c->out.controlseq, cseq); 
			return; 
		} 
		if(BLEN(b) < sizeof(AckPkt)) 
			return; 
		ack = (AckPkt*)(b->rp); 
		c->rstats.outPackets = nhgetl(ack->outPackets); 
		c->rstats.outDataPackets = nhgetl(ack->outDataPackets); 
		c->rstats.outDataBytes = nhgetl(ack->outDataBytes); 
		c->rstats.outCompDataBytes = nhgetl(ack->outCompDataBytes); 
		c->rstats.inPackets = nhgetl(ack->inPackets); 
		c->rstats.inDataPackets = nhgetl(ack->inDataPackets); 
		c->rstats.inDataBytes = nhgetl(ack->inDataBytes); 
		c->rstats.inCompDataBytes = nhgetl(ack->inCompDataBytes); 
		c->rstats.inMissing = nhgetl(ack->inMissing); 
		c->rstats.inDup = nhgetl(ack->inDup); 
		c->rstats.inReorder = nhgetl(ack->inReorder); 
		c->rstats.inBadAuth = nhgetl(ack->inBadAuth); 
		c->rstats.inBadSeq = nhgetl(ack->inBadSeq); 
		freeb(b); 
		freeb(c->out.controlpkt); 
		c->out.controlpkt = nil; 
		c->timeout = c->lastrecv + KeepAlive; 
		wakeup(&c->out.controlready); 
		return; 
	} 
} 
 
static Block* 
convicomp(Conv *c, int subtype, Block *b) 
{ 
	if(c->in.comp == nil) { 
		freeb(b); 
		return nil; 
	} 
	if((*c->in.comp)(&c->in, subtype, &b) < 0) 
		return nil; 
	return b; 
} 
 
1999/0930    
// c is locked 
static void 
convwriteblock(Conv *c, Block *b) 
1999/1001/sys/src/9/port/devsdp.c:1356,13681999/1015/sys/src/9/port/devsdp.c:1404,1416
1999/0930    
 
1999/0907    
// assume hold conv lock 
static void 
convoput(Conv *c, int type, Block *b) 
1999/1015    
convoput(Conv *c, int type, int subtype, Block *b) 
1999/0907    
{ 
	// try and compress 
1999/0929    
	c->lstats.outPackets++; 
1999/0907    
	/* Make space to fit sdp header */ 
	b = padblock(b, 4 + c->out.cipherivlen); 
	b->rp[0] = type; 
1999/1015    
	b->rp[0] = (type << 4) | subtype; 
1999/0907    
	c->out.seq++; 
	if(c->out.seq == (1<<24)) { 
		c->out.seq = 0; 
1999/1001/sys/src/9/port/devsdp.c:1374,13791999/1015/sys/src/9/port/devsdp.c:1422,1432
1999/0907    
	 
	// encrypt 
	// auth 
1999/1015    
	if(c->out.auth) { 
		b = padblock(b, -c->out.authlen); 
		b->wp += c->out.authlen; 
		(*c->out.auth)(&c->out, b->rp, BLEN(b)); 
	} 
1999/0930    
	 
	convwriteblock(c, b); 
1999/0907    
} 
1999/1001/sys/src/9/port/devsdp.c:1380,13891999/1015/sys/src/9/port/devsdp.c:1433,1441
1999/0907    
 
// assume hold conv lock 
static void 
convoput2(Conv *c, int op, ulong dialid, ulong acceptid) 
1999/1015    
convoconnect(Conv *c, int op, ulong dialid, ulong acceptid) 
1999/0907    
{ 
1999/0930    
	Block *b; 
	ConnectPkt *con; 
1999/0907    
 
1999/0929    
	c->lstats.outPackets++; 
1999/0906    
	if(c->chan == nil) { 
1999/1001/sys/src/9/port/devsdp.c:1390,14021999/1015/sys/src/9/port/devsdp.c:1442,1452
1999/0906    
print("chan = nil\n"); 
		error("no channel attached"); 
	} 
1999/0930    
	b = allocb(sizeof(ConnectPkt)); 
	con = (ConnectPkt*)b->wp; 
	b->wp += sizeof(ConnectPkt); 
	con->type = TConnect; 
	con->op = op; 
	hnputl(con->dialid, dialid); 
	hnputl(con->acceptid, acceptid); 
1999/1015    
	b = allocb(9); 
	b->wp[0] = (TConnect << 4) | op; 
	hnputl(b->wp+1, dialid); 
	hnputl(b->wp+5, acceptid); 
	b->wp += 9; 
1999/0906    
 
1999/0930    
	convwriteblock(c, b); 
1999/0907    
} 
1999/1001/sys/src/9/port/devsdp.c:1525,15311999/1015/sys/src/9/port/devsdp.c:1575,1580
1999/0929    
{ 
	Block *b; 
 
                 
	qlock(&c->out.controllk); 
	qlock(c); 
	if(waserror()) { 
1999/1001/sys/src/9/port/devsdp.c:1541,15471999/1015/sys/src/9/port/devsdp.c:1590,1596
1999/0914    
	b->wp += 4+n; 
	c->out.controlpkt = b; 
	convretryinit(c); 
	convoput(c, TControl, copyblock(b, blocklen(b))); 
1999/1015    
	convoput(c, TControl, ControlMesg, copyblock(b, blocklen(b))); 
1999/1001    
	if(wait) 
1999/0929    
		writewait(c); 
1999/0915    
	poperror(); 
1999/1001/sys/src/9/port/devsdp.c:1574,15821999/1015/sys/src/9/port/devsdp.c:1623,1629
1999/0915    
static long 
writedata(Conv *c, Block *b) 
{ 
1999/1001    
	int n, nn; 
	ulong seq; 
	Block *bb; 
1999/1015    
	int n; 
1999/0915    
 
	qlock(c); 
	if(waserror()) { 
1999/1001/sys/src/9/port/devsdp.c:1593,16261999/1015/sys/src/9/port/devsdp.c:1640,1651
1999/0930    
	c->lstats.outDataPackets++; 
	c->lstats.outDataBytes += n; 
1999/1001    
 
	if(0) { 
		c->lstats.outCompDataBytes += n; 
		convoput(c, TData, b); 
		poperror(); 
		qunlock(c); 
		return n; 
	} 
	b = padblock(b, 4); 
	b->rp[0] = (c->in.window>>1) & 0xff; 
	b->rp[1] = c->in.seq>>16; 
	b->rp[2] = c->in.seq>>8; 
	b->rp[3] = c->in.seq; 
                 
	// must generate same value as convoput 
	seq = (c->out.seq + 1) & (SeqMax-1); 
                 
	bb = allocb(BLEN(b)); 
	nn = thwack(c->out.compstate, bb->wp, b->rp, BLEN(b), seq); 
	if(nn < 0) { 
1999/1015    
	if(c->out.comp != nil) { 
		int subtype = (*c->out.comp)(&c->out, 0, &b); 
1999/1001    
		c->lstats.outCompDataBytes += BLEN(b); 
		convoput(c, TThwackU, b); 
		freeb(bb); 
	} else { 
		c->lstats.outCompDataBytes += nn; 
		bb->wp += nn; 
		convoput(c, TThwackC, bb); 
		freeb(b); 
	} 
1999/1015    
		convoput(c, TCompData, subtype, b); 
	} else 
		convoput(c, TData, 0, b); 
1999/1001    
 
1999/0915    
	poperror(); 
	qunlock(c); 
1999/1001/sys/src/9/port/devsdp.c:1663,16651999/1015/sys/src/9/port/devsdp.c:1688,2040
1999/0910    
	qunlock(c); 
	pexit("hangup", 1); 
1999/0906    
} 
1999/1015    
 
 
/* ciphers, authenticators, and compressors  */ 
 
static void 
setalg(Conv *c, char *name, Algorithm *alg) 
{ 
	for(; alg->name; alg++) 
		if(strcmp(name, alg->name) == 0) 
			break; 
	if(alg->name == nil) 
		error("unknown algorithm"); 
 
	alg->init(c, alg->name, alg->keylen); 
} 
 
static void 
setsecret(OneWay *ow, char *secret) 
{ 
	char *p; 
	int i, c; 
	 
	i = 0; 
	memset(ow->secret, 0, sizeof(ow->secret)); 
	for(p=secret; *p; p++) { 
		if(i >= sizeof(ow->secret)*2) 
			break; 
		c = *p; 
		if(c >= '0' && c <= '9') 
			c -= '0'; 
		else if(c >= 'a' && c <= 'f') 
			c -= 'a'-10; 
		else if(c >= 'A' && c <= 'F') 
			c -= 'A'-10; 
		else 
			error("bad character in secret"); 
		if((i&1) == 0) 
			c <<= 4; 
		ow->secret[i>>1] |= c; 
		i++; 
	} 
} 
 
static void 
setkey(uchar *key, int n, OneWay *ow, char *prefix) 
{ 
	uchar ibuf[SHAdlen], obuf[MD5dlen], salt[10]; 
	int i, round = 0; 
 
	while(n > 0){ 
		for(i=0; i<round+1; i++) 
			salt[i] = 'A'+round; 
		sha((uchar*)prefix, strlen(prefix), ibuf, sha(salt, round+1, nil, nil)); 
		md5(ibuf, SHAdlen, obuf, md5(ow->secret, sizeof(ow->secret), nil, nil)); 
		i = (n<MD5dlen) ? n : MD5dlen; 
		memmove(key, obuf, i); 
		key += i; 
		n -= i; 
		if(++round > sizeof salt) 
			panic("setkey: you ask too much"); 
	} 
} 
 
 
static void 
cipherfree(Conv *c) 
{ 
	if(c->ciphername) { 
		free(c->ciphername); 
		c->ciphername = nil; 
	} 
	if(c->in.cipherstate) { 
		free(c->in.cipherstate); 
		c->in.cipherstate = nil; 
	} 
	if(c->out.cipherstate) { 
		free(c->out.cipherstate); 
		c->out.cipherstate = nil; 
	} 
	c->in.cipher = nil; 
} 
 
static void 
authfree(Conv *c) 
{ 
	if(c->authname) { 
		free(c->authname); 
		c->authname = nil; 
	} 
	if(c->in.authstate) { 
		free(c->in.authstate); 
		c->in.authstate = nil; 
	} 
	if(c->out.authstate) { 
		free(c->out.authstate); 
		c->out.authstate = nil; 
	} 
	c->in.auth = nil; 
} 
 
static void 
compfree(Conv *c) 
{ 
	if(c->compname) { 
		free(c->compname); 
		c->compname = nil; 
	} 
	if(c->in.compstate) { 
		free(c->in.compstate); 
		c->in.compstate = nil; 
	} 
	if(c->out.compstate) { 
		free(c->out.compstate); 
		c->out.compstate = nil; 
	} 
	c->in.comp = nil; 
} 
 
 
static void 
nullcipherinit(Conv *c, char *, int) 
{ 
	cipherfree(c); 
} 
 
static int 
desencrypt(OneWay *ow, uchar *p, int n) 
{ 
	uchar *pp, *ip, *eip, *ep; 
	DESstate *ds = ow->cipherstate; 
 
	ep = p + n; 
	memmove(p, ds->ivec, 8); 
	for(p += 8; p < ep; p += 8){ 
		pp = p; 
		ip = ds->ivec; 
		for(eip = ip+8; ip < eip; ) 
			*pp++ ^= *ip++; 
		block_cipher(ds->expanded, p, 0); 
		memmove(ds->ivec, p, 8); 
	} 
	return 1; 
} 
 
static int 
desdecrypt(OneWay *ow, uchar *p, int n) 
{ 
	uchar tmp[8]; 
	uchar *tp, *ip, *eip, *ep; 
	DESstate *ds = ow->cipherstate; 
 
	ep = p + n; 
	memmove(ds->ivec, p, 8); 
	p += 8; 
	while(p < ep){ 
		memmove(tmp, p, 8); 
		block_cipher(ds->expanded, p, 1); 
		tp = tmp; 
		ip = ds->ivec; 
		for(eip = ip+8; ip < eip; ){ 
			*p++ ^= *ip; 
			*ip++ = *tp++; 
		} 
	} 
	return 1; 
} 
 
static void 
descipherinit(Conv *c, char *name, int n) 
{ 
	uchar key[8]; 
	uchar ivec[8]; 
	int i; 
 
	cipherfree(c); 
	c->ciphername = malloc(strlen(name)+1); 
	strcpy(c->ciphername, name); 
	 
	if(n > sizeof(key)) 
		n = sizeof(key); 
 
	/* in */ 
	memset(key, 0, sizeof(key)); 
	setkey(key, n, &c->in, "cipher"); 
	memset(ivec, 0, sizeof(ivec)); 
	c->in.cipherblklen = 8; 
	c->in.cipherivlen = 8; 
	c->in.cipher = desdecrypt; 
	c->in.cipherstate = smalloc(sizeof(DESstate)); 
	setupDESstate(c->in.cipherstate, key, ivec); 
	 
	/* out */ 
	memset(key, 0, sizeof(key)); 
	setkey(key, n, &c->out, "cipher"); 
	for(i=0; i<8; i++) 
		ivec[i] = nrand(256); 
	c->out.cipherblklen = 8; 
	c->out.cipherivlen = 8; 
	c->out.cipher = desencrypt; 
	c->out.cipherstate = smalloc(sizeof(DESstate)); 
	setupDESstate(c->out.cipherstate, key, ivec); 
} 
 
static void 
rc4cipherinit(Conv *c, char *name, int keylen) 
{ 
} 
 
static void 
nullauthinit(Conv *c, char *name, int keylen) 
{ 
	authfree(c); 
} 
 
static void 
shaauthinit(Conv *c, char *name, int keylen) 
{ 
	authfree(c); 
} 
 
static void 
hmac_md5(uchar hash[MD5dlen], ulong wrap, uchar *t, long tlen, uchar *key, long klen) 
{ 
	uchar ipad[65], opad[65], wbuf[4]; 
	int i; 
	DigestState *digest; 
	uchar innerhash[MD5dlen]; 
 
	for(i=0; i<64; i++){ 
		ipad[i] = 0x36; 
		opad[i] = 0x5c; 
	} 
	ipad[64] = opad[64] = 0; 
	for(i=0; i<klen; i++){ 
		ipad[i] ^= key[i]; 
		opad[i] ^= key[i]; 
	} 
	hnputl(wbuf, wrap); 
	digest = md5(ipad, 64, nil, nil); 
	digest = md5(wbuf, sizeof(wbuf), nil, digest); 
	md5(t, tlen, innerhash, digest); 
	digest = md5(opad, 64, nil, nil); 
	md5(innerhash, MD5dlen, hash, digest); 
} 
 
static int 
md5auth(OneWay *ow, uchar *t, int tlen) 
{ 
	uchar hash[MD5dlen]; 
	int r; 
 
	if(tlen < ow->authlen) 
		return 0; 
	tlen -= ow->authlen; 
 
	memset(hash, 0, MD5dlen); 
	hmac_md5(hash, ow->seqwrap, t, tlen, (uchar*)ow->authstate, 16); 
	r = memcmp(t+tlen, hash, ow->authlen) == 0; 
	memmove(t+tlen, hash, ow->authlen); 
	return r; 
} 
 
static void 
md5authinit(Conv *c, char *name, int keylen) 
{ 
	authfree(c); 
 
	c->authname = malloc(strlen(name)+1); 
	strcpy(c->authname, name); 
 
	if(keylen > 16) 
		keylen = 16; 
 
	/* in */ 
	c->in.authstate = smalloc(16); 
	memset(c->in.authstate, 0, 16); 
	setkey(c->in.authstate, keylen, &c->in, "auth"); 
	c->in.authlen = 12; 
	c->in.auth = md5auth; 
	 
	/* out */ 
	c->out.authstate = smalloc(16); 
	memset(c->out.authstate, 0, 16); 
	setkey(c->out.authstate, keylen, &c->out, "auth"); 
	c->out.authlen = 12; 
	c->out.auth = md5auth; 
} 
 
static void 
nullcompinit(Conv *c, char *name, int keylen) 
{ 
} 
 
static void 
thwackcompinit(Conv *c, char *name, int keylen) 
{ 
} 
 
 
#ifdef XXX 
	case TThwackU: 
		mask = b->rp[0]; 
		mseq = (b->rp[1]<<16) | (b->rp[2]<<8) | b->rp[3]; 
		b->rp += 4; 
		thwackack(c->out.compstate, mseq, mask); 
		c->lstats.inDataBytes += BLEN(b); 
		if(control) 
			break; 
		return b; 
	case TThwackC: 
		c->lstats.inDataPackets++; 
		c->lstats.inCompDataBytes += BLEN(b); 
		bb = b; 
		b = allocb(ThwMaxBlock); 
		n = unthwack(c->in.compstate, b->wp, ThwMaxBlock, bb->rp, BLEN(bb), seq); 
		freeb(bb); 
		if(n < 0) 
			break; 
		b->wp += n; 
		mask = b->rp[0]; 
		mseq = (b->rp[1]<<16) | (b->rp[2]<<8) | b->rp[3]; 
		thwackack(c->out.compstate, mseq, mask); 
		b->rp += 4; 
		c->lstats.inDataBytes += BLEN(b); 
		if(control) 
			break; 
		return b; 
	} 
	b = padblock(b, 4); 
	b->rp[0] = (c->in.window>>1) & 0xff; 
	b->rp[1] = c->in.seq>>16; 
	b->rp[2] = c->in.seq>>8; 
	b->rp[3] = c->in.seq; 
 
	// must generate same value as convoput 
	seq = (c->out.seq + 1) & (SeqMax-1); 
 
	bb = allocb(BLEN(b)); 
	nn = thwack(c->out.compstate, bb->wp, b->rp, BLEN(b), seq); 
	if(nn < 0) { 
		c->lstats.outCompDataBytes += BLEN(b); 
		convoput(c, TThwackU, b); 
		freeb(bb); 
	} else { 
		c->lstats.outCompDataBytes += nn; 
		bb->wp += nn; 
		convoput(c, TThwackC, bb); 
		freeb(b); 
	} 
#endif 
1999/1015/sys/src/9/port/devsdp.c:65,701999/1016/sys/src/9/port/devsdp.c:65,71 (short | long)
1999/0929    
	ulong	inMissing; 
	ulong	inDup; 
	ulong	inReorder; 
1999/1016    
	ulong	inBadComp; 
1999/0929    
	ulong	inBadAuth; 
	ulong	inBadSeq; 
}; 
1999/1015/sys/src/9/port/devsdp.c:94,1001999/1016/sys/src/9/port/devsdp.c:95,101
1999/0907    
	int		(*auth)(OneWay*, uchar *buf, int len); 
1999/0902    
 
	void	*compstate; 
1999/1015    
	int		(*comp)(OneWay*, int subtype, Block **); 
1999/1016    
	int		(*comp)(Conv*, int subtype, ulong seq, Block **); 
1999/0901    
}; 
 
1999/0907    
// conv states 
1999/1015/sys/src/9/port/devsdp.c:170,1751999/1016/sys/src/9/port/devsdp.c:171,181
1999/1015    
}; 
 
enum { 
1999/1016    
	ThwackU, 
	ThwackC, 
}; 
 
enum { 
1999/0909    
	ConOpenRequest, 
1999/0906    
	ConOpenAck, 
1999/0910    
	ConOpenAckAck, 
1999/1015/sys/src/9/port/devsdp.c:191,1961999/1016/sys/src/9/port/devsdp.c:197,203
1999/0929    
	uchar	inMissing[4]; 
	uchar	inDup[4]; 
	uchar	inReorder[4]; 
1999/1016    
	uchar	inBadComp[4]; 
1999/0929    
	uchar	inBadAuth[4]; 
	uchar	inBadSeq[4]; 
}; 
1999/1015/sys/src/9/port/devsdp.c:258,2641999/1016/sys/src/9/port/devsdp.c:265,271
1999/0907    
static Block *conviput(Conv *c, Block *b, int control); 
1999/1015    
static void conviconnect(Conv *c, int op, Block *b); 
static void convicontrol(Conv *c, int op, Block *b); 
static Block *convicomp(Conv *c, int op, Block *b); 
1999/1016    
static Block *convicomp(Conv *c, int op, ulong, Block *b); 
1999/0929    
static void writecontrol(Conv *c, void *p, int n, int wait); 
1999/0907    
static Block *readcontrol(Conv *c, int n); 
static Block *readdata(Conv *c, int n); 
1999/1015/sys/src/9/port/devsdp.c:748,7571999/1016/sys/src/9/port/devsdp.c:755,760
1999/0902    
	c->ref++; 
1999/0906    
	c->state = CInit; 
1999/1001    
	c->in.window = ~0; 
	c->in.compstate = malloc(sizeof(Unthwack)); 
	unthwackinit(c->in.compstate); 
	c->out.compstate = malloc(sizeof(Thwack)); 
	thwackinit(c->out.compstate); 
1999/0907    
	strncpy(c->owner, up->user, sizeof(c->owner)); 
1999/0901    
	c->perm = 0660; 
	qunlock(c); 
1999/1015/sys/src/9/port/devsdp.c:955,9721999/1016/sys/src/9/port/devsdp.c:958,966
1999/0910    
			free(c->channame); 
			c->channame = nil; 
		} 
1999/1001    
		if(c->ciphername) { 
			free(c->ciphername); 
			c->ciphername = nil; 
		} 
		if(c->authname) { 
			free(c->authname); 
			c->authname = nil; 
		} 
			if(c->compname) { 
			free(c->compname); 
			c->compname = nil; 
		} 
1999/1016    
		c->ciphername = nil; 
		c->authname = nil; 
		c->compname = nil; 
1999/1001    
	strcpy(c->owner, "network"); 
1999/0907    
		c->perm = 0660; 
		c->dialid = 0; 
1999/1015/sys/src/9/port/devsdp.c:1049,10541999/1016/sys/src/9/port/devsdp.c:1043,1049
1999/0929    
	p += snprint(p, ep-p, "inMissing: %ld\n", stats->inMissing); 
	p += snprint(p, ep-p, "inDup: %ld\n", stats->inDup); 
	p += snprint(p, ep-p, "inReorder: %ld\n", stats->inReorder); 
1999/1016    
	p += snprint(p, ep-p, "inBadComp: %ld\n", stats->inBadComp); 
1999/0929    
	p += snprint(p, ep-p, "inBadAuth: %ld\n", stats->inBadAuth); 
	p += snprint(p, ep-p, "inBadSeq: %ld\n", stats->inBadSeq); 
	USED(p); 
1999/1015/sys/src/9/port/devsdp.c:1079,10841999/1016/sys/src/9/port/devsdp.c:1074,1080
1999/0929    
	hnputl(ack->inMissing, s->inMissing); 
	hnputl(ack->inDup, s->inDup); 
	hnputl(ack->inReorder, s->inReorder); 
1999/1016    
	hnputl(ack->inBadComp, s->inBadComp); 
1999/0929    
	hnputl(ack->inBadAuth, s->inBadAuth); 
	hnputl(ack->inBadSeq, s->inBadSeq); 
1999/1015    
	convoput(c, TControl, ControlAck, b); 
1999/1015/sys/src/9/port/devsdp.c:1101,11071999/1016/sys/src/9/port/devsdp.c:1097,1103
1999/0907    
	} 
	 
1999/1015    
	type = b->rp[0] >> 4; 
	subtype = type & 0xf; 
1999/1016    
	subtype = b->rp[0] & 0xf; 
1999/1015    
	b->rp += 1; 
1999/0907    
	if(type == TConnect) { 
1999/1015    
		conviconnect(c, subtype, b); 
1999/1015/sys/src/9/port/devsdp.c:1186,11941999/1016/sys/src/9/port/devsdp.c:1182,1192
1999/1015    
	case TCompData: 
1999/1001    
		c->lstats.inDataPackets++; 
		c->lstats.inCompDataBytes += BLEN(b); 
1999/1015    
		b = convicomp(c, subtype, b); 
		if(b == nil); 
1999/1016    
		b = convicomp(c, subtype, seq, b); 
		if(b == nil) { 
			c->lstats.inBadComp++; 
1999/1015    
			return nil; 
1999/1016    
		} 
1999/1001    
		c->lstats.inDataBytes += BLEN(b); 
		if(control) 
			break; 
1999/1015/sys/src/9/port/devsdp.c:1362,13671999/1016/sys/src/9/port/devsdp.c:1360,1366
1999/1015    
		c->rstats.inMissing = nhgetl(ack->inMissing); 
		c->rstats.inDup = nhgetl(ack->inDup); 
		c->rstats.inReorder = nhgetl(ack->inReorder); 
1999/1016    
		c->rstats.inBadComp = nhgetl(ack->inBadComp); 
1999/1015    
		c->rstats.inBadAuth = nhgetl(ack->inBadAuth); 
		c->rstats.inBadSeq = nhgetl(ack->inBadSeq); 
		freeb(b); 
1999/1015/sys/src/9/port/devsdp.c:1374,13861999/1016/sys/src/9/port/devsdp.c:1373,1385
1999/1015    
} 
 
static Block* 
convicomp(Conv *c, int subtype, Block *b) 
1999/1016    
convicomp(Conv *c, int subtype, ulong seq, Block *b) 
1999/1015    
{ 
	if(c->in.comp == nil) { 
		freeb(b); 
		return nil; 
	} 
	if((*c->in.comp)(&c->in, subtype, &b) < 0) 
1999/1016    
	if(!(*c->in.comp)(c, subtype, seq, &b)) 
1999/1015    
		return nil; 
	return b; 
} 
1999/1015/sys/src/9/port/devsdp.c:1624,16291999/1016/sys/src/9/port/devsdp.c:1623,1630
1999/0915    
writedata(Conv *c, Block *b) 
{ 
1999/1015    
	int n; 
1999/1016    
	ulong seq; 
	int subtype; 
1999/0915    
 
	qlock(c); 
	if(waserror()) { 
1999/1015/sys/src/9/port/devsdp.c:1641,16471999/1016/sys/src/9/port/devsdp.c:1642,1651
1999/0930    
	c->lstats.outDataBytes += n; 
1999/1001    
 
1999/1015    
	if(c->out.comp != nil) { 
		int subtype = (*c->out.comp)(&c->out, 0, &b); 
1999/1016    
		// must generate same value as convoput 
		seq = (c->out.seq + 1) & (SeqMax-1); 
 
		subtype = (*c->out.comp)(c, 0, seq, &b); 
1999/1001    
		c->lstats.outCompDataBytes += BLEN(b); 
1999/1015    
		convoput(c, TCompData, subtype, b); 
	} else 
1999/1015/sys/src/9/port/devsdp.c:1751,17641999/1016/sys/src/9/port/devsdp.c:1755,1764
1999/1015    
	} 
} 
 
                 
static void 
cipherfree(Conv *c) 
{ 
	if(c->ciphername) { 
		free(c->ciphername); 
		c->ciphername = nil; 
	} 
1999/1016    
	c->ciphername = nil; 
1999/1015    
	if(c->in.cipherstate) { 
		free(c->in.cipherstate); 
		c->in.cipherstate = nil; 
1999/1015/sys/src/9/port/devsdp.c:1773,17821999/1016/sys/src/9/port/devsdp.c:1773,1779
1999/1015    
static void 
authfree(Conv *c) 
{ 
	if(c->authname) { 
		free(c->authname); 
		c->authname = nil; 
	} 
1999/1016    
	c->authname = nil; 
1999/1015    
	if(c->in.authstate) { 
		free(c->in.authstate); 
		c->in.authstate = nil; 
1999/1015/sys/src/9/port/devsdp.c:1791,18001999/1016/sys/src/9/port/devsdp.c:1788,1794
1999/1015    
static void 
compfree(Conv *c) 
{ 
	if(c->compname) { 
		free(c->compname); 
		c->compname = nil; 
	} 
1999/1016    
	c->compname = nil; 
1999/1015    
	if(c->in.compstate) { 
		free(c->in.compstate); 
		c->in.compstate = nil; 
1999/1015/sys/src/9/port/devsdp.c:1806,18121999/1016/sys/src/9/port/devsdp.c:1800,1805
1999/1015    
	c->in.comp = nil; 
} 
 
                 
static void 
nullcipherinit(Conv *c, char *, int) 
{ 
1999/1015/sys/src/9/port/devsdp.c:1863,18701999/1016/sys/src/9/port/devsdp.c:1856,1862
1999/1015    
	int i; 
 
	cipherfree(c); 
	c->ciphername = malloc(strlen(name)+1); 
	strcpy(c->ciphername, name); 
1999/1016    
	c->ciphername = name; 
1999/1015    
	 
	if(n > sizeof(key)) 
		n = sizeof(key); 
1999/1015/sys/src/9/port/devsdp.c:1894,18991999/1016/sys/src/9/port/devsdp.c:1886,1892
1999/1015    
static void 
rc4cipherinit(Conv *c, char *name, int keylen) 
{ 
1999/1016    
	cipherfree(c); 
1999/1015    
} 
 
static void 
1999/1015/sys/src/9/port/devsdp.c:1955,19621999/1016/sys/src/9/port/devsdp.c:1948,1954
1999/1015    
{ 
	authfree(c); 
 
	c->authname = malloc(strlen(name)+1); 
	strcpy(c->authname, name); 
1999/1016    
	c->authname = name; 
1999/1015    
 
	if(keylen > 16) 
		keylen = 16; 
1999/1015/sys/src/9/port/devsdp.c:1977,20401999/1016/sys/src/9/port/devsdp.c:1969,2054
1999/1015    
} 
 
static void 
nullcompinit(Conv *c, char *name, int keylen) 
1999/1016    
nullcompinit(Conv *c, char*, int) 
1999/1015    
{ 
1999/1016    
	compfree(c); 
1999/1015    
} 
 
static void 
thwackcompinit(Conv *c, char *name, int keylen) 
1999/1016    
static int 
thwackcomp(Conv *c, int, ulong seq, Block **bp) 
1999/1015    
{ 
1999/1016    
	Block *b, *bb; 
	int nn; 
 
	// add ack info 
	b = padblock(*bp, 4); 
	b->rp[0] = (c->in.window>>1) & 0xff; 
	b->rp[1] = c->in.seq>>16; 
	b->rp[2] = c->in.seq>>8; 
	b->rp[3] = c->in.seq; 
 
	bb = allocb(BLEN(b)); 
	nn = thwack(c->out.compstate, bb->wp, b->rp, BLEN(b), seq); 
	if(nn < 0) { 
		freeb(bb); 
		*bp = b; 
		return ThwackU; 
	} else { 
		bb->wp += nn; 
		freeb(b); 
		*bp = bb; 
		return ThwackC; 
	} 
1999/1015    
} 
 
1999/1016    
static int 
thwackuncomp(Conv *c, int subtype, ulong seq, Block **bp) 
{ 
	Block *b, *bb; 
	ulong mask; 
	ulong mseq; 
	int n; 
1999/1015    
 
#ifdef XXX 
	case TThwackU: 
1999/1016    
	switch(subtype) { 
	default: 
		return 0; 
	case ThwackU: 
		b = *bp; 
1999/1015    
		mask = b->rp[0]; 
		mseq = (b->rp[1]<<16) | (b->rp[2]<<8) | b->rp[3]; 
		b->rp += 4; 
		thwackack(c->out.compstate, mseq, mask); 
		c->lstats.inDataBytes += BLEN(b); 
		if(control) 
			break; 
		return b; 
	case TThwackC: 
		c->lstats.inDataPackets++; 
		c->lstats.inCompDataBytes += BLEN(b); 
		bb = b; 
1999/1016    
		return 1; 
	case ThwackC: 
		bb = *bp; 
1999/1015    
		b = allocb(ThwMaxBlock); 
		n = unthwack(c->in.compstate, b->wp, ThwMaxBlock, bb->rp, BLEN(bb), seq); 
		freeb(bb); 
		if(n < 0) 
			break; 
1999/1016    
		if(n < 0) { 
print("unthwack failed: %r!\n"); 
			freeb(b); 
			return 0; 
		} 
1999/1015    
		b->wp += n; 
		mask = b->rp[0]; 
		mseq = (b->rp[1]<<16) | (b->rp[2]<<8) | b->rp[3]; 
		thwackack(c->out.compstate, mseq, mask); 
		b->rp += 4; 
		c->lstats.inDataBytes += BLEN(b); 
		if(control) 
			break; 
		return b; 
1999/1016    
		*bp = b; 
		return 1; 
1999/1015    
	} 
	b = padblock(b, 4); 
	b->rp[0] = (c->in.window>>1) & 0xff; 
	b->rp[1] = c->in.seq>>16; 
	b->rp[2] = c->in.seq>>8; 
	b->rp[3] = c->in.seq; 
1999/1016    
} 
1999/1015    
 
	// must generate same value as convoput 
	seq = (c->out.seq + 1) & (SeqMax-1); 
1999/1016    
static void 
thwackcompinit(Conv *c, char *name, int keylen) 
{ 
	compfree(c); 
1999/1015    
 
	bb = allocb(BLEN(b)); 
	nn = thwack(c->out.compstate, bb->wp, b->rp, BLEN(b), seq); 
	if(nn < 0) { 
		c->lstats.outCompDataBytes += BLEN(b); 
		convoput(c, TThwackU, b); 
		freeb(bb); 
	} else { 
		c->lstats.outCompDataBytes += nn; 
		bb->wp += nn; 
		convoput(c, TThwackC, bb); 
		freeb(b); 
	} 
#endif 
1999/1016    
	c->compname = name; 
	c->in.compstate = malloc(sizeof(Unthwack)); 
	unthwackinit(c->in.compstate); 
	c->out.compstate = malloc(sizeof(Thwack)); 
	thwackinit(c->out.compstate); 
	c->in.comp = thwackuncomp; 
	c->out.comp = thwackcomp; 
} 
1999/1016/sys/src/9/port/devsdp.c:45,501999/1019/sys/src/9/port/devsdp.c:45,51 (short | long)
1999/1015    
	SecretLength= 32,	// a secret per direction 
1999/1001    
	SeqMax = (1<<24), 
	SeqWindow = 32, 
1999/1019    
	NCompStats = 8, 
1999/0824    
}; 
 
#define TYPE(x) 	((x).path & 0xff) 
1999/1016/sys/src/9/port/devsdp.c:58,631999/1019/sys/src/9/port/devsdp.c:59,65
1999/0929    
	ulong	outDataBytes; 
	ulong	outCompDataBytes; 
	ulong	outCompBytes; 
1999/1019    
	ulong	outCompStats[NCompStats]; 
1999/0929    
	ulong	inPackets; 
	ulong	inDataPackets; 
	ulong	inDataBytes; 
1999/1016/sys/src/9/port/devsdp.c:190,1951999/1019/sys/src/9/port/devsdp.c:192,198
1999/0929    
	uchar	outDataPackets[4]; 
	uchar	outDataBytes[4]; 
	uchar	outCompDataBytes[4]; 
1999/1019    
	uchar	outCompStats[4*NCompStats]; 
1999/0929    
	uchar	inPackets[4]; 
	uchar	inDataPackets[4]; 
	uchar	inDataBytes[4]; 
1999/1016/sys/src/9/port/devsdp.c:1018,10231999/1019/sys/src/9/port/devsdp.c:1021,1027
1999/0929    
{ 
	Stats *stats; 
	char *p, *ep; 
1999/1019    
	int i; 
1999/0907    
 
1999/0929    
	if(local) { 
		stats = &c->lstats; 
1999/1016/sys/src/9/port/devsdp.c:1032,10511999/1019/sys/src/9/port/devsdp.c:1036,1061
1999/0930    
	qlock(c); 
1999/0929    
	p = buf; 
	ep = buf + n; 
	p += snprint(p, ep-p, "outPackets: %ld\n", stats->outPackets); 
	p += snprint(p, ep-p, "outDataPackets: %ld\n", stats->outDataPackets); 
	p += snprint(p, ep-p, "outDataBytes: %ld\n", stats->outDataBytes); 
	p += snprint(p, ep-p, "outCompDataBytes: %ld\n", stats->outCompDataBytes); 
	p += snprint(p, ep-p, "inPackets: %ld\n", stats->inPackets); 
	p += snprint(p, ep-p, "inDataPackets: %ld\n", stats->inDataPackets); 
1999/0930    
	p += snprint(p, ep-p, "inDataBytes: %ld\n", stats->inDataBytes); 
1999/0929    
	p += snprint(p, ep-p, "inCompDataBytes: %ld\n", stats->inCompDataBytes); 
	p += snprint(p, ep-p, "inMissing: %ld\n", stats->inMissing); 
	p += snprint(p, ep-p, "inDup: %ld\n", stats->inDup); 
	p += snprint(p, ep-p, "inReorder: %ld\n", stats->inReorder); 
1999/1016    
	p += snprint(p, ep-p, "inBadComp: %ld\n", stats->inBadComp); 
1999/0929    
	p += snprint(p, ep-p, "inBadAuth: %ld\n", stats->inBadAuth); 
	p += snprint(p, ep-p, "inBadSeq: %ld\n", stats->inBadSeq); 
1999/1019    
	p += snprint(p, ep-p, "outPackets: %lud\n", stats->outPackets); 
	p += snprint(p, ep-p, "outDataPackets: %lud\n", stats->outDataPackets); 
	p += snprint(p, ep-p, "outDataBytes: %lud\n", stats->outDataBytes); 
	p += snprint(p, ep-p, "outCompDataBytes: %lud\n", stats->outCompDataBytes); 
	for(i=0; i<NCompStat; i++) { 
		if(stat->outCompStats[i] == 0) 
			continue; 
		p += snprint(p, ep-p, "outCompStats[%d]: %lud\n", i, stats->outCompStats[i]); 
	} 
	p += snprint(p, ep-p, "outCompDataBytes: %lud\n", stats->outCompDataBytes); 
	p += snprint(p, ep-p, "inPackets: %lud\n", stats->inPackets); 
	p += snprint(p, ep-p, "inDataPackets: %lud\n", stats->inDataPackets); 
	p += snprint(p, ep-p, "inDataBytes: %lud\n", stats->inDataBytes); 
	p += snprint(p, ep-p, "inCompDataBytes: %lud\n", stats->inCompDataBytes); 
	p += snprint(p, ep-p, "inMissing: %lud\n", stats->inMissing); 
	p += snprint(p, ep-p, "inDup: %lud\n", stats->inDup); 
	p += snprint(p, ep-p, "inReorder: %lud\n", stats->inReorder); 
	p += snprint(p, ep-p, "inBadComp: %lud\n", stats->inBadComp); 
	p += snprint(p, ep-p, "inBadAuth: %lud\n", stats->inBadAuth); 
	p += snprint(p, ep-p, "inBadSeq: %lud\n", stats->inBadSeq); 
1999/0929    
	USED(p); 
	qunlock(c); 
} 
1999/1016/sys/src/9/port/devsdp.c:1057,10621999/1019/sys/src/9/port/devsdp.c:1067,1073
1999/0929    
	Block *b; 
	AckPkt *ack; 
	Stats *s; 
1999/1019    
	int i; 
1999/0929    
 
	b = allocb(sizeof(AckPkt)); 
1999/0930    
	ack = (AckPkt*)b->wp; 
1999/1016/sys/src/9/port/devsdp.c:1067,10721999/1019/sys/src/9/port/devsdp.c:1078,1085
1999/0929    
	hnputl(ack->outDataPackets, s->outDataPackets); 
	hnputl(ack->outDataBytes, s->outDataBytes); 
	hnputl(ack->outCompDataBytes, s->outCompDataBytes); 
1999/1019    
	for(i=0; i<NCompStat; i++) 
		hnputl(ack->outCompStats+i*4, s->outCompStats[i]); 
1999/0929    
	hnputl(ack->inPackets, s->inPackets); 
	hnputl(ack->inDataPackets, s->inDataPackets); 
	hnputl(ack->inDataBytes, s->inDataBytes); 
1999/1016/sys/src/9/port/devsdp.c:1311,13161999/1019/sys/src/9/port/devsdp.c:1324,1330
1999/1015    
{ 
	ulong cseq; 
	AckPkt *ack; 
1999/1019    
	int i; 
1999/1015    
 
	if(BLEN(b) < 4) 
		return; 
1999/1016/sys/src/9/port/devsdp.c:1988,19941999/1019/sys/src/9/port/devsdp.c:2002,2008
1999/1016    
	b->rp[3] = c->in.seq; 
 
	bb = allocb(BLEN(b)); 
	nn = thwack(c->out.compstate, bb->wp, b->rp, BLEN(b), seq); 
1999/1019    
	nn = thwack(c->out.compstate, bb->wp, b->rp, BLEN(b), seq, c->lstats.outCompStats); 
1999/1016    
	if(nn < 0) { 
		freeb(bb); 
		*bp = b; 
1999/1019/sys/src/9/port/devsdp.c:1040,10471999/1021/sys/src/9/port/devsdp.c:1040,1047 (short | long)
1999/1019    
	p += snprint(p, ep-p, "outDataPackets: %lud\n", stats->outDataPackets); 
	p += snprint(p, ep-p, "outDataBytes: %lud\n", stats->outDataBytes); 
	p += snprint(p, ep-p, "outCompDataBytes: %lud\n", stats->outCompDataBytes); 
	for(i=0; i<NCompStat; i++) { 
		if(stat->outCompStats[i] == 0) 
1999/1021    
	for(i=0; i<NCompStats; i++) { 
		if(stats->outCompStats[i] == 0) 
1999/1019    
			continue; 
		p += snprint(p, ep-p, "outCompStats[%d]: %lud\n", i, stats->outCompStats[i]); 
	} 
1999/1019/sys/src/9/port/devsdp.c:1078,10841999/1021/sys/src/9/port/devsdp.c:1078,1084
1999/0929    
	hnputl(ack->outDataPackets, s->outDataPackets); 
	hnputl(ack->outDataBytes, s->outDataBytes); 
	hnputl(ack->outCompDataBytes, s->outCompDataBytes); 
1999/1019    
	for(i=0; i<NCompStat; i++) 
1999/1021    
	for(i=0; i<NCompStats; i++) 
1999/1019    
		hnputl(ack->outCompStats+i*4, s->outCompStats[i]); 
1999/0929    
	hnputl(ack->inPackets, s->inPackets); 
	hnputl(ack->inDataPackets, s->inDataPackets); 
1999/1019/sys/src/9/port/devsdp.c:1324,13301999/1021/sys/src/9/port/devsdp.c:1324,1329
1999/1015    
{ 
	ulong cseq; 
	AckPkt *ack; 
1999/1019    
	int i; 
1999/1015    
 
	if(BLEN(b) < 4) 
		return; 
1999/1019/sys/src/9/port/devsdp.c:2002,20081999/1021/sys/src/9/port/devsdp.c:2001,2007
1999/1016    
	b->rp[3] = c->in.seq; 
 
	bb = allocb(BLEN(b)); 
1999/1019    
	nn = thwack(c->out.compstate, bb->wp, b->rp, BLEN(b), seq, c->lstats.outCompStats); 
1999/1021    
	nn = thwack(c->out.compstate, bb->wp, b->rp, BLEN(b), seq); 
1999/1016    
	if(nn < 0) { 
		freeb(bb); 
		*bp = b; 
1999/1021/sys/src/9/port/devsdp.c:19,241999/1022/sys/src/9/port/devsdp.c:19,25 (short | long)
1999/0929    
typedef struct Stats Stats; 
typedef struct AckPkt AckPkt; 
1999/1001    
typedef struct Algorithm Algorithm; 
1999/1022    
typedef struct CipherRc4 CipherRc4; 
1999/0824    
 
enum 
{ 
1999/1021/sys/src/9/port/devsdp.c:70,751999/1022/sys/src/9/port/devsdp.c:71,77
1999/1016    
	ulong	inBadComp; 
1999/0929    
	ulong	inBadAuth; 
	ulong	inBadSeq; 
1999/1022    
	ulong	inBadOther; 
1999/0929    
}; 
 
1999/0907    
struct OneWay 
1999/1021/sys/src/9/port/devsdp.c:141,1491999/1022/sys/src/9/port/devsdp.c:143,151
1999/0907    
	char owner[NAMELEN];		/* protections */ 
1999/0901    
	int	perm; 
 
1999/1001    
	char *authname; 
	char *ciphername; 
	char *compname; 
1999/1022    
	Algorithm *auth; 
	Algorithm *cipher; 
	Algorithm *comp; 
1999/0907    
 
1999/0906    
	int drop; 
 
1999/1021/sys/src/9/port/devsdp.c:203,2081999/1022/sys/src/9/port/devsdp.c:205,211
1999/1016    
	uchar	inBadComp[4]; 
1999/0929    
	uchar	inBadAuth[4]; 
	uchar	inBadSeq[4]; 
1999/1022    
	uchar	inBadOther[4]; 
1999/0929    
}; 
1999/0907    
 
1999/1001    
struct Algorithm 
1999/1021/sys/src/9/port/devsdp.c:209,2171999/1022/sys/src/9/port/devsdp.c:212,236
1999/1001    
{ 
	char 	*name; 
	int		keylen;		// in bytes 
	void	(*init)(Conv*, char* name, int keylen); 
1999/1022    
	void	(*init)(Conv*); 
1999/1001    
}; 
1999/0929    
 
1999/1022    
enum { 
	RC4forward	= 10*1024*1024,	// maximum skip forward 
	RC4back = 100*1024,		// maximum look back 
}; 
 
struct CipherRc4 
{ 
	ulong cseq;	// current byte sequence number 
	RC4state current; 
 
	int ovalid;	// old is valid 
	ulong lgseq; // last good sequence 
	ulong oseq;	// old byte sequence number 
	RC4state old; 
}; 
 
1999/0824    
static Dirtab sdpdirtab[]={ 
	"log",		{Qlog},		0,	0666, 
1999/0901    
	"clone",	{Qclone},		0,	0666, 
1999/1021/sys/src/9/port/devsdp.c:279,2951999/1022/sys/src/9/port/devsdp.c:298,314
1999/0914    
static void convopenchan(Conv *c, char *path); 
1999/0929    
static void convstats(Conv *c, int local, char *buf, int n); 
1999/0824    
 
1999/1015    
static void setalg(Conv *c, char *name, Algorithm *tab); 
1999/1022    
static void setalg(Conv *c, char *name, Algorithm *tab, Algorithm **); 
1999/1015    
static void setsecret(OneWay *cc, char *secret); 
 
static void nullcipherinit(Conv*c, char *name, int keylen); 
static void descipherinit(Conv*c, char *name, int keylen); 
static void rc4cipherinit(Conv*c, char *name, int keylen); 
static void nullauthinit(Conv*c, char *name, int keylen); 
static void shaauthinit(Conv*c, char *name, int keylen); 
static void md5authinit(Conv*c, char *name, int keylen); 
static void nullcompinit(Conv*c, char *name, int keylen); 
static void thwackcompinit(Conv*c, char *name, int keylen); 
1999/1022    
static void nullcipherinit(Conv*c); 
static void descipherinit(Conv*c); 
static void rc4cipherinit(Conv*c); 
static void nullauthinit(Conv*c); 
static void shaauthinit(Conv*c); 
static void md5authinit(Conv*c); 
static void nullcompinit(Conv*c); 
static void thwackcompinit(Conv*c); 
1999/1015    
 
static Algorithm cipheralg[] = 
{ 
1999/1021/sys/src/9/port/devsdp.c:296,3011999/1022/sys/src/9/port/devsdp.c:315,321
1999/1015    
	"null",			0,	nullcipherinit, 
	"des_56_cbc",	7,	descipherinit, 
	"rc4_128",		16,	rc4cipherinit, 
1999/1022    
	"rc4_256",		32,	rc4cipherinit, 
1999/1015    
	nil,			0,	nil, 
}; 
 
1999/1021/sys/src/9/port/devsdp.c:617,6391999/1022/sys/src/9/port/devsdp.c:637,667
1999/1015    
		} else if(strcmp(arg0, "cipher") == 0) { 
			if(cb->nf != 2) 
				error("usage: cipher alg"); 
			setalg(c, cb->f[1], cipheralg); 
1999/1022    
			setalg(c, cb->f[1], cipheralg, &c->cipher); 
1999/1015    
		} else if(strcmp(arg0, "auth") == 0) { 
			if(cb->nf != 2) 
				error("usage: auth alg"); 
			setalg(c, cb->f[1], authalg); 
1999/1022    
			setalg(c, cb->f[1], authalg, &c->auth); 
1999/1015    
		} else if(strcmp(arg0, "comp") == 0) { 
			if(cb->nf != 2) 
				error("usage: comp alg"); 
			setalg(c, cb->f[1], compalg); 
1999/1022    
			setalg(c, cb->f[1], compalg, &c->comp); 
1999/1015    
		} else if(strcmp(arg0, "insecret") == 0) { 
			if(cb->nf != 2) 
				error("usage: insecret secret"); 
			setsecret(&c->in, cb->f[1]); 
1999/1022    
			if(c->cipher) 
				c->cipher->init(c); 
			if(c->auth) 
				c->auth->init(c); 
1999/1015    
		} else if(strcmp(arg0, "outsecret") == 0) { 
			if(cb->nf != 2) 
				error("usage: outsecret secret"); 
			setsecret(&c->out, cb->f[1]); 
1999/1022    
			if(c->cipher) 
				c->cipher->init(c); 
			if(c->auth) 
				c->auth->init(c); 
1999/0824    
		} else 
			error("unknown control request"); 
		poperror(); 
1999/1021/sys/src/9/port/devsdp.c:934,9401999/1022/sys/src/9/port/devsdp.c:962,968
1999/1015    
			hnputl(c->out.secret, c->acceptid); 
			hnputl(c->out.secret+4, c->dialid); 
1999/0906    
		} 
1999/1015    
		md5authinit(c, "hmac_md5_96", 16); 
1999/1022    
		setalg(c, "hmac_md5_96", authalg, &c->auth); 
1999/0906    
		break; 
1999/0910    
	case CLocalClose: 
		assert(c->state == CAccept || c->state == COpen); 
1999/1021/sys/src/9/port/devsdp.c:961,9691999/1022/sys/src/9/port/devsdp.c:989,997
1999/0910    
			free(c->channame); 
			c->channame = nil; 
		} 
1999/1016    
		c->ciphername = nil; 
		c->authname = nil; 
		c->compname = nil; 
1999/1022    
		c->cipher = nil; 
		c->auth = nil; 
		c->comp = nil; 
1999/1001    
	strcpy(c->owner, "network"); 
1999/0907    
		c->perm = 0660; 
		c->dialid = 0; 
1999/1021/sys/src/9/port/devsdp.c:1045,10511999/1022/sys/src/9/port/devsdp.c:1073,1078
1999/1019    
			continue; 
		p += snprint(p, ep-p, "outCompStats[%d]: %lud\n", i, stats->outCompStats[i]); 
	} 
	p += snprint(p, ep-p, "outCompDataBytes: %lud\n", stats->outCompDataBytes); 
	p += snprint(p, ep-p, "inPackets: %lud\n", stats->inPackets); 
	p += snprint(p, ep-p, "inDataPackets: %lud\n", stats->inDataPackets); 
	p += snprint(p, ep-p, "inDataBytes: %lud\n", stats->inDataBytes); 
1999/1021/sys/src/9/port/devsdp.c:1056,10611999/1022/sys/src/9/port/devsdp.c:1083,1089
1999/1019    
	p += snprint(p, ep-p, "inBadComp: %lud\n", stats->inBadComp); 
	p += snprint(p, ep-p, "inBadAuth: %lud\n", stats->inBadAuth); 
	p += snprint(p, ep-p, "inBadSeq: %lud\n", stats->inBadSeq); 
1999/1022    
	p += snprint(p, ep-p, "inBadOther: %lud\n", stats->inBadOther); 
1999/0929    
	USED(p); 
	qunlock(c); 
} 
1999/1021/sys/src/9/port/devsdp.c:1090,10951999/1022/sys/src/9/port/devsdp.c:1118,1124
1999/1016    
	hnputl(ack->inBadComp, s->inBadComp); 
1999/0929    
	hnputl(ack->inBadAuth, s->inBadAuth); 
	hnputl(ack->inBadSeq, s->inBadSeq); 
1999/1022    
	hnputl(ack->inBadOther, s->inBadOther); 
1999/1015    
	convoput(c, TControl, ControlAck, b); 
1999/0929    
} 
 
1999/1021/sys/src/9/port/devsdp.c:1101,11101999/1022/sys/src/9/port/devsdp.c:1130,1141
1999/1015    
	int type, subtype; 
	ulong seq, seqwrap; 
1999/1001    
	long seqdiff; 
1999/1022    
	int pad; 
1999/0907    
 
1999/0930    
	c->lstats.inPackets++; 
1999/0929    
 
1999/0907    
	if(BLEN(b) < 4) { 
1999/1022    
		c->lstats.inBadOther++; 
1999/0907    
		freeb(b); 
		return nil; 
	} 
1999/1021/sys/src/9/port/devsdp.c:1160,11661999/1022/sys/src/9/port/devsdp.c:1191,1215
1999/1015    
		b->wp -= c->in.authlen; 
	} 
 
1999/0907    
	// decrypt 
1999/1022    
	if(c->in.cipher != 0) { 
		if(!(*c->in.cipher)(&c->in, b->rp, BLEN(b))) { 
print("bad cipher\n"); 
			c->lstats.inBadOther++; 
			freeb(b); 
			return nil; 
		} 
		b->rp += c->in.cipherivlen; 
		if(c->in.cipherblklen > 1) { 
			pad = b->wp[-1]; 
			if(pad > BLEN(b)) { 
print("pad too big\n"); 
				c->lstats.inBadOther++; 
				freeb(b); 
				return nil; 
			} 
			b->wp -= pad; 
		} 
	} 
1999/0907    
 
	// ok the packet is good 
1999/1001    
	if(seqdiff > 0) { 
1999/1021/sys/src/9/port/devsdp.c:1206,12111999/1022/sys/src/9/port/devsdp.c:1255,1261
1999/1001    
		return b; 
1999/0907    
	} 
print("droping packet %d n=%ld\n", type, BLEN(b)); 
1999/1022    
	c->lstats.inBadOther++; 
1999/0907    
	freeb(b); 
	return nil; 
} 
1999/1021/sys/src/9/port/devsdp.c:1324,13291999/1022/sys/src/9/port/devsdp.c:1374,1380
1999/1015    
{ 
	ulong cseq; 
	AckPkt *ack; 
1999/1022    
	int i; 
1999/1015    
 
	if(BLEN(b) < 4) 
		return; 
1999/1021/sys/src/9/port/devsdp.c:1366,13711999/1022/sys/src/9/port/devsdp.c:1417,1424
1999/1015    
		c->rstats.outDataPackets = nhgetl(ack->outDataPackets); 
		c->rstats.outDataBytes = nhgetl(ack->outDataBytes); 
		c->rstats.outCompDataBytes = nhgetl(ack->outCompDataBytes); 
1999/1022    
		for(i=0; i<NCompStats; i++) 
			c->rstats.outCompStats[i] = nhgetl(ack->outCompStats + 4*i); 
1999/1015    
		c->rstats.inPackets = nhgetl(ack->inPackets); 
		c->rstats.inDataPackets = nhgetl(ack->inDataPackets); 
		c->rstats.inDataBytes = nhgetl(ack->inDataBytes); 
1999/1021/sys/src/9/port/devsdp.c:1376,13811999/1022/sys/src/9/port/devsdp.c:1429,1435
1999/1016    
		c->rstats.inBadComp = nhgetl(ack->inBadComp); 
1999/1015    
		c->rstats.inBadAuth = nhgetl(ack->inBadAuth); 
		c->rstats.inBadSeq = nhgetl(ack->inBadSeq); 
1999/1022    
		c->rstats.inBadOther = nhgetl(ack->inBadOther); 
1999/1015    
		freeb(b); 
		freeb(c->out.controlpkt); 
		c->out.controlpkt = nil; 
1999/1021/sys/src/9/port/devsdp.c:1418,14251999/1022/sys/src/9/port/devsdp.c:1472,1494
1999/0907    
static void 
1999/1015    
convoput(Conv *c, int type, int subtype, Block *b) 
1999/0907    
{ 
	// try and compress 
1999/1022    
	int pad; 
	 
1999/0929    
	c->lstats.outPackets++; 
1999/1022    
	/* Make room for sdp trailer */ 
	if(c->out.cipherblklen > 1) 
		pad = c->out.cipherblklen - (BLEN(b) + c->out.cipherivlen) % c->out.cipherblklen; 
	else 
		pad = 0; 
 
	b = padblock(b, -(pad+c->out.authlen)); 
 
	if(pad) { 
		memset(b->wp, 0, pad-1); 
		b->wp[pad-1] = pad; 
		b->wp += pad; 
	} 
 
1999/0907    
	/* Make space to fit sdp header */ 
	b = padblock(b, 4 + c->out.cipherivlen); 
1999/1015    
	b->rp[0] = (type << 4) | subtype; 
1999/1021/sys/src/9/port/devsdp.c:1432,14411999/1022/sys/src/9/port/devsdp.c:1501,1511
1999/0907    
	b->rp[2] = c->out.seq>>8; 
	b->rp[3] = c->out.seq; 
	 
	// encrypt 
1999/1022    
	if(c->out.cipher) 
		(*c->out.cipher)(&c->out, b->rp+4, BLEN(b)-4); 
 
1999/0907    
	// auth 
1999/1015    
	if(c->out.auth) { 
		b = padblock(b, -c->out.authlen); 
		b->wp += c->out.authlen; 
		(*c->out.auth)(&c->out, b->rp, BLEN(b)); 
	} 
1999/1021/sys/src/9/port/devsdp.c:1710,17161999/1022/sys/src/9/port/devsdp.c:1780,1786
1999/1015    
/* ciphers, authenticators, and compressors  */ 
 
static void 
setalg(Conv *c, char *name, Algorithm *alg) 
1999/1022    
setalg(Conv *c, char *name, Algorithm *alg, Algorithm **p) 
1999/1015    
{ 
	for(; alg->name; alg++) 
		if(strcmp(name, alg->name) == 0) 
1999/1021/sys/src/9/port/devsdp.c:1718,17241999/1022/sys/src/9/port/devsdp.c:1788,1795
1999/1015    
	if(alg->name == nil) 
		error("unknown algorithm"); 
 
	alg->init(c, alg->name, alg->keylen); 
1999/1022    
	*p = alg; 
	alg->init(c); 
1999/1015    
} 
 
static void 
1999/1021/sys/src/9/port/devsdp.c:1771,17771999/1022/sys/src/9/port/devsdp.c:1842,1847
1999/1015    
static void 
cipherfree(Conv *c) 
{ 
1999/1016    
	c->ciphername = nil; 
1999/1015    
	if(c->in.cipherstate) { 
		free(c->in.cipherstate); 
		c->in.cipherstate = nil; 
1999/1021/sys/src/9/port/devsdp.c:1781,17921999/1022/sys/src/9/port/devsdp.c:1851,1865
1999/1015    
		c->out.cipherstate = nil; 
	} 
	c->in.cipher = nil; 
1999/1022    
	c->in.cipherblklen = 0; 
	c->out.cipherblklen = 0; 
	c->in.cipherivlen = 0; 
	c->out.cipherivlen = 0; 
1999/1015    
} 
 
static void 
authfree(Conv *c) 
{ 
1999/1016    
	c->authname = nil; 
1999/1015    
	if(c->in.authstate) { 
		free(c->in.authstate); 
		c->in.authstate = nil; 
1999/1021/sys/src/9/port/devsdp.c:1796,18071999/1022/sys/src/9/port/devsdp.c:1869,1881
1999/1015    
		c->out.authstate = nil; 
	} 
	c->in.auth = nil; 
1999/1022    
	c->in.authlen = 0; 
	c->out.authlen = 0; 
1999/1015    
} 
 
static void 
compfree(Conv *c) 
{ 
1999/1016    
	c->compname = nil; 
1999/1015    
	if(c->in.compstate) { 
		free(c->in.compstate); 
		c->in.compstate = nil; 
1999/1021/sys/src/9/port/devsdp.c:1814,18201999/1022/sys/src/9/port/devsdp.c:1888,1894
1999/1015    
} 
 
static void 
nullcipherinit(Conv *c, char *, int) 
1999/1022    
nullcipherinit(Conv *c) 
1999/1015    
{ 
	cipherfree(c); 
} 
1999/1021/sys/src/9/port/devsdp.c:1825,18301999/1022/sys/src/9/port/devsdp.c:1899,1906
1999/1015    
	uchar *pp, *ip, *eip, *ep; 
	DESstate *ds = ow->cipherstate; 
 
1999/1022    
	if(n < 8 || (n & 0x7 != 0)) 
		return 0; 
1999/1015    
	ep = p + n; 
	memmove(p, ds->ivec, 8); 
	for(p += 8; p < ep; p += 8){ 
1999/1021/sys/src/9/port/devsdp.c:1845,18501999/1022/sys/src/9/port/devsdp.c:1921,1928
1999/1015    
	uchar *tp, *ip, *eip, *ep; 
	DESstate *ds = ow->cipherstate; 
 
1999/1022    
	if(n < 8 || (n & 0x7 != 0)) 
		return 0; 
1999/1015    
	ep = p + n; 
	memmove(ds->ivec, p, 8); 
	p += 8; 
1999/1021/sys/src/9/port/devsdp.c:1862,18751999/1022/sys/src/9/port/devsdp.c:1940,1953
1999/1015    
} 
 
static void 
descipherinit(Conv *c, char *name, int n) 
1999/1022    
descipherinit(Conv *c) 
1999/1015    
{ 
	uchar key[8]; 
	uchar ivec[8]; 
	int i; 
1999/1022    
	int n = c->cipher->keylen; 
1999/1015    
 
	cipherfree(c); 
1999/1016    
	c->ciphername = name; 
1999/1015    
	 
	if(n > sizeof(key)) 
		n = sizeof(key); 
1999/1021/sys/src/9/port/devsdp.c:1896,19151999/1022/sys/src/9/port/devsdp.c:1974,2099
1999/1015    
	setupDESstate(c->out.cipherstate, key, ivec); 
} 
 
1999/1022    
static int 
rc4encrypt(OneWay *ow, uchar *p, int n) 
{ 
	CipherRc4 *cr = ow->cipherstate; 
 
	if(n < 4) 
		return 0; 
 
	hnputl(p, cr->cseq); 
	p += 4; 
	n -= 4; 
	rc4(&cr->current, p, n); 
	cr->cseq += n; 
	return 1; 
} 
 
static int 
rc4decrypt(OneWay *ow, uchar *p, int n) 
{ 
	CipherRc4 *cr = ow->cipherstate; 
	RC4state tmpstate; 
	ulong seq; 
	long d, dd; 
 
	if(n < 4) 
		return 0; 
 
	seq = nhgetl(p); 
	p += 4; 
	n -= 4; 
	d = seq-cr->cseq; 
	if(d == 0) { 
		rc4(&cr->current, p, n); 
		cr->cseq += n; 
		if(cr->ovalid) { 
			dd = cr->cseq - cr->lgseq; 
			if(dd > RC4back) 
				cr->ovalid = 0; 
		} 
	} else if(d > 0) { 
print("missing packet: %uld %ld\n", seq, d); 
		// this link is hosed  
		if(d > RC4forward) 
			return 0; 
		cr->lgseq = seq; 
		if(!cr->ovalid) { 
			cr->ovalid = 1; 
			cr->oseq = cr->cseq; 
			memmove(&cr->old, &cr->current, sizeof(RC4state)); 
		} 
		rc4skip(&cr->current, d); 
		rc4(&cr->current, p, n); 
		cr->cseq = seq+n; 
	} else { 
print("reordered packet: %uld %ld\n", seq, d); 
		dd = seq - cr->oseq; 
		if(!cr->ovalid || -d > RC4back || dd < 0) 
			return 0; 
		memmove(&tmpstate, &cr->old, sizeof(RC4state)); 
		rc4skip(&tmpstate, dd); 
		rc4(&tmpstate, p, n); 
		return 1; 
	} 
 
	// move old state up 
	if(cr->ovalid) { 
		dd = cr->cseq - RC4back - cr->oseq; 
		if(dd > 0) { 
			rc4skip(&cr->old, dd); 
			cr->oseq += dd; 
		} 
	} 
 
	return 1; 
} 
 
1999/1015    
static void 
rc4cipherinit(Conv *c, char *name, int keylen) 
1999/1022    
rc4cipherinit(Conv *c) 
1999/1015    
{ 
1999/1022    
	uchar key[32]; 
	CipherRc4 *cr; 
	int n; 
 
1999/1016    
	cipherfree(c); 
1999/1022    
 
	n = c->cipher->keylen; 
	if(n > sizeof(key)) 
		n = sizeof(key); 
 
	/* in */ 
	memset(key, 0, sizeof(key)); 
	setkey(key, n, &c->in, "cipher"); 
	c->in.cipherblklen = 1; 
	c->in.cipherivlen = 4; 
	c->in.cipher = rc4decrypt; 
	cr = smalloc(sizeof(CipherRc4)); 
	memset(cr, 0, sizeof(*cr)); 
	setupRC4state(&cr->current, key, n); 
	c->in.cipherstate = cr; 
 
	/* out */ 
	memset(key, 0, sizeof(key)); 
	setkey(key, n, &c->out, "cipher"); 
	c->out.cipherblklen = 1; 
	c->out.cipherivlen = 4; 
	c->out.cipher = rc4encrypt; 
	cr = smalloc(sizeof(CipherRc4)); 
	memset(cr, 0, sizeof(*cr)); 
	setupRC4state(&cr->current, key, n); 
	c->out.cipherstate = cr; 
1999/1015    
} 
 
static void 
nullauthinit(Conv *c, char *name, int keylen) 
1999/1022    
nullauthinit(Conv *c) 
1999/1015    
{ 
	authfree(c); 
} 
 
static void 
shaauthinit(Conv *c, char *name, int keylen) 
1999/1022    
shaauthinit(Conv *c) 
1999/1015    
{ 
	authfree(c); 
} 
1999/1021/sys/src/9/port/devsdp.c:1957,19681999/1022/sys/src/9/port/devsdp.c:2141,2153
1999/1015    
} 
 
static void 
md5authinit(Conv *c, char *name, int keylen) 
1999/1022    
md5authinit(Conv *c) 
1999/1015    
{ 
1999/1022    
	int keylen; 
 
1999/1015    
	authfree(c); 
 
1999/1016    
	c->authname = name; 
1999/1015    
                 
1999/1022    
	keylen = c->auth->keylen; 
1999/1015    
	if(keylen > 16) 
		keylen = 16; 
 
1999/1021/sys/src/9/port/devsdp.c:1982,19881999/1022/sys/src/9/port/devsdp.c:2167,2173
1999/1015    
} 
 
static void 
1999/1016    
nullcompinit(Conv *c, char*, int) 
1999/1022    
nullcompinit(Conv *c) 
1999/1015    
{ 
1999/1016    
	compfree(c); 
1999/1015    
} 
1999/1021/sys/src/9/port/devsdp.c:2001,20071999/1022/sys/src/9/port/devsdp.c:2186,2192
1999/1016    
	b->rp[3] = c->in.seq; 
 
	bb = allocb(BLEN(b)); 
1999/1021    
	nn = thwack(c->out.compstate, bb->wp, b->rp, BLEN(b), seq); 
1999/1022    
	nn = thwack(c->out.compstate, bb->wp, b->rp, BLEN(b), seq, c->lstats.outCompStats); 
1999/1016    
	if(nn < 0) { 
		freeb(bb); 
		*bp = b; 
1999/1021/sys/src/9/port/devsdp.c:2053,20631999/1022/sys/src/9/port/devsdp.c:2238,2247
1999/1016    
} 
1999/1015    
 
1999/1016    
static void 
thwackcompinit(Conv *c, char *name, int keylen) 
1999/1022    
thwackcompinit(Conv *c) 
1999/1016    
{ 
	compfree(c); 
1999/1015    
 
1999/1016    
	c->compname = name; 
	c->in.compstate = malloc(sizeof(Unthwack)); 
	unthwackinit(c->in.compstate); 
	c->out.compstate = malloc(sizeof(Thwack)); 
1999/1022/sys/src/9/port/devsdp.c:330,3361999/1027/sys/src/9/port/devsdp.c:330,336 (short | long)
1999/1015    
static Algorithm compalg[] = 
{ 
	"null",			0,	nullcompinit, 
	"thwack",		0,	thwackcompinit, 
1999/1027    
//	"thwack",		0,	thwackcompinit, 
1999/1015    
	nil,			0,	nil, 
}; 
 
1999/1022/sys/src/9/port/devsdp.c:340,3451999/1027/sys/src/9/port/devsdp.c:340,347
1999/0824    
{ 
	int i; 
	Dirtab *dt; 
1999/1027    
	 
	return; 
1999/0824    
 
	// setup dirtab with non directory entries 
	for(i=0; i<nelem(sdpdirtab); i++) { 
1999/1022/sys/src/9/port/devsdp.c:367,3731999/1027/sys/src/9/port/devsdp.c:369,375
1999/0824    
	if(dev<0 || dev >= Nfs) 
		error("bad specification"); 
 
1999/0901    
	c = devattach('T', spec); 
1999/1027    
	c = devattach('E', spec); 
1999/0824    
	c->qid = (Qid){QID(0, Qtopdir)|CHDIR, 0}; 
	c->dev = dev; 
 
1999/1022/sys/src/9/port/devsdp.c:556,5611999/1027/sys/src/9/port/devsdp.c:558,564
1999/0901    
		return readstr(off, a, n, buf); 
1999/0907    
	case Qcontrol: 
		b = readcontrol(sdp->conv[CONV(ch->qid)], n); 
1999/1027    
print("readcontrol asked %ld\n", n); 
1999/0907    
		if(b == nil) 
			return 0; 
1999/0914    
print("readcontrol asked %ld got %ld\n", n, BLEN(b)); 
1999/1022/sys/src/9/port/devsdp.c:905,9111999/1027/sys/src/9/port/devsdp.c:908,914
1999/0902    
} 
1999/0824    
 
Dev sdpdevtab = { 
	'T', 
1999/1027    
	'E', 
1999/0824    
	"sdp", 
 
	devreset, 
1999/1022/sys/src/9/port/devsdp.c:971,9771999/1027/sys/src/9/port/devsdp.c:974,980
1999/0906    
		break; 
1999/0910    
	case CRemoteClose: 
1999/0914    
		wakeup(&c->in.controlready); 
1999/1015    
		convoconnect(c, ConReset, c->dialid, c->acceptid); 
1999/1027    
// convoconnect(c, ConReset, c->dialid, c->acceptid); 
1999/0910    
		break; 
1999/0906    
	case CClosed: 
1999/0914    
		wakeup(&c->in.controlready); 
1999/1027/sys/src/9/port/devsdp.c:330,3361999/1028/sys/src/9/port/devsdp.c:330,336 (short | long)
1999/1015    
static Algorithm compalg[] = 
{ 
	"null",			0,	nullcompinit, 
1999/1027    
//	"thwack",		0,	thwackcompinit, 
1999/1028    
	"thwack",		0,	thwackcompinit, 
1999/1015    
	nil,			0,	nil, 
}; 
 
1999/1027/sys/src/9/port/devsdp.c:558,5641999/1028/sys/src/9/port/devsdp.c:558,563
1999/0901    
		return readstr(off, a, n, buf); 
1999/0907    
	case Qcontrol: 
		b = readcontrol(sdp->conv[CONV(ch->qid)], n); 
1999/1027    
print("readcontrol asked %ld\n", n); 
1999/0907    
		if(b == nil) 
			return 0; 
1999/0914    
print("readcontrol asked %ld got %ld\n", n, BLEN(b)); 
1999/1028/sys/src/9/port/devsdp.c:1185,11911999/1031/sys/src/9/port/devsdp.c:1185,1191 (short | long)
1999/0930    
if(0) print("coniput seq=%ulx\n", seq); 
1999/1015    
	if(c->in.auth != 0) { 
		if(!(*c->in.auth)(&c->in, b->rp-4, BLEN(b)+4)) { 
print("bad auth\n"); 
1999/1031    
print("bad auth %d\n", BLEN(b)+4); 
1999/1015    
			c->lstats.inBadAuth++; 
			freeb(b); 
			return nil; 
1999/1028/sys/src/9/port/devsdp.c:1726,17321999/1031/sys/src/9/port/devsdp.c:1726,1732
1999/0930    
	c->lstats.outDataPackets++; 
	c->lstats.outDataBytes += n; 
1999/1001    
 
1999/1015    
	if(c->out.comp != nil) { 
1999/1031    
	if(c->out.comp != nil && 0) { 
1999/1016    
		// must generate same value as convoput 
		seq = (c->out.seq + 1) & (SeqMax-1); 
 
1999/1031/sys/src/9/port/devsdp.c:1185,11911999/1106/sys/src/9/port/devsdp.c:1185,1191 (short | long)
1999/0930    
if(0) print("coniput seq=%ulx\n", seq); 
1999/1015    
	if(c->in.auth != 0) { 
		if(!(*c->in.auth)(&c->in, b->rp-4, BLEN(b)+4)) { 
1999/1031    
print("bad auth %d\n", BLEN(b)+4); 
1999/1106    
print("bad auth %ld\n", BLEN(b)+4); 
1999/1015    
			c->lstats.inBadAuth++; 
			freeb(b); 
			return nil; 
1999/1031/sys/src/9/port/devsdp.c:1686,16941999/1106/sys/src/9/port/devsdp.c:1686,1702
1999/0907    
readdata(Conv *c, int n) 
{ 
	Block *b; 
1999/1106    
	int nn; 
1999/0907    
 
	for(;;) { 
		b = convreadblock(c, n); 
1999/1106    
 
		// some slack for tunneling overhead 
		nn = n + 100; 
 
		// make sure size is big enough for control messages 
		if(nn < 1000) 
			nn = 1000; 
		b = convreadblock(c, nn); 
1999/0930    
		if(b == nil) 
			return nil; 
1999/0907    
		qlock(c); 
1999/1031/sys/src/9/port/devsdp.c:1699,17061999/1106/sys/src/9/port/devsdp.c:1707,1717
1999/0907    
		b = conviput(c, b, 0); 
		poperror(); 
		qunlock(c); 
		if(b != nil) 
1999/1106    
		if(b != nil) { 
			if(BLEN(b) > n) 
				b->wp = b->rp + n; 
1999/0907    
			return b; 
1999/1106    
		} 
1999/0907    
	} 
1999/0910    
} 
 
1999/1031/sys/src/9/port/devsdp.c:1726,17321999/1106/sys/src/9/port/devsdp.c:1737,1743
1999/0930    
	c->lstats.outDataPackets++; 
	c->lstats.outDataBytes += n; 
1999/1001    
 
1999/1031    
	if(c->out.comp != nil && 0) { 
1999/1106    
	if(0 && c->out.comp != nil) { 
1999/1016    
		// must generate same value as convoput 
		seq = (c->out.seq + 1) & (SeqMax-1); 
 
1999/1106/sys/src/9/port/devsdp.c:1737,17431999/1111/sys/src/9/port/devsdp.c:1737,1743 (short | long)
1999/0930    
	c->lstats.outDataPackets++; 
	c->lstats.outDataBytes += n; 
1999/1001    
 
1999/1106    
	if(0 && c->out.comp != nil) { 
1999/1111    
	if(c->out.comp != nil) { 
1999/1016    
		// must generate same value as convoput 
		seq = (c->out.seq + 1) & (SeqMax-1); 
 
1999/1111/sys/src/9/port/devsdp.c:341,3481999/1116/sys/src/9/port/devsdp.c:341,346 (short | long)
1999/0824    
	int i; 
	Dirtab *dt; 
1999/1027    
	 
	return; 
1999/0824    
                 
	// setup dirtab with non directory entries 
	for(i=0; i<nelem(sdpdirtab); i++) { 
		dt = sdpdirtab + i; 
1999/1111/sys/src/9/port/devsdp.c:774,7801999/1116/sys/src/9/port/devsdp.c:772,778
1999/0901    
			break; 
		} 
		if(canqlock(c)){ 
1999/0910    
			if(c->state == CClosed && c->reader == 0) 
1999/1116    
			if(c->state == CClosed && c->reader == 0 && c->ref == 0) 
1999/0901    
				break; 
			qunlock(c); 
		} 
1999/1116/sys/src/9/port/devsdp.c:41,481999/1211/sys/src/9/port/devsdp.c:41,48 (short | long)
1999/0824    
 
1999/0907    
	Maxconv= 256,		// power of 2 
	Nfs= 4,				// number of file systems 
1999/1001    
	MaxRetries=	8, 
1999/0909    
	KeepAlive = 60,		// keep alive in seconds 
1999/1211    
	MaxRetries=	4, 
	KeepAlive = 10,		// keep alive in seconds 
1999/1015    
	SecretLength= 32,	// a secret per direction 
1999/1001    
	SeqMax = (1<<24), 
	SeqWindow = 32, 
1999/1116/sys/src/9/port/devsdp.c:104,1091999/1211/sys/src/9/port/devsdp.c:104,110
1999/0901    
 
1999/0907    
// conv states 
1999/0902    
enum { 
1999/1211    
	CFree, 
1999/0906    
	CInit, 
1999/0909    
	CDial, 
	CAccept, 
1999/1116/sys/src/9/port/devsdp.c:115,1261999/1211/sys/src/9/port/devsdp.c:116,130
1999/0902    
 
1999/0901    
struct Conv { 
	QLock; 
1999/0824    
	int	id; 
1999/0906    
	int ref;	// number of times the conv is opened 
1999/0824    
	Sdp	*sdp; 
1999/1211    
	int	id; 
1999/0901    
 
1999/1211    
	int ref;	// holds conv up 
 
1999/0902    
	int state; 
1999/0906    
	int dataopen; 
1999/1211    
 
	int dataopen;	// ref count of opens on Qdata 
	int controlopen;	// ref count of opens on Qcontrol 
1999/0910    
	int reader;		// reader proc has been started 
1999/0901    
 
1999/0929    
	Stats	lstats; 
1999/1116/sys/src/9/port/devsdp.c:137,1431999/1211/sys/src/9/port/devsdp.c:141,147
1999/0910    
	QLock readlk;		// protects readproc 
1999/0907    
	Proc *readproc; 
1999/0910    
 
1999/0902    
	Chan *chan;	// packet channel 
1999/1211    
	Chan *chan;		// packet channel 
1999/0910    
	char *channame; 
1999/0902    
 
1999/0907    
	char owner[NAMELEN];		/* protections */ 
1999/1116/sys/src/9/port/devsdp.c:268,3021999/1211/sys/src/9/port/devsdp.c:272,308
1999/0824    
static Dirtab	*dirtab[MaxQ]; 
static Sdp sdptab[Nfs]; 
1999/0908    
static char *convstatename[] = { 
	[CInit] "Init", 
1999/0909    
	[CDial] "Dial", 
	[CAccept] "Accept", 
1999/0908    
	[COpen] "Open", 
1999/1211    
	[CFree]		"Free", 
	[CInit]		"Init", 
	[CDial]		"Dial", 
	[CAccept]	"Accept", 
	[COpen]		"Open", 
1999/0910    
	[CLocalClose] "LocalClose", 
	[CRemoteClose] "RemoteClose", 
1999/0908    
	[CClosed] "Closed", 
1999/1211    
	[CClosed]	"Closed", 
1999/0908    
}; 
1999/0824    
 
static int sdpgen(Chan *c, Dirtab*, int, int s, Dir *dp); 
1999/0901    
static Conv *sdpclone(Sdp *sdp); 
1999/0906    
static void convsetstate(Conv *c, int state); 
static void sdpackproc(void *a); 
1999/0907    
static void onewaycleanup(OneWay *ow); 
static int readready(void *a); 
static int controlread(); 
1999/1211    
static void convsetstate(Conv *c, int state); 
static Block *readcontrol(Conv *c, int n); 
static void writecontrol(Conv *c, void *p, int n, int wait); 
static Block *readdata(Conv *c, int n); 
static long writedata(Conv *c, Block *b); 
static void convderef(Conv *c); 
1999/0907    
static Block *conviput(Conv *c, Block *b, int control); 
1999/1015    
static void conviconnect(Conv *c, int op, Block *b); 
static void convicontrol(Conv *c, int op, Block *b); 
1999/1016    
static Block *convicomp(Conv *c, int op, ulong, Block *b); 
1999/0929    
static void writecontrol(Conv *c, void *p, int n, int wait); 
1999/0907    
static Block *readcontrol(Conv *c, int n); 
static Block *readdata(Conv *c, int n); 
1999/0915    
static long writedata(Conv *c, Block *b); 
1999/1015    
static void convoput(Conv *c, int type, int subtype, Block *b); 
static void convoconnect(Conv *c, int op, ulong dialid, ulong acceptid); 
1999/0910    
static void convreader(void *a); 
1999/0914    
static void convopenchan(Conv *c, char *path); 
1999/0929    
static void convstats(Conv *c, int local, char *buf, int n); 
1999/1211    
static void convreader(void *a); 
1999/0824    
 
1999/1022    
static void setalg(Conv *c, char *name, Algorithm *tab, Algorithm **); 
1999/1015    
static void setsecret(OneWay *cc, char *secret); 
1999/1116/sys/src/9/port/devsdp.c:412,4171999/1211/sys/src/9/port/devsdp.c:418,424
1999/0824    
	devstat(c, db, nil, 0, sdpgen); 
} 
 
1999/1211    
 
1999/0824    
static Chan* 
1999/0901    
sdpopen(Chan* ch, int omode) 
1999/0824    
{ 
1999/1116/sys/src/9/port/devsdp.c:450,4551999/1211/sys/src/9/port/devsdp.c:457,463
1999/0929    
	case Qstats: 
	case Qrstats: 
1999/0902    
		c = sdp->conv[CONV(ch->qid)]; 
1999/1211    
print("open %d:%d: ref=%d\n", c->id, TYPE(ch->qid), c->ref); 
1999/0902    
		qlock(c); 
		if(waserror()) { 
			qunlock(c); 
1999/1116/sys/src/9/port/devsdp.c:458,4691999/1211/sys/src/9/port/devsdp.c:466,481
1999/0902    
		if((perm & (c->perm>>6)) != perm) 
1999/0907    
		if(strcmp(up->user, c->owner) != 0 || (perm & c->perm) != perm) 
1999/0902    
				error(Eperm); 
1999/1211    
 
1999/0902    
		c->ref++; 
1999/0910    
		if(TYPE(ch->qid) == Qdata) { 
			if(c->dataopen == 0) 
1999/1211    
			c->dataopen++; 
			// kill reader if Qdata is opened for the first time 
			if(c->dataopen == 1) 
1999/0910    
			if(c->readproc != nil) 
				postnote(c->readproc, 1, "interrupt", 0); 
1999/0907    
			c->dataopen++; 
1999/1211    
		} else if(TYPE(ch->qid) == Qcontrol) {	 
			c->controlopen++; 
1999/0910    
		} 
1999/0902    
		qunlock(c); 
		poperror(); 
1999/1116/sys/src/9/port/devsdp.c:481,5121999/1211/sys/src/9/port/devsdp.c:493,537
1999/0902    
	Sdp *sdp  = sdptab + ch->dev; 
1999/0907    
	Conv *c; 
1999/0824    
 
1999/1211    
	if(!(ch->flag & COPEN)) 
		return; 
1999/0902    
	switch(TYPE(ch->qid)) { 
1999/0824    
	case Qlog: 
1999/0902    
		if(ch->flag & COPEN) 
1999/0824    
			logclose(sdp); 
1999/1211    
		logclose(sdp); 
1999/0824    
		break; 
1999/0907    
	case Qdata: 
	case Qctl: 
	case Qstatus: 
	case Qcontrol: 
		if(!(ch->flag & COPEN)) 
			break; 
1999/1211    
	case Qstats: 
	case Qrstats: 
1999/0907    
		c = sdp->conv[CONV(ch->qid)]; 
		qlock(c); 
		if(waserror()) { 
			qunlock(c); 
			nexterror(); 
1999/1211    
		convderef(c); 
		qunlock(c); 
		break; 
 
	case Qdata: 
		c = sdp->conv[CONV(ch->qid)]; 
		qlock(c); 
		c->dataopen--; 
		convderef(c); 
		if(c->dataopen == 0) 
		if(c->reader == 0) 
		if(c->chan != nil) 
		if(!waserror()) { 
			kproc("convreader", convreader, c); 
			c->reader = 1; 
			c->ref++; 
			poperror(); 
1999/0907    
		} 
		c->ref--; 
		if(TYPE(ch->qid) == Qdata) { 
			c->dataopen--; 
1999/0915    
			if(c->dataopen == 0 && c->reader == 0) { 
				kproc("convreader", convreader, c); 
				c->reader = 1; 
			} 
1999/0907    
		} 
		if(c->ref == 0) { 
1999/1211    
		qunlock(c); 
		break; 
 
	case Qcontrol: 
		c = sdp->conv[CONV(ch->qid)]; 
		qlock(c); 
		c->controlopen--; 
		convderef(c); 
		if(c->controlopen == 0 && c->ref != 0) { 
1999/0907    
			switch(c->state) { 
			default: 
				convsetstate(c, CClosed); 
1999/1116/sys/src/9/port/devsdp.c:515,5221999/1211/sys/src/9/port/devsdp.c:540,545
1999/0907    
			case COpen: 
1999/0910    
				convsetstate(c, CLocalClose); 
1999/0907    
				break; 
1999/0910    
			case CLocalClose: 
				panic("local close already happened"); 
1999/0907    
			} 
		} 
		qunlock(c); 
1999/1116/sys/src/9/port/devsdp.c:771,7781999/1211/sys/src/9/port/devsdp.c:794,802
1999/0901    
			sdp->nconv++; 
			break; 
		} 
		if(canqlock(c)){ 
1999/1116    
			if(c->state == CClosed && c->reader == 0 && c->ref == 0) 
1999/1211    
		if(c->ref == 0 && canqlock(c)){ 
print("%d: state=%d reader=%d ref=%d\n", c->id, c->state, c->reader, c->ref); 
			if(c->ref == 0) 
1999/0901    
				break; 
			qunlock(c); 
		} 
1999/1116/sys/src/9/port/devsdp.c:783,7891999/1211/sys/src/9/port/devsdp.c:807,815
1999/0902    
	if(pp >= ep) 
1999/0901    
		return nil; 
 
1999/0902    
	c->ref++; 
1999/1211    
	assert(c->state == CFree); 
	// set ref to 2 - 1 ref for open - 1 ref for channel state 
	c->ref = 2; 
1999/0906    
	c->state = CInit; 
1999/1001    
	c->in.window = ~0; 
1999/0907    
	strncpy(c->owner, up->user, sizeof(c->owner)); 
1999/1116/sys/src/9/port/devsdp.c:819,8241999/1211/sys/src/9/port/devsdp.c:845,851
1999/0906    
	return 1; 
} 
 
1999/1211    
// assumes c is locked 
1999/0902    
static void 
1999/0906    
convtimer(Conv *c, ulong sec) 
1999/0902    
{ 
1999/1116/sys/src/9/port/devsdp.c:826,8371999/1211/sys/src/9/port/devsdp.c:853,862
1999/0914    
 
1999/1001    
	if(c->timeout > sec) 
1999/0906    
		return; 
1999/0902    
	qlock(c); 
1999/0906    
	if(waserror()) { 
1999/0902    
		qunlock(c); 
1999/0906    
		nexterror(); 
1999/0902    
	} 
1999/1211    
 
1999/0906    
	switch(c->state) { 
1999/1211    
	case CInit: 
		break; 
1999/0909    
	case CDial: 
1999/0914    
		if(convretry(c, 1)) 
1999/1015    
			convoconnect(c, ConOpenRequest, c->dialid, 0); 
1999/1116/sys/src/9/port/devsdp.c:873,8831999/1211/sys/src/9/port/devsdp.c:898,905
1999/0906    
		break; 
1999/0914    
	case CRemoteClose: 
	case CClosed: 
1999/1001    
		c->timeout = ~0; 
1999/0914    
		break; 
1999/0906    
	} 
1999/0914    
	poperror(); 
1999/0906    
	qunlock(c); 
} 
1999/0902    
 
 
1999/1116/sys/src/9/port/devsdp.c:895,9041999/1211/sys/src/9/port/devsdp.c:917,932
1999/0906    
		qlock(sdp); 
		for(i=0; i<sdp->nconv; i++) { 
			c = sdp->conv[i]; 
			if(!waserror()) { 
1999/1211    
			if(c->ref == 0) 
				continue; 
			qunlock(sdp); 
			qlock(c); 
			if(c->ref > 0 && !waserror()) { 
1999/0906    
				convtimer(c, sec); 
				poperror(); 
			} 
1999/1211    
			qunlock(c); 
			qlock(sdp); 
1999/0906    
		} 
		qunlock(sdp); 
1999/0902    
	} 
1999/1116/sys/src/9/port/devsdp.c:949,9541999/1211/sys/src/9/port/devsdp.c:977,983
1999/0909    
		break; 
1999/0906    
	case COpen: 
1999/0909    
		assert(c->state == CDial || c->state == CAccept); 
1999/1211    
		c->lastrecv = TK2SEC(m->ticks); 
1999/0909    
		if(c->state == CDial) { 
			convretryinit(c); 
1999/1015    
			convoconnect(c, ConOpenAckAck, c->dialid, c->acceptid); 
1999/1116/sys/src/9/port/devsdp.c:971,9771999/1211/sys/src/9/port/devsdp.c:1000,1006
1999/0906    
		break; 
1999/0910    
	case CRemoteClose: 
1999/0914    
		wakeup(&c->in.controlready); 
1999/1027    
// convoconnect(c, ConReset, c->dialid, c->acceptid); 
1999/1211    
		wakeup(&c->out.controlready); 
1999/0910    
		break; 
1999/0906    
	case CClosed: 
1999/0914    
		wakeup(&c->in.controlready); 
1999/1116/sys/src/9/port/devsdp.c:978,10141999/1211/sys/src/9/port/devsdp.c:1007,1058
1999/0915    
		wakeup(&c->out.controlready); 
1999/0907    
		if(c->readproc) 
			postnote(c->readproc, 1, "interrupt", 0); 
1999/0915    
print("CClosed -> ref = %d\n", c->ref); 
1999/0907    
		if(c->chan) {	 
			cclose(c->chan); 
			c->chan = nil; 
		} 
1999/0915    
		if(c->ref) 
			break; 
1999/0910    
		if(c->channame) { 
			free(c->channame); 
			c->channame = nil; 
		} 
1999/1022    
		c->cipher = nil; 
		c->auth = nil; 
		c->comp = nil; 
1999/1001    
	strcpy(c->owner, "network"); 
1999/0907    
		c->perm = 0660; 
		c->dialid = 0; 
		c->acceptid = 0; 
1999/1001    
		c->timeout = ~0; 
1999/0907    
		c->retries = 0; 
		c->drop = 0; 
		onewaycleanup(&c->in); 
		onewaycleanup(&c->out); 
1999/1001    
		memset(&c->lstats, 0, sizeof(Stats)); 
		memset(&c->rstats, 0, sizeof(Stats)); 
1999/1211    
		if(c->state != CClosed) 
			convderef(c); 
1999/0906    
		break; 
	} 
	c->state = state; 
} 
 
1999/1211    
 
//assumes c is locked 
1999/0906    
static void 
1999/1211    
convderef(Conv *c) 
{ 
	c->ref--; 
print("convderef: %d: ref == %d\n", c->id, c->ref); 
	if(c->ref > 0) 
		return; 
	assert(c->ref == 0); 
	assert(c->dataopen == 0); 
	assert(c->controlopen == 0); 
//print("convderef: %d: ref == 0!\n", c->id); 
	c->state = CFree; 
	if(c->chan) {	 
		cclose(c->chan); 
		c->chan = nil; 
	} 
	if(c->channame) { 
		free(c->channame); 
		c->channame = nil; 
	} 
	c->cipher = nil; 
	c->auth = nil; 
	c->comp = nil; 
	strcpy(c->owner, "network"); 
	c->perm = 0660; 
	c->dialid = 0; 
	c->acceptid = 0; 
	c->timeout = 0; 
	c->retries = 0; 
	c->drop = 0; 
	onewaycleanup(&c->in); 
	onewaycleanup(&c->out); 
	memset(&c->lstats, 0, sizeof(Stats)); 
	memset(&c->rstats, 0, sizeof(Stats)); 
} 
 
static void 
1999/0907    
onewaycleanup(OneWay *ow) 
1999/0906    
{ 
1999/0907    
	if(ow->controlpkt) 
1999/1116/sys/src/9/port/devsdp.c:1040,10461999/1211/sys/src/9/port/devsdp.c:1084,1095
1999/0914    
		nexterror(); 
	} 
	kproc("convreader", convreader, c); 
1999/1211    
 
	assert(c->reader == 0 && c->ref > 0); 
	// after kproc in case it fails 
1999/0914    
	c->reader = 1; 
1999/1211    
	c->ref++; 
 
1999/0914    
	poperror(); 
} 
1999/0907    
 
1999/1116/sys/src/9/port/devsdp.c:1215,12211999/1211/sys/src/9/port/devsdp.c:1264,1270
1999/1001    
	if(seqdiff > 0) { 
		while(seqdiff > 0 && c->in.window != 0) { 
			if((c->in.window & (1<<(SeqWindow-1))) == 0) { 
print("missing packet: %ld\n", seq - seqdiff); 
1999/1211    
//print("missing packet: %ld\n", seq - seqdiff); 
1999/1001    
				c->lstats.inMissing++; 
			} 
			c->in.window <<= 1; 
1999/1116/sys/src/9/port/devsdp.c:1222,12281999/1211/sys/src/9/port/devsdp.c:1271,1277
1999/1001    
			seqdiff--; 
		} 
		if(seqdiff > 0) { 
print("missing packets: %ld-%ld\n", seq - SeqWindow - seqdiff+1, seq-SeqWindow); 
1999/1211    
//print("missing packets: %ld-%ld\n", seq - SeqWindow - seqdiff+1, seq-SeqWindow); 
1999/1001    
			c->lstats.inMissing += seqdiff; 
		} 
		c->in.seq = seq; 
1999/1116/sys/src/9/port/devsdp.c:1520,15291999/1211/sys/src/9/port/devsdp.c:1569,1575
1999/0930    
	Block *b; 
1999/0907    
 
1999/0929    
	c->lstats.outPackets++; 
1999/0906    
	if(c->chan == nil) { 
print("chan = nil\n"); 
		error("no channel attached"); 
	} 
1999/1211    
	assert(c->chan != nil); 
1999/1015    
	b = allocb(9); 
	b->wp[0] = (TConnect << 4) | op; 
	hnputl(b->wp+1, dialid); 
1999/1116/sys/src/9/port/devsdp.c:1530,15361999/1211/sys/src/9/port/devsdp.c:1576,1585
1999/1015    
	hnputl(b->wp+5, acceptid); 
	b->wp += 9; 
1999/0906    
 
1999/0930    
	convwriteblock(c, b); 
1999/1211    
	if(!waserror()) { 
		convwriteblock(c, b); 
		poperror(); 
	} 
1999/0907    
} 
 
1999/0910    
static Block * 
1999/1116/sys/src/9/port/devsdp.c:1537,15491999/1211/sys/src/9/port/devsdp.c:1586,1596
1999/0910    
convreadblock(Conv *c, int n) 
{ 
	Block *b; 
	Chan *ch = nil; 
1999/1211    
	Chan *ch; 
1999/0910    
 
	qlock(&c->readlk); 
	if(waserror()) { 
		c->readproc = nil; 
		if(ch) 
			cclose(ch); 
		qunlock(&c->readlk); 
		nexterror(); 
	} 
1999/1116/sys/src/9/port/devsdp.c:1554,15651999/1211/sys/src/9/port/devsdp.c:1601,1611
1999/0910    
	} 
	c->readproc = up; 
	ch = c->chan; 
	incref(ch); 
1999/1211    
	assert(c->ref > 0); 
1999/0910    
	qunlock(c); 
 
	b = devtab[ch->type]->bread(ch, n, 0); 
	c->readproc = nil; 
	cclose(ch); 
	poperror(); 
	qunlock(&c->readlk); 
 
1999/1116/sys/src/9/port/devsdp.c:1770,17791999/1211/sys/src/9/port/devsdp.c:1816,1822
1999/0910    
		if(b == nil) { 
1999/0915    
print("up->error = %s\n", up->error); 
			if(strcmp(up->error, Eintr) != 0) { 
				if(!waserror()) { 
					convsetstate(c, CClosed); 
					poperror(); 
				} 
1999/1211    
				convsetstate(c, CClosed); 
1999/0915    
				break; 
			} 
		} else if(!waserror()) { 
1999/1116/sys/src/9/port/devsdp.c:1783,17881999/1211/sys/src/9/port/devsdp.c:1826,1832
1999/0910    
	} 
1999/0914    
print("convreader exiting\n"); 
1999/0910    
	c->reader = 0; 
1999/1211    
	convderef(c); 
1999/0910    
	qunlock(c); 
	pexit("hangup", 1); 
1999/0906    
} 
1999/1116/sys/src/9/port/devsdp.c:2025,20311999/1211/sys/src/9/port/devsdp.c:2069,2075
1999/1022    
				cr->ovalid = 0; 
		} 
	} else if(d > 0) { 
print("missing packet: %uld %ld\n", seq, d); 
1999/1211    
//print("missing packet: %uld %ld\n", seq, d); 
1999/1022    
		// this link is hosed  
		if(d > RC4forward) 
			return 0; 
1999/1116/sys/src/9/port/devsdp.c:2039,20451999/1211/sys/src/9/port/devsdp.c:2083,2089
1999/1022    
		rc4(&cr->current, p, n); 
		cr->cseq = seq+n; 
	} else { 
print("reordered packet: %uld %ld\n", seq, d); 
1999/1211    
//print("reordered packet: %uld %ld\n", seq, d); 
1999/1022    
		dd = seq - cr->oseq; 
		if(!cr->ovalid || -d > RC4back || dd < 0) 
			return 0; 
1999/1211/sys/src/9/port/devsdp.c:41,481999/1221/sys/src/9/port/devsdp.c:41,48 (short | long)
1999/0824    
 
1999/0907    
	Maxconv= 256,		// power of 2 
	Nfs= 4,				// number of file systems 
1999/1211    
	MaxRetries=	4, 
	KeepAlive = 10,		// keep alive in seconds 
1999/1221    
	MaxRetries=	12, 
	KeepAlive = 120,	// keep alive in seconds 
1999/1015    
	SecretLength= 32,	// a secret per direction 
1999/1001    
	SeqMax = (1<<24), 
	SeqWindow = 32, 
Too many diffs (26 > 25). Stopping.


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)