Plan 9 from Bell Labs’s /usr/web/sources/extra/9hist/port/devsdp.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


## diffname port/devsdp.c 1999/0824
## diff -e /dev/null /n/emeliedump/1999/0824/sys/src/brazil/port/devsdp.c
0a
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "../port/netif.h"
#include "../port/error.h"

#include	<libcrypt.h>

typedef struct Sdp		Sdp;
typedef struct Port 	Port;

enum
{
	Qtopdir=	1,		/* top level directory */

	Qsdpdir,			/* sdp directory */
	Qclone,
	Qstats,
	Qlog,

	Qportdir,			/* directory for a protocol */
	Qctl,
	Qdata,				/* reliable control channel */
	Qpacket,			/* unreliable packet channel */
	Qerr,
	Qlisten,
	Qlocal,
	Qremote,
	Qstatus,

	MaxQ,

	Maxport=	256,		// power of 2
	Nfs=		4,			// number of file systems
};

#define TYPE(x) 	((x).path & 0xff)
#define PORT(x) 	(((x).path >> 8)&(Maxport-1))
#define QID(x, y) 	(((x)<<8) | (y))

struct Port {
	int	id;
	Sdp	*sdp;
	int	ref;
	int	closed;
};

struct Sdp {
	QLock;
	Log;
	int	nport;
	Port	*port[Maxport];
};

static Dirtab sdpdirtab[]={
	"ctl",		{Qctl},	0,	0666,
	"stats",	{Qstats},	0,	0444,
	"log",		{Qlog},		0,	0666,
};

static Dirtab portdirtab[]={
	"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,
};

static int m2p[] = {
	[OREAD]		4,
	[OWRITE]	2,
	[ORDWR]		6
};

enum {
	Logcompress=	(1<<0),
	Logauth=	(1<<1),
	Loghmac=	(1<<2),
};

static Logflag logflags[] =
{
	{ "compress",	Logcompress, },
	{ "auth",	Logauth, },
	{ "hmac",	Loghmac, },
	{ nil,		0, },
};

static Dirtab	*dirtab[MaxQ];
static Sdp sdptab[Nfs];

static int sdpgen(Chan *c, Dirtab*, int, int s, Dir *dp);

static void
sdpinit(void)
{
	int i;
	Dirtab *dt;

	// setup dirtab with non directory entries
	for(i=0; i<nelem(sdpdirtab); i++) {
		dt = sdpdirtab + i;
		dirtab[TYPE(dt->qid)] = dt;
	}

	for(i=0; i<nelem(portdirtab); i++) {
		dt = portdirtab + i;
		dirtab[TYPE(dt->qid)] = dt;
	}
}

static Chan*
sdpattach(char* spec)
{
	Chan *c;
	int dev;

	dev = atoi(spec);
	if(dev<0 || dev >= Nfs)
		error("bad specification");

	c = devattach('B', spec);
	c->qid = (Qid){QID(0, Qtopdir)|CHDIR, 0};
	c->dev = dev;

	return c;
}

static int
sdpwalk(Chan *c, char *name)
{
	if(strcmp(name, "..") == 0){
		switch(TYPE(c->qid)){
		case Qtopdir:
		case Qsdpdir:
			c->qid = (Qid){CHDIR|Qtopdir, 0};
			break;
		case Qportdir:
			c->qid = (Qid){CHDIR|Qsdpdir, 0};
			break;
		default:
			panic("sdpwalk %lux", c->qid.path);
		}
		return 1;
	}

	return devwalk(c, name, 0, 0, sdpgen);
}

static void
sdpstat(Chan* c, char* db)
{
	devstat(c, db, nil, 0, sdpgen);
}

static Chan*
sdpopen(Chan* c, int omode)
{
	int perm;
	Sdp *sdp;

	omode &= 3;
	perm = m2p[omode];
	USED(perm);

	sdp = sdptab + c->dev;

	switch(TYPE(c->qid)) {
	default:
		break;
	case Qtopdir:
	case Qsdpdir:
	case Qportdir:
	case Qstatus:
	case Qlocal:
	case Qstats:
		if(omode != OREAD)
			error(Eperm);
		break;
	case Qlog:
		logopen(sdp);
		break;
	}
	c->mode = openmode(omode);
	c->flag |= COPEN;
	c->offset = 0;
	return c;
}

static void
sdpclose(Chan* c)
{
	Sdp *sdp  = sdptab + c->dev;

	switch(TYPE(c->qid)) {
	case Qlog:
		if(c->flag & COPEN)
			logclose(sdp);
		break;
	}
}

static long
sdpread(Chan *c, void *a, long n, vlong off)
{
	char buf[256];
	Sdp *sdp = sdptab + c->dev;
	Port *port;

	USED(off);
	switch(TYPE(c->qid)) {
	default:
		error(Eperm);
	case Qtopdir:
	case Qsdpdir:
	case Qportdir:
		return devdirread(c, a, n, 0, 0, sdpgen);
	case Qlog:
		return logread(sdp, a, off, n);
	case Qstatus:
		qlock(sdp);
		port = sdp->port[PORT(c->qid)];
		if(port == 0)
			strcpy(buf, "unbound\n");
		else {
		}
		n = readstr(off, a, n, buf);
		qunlock(sdp);
		return n;
	}

}

static long
sdpwrite(Chan *c, void *a, long n, vlong off)
{
	Sdp *sdp = sdptab + c->dev;
	Cmdbuf *cb;
	char *arg0;
	char *p;
	
	USED(off);
	switch(TYPE(c->qid)) {
	default:
		error(Eperm);
	case Qctl:
		cb = parsecmd(a, n);
		qlock(sdp);
		if(waserror()) {
			qunlock(sdp);
			free(cb);
			nexterror();
		}
		if(cb->nf == 0)
			error("short write");
		arg0 = cb->f[0];
		if(strcmp(arg0, "xxx") == 0) {
			print("xxx\n");
		} else
			error("unknown control request");
		poperror();
		qunlock(sdp);
		free(cb);
		return n;
	case Qlog:
		cb = parsecmd(a, n);
		p = logctl(sdp, cb->nf, cb->f, logflags);
		free(cb);
		if(p != nil)
			error(p);
		return n;
	}
}

static int
sdpgen(Chan *c, Dirtab*, int, int s, Dir *dp)
{
	Sdp *sdp = sdptab + c->dev;
	int type = TYPE(c->qid);
	char buf[32];
	Dirtab *dt;
	Qid qid;

	switch(type) {
	default:
		// non directory entries end up here
		if(c->qid.path & CHDIR)
			panic("sdpgen: unexpected directory");	
		if(s != 0)
			return -1;
		dt = dirtab[TYPE(c->qid)];
		if(dt == nil)
			panic("sdpgen: unknown type: %d", TYPE(c->qid));
		devdir(c, c->qid, dt->name, dt->length, eve, dt->perm, dp);
		return 1;
	case Qtopdir:
		if(s != 0)
			return -1;
		devdir(c, (Qid){QID(0,Qsdpdir)|CHDIR,0}, "sdp", 0, eve, 0555, dp);
		return 1;
	case Qsdpdir:
		if(s<nelem(sdpdirtab)) {
			dt = sdpdirtab+s;
			devdir(c, dt->qid, dt->name, dt->length, eve, dt->perm, dp);
			return 1;
		}
		s -= nelem(sdpdirtab);
		if(s >= sdp->nport)
			return -1;
		qid = (Qid){QID(s,Qportdir)|CHDIR, 0};
		snprint(buf, sizeof(buf), "%d", s);
		devdir(c, qid, buf, 0, eve, 0555, dp);
		return 1;
	case Qportdir:
		if(s>=nelem(portdirtab))
			return -1;
		dt = portdirtab+s;
		qid = (Qid){QID(PORT(c->qid),TYPE(dt->qid)),0};
		devdir(c, qid, dt->name, dt->length, eve, dt->perm, dp);
		return 1;
	}
}


