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

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

1999/0906/sys/src/9/port/devsdp.c:8,181999/0907/sys/src/9/port/devsdp.c:8,21 (short | long | prev | next)
1999/0824    
 
#include	<libcrypt.h> 
 
1999/0907    
/* 
 * sdp - secure datagram protocol 
 */ 
 
1999/0902    
typedef struct Sdp Sdp; 
typedef struct Conv Conv; 
typedef struct Out Out; 
typedef struct In In; 
1999/0906    
typedef struct ConPkt ConPkt; 
1999/0907    
typedef struct OneWay OneWay; 
typedef struct ConnectPkt ConnectPkt; 
1999/0824    
 
enum 
{ 
1999/0906/sys/src/9/port/devsdp.c:31,391999/0907/sys/src/9/port/devsdp.c:34,43
1999/0824    
 
	MaxQ, 
 
1999/0901    
	Maxconv=	256,		// power of 2 
1999/0824    
	Nfs=		4,			// number of file systems 
1999/0907    
	Maxconv= 256,		// power of 2 
	Nfs= 4,				// number of file systems 
1999/0906    
	Maxretries=	4, 
1999/0907    
	KeyLength= 32, 
1999/0824    
}; 
 
#define TYPE(x) 	((x).path & 0xff) 
1999/0906/sys/src/9/port/devsdp.c:40,861999/0907/sys/src/9/port/devsdp.c:44,73
1999/0901    
#define CONV(x) 	(((x).path >> 8)&(Maxconv-1)) 
1999/0824    
#define QID(x, y) 	(((x)<<8) | (y)) 
 
1999/0902    
struct Out 
1999/0907    
struct OneWay 
1999/0901    
{ 
	ulong	seqwrap;	// number of wraps of the sequence number 
	ulong	seq; 
1999/0907    
	ulong	window; 
1999/0901    
 
1999/0907    
	Rendez	controlready; 
1999/0902    
	Block	*controlpkt;		// control channel 
	ulong	*controlseq; 
1999/0907    
	ulong	controlseq; 
1999/0901    
 
1999/0902    
	void	*cipherstate;	// state cipher 
	int		ivlen;			// in bytes 
	int		(*encrypt)(Out*, uchar *buf, int len); 
1999/0907    
	int		cipherivlen;	// initial vector length 
	int		cipherblklen;	// block length 
	int		(*cipher)(OneWay*, uchar *buf, int len); 
1999/0902    
 
	void	*authstate;		// auth state 
	int		authlen;		// auth data length in bytes 
	int		(*auth)(Out*, uchar *buf, int len); 
1999/0907    
	int		(*auth)(OneWay*, uchar *buf, int len); 
1999/0902    
 
	void	*compstate; 
	int		(*comp)(Out*, uchar *dst, uchar *src, int n); 
1999/0907    
	int		(*comp)(OneWay*, uchar *dst, uchar *src, int n); 
1999/0901    
}; 
 
1999/0902    
struct In 
{ 
	ulong	seqwrap;	// number of wraps of the sequence number 
	ulong	seq; 
	ulong	window; 
                 
	Block	*controlpkt; 
	ulong	controlseq; 
                 
	void	*cipherstate;	// state cipher 
	int		ivlen;			// in bytes 
	int		(*decrypt)(In*, uchar *buf, int len); 
                 
	void	*authstate;		// auth state 
	int		authlen;		// auth data length in bytes 
	int		(*auth)(In*, uchar *buf, int len); 
                 
	void	*uncompstate; 
	int		(*uncomp)(In*, uchar *dst, uchar *src, int n); 
}; 
                 
1999/0907    
// conv states 
1999/0902    
enum { 
1999/0906    
	CInit, 
1999/0902    
	COpening, 
1999/0906/sys/src/9/port/devsdp.c:98,1041999/0907/sys/src/9/port/devsdp.c:85,90
1999/0902    
	int state; 
1999/0906    
	int dataopen; 
1999/0901    
 
1999/0906    
	Proc *readproc; 
 
	ulong	timeout; 
	int		retries; 
1999/0906/sys/src/9/port/devsdp.c:107,1211999/0907/sys/src/9/port/devsdp.c:93,111
1999/0906    
	ulong dialid; 
	ulong acceptid; 
 
1999/0907    
	Proc *readproc; 
	QLock readlk; 
1999/0902    
	Chan *chan;	// packet channel 
 
1999/0901    
	char	user[NAMELEN];		/* protections */ 
1999/0907    
	char owner[NAMELEN];		/* protections */ 
1999/0901    
	int	perm; 
 
1999/0907    
	uchar	masterkey[KeyLength]; 
 
1999/0906    
	int drop; 
 
1999/0902    
	In	in; 
	Out	out; 
1999/0907    
	OneWay	in; 
	OneWay	out; 
1999/0824    
}; 
 
