~kris/9p

9hist

e041b930696c9816ee023d7e577381b61284ee6a — David du Colombier 24 years ago 00f9c62
Plan 9 from Bell Labs 2001-10-07
3 files changed, 265 insertions(+), 288 deletions(-)

M ip/ip.c
M pc/devusb.c
M port/devtls.c
M ip/ip.c => ip/ip.c +2 -2
@@ 150,7 150,7 @@ ipoput(Fs *f, Block *bp, int gating, int ttl, int tos)
{
	Ipifc *ifc;
	uchar *gate;
	ushort fragoff;
	ulong fragoff;
	Block *xp, *nb;
	Iphdr *eh, *feh;
	int lid, len, seglen, chunk, dlen, blklen, offset, medialen;


@@ 269,7 269,7 @@ ipoput(Fs *f, Block *bp, int gating, int ttl, int tos)
	xp->rp += offset;

	if(gating)
		fragoff = nhgets(eh->frag);
		fragoff = nhgets(eh->frag)<<3;
	else
		fragoff = 0;
	dlen += fragoff;

M pc/devusb.c => pc/devusb.c +111 -141
@@ 146,7 146,6 @@ enum {

	/* TD.flags (software) */
	CancelTD=	1<<0,
	IsoLock=		1<<1,
	IsoClean=		1<<2,
};



@@ 212,25 211,27 @@ struct Endpt {
	volatile byte	iso;
	byte		debug;
	byte		active;	/* listed for examination by interrupts */
	int		setin;
	/* ISO related: */
	byte *	tdalloc;
	byte *	bpalloc;
	int		hz;
	int		remain;
	int		remain;	/* for packet size calculations */
	int		samplesz;
	int		sched;	/* schedule index; -1 if undefined or aperiodic */
	int		setin;
	int		pollms;	/* polling interval in msec */
	int		psize;	/* size of this packet */
	int		curbytes;		/* # of bytes in that block */
	int		psize;	/* (remaining) size of this packet */
	int		off;		/* offset into packet */
	int		isolock;	/* reader/writer interlock with interrupt */
	TD*		td0;		/* first td in array */
	TD*		etd;		/* pointer into circular list of TDs for isochronous ept */
	TD*		xtd;		/* next td to be cleaned */
	/* end ISO stuff */
	QH*		epq;		/* queue of TDs for this endpoint */
	TD*		td0;		/* pointer to list of TDs for isochronous ept */
	volatile TD*	etd;	/* reader/writer pointer into list of TDs for isochronous ept */
	volatile TD*	xtd;	/* next td to be cleaned */
	QLock	rlock;
	Rendez	rr;
	Queue*	rq;
	QLock	wlock;
	int		isolock;
	Rendez	wr;
	Queue*	wq;



@@ 803,7 804,7 @@ schedendpt(Endpt *e)
	if (e->isopen){
		return -1;
	}
	e->curbytes = 0;
	e->off = 0;
	e->sched = usbsched(ub, e->pollms, e->maxpkt);
	if(e->sched < 0){
		qunlock(&usbstate);


@@ 818,9 819,8 @@ schedendpt(Endpt *e)
	bp = (byte *)(((ulong)e->bpalloc + 0xf) & ~0xf);
	frnum = (IN(Frnum) + 1) & 0x3ff;
	frnum = (frnum & ~(e->pollms - 1)) + e->sched;
	e->isolock = 1;
	e->xtd = &e->td0[frnum];	/* Next td to finish */
	e->etd = nil;	/* Writer is idle */
	e->xtd = &e->td0[(frnum+8)&0x3ff];	/* Next td to finish */
	e->etd = nil;
	e->remain = 0;
	td = e->td0;
	for(i = e->sched; i < NFRAME; i += e->pollms){


@@ 851,7 851,6 @@ schedendpt(Endpt *e)
		td->link = ub->frames[ix];
		ub->frames[ix] = PADDR(td);
	}
	e->isolock = 0;
	return 0;
}



@@ 1067,41 1066,50 @@ static void
cleaniso(Endpt *e, int frnum)
{
	TD *td;
	int tok, id, size;
	int id, n;

	if (e->xtd->status & Active){
		td = e->td0 + ((frnum -1)&0x3ff);
		if (td->status & Active)
			return;
		iprint("%ld active -> %ld", e->xtd - e->td0, td - e->td0);
		e->xtd = td;
	}
	tok = (e->mode == OREAD)?TokIN:TokOUT;
	td = e->xtd;
	if (td->status & Active)
		return;
	id = (e->x<<7)|(e->dev->x&0x7F);
	for(td = e->xtd; (td->status & Active) == 0; td = td->next){
		if (td->flags & IsoLock)
			iprint("usbinterrupt: locked?\n");
		if (e->isolock == 0 && td == e->etd){
			/* if isolock is set, don't touch e->etd */
			if (e->xtd == e->etd)
				wakeup(&e->wr);	/* writer had to wait */
			else
				e->etd = nil;		/* writer was overtaken */
		}
	do{
		if (td->status & AnyError)
			iprint("usbisoerror 0x%lux\n", td->status);
		size = (e->hz + e->remain)*e->pollms/1000;
		e->remain = (e->hz + e->remain)*e->pollms%1000;
		size *= e->samplesz;
		if ((td->flags & IsoClean) == 0){
		if (e->mode == OREAD){
			td->dev = ((e->maxpkt -1)<<21) | ((id&0x7FF)<<8) | TokIN;
		}else{
			n = (e->hz + e->remain)*e->pollms/1000;
			e->remain = (e->hz + e->remain)*e->pollms%1000;
			n *= e->samplesz;
			td->dev = ((n -1)<<21) | ((id&0x7FF)<<8) | TokOUT;
		}
		td = td->next;
		if (e->xtd == td){
			iprint("@");
			break;
		}
	} while ((td->status & Active) == 0);
	e->xtd = td;
	if (e->isolock){
		wakeup(&e->wr);
		return;
	}
	for (n = 2; n < 6; n++){
		td = e->td0 + ((frnum + n)&0x3ff);
		if (td->status & Active)
			continue;

		if (td == e->etd) {
			memset((byte*)td->bp+e->off, 0, e->maxpkt-e->off);
			if (e->off == 0)
				td->flags |= IsoClean;
			e->etd = nil;
		}else if ((td->flags & IsoClean) == 0){
			memset((byte*)td->bp, 0, e->maxpkt);
			td->flags |= IsoClean;
		}
		td->dev = ((size-1)<<21) | ((id&0x7FF)<<8) | tok;
		td->status = ErrLimit3 | Active | IsoSelect | IOC;
	}
	e->xtd = td;
	if (e->etd) wakeup(&e->wr);
}

static void


@@ 1597,33 1605,12 @@ eptinput(void *arg)
}

static int
isorready(void *arg)
isoready(void *arg)
{
	int frnum;
	Ctlr *ub;
	Endpt *e;

	e = arg;
	e->isolock = 1;
	ub = &ubus;
	frnum = IN(Frnum) & 0x3ff;
	if (e->etd == nil){
		/* reader was idle, find a place to start */
		e->etd = e->td0 + (frnum & 0x3ff);
	}
	if (e->etd->status & Active){
		/* not yet ready */
		e->isolock = 0;
		return 0;
	}
	/* leave locked if succesful */
	e->psize = (e->etd->status + 1) & 0x7FF;
	e->curbytes = 0;
	e->nbytes += e->psize;
	e->nblocks++;
	if (e->psize > e->maxpkt)
		panic("packet size > maximum");
	return 1;
	return e->etd == nil || (e->etd->status & Active) == 0;
}

static long


@@ 1631,8 1618,9 @@ readusb(Endpt *e, void *a, long n)
{
	Block *b;
	uchar *p, *q;
	long l, i, id;
	int l, i, frnum;
	TD *td;
	Ctlr *ub;

	XPRINT("qlock(%p)\n", &e->rlock);
	qlock(&e->rlock);


@@ 1644,43 1632,47 @@ readusb(Endpt *e, void *a, long n)
	}
	p = a;
	if (e->iso){
		if(waserror()){
			e->isolock = 0;
			nexterror();
		}
		e->isolock = 1;
		do {
			if (e->psize == 0){
				while(isorready(e) == 0){
					XPRINT("readusb: sleep %lux\n", &e->wr);
					sleep(&e->wr, isorready, e);
					XPRINT("readusb: awake\n");
				}
			while (isoready(e) == 0){
				XPRINT("readusb: sleep %lux\n", &e->wr);
				sleep(&e->wr, isoready, e);
				XPRINT("readusb: awake\n");
			}
			td = e->etd;
			e->isolock = 0;

			if (e->psize > 0){
				q = (byte*)td->bp + e->curbytes;
			if ((td = e->etd) == nil){
				ub = &ubus;
				frnum = (IN(Frnum) + 8) & 0x3ff;
				e->etd = e->td0 +frnum;
			}else{
				q = (uchar*)td->bp + e->off;
				if((i = n) >= e->psize)
					i = e->psize;
				memmove(p, q, i);
				p += i;
				n -= i;
				e->curbytes += i;
				e->off += i;
				e->psize -= i;
				if (e->psize > 0){
					/* Read done, return */
				if (e->psize){
					if (n != 0)
						panic("usb iso: can't happen");
					break;
				}
				td->status = ErrLimit3 | Active | IsoSelect | IOC;
				e->etd = td->next;
			}
			e->isolock = 1;
			/* Finished a packet */
			id = (e->x<<7)|(e->dev->x&0x7F);
			td->dev = ((e->maxpkt-1)<<21) | ((id&0x7FF)<<8) | TokIN;
			td->status = ErrLimit3 | Active | IsoSelect | IOC;
			if (e->xtd == td)
				e->xtd = td->next;
			/* Get next buffer, wait for it to become ready */
			e->etd = td->next;
		} while (n > 0);
			e->off = 0;
			e->psize = (e->etd->status + 1) & 0x7ff;
			if (e->psize > e->maxpkt)
				panic("packet size > maximum");
			e->nbytes += e->psize;
			e->nblocks++;
		} while(n > 0);
		e->isolock = 0;
		poperror();
	}else{
		do {
			if(e->eof) {


@@ 1801,40 1793,14 @@ qisempty(void *arg)
	return ((QH*)arg)->entries & Terminate;
}

static int
isowready(void *arg)
{
	int frnum;
	Ctlr *ub;
	Endpt *e;

	e = arg;
	e->isolock = 1;
	ub = &ubus;
	frnum = IN(Frnum) & 0x3ff;
	if (e->etd == nil){
		/* writer was idle, find a place to start */
		e->etd = e->td0 + ((frnum + 4) & 0x3ff);
		e->curbytes = 0;
		e->psize = ((e->etd->dev >> 21) & 0x7ff) + 1;
		if (e->psize > e->maxpkt)
			panic("packet size > maximum");
	}	
	if (e->etd != e->xtd && e->etd->next != e->xtd){
		/* leave locked if succesful */
		return 1;
	}
	e->isolock = 0;
	return 0;
}

static long
writeusb(Endpt *e, void *a, long n, int tok)
{
	int i;
	int i, frnum;
	Block *b;
	uchar *p, *q;
	QH *qh;
	Ctlr *ub;
	TD *td;

	p = a;


@@ 1848,41 1814,45 @@ writeusb(Endpt *e, void *a, long n, int tok)
	if (e->iso){
		if(waserror()){
			e->isolock = 0;
			if (td = e->etd)
				td->flags &= ~IsoLock;
			nexterror();
		}
		e->isolock = 1;
		do {
			while (isowready(e) == 0){
				XPRINT("writeusb: sleep %lux\n", &e->wr);
				sleep(&e->wr, isowready, e);
				XPRINT("writeusb: awake\n");
			while (isoready(e) == 0){
				iprint("i");
				sleep(&e->wr, isoready, e);
			}
			td = e->etd;
			e->isolock = 0;
			td->flags |= IsoLock;
			td->flags &= ~IsoClean;
			q = (uchar*)td->bp + e->curbytes;
			if((i = n) >= e->psize - e->curbytes)
				i = e->psize - e->curbytes;
			memmove(q, p, i);
			p += i;
			n -= i;
			e->curbytes += i;
			td->flags &= ~IsoLock;
			if (e->curbytes < e->psize){
				if (n != 0)
					panic("usb iso: can't happen");
				break;
			if ((td = e->etd) == nil){
				iprint("0");
				ub = &ubus;
				frnum = (IN(Frnum) + 8) & 0x3ff;
				e->etd = e->td0 +frnum;
			}else{
				td->flags &= ~IsoClean;
				q = (uchar*)td->bp + e->off;
				if((i = n) >= e->psize)
					i = e->psize;
				memmove(q, p, i);
				p += i;
				n -= i;
				e->off += i;
				e->psize -= i;
				if (e->psize){
					if (n != 0)
						panic("usb iso: can't happen");
					break;
				}
				td->status = ErrLimit3 | Active | IsoSelect | IOC;
				e->etd = td->next;
			}
			e->etd = td->next;
			e->curbytes = 0;
			e->psize = ((e->etd->dev >> 21) & 0x7ff) + 1;
			e->off = 0;
			e->psize = ((e->etd->dev >> 21) + 1) & 0x7ff;
			if (e->psize > e->maxpkt)
				panic("packet size > maximum");
			e->nbytes += e->psize;
			e->nblocks++;
		} while(n > 0);
		e->isolock = 0;
		poperror();
	}else{
		do {

M port/devtls.c => port/devtls.c +152 -145
@@ 11,21 11,21 @@
#include	<libsec.h>

typedef struct OneWay	OneWay;
typedef struct Secret	Secret;
typedef struct Secret		Secret;
typedef struct TlsRec	TlsRec;
typedef struct TlsErrs	TlsErrs;

enum {
	Statlen=	1024,		/* max. length of status or stats message */
	/* buffer limits */
	MaxRecLen	= 1<<14,	/* max payload length of a record layer message */
	MaxRecLen		= 1<<14,	/* max payload length of a record layer message */
	MaxCipherRecLen	= MaxRecLen + 2048,
	RecHdrLen	= 5,
	MaxMacLen	= SHA1dlen,
	RecHdrLen		= 5,
	MaxMacLen		= SHA1dlen,

	/* protocol versions we can accept */
	TLSVersion	= 0x0301,
	SSL3Version	= 0x0300,
	TLSVersion		= 0x0301,
	SSL3Version		= 0x0300,
	ProtocolVersion	= 0x0301,	/* maximum version we speak */
	MinProtoVersion	= 0x0300,	/* limits on version we accept */
	MaxProtoVersion	= 0x03ff,


@@ 46,30 46,30 @@ enum {
	RApplication,

	/* alerts */
	ECloseNotify = 0,
	EUnexpectedMessage = 10,
	EBadRecordMac = 20,
	EDecryptionFailed = 21,
	ERecordOverflow = 22,
	EDecompressionFailure = 30,
	EHandshakeFailure = 40,
	ENoCertificate = 41,
	EBadCertificate = 42,
	EUnsupportedCertificate = 43,
	ECertificateRevoked = 44,
	ECertificateExpired = 45,
	ECertificateUnknown = 46,
	EIllegalParameter = 47,
	EUnknownCa = 48,
	EAccessDenied = 49,
	EDecodeError = 50,
	EDecryptError = 51,
	EExportRestriction = 60,
	EProtocolVersion = 70,
	EInsufficientSecurity = 71,
	EInternalError = 80,
	EUserCanceled = 90,
	ENoRenegotiation = 100,
	ECloseNotify 			= 0,
	EUnexpectedMessage 	= 10,
	EBadRecordMac 		= 20,
	EDecryptionFailed 		= 21,
	ERecordOverflow 		= 22,
	EDecompressionFailure 	= 30,
	EHandshakeFailure 		= 40,
	ENoCertificate 			= 41,
	EBadCertificate 		= 42,
	EUnsupportedCertificate 	= 43,
	ECertificateRevoked 		= 44,
	ECertificateExpired 		= 45,
	ECertificateUnknown 	= 46,
	EIllegalParameter 		= 47,
	EUnknownCa 			= 48,
	EAccessDenied 		= 49,
	EDecodeError 			= 50,
	EDecryptError 			= 51,
	EExportRestriction 		= 60,
	EProtocolVersion 		= 70,
	EInsufficientSecurity 	= 71,
	EInternalError 			= 80,
	EUserCanceled 			= 90,
	ENoRenegotiation 		= 100,

	EMAX = 256
};


@@ 85,7 85,7 @@ struct Secret
	int		block;		/* encryption block len, 0 if none */
	int		maclen;
	void		*enckey;
	uchar		mackey[MaxMacLen];
	uchar	mackey[MaxMacLen];
};

struct OneWay


@@ 99,16 99,16 @@ struct OneWay

struct TlsRec
{
	Chan		*c;		/* io channel */
	int		ref;		/* serialized by tdlock for atomic destroy */
	int		version;	/* version of the protocol we are speaking */
	char		verset;		/* version has been set */
	char		opened;		/* opened command every issued? */
	char		err[ERRLEN];	/* error message to return to handshake requests */
	vlong		handin;		/* bytes communicated by the record layer */
	vlong		handout;
	vlong		datain;
	vlong		dataout;
	Chan	*c;				/* io channel */
	int		ref;				/* serialized by tdlock for atomic destroy */
	int		version;			/* version of the protocol we are speaking */
	char		verset;			/* version has been set */
	char		opened;			/* opened command every issued? */
	char		err[ERRMAX];		/* error message to return to handshake requests */
	vlong	handin;			/* bytes communicated by the record layer */
	vlong	handout;
	vlong	datain;
	vlong	dataout;

	Lock		statelk;
	int		state;


@@ 122,7 122,7 @@ struct TlsRec
	Block		*unprocessed;	/* data read from c but not parsed into records */

	/* handshake queue */
	Lock		hqlock;		/* protects hqref, alloc & free of handq, hprocessed */
	Lock		hqlock;			/* protects hqref, alloc & free of handq, hprocessed */
	int		hqref;
	Queue		*handq;		/* queue of handshake messages */
	Block		*hprocessed;	/* remainder of last block read from handq */


@@ 132,7 132,7 @@ struct TlsRec
	OneWay		out;

	/* protections */
	char		user[NAMELEN];
	char		*user;
	int		perm;
};



@@ 145,54 145,30 @@ struct TlsErrs{
};

static TlsErrs tlserrs[] = {
	{ECloseNotify,			ECloseNotify,			ECloseNotify,
		0, "close notify"},
	{EUnexpectedMessage,		EUnexpectedMessage,		EUnexpectedMessage,
		1, "unexpected message"},
	{EBadRecordMac,			EBadRecordMac,			EBadRecordMac,
		1, "bad record mac"},
	{EDecryptionFailed,		EIllegalParameter,		EDecryptionFailed,
		1, "decryption failed"},
	{ERecordOverflow,		EIllegalParameter,		ERecordOverflow,
		1, "record too long"},
	{EDecompressionFailure,		EDecompressionFailure,		EDecompressionFailure,
		1, "decompression failed"},
	{EHandshakeFailure,		EHandshakeFailure,		EHandshakeFailure,
		1, "could not negotiate acceptable security paramters"},
	{ENoCertificate,		ENoCertificate,			ECertificateUnknown,
		1, "no appropriate certificate available"},
	{EBadCertificate,		EBadCertificate,		EBadCertificate,
		1, "corrupted or invalid certificate"},
	{EUnsupportedCertificate,	EUnsupportedCertificate,	EUnsupportedCertificate,
		1, "unsupported certificate type"},
	{ECertificateRevoked,		ECertificateRevoked,		ECertificateRevoked,
		1, "revoked certificate"},
	{ECertificateExpired,		ECertificateExpired,		ECertificateExpired,
		1, "expired certificate"},
	{ECertificateUnknown,		ECertificateUnknown,		ECertificateUnknown,
		1, "unacceptable certificate"},
	{EIllegalParameter,		EIllegalParameter,		EIllegalParameter,
		1, "illegal parameter"},
	{EUnknownCa,			EHandshakeFailure,		EUnknownCa,
		1, "unknown certificate authority"},
	{EAccessDenied,			EHandshakeFailure,		EAccessDenied,
		1, "access denied"},
	{EDecodeError,			EIllegalParameter,		EDecodeError,
		1, "error decoding message"},
	{EDecryptError,			EIllegalParameter,		EDecryptError,
		1, "error decrypting message"},
	{EExportRestriction,		EHandshakeFailure,		EExportRestriction,
		1, "export restriction violated"},
	{EProtocolVersion,		EIllegalParameter,		EProtocolVersion,
		1, "protocol version not supported"},
	{EInsufficientSecurity,		EHandshakeFailure,		EInsufficientSecurity,
		1, "stronger security routines required"},
	{EInternalError,		EHandshakeFailure,		EInternalError,
		1, "internal error"},
	{EUserCanceled,			ECloseNotify,		EUserCanceled,
		0, "handshake canceled by user"},
	{ENoRenegotiation,		EUnexpectedMessage,		ENoRenegotiation,
		0, "no renegotiation"},
	{ECloseNotify,			ECloseNotify,			ECloseNotify,			0, 	"close notify"},
	{EUnexpectedMessage,	EUnexpectedMessage,	EUnexpectedMessage, 	1, "unexpected message"},
	{EBadRecordMac,		EBadRecordMac,		EBadRecordMac, 		1, "bad record mac"},
	{EDecryptionFailed,		EIllegalParameter,		EDecryptionFailed,		1, "decryption failed"},
	{ERecordOverflow,		EIllegalParameter,		ERecordOverflow,		1, "record too long"},
	{EDecompressionFailure,	EDecompressionFailure,	EDecompressionFailure,	1, "decompression failed"},
	{EHandshakeFailure,		EHandshakeFailure,		EHandshakeFailure,		1, "could not negotiate acceptable security paramters"},
	{ENoCertificate,		ENoCertificate,			ECertificateUnknown,	1, "no appropriate certificate available"},
	{EBadCertificate,		EBadCertificate,		EBadCertificate,		1, "corrupted or invalid certificate"},
	{EUnsupportedCertificate,	EUnsupportedCertificate,	EUnsupportedCertificate,	1, "unsupported certificate type"},
	{ECertificateRevoked,	ECertificateRevoked,		ECertificateRevoked,		1, "revoked certificate"},
	{ECertificateExpired,		ECertificateExpired,		ECertificateExpired,		1, "expired certificate"},
	{ECertificateUnknown,	ECertificateUnknown,	ECertificateUnknown,	1, "unacceptable certificate"},
	{EIllegalParameter,		EIllegalParameter,		EIllegalParameter,		1, "illegal parameter"},
	{EUnknownCa,			EHandshakeFailure,		EUnknownCa,			1, "unknown certificate authority"},
	{EAccessDenied,		EHandshakeFailure,		EAccessDenied,		1, "access denied"},
	{EDecodeError,			EIllegalParameter,		EDecodeError,			1, "error decoding message"},
	{EDecryptError,			EIllegalParameter,		EDecryptError,			1, "error decrypting message"},
	{EExportRestriction,		EHandshakeFailure,		EExportRestriction,		1, "export restriction violated"},
	{EProtocolVersion,		EIllegalParameter,		EProtocolVersion,		1, "protocol version not supported"},
	{EInsufficientSecurity,	EHandshakeFailure,		EInsufficientSecurity,	1, "stronger security routines required"},
	{EInternalError,			EHandshakeFailure,		EInternalError,			1, "internal error"},
	{EUserCanceled,		ECloseNotify,			EUserCanceled,			0, "handshake canceled by user"},
	{ENoRenegotiation,		EUnexpectedMessage,	ENoRenegotiation,		0, "no renegotiation"},
};

enum


@@ 205,6 181,7 @@ static	Lock	tdlock;
static	int	tdhiwat;
static	int	maxtlsdevs = 128;
static	TlsRec	**tlsdevs;
static	char	**trnames;
static	char	*encalgs;
static	char	*hashalgs;



@@ 262,46 239,49 @@ static char	*tlsstate(int s);
#pragma	varargck	argpos	rcvError	3

static char *tlsnames[] = {
[Qclonus]	"clone",
[Qclonus]		"clone",
[Qencalgs]	"encalgs",
[Qhashalgs]	"hashalgs",
[Qdata]		"data",
[Qctl]		"ctl",
[Qhand]		"hand",
[Qstatus]	"status",
[Qstats]	"stats",
[Qstatus]		"status",
[Qstats]		"stats",
};

static int convdir[] = { Qctl, Qdata, Qhand, Qstatus, Qstats };

static int
tlsgen(Chan *c, Dirtab *d, int nd, int s, Dir *dp)
tlsgen(Chan *c, char*, Dirtab *, int, int s, Dir *dp)
{
	Qid q;
	TlsRec *tr;
	char name[16], *nm;
	char *name, *nm;
	int perm, t;

	USED(nd);
	USED(d);
	q.vers = 0;
	q.type = QTFILE;

	t = TYPE(c->qid);
	switch(t) {
	case Qtopdir:
		if(s == DEVDOTDOT){
			q.path = QID(0, Qtopdir)|CHDIR;
			devdir(c, q, "#D", 0, eve, CHDIR|0555, dp);
			q.path = QID(0, Qtopdir);
			q.type = QTDIR;
			devdir(c, q, "#a", 0, eve, 0555, dp);
			return 1;
		}
		if(s > 0)
			return -1;
		q.path = QID(0, Qprotodir)|CHDIR;
		devdir(c, q, "tls", 0, eve, CHDIR|0555, dp);
		q.path = QID(0, Qprotodir);
		q.type = QTDIR;
		devdir(c, q, "tls", 0, eve, 0555, dp);
		return 1;
	case Qprotodir:
		if(s == DEVDOTDOT){
			q.path = QID(0, Qtopdir)|CHDIR;
			devdir(c, q, ".", 0, eve, CHDIR|0555, dp);
			q.path = QID(0, Qtopdir);
			q.type = QTDIR;
			devdir(c, q, ".", 0, eve, 0555, dp);
			return 1;
		}
		if(s < 3){


@@ 327,21 307,26 @@ tlsgen(Chan *c, Dirtab *d, int nd, int s, Dir *dp)
		s -= 3;
		if(s >= tdhiwat)
			return -1;
		sprint(name, "%d", s);
		q.path = QID(s, Qconvdir)|CHDIR;
		q.path = QID(s, Qconvdir);
		q.type = QTDIR;
		lock(&tdlock);
		tr = tlsdevs[s];
		if(tr != nil)
			nm = tr->user;
		else
			nm = eve;
		devdir(c, q, name, 0, nm, CHDIR|0555, dp);
		if ((name = trnames[s]) == nil) {
			name = trnames[s] = smalloc(16);
			sprint(name, "%d", s);
		}
		devdir(c, q, name, 0, nm, 0555, dp);
		unlock(&tdlock);
		return 1;
	case Qconvdir:
		if(s == DEVDOTDOT){
			q.path = QID(0, Qprotodir)|CHDIR;
			devdir(c, q, "tls", 0, eve, CHDIR|0555, dp);
			q.path = QID(0, Qprotodir);
			q.type = QTDIR;
			devdir(c, q, "tls", 0, eve, 0555, dp);
			return 1;
		}
		if(s < 0 || s >= nelem(convdir))


@@ 395,21 380,22 @@ tlsattach(char *spec)
	Chan *c;

	c = devattach('a', spec);
	c->qid.path = QID(0, Qtopdir)|CHDIR;
	c->qid.path = QID(0, Qtopdir);
	c->qid.type = QTDIR;
	c->qid.vers = 0;
	return c;
}

static int
tlswalk(Chan *c, char *name)
static Walkqid*
tlswalk(Chan *c, Chan *nc, char **name, int nname)
{
	return devwalk(c, name, 0, 0, tlsgen);
	return devwalk(c, nc, name, nname, nil, 0, tlsgen);
}

static void
tlsstat(Chan *c, char *db)
static int
tlsstat(Chan *c, uchar *db, int n)
{
	devstat(c, db, 0, 0, tlsgen);
	return devstat(c, db, n, nil, 0, tlsgen);
}

static Chan*


@@ 498,18 484,18 @@ tlsopen(Chan *c, int omode)
	return c;
}

static void
tlswstat(Chan *c, char *dp)
static int
tlswstat(Chan *c, uchar *dp, int n)
{
	Dir d;
	Dir *d;
	TlsRec *tr;

	convM2D(dp, &d);
	int rv;

	if(waserror()){
		unlock(&tdlock);
		nexterror();
	}

	lock(&tdlock);
	tr = tlsdevs[CONV(c->qid)];
	if(tr == nil)


@@ 517,9 503,17 @@ tlswstat(Chan *c, char *dp)
	if(strcmp(tr->user, up->user) != 0)
		error(Eperm);

	memmove(tr->user, d.uid, NAMELEN);
	tr->perm = d.mode;
	d = smalloc(n + sizeof *d);
	rv = convM2D(dp, n, &d[0], (char*) &d[1]);
	if (rv > 0) {
		kstrdup(&tr->user, d->uid);
		tr->perm = d->mode;
	}
	free(d);
	poperror();
	unlock(&tdlock);

	return rv;
}

static void


@@ 582,6 576,7 @@ tlsclose(Chan *c)
		freeSec(tr->in.new);
		freeSec(tr->out.sec);
		freeSec(tr->out.new);
		free(tr->user);
		free(tr);
		break;
	}


@@ 731,7 726,7 @@ tlsrecread(TlsRec *tr)

	nconsumed = 0;
	if(waserror()){
		if(strcmp(up->error, Eintr) == 0 && !waserror()){
		if(strcmp(up->errstr, Eintr) == 0 && !waserror()){
			regurgitate(tr, header, nconsumed);
			poperror();
		}else


@@ 909,7 904,7 @@ rcvAlert(TlsRec *tr, int err)
static void
rcvError(TlsRec *tr, int err, char *fmt, ...)
{
	char msg[ERRLEN];
	char msg[ERRMAX];
	va_list arg;

	va_start(arg, fmt);


@@ 986,10 981,12 @@ checkstate(TlsRec *tr, int ishand, int ok)
static Block*
tlsbread(Chan *c, long n, ulong offset)
{
	TlsRec *volatile tr;
	int ty;
	Block *b;
	TlsRec *volatile tr;

	switch(TYPE(c->qid)) {
	ty = TYPE(c->qid);
	switch(ty) {
	default:
		return devbread(c, n, offset);
	case Qhand:


@@ 1006,7 1003,7 @@ tlsbread(Chan *c, long n, ulong offset)
		nexterror();
	}
	qlock(&tr->in.io);
	if(TYPE(c->qid) == Qdata){
	if(ty == Qdata){
		checkstate(tr, 0, SOpen);
		while(tr->processed == nil)
			tlsrecread(tr);


@@ 1038,10 1035,9 @@ tlsbread(Chan *c, long n, ulong offset)
		if(tr->hprocessed == nil){
			b = qbread(tr->handq, MaxRecLen + 1);
			if(*b->rp++ == RAlert){
				strncpy(up->error, (char*)b->rp, ERRLEN - 1);
				up->error[ERRLEN - 1] = '\0';
				strecpy(up->errstr, up->errstr+ERRMAX, (char*)b->rp);
				freeb(b);
				error(up->error);
				nexterror();
			}
			tr->hprocessed = b;
		}


@@ 1060,16 1056,17 @@ tlsread(Chan *c, void *a, long n, vlong off)
	Block *volatile b;
	Block *nb;
	uchar *va;
	int i;
	int i, ty;
	char *buf, *s, *e;
	ulong offset = off;
	TlsRec * tr;

	if(c->qid.path & CHDIR)
	if(c->qid.type & QTDIR)
		return devdirread(c, a, n, 0, 0, tlsgen);

	tr = tlsdevs[CONV(c->qid)];
	switch(TYPE(c->qid)) {
	ty = TYPE(c->qid);
	switch(ty) {
	default:
		error(Ebadusefd);
	case Qstatus:


@@ 1106,7 1103,7 @@ tlsread(Chan *c, void *a, long n, vlong off)
		return n;
	case Qctl:
		buf = smalloc(Statlen);
		snprint(buf, Statlen, "%lud", CONV(c->qid));
		snprint(buf, Statlen, "%llud", CONV(c->qid));
		n = readstr(offset, a, n, buf);
		free(buf);
		return n;


@@ 1235,7 1232,7 @@ tlsrecwrite(TlsRec *tr, int type, Block *b)
		 * if not, we're out of sync with the receiver and will not recover.
		 */
		if(waserror()){
			if(strcmp(up->error, "interrupted") != 0)
			if(strcmp(up->errstr, "interrupted") != 0)
				tlsError(tr, "channel error");
			nexterror();
		}


@@ 1249,8 1246,9 @@ tlsrecwrite(TlsRec *tr, int type, Block *b)
static long
tlsbwrite(Chan *c, Block *b, ulong offset)
{
	TlsRec *tr;
	int ty;
	ulong n;
	TlsRec *tr;

	n = BLEN(b);



@@ 1258,7 1256,8 @@ tlsbwrite(Chan *c, Block *b, ulong offset)
	if(tr == nil)
		panic("tlsbread");

	switch(TYPE(c->qid)) {
	ty = TYPE(c->qid);
	switch(ty) {
	default:
		return devbwrite(c, b, offset);
	case Qhand:


@@ 1398,7 1397,7 @@ tlswrite(Chan *c, void *a, long n, vlong off)
	Secret *volatile tos, *volatile toc;
	Block *volatile b;
	Cmdbuf *volatile cb;
	int m;
	int m, ty;
	char *p, *e;
	uchar *volatile x;
	ulong offset = off;


@@ 1407,7 1406,8 @@ tlswrite(Chan *c, void *a, long n, vlong off)
	if(tr == nil)
		panic("tlswrite");

	switch(TYPE(c->qid)){
	ty = TYPE(c->qid);
	switch(ty){
	case Qdata:
	case Qhand:
		p = a;


@@ 1572,7 1572,7 @@ tlswrite(Chan *c, void *a, long n, vlong off)
		if(cb->nf != 1)
			error("usage: opened");
		if(tr->in.sec == nil || tr->out.sec == nil)
			error("cipher must be configure before enabling data messages");
			error("cipher must be configured before enabling data messages");
		lock(&tr->statelk);
		if(tr->state != SHandshake && tr->state != SOpen){
			unlock(&tr->statelk);


@@ 1622,6 1622,8 @@ tlsinit(void)

	if((tlsdevs = smalloc(sizeof(TlsRec*) * maxtlsdevs)) == 0)
		panic("tlsinit");
	if((trnames = smalloc((sizeof *trnames) * maxtlsdevs)) == 0)
		panic("tlsinit");

	n = 1;
	for(e = encrypttab; e->name != nil; e++)


@@ 1659,7 1661,6 @@ Dev tlsdevtab = {
	devreset,
	tlsinit,
	tlsattach,
	devclone,
	tlswalk,
	tlsstat,
	tlsopen,


@@ 1732,8 1733,8 @@ tlsError(TlsRec *tr, char *msg)
	s = tr->state;
	tr->state = SError;
	if(s != SError){
		strncpy(tr->err, msg, ERRLEN - 1);
		tr->err[ERRLEN - 1] = '\0';
		strncpy(tr->err, msg, ERRMAX - 1);
		tr->err[ERRMAX - 1] = '\0';
	}
	unlock(&tr->statelk);
	if(s != SError)


@@ 1773,6 1774,7 @@ static TlsRec*
newtls(Chan *ch)
{
	TlsRec **pp, **ep, **np;
	char **nmp;
	int t, newmax;

	if(waserror()) {


@@ 1798,6 1800,11 @@ newtls(Chan *ch)
		tlsdevs = np;
		pp = &tlsdevs[maxtlsdevs];
		memset(pp, 0, sizeof(TlsRec*)*(newmax - maxtlsdevs));

		nmp = smalloc(sizeof *nmp * newmax);
		memmove(nmp, trnames, sizeof *nmp * maxtlsdevs);
		trnames = nmp;

		maxtlsdevs = newmax;
	}
	*pp = mktlsrec();


@@ 1823,7 1830,7 @@ mktlsrec(void)
		error(Enomem);
	tr->state = SClosed;
	tr->ref = 1;
	strncpy(tr->user, up->user, sizeof(tr->user));
	kstrdup(&tr->user, up->user);
	tr->perm = 0660;
	return tr;
}