Dev sdpdevtab = {
	'T',
	"sdp",

	devreset,
	sdpinit,
	sdpattach,
	devclone,
	sdpwalk,
	sdpstat,
	sdpopen,
	devcreate,
	sdpclose,
	sdpread,
	devbread,
	sdpwrite,
	devbwrite,
	devremove,
	devwstat,
};
.
## diffname port/devsdp.c 1999/0901
## diff -e /n/emeliedump/1999/0824/sys/src/brazil/port/devsdp.c /n/emeliedump/1999/0901/sys/src/brazil/port/devsdp.c
325a
}

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;
.
321,322c
		dt = convdirtab+s;
		qid = (Qid){QID(CONV(c->qid),TYPE(dt->qid)),0};
.
318,319c
	case Qconvdir:
		if(s>=nelem(convdirtab))
.
314c
		qid = (Qid){QID(s,Qconvdir)|CHDIR, 0};
.
312c
		if(s >= sdp->nconv)
.
260a
print("cmd = %s\n", arg0);
.
247c
	switch(TYPE(ch->qid)) {
.
241c
	Sdp *sdp = sdptab + ch->dev;
.
239c
sdpwrite(Chan *ch, void *a, long n, vlong off)
.
235d
233a
	case Qctl:
		sprint(buf, "%lud", CONV(ch->qid));
		return readstr(off, a, n, buf);
.
226,227c
		c = sdp->conv[CONV(ch->qid)];
		if(c == 0)
.
220,221c
	case Qconvdir:
		return devdirread(ch, a, n, 0, 0, sdpgen);
.
215c
	switch(TYPE(ch->qid)) {
.
211,212c
	Sdp *sdp = sdptab + ch->dev;
	Conv *c;
.
208c
sdpread(Chan *ch, void *a, long n, vlong off)
.
188,191c
	ch->mode = openmode(omode);
	ch->flag |= COPEN;
	ch->offset = 0;
	return ch;
.
186a
	case Qclone:
		c = sdpclone(sdp);
		if(c == nil)
			error(Enodev);
		ch->qid.path = QID(c->id, Qctl);
		break;
.
179d
177c
	case Qconvdir:
.
172c
	switch(TYPE(ch->qid)) {
.
170c
	sdp = sdptab + ch->dev;
.
164a
	Conv *c;
.
161c
sdpopen(Chan* ch, int omode)
.
142c
		case Qconvdir:
.
126c
	c = devattach('T', spec);
.
110,111c
	for(i=0; i<nelem(convdirtab); i++) {
		dt = convdirtab + i;
.
96a
static Conv *sdpclone(Sdp *sdp);
.
67,69d
63c
static Dirtab convdirtab[]={
.
60a
	"clone",	{Qclone},		0,	0666,
.
58d
53,54c
	int	nconv;
	Conv	*conv[Maxconv];
.
46,47c

	Chan chan;	// packet channel

	char	user[NAMELEN];		/* protections */
	int	perm;
	int	inuse;
	int	length;
	int	state;

	OneWay	in;
	OneWay	out;
.
43c
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;

.
40c
#define CONV(x) 	(((x).path >> 8)&(Maxconv-1))
.
35c
	Maxconv=	256,		// power of 2
.
27,30d
23c
	Qconvdir,			/* directory per conversation */
.
12c
typedef struct Conv 	Conv;
typedef struct OneWay OneWay;
.
## diffname port/devsdp.c 1999/0902
## diff -e /n/emeliedump/1999/0901/sys/src/brazil/port/devsdp.c /n/emeliedump/1999/0902/sys/src/brazil/port/devsdp.c
400a
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);
}
.
397a

.
395,396d
392c
	c->ref++;
	c->state = COpening;

.
390d
388c
	if(pp >= ep)
.
386a
	poperror();
	qunlock(sdp);
.
383d
381c
			if(c->state == CClosed)
.
366a
	qlock(sdp);
	if(waserror()) {
		qunlock(sdp);
		nexterror();
	}
.
260,261c
		n = readstr(off, a, n, s);
		qunlock(c);
.
256,258c
		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;
.
254d
240a
	char *s;
.
230c
		if(ch->flag & COPEN)
.
228c
	switch(TYPE(ch->qid)) {
.
226c
	Sdp *sdp  = sdptab + ch->dev;
.
224c
sdpclose(Chan* ch)
.
215a
	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;
.
202d
91c
	"control",	{Qcontrol},	0,	0666,
.
79c
	Conv *conv[Maxconv];
.
71,72c
	In	in;
	Out	out;
.
67,69d
64a
	Chan *chan;	// packet channel

.
63c
	int state;
	ulong session;
.
60a
	int ref;
.
59d
56a
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,
};

.
51,54c
	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);
.
46,49c
	Block	*controlpkt;		// control channel
	ulong	*controlseq;
	ulong	controltimeout;		// timeout when it will be resent
	int		controlretries;
.
44d
40c
struct Out
.
26,27c
	Qdata,				/* unreliable packet channel */
	Qcontrol,			/* reliable control channel */
.
11,13c
typedef struct Sdp Sdp;
typedef struct Conv Conv;
typedef struct Out Out;
typedef struct In In;
.
## diffname port/devsdp.c 1999/0906
## diff -e /n/emeliedump/1999/0902/sys/src/brazil/port/devsdp.c /n/emeliedump/1999/0906/sys/src/brazil/port/devsdp.c
511a

// 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);
}
.
489d
485,487c
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);
.
482,483d
480a
	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);
}
.
479c
		nexterror();
.
474,477c
	if(waserror()) {
.
472a
	if(c->timeout == 0 || c->timeout > sec)
		return;
.
471c
convtimer(Conv *c, ulong sec)
.
469a
// 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;
}

.
461c
	c->state = CInit;
.
361c
		qunlock(c);
.
356,357c
		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]);
.
348c
			qunlock(c);
.
346c
		qlock(c);
.
344a
		c = sdp->conv[CONV(ch->qid)];
print("Qctl write : conv->id = %d\n", c->id);
.
338a
	Conv *c;
.
186a
	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);
	}
	
.
177a
	char buf[100];
	Sdp *sdp;
	int start;
.
170a

.
153a
static void convsetstate(Conv *c, int state);
static void sendconnect(Conv *c, int op, ulong dialid, ulong acceptid);
static void sdpackproc(void *a);
.
115a
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];
};

.
113a
	int ackproc;
.
111a
	Rendez	vous;			/* used by sdpackproc */
.
104a
	int drop;

.
99a
	Proc *readproc;

	ulong	timeout;
	int		retries;

	// the following pair uniquely define conversation on this port
	ulong dialid;
	ulong acceptid;

.
98c
	int dataopen;
.
94c
	int ref;	// number of times the conv is opened
.
88a
	CClosed,
.
85c
	CInit,
.
48,49d
34a
	Maxretries=	4,
.
14a
typedef struct ConPkt ConPkt;
.
## diffname port/devsdp.c 1999/0907
## diff -e /n/emeliedump/1999/0906/sys/src/brazil/port/devsdp.c /n/emeliedump/1999/0907/sys/src/brazil/port/devsdp.c
691a
}

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;
	}
.
677a

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;

.
676c
	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));
}
.
674c
onewaycleanup(OneWay *ow)
.
667a
		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);
.
663a
		convoput2(c, ConClose, c->dialid, c->acceptid);
.
656c
			convoput2(c, ConOpenAck, c->dialid, c->acceptid);
.
648c
		convoput2(c, ConOpen, c->dialid, 0);
.
638a

print("convsetstate %d -> %d\n", c->state, state);

.
584c
			convoput2(c, ConClose, c->dialid, c->acceptid);
.
576c
			convoput2(c, ConOpen, c->dialid, 0);
.
541c
	strncpy(c->owner, up->user, sizeof(c->owner));
.
389a
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);
}

.
386a
	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;
.
350a
	Block *b;
.
340a
	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;
.
334a
	Conv *c;
.
320a
		if(TYPE(ch->qid) == Qdata)
			c->dataopen++;
.
318c
		if(strcmp(up->user, c->owner) != 0 || (perm & c->perm) != perm)
.
197a

.
196a
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);
.
195d
155a

.
147c
struct ConnectPkt
.
117,118c
	OneWay	in;
	OneWay	out;
.
114a
	uchar	masterkey[KeyLength];

.
112c
	char owner[NAMELEN];		/* protections */
.
109a
	Proc *readproc;
	QLock readlk;
.
101d
63,83c
// conv states
.
60c
	int		(*comp)(OneWay*, uchar *dst, uchar *src, int n);