struct Sdp { 
1999/0906/sys/src/9/port/devsdp.c:144,1501999/0907/sys/src/9/port/devsdp.c:134,140
1999/0906    
	ConCloseAck, 
}; 
 
struct ConPkt 
1999/0907    
struct ConnectPkt 
1999/0906    
{ 
	uchar type;		// always zero = connection packet 
	uchar op; 
1999/0906/sys/src/9/port/devsdp.c:153,1581999/0907/sys/src/9/port/devsdp.c:143,149
1999/0906    
	uchar acceptid[4]; 
}; 
 
1999/0907    
 
1999/0824    
static Dirtab sdpdirtab[]={ 
	"stats",	{Qstats},	0,	0444, 
	"log",		{Qlog},		0,	0666, 
1999/0906/sys/src/9/port/devsdp.c:192,2001999/0907/sys/src/9/port/devsdp.c:183,200
1999/0824    
static int sdpgen(Chan *c, Dirtab*, int, int s, Dir *dp); 
1999/0901    
static Conv *sdpclone(Sdp *sdp); 
1999/0906    
static void convsetstate(Conv *c, int state); 
static void sendconnect(Conv *c, int op, ulong dialid, ulong acceptid); 
static void sdpackproc(void *a); 
1999/0907    
static void onewaycleanup(OneWay *ow); 
static int readready(void *a); 
static int controlread(); 
static Block *conviput(Conv *c, Block *b, int control); 
static void conviput2(Conv *c, Block *b); 
static Block *readcontrol(Conv *c, int n); 
static Block *readdata(Conv *c, int n); 
static void convoput(Conv *c, int type, Block *b); 
static void convoput2(Conv *c, int op, ulong dialid, ulong acceptid); 
1999/0824    
 
1999/0907    
 
1999/0824    
static void 
sdpinit(void) 
{ 
1999/0906/sys/src/9/port/devsdp.c:315,3231999/0907/sys/src/9/port/devsdp.c:315,325
1999/0902    
			nexterror(); 
		} 
		if((perm & (c->perm>>6)) != perm) 
		if(strcmp(up->user, c->user) != 0 || (perm & c->perm) != perm) 
1999/0907    
		if(strcmp(up->user, c->owner) != 0 || (perm & c->perm) != perm) 
1999/0902    
				error(Eperm); 
		c->ref++; 
1999/0907    
		if(TYPE(ch->qid) == Qdata) 
			c->dataopen++; 
1999/0902    
		qunlock(c); 
		poperror(); 
		break; 
1999/0906/sys/src/9/port/devsdp.c:332,3371999/0907/sys/src/9/port/devsdp.c:334,340
1999/0902    
sdpclose(Chan* ch) 
1999/0824    
{ 
1999/0902    
	Sdp *sdp  = sdptab + ch->dev; 
1999/0907    
	Conv *c; 
1999/0824    
 
1999/0902    
	switch(TYPE(ch->qid)) { 
1999/0824    
	case Qlog: 
1999/0906/sys/src/9/port/devsdp.c:338,3431999/0907/sys/src/9/port/devsdp.c:341,380
1999/0902    
		if(ch->flag & COPEN) 
1999/0824    
			logclose(sdp); 
		break; 
1999/0907    
	case Qdata: 
	case Qctl: 
	case Qstatus: 
	case Qcontrol: 
		if(!(ch->flag & COPEN)) 
			break; 
		c = sdp->conv[CONV(ch->qid)]; 
		qlock(c); 
		if(waserror()) { 
			qunlock(c); 
			nexterror(); 
		} 
		c->ref--; 
		if(TYPE(ch->qid) == Qdata) { 
			c->dataopen--; 
			if(c->dataopen == 0) 
				wakeup(&c->in.controlready); 
		} 
 
		if(c->ref == 0) { 
			switch(c->state) { 
			default: 
				convsetstate(c, CClosed); 
				break; 
			case COpen: 
				convsetstate(c, CClosing); 
				break; 
			case CClosing: 
				break; 
			} 
		} 
		qunlock(c); 
		poperror(); 
		break; 
1999/0824    
	} 
} 
 
1999/0906/sys/src/9/port/devsdp.c:348,3531999/0907/sys/src/9/port/devsdp.c:385,391
1999/0901    
	Sdp *sdp = sdptab + ch->dev; 
1999/0902    
	char *s; 
1999/0901    
	Conv *c; 
1999/0907    
	Block *b; 
1999/0824    
 
	USED(off); 
1999/0901    
	switch(TYPE(ch->qid)) { 
1999/0906/sys/src/9/port/devsdp.c:384,3921999/0907/sys/src/9/port/devsdp.c:422,458
1999/0901    
	case Qctl: 
		sprint(buf, "%lud", CONV(ch->qid)); 
		return readstr(off, a, n, buf); 
1999/0907    
	case Qcontrol: 
		b = readcontrol(sdp->conv[CONV(ch->qid)], n); 
		if(b == nil) 
			return 0; 
		if(BLEN(b) < n) 
			n = BLEN(b); 
		memmove(a, b->rp, n); 
		freeb(b); 
		return n; 
	case Qdata: 
		b = readdata(sdp->conv[CONV(ch->qid)], n); 
		if(b == nil) 
			return 0; 
		if(BLEN(b) < n) 
			n = BLEN(b); 
		memmove(a, b->rp, n); 
		freeb(b); 
		return n; 
1999/0824    
	} 
} 
 
1999/0907    
static Block* 
sdpbread(Chan* ch, long n, ulong offset) 
{ 
	Sdp *sdp = sdptab + ch->dev; 
 
	if(TYPE(ch->qid) != Qdata) 
		return devbread(ch, n, offset); 
	return readdata(sdp->conv[CONV(ch->qid)], n); 
} 
 
1999/0824    
static long 
1999/0901    
sdpwrite(Chan *ch, void *a, long n, vlong off) 
1999/0824    
{ 
1999/0906/sys/src/9/port/devsdp.c:538,5441999/0907/sys/src/9/port/devsdp.c:604,610
1999/0902    
	c->ref++; 
1999/0906    
	c->state = CInit; 
1999/0902    
 
1999/0901    
	strncpy(c->user, up->user, sizeof(c->user)); 
1999/0907    
	strncpy(c->owner, up->user, sizeof(c->owner)); 
1999/0901    
	c->perm = 0660; 
	qunlock(c); 
1999/0902    
 
1999/0906/sys/src/9/port/devsdp.c:573,5791999/0907/sys/src/9/port/devsdp.c:639,645
1999/0906    
	case COpening: 
print("COpening timeout\n"); 
		if(convretry(c)) 
			sendconnect(c, ConOpen, c->dialid, 0); 
1999/0907    
			convoput2(c, ConOpen, c->dialid, 0); 
1999/0906    
		break; 
	case COpen: 
		// check for control packet 
1999/0906/sys/src/9/port/devsdp.c:581,5871999/0907/sys/src/9/port/devsdp.c:647,653
1999/0906    
	case CClosing: 
print("CClosing timeout\n"); 
		if(convretry(c)) 
			sendconnect(c, ConClose, c->dialid, c->acceptid); 
1999/0907    
			convoput2(c, ConClose, c->dialid, c->acceptid); 
1999/0906    
		break; 
	} 
	qunlock(c); 
1999/0906/sys/src/9/port/devsdp.c:636,6411999/0907/sys/src/9/port/devsdp.c:702,710
1999/0906    
static void 
convsetstate(Conv *c, int state) 
{ 
1999/0907    
 
print("convsetstate %d -> %d\n", c->state, state); 
 
1999/0906    
	switch(state) { 
	default: 
		panic("setstate: bad state: %d", state); 
1999/0906/sys/src/9/port/devsdp.c:645,6511999/0907/sys/src/9/port/devsdp.c:714,720
1999/0906    
		c->dialid = (rand()<<16) + rand(); 
		c->timeout = TK2SEC(m->ticks) + 2; 
		c->retries = 0; 
		sendconnect(c, ConOpen, c->dialid, 0); 
1999/0907    
		convoput2(c, ConOpen, c->dialid, 0); 
1999/0906    
		break; 
	case COpen: 
		switch(c->state) { 
1999/0906/sys/src/9/port/devsdp.c:653,6591999/0907/sys/src/9/port/devsdp.c:722,728
1999/0906    
			error("convsetstate: illegal transition"); 
		case CInit: 
			c->acceptid = (rand()<<16) + rand(); 
			sendconnect(c, ConOpenAck, c->dialid, c->acceptid); 
1999/0907    
			convoput2(c, ConOpenAck, c->dialid, c->acceptid); 
1999/0906    
			break; 
		case COpening: 
			break; 
1999/0906/sys/src/9/port/devsdp.c:661,6701999/0907/sys/src/9/port/devsdp.c:730,758
1999/0906    
		// setup initial key and auth method 
		break; 
	case CClosing: 
1999/0907    
		convoput2(c, ConClose, c->dialid, c->acceptid); 
1999/0906    
		c->timeout = TK2SEC(m->ticks) + 2; 
		c->retries = 0; 
		break; 
	case CClosed: 
1999/0907    
		if(c->readproc) 
			postnote(c->readproc, 1, "interrupt", 0); 
		if(c->ref) 
			break; 
		if(c->chan) {	 
			cclose(c->chan); 
			c->chan = nil; 
		} 
		strcpy(c->owner, "network"); 
		c->perm = 0660; 
		c->dialid = 0; 
		c->acceptid = 0; 
		c->timeout = 0; 
		c->retries = 0; 
		c->drop = 0; 
		memset(c->masterkey, 0, sizeof(c->masterkey)); 
		onewaycleanup(&c->in); 
		onewaycleanup(&c->out); 
1999/0906    
		break; 
	} 
	c->state = state; 
1999/0906/sys/src/9/port/devsdp.c:671,6801999/0907/sys/src/9/port/devsdp.c:759,960
1999/0906    
} 
 
static void 
sendconnect(Conv *c, int op, ulong dialid, ulong acceptid) 
1999/0907    
onewaycleanup(OneWay *ow) 
1999/0906    
{ 
	ConPkt con; 
1999/0907    
	if(ow->controlpkt) 
		freeb(ow->controlpkt); 
	if(ow->authstate) 
		free(ow->authstate); 
	if(ow->cipherstate) 
		free(ow->cipherstate); 
	if(ow->compstate) 
		free(ow->compstate); 
	memset(ow, 0, sizeof(OneWay)); 
} 
1999/0906    
 
1999/0907    
 
static Block * 
convreadblock(Conv *c, int n) 
{ 
	Block *b; 
 
	qlock(&c->readlk); 
	if(waserror()) { 
		c->readproc = nil; 
		qunlock(&c->readlk); 
		nexterror(); 
	} 
	qlock(c); 
	if(c->state == CClosed) { 
		qunlock(c); 
		poperror(); 
		qunlock(&c->readlk); 
		return 0; 
	} 
	c->readproc = up; 
	qunlock(c); 
 
	b = devtab[c->chan->type]->bread(c->chan, n, 0); 
	c->readproc = nil; 
	poperror(); 
	qunlock(&c->readlk); 
 
	return b; 
} 
 
 
// assume we hold lock for c 
static Block * 
conviput(Conv *c, Block *b, int control) 
{ 
	int type; 
	ulong seq, cseq; 
 
	if(BLEN(b) < 4) { 
		freeb(b); 
		return nil; 
	} 
	 
	type = b->rp[0]; 
	if(type == TConnect) { 
		conviput2(c, b); 
		return nil; 
	} 
 
	seq = (b->rp[1]<<16) + (b->rp[2]<<8) + b->rp[3]; 
	b->rp += 4; 
 
	USED(seq); 
	// auth 
	// decrypt 
 
	// ok the packet is good 
 
	switch(type) { 
	case TControl: 
		if(BLEN(b) <= 4) 
			break; 
		cseq = nhgetl(b->rp); 
		if(cseq == c->in.controlseq) { 
			// duplicate control packet 
			// send ack 
			b->wp = b->rp + 4; 
			convoput(c, TControlAck, b); 
			return nil; 
		} 
 
		if(cseq != c->in.controlseq+1) 
			break; 
	 
		c->in.controlseq = cseq; 
		b->rp += 4; 
		if(control) 
			return b; 
		c->in.controlpkt = b; 
		wakeup(&c->in.controlready); 
		return nil; 
	case TControlAck: 
		if(BLEN(b) != 4) 
			break; 
		cseq = nhgetl(b->rp); 
		if(cseq != c->out.controlseq) 
			break; 
		freeb(b); 
		freeb(c->out.controlpkt); 
		c->out.controlpkt = 0; 
		wakeup(&c->out.controlready); 
		return nil; 
	case TData: 
		if(control) 
			break; 
		return b; 
	} 
print("droping packet %d n=%ld\n", type, BLEN(b)); 
	freeb(b); 
	return nil; 
} 
 
// assume hold conv lock 
static void 
conviput2(Conv *c, Block *b) 
{ 
	ConnectPkt *con; 
	ulong dialid; 
	ulong acceptid; 
 
	if(BLEN(b) != sizeof(ConnectPkt)) { 
		freeb(b); 
		return; 
	} 
	con = (ConnectPkt*)b->rp; 
	dialid = nhgetl(con->dialid); 
	acceptid = nhgetl(con->acceptid); 
 
print("conviput2: %d %uld %uld\n", con->op, dialid, acceptid); 
	switch(con->op) { 
	case ConOpen: 
		if(c->state != COpen || dialid != c->dialid || acceptid != c->acceptid) 
			convoput2(c, ConOpenNack, dialid, acceptid); 
		else 
			convoput2(c, ConOpenAck, dialid, acceptid); 
		break; 
	case ConOpenAck: 
		if(c->state != COpening || dialid != c->dialid) 
			break; 
		c->acceptid = acceptid; 
		convsetstate(c, COpen); 
		break; 
	case ConOpenNack: 
		if(c->state != COpening || dialid != c->dialid) 
			break; 
		convsetstate(c, CClosed); 
		break; 
	case ConClose: 
		if(dialid != c->dialid || acceptid != c->acceptid) 
			break; 
		convsetstate(c, CClosed); 
		break; 
	case ConCloseAck: 
		if(c->state != CClosing || dialid != c->dialid || acceptid != c->acceptid) 
			break; 
		convsetstate(c, CClosed); 
		break; 
	} 
} 
 
// assume hold conv lock 
static void 
convoput(Conv *c, int type, Block *b) 
{ 
	// try and compress 
 
	/* Make space to fit sdp header */ 
	b = padblock(b, 4 + c->out.cipherivlen); 
	b->rp[0] = type; 
	c->out.seq++; 
	if(c->out.seq == (1<<24)) { 
		c->out.seq = 0; 
		c->out.seqwrap++; 
	} 
	b->rp[1] = c->out.seq>>16; 
	b->rp[2] = c->out.seq>>8; 
	b->rp[3] = c->out.seq; 
	 
	// encrypt 
	// auth 
 
	// simulated errors 
	if(c->drop && c->drop > nrand(c->drop)) 
		return; 
	devtab[c->chan->type]->bwrite(c->chan, b, 0); 
} 
 
// assume hold conv lock 
static void 
convoput2(Conv *c, int op, ulong dialid, ulong acceptid) 
{ 
	ConnectPkt con; 
 
1999/0906    
	if(c->chan == nil) { 
print("chan = nil\n"); 
		error("no channel attached"); 
1999/0906/sys/src/9/port/devsdp.c:689,6921999/0907/sys/src/9/port/devsdp.c:969,1052
1999/0906    
	if(c->drop && c->drop > nrand(c->drop)) 
		return; 
	devtab[c->chan->type]->write(c->chan, &con, sizeof(con), 0); 
1999/0907    
} 
 
static int 
readready(void *a) 
{ 
	Conv *c = a; 
 
	return (c->state == CClosed) || c->in.controlpkt != nil || c->dataopen == 0; 
} 
 
static Block * 
readcontrol(Conv *c, int n) 
{ 
	Block *b; 
 
	for(;;) { 
		qlock(c); 
		if(c->state == CClosed || c->state == CInit) { 
			qunlock(c); 
			return nil; 
		} 
 
		if(c->in.controlpkt != nil) { 
			b = c->in.controlpkt; 
			c->in.controlpkt = nil; 
			qunlock(c); 
			return b; 
		} 
		qunlock(c); 
 
		// hack - this is to avoid gating onto the 
		// read which will in general result in excessive 
		// context switches. 
		// The assumed behavior is that the client will read 
		// from the control channel until the session is authenticated 
		// at which point it will open the data channel and 
		// start reading on that.  After the data channel is opened, 
		// read on the channel are required for packets to 
		// be delivered to the control channel 
 
		if(c->dataopen) { 
			sleep(&c->in.controlready, readready, c); 
		} else { 
			b = convreadblock(c, n); 
			if(b == nil) 
				return nil; 
			qlock(c); 
			if(waserror()) { 
				qunlock(c); 
				return nil; 
			} 
			b = conviput(c, b, 1); 
			poperror(); 
			qunlock(c); 
			if(b != nil) 
				return b; 
		} 
	} 
} 
 
static Block * 
readdata(Conv *c, int n) 
{ 
	Block *b; 
 
	for(;;) { 
		b = convreadblock(c, n); 
		if(b == nil) 
			return nil; 
		qlock(c); 
		if(waserror()) { 
			qunlock(c); 
			return nil; 
		} 
		b = conviput(c, b, 0); 
		poperror(); 
		qunlock(c); 
		if(b != nil) 
			return b; 
	} 
1999/0906    
} 


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