shithub: rd

ref: 358c45c5326b463845e900fd8f16475c85a8d681
dir: rd/x224.c

View raw version
#include <u.h>
#include <libc.h>
#include "dat.h"
#include "fns.h"

/*
 * examine a packet header
 * returns 1 if it's a TPKT-encapsulated TPDU (T.123 clause 8; RFC 1006)
 * returns 0 if not - likely a Fast-Path Update PDU ([MS-RDPBCGR] 5.3.8 and 5.4.4)
 */
int
istpkt(uchar* p, uchar* ep)
{
	int magic;

	if(p+1>ep){
		werrstr(Eshort);
		return -1;
	}

	magic = p[0];
	return (magic == 3);
}

int
tptype(uchar* p, uchar* ep)
{
	if(p+5 >= ep){
		werrstr(Eshort);
		return -1;
	}
	return p[5];
}

/*
 * read a PDU: either TPKT-encapsulated TPDU or Fast-Path Update PDU
 */
int
readpdu(int fd, uchar *buf, uint nbuf)
{
	int n, len;
	uchar *p;

	p = buf;

	n = readn(fd, p, TPKTFIXLEN);
	if(n != TPKTFIXLEN){
		werrstr("short read: %r");
		return -1;
	}

	switch(istpkt(p, p+n)){
	case -1:
		return -1;
	case 0:
		/* Fast-Path Update PDU */
		len = p[1];
		if(len&(1<<7))
			len = ((len^(1<<7))<<8) | p[2];
		break;
	default:
		/* TPKT-encapsulated TPDU */
		len = nhgets(p+2);
	}
	
	if(len <= n || len > nbuf){
		werrstr("bad length in PDU header: %d", len);
		return -1;
	}

	n += readn(fd, p+n, len-n);
	if(n != len)
		return -1;
	return n;
}

uchar*
tpdat(uchar* p, uchar* ep)
{
	uchar* q;

	if(istpkt(p, ep) == 0){
		werrstr("Fast-Path Update PDU is not expected");
		return nil;
	}
	if(tptype(p,ep) == Data)
		q = p+7;
	else
		q = p+11;
	if(q > ep){
		werrstr(Eshort);
		return nil;
	}
	return q;
}

/* connect request */
int
mktpcr(uchar* buf, int nbuf, int ndata)
{
	int size;
	uchar *p;

	p = buf;
	size = TPKTFIXLEN+7+ndata;
	if(size > nbuf){
		werrstr(Esmall);
		return -1;
	}

	/* TPKT header: version[1] unused[1] len[2] */
	p[0] = 0x03;
	p[1] = 0;
	hnputs(p+2, size);

	/* ConReq: hdlen[1] type[1] dstref[2] srcref[2] class[1] */
	p[4+0] = 7-1+ndata;
	p[4+1] = ConReq;
	hnputs(p+4+2, 0);
	hnputs(p+4+4, 0);
	p[4+6] = 0;

	return size;
}

/* data transfer */
int
mktpdat(uchar* buf, int nbuf, int ndata)
{
	int size;
	uchar *p;

	p = buf;
	size = TPDATAFIXLEN+ndata;
	if(size > nbuf){
		werrstr("buffer too small: provided %d need %d", nbuf, size);
		return -1;
	}

	/* TPKT header: version[1] unused[1] len[2] */
	p[0] = 0x03;
	p[1] = 0;
	hnputs(p+2, size);

	/* TPDU: hdlen[1] type[1] seqno[1] */
	p[4] = 2;
	p[5] = Data;
	p[6] = (1<<7);	/* seqno (0 in Class 0) + EOT mark (1<<7) */

	return size;
}

/* disconnection request */
int
mktpdr(uchar* buf, int nbuf, int ndata)
{
	int size;
	uchar *p;

	p = buf;
	size = TPDATAFIXLEN+ndata;
	if(size > nbuf){
		werrstr("buffer too small");
		return -1;
	}

	/* TPKT header: version[1] unused[1] len[2] */
	p[0] = 0x03;
	p[1] = 0;
	hnputs(p+2, size);

	/* HupReq: hdlen[1] type[1] seqno[1] */
	p[4] = 2;
	p[5] = HupReq;
	p[6] = (1<<7);		/* seqno (0 in Class 0) + EOT mark (1<<7) */
	return size;
}