.
57c
	int		(*auth)(OneWay*, uchar *buf, int len);
.
52,53c
	int		cipherivlen;	// initial vector length
	int		cipherblklen;	// block length
	int		(*cipher)(OneWay*, uchar *buf, int len);
.
49c
	ulong	controlseq;
.
47a
	Rendez	controlready;
.
46a
	ulong	window;
.
43c
struct OneWay
.
36a
	KeyLength= 32,
.
34,35c
	Maxconv= 256,		// power of 2
	Nfs= 4,				// number of file systems
.
13,15c
typedef struct OneWay OneWay;
typedef struct ConnectPkt ConnectPkt;
.
10a
/*
 * sdp - secure datagram protocol
 */

.
## diffname port/devsdp.c 1999/0908
## diff -e /n/emeliedump/1999/0907/sys/src/brazil/port/devsdp.c /n/emeliedump/1999/0908/sys/src/brazil/port/devsdp.c
706c
print("convsetstate %s -> %s\n", convstatename[c->state], convstatename[state]);
.
362c
print("close c->ref = %d\n", c->ref);
.
320a
print(c->ref = %d\n", c->ref);
.
181a
static char *convstatename[] = {
	[CInit] "Init",
	[COpening] "Opening",
	[COpen] "Open",
	[CClosing] "Closing",
	[CClosed] "Closed",
};
.
## diffname port/devsdp.c 1999/0909
## diff -e /n/emeliedump/1999/0908/sys/src/brazil/port/devsdp.c /n/emeliedump/1999/0909/sys/src/brazil/port/devsdp.c
928c
		}
	case ConCloseAck:
		if(c->state == CClosing && dialid == c->dialid && acceptid == c->acceptid)
			convsetstate(c, CClosed);
.
923,926c
		case CAccept:
		case COpen:
		case CClosing:
			if(dialid == c->dialid && acceptid == c->acceptid)
				convsetstate(c, CClosed);
.
921c
		convoput2(c, ConCloseAck, dialid, acceptid);
		// fall though
	case ConReset:
		switch(c->state) {
		case CDial:
			if(dialid == c->dialid)
				convsetstate(c, CClosed);
.
915,919d
912,913c
		case CAccept:
			if(dialid != c->dialid || acceptid != c->acceptid) {
				convoput2(c, ConReset, dialid, acceptid);
				break;
			}
			convsetstate(c, COpen);
		}
.
910c
		switch(c->state) {
		case CDial:
			if(dialid != c->dialid) {
				convoput2(c, ConReset, dialid, acceptid);
				break;
			}
			c->acceptid = acceptid;
			convsetstate(c, COpen);
.
903,907c
	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;
		}
.
742,743d
740a
		assert(c->state == COpen);
		convretryinit(c);
.
734,736d
728,732c
		assert(c->state == CDial || c->state == CAccept);
		if(c->state == CDial) {
			convretryinit(c);
.
726a
	case CAccept:
		assert(c->state == CInit);
		c->acceptid = (rand()<<16) + rand();
		convretryinit(c);
		convoput2(c, ConOpenAck, c->dialid, c->acceptid);
		break;
.
723,725c
		convretryinit(c);
		convoput2(c, ConOpenRequest, c->dialid, 0);
.
719,721c
	case CDial:
		assert(c->state == CInit);
.
656d
653c
		// check for control packet and keepalive
.
651a
	case CAccept:
		if(convretry(c))
			convoput2(c, ConOpenAck, c->dialid, c->acceptid);
		break;
.
650c
			convoput2(c, ConOpenRequest, c->dialid, 0);
.
647,648c
	case CDial:
.
645a
print("convtimer: %s\n", convstatename[c->state]);
.
632c
	c->timeout = TK2SEC(m->ticks) + (c->retries+1);
.
627c
	if(c->retries > MaxRetries) {
.
622a
static void
convretryinit(Conv *c)
{
	c->retries = 0;
	// +2 to avoid rounding effects.
	c->timeout = TK2SEC(m->ticks) + 2;
};

// assume c is locked
.
505c
			convsetstate(c, CDial);
.
501c
			convsetstate(c, CAccept);
.
411,427c
		n = readstr(off, a, n, convstatename[c->state]);
.
394d
375a
			case CAccept:
.
328d
184c
	[CDial] "Dial",
	[CAccept] "Accept",
.
134a
	ConReset,
.
132d
130c
	ConOpenRequest,
.
73c
	CDial,
	CAccept,
.
39c
	MaxRetries=	8,
	KeepAlive = 60,		// keep alive in seconds
.
## diffname port/devsdp.c 1999/0910
## diff -e /n/emeliedump/1999/0909/sys/src/brazil/port/devsdp.c /n/emeliedump/1999/0910/sys/src/brazil/port/devsdp.c
1083a
}

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);
.
1071,1072d
1061a
	return 0;
.
1034,1060c
		sleep(&c->in.controlready, readready, c);
.
1021c
		if(c->state == CInit || c->state == CClosed) {
.
1018a
	USED(n);
.
1011c
	return (c->state == CClosed) || c->in.controlpkt != nil;
.
1005a
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;
}

.
954a
Reset:
	// invalid connection message - reset to sender
	convoput2(c, ConReset, dialid, acceptid);
.
953c
			return;
		case CRemoteClose:
			return;
		}
		return;
.
950,951c
		return;
	case ConReset:
		switch(c->state) {
		case CInit:
		case CDial:
		case CAccept:
		case COpen:
		case CLocalClose:
.
945,948c
			convsetstate(c, CRemoteClose);
			return;
		case CRemoteClose:
			return;
.
943a
		case CLocalClose:
			convsetstate(c, CClosed);
			return;
.
940,942d
938a
		case CInit:
.
935,937c
		convoput2(c, ConReset, dialid, acceptid);
.
931a
			return;
		case COpen:
			// duplicate that we ignore
			return;
.
927,930d
925c
			return;
		case COpen:
			// duplicate that we have to ack
			convoput2(c, ConOpenAckAck, acceptid, dialid);
			return;
		}
		break;
	case ConOpenAckAck:
		switch(c->state) {
.
919,922d
911,913c
			// duplicate ConOpenRequest that we ignore
			return;
.
908c
			return;
.
902,904d
898c
	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);
.
856,857d
802,810d
786,800d
781,784d
750a
		if(c->channame) {
			free(c->channame);
			c->channame = nil;
		}
.
741a
	case CRemoteClose:
		convoput2(c, ConReset, c->dialid, c->acceptid);
		break;
.
737,738c
	case CLocalClose:
		assert(c->state == CAccept || c->state == COpen);
.
733c
			convoput2(c, ConOpenAckAck, c->dialid, c->acceptid);
.
654c
	case CLocalClose:
.
649a
		else
			convoput2(c, ConReset, c->dialid, c->acceptid);
.
600c
	if(!waserror()) {
		kproc("convreader", convreader, c);
		c->reader = 1;
	}
.
587c
			if(c->state == CClosed && c->reader == 0)
.
489,490c
			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]);
.
483,487c
			c->channame = malloc(strlen(cb->f[1])+1);
			strcpy(c->channame, cb->f[1]);
.
481c
				error("already connected");
.
479c
				error("usage: accect file");
.
477c
		if(strcmp(arg0, "accept") == 0) {
.
382,383c
			case CLocalClose:
				panic("local close already happened");
.
380c
				convsetstate(c, CLocalClose);
.
332a
		}
.
331c
		if(TYPE(ch->qid) == Qdata) {
			if(c->dataopen == 0)
			if(c->readproc != nil)
				postnote(c->readproc, 1, "interrupt", 0);
.
205a
static void convreader(void *a);
.
189c
	[CLocalClose] "LocalClose",
	[CRemoteClose] "RemoteClose",
.
135d
133a
	ConOpenAckAck,
.
100a
	char *channame;
.
99c

.
97a
	QLock readlk;		// protects readproc
.
90d
88a
	int reader;		// reader proc has been started
.
77c
	CLocalClose,
	CRemoteClose,
.
## diffname port/devsdp.c 1999/0914
## diff -e /n/emeliedump/1999/0910/sys/src/brazil/port/devsdp.c /n/emeliedump/1999/0914/sys/src/brazil/port/devsdp.c
1143a
print("convreader exiting\n");
.
1124a
print("convreader\n");
.
1098a

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);
}

.
1096c

	// 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;
.
1094a
		qlock(c);
.
1093d
1090c
print("readcontrol: return nil - state = %s\n", convstatename[c->state]);
			return nil;
.
1086,1088c
		if(c->in.controlpkt != nil)
			break;

		if(c->state == CRemoteClose) {
.
1083c
print("readcontrol: return error - state = %s\n", convstatename[c->state]);
			error("conversation closed");
.
1080d
1078a
	qlock(c);
.
1070c
	return c->in.controlpkt != nil || (c->state == CClosed) || (c->state == CRemoteClose);
.
979a
print("invalid conviput2 - sending reset\n");
.
912d
890a
print("conviput2: %s: %d %uld %uld\n", convstatename[c->state], con->op, dialid, acceptid);

.
862c
		c->out.controlpkt = nil;
.
857a
print("ControlAck expected %ulx got %ulx\n", c->out.controlseq, cseq);
.
851a
print("recv %ld size=%ld\n", cseq, BLEN(b));
.
848d
840,842c
			if(c->in.controlpkt == nil) {
				// send ack
				b->wp = b->rp + 4;
				convoput(c, TControlAck, b);
			} else
				freeb(b);
.
838a
print("duplicate control packet: %ulx\n", cseq);
.
827a
print("coniput seq=%ulx\n", seq);
.
803a
// 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();
}
.
761a
		wakeup(&c->in.controlready);
.
758a
		wakeup(&c->in.controlready);
.
674a
	poperror();
.
673a
	case CRemoteClose:
	case CClosed:
		c->timeout = 0;
		break;
.
671c
		if(convretry(c, 0))
.
668c
		b = c->out.controlpkt;
		if(b != nil) {
			if(convretry(c, 1))
				convoput(c, TControl, copyblock(b, blocklen(b)));
		} else {
			c->timeout = 0;
		}
		// keepalive
.
664,665d
662c
		if(convretry(c, 1))
.
658c
		if(convretry(c, 1))
.
655d
647a
	Block *b;

.
637a
		if(reset)
			convoput2(c, ConReset, c->dialid, c->acceptid);
.
635a
print("convretry: %s: %d\n", convstatename[c->state], c->retries);
.
633c
convretry(Conv *c, int reset)
.
611,614d
519a
	case Qcontrol:
print("writecontrol %ld\n", n);
		writecontrol(sdp->conv[CONV(ch->qid)], a, n);
		return n;
.
497,501c
			convopenchan(c, cb->f[1]);
.
489,493c
			convopenchan(c, cb->f[1]);
.
485d
474d
458a

.
437a
print("readdata\n");
.
431a
print("readcontrol asked %ld got %ld\n", n, BLEN(b));
.
381d
210a
static void convopenchan(Conv *c, char *path);
.
205a
static void writecontrol(Conv *c, void *p, int n);
.
39c
	MaxRetries=	4,
.
## diffname port/devsdp.c 1999/0915
## diff -e /n/emeliedump/1999/0914/sys/src/brazil/port/devsdp.c /n/emeliedump/1999/0915/sys/src/brazil/port/devsdp.c
1229,1232c
print("up->error = %s\n", up->error);
			if(strcmp(up->error, Eintr) != 0) {
				if(!waserror()) {
					convsetstate(c, CClosed);
					poperror();
				}
				break;
			}
		} else if(!waserror()) {
.
1220c
	while(c->dataopen == 0 && c->state != CClosed) {
.
1210a
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;
}

.
1188a
	poperror();
	qunlock(&c->out.controllk);
.
1164c

	qlock(&c->out.controllk);
	if(waserror()) {
		qunlock(&c->out.controllk);
		nexterror();
	}
	qlock(c);	// this lock is not held in the sleep below
.
1146a
	poperror();
	qunlock(&c->in.controllk);
.
1130a
			poperror();
.
1117c

	qlock(&c->in.controllk);
	if(waserror()) {
		qunlock(&c->in.controllk);
		nexterror();
	}
	qlock(c);	// this lock is not held during the sleep below

.
1044a
print("convoput\n");
.
818c
	if(c->state != CInit || c->chan != nil)
.
779a
		if(c->ref)
			break;
.
774,775c
print("CClosed -> ref = %d\n", c->ref);
.
771a
		wakeup(&c->out.controlready);
.
520a
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);
}

.
517a
	case Qdata:
		b = allocb(n);
		memmove(b->wp, a, n);
		b->wp += n;
		return writedata(sdp->conv[CONV(ch->qid)], b);
.
470a
	Block *b;
.
380,381c
			if(c->dataopen == 0 && c->reader == 0) {
				kproc("convreader", convreader, c);
				c->reader = 1;
			}
.
208a
static long writedata(Conv *c, Block *b);
.
53a
	QLock	controllk;
.
## diffname port/devsdp.c 1999/0929
## diff -e /n/emeliedump/1999/0915/sys/src/brazil/port/devsdp.c /n/emeliedump/1999/0929/sys/src/brazil/port/devsdp.c
1269a
	c->outDataPackets++;
	c->outDataBytes += n;
	c->outCompDataBytes += n;
.
1228a
	qunlock(c);
.
1227c
	if(wait)
		writewait(c);
.
1217a
}

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);
.
1215a
		poperror();
.
1214a
		if(waserror()) {
			qlock(c);
			nexterror();
		}
.
1206d
1195,1203d
1193c
writewait(Conv *c)
.
1191a
// c is locked
.
1169,1173c
	convack(c);
.
1076a
	c->lstats.outPackets++;
.
1048c
	c->lstats.outPackets++;
.
923a
		c->lstats.inDataPackets++;
		c->lstats.inDataBytes += BLEN(b);
		c->lstats.inCompDataBytes += BLEN(b);
.
917a
		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);
.
914c
		ack = (AckPkt*)(b->rp);
		cseq = nhgetl(ack->cseq);
.
912c
		if(BLEN(b) != sizeof(AckPkt))
.
909c
			wakeup(&c->in.controlready);
		}
.
907c
		if(BLEN(b) == 0) {
			// just a ping
			freeb(b);
			convack(c);
		} else {
			c->in.controlpkt = b;
.
894,899c
			freeb(b);
			if(c->in.controlpkt == nil)
				convack(c);
.
888c
		if(BLEN(b) < 4)
.
864a
	c->lstat.inPackets++;

.
863a
	AckPkt *ack;
.
857a
	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);
}


.
856a
static void
convstats(Conv *c, int local, char *buf, int n)
{
	Stats *stats;
	char *p, *ep;
.
521c
		writecontrol(sdp->conv[CONV(ch->qid)], a, n, 0);
.
452a
	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;
.
412a
	int rv;
.
409a
	char *s;
.
329a
	case Qstats:
	case Qrstats:
.
313d
216d
214a
static void convstats(Conv *c, int local, char *buf, int n);
.
207c
static void writecontrol(Conv *c, void *p, int n, int wait);
.
163a
	"stats",	{Qstats},	0,	0444,
	"rstats",	{Qrstats},	0,	0444,
.
154d
152a

.
151a
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];
};
.
92a
	Stats	lstats;
	Stats	rstats;

.
49a
	Rendez	statsready;

.
47a
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;
};

.
33a
	Qstats,
	Qrstats,
.
26d
18a
typedef struct AckPkt AckPkt;
.
17a
typedef struct Stats Stats;
.
## diffname port/devsdp.c 1999/0930
## diff -e /n/emeliedump/1999/0929/sys/src/brazil/port/devsdp.c /n/emeliedump/1999/0930/sys/src/brazil/port/devsdp.c
1423,1425c
	c->lstats.outDataPackets++;
	c->lstats.outDataBytes += n;
	c->lstats.outCompDataBytes += n;
.
1411d
1391a
		if(b == nil)
			return nil;
.
1379a
	}
.
1378c
	if(wait) {
print("writecontrol wait!\n");
.
1230,1233c
	convwriteblock(c, b);
.
1224,1228c
	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);
.
1217c
	Block *b;
	ConnectPkt *con;
.
1205,1210c
	
	convwriteblock(c, b);
.
1184a
// 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();
}


.
1044,1056c
		}
		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);
.
1042d
1040a
		if(cseq != c->out.controlseq) {
.
1032c
if(0) print("recv %ld size=%ld\n", cseq, BLEN(b));
.
1002c
if(0) print("coniput seq=%ulx\n", seq);
.
985c
	c->lstats.inPackets++;
.
956c
	ack = (AckPkt*)b->wp;
.
936a
	p += snprint(p, ep-p, "inDataBytes: %ld\n", stats->inDataBytes);
.
928a

	qlock(c);
.
919d
492d
## diffname port/devsdp.c 1999/1001
## diff -e /n/emeliedump/1999/0930/sys/src/brazil/port/devsdp.c /n/emeliedump/1999/1001/sys/src/brazil/port/devsdp.c
1443,1444c

	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);
	}

.
1427c
	int n, nn;
	ulong seq;
	Block *bb;
.
1396d
1393,1394c
	if(wait)
.
1391d
1192c
	if(c->drop && nrand(c->drop) == 0)
.
1115d
1070a
	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;
.
1061a
		c->timeout = c->lastrecv + KeepAlive;
.
1007a
	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);
.
1002c
	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
.
984a
	ulong mseq, mask;
	Block *bb;
.
982,983c
	int type, n;
	ulong seq, seqwrap, cseq;
	long seqdiff;
.
870a
		memset(&c->lstats, 0, sizeof(Stats));
		memset(&c->rstats, 0, sizeof(Stats));
.
865c
		c->timeout = ~0;
.
861c
		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");
.
754c
		c->timeout = ~0;
.
746c

		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();
		}
.
743,744c
			break;
.
722c
	if(c->timeout > sec)
.
683a
	c->in.window = ~0;
	c->in.compstate = malloc(sizeof(Unthwack));
	unthwackinit(c->in.compstate);
	c->out.compstate = malloc(sizeof(Thwack));
	thwackinit(c->out.compstate);
.
662a
			memset(c, 0, sizeof(Conv));
.
575d
210a
#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

.
195a
struct Algorithm
{
	char 	*name;
	int		keylen;		// in bytes
	void	(*init)(Conv*, char* name, int keylen);
};
.
135a
	char *authname;
	char *ciphername;
	char *compname;
.
118c
	
	ulong	lastrecv;	// time last packet was received 
.
44a
	SeqMax = (1<<24),
	SeqWindow = 32,
.
42c
	MaxRetries=	8,
.
20a
typedef struct Algorithm Algorithm;
.
9a
#include "../port/thwack.h"
.
## diffname port/devsdp.c 1999/1015
## diff -e /n/emeliedump/1999/1001/sys/src/brazil/port/devsdp.c /n/emeliedump/1999/1015/sys/src/brazil/port/devsdp.c
1665a


/* 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
.
1616,1623c
		convoput(c, TCompData, subtype, b);
	} else
		convoput(c, TData, 0, b);
.
1596,1614c
	if(c->out.comp != nil) {
		int subtype = (*c->out.comp)(&c->out, 0, &b);
.
1577,1579c
	int n;
.
1544c
	convoput(c, TControl, ControlMesg, copyblock(b, blocklen(b)));
.
1528d
1393,1399c
	b = allocb(9);
	b->wp[0] = (TConnect << 4) | op;
	hnputl(b->wp+1, dialid);
	hnputl(b->wp+5, acceptid);
	b->wp += 9;
.
1386d
1383c
convoconnect(Conv *c, int op, ulong dialid, ulong acceptid)
.
1376a
	if(c->out.auth) {
		b = padblock(b, -c->out.authlen);
		b->wp += c->out.authlen;
		(*c->out.auth)(&c->out, b->rp, BLEN(b));
	}
.
1365c
	b->rp[0] = (type << 4) | subtype;
.
1359c
convoput(Conv *c, int type, int subtype, Block *b)
.
1339a
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;
}

.
1336,1337c
print("invalid conviconnect - sending reset\n");
	convoconnect(c, ConReset, dialid, acceptid);
.
1332c
		break;
.
1319c
		break;
.
1305c
		convoconnect(c, ConReset, dialid, acceptid);
.
1290c
			convoconnect(c, ConOpenAckAck, acceptid, dialid);
.
1269c
	switch(subtype) {
.
1262c
		if(dialid != c->dialid
		|| subtype != ConOpenRequest && acceptid != c->acceptid)
.
1247c
print("conviconnect: %s: %d %uld %uld\n", convstatename[c->state], subtype, dialid, acceptid);
.
1243,1245c
	dialid = nhgetl(b->rp);
	acceptid = nhgetl(b->rp + 4);
	freeb(b);
.
1239c
	if(BLEN(b) != 8) {
.
1235d
1233c
conviconnect(Conv *c, int subtype, Block *b)
.
1207,1224d
1199,1202c
		b = convicomp(c, subtype, b);
		if(b == nil);
			return nil;
.
1196c
	case TCompData:
.
1192d
1161,1188d
1135,1159c
		convicontrol(c, subtype, b);
.
1110c
	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;
	}

.
1077,1078c
	seq = (b->rp[0]<<16) + (b->rp[1]<<8) + b->rp[2];
	b->rp += 3;
.
1073c
		conviconnect(c, subtype, b);
.
1071c
	type = b->rp[0] >> 4;
	subtype = type & 0xf;
	b->rp += 1;
.
1060,1062d
1057,1058c
	int type, subtype;
	ulong seq, seqwrap;
.
1049c
	convoput(c, TControl, ControlAck, b);
.
941d
904c
		convoconnect(c, ConReset, c->dialid, c->acceptid);
.
900c
		convoconnect(c, ConClose, c->dialid, c->acceptid);
.
895c
		md5authinit(c, "hmac_md5_96", 16);
.
893c
			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);
.
887c
		convoconnect(c, ConOpenAck, c->dialid, c->acceptid);
.
881c
		convoconnect(c, ConOpenRequest, c->dialid, 0);
.
811c
			convoconnect(c, ConClose, c->dialid, c->acceptid);
.
805c
			convoput(c, TControl, ControlMesg, copyblock(b, blocklen(b)));
.
786c
				convoput(c, TControl, ControlMesg, copyblock(b, blocklen(b)));
.
780c
			convoconnect(c, ConOpenAck, c->dialid, c->acceptid);
.
776c
			convoconnect(c, ConOpenRequest, c->dialid, 0);
.
753c
			convoconnect(c, ConReset, c->dialid, c->acceptid);
.
742c
}
.
599a
		} 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]);
.
300a
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,
};


.
295,296c
static void convoput(Conv *c, int type, int subtype, Block *b);
static void convoconnect(Conv *c, int op, ulong dialid, ulong acceptid);
.
290c
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);
.
225,249d
177,185d
169a
	ControlMesg,
	ControlAck,
};

enum {
.
165,166c
	TCompData,
.
163d
140d
96c
	int		(*comp)(OneWay*, int subtype, Block **);
.
80a
	uchar	secret[SecretLength];

.
46c
	SecretLength= 32,	// a secret per direction
.
20d
## diffname port/devsdp.c 1999/1016
## diff -e /n/emeliedump/1999/1015/sys/src/brazil/port/devsdp.c /n/emeliedump/1999/1016/sys/src/brazil/port/devsdp.c
2028,2040c
	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;
}
.
2025,2026c
static void
thwackcompinit(Conv *c, char *name, int keylen)
{
	compfree(c);
.
2019,2023c
}
.
2014,2017c
		*bp = b;
		return 1;
.
2007,2008c
		if(n < 0) {
print("unthwack failed: %r!\n");
			freeb(b);
			return 0;
		}
.
1996,2003c
		return 1;
	case ThwackC:
		bb = *bp;
.
1990,1991c
	switch(subtype) {
	default:
		return 0;
	case ThwackU:
		b = *bp;
.
1988a
static int
thwackuncomp(Conv *c, int subtype, ulong seq, Block **bp)
{
	Block *b, *bb;
	ulong mask;
	ulong mseq;
	int n;
.
1986a
	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;
	}
.
1984,1985c
static int
thwackcomp(Conv *c, int, ulong seq, Block **bp)
.
1981a
	compfree(c);
.
1980c
nullcompinit(Conv *c, char*, int)
.
1958,1959c
	c->authname = name;
.
1896a
	cipherfree(c);
.
1866,1867c
	c->ciphername = name;
.
1809d
1794,1797c
	c->compname = nil;
.
1776,1779c
	c->authname = nil;
.
1758,1761c
	c->ciphername = nil;
.
1754d
1644c
		// must generate same value as convoput
		seq = (c->out.seq + 1) & (SeqMax-1);

		subtype = (*c->out.comp)(c, 0, seq, &b);
.
1626a
	ulong seq;
	int subtype;
.
1383c
	if(!(*c->in.comp)(c, subtype, seq, &b))
.
1377c
convicomp(Conv *c, int subtype, ulong seq, Block *b)
.
1364a
		c->rstats.inBadComp = nhgetl(ack->inBadComp);
.
1191a
		}
.
1189,1190c
		b = convicomp(c, subtype, seq, b);
		if(b == nil) {
			c->lstats.inBadComp++;
.
1104c
	subtype = b->rp[0] & 0xf;
.
1081a
	hnputl(ack->inBadComp, s->inBadComp);
.
1051a
	p += snprint(p, ep-p, "inBadComp: %ld\n", stats->inBadComp);
.
958,969c
		c->ciphername = nil;
		c->authname = nil;
		c->compname = nil;
.
751,754d
261c
static Block *convicomp(Conv *c, int op, ulong, Block *b);
.
193a
	uchar	inBadComp[4];
.
172a
	ThwackU,
	ThwackC,
};

enum {
.
97c
	int		(*comp)(Conv*, int subtype, ulong seq, Block **);
.
67a
	ulong	inBadComp;
.
## diffname port/devsdp.c 1999/1019
## diff -e /n/emeliedump/1999/1016/sys/src/brazil/port/devsdp.c /n/emeliedump/1999/1019/sys/src/brazil/port/devsdp.c
1991c
	nn = thwack(c->out.compstate, bb->wp, b->rp, BLEN(b), seq, c->lstats.outCompStats);
.
1313a
	int i;
.
1069a
	for(i=0; i<NCompStat; i++)
		hnputl(ack->outCompStats+i*4, s->outCompStats[i]);
.
1059a
	int i;
.
1035,1048c
	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);
.
1020a
	int i;
.
192a
	uchar	outCompStats[4*NCompStats];
.
60a
	ulong	outCompStats[NCompStats];
.
47a
	NCompStats = 8,
.
## diffname port/devsdp.c 1999/1021
## diff -e /n/emeliedump/1999/1019/sys/src/brazil/port/devsdp.c /n/emeliedump/1999/1021/sys/src/brazil/port/devsdp.c
2005c
	nn = thwack(c->out.compstate, bb->wp, b->rp, BLEN(b), seq);
.
1327d
1081c
	for(i=0; i<NCompStats; i++)
.
1043,1044c
	for(i=0; i<NCompStats; i++) {
		if(stats->outCompStats[i] == 0)
.
## diffname port/devsdp.c 1999/1022
## diff -e /n/emeliedump/1999/1021/sys/src/brazil/port/devsdp.c /n/emeliedump/1999/1022/sys/src/brazil/port/devsdp.c
2060d
2056c
thwackcompinit(Conv *c)
.
2004c
	nn = thwack(c->out.compstate, bb->wp, b->rp, BLEN(b), seq, c->lstats.outCompStats);
.
1985c
nullcompinit(Conv *c)
.
1964,1965c
	keylen = c->auth->keylen;
.
1961a
	int keylen;

.
1960c
md5authinit(Conv *c)
.
1912c
shaauthinit(Conv *c)
.
1906c
nullauthinit(Conv *c)
.
1902a

	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;
.
1901a
	uchar key[32];
	CipherRc4 *cr;
	int n;

.
1900c
rc4cipherinit(Conv *c)
.
1898a
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;
}

.
1872d
1869a
	int n = c->cipher->keylen;
.
1865c
descipherinit(Conv *c)
.
1847a
	if(n < 8 || (n & 0x7 != 0))
		return 0;
.
1827a
	if(n < 8 || (n & 0x7 != 0))
		return 0;
.
1817c
nullcipherinit(Conv *c)
.
1804d
1798a
	c->in.authlen = 0;
	c->out.authlen = 0;
.
1789d
1783a
	c->in.cipherblklen = 0;
	c->out.cipherblklen = 0;
	c->in.cipherivlen = 0;
	c->out.cipherivlen = 0;
.
1774d
1721c
	*p = alg;
	alg->init(c);
.
1713c
setalg(Conv *c, char *name, Algorithm *alg, Algorithm **p)
.
1438d
1435c
	if(c->out.cipher)
		(*c->out.cipher)(&c->out, b->rp+4, BLEN(b)-4);

.
1422a
	/* 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;
	}

.
1421c
	int pad;
	
.
1378a
		c->rstats.inBadOther = nhgetl(ack->inBadOther);
.
1368a
		for(i=0; i<NCompStats; i++)
			c->rstats.outCompStats[i] = nhgetl(ack->outCompStats + 4*i);
.
1326a
	int i;
.
1208a
	c->lstats.inBadOther++;
.
1163c
	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;
		}
	}
.
1107a
		c->lstats.inBadOther++;
.
1103a
	int pad;
.
1092a
	hnputl(ack->inBadOther, s->inBadOther);
.
1058a
	p += snprint(p, ep-p, "inBadOther: %lud\n", stats->inBadOther);
.
1048d
964,966c
		c->cipher = nil;
		c->auth = nil;
		c->comp = nil;
.
937c
		setalg(c, "hmac_md5_96", authalg, &c->auth);
.
636a
			if(c->cipher)
				c->cipher->init(c);
			if(c->auth)
				c->auth->init(c);
.
632a
			if(c->cipher)
				c->cipher->init(c);
			if(c->auth)
				c->auth->init(c);
.
628c
			setalg(c, cb->f[1], compalg, &c->comp);
.
624c
			setalg(c, cb->f[1], authalg, &c->auth);
.
620c
			setalg(c, cb->f[1], cipheralg, &c->cipher);
.
298a
	"rc4_256",		32,	rc4cipherinit,
.
285,292c
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);
.
282c
static void setalg(Conv *c, char *name, Algorithm *tab, Algorithm **);
.
214a
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;
};

.
212c
	void	(*init)(Conv*);
.
205a
	uchar	inBadOther[4];
.
144,146c
	Algorithm *auth;
	Algorithm *cipher;
	Algorithm *comp;
.
72a
	ulong	inBadOther;
.
21a
typedef struct CipherRc4 CipherRc4;
.
## diffname port/devsdp.c 1999/1027
## diff -e /n/emeliedump/1999/1022/sys/src/brazil/port/devsdp.c /n/emeliedump/1999/1027/sys/src/brazil/port/devsdp.c
974c
// convoconnect(c, ConReset, c->dialid, c->acceptid);
.
908c
	'E',
.
558a
print("readcontrol asked %ld\n", n);
.
370c
	c = devattach('E', spec);
.
342a
	
	return;
.
333c
//	"thwack",		0,	thwackcompinit,
.
## diffname port/devsdp.c 1999/1028
## diff -e /n/emeliedump/1999/1027/sys/src/brazil/port/devsdp.c /n/emeliedump/1999/1028/sys/src/brazil/port/devsdp.c
561d
333c
	"thwack",		0,	thwackcompinit,
.
## diffname port/devsdp.c 1999/1031
## diff -e /n/emeliedump/1999/1028/sys/src/brazil/port/devsdp.c /n/emeliedump/1999/1031/sys/src/9/port/devsdp.c
1729c
	if(c->out.comp != nil && 0) {
.
1188c
print("bad auth %d\n", BLEN(b)+4);
.
## diffname port/devsdp.c 1999/1106
## diff -e /n/emeliedump/1999/1031/sys/src/9/port/devsdp.c /n/emeliedump/1999/1106/sys/src/9/port/devsdp.c
1729c
	if(0 && c->out.comp != nil) {
.
1703a
		}
.
1702c
		if(b != nil) {
			if(BLEN(b) > n)
				b->wp = b->rp + n;
.
1691c

		// 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);
.
1688a
	int nn;
.
1188c
print("bad auth %ld\n", BLEN(b)+4);
.
## diffname port/devsdp.c 1999/1111
## diff -e /n/emeliedump/1999/1106/sys/src/9/port/devsdp.c /n/emeliedump/1999/1111/sys/src/9/port/devsdp.c
1740c
	if(c->out.comp != nil) {
.
## diffname port/devsdp.c 1999/1116
## diff -e /n/emeliedump/1999/1111/sys/src/9/port/devsdp.c /n/emeliedump/1999/1116/sys/src/9/port/devsdp.c
777c
			if(c->state == CClosed && c->reader == 0 && c->ref == 0)
.
344,345d
## diffname port/devsdp.c 1999/1211
## diff -e /n/emeliedump/1999/1116/sys/src/9/port/devsdp.c /n/emeliedump/1999/1211/sys/src/9/port/devsdp.c
2042c
//print("reordered packet: %uld %ld\n", seq, d);
.
2028c
//print("missing packet: %uld %ld\n", seq, d);
.
1785a
	convderef(c);
.
1773,1776c
				convsetstate(c, CClosed);
.
1562d
1557c
	assert(c->ref > 0);
.
1545,1546d
1540c
	Chan *ch;
.
1533c
	if(!waserror()) {
		convwriteblock(c, b);
		poperror();
	}
.
1523,1526c
	assert(c->chan != nil);
.
1225c
//print("missing packets: %ld-%ld\n", seq - SeqWindow - seqdiff+1, seq-SeqWindow);
.
1218c
//print("missing packet: %ld\n", seq - seqdiff);
.
1043a
	c->ref++;

.
1042a

	assert(c->reader == 0 && c->ref > 0);
	// after kproc in case it fails
.
1011a
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
.
1010a

//assumes c is locked
.
981,1005c
		if(c->state != CClosed)
			convderef(c);
.
974c
		wakeup(&c->out.controlready);
.
951a
		c->lastrecv = TK2SEC(m->ticks);
.
901a
			qunlock(c);
			qlock(sdp);
.
898c
			if(c->ref == 0)
				continue;
			qunlock(sdp);
			qlock(c);
			if(c->ref > 0 && !waserror()) {
.
879,880d
876d
834a
	case CInit:
		break;
.
829,833c

.
821a
// assumes c is locked
.
786c
	assert(c->state == CFree);
	// set ref to 2 - 1 ref for open - 1 ref for channel state
	c->ref = 2;
.
774,775c
		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)
.
518,519d
501,509c
		qunlock(c);
		break;

	case Qcontrol:
		c = sdp->conv[CONV(ch->qid)];
		qlock(c);
		c->controlopen--;
		convderef(c);
		if(c->controlopen == 0 && c->ref != 0) {
.
497,499c
		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();
.
492,494c
	case Qstats:
	case Qrstats:
.
489d
486,487c
		logclose(sdp);
.
483a
	if(!(ch->flag & COPEN))
		return;
.
466c
		} else if(TYPE(ch->qid) == Qcontrol) {	
			c->controlopen++;
.
463c
			c->dataopen++;
			// kill reader if Qdata is opened for the first time
			if(c->dataopen == 1)
.
460a

.
452a
print("open %d:%d: ref=%d\n", c->id, TYPE(ch->qid), c->ref);
.
414a

.
299a
static void convreader(void *a);
.
297d
291,294d
286a
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);
.
282d
277c
	[CClosed]	"Closed",
.
271,274c
	[CFree]		"Free",
	[CInit]		"Init",
	[CDial]		"Dial",
	[CAccept]	"Accept",
	[COpen]		"Open",
.
140c
	Chan *chan;		// packet channel
.
123c

	int dataopen;	// ref count of opens on Qdata
	int controlopen;	// ref count of opens on Qcontrol
.
121a
	int ref;	// holds conv up

.
120a
	int	id;
.
118,119d
106a
	CFree,
.
44,45c
	MaxRetries=	4,
	KeepAlive = 10,		// keep alive in seconds
.
## diffname port/devsdp.c 1999/1221
## diff -e /n/emeliedump/1999/1211/sys/src/9/port/devsdp.c /n/emeliedump/1999/1221/sys/src/9/port/devsdp.c
44,45c
	MaxRetries=	12,
	KeepAlive = 120,	// keep alive in seconds
.
## diffname port/devsdp.c 1999/1230
## diff -e /n/emeliedump/1999/1221/sys/src/9/port/devsdp.c /n/emeliedump/1999/1230/sys/src/9/port/devsdp.c
729a

	if(s == DEVDOTDOT){
		switch(TYPE(c->qid)){
		case Qtopdir:
		case Qsdpdir:
			snprint(buf, sizeof(buf), "#E%d", c->dev);
			devdir(c, (Qid){CHDIR|Qtopdir, 0}, buf, 0, eve, 0555, dp);
			break;
		case Qconvdir:
			snprint(buf, sizeof(buf), "%d", s);
			devdir(c, (Qid){CHDIR|Qsdpdir, 0}, buf, 0, eve, 0555, dp);
			break;
		default:
			panic("sdpwalk %lux", c->qid.path);
		}
		return 1;
	}
.
397,411d
## diffname port/devsdp.c 2000/0112
## diff -e /n/emeliedump/1999/1230/sys/src/9/port/devsdp.c /n/emeliedump/2000/0112/sys/src/9/port/devsdp.c
2194c
	seanq_hmac_md5(hash, ow->seqwrap, t, tlen, (uchar*)ow->authstate, 16);
.
2159c
seanq_hmac_md5(uchar hash[MD5dlen], ulong wrap, uchar *t, long tlen, uchar *key, long klen)
.
1888,1889c
		sha1((uchar*)prefix, strlen(prefix), ibuf, sha1(salt, round+1, nil, nil));
		md5(ibuf, SHA1dlen, obuf, md5(ow->secret, sizeof(ow->secret), nil, nil));
.
1882c
	uchar ibuf[SHA1dlen], obuf[MD5dlen], salt[10];
.
996c
		setalg(c, "seanq_hmac_md5_96", authalg, &c->auth);
.
331,332c
	"seanq_hmac_sha1_96",	16,	shaauthinit,
	"seanq_hmac_md5_96",	16,	md5authinit,
.
9c
#include	<libsec.h>
.
## diffname port/devsdp.c 2000/0115
## diff -e /n/emeliedump/2000/0112/sys/src/9/port/devsdp.c /n/emeliedump/2000/0115/sys/src/9/port/devsdp.c
996c
		setalg(c, "hmac_md5_96", authalg, &c->auth);
.
331,332c
	"hmac_sha1_96",	16,	shaauthinit,
	"hmac_md5_96",	16,	md5authinit,
.
## diffname port/devsdp.c 2000/0215
## diff -e /n/emeliedump/2000/0115/sys/src/9/port/devsdp.c /n/emeliedump/2000/0215/sys/src/9/port/devsdp.c
1640c
		if(c->chan == nil || c->state == CClosed) {
.
1420a
	convsetstate(c, CClosed);
.
1412,1413d
1405,1408d
1403c
	case ConCloseAck:
.
1399a
			// duplicate ConClose
			convoconnect(c, ConCloseAck, dialid, acceptid);
.
1396a
			convoconnect(c, ConCloseAck, dialid, acceptid);
.
1390,1395d
1388d
1382a
		case CLocalClose:
		case CRemoteClose:
.
1330a
	if(subtype == ConReset) {
		convsetstate(c, CClosed);
		return;
	}

.
1201a
	switch(c->state) {
	case CInit:
	case CDial:
		c->lstats.inBadOther++;
		convoconnect(c, ConReset, c->dialid, c->acceptid);
		convsetstate(c, CClosed);
		break;
	case CAccept:
	case CRemoteClose:
	case CLocalClose:
		c->lstats.inBadOther++;
		freeb(b);
		return nil;
	}

.
720c
			snprint(buf, sizeof(buf), "#E%ld", c->dev);
.
445c
print("open %d:%ld: ref=%d\n", c->id, TYPE(ch->qid), c->ref);
.
190a
	ConCloseAck,
.
## diffname port/devsdp.c 2000/0222
## diff -e /n/emeliedump/2000/0215/sys/src/9/port/devsdp.c /n/emeliedump/2000/0222/sys/src/9/port/devsdp.c
1843d
1833d
1821d
1701d
1698,1699c
		if(c->state == CInit || c->state == CClosed || c->state == CRemoteClose)
.
1665c
if(0)print("readcontrol: return nil - state = %s\n", convstatename[c->state]);
.
1656c
if(0)print("readcontrol: return error - state = %s\n", convstatename[c->state]);
.
1477d
1474,1475c
		if(cseq != c->out.controlseq)
.
1432c
if(0)print("invalid conviconnect - sending reset\n");
.
1345c
if(0)print("conviconnect: %s: %d %uld %uld\n", convstatename[c->state], subtype, dialid, acceptid);
.
1026d
964c
if(0)print("convsetstate %s -> %s\n", convstatename[c->state], convstatename[state]);
.
885d
841d
839d
801d
570d
446d
## diffname port/devsdp.c 2000/0425
## diff -e /n/emeliedump/2000/0222/sys/src/9/port/devsdp.c /n/emeliedump/2000/0425/sys/src/9/port/devsdp.c
2304a
	if(c->out.compstate == nil)
		error(Enomem);
.
2302a
	if(c->in.compstate == nil)
		error(Enomem);
.
1073c
	c->channame = smalloc(strlen(path)+1);
.
1025c
if(0)print("convderef: %d: ref == 0!\n", c->id);
.
1021a
	}
.
1020c
	if(c->ref > 0) {
.
958c
if(1)print("convsetstate %d: %s -> %s\n", c->id, convstatename[c->state], convstatename[state]);
.
## diffname port/devsdp.c 2000/0617
## diff -e /n/emeliedump/2000/0425/sys/src/9/port/devsdp.c /n/emeliedump/2000/0617/sys/src/9/port/devsdp.c
531d
## diffname port/devsdp.c 2001/0213
## diff -e /n/emeliedump/2000/0617/sys/src/9/port/devsdp.c /n/emeliedump/2001/0213/sys/src/9/port/devsdp.c
2283c
print("unthwack failed: %d\n", n);
.
2240,2243c
	b->rp[0] = (c->in.compwindow>>1) & 0xff;
	b->rp[1] = c->in.compseq>>16;
	b->rp[2] = c->in.compseq>>8;
	b->rp[3] = c->in.compseq;
.
1689c
		if(c->state == CFree || c->state == CInit ||
		   c->state == CClosed || c->state == CRemoteClose)
.
1317c
print("dropping packet id=%d: type=%d n=%ld control=%d\n", c->id, type, BLEN(b), control);
.
1311a
		c->in.compseq = c->in.seq;
		c->in.compwindow = c->in.window;
.
1291a
	c->in.window |= 1<<-seqdiff;
.
1290d
1286a
			seqdiff = 0;
.
1285d
1278d
101a
	ulong	compseq;
	ulong	compwindow;
.
## diffname port/devsdp.c 2001/0214
## diff -e /n/emeliedump/2001/0213/sys/src/9/port/devsdp.c /n/emeliedump/2001/0214/sys/src/9/port/devsdp.c
2244,2247c

	ackseq = unthwackstate(c->in.compstate, &mask);
	b->rp[0] = mask;
	b->rp[1] = ackseq>>16;
	b->rp[2] = ackseq>>8;
	b->rp[3] = ackseq;
.
2240a
	ulong ackseq;
	uchar mask;
.
1313,1314d
102,103d
## diffname port/devsdp.c 2001/0918
## diff -e /n/emeliedump/2001/0214/sys/src/9/port/devsdp.c /n/emeliedump/2001/0918/sys/src/9/port/devsdp.c
938d
765c
		mkqid(&qid, QID(CONV(c->qid),TYPE(dt->qid)), 0, QTFILE);
.
757,759c
		mkqid(&qid, QID(s, Qconvdir), 0, QTDIR);
		snprint(up->genbuf, sizeof(up->genbuf), "%d", s);
		devdir(c, qid, up->genbuf, 0, eve, 0555, dp);
.
746c
		mkqid(&qid, QID(0, Qsdpdir), 0, QTDIR);
		devdir(c, qid, "sdp", 0, eve, 0555, dp);
.
734c
		if(c->qid.type & QTDIR)
.
722,723c
			snprint(up->genbuf, sizeof(up->genbuf), "%d", s);
			mkqid(&qid, Qsdpdir, 0, QTDIR);
			devdir(c, qid, up->genbuf, 0, eve, 0555, dp);
.
718,719c
			snprint(up->genbuf, sizeof(up->genbuf), "#E%ld", c->dev);
			mkqid(&qid, Qtopdir, 0, QTDIR);
			devdir(c, qid, up->genbuf, 0, eve, 0555, dp);
.
710d
706c
sdpgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp)
.
407d
404c
	return devstat(c, db, n, nil, 0, sdpgen);
.
401,402c
static int
sdpstat(Chan* c, uchar* db, int n)
.
398c
	return devwalk(c, nc, name, nname, 0, 0, sdpgen);
.
395,396c
static Walkqid*
sdpwalk(Chan *c, Chan *nc, char **name, int nname)
.
378c
	c->qid = (Qid){QID(0, Qtopdir), 0, QTDIR};
.
286c
static int sdpgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp);
.
147c
	char owner[KNAMELEN];		/* protections */
.
52,53c
#define TYPE(x) 	(((ulong)(x).path) & 0xff)
#define CONV(x) 	((((ulong)(x).path) >> 8)&(Maxconv-1))
.
## diffname port/devsdp.c 2001/0926
## diff -e /n/emeliedump/2001/0918/sys/src/9/port/devsdp.c /n/emeliedump/2001/0926/sys/src/9/port/devsdp.c
1821c
			if(strcmp(up->errstr, Eintr) != 0) {
.
## diffname port/devsdp.c 2002/0109
## diff -e /n/emeliedump/2001/0926/sys/src/9/port/devsdp.c /n/emeliedump/2002/0109/sys/src/9/port/devsdp.c
937a
	devshutdown,
.
## diffname port/devsdp.c 2002/0125
## diff -e /n/emeliedump/2002/0109/sys/src/9/port/devsdp.c /n/emeliedump/2002/0125/sys/src/9/port/devsdp.c
740c
			panic("sdpgen: unknown type: %lud", TYPE(c->qid));
.
726c
			panic("sdpwalk %llux", c->qid.path);
.
## diffname port/devsdp.c 2002/0326
## diff -e /n/emeliedump/2002/0125/sys/src/9/port/devsdp.c /n/emeliedump/2002/0326/sys/src/9/port/devsdp.c
2288c
if(0)print("unthwack failed: %d\n", n);
.
1444c
if(0)print("duplicate control packet: %ulx\n", cseq);
.
1317c
if(0)print("dropping packet id=%d: type=%d n=%ld control=%d\n", c->id, type, BLEN(b), control);
.
1266c
if(0)print("pad too big\n");
.
1257c
if(0)print("bad cipher\n");
.
1247c
if(0)print("bad auth %ld\n", BLEN(b)+4);
.
1234c
if(0)print("dup sequence number: %ld (%ld %ld)\n", seq, c->in.seqwrap, seqdiff);
.
1227c
if(0)print("old sequence number: %ld (%ld %ld)\n", seq, c->in.seqwrap, seqdiff);
.
958c
if(0)print("convsetstate %d: %s -> %s\n", c->id, convstatename[c->state], convstatename[state]);
.
## diffname port/devsdp.c 2002/0612
## diff -e /n/emeliedump/2002/0326/sys/src/9/port/devsdp.c /n/emeliedump/2002/0612/sys/src/9/port/devsdp.c
1425c
if(1)print("invalid conviconnect - sending reset\n");
.
45c
	KeepAlive = 60,		// keep alive in seconds
.
43c
	Nfs= 4,			// number of file systems
.
## diffname port/devsdp.c 2002/0625
## diff -e /n/emeliedump/2002/0612/sys/src/9/port/devsdp.c /n/emeliedump/2002/0625/sys/src/9/port/devsdp.c
45c
	KeepAlive = 300,	// keep alive in seconds - should probably be about 60 but is higher to avoid linksys bug
.
## diffname port/devsdp.c 2003/0407
## diff -e /n/emeliedump/2002/0625/sys/src/9/port/devsdp.c /n/emeliedump/2003/0407/sys/src/9/port/devsdp.c
912c
		tsleep(&up->sleep, return0, 0, 1000);
.
163d

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].