#include #include #include #include "dat.h" #include "fns.h" enum { Bit7 = (1<<7), /* X.224 PDU codes */ TPDUCR = 0xE0, /* connection request */ TPDUCC = 0xD0, /* connection confirm */ TPDUDR = 0x80, /* disconnection request */ TPDUDT = 0xF0, /* data */ TPDUER = 0x70, /* error */ }; /* * examine a packet header at between p and ep * 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); } /* * 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&Bit7) len = ((len^Bit7)<<8) | p[2]; break; default: /* TPKT-encapsulated TPDU */ len = GSHORTB(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; } int tpdutype(uchar* p, uchar* ep) { if(p+5 >= ep){ werrstr(Eshort); return -1; } return p[5]; } int isdatatpdu(uchar* p, uchar* ep) { return (tpdutype(p,ep) == TPDUDT); } uchar* tpdupayload(uchar* p, uchar* ep) { uchar* q; if(istpkt(p, ep) == 0){ werrstr("Fast-Path Update PDU is not expected"); return nil; } if(tpdutype(p,ep) == TPDUDT) q = p+7; else q = p+11; if(q > ep) return nil; return q; } int mktpcr(uchar* buf, int nbuf, int ndata) /* connect request */ { int size; uchar *p; p = buf; size = TPKTFIXLEN+8+ndata; if(size > nbuf){ werrstr(Esmall); return -1; } /* TPKT header */ p[0] = 0x03; p[1] = 0; PSHORTB(p+2, size); /* TPDU */ p[4] = 7+ndata; /* length indicator */ p[5] = TPDUCR; /* TPDU code */ PSHORTB(p+6, 0); /* DST-REF */ PSHORTB(p+8, 0); /* SRC-REF */ p[10] = 0; /* CLASS OPTION: class 0 */ return size; } int mktpdat(uchar* buf, int nbuf, int ndata) /* data transfer */ { 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 */ p[0] = 0x03; p[1] = 0; PSHORTB(p+2, size); /* TPDU */ p[4] = 2; /* length indicator */ p[5] = TPDUDT; /* TPDU code */ p[6] = Bit7; /* TPDU send seqno (0 in Class 0) + EOT mark (1<<7) */ return size; } int mktpdr(uchar* buf, int nbuf, int ndata) /* disconnection request */ { int size; uchar *p; p = buf; size = TPDATAFIXLEN+ndata; if(size > nbuf){ werrstr("buffer too small"); return -1; } /* TPKT header */ p[0] = 0x03; p[1] = 0; PSHORTB(p+2, size); /* TPDU */ p[4] = 2; /* length indicator */ p[5] = TPDUDR; /* TPDU code */ p[6] = Bit7; /* TPDU send seqno (0 in Class 0) + EOT mark (1<<7) */ return size; } int x224connect(int fd) { int n; uchar buf[12]; n = mktpcr(buf, sizeof buf, 0); if(n < 0) return -1; if(write(fd, buf, n) != n) return -1; n = readpdu(fd, buf, sizeof buf); if(n < 6) return -1; if(!istpkt(buf, buf+n) || tpdutype(buf,buf+n) != TPDUCC){ werrstr("X.224: protocol botch"); return -1; } return 1; } int x224disconnect(int fd) { int n, m; uchar buf[12]; n = mktpdr(buf, sizeof buf, 0); m = write(fd, buf, n); return m; }