146ecee76SDavid du Colombier #include "u.h"
246ecee76SDavid du Colombier #include "../port/lib.h"
346ecee76SDavid du Colombier #include "mem.h"
446ecee76SDavid du Colombier #include "dat.h"
546ecee76SDavid du Colombier #include "fns.h"
646ecee76SDavid du Colombier #include "../port/netif.h"
746ecee76SDavid du Colombier #include "../port/error.h"
846ecee76SDavid du Colombier
946ecee76SDavid du Colombier #include <libsec.h>
1046ecee76SDavid du Colombier #include "../port/thwack.h"
1146ecee76SDavid du Colombier
1246ecee76SDavid du Colombier /*
1346ecee76SDavid du Colombier * sdp - secure datagram protocol
1446ecee76SDavid du Colombier */
1546ecee76SDavid du Colombier
1646ecee76SDavid du Colombier typedef struct Sdp Sdp;
1746ecee76SDavid du Colombier typedef struct Conv Conv;
1846ecee76SDavid du Colombier typedef struct OneWay OneWay;
1946ecee76SDavid du Colombier typedef struct Stats Stats;
2046ecee76SDavid du Colombier typedef struct AckPkt AckPkt;
2146ecee76SDavid du Colombier typedef struct Algorithm Algorithm;
2246ecee76SDavid du Colombier typedef struct CipherRc4 CipherRc4;
2346ecee76SDavid du Colombier
2446ecee76SDavid du Colombier enum
2546ecee76SDavid du Colombier {
2646ecee76SDavid du Colombier Qtopdir= 1, /* top level directory */
2746ecee76SDavid du Colombier
2846ecee76SDavid du Colombier Qsdpdir, /* sdp directory */
2946ecee76SDavid du Colombier Qclone,
3046ecee76SDavid du Colombier Qlog,
3146ecee76SDavid du Colombier
3246ecee76SDavid du Colombier Qconvdir, /* directory per conversation */
3346ecee76SDavid du Colombier Qctl,
3446ecee76SDavid du Colombier Qdata, /* unreliable packet channel */
3546ecee76SDavid du Colombier Qcontrol, /* reliable control channel */
3646ecee76SDavid du Colombier Qstatus,
3746ecee76SDavid du Colombier Qstats,
3846ecee76SDavid du Colombier Qrstats,
3946ecee76SDavid du Colombier
4046ecee76SDavid du Colombier MaxQ,
4146ecee76SDavid du Colombier
4246ecee76SDavid du Colombier Maxconv= 256, // power of 2
4346ecee76SDavid du Colombier Nfs= 4, // number of file systems
4446ecee76SDavid du Colombier MaxRetries= 12,
4546ecee76SDavid du Colombier KeepAlive = 300, // keep alive in seconds - should probably be about 60 but is higher to avoid linksys bug
4646ecee76SDavid du Colombier SecretLength= 32, // a secret per direction
4746ecee76SDavid du Colombier SeqMax = (1<<24),
4846ecee76SDavid du Colombier SeqWindow = 32,
4946ecee76SDavid du Colombier NCompStats = 8,
5046ecee76SDavid du Colombier };
5146ecee76SDavid du Colombier
5246ecee76SDavid du Colombier #define TYPE(x) (((ulong)(x).path) & 0xff)
5346ecee76SDavid du Colombier #define CONV(x) ((((ulong)(x).path) >> 8)&(Maxconv-1))
5446ecee76SDavid du Colombier #define QID(x, y) (((x)<<8) | (y))
5546ecee76SDavid du Colombier
5646ecee76SDavid du Colombier struct Stats
5746ecee76SDavid du Colombier {
5846ecee76SDavid du Colombier ulong outPackets;
5946ecee76SDavid du Colombier ulong outDataPackets;
6046ecee76SDavid du Colombier ulong outDataBytes;
6146ecee76SDavid du Colombier ulong outCompDataBytes;
6246ecee76SDavid du Colombier ulong outCompBytes;
6346ecee76SDavid du Colombier ulong outCompStats[NCompStats];
6446ecee76SDavid du Colombier ulong inPackets;
6546ecee76SDavid du Colombier ulong inDataPackets;
6646ecee76SDavid du Colombier ulong inDataBytes;
6746ecee76SDavid du Colombier ulong inCompDataBytes;
6846ecee76SDavid du Colombier ulong inMissing;
6946ecee76SDavid du Colombier ulong inDup;
7046ecee76SDavid du Colombier ulong inReorder;
7146ecee76SDavid du Colombier ulong inBadComp;
7246ecee76SDavid du Colombier ulong inBadAuth;
7346ecee76SDavid du Colombier ulong inBadSeq;
7446ecee76SDavid du Colombier ulong inBadOther;
7546ecee76SDavid du Colombier };
7646ecee76SDavid du Colombier
7746ecee76SDavid du Colombier struct OneWay
7846ecee76SDavid du Colombier {
7946ecee76SDavid du Colombier Rendez statsready;
8046ecee76SDavid du Colombier
8146ecee76SDavid du Colombier ulong seqwrap; // number of wraps of the sequence number
8246ecee76SDavid du Colombier ulong seq;
8346ecee76SDavid du Colombier ulong window;
8446ecee76SDavid du Colombier
8546ecee76SDavid du Colombier uchar secret[SecretLength];
8646ecee76SDavid du Colombier
8746ecee76SDavid du Colombier QLock controllk;
8846ecee76SDavid du Colombier Rendez controlready;
8946ecee76SDavid du Colombier Block *controlpkt; // control channel
9046ecee76SDavid du Colombier ulong controlseq;
9146ecee76SDavid du Colombier
9246ecee76SDavid du Colombier void *cipherstate; // state cipher
9346ecee76SDavid du Colombier int cipherivlen; // initial vector length
9446ecee76SDavid du Colombier int cipherblklen; // block length
9546ecee76SDavid du Colombier int (*cipher)(OneWay*, uchar *buf, int len);
9646ecee76SDavid du Colombier
9746ecee76SDavid du Colombier void *authstate; // auth state
9846ecee76SDavid du Colombier int authlen; // auth data length in bytes
9946ecee76SDavid du Colombier int (*auth)(OneWay*, uchar *buf, int len);
10046ecee76SDavid du Colombier
10146ecee76SDavid du Colombier void *compstate;
10246ecee76SDavid du Colombier int (*comp)(Conv*, int subtype, ulong seq, Block **);
10346ecee76SDavid du Colombier };
10446ecee76SDavid du Colombier
10546ecee76SDavid du Colombier // conv states
10646ecee76SDavid du Colombier enum {
10746ecee76SDavid du Colombier CFree,
10846ecee76SDavid du Colombier CInit,
10946ecee76SDavid du Colombier CDial,
11046ecee76SDavid du Colombier CAccept,
11146ecee76SDavid du Colombier COpen,
11246ecee76SDavid du Colombier CLocalClose,
11346ecee76SDavid du Colombier CRemoteClose,
11446ecee76SDavid du Colombier CClosed,
11546ecee76SDavid du Colombier };
11646ecee76SDavid du Colombier
11746ecee76SDavid du Colombier struct Conv {
11846ecee76SDavid du Colombier QLock;
11946ecee76SDavid du Colombier Sdp *sdp;
12046ecee76SDavid du Colombier int id;
12146ecee76SDavid du Colombier
12246ecee76SDavid du Colombier int ref; // holds conv up
12346ecee76SDavid du Colombier
12446ecee76SDavid du Colombier int state;
12546ecee76SDavid du Colombier
12646ecee76SDavid du Colombier int dataopen; // ref count of opens on Qdata
12746ecee76SDavid du Colombier int controlopen; // ref count of opens on Qcontrol
12846ecee76SDavid du Colombier int reader; // reader proc has been started
12946ecee76SDavid du Colombier
13046ecee76SDavid du Colombier Stats lstats;
13146ecee76SDavid du Colombier Stats rstats;
13246ecee76SDavid du Colombier
13346ecee76SDavid du Colombier ulong lastrecv; // time last packet was received
13446ecee76SDavid du Colombier ulong timeout;
13546ecee76SDavid du Colombier int retries;
13646ecee76SDavid du Colombier
13746ecee76SDavid du Colombier // the following pair uniquely define conversation on this port
13846ecee76SDavid du Colombier ulong dialid;
13946ecee76SDavid du Colombier ulong acceptid;
14046ecee76SDavid du Colombier
14146ecee76SDavid du Colombier QLock readlk; // protects readproc
14246ecee76SDavid du Colombier Proc *readproc;
14346ecee76SDavid du Colombier
14446ecee76SDavid du Colombier Chan *chan; // packet channel
14546ecee76SDavid du Colombier char *channame;
14646ecee76SDavid du Colombier
14746ecee76SDavid du Colombier char owner[KNAMELEN]; /* protections */
14846ecee76SDavid du Colombier int perm;
14946ecee76SDavid du Colombier
15046ecee76SDavid du Colombier Algorithm *auth;
15146ecee76SDavid du Colombier Algorithm *cipher;
15246ecee76SDavid du Colombier Algorithm *comp;
15346ecee76SDavid du Colombier
15446ecee76SDavid du Colombier int drop;
15546ecee76SDavid du Colombier
15646ecee76SDavid du Colombier OneWay in;
15746ecee76SDavid du Colombier OneWay out;
15846ecee76SDavid du Colombier };
15946ecee76SDavid du Colombier
16046ecee76SDavid du Colombier struct Sdp {
16146ecee76SDavid du Colombier QLock;
16246ecee76SDavid du Colombier Log;
16346ecee76SDavid du Colombier int nconv;
16446ecee76SDavid du Colombier Conv *conv[Maxconv];
16546ecee76SDavid du Colombier int ackproc;
16646ecee76SDavid du Colombier };
16746ecee76SDavid du Colombier
16846ecee76SDavid du Colombier enum {
16946ecee76SDavid du Colombier TConnect,
17046ecee76SDavid du Colombier TControl,
17146ecee76SDavid du Colombier TData,
17246ecee76SDavid du Colombier TCompData,
17346ecee76SDavid du Colombier };
17446ecee76SDavid du Colombier
17546ecee76SDavid du Colombier enum {
17646ecee76SDavid du Colombier ControlMesg,
17746ecee76SDavid du Colombier ControlAck,
17846ecee76SDavid du Colombier };
17946ecee76SDavid du Colombier
18046ecee76SDavid du Colombier enum {
18146ecee76SDavid du Colombier ThwackU,
18246ecee76SDavid du Colombier ThwackC,
18346ecee76SDavid du Colombier };
18446ecee76SDavid du Colombier
18546ecee76SDavid du Colombier enum {
18646ecee76SDavid du Colombier ConOpenRequest,
18746ecee76SDavid du Colombier ConOpenAck,
18846ecee76SDavid du Colombier ConOpenAckAck,
18946ecee76SDavid du Colombier ConClose,
19046ecee76SDavid du Colombier ConCloseAck,
19146ecee76SDavid du Colombier ConReset,
19246ecee76SDavid du Colombier };
19346ecee76SDavid du Colombier
19446ecee76SDavid du Colombier struct AckPkt
19546ecee76SDavid du Colombier {
19646ecee76SDavid du Colombier uchar cseq[4];
19746ecee76SDavid du Colombier uchar outPackets[4];
19846ecee76SDavid du Colombier uchar outDataPackets[4];
19946ecee76SDavid du Colombier uchar outDataBytes[4];
20046ecee76SDavid du Colombier uchar outCompDataBytes[4];
20146ecee76SDavid du Colombier uchar outCompStats[4*NCompStats];
20246ecee76SDavid du Colombier uchar inPackets[4];
20346ecee76SDavid du Colombier uchar inDataPackets[4];
20446ecee76SDavid du Colombier uchar inDataBytes[4];
20546ecee76SDavid du Colombier uchar inCompDataBytes[4];
20646ecee76SDavid du Colombier uchar inMissing[4];
20746ecee76SDavid du Colombier uchar inDup[4];
20846ecee76SDavid du Colombier uchar inReorder[4];
20946ecee76SDavid du Colombier uchar inBadComp[4];
21046ecee76SDavid du Colombier uchar inBadAuth[4];
21146ecee76SDavid du Colombier uchar inBadSeq[4];
21246ecee76SDavid du Colombier uchar inBadOther[4];
21346ecee76SDavid du Colombier };
21446ecee76SDavid du Colombier
21546ecee76SDavid du Colombier struct Algorithm
21646ecee76SDavid du Colombier {
21746ecee76SDavid du Colombier char *name;
21846ecee76SDavid du Colombier int keylen; // in bytes
21946ecee76SDavid du Colombier void (*init)(Conv*);
22046ecee76SDavid du Colombier };
22146ecee76SDavid du Colombier
22246ecee76SDavid du Colombier enum {
22346ecee76SDavid du Colombier RC4forward = 10*1024*1024, // maximum skip forward
22446ecee76SDavid du Colombier RC4back = 100*1024, // maximum look back
22546ecee76SDavid du Colombier };
22646ecee76SDavid du Colombier
22746ecee76SDavid du Colombier struct CipherRc4
22846ecee76SDavid du Colombier {
22946ecee76SDavid du Colombier ulong cseq; // current byte sequence number
23046ecee76SDavid du Colombier RC4state current;
23146ecee76SDavid du Colombier
23246ecee76SDavid du Colombier int ovalid; // old is valid
23346ecee76SDavid du Colombier ulong lgseq; // last good sequence
23446ecee76SDavid du Colombier ulong oseq; // old byte sequence number
23546ecee76SDavid du Colombier RC4state old;
23646ecee76SDavid du Colombier };
23746ecee76SDavid du Colombier
23846ecee76SDavid du Colombier static Dirtab sdpdirtab[]={
23946ecee76SDavid du Colombier "log", {Qlog}, 0, 0666,
24046ecee76SDavid du Colombier "clone", {Qclone}, 0, 0666,
24146ecee76SDavid du Colombier };
24246ecee76SDavid du Colombier
24346ecee76SDavid du Colombier static Dirtab convdirtab[]={
24446ecee76SDavid du Colombier "ctl", {Qctl}, 0, 0666,
24546ecee76SDavid du Colombier "data", {Qdata}, 0, 0666,
24646ecee76SDavid du Colombier "control", {Qcontrol}, 0, 0666,
24746ecee76SDavid du Colombier "status", {Qstatus}, 0, 0444,
24846ecee76SDavid du Colombier "stats", {Qstats}, 0, 0444,
24946ecee76SDavid du Colombier "rstats", {Qrstats}, 0, 0444,
25046ecee76SDavid du Colombier };
25146ecee76SDavid du Colombier
25246ecee76SDavid du Colombier static int m2p[] = {
25346ecee76SDavid du Colombier [OREAD] 4,
25446ecee76SDavid du Colombier [OWRITE] 2,
25546ecee76SDavid du Colombier [ORDWR] 6
25646ecee76SDavid du Colombier };
25746ecee76SDavid du Colombier
25846ecee76SDavid du Colombier enum {
25946ecee76SDavid du Colombier Logcompress= (1<<0),
26046ecee76SDavid du Colombier Logauth= (1<<1),
26146ecee76SDavid du Colombier Loghmac= (1<<2),
26246ecee76SDavid du Colombier };
26346ecee76SDavid du Colombier
26446ecee76SDavid du Colombier static Logflag logflags[] =
26546ecee76SDavid du Colombier {
26646ecee76SDavid du Colombier { "compress", Logcompress, },
26746ecee76SDavid du Colombier { "auth", Logauth, },
26846ecee76SDavid du Colombier { "hmac", Loghmac, },
26946ecee76SDavid du Colombier { nil, 0, },
27046ecee76SDavid du Colombier };
27146ecee76SDavid du Colombier
27246ecee76SDavid du Colombier static Dirtab *dirtab[MaxQ];
27346ecee76SDavid du Colombier static Sdp sdptab[Nfs];
27446ecee76SDavid du Colombier static char *convstatename[] = {
27546ecee76SDavid du Colombier [CFree] "Free",
27646ecee76SDavid du Colombier [CInit] "Init",
27746ecee76SDavid du Colombier [CDial] "Dial",
27846ecee76SDavid du Colombier [CAccept] "Accept",
27946ecee76SDavid du Colombier [COpen] "Open",
28046ecee76SDavid du Colombier [CLocalClose] "LocalClose",
28146ecee76SDavid du Colombier [CRemoteClose] "RemoteClose",
28246ecee76SDavid du Colombier [CClosed] "Closed",
28346ecee76SDavid du Colombier };
28446ecee76SDavid du Colombier
28546ecee76SDavid du Colombier static int sdpgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp);
28646ecee76SDavid du Colombier static Conv *sdpclone(Sdp *sdp);
28746ecee76SDavid du Colombier static void sdpackproc(void *a);
28846ecee76SDavid du Colombier static void onewaycleanup(OneWay *ow);
28946ecee76SDavid du Colombier static int readready(void *a);
29046ecee76SDavid du Colombier static int controlread();
29146ecee76SDavid du Colombier static void convsetstate(Conv *c, int state);
29246ecee76SDavid du Colombier static Block *readcontrol(Conv *c, int n);
29346ecee76SDavid du Colombier static void writecontrol(Conv *c, void *p, int n, int wait);
29446ecee76SDavid du Colombier static Block *readdata(Conv *c, int n);
29546ecee76SDavid du Colombier static long writedata(Conv *c, Block *b);
29646ecee76SDavid du Colombier static void convderef(Conv *c);
29746ecee76SDavid du Colombier static Block *conviput(Conv *c, Block *b, int control);
29846ecee76SDavid du Colombier static void conviconnect(Conv *c, int op, Block *b);
29946ecee76SDavid du Colombier static void convicontrol(Conv *c, int op, Block *b);
30046ecee76SDavid du Colombier static Block *convicomp(Conv *c, int op, ulong, Block *b);
30146ecee76SDavid du Colombier static void convoput(Conv *c, int type, int subtype, Block *b);
30246ecee76SDavid du Colombier static void convoconnect(Conv *c, int op, ulong dialid, ulong acceptid);
30346ecee76SDavid du Colombier static void convopenchan(Conv *c, char *path);
30446ecee76SDavid du Colombier static void convstats(Conv *c, int local, char *buf, int n);
30546ecee76SDavid du Colombier static void convreader(void *a);
30646ecee76SDavid du Colombier
30746ecee76SDavid du Colombier static void setalg(Conv *c, char *name, Algorithm *tab, Algorithm **);
30846ecee76SDavid du Colombier static void setsecret(OneWay *cc, char *secret);
30946ecee76SDavid du Colombier
31046ecee76SDavid du Colombier static void nullcipherinit(Conv*c);
31146ecee76SDavid du Colombier static void descipherinit(Conv*c);
31246ecee76SDavid du Colombier static void rc4cipherinit(Conv*c);
31346ecee76SDavid du Colombier static void nullauthinit(Conv*c);
31446ecee76SDavid du Colombier static void shaauthinit(Conv*c);
31546ecee76SDavid du Colombier static void md5authinit(Conv*c);
31646ecee76SDavid du Colombier static void nullcompinit(Conv*c);
31746ecee76SDavid du Colombier static void thwackcompinit(Conv*c);
31846ecee76SDavid du Colombier
31946ecee76SDavid du Colombier static Algorithm cipheralg[] =
32046ecee76SDavid du Colombier {
32146ecee76SDavid du Colombier "null", 0, nullcipherinit,
32246ecee76SDavid du Colombier "des_56_cbc", 7, descipherinit,
32346ecee76SDavid du Colombier "rc4_128", 16, rc4cipherinit,
32446ecee76SDavid du Colombier "rc4_256", 32, rc4cipherinit,
32546ecee76SDavid du Colombier nil, 0, nil,
32646ecee76SDavid du Colombier };
32746ecee76SDavid du Colombier
32846ecee76SDavid du Colombier static Algorithm authalg[] =
32946ecee76SDavid du Colombier {
33046ecee76SDavid du Colombier "null", 0, nullauthinit,
33146ecee76SDavid du Colombier "hmac_sha1_96", 16, shaauthinit,
33246ecee76SDavid du Colombier "hmac_md5_96", 16, md5authinit,
33346ecee76SDavid du Colombier nil, 0, nil,
33446ecee76SDavid du Colombier };
33546ecee76SDavid du Colombier
33646ecee76SDavid du Colombier static Algorithm compalg[] =
33746ecee76SDavid du Colombier {
33846ecee76SDavid du Colombier "null", 0, nullcompinit,
33946ecee76SDavid du Colombier "thwack", 0, thwackcompinit,
34046ecee76SDavid du Colombier nil, 0, nil,
34146ecee76SDavid du Colombier };
34246ecee76SDavid du Colombier
34346ecee76SDavid du Colombier
34446ecee76SDavid du Colombier static void
sdpinit(void)34546ecee76SDavid du Colombier sdpinit(void)
34646ecee76SDavid du Colombier {
34746ecee76SDavid du Colombier int i;
34846ecee76SDavid du Colombier Dirtab *dt;
34946ecee76SDavid du Colombier
35046ecee76SDavid du Colombier // setup dirtab with non directory entries
35146ecee76SDavid du Colombier for(i=0; i<nelem(sdpdirtab); i++) {
35246ecee76SDavid du Colombier dt = sdpdirtab + i;
35346ecee76SDavid du Colombier dirtab[TYPE(dt->qid)] = dt;
35446ecee76SDavid du Colombier }
35546ecee76SDavid du Colombier
35646ecee76SDavid du Colombier for(i=0; i<nelem(convdirtab); i++) {
35746ecee76SDavid du Colombier dt = convdirtab + i;
35846ecee76SDavid du Colombier dirtab[TYPE(dt->qid)] = dt;
35946ecee76SDavid du Colombier }
36046ecee76SDavid du Colombier
36146ecee76SDavid du Colombier }
36246ecee76SDavid du Colombier
36346ecee76SDavid du Colombier static Chan*
sdpattach(char * spec)36446ecee76SDavid du Colombier sdpattach(char* spec)
36546ecee76SDavid du Colombier {
36646ecee76SDavid du Colombier Chan *c;
36746ecee76SDavid du Colombier int dev;
36846ecee76SDavid du Colombier char buf[100];
36946ecee76SDavid du Colombier Sdp *sdp;
37046ecee76SDavid du Colombier int start;
37146ecee76SDavid du Colombier
37246ecee76SDavid du Colombier dev = atoi(spec);
37346ecee76SDavid du Colombier if(dev<0 || dev >= Nfs)
37446ecee76SDavid du Colombier error("bad specification");
37546ecee76SDavid du Colombier
37646ecee76SDavid du Colombier c = devattach('E', spec);
37746ecee76SDavid du Colombier c->qid = (Qid){QID(0, Qtopdir), 0, QTDIR};
37846ecee76SDavid du Colombier c->dev = dev;
37946ecee76SDavid du Colombier
38046ecee76SDavid du Colombier sdp = sdptab + dev;
38146ecee76SDavid du Colombier qlock(sdp);
38246ecee76SDavid du Colombier start = sdp->ackproc == 0;
38346ecee76SDavid du Colombier sdp->ackproc = 1;
38446ecee76SDavid du Colombier qunlock(sdp);
38546ecee76SDavid du Colombier
38646ecee76SDavid du Colombier if(start) {
38746ecee76SDavid du Colombier snprint(buf, sizeof(buf), "sdpackproc%d", dev);
38846ecee76SDavid du Colombier kproc(buf, sdpackproc, sdp);
38946ecee76SDavid du Colombier }
39046ecee76SDavid du Colombier
39146ecee76SDavid du Colombier return c;
39246ecee76SDavid du Colombier }
39346ecee76SDavid du Colombier
39446ecee76SDavid du Colombier static Walkqid*
sdpwalk(Chan * c,Chan * nc,char ** name,int nname)39546ecee76SDavid du Colombier sdpwalk(Chan *c, Chan *nc, char **name, int nname)
39646ecee76SDavid du Colombier {
39746ecee76SDavid du Colombier return devwalk(c, nc, name, nname, 0, 0, sdpgen);
39846ecee76SDavid du Colombier }
39946ecee76SDavid du Colombier
40046ecee76SDavid du Colombier static int
sdpstat(Chan * c,uchar * db,int n)40146ecee76SDavid du Colombier sdpstat(Chan* c, uchar* db, int n)
40246ecee76SDavid du Colombier {
40346ecee76SDavid du Colombier return devstat(c, db, n, nil, 0, sdpgen);
40446ecee76SDavid du Colombier }
40546ecee76SDavid du Colombier
40646ecee76SDavid du Colombier static Chan*
sdpopen(Chan * ch,int omode)40746ecee76SDavid du Colombier sdpopen(Chan* ch, int omode)
40846ecee76SDavid du Colombier {
40946ecee76SDavid du Colombier int perm;
41046ecee76SDavid du Colombier Sdp *sdp;
41146ecee76SDavid du Colombier Conv *c;
41246ecee76SDavid du Colombier
41346ecee76SDavid du Colombier omode &= 3;
41446ecee76SDavid du Colombier perm = m2p[omode];
41546ecee76SDavid du Colombier USED(perm);
41646ecee76SDavid du Colombier
41746ecee76SDavid du Colombier sdp = sdptab + ch->dev;
41846ecee76SDavid du Colombier
41946ecee76SDavid du Colombier switch(TYPE(ch->qid)) {
42046ecee76SDavid du Colombier default:
42146ecee76SDavid du Colombier break;
42246ecee76SDavid du Colombier case Qtopdir:
42346ecee76SDavid du Colombier case Qsdpdir:
42446ecee76SDavid du Colombier case Qconvdir:
42546ecee76SDavid du Colombier if(omode != OREAD)
42646ecee76SDavid du Colombier error(Eperm);
42746ecee76SDavid du Colombier break;
42846ecee76SDavid du Colombier case Qlog:
42946ecee76SDavid du Colombier logopen(sdp);
43046ecee76SDavid du Colombier break;
43146ecee76SDavid du Colombier case Qclone:
43246ecee76SDavid du Colombier c = sdpclone(sdp);
43346ecee76SDavid du Colombier if(c == nil)
43446ecee76SDavid du Colombier error(Enodev);
43546ecee76SDavid du Colombier ch->qid.path = QID(c->id, Qctl);
43646ecee76SDavid du Colombier break;
43746ecee76SDavid du Colombier case Qdata:
43846ecee76SDavid du Colombier case Qctl:
43946ecee76SDavid du Colombier case Qstatus:
44046ecee76SDavid du Colombier case Qcontrol:
44146ecee76SDavid du Colombier case Qstats:
44246ecee76SDavid du Colombier case Qrstats:
44346ecee76SDavid du Colombier c = sdp->conv[CONV(ch->qid)];
44446ecee76SDavid du Colombier qlock(c);
44546ecee76SDavid du Colombier if(waserror()) {
44646ecee76SDavid du Colombier qunlock(c);
44746ecee76SDavid du Colombier nexterror();
44846ecee76SDavid du Colombier }
44946ecee76SDavid du Colombier if((perm & (c->perm>>6)) != perm)
45046ecee76SDavid du Colombier if(strcmp(up->user, c->owner) != 0 || (perm & c->perm) != perm)
45146ecee76SDavid du Colombier error(Eperm);
45246ecee76SDavid du Colombier
45346ecee76SDavid du Colombier c->ref++;
45446ecee76SDavid du Colombier if(TYPE(ch->qid) == Qdata) {
45546ecee76SDavid du Colombier c->dataopen++;
45646ecee76SDavid du Colombier // kill reader if Qdata is opened for the first time
45746ecee76SDavid du Colombier if(c->dataopen == 1)
45846ecee76SDavid du Colombier if(c->readproc != nil)
45946ecee76SDavid du Colombier postnote(c->readproc, 1, "interrupt", 0);
46046ecee76SDavid du Colombier } else if(TYPE(ch->qid) == Qcontrol) {
46146ecee76SDavid du Colombier c->controlopen++;
46246ecee76SDavid du Colombier }
46346ecee76SDavid du Colombier qunlock(c);
46446ecee76SDavid du Colombier poperror();
46546ecee76SDavid du Colombier break;
46646ecee76SDavid du Colombier }
46746ecee76SDavid du Colombier ch->mode = openmode(omode);
46846ecee76SDavid du Colombier ch->flag |= COPEN;
46946ecee76SDavid du Colombier ch->offset = 0;
47046ecee76SDavid du Colombier return ch;
47146ecee76SDavid du Colombier }
47246ecee76SDavid du Colombier
47346ecee76SDavid du Colombier static void
sdpclose(Chan * ch)47446ecee76SDavid du Colombier sdpclose(Chan* ch)
47546ecee76SDavid du Colombier {
47646ecee76SDavid du Colombier Sdp *sdp = sdptab + ch->dev;
47746ecee76SDavid du Colombier Conv *c;
47846ecee76SDavid du Colombier
47946ecee76SDavid du Colombier if(!(ch->flag & COPEN))
48046ecee76SDavid du Colombier return;
48146ecee76SDavid du Colombier switch(TYPE(ch->qid)) {
48246ecee76SDavid du Colombier case Qlog:
48346ecee76SDavid du Colombier logclose(sdp);
48446ecee76SDavid du Colombier break;
48546ecee76SDavid du Colombier case Qctl:
48646ecee76SDavid du Colombier case Qstatus:
48746ecee76SDavid du Colombier case Qstats:
48846ecee76SDavid du Colombier case Qrstats:
48946ecee76SDavid du Colombier c = sdp->conv[CONV(ch->qid)];
49046ecee76SDavid du Colombier qlock(c);
49146ecee76SDavid du Colombier convderef(c);
49246ecee76SDavid du Colombier qunlock(c);
49346ecee76SDavid du Colombier break;
49446ecee76SDavid du Colombier
49546ecee76SDavid du Colombier case Qdata:
49646ecee76SDavid du Colombier c = sdp->conv[CONV(ch->qid)];
49746ecee76SDavid du Colombier qlock(c);
49846ecee76SDavid du Colombier c->dataopen--;
49946ecee76SDavid du Colombier convderef(c);
50046ecee76SDavid du Colombier if(c->dataopen == 0)
50146ecee76SDavid du Colombier if(c->reader == 0)
50246ecee76SDavid du Colombier if(c->chan != nil)
50346ecee76SDavid du Colombier if(!waserror()) {
50446ecee76SDavid du Colombier kproc("convreader", convreader, c);
50546ecee76SDavid du Colombier c->reader = 1;
50646ecee76SDavid du Colombier c->ref++;
50746ecee76SDavid du Colombier poperror();
50846ecee76SDavid du Colombier }
50946ecee76SDavid du Colombier qunlock(c);
51046ecee76SDavid du Colombier break;
51146ecee76SDavid du Colombier
51246ecee76SDavid du Colombier case Qcontrol:
51346ecee76SDavid du Colombier c = sdp->conv[CONV(ch->qid)];
51446ecee76SDavid du Colombier qlock(c);
51546ecee76SDavid du Colombier c->controlopen--;
51646ecee76SDavid du Colombier convderef(c);
51746ecee76SDavid du Colombier if(c->controlopen == 0 && c->ref != 0) {
51846ecee76SDavid du Colombier switch(c->state) {
51946ecee76SDavid du Colombier default:
52046ecee76SDavid du Colombier convsetstate(c, CClosed);
52146ecee76SDavid du Colombier break;
52246ecee76SDavid du Colombier case CAccept:
52346ecee76SDavid du Colombier case COpen:
52446ecee76SDavid du Colombier convsetstate(c, CLocalClose);
52546ecee76SDavid du Colombier break;
52646ecee76SDavid du Colombier }
52746ecee76SDavid du Colombier }
52846ecee76SDavid du Colombier qunlock(c);
52946ecee76SDavid du Colombier break;
53046ecee76SDavid du Colombier }
53146ecee76SDavid du Colombier }
53246ecee76SDavid du Colombier
53346ecee76SDavid du Colombier static long
sdpread(Chan * ch,void * a,long n,vlong off)53446ecee76SDavid du Colombier sdpread(Chan *ch, void *a, long n, vlong off)
53546ecee76SDavid du Colombier {
53646ecee76SDavid du Colombier char buf[256];
53746ecee76SDavid du Colombier char *s;
53846ecee76SDavid du Colombier Sdp *sdp = sdptab + ch->dev;
53946ecee76SDavid du Colombier Conv *c;
54046ecee76SDavid du Colombier Block *b;
54146ecee76SDavid du Colombier int rv;
54246ecee76SDavid du Colombier
54346ecee76SDavid du Colombier USED(off);
54446ecee76SDavid du Colombier switch(TYPE(ch->qid)) {
54546ecee76SDavid du Colombier default:
54646ecee76SDavid du Colombier error(Eperm);
54746ecee76SDavid du Colombier case Qtopdir:
54846ecee76SDavid du Colombier case Qsdpdir:
54946ecee76SDavid du Colombier case Qconvdir:
55046ecee76SDavid du Colombier return devdirread(ch, a, n, 0, 0, sdpgen);
55146ecee76SDavid du Colombier case Qlog:
55246ecee76SDavid du Colombier return logread(sdp, a, off, n);
55346ecee76SDavid du Colombier case Qstatus:
55446ecee76SDavid du Colombier c = sdp->conv[CONV(ch->qid)];
55546ecee76SDavid du Colombier qlock(c);
55646ecee76SDavid du Colombier n = readstr(off, a, n, convstatename[c->state]);
55746ecee76SDavid du Colombier qunlock(c);
55846ecee76SDavid du Colombier return n;
55946ecee76SDavid du Colombier case Qctl:
560*4e3613abSDavid du Colombier snprint(buf, sizeof buf, "%lud", CONV(ch->qid));
56146ecee76SDavid du Colombier return readstr(off, a, n, buf);
56246ecee76SDavid du Colombier case Qcontrol:
56346ecee76SDavid du Colombier b = readcontrol(sdp->conv[CONV(ch->qid)], n);
56446ecee76SDavid du Colombier if(b == nil)
56546ecee76SDavid du Colombier return 0;
56646ecee76SDavid du Colombier if(BLEN(b) < n)
56746ecee76SDavid du Colombier n = BLEN(b);
56846ecee76SDavid du Colombier memmove(a, b->rp, n);
56946ecee76SDavid du Colombier freeb(b);
57046ecee76SDavid du Colombier return n;
57146ecee76SDavid du Colombier case Qdata:
57246ecee76SDavid du Colombier b = readdata(sdp->conv[CONV(ch->qid)], n);
57346ecee76SDavid du Colombier if(b == nil)
57446ecee76SDavid du Colombier return 0;
57546ecee76SDavid du Colombier if(BLEN(b) < n)
57646ecee76SDavid du Colombier n = BLEN(b);
57746ecee76SDavid du Colombier memmove(a, b->rp, n);
57846ecee76SDavid du Colombier freeb(b);
57946ecee76SDavid du Colombier return n;
58046ecee76SDavid du Colombier case Qstats:
58146ecee76SDavid du Colombier case Qrstats:
58246ecee76SDavid du Colombier c = sdp->conv[CONV(ch->qid)];
58346ecee76SDavid du Colombier s = smalloc(1000);
58446ecee76SDavid du Colombier convstats(c, TYPE(ch->qid) == Qstats, s, 1000);
58546ecee76SDavid du Colombier rv = readstr(off, a, n, s);
58646ecee76SDavid du Colombier free(s);
58746ecee76SDavid du Colombier return rv;
58846ecee76SDavid du Colombier }
58946ecee76SDavid du Colombier }
59046ecee76SDavid du Colombier
59146ecee76SDavid du Colombier static Block*
sdpbread(Chan * ch,long n,ulong offset)59246ecee76SDavid du Colombier sdpbread(Chan* ch, long n, ulong offset)
59346ecee76SDavid du Colombier {
59446ecee76SDavid du Colombier Sdp *sdp = sdptab + ch->dev;
59546ecee76SDavid du Colombier
59646ecee76SDavid du Colombier if(TYPE(ch->qid) != Qdata)
59746ecee76SDavid du Colombier return devbread(ch, n, offset);
59846ecee76SDavid du Colombier return readdata(sdp->conv[CONV(ch->qid)], n);
59946ecee76SDavid du Colombier }
60046ecee76SDavid du Colombier
60146ecee76SDavid du Colombier
60246ecee76SDavid du Colombier static long
sdpwrite(Chan * ch,void * a,long n,vlong off)60346ecee76SDavid du Colombier sdpwrite(Chan *ch, void *a, long n, vlong off)
60446ecee76SDavid du Colombier {
60546ecee76SDavid du Colombier Sdp *sdp = sdptab + ch->dev;
60646ecee76SDavid du Colombier Cmdbuf *cb;
60746ecee76SDavid du Colombier char *arg0;
60846ecee76SDavid du Colombier char *p;
60946ecee76SDavid du Colombier Conv *c;
61046ecee76SDavid du Colombier Block *b;
61146ecee76SDavid du Colombier
61246ecee76SDavid du Colombier USED(off);
61346ecee76SDavid du Colombier switch(TYPE(ch->qid)) {
61446ecee76SDavid du Colombier default:
61546ecee76SDavid du Colombier error(Eperm);
61646ecee76SDavid du Colombier case Qctl:
61746ecee76SDavid du Colombier c = sdp->conv[CONV(ch->qid)];
61846ecee76SDavid du Colombier cb = parsecmd(a, n);
61946ecee76SDavid du Colombier qlock(c);
62046ecee76SDavid du Colombier if(waserror()) {
62146ecee76SDavid du Colombier qunlock(c);
62246ecee76SDavid du Colombier free(cb);
62346ecee76SDavid du Colombier nexterror();
62446ecee76SDavid du Colombier }
62546ecee76SDavid du Colombier if(cb->nf == 0)
62646ecee76SDavid du Colombier error("short write");
62746ecee76SDavid du Colombier arg0 = cb->f[0];
62846ecee76SDavid du Colombier if(strcmp(arg0, "accept") == 0) {
62946ecee76SDavid du Colombier if(cb->nf != 2)
630567483c8SDavid du Colombier error("usage: accept file");
63146ecee76SDavid du Colombier convopenchan(c, cb->f[1]);
63246ecee76SDavid du Colombier } else if(strcmp(arg0, "dial") == 0) {
63346ecee76SDavid du Colombier if(cb->nf != 2)
634567483c8SDavid du Colombier error("usage: dial file");
63546ecee76SDavid du Colombier convopenchan(c, cb->f[1]);
63646ecee76SDavid du Colombier convsetstate(c, CDial);
63746ecee76SDavid du Colombier } else if(strcmp(arg0, "drop") == 0) {
63846ecee76SDavid du Colombier if(cb->nf != 2)
63946ecee76SDavid du Colombier error("usage: drop permil");
64046ecee76SDavid du Colombier c->drop = atoi(cb->f[1]);
64146ecee76SDavid du Colombier } else if(strcmp(arg0, "cipher") == 0) {
64246ecee76SDavid du Colombier if(cb->nf != 2)
64346ecee76SDavid du Colombier error("usage: cipher alg");
64446ecee76SDavid du Colombier setalg(c, cb->f[1], cipheralg, &c->cipher);
64546ecee76SDavid du Colombier } else if(strcmp(arg0, "auth") == 0) {
64646ecee76SDavid du Colombier if(cb->nf != 2)
64746ecee76SDavid du Colombier error("usage: auth alg");
64846ecee76SDavid du Colombier setalg(c, cb->f[1], authalg, &c->auth);
64946ecee76SDavid du Colombier } else if(strcmp(arg0, "comp") == 0) {
65046ecee76SDavid du Colombier if(cb->nf != 2)
65146ecee76SDavid du Colombier error("usage: comp alg");
65246ecee76SDavid du Colombier setalg(c, cb->f[1], compalg, &c->comp);
65346ecee76SDavid du Colombier } else if(strcmp(arg0, "insecret") == 0) {
65446ecee76SDavid du Colombier if(cb->nf != 2)
65546ecee76SDavid du Colombier error("usage: insecret secret");
65646ecee76SDavid du Colombier setsecret(&c->in, cb->f[1]);
65746ecee76SDavid du Colombier if(c->cipher)
65846ecee76SDavid du Colombier c->cipher->init(c);
65946ecee76SDavid du Colombier if(c->auth)
66046ecee76SDavid du Colombier c->auth->init(c);
66146ecee76SDavid du Colombier } else if(strcmp(arg0, "outsecret") == 0) {
66246ecee76SDavid du Colombier if(cb->nf != 2)
66346ecee76SDavid du Colombier error("usage: outsecret secret");
66446ecee76SDavid du Colombier setsecret(&c->out, cb->f[1]);
66546ecee76SDavid du Colombier if(c->cipher)
66646ecee76SDavid du Colombier c->cipher->init(c);
66746ecee76SDavid du Colombier if(c->auth)
66846ecee76SDavid du Colombier c->auth->init(c);
66946ecee76SDavid du Colombier } else
67046ecee76SDavid du Colombier error("unknown control request");
67146ecee76SDavid du Colombier poperror();
67246ecee76SDavid du Colombier qunlock(c);
67346ecee76SDavid du Colombier free(cb);
67446ecee76SDavid du Colombier return n;
67546ecee76SDavid du Colombier case Qlog:
67646ecee76SDavid du Colombier cb = parsecmd(a, n);
67746ecee76SDavid du Colombier p = logctl(sdp, cb->nf, cb->f, logflags);
67846ecee76SDavid du Colombier free(cb);
67946ecee76SDavid du Colombier if(p != nil)
68046ecee76SDavid du Colombier error(p);
68146ecee76SDavid du Colombier return n;
68246ecee76SDavid du Colombier case Qcontrol:
68346ecee76SDavid du Colombier writecontrol(sdp->conv[CONV(ch->qid)], a, n, 0);
68446ecee76SDavid du Colombier return n;
68546ecee76SDavid du Colombier case Qdata:
68646ecee76SDavid du Colombier b = allocb(n);
68746ecee76SDavid du Colombier memmove(b->wp, a, n);
68846ecee76SDavid du Colombier b->wp += n;
68946ecee76SDavid du Colombier return writedata(sdp->conv[CONV(ch->qid)], b);
69046ecee76SDavid du Colombier }
69146ecee76SDavid du Colombier }
69246ecee76SDavid du Colombier
69346ecee76SDavid du Colombier long
sdpbwrite(Chan * ch,Block * bp,ulong offset)69446ecee76SDavid du Colombier sdpbwrite(Chan *ch, Block *bp, ulong offset)
69546ecee76SDavid du Colombier {
69646ecee76SDavid du Colombier Sdp *sdp = sdptab + ch->dev;
69746ecee76SDavid du Colombier
69846ecee76SDavid du Colombier if(TYPE(ch->qid) != Qdata)
69946ecee76SDavid du Colombier return devbwrite(ch, bp, offset);
70046ecee76SDavid du Colombier return writedata(sdp->conv[CONV(ch->qid)], bp);
70146ecee76SDavid du Colombier }
70246ecee76SDavid du Colombier
70346ecee76SDavid du Colombier static int
sdpgen(Chan * c,char *,Dirtab *,int,int s,Dir * dp)70446ecee76SDavid du Colombier sdpgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp)
70546ecee76SDavid du Colombier {
70646ecee76SDavid du Colombier Sdp *sdp = sdptab + c->dev;
70746ecee76SDavid du Colombier int type = TYPE(c->qid);
70846ecee76SDavid du Colombier Dirtab *dt;
70946ecee76SDavid du Colombier Qid qid;
71046ecee76SDavid du Colombier
71146ecee76SDavid du Colombier if(s == DEVDOTDOT){
71246ecee76SDavid du Colombier switch(TYPE(c->qid)){
71346ecee76SDavid du Colombier case Qtopdir:
71446ecee76SDavid du Colombier case Qsdpdir:
71546ecee76SDavid du Colombier snprint(up->genbuf, sizeof(up->genbuf), "#E%ld", c->dev);
71646ecee76SDavid du Colombier mkqid(&qid, Qtopdir, 0, QTDIR);
71746ecee76SDavid du Colombier devdir(c, qid, up->genbuf, 0, eve, 0555, dp);
71846ecee76SDavid du Colombier break;
71946ecee76SDavid du Colombier case Qconvdir:
72046ecee76SDavid du Colombier snprint(up->genbuf, sizeof(up->genbuf), "%d", s);
72146ecee76SDavid du Colombier mkqid(&qid, Qsdpdir, 0, QTDIR);
72246ecee76SDavid du Colombier devdir(c, qid, up->genbuf, 0, eve, 0555, dp);
72346ecee76SDavid du Colombier break;
72446ecee76SDavid du Colombier default:
72546ecee76SDavid du Colombier panic("sdpwalk %llux", c->qid.path);
72646ecee76SDavid du Colombier }
72746ecee76SDavid du Colombier return 1;
72846ecee76SDavid du Colombier }
72946ecee76SDavid du Colombier
73046ecee76SDavid du Colombier switch(type) {
73146ecee76SDavid du Colombier default:
73246ecee76SDavid du Colombier // non directory entries end up here
73346ecee76SDavid du Colombier if(c->qid.type & QTDIR)
73446ecee76SDavid du Colombier panic("sdpgen: unexpected directory");
73546ecee76SDavid du Colombier if(s != 0)
73646ecee76SDavid du Colombier return -1;
73746ecee76SDavid du Colombier dt = dirtab[TYPE(c->qid)];
73846ecee76SDavid du Colombier if(dt == nil)
73946ecee76SDavid du Colombier panic("sdpgen: unknown type: %lud", TYPE(c->qid));
74046ecee76SDavid du Colombier devdir(c, c->qid, dt->name, dt->length, eve, dt->perm, dp);
74146ecee76SDavid du Colombier return 1;
74246ecee76SDavid du Colombier case Qtopdir:
74346ecee76SDavid du Colombier if(s != 0)
74446ecee76SDavid du Colombier return -1;
74546ecee76SDavid du Colombier mkqid(&qid, QID(0, Qsdpdir), 0, QTDIR);
74646ecee76SDavid du Colombier devdir(c, qid, "sdp", 0, eve, 0555, dp);
74746ecee76SDavid du Colombier return 1;
74846ecee76SDavid du Colombier case Qsdpdir:
74946ecee76SDavid du Colombier if(s<nelem(sdpdirtab)) {
75046ecee76SDavid du Colombier dt = sdpdirtab+s;
75146ecee76SDavid du Colombier devdir(c, dt->qid, dt->name, dt->length, eve, dt->perm, dp);
75246ecee76SDavid du Colombier return 1;
75346ecee76SDavid du Colombier }
75446ecee76SDavid du Colombier s -= nelem(sdpdirtab);
75546ecee76SDavid du Colombier if(s >= sdp->nconv)
75646ecee76SDavid du Colombier return -1;
75746ecee76SDavid du Colombier mkqid(&qid, QID(s, Qconvdir), 0, QTDIR);
75846ecee76SDavid du Colombier snprint(up->genbuf, sizeof(up->genbuf), "%d", s);
75946ecee76SDavid du Colombier devdir(c, qid, up->genbuf, 0, eve, 0555, dp);
76046ecee76SDavid du Colombier return 1;
76146ecee76SDavid du Colombier case Qconvdir:
76246ecee76SDavid du Colombier if(s>=nelem(convdirtab))
76346ecee76SDavid du Colombier return -1;
76446ecee76SDavid du Colombier dt = convdirtab+s;
76546ecee76SDavid du Colombier mkqid(&qid, QID(CONV(c->qid),TYPE(dt->qid)), 0, QTFILE);
76646ecee76SDavid du Colombier devdir(c, qid, dt->name, dt->length, eve, dt->perm, dp);
76746ecee76SDavid du Colombier return 1;
76846ecee76SDavid du Colombier }
76946ecee76SDavid du Colombier }
77046ecee76SDavid du Colombier
77146ecee76SDavid du Colombier static Conv*
sdpclone(Sdp * sdp)77246ecee76SDavid du Colombier sdpclone(Sdp *sdp)
77346ecee76SDavid du Colombier {
77446ecee76SDavid du Colombier Conv *c, **pp, **ep;
77546ecee76SDavid du Colombier
77646ecee76SDavid du Colombier c = nil;
77746ecee76SDavid du Colombier ep = sdp->conv + nelem(sdp->conv);
77846ecee76SDavid du Colombier qlock(sdp);
77946ecee76SDavid du Colombier if(waserror()) {
78046ecee76SDavid du Colombier qunlock(sdp);
78146ecee76SDavid du Colombier nexterror();
78246ecee76SDavid du Colombier }
78346ecee76SDavid du Colombier for(pp = sdp->conv; pp < ep; pp++) {
78446ecee76SDavid du Colombier c = *pp;
78546ecee76SDavid du Colombier if(c == nil){
78646ecee76SDavid du Colombier c = malloc(sizeof(Conv));
78746ecee76SDavid du Colombier if(c == nil)
78846ecee76SDavid du Colombier error(Enomem);
78946ecee76SDavid du Colombier memset(c, 0, sizeof(Conv));
79046ecee76SDavid du Colombier qlock(c);
79146ecee76SDavid du Colombier c->sdp = sdp;
79246ecee76SDavid du Colombier c->id = pp - sdp->conv;
79346ecee76SDavid du Colombier *pp = c;
79446ecee76SDavid du Colombier sdp->nconv++;
79546ecee76SDavid du Colombier break;
79646ecee76SDavid du Colombier }
79746ecee76SDavid du Colombier if(c->ref == 0 && canqlock(c)){
79846ecee76SDavid du Colombier if(c->ref == 0)
79946ecee76SDavid du Colombier break;
80046ecee76SDavid du Colombier qunlock(c);
80146ecee76SDavid du Colombier }
80246ecee76SDavid du Colombier }
80346ecee76SDavid du Colombier poperror();
80446ecee76SDavid du Colombier qunlock(sdp);
80546ecee76SDavid du Colombier
80646ecee76SDavid du Colombier if(pp >= ep)
80746ecee76SDavid du Colombier return nil;
80846ecee76SDavid du Colombier
80946ecee76SDavid du Colombier assert(c->state == CFree);
81046ecee76SDavid du Colombier // set ref to 2 - 1 ref for open - 1 ref for channel state
81146ecee76SDavid du Colombier c->ref = 2;
81246ecee76SDavid du Colombier c->state = CInit;
81346ecee76SDavid du Colombier c->in.window = ~0;
81446ecee76SDavid du Colombier strncpy(c->owner, up->user, sizeof(c->owner));
81546ecee76SDavid du Colombier c->perm = 0660;
81646ecee76SDavid du Colombier qunlock(c);
81746ecee76SDavid du Colombier
81846ecee76SDavid du Colombier return c;
81946ecee76SDavid du Colombier }
82046ecee76SDavid du Colombier
82146ecee76SDavid du Colombier // assume c is locked
82246ecee76SDavid du Colombier static void
convretryinit(Conv * c)82346ecee76SDavid du Colombier convretryinit(Conv *c)
82446ecee76SDavid du Colombier {
82546ecee76SDavid du Colombier c->retries = 0;
82646ecee76SDavid du Colombier // +2 to avoid rounding effects.
82746ecee76SDavid du Colombier c->timeout = TK2SEC(m->ticks) + 2;
82846ecee76SDavid du Colombier }
82946ecee76SDavid du Colombier
83046ecee76SDavid du Colombier // assume c is locked
83146ecee76SDavid du Colombier static int
convretry(Conv * c,int reset)83246ecee76SDavid du Colombier convretry(Conv *c, int reset)
83346ecee76SDavid du Colombier {
83446ecee76SDavid du Colombier c->retries++;
83546ecee76SDavid du Colombier if(c->retries > MaxRetries) {
83646ecee76SDavid du Colombier if(reset)
83746ecee76SDavid du Colombier convoconnect(c, ConReset, c->dialid, c->acceptid);
83846ecee76SDavid du Colombier convsetstate(c, CClosed);
83946ecee76SDavid du Colombier return 0;
84046ecee76SDavid du Colombier }
84146ecee76SDavid du Colombier c->timeout = TK2SEC(m->ticks) + (c->retries+1);
84246ecee76SDavid du Colombier return 1;
84346ecee76SDavid du Colombier }
84446ecee76SDavid du Colombier
84546ecee76SDavid du Colombier // assumes c is locked
84646ecee76SDavid du Colombier static void
convtimer(Conv * c,ulong sec)84746ecee76SDavid du Colombier convtimer(Conv *c, ulong sec)
84846ecee76SDavid du Colombier {
84946ecee76SDavid du Colombier Block *b;
85046ecee76SDavid du Colombier
85146ecee76SDavid du Colombier if(c->timeout > sec)
85246ecee76SDavid du Colombier return;
85346ecee76SDavid du Colombier
85446ecee76SDavid du Colombier switch(c->state) {
85546ecee76SDavid du Colombier case CInit:
85646ecee76SDavid du Colombier break;
85746ecee76SDavid du Colombier case CDial:
85846ecee76SDavid du Colombier if(convretry(c, 1))
85946ecee76SDavid du Colombier convoconnect(c, ConOpenRequest, c->dialid, 0);
86046ecee76SDavid du Colombier break;
86146ecee76SDavid du Colombier case CAccept:
86246ecee76SDavid du Colombier if(convretry(c, 1))
86346ecee76SDavid du Colombier convoconnect(c, ConOpenAck, c->dialid, c->acceptid);
86446ecee76SDavid du Colombier break;
86546ecee76SDavid du Colombier case COpen:
86646ecee76SDavid du Colombier b = c->out.controlpkt;
86746ecee76SDavid du Colombier if(b != nil) {
86846ecee76SDavid du Colombier if(convretry(c, 1))
86946ecee76SDavid du Colombier convoput(c, TControl, ControlMesg, copyblock(b, blocklen(b)));
87046ecee76SDavid du Colombier break;
87146ecee76SDavid du Colombier }
87246ecee76SDavid du Colombier
87346ecee76SDavid du Colombier c->timeout = c->lastrecv + KeepAlive;
87446ecee76SDavid du Colombier if(c->timeout > sec)
87546ecee76SDavid du Colombier break;
87646ecee76SDavid du Colombier // keepalive - randomly spaced between KeepAlive and 2*KeepAlive
87746ecee76SDavid du Colombier if(c->timeout + KeepAlive > sec && nrand(c->lastrecv + 2*KeepAlive - sec) > 0)
87846ecee76SDavid du Colombier break;
87946ecee76SDavid du Colombier // can not use writecontrol
88046ecee76SDavid du Colombier b = allocb(4);
88146ecee76SDavid du Colombier c->out.controlseq++;
88246ecee76SDavid du Colombier hnputl(b->wp, c->out.controlseq);
88346ecee76SDavid du Colombier b->wp += 4;
88446ecee76SDavid du Colombier c->out.controlpkt = b;
88546ecee76SDavid du Colombier convretryinit(c);
88646ecee76SDavid du Colombier if(!waserror()) {
88746ecee76SDavid du Colombier convoput(c, TControl, ControlMesg, copyblock(b, blocklen(b)));
88846ecee76SDavid du Colombier poperror();
88946ecee76SDavid du Colombier }
89046ecee76SDavid du Colombier break;
89146ecee76SDavid du Colombier case CLocalClose:
89246ecee76SDavid du Colombier if(convretry(c, 0))
89346ecee76SDavid du Colombier convoconnect(c, ConClose, c->dialid, c->acceptid);
89446ecee76SDavid du Colombier break;
89546ecee76SDavid du Colombier case CRemoteClose:
89646ecee76SDavid du Colombier case CClosed:
89746ecee76SDavid du Colombier break;
89846ecee76SDavid du Colombier }
89946ecee76SDavid du Colombier }
90046ecee76SDavid du Colombier
90146ecee76SDavid du Colombier
90246ecee76SDavid du Colombier static void
sdpackproc(void * a)90346ecee76SDavid du Colombier sdpackproc(void *a)
90446ecee76SDavid du Colombier {
90546ecee76SDavid du Colombier Sdp *sdp = a;
90646ecee76SDavid du Colombier ulong sec;
90746ecee76SDavid du Colombier int i;
90846ecee76SDavid du Colombier Conv *c;
90946ecee76SDavid du Colombier
91046ecee76SDavid du Colombier for(;;) {
91146ecee76SDavid du Colombier tsleep(&up->sleep, return0, 0, 1000);
91246ecee76SDavid du Colombier sec = TK2SEC(m->ticks);
91346ecee76SDavid du Colombier qlock(sdp);
91446ecee76SDavid du Colombier for(i=0; i<sdp->nconv; i++) {
91546ecee76SDavid du Colombier c = sdp->conv[i];
91646ecee76SDavid du Colombier if(c->ref == 0)
91746ecee76SDavid du Colombier continue;
91846ecee76SDavid du Colombier qunlock(sdp);
91946ecee76SDavid du Colombier qlock(c);
92046ecee76SDavid du Colombier if(c->ref > 0 && !waserror()) {
92146ecee76SDavid du Colombier convtimer(c, sec);
92246ecee76SDavid du Colombier poperror();
92346ecee76SDavid du Colombier }
92446ecee76SDavid du Colombier qunlock(c);
92546ecee76SDavid du Colombier qlock(sdp);
92646ecee76SDavid du Colombier }
92746ecee76SDavid du Colombier qunlock(sdp);
92846ecee76SDavid du Colombier }
92946ecee76SDavid du Colombier }
93046ecee76SDavid du Colombier
93146ecee76SDavid du Colombier Dev sdpdevtab = {
93246ecee76SDavid du Colombier 'E',
93346ecee76SDavid du Colombier "sdp",
93446ecee76SDavid du Colombier
93546ecee76SDavid du Colombier devreset,
93646ecee76SDavid du Colombier sdpinit,
93746ecee76SDavid du Colombier devshutdown,
93846ecee76SDavid du Colombier sdpattach,
93946ecee76SDavid du Colombier sdpwalk,
94046ecee76SDavid du Colombier sdpstat,
94146ecee76SDavid du Colombier sdpopen,
94246ecee76SDavid du Colombier devcreate,
94346ecee76SDavid du Colombier sdpclose,
94446ecee76SDavid du Colombier sdpread,
94546ecee76SDavid du Colombier devbread,
94646ecee76SDavid du Colombier sdpwrite,
94746ecee76SDavid du Colombier devbwrite,
94846ecee76SDavid du Colombier devremove,
94946ecee76SDavid du Colombier devwstat,
95046ecee76SDavid du Colombier };
95146ecee76SDavid du Colombier
95246ecee76SDavid du Colombier // assume hold lock on c
95346ecee76SDavid du Colombier static void
convsetstate(Conv * c,int state)95446ecee76SDavid du Colombier convsetstate(Conv *c, int state)
95546ecee76SDavid du Colombier {
95646ecee76SDavid du Colombier
95746ecee76SDavid du Colombier if(0)print("convsetstate %d: %s -> %s\n", c->id, convstatename[c->state], convstatename[state]);
95846ecee76SDavid du Colombier
95946ecee76SDavid du Colombier switch(state) {
96046ecee76SDavid du Colombier default:
96146ecee76SDavid du Colombier panic("setstate: bad state: %d", state);
96246ecee76SDavid du Colombier case CDial:
96346ecee76SDavid du Colombier assert(c->state == CInit);
96446ecee76SDavid du Colombier c->dialid = (rand()<<16) + rand();
96546ecee76SDavid du Colombier convretryinit(c);
96646ecee76SDavid du Colombier convoconnect(c, ConOpenRequest, c->dialid, 0);
96746ecee76SDavid du Colombier break;
96846ecee76SDavid du Colombier case CAccept:
96946ecee76SDavid du Colombier assert(c->state == CInit);
97046ecee76SDavid du Colombier c->acceptid = (rand()<<16) + rand();
97146ecee76SDavid du Colombier convretryinit(c);
97246ecee76SDavid du Colombier convoconnect(c, ConOpenAck, c->dialid, c->acceptid);
97346ecee76SDavid du Colombier break;
97446ecee76SDavid du Colombier case COpen:
97546ecee76SDavid du Colombier assert(c->state == CDial || c->state == CAccept);
97646ecee76SDavid du Colombier c->lastrecv = TK2SEC(m->ticks);
97746ecee76SDavid du Colombier if(c->state == CDial) {
97846ecee76SDavid du Colombier convretryinit(c);
97946ecee76SDavid du Colombier convoconnect(c, ConOpenAckAck, c->dialid, c->acceptid);
98046ecee76SDavid du Colombier hnputl(c->in.secret, c->acceptid);
98146ecee76SDavid du Colombier hnputl(c->in.secret+4, c->dialid);
98246ecee76SDavid du Colombier hnputl(c->out.secret, c->dialid);
98346ecee76SDavid du Colombier hnputl(c->out.secret+4, c->acceptid);
98446ecee76SDavid du Colombier } else {
98546ecee76SDavid du Colombier hnputl(c->in.secret, c->dialid);
98646ecee76SDavid du Colombier hnputl(c->in.secret+4, c->acceptid);
98746ecee76SDavid du Colombier hnputl(c->out.secret, c->acceptid);
98846ecee76SDavid du Colombier hnputl(c->out.secret+4, c->dialid);
98946ecee76SDavid du Colombier }
99046ecee76SDavid du Colombier setalg(c, "hmac_md5_96", authalg, &c->auth);
99146ecee76SDavid du Colombier break;
99246ecee76SDavid du Colombier case CLocalClose:
99346ecee76SDavid du Colombier assert(c->state == CAccept || c->state == COpen);
99446ecee76SDavid du Colombier convretryinit(c);
99546ecee76SDavid du Colombier convoconnect(c, ConClose, c->dialid, c->acceptid);
99646ecee76SDavid du Colombier break;
99746ecee76SDavid du Colombier case CRemoteClose:
99846ecee76SDavid du Colombier wakeup(&c->in.controlready);
99946ecee76SDavid du Colombier wakeup(&c->out.controlready);
100046ecee76SDavid du Colombier break;
100146ecee76SDavid du Colombier case CClosed:
100246ecee76SDavid du Colombier wakeup(&c->in.controlready);
100346ecee76SDavid du Colombier wakeup(&c->out.controlready);
100446ecee76SDavid du Colombier if(c->readproc)
100546ecee76SDavid du Colombier postnote(c->readproc, 1, "interrupt", 0);
100646ecee76SDavid du Colombier if(c->state != CClosed)
100746ecee76SDavid du Colombier convderef(c);
100846ecee76SDavid du Colombier break;
100946ecee76SDavid du Colombier }
101046ecee76SDavid du Colombier c->state = state;
101146ecee76SDavid du Colombier }
101246ecee76SDavid du Colombier
101346ecee76SDavid du Colombier
101446ecee76SDavid du Colombier //assumes c is locked
101546ecee76SDavid du Colombier static void
convderef(Conv * c)101646ecee76SDavid du Colombier convderef(Conv *c)
101746ecee76SDavid du Colombier {
101846ecee76SDavid du Colombier c->ref--;
101946ecee76SDavid du Colombier if(c->ref > 0) {
102046ecee76SDavid du Colombier return;
102146ecee76SDavid du Colombier }
102246ecee76SDavid du Colombier assert(c->ref == 0);
102346ecee76SDavid du Colombier assert(c->dataopen == 0);
102446ecee76SDavid du Colombier assert(c->controlopen == 0);
102546ecee76SDavid du Colombier if(0)print("convderef: %d: ref == 0!\n", c->id);
102646ecee76SDavid du Colombier c->state = CFree;
102746ecee76SDavid du Colombier if(c->chan) {
102846ecee76SDavid du Colombier cclose(c->chan);
102946ecee76SDavid du Colombier c->chan = nil;
103046ecee76SDavid du Colombier }
103146ecee76SDavid du Colombier if(c->channame) {
103246ecee76SDavid du Colombier free(c->channame);
103346ecee76SDavid du Colombier c->channame = nil;
103446ecee76SDavid du Colombier }
103546ecee76SDavid du Colombier c->cipher = nil;
103646ecee76SDavid du Colombier c->auth = nil;
103746ecee76SDavid du Colombier c->comp = nil;
103846ecee76SDavid du Colombier strcpy(c->owner, "network");
103946ecee76SDavid du Colombier c->perm = 0660;
104046ecee76SDavid du Colombier c->dialid = 0;
104146ecee76SDavid du Colombier c->acceptid = 0;
104246ecee76SDavid du Colombier c->timeout = 0;
104346ecee76SDavid du Colombier c->retries = 0;
104446ecee76SDavid du Colombier c->drop = 0;
104546ecee76SDavid du Colombier onewaycleanup(&c->in);
104646ecee76SDavid du Colombier onewaycleanup(&c->out);
104746ecee76SDavid du Colombier memset(&c->lstats, 0, sizeof(Stats));
104846ecee76SDavid du Colombier memset(&c->rstats, 0, sizeof(Stats));
104946ecee76SDavid du Colombier }
105046ecee76SDavid du Colombier
105146ecee76SDavid du Colombier static void
onewaycleanup(OneWay * ow)105246ecee76SDavid du Colombier onewaycleanup(OneWay *ow)
105346ecee76SDavid du Colombier {
105446ecee76SDavid du Colombier if(ow->controlpkt)
105546ecee76SDavid du Colombier freeb(ow->controlpkt);
105646ecee76SDavid du Colombier if(ow->authstate)
105746ecee76SDavid du Colombier free(ow->authstate);
105846ecee76SDavid du Colombier if(ow->cipherstate)
105946ecee76SDavid du Colombier free(ow->cipherstate);
106046ecee76SDavid du Colombier if(ow->compstate)
106146ecee76SDavid du Colombier free(ow->compstate);
106246ecee76SDavid du Colombier memset(ow, 0, sizeof(OneWay));
106346ecee76SDavid du Colombier }
106446ecee76SDavid du Colombier
106546ecee76SDavid du Colombier
106646ecee76SDavid du Colombier // assumes conv is locked
106746ecee76SDavid du Colombier static void
convopenchan(Conv * c,char * path)106846ecee76SDavid du Colombier convopenchan(Conv *c, char *path)
106946ecee76SDavid du Colombier {
107046ecee76SDavid du Colombier if(c->state != CInit || c->chan != nil)
107146ecee76SDavid du Colombier error("already connected");
107246ecee76SDavid du Colombier c->chan = namec(path, Aopen, ORDWR, 0);
107346ecee76SDavid du Colombier c->channame = smalloc(strlen(path)+1);
107446ecee76SDavid du Colombier strcpy(c->channame, path);
107546ecee76SDavid du Colombier if(waserror()) {
107646ecee76SDavid du Colombier cclose(c->chan);
107746ecee76SDavid du Colombier c->chan = nil;
107846ecee76SDavid du Colombier free(c->channame);
107946ecee76SDavid du Colombier c->channame = nil;
108046ecee76SDavid du Colombier nexterror();
108146ecee76SDavid du Colombier }
108246ecee76SDavid du Colombier kproc("convreader", convreader, c);
108346ecee76SDavid du Colombier
108446ecee76SDavid du Colombier assert(c->reader == 0 && c->ref > 0);
108546ecee76SDavid du Colombier // after kproc in case it fails
108646ecee76SDavid du Colombier c->reader = 1;
108746ecee76SDavid du Colombier c->ref++;
108846ecee76SDavid du Colombier
108946ecee76SDavid du Colombier poperror();
109046ecee76SDavid du Colombier }
109146ecee76SDavid du Colombier
109246ecee76SDavid du Colombier static void
convstats(Conv * c,int local,char * buf,int n)109346ecee76SDavid du Colombier convstats(Conv *c, int local, char *buf, int n)
109446ecee76SDavid du Colombier {
109546ecee76SDavid du Colombier Stats *stats;
109646ecee76SDavid du Colombier char *p, *ep;
109746ecee76SDavid du Colombier int i;
109846ecee76SDavid du Colombier
109946ecee76SDavid du Colombier if(local) {
110046ecee76SDavid du Colombier stats = &c->lstats;
110146ecee76SDavid du Colombier } else {
110246ecee76SDavid du Colombier if(!waserror()) {
110346ecee76SDavid du Colombier writecontrol(c, 0, 0, 1);
110446ecee76SDavid du Colombier poperror();
110546ecee76SDavid du Colombier }
110646ecee76SDavid du Colombier stats = &c->rstats;
110746ecee76SDavid du Colombier }
110846ecee76SDavid du Colombier
110946ecee76SDavid du Colombier qlock(c);
111046ecee76SDavid du Colombier p = buf;
111146ecee76SDavid du Colombier ep = buf + n;
111246ecee76SDavid du Colombier p += snprint(p, ep-p, "outPackets: %lud\n", stats->outPackets);
111346ecee76SDavid du Colombier p += snprint(p, ep-p, "outDataPackets: %lud\n", stats->outDataPackets);
111446ecee76SDavid du Colombier p += snprint(p, ep-p, "outDataBytes: %lud\n", stats->outDataBytes);
111546ecee76SDavid du Colombier p += snprint(p, ep-p, "outCompDataBytes: %lud\n", stats->outCompDataBytes);
111646ecee76SDavid du Colombier for(i=0; i<NCompStats; i++) {
111746ecee76SDavid du Colombier if(stats->outCompStats[i] == 0)
111846ecee76SDavid du Colombier continue;
111946ecee76SDavid du Colombier p += snprint(p, ep-p, "outCompStats[%d]: %lud\n", i, stats->outCompStats[i]);
112046ecee76SDavid du Colombier }
112146ecee76SDavid du Colombier p += snprint(p, ep-p, "inPackets: %lud\n", stats->inPackets);
112246ecee76SDavid du Colombier p += snprint(p, ep-p, "inDataPackets: %lud\n", stats->inDataPackets);
112346ecee76SDavid du Colombier p += snprint(p, ep-p, "inDataBytes: %lud\n", stats->inDataBytes);
112446ecee76SDavid du Colombier p += snprint(p, ep-p, "inCompDataBytes: %lud\n", stats->inCompDataBytes);
112546ecee76SDavid du Colombier p += snprint(p, ep-p, "inMissing: %lud\n", stats->inMissing);
112646ecee76SDavid du Colombier p += snprint(p, ep-p, "inDup: %lud\n", stats->inDup);
112746ecee76SDavid du Colombier p += snprint(p, ep-p, "inReorder: %lud\n", stats->inReorder);
112846ecee76SDavid du Colombier p += snprint(p, ep-p, "inBadComp: %lud\n", stats->inBadComp);
112946ecee76SDavid du Colombier p += snprint(p, ep-p, "inBadAuth: %lud\n", stats->inBadAuth);
113046ecee76SDavid du Colombier p += snprint(p, ep-p, "inBadSeq: %lud\n", stats->inBadSeq);
113146ecee76SDavid du Colombier p += snprint(p, ep-p, "inBadOther: %lud\n", stats->inBadOther);
113246ecee76SDavid du Colombier USED(p);
113346ecee76SDavid du Colombier qunlock(c);
113446ecee76SDavid du Colombier }
113546ecee76SDavid du Colombier
113646ecee76SDavid du Colombier // c is locked
113746ecee76SDavid du Colombier static void
convack(Conv * c)113846ecee76SDavid du Colombier convack(Conv *c)
113946ecee76SDavid du Colombier {
114046ecee76SDavid du Colombier Block *b;
114146ecee76SDavid du Colombier AckPkt *ack;
114246ecee76SDavid du Colombier Stats *s;
114346ecee76SDavid du Colombier int i;
114446ecee76SDavid du Colombier
114546ecee76SDavid du Colombier b = allocb(sizeof(AckPkt));
114646ecee76SDavid du Colombier ack = (AckPkt*)b->wp;
114746ecee76SDavid du Colombier b->wp += sizeof(AckPkt);
114846ecee76SDavid du Colombier s = &c->lstats;
114946ecee76SDavid du Colombier hnputl(ack->cseq, c->in.controlseq);
115046ecee76SDavid du Colombier hnputl(ack->outPackets, s->outPackets);
115146ecee76SDavid du Colombier hnputl(ack->outDataPackets, s->outDataPackets);
115246ecee76SDavid du Colombier hnputl(ack->outDataBytes, s->outDataBytes);
115346ecee76SDavid du Colombier hnputl(ack->outCompDataBytes, s->outCompDataBytes);
115446ecee76SDavid du Colombier for(i=0; i<NCompStats; i++)
115546ecee76SDavid du Colombier hnputl(ack->outCompStats+i*4, s->outCompStats[i]);
115646ecee76SDavid du Colombier hnputl(ack->inPackets, s->inPackets);
115746ecee76SDavid du Colombier hnputl(ack->inDataPackets, s->inDataPackets);
115846ecee76SDavid du Colombier hnputl(ack->inDataBytes, s->inDataBytes);
115946ecee76SDavid du Colombier hnputl(ack->inCompDataBytes, s->inCompDataBytes);
116046ecee76SDavid du Colombier hnputl(ack->inMissing, s->inMissing);
116146ecee76SDavid du Colombier hnputl(ack->inDup, s->inDup);
116246ecee76SDavid du Colombier hnputl(ack->inReorder, s->inReorder);
116346ecee76SDavid du Colombier hnputl(ack->inBadComp, s->inBadComp);
116446ecee76SDavid du Colombier hnputl(ack->inBadAuth, s->inBadAuth);
116546ecee76SDavid du Colombier hnputl(ack->inBadSeq, s->inBadSeq);
116646ecee76SDavid du Colombier hnputl(ack->inBadOther, s->inBadOther);
116746ecee76SDavid du Colombier convoput(c, TControl, ControlAck, b);
116846ecee76SDavid du Colombier }
116946ecee76SDavid du Colombier
117046ecee76SDavid du Colombier
117146ecee76SDavid du Colombier // assume we hold lock for c
117246ecee76SDavid du Colombier static Block *
conviput(Conv * c,Block * b,int control)117346ecee76SDavid du Colombier conviput(Conv *c, Block *b, int control)
117446ecee76SDavid du Colombier {
117546ecee76SDavid du Colombier int type, subtype;
117646ecee76SDavid du Colombier ulong seq, seqwrap;
117746ecee76SDavid du Colombier long seqdiff;
117846ecee76SDavid du Colombier int pad;
117946ecee76SDavid du Colombier
118046ecee76SDavid du Colombier c->lstats.inPackets++;
118146ecee76SDavid du Colombier
118246ecee76SDavid du Colombier if(BLEN(b) < 4) {
118346ecee76SDavid du Colombier c->lstats.inBadOther++;
118446ecee76SDavid du Colombier freeb(b);
118546ecee76SDavid du Colombier return nil;
118646ecee76SDavid du Colombier }
118746ecee76SDavid du Colombier
118846ecee76SDavid du Colombier type = b->rp[0] >> 4;
118946ecee76SDavid du Colombier subtype = b->rp[0] & 0xf;
119046ecee76SDavid du Colombier b->rp += 1;
119146ecee76SDavid du Colombier if(type == TConnect) {
119246ecee76SDavid du Colombier conviconnect(c, subtype, b);
119346ecee76SDavid du Colombier return nil;
119446ecee76SDavid du Colombier }
119546ecee76SDavid du Colombier
119646ecee76SDavid du Colombier switch(c->state) {
119746ecee76SDavid du Colombier case CInit:
119846ecee76SDavid du Colombier case CDial:
119946ecee76SDavid du Colombier c->lstats.inBadOther++;
120046ecee76SDavid du Colombier convoconnect(c, ConReset, c->dialid, c->acceptid);
120146ecee76SDavid du Colombier convsetstate(c, CClosed);
120246ecee76SDavid du Colombier break;
120346ecee76SDavid du Colombier case CAccept:
120446ecee76SDavid du Colombier case CRemoteClose:
120546ecee76SDavid du Colombier case CLocalClose:
120646ecee76SDavid du Colombier c->lstats.inBadOther++;
120746ecee76SDavid du Colombier freeb(b);
120846ecee76SDavid du Colombier return nil;
120946ecee76SDavid du Colombier }
121046ecee76SDavid du Colombier
121146ecee76SDavid du Colombier seq = (b->rp[0]<<16) + (b->rp[1]<<8) + b->rp[2];
121246ecee76SDavid du Colombier b->rp += 3;
121346ecee76SDavid du Colombier
121446ecee76SDavid du Colombier seqwrap = c->in.seqwrap;
121546ecee76SDavid du Colombier seqdiff = seq - c->in.seq;
121646ecee76SDavid du Colombier if(seqdiff < -(SeqMax*3/4)) {
121746ecee76SDavid du Colombier seqwrap++;
121846ecee76SDavid du Colombier seqdiff += SeqMax;
121946ecee76SDavid du Colombier } else if(seqdiff > SeqMax*3/4) {
122046ecee76SDavid du Colombier seqwrap--;
122146ecee76SDavid du Colombier seqdiff -= SeqMax;
122246ecee76SDavid du Colombier }
122346ecee76SDavid du Colombier
122446ecee76SDavid du Colombier if(seqdiff <= 0) {
122546ecee76SDavid du Colombier if(seqdiff <= -SeqWindow) {
122646ecee76SDavid du Colombier if(0)print("old sequence number: %ld (%ld %ld)\n", seq, c->in.seqwrap, seqdiff);
122746ecee76SDavid du Colombier c->lstats.inBadSeq++;
122846ecee76SDavid du Colombier freeb(b);
122946ecee76SDavid du Colombier return nil;
123046ecee76SDavid du Colombier }
123146ecee76SDavid du Colombier
123246ecee76SDavid du Colombier if(c->in.window & (1<<-seqdiff)) {
123346ecee76SDavid du Colombier if(0)print("dup sequence number: %ld (%ld %ld)\n", seq, c->in.seqwrap, seqdiff);
123446ecee76SDavid du Colombier c->lstats.inDup++;
123546ecee76SDavid du Colombier freeb(b);
123646ecee76SDavid du Colombier return nil;
123746ecee76SDavid du Colombier }
123846ecee76SDavid du Colombier
123946ecee76SDavid du Colombier c->lstats.inReorder++;
124046ecee76SDavid du Colombier }
124146ecee76SDavid du Colombier
124246ecee76SDavid du Colombier // ok the sequence number looks ok
124346ecee76SDavid du Colombier if(0) print("coniput seq=%ulx\n", seq);
124446ecee76SDavid du Colombier if(c->in.auth != 0) {
124546ecee76SDavid du Colombier if(!(*c->in.auth)(&c->in, b->rp-4, BLEN(b)+4)) {
124646ecee76SDavid du Colombier if(0)print("bad auth %ld\n", BLEN(b)+4);
124746ecee76SDavid du Colombier c->lstats.inBadAuth++;
124846ecee76SDavid du Colombier freeb(b);
124946ecee76SDavid du Colombier return nil;
125046ecee76SDavid du Colombier }
125146ecee76SDavid du Colombier b->wp -= c->in.authlen;
125246ecee76SDavid du Colombier }
125346ecee76SDavid du Colombier
125446ecee76SDavid du Colombier if(c->in.cipher != 0) {
125546ecee76SDavid du Colombier if(!(*c->in.cipher)(&c->in, b->rp, BLEN(b))) {
125646ecee76SDavid du Colombier if(0)print("bad cipher\n");
125746ecee76SDavid du Colombier c->lstats.inBadOther++;
125846ecee76SDavid du Colombier freeb(b);
125946ecee76SDavid du Colombier return nil;
126046ecee76SDavid du Colombier }
126146ecee76SDavid du Colombier b->rp += c->in.cipherivlen;
126246ecee76SDavid du Colombier if(c->in.cipherblklen > 1) {
126346ecee76SDavid du Colombier pad = b->wp[-1];
126446ecee76SDavid du Colombier if(pad > BLEN(b)) {
126546ecee76SDavid du Colombier if(0)print("pad too big\n");
126646ecee76SDavid du Colombier c->lstats.inBadOther++;
126746ecee76SDavid du Colombier freeb(b);
126846ecee76SDavid du Colombier return nil;
126946ecee76SDavid du Colombier }
127046ecee76SDavid du Colombier b->wp -= pad;
127146ecee76SDavid du Colombier }
127246ecee76SDavid du Colombier }
127346ecee76SDavid du Colombier
127446ecee76SDavid du Colombier // ok the packet is good
127546ecee76SDavid du Colombier if(seqdiff > 0) {
127646ecee76SDavid du Colombier while(seqdiff > 0 && c->in.window != 0) {
127746ecee76SDavid du Colombier if((c->in.window & (1<<(SeqWindow-1))) == 0) {
127846ecee76SDavid du Colombier c->lstats.inMissing++;
127946ecee76SDavid du Colombier }
128046ecee76SDavid du Colombier c->in.window <<= 1;
128146ecee76SDavid du Colombier seqdiff--;
128246ecee76SDavid du Colombier }
128346ecee76SDavid du Colombier if(seqdiff > 0) {
128446ecee76SDavid du Colombier c->lstats.inMissing += seqdiff;
128546ecee76SDavid du Colombier seqdiff = 0;
128646ecee76SDavid du Colombier }
128746ecee76SDavid du Colombier c->in.seq = seq;
128846ecee76SDavid du Colombier c->in.seqwrap = seqwrap;
128946ecee76SDavid du Colombier }
129046ecee76SDavid du Colombier c->in.window |= 1<<-seqdiff;
129146ecee76SDavid du Colombier c->lastrecv = TK2SEC(m->ticks);
129246ecee76SDavid du Colombier
129346ecee76SDavid du Colombier switch(type) {
129446ecee76SDavid du Colombier case TControl:
129546ecee76SDavid du Colombier convicontrol(c, subtype, b);
129646ecee76SDavid du Colombier return nil;
129746ecee76SDavid du Colombier case TData:
129846ecee76SDavid du Colombier c->lstats.inDataPackets++;
129946ecee76SDavid du Colombier c->lstats.inDataBytes += BLEN(b);
130046ecee76SDavid du Colombier if(control)
130146ecee76SDavid du Colombier break;
130246ecee76SDavid du Colombier return b;
130346ecee76SDavid du Colombier case TCompData:
130446ecee76SDavid du Colombier c->lstats.inDataPackets++;
130546ecee76SDavid du Colombier c->lstats.inCompDataBytes += BLEN(b);
130646ecee76SDavid du Colombier b = convicomp(c, subtype, seq, b);
130746ecee76SDavid du Colombier if(b == nil) {
130846ecee76SDavid du Colombier c->lstats.inBadComp++;
130946ecee76SDavid du Colombier return nil;
131046ecee76SDavid du Colombier }
131146ecee76SDavid du Colombier c->lstats.inDataBytes += BLEN(b);
131246ecee76SDavid du Colombier if(control)
131346ecee76SDavid du Colombier break;
131446ecee76SDavid du Colombier return b;
131546ecee76SDavid du Colombier }
131646ecee76SDavid du Colombier if(0)print("dropping packet id=%d: type=%d n=%ld control=%d\n", c->id, type, BLEN(b), control);
131746ecee76SDavid du Colombier c->lstats.inBadOther++;
131846ecee76SDavid du Colombier freeb(b);
131946ecee76SDavid du Colombier return nil;
132046ecee76SDavid du Colombier }
132146ecee76SDavid du Colombier
132246ecee76SDavid du Colombier // assume hold conv lock
132346ecee76SDavid du Colombier static void
conviconnect(Conv * c,int subtype,Block * b)132446ecee76SDavid du Colombier conviconnect(Conv *c, int subtype, Block *b)
132546ecee76SDavid du Colombier {
132646ecee76SDavid du Colombier ulong dialid;
132746ecee76SDavid du Colombier ulong acceptid;
132846ecee76SDavid du Colombier
132946ecee76SDavid du Colombier if(BLEN(b) != 8) {
133046ecee76SDavid du Colombier freeb(b);
133146ecee76SDavid du Colombier return;
133246ecee76SDavid du Colombier }
133346ecee76SDavid du Colombier dialid = nhgetl(b->rp);
133446ecee76SDavid du Colombier acceptid = nhgetl(b->rp + 4);
133546ecee76SDavid du Colombier freeb(b);
133646ecee76SDavid du Colombier
1337d9814433SDavid du Colombier if(0)print("sdp: conviconnect: %s: %d %uld %uld\n", convstatename[c->state], subtype, dialid, acceptid);
133846ecee76SDavid du Colombier
133946ecee76SDavid du Colombier if(subtype == ConReset) {
134046ecee76SDavid du Colombier convsetstate(c, CClosed);
134146ecee76SDavid du Colombier return;
134246ecee76SDavid du Colombier }
134346ecee76SDavid du Colombier
134446ecee76SDavid du Colombier switch(c->state) {
134546ecee76SDavid du Colombier default:
134646ecee76SDavid du Colombier panic("unknown state: %d", c->state);
134746ecee76SDavid du Colombier case CInit:
134846ecee76SDavid du Colombier break;
134946ecee76SDavid du Colombier case CDial:
135046ecee76SDavid du Colombier if(dialid != c->dialid)
135146ecee76SDavid du Colombier goto Reset;
135246ecee76SDavid du Colombier break;
135346ecee76SDavid du Colombier case CAccept:
135446ecee76SDavid du Colombier case COpen:
135546ecee76SDavid du Colombier case CLocalClose:
135646ecee76SDavid du Colombier case CRemoteClose:
135746ecee76SDavid du Colombier if(dialid != c->dialid
135846ecee76SDavid du Colombier || subtype != ConOpenRequest && acceptid != c->acceptid)
135946ecee76SDavid du Colombier goto Reset;
136046ecee76SDavid du Colombier break;
136146ecee76SDavid du Colombier case CClosed:
136246ecee76SDavid du Colombier goto Reset;
136346ecee76SDavid du Colombier }
136446ecee76SDavid du Colombier
136546ecee76SDavid du Colombier switch(subtype) {
136646ecee76SDavid du Colombier case ConOpenRequest:
136746ecee76SDavid du Colombier switch(c->state) {
136846ecee76SDavid du Colombier case CInit:
136946ecee76SDavid du Colombier c->dialid = dialid;
137046ecee76SDavid du Colombier convsetstate(c, CAccept);
137146ecee76SDavid du Colombier return;
137246ecee76SDavid du Colombier case CAccept:
137346ecee76SDavid du Colombier case COpen:
137446ecee76SDavid du Colombier // duplicate ConOpenRequest that we ignore
137546ecee76SDavid du Colombier return;
137646ecee76SDavid du Colombier }
137746ecee76SDavid du Colombier break;
137846ecee76SDavid du Colombier case ConOpenAck:
137946ecee76SDavid du Colombier switch(c->state) {
138046ecee76SDavid du Colombier case CDial:
138146ecee76SDavid du Colombier c->acceptid = acceptid;
138246ecee76SDavid du Colombier convsetstate(c, COpen);
138346ecee76SDavid du Colombier return;
138446ecee76SDavid du Colombier case COpen:
138546ecee76SDavid du Colombier // duplicate that we have to ack
138646ecee76SDavid du Colombier convoconnect(c, ConOpenAckAck, acceptid, dialid);
138746ecee76SDavid du Colombier return;
138846ecee76SDavid du Colombier }
138946ecee76SDavid du Colombier break;
139046ecee76SDavid du Colombier case ConOpenAckAck:
139146ecee76SDavid du Colombier switch(c->state) {
139246ecee76SDavid du Colombier case CAccept:
139346ecee76SDavid du Colombier convsetstate(c, COpen);
139446ecee76SDavid du Colombier return;
139546ecee76SDavid du Colombier case COpen:
139646ecee76SDavid du Colombier case CLocalClose:
139746ecee76SDavid du Colombier case CRemoteClose:
139846ecee76SDavid du Colombier // duplicate that we ignore
139946ecee76SDavid du Colombier return;
140046ecee76SDavid du Colombier }
140146ecee76SDavid du Colombier break;
140246ecee76SDavid du Colombier case ConClose:
140346ecee76SDavid du Colombier switch(c->state) {
140446ecee76SDavid du Colombier case COpen:
140546ecee76SDavid du Colombier convoconnect(c, ConCloseAck, dialid, acceptid);
140646ecee76SDavid du Colombier convsetstate(c, CRemoteClose);
140746ecee76SDavid du Colombier return;
140846ecee76SDavid du Colombier case CRemoteClose:
140946ecee76SDavid du Colombier // duplicate ConClose
141046ecee76SDavid du Colombier convoconnect(c, ConCloseAck, dialid, acceptid);
141146ecee76SDavid du Colombier return;
141246ecee76SDavid du Colombier }
141346ecee76SDavid du Colombier break;
141446ecee76SDavid du Colombier case ConCloseAck:
141546ecee76SDavid du Colombier switch(c->state) {
141646ecee76SDavid du Colombier case CLocalClose:
141746ecee76SDavid du Colombier convsetstate(c, CClosed);
141846ecee76SDavid du Colombier return;
141946ecee76SDavid du Colombier }
142046ecee76SDavid du Colombier break;
142146ecee76SDavid du Colombier }
142246ecee76SDavid du Colombier Reset:
142346ecee76SDavid du Colombier // invalid connection message - reset to sender
1424d9814433SDavid du Colombier if(1)print("sdp: invalid conviconnect - sending reset\n");
142546ecee76SDavid du Colombier convoconnect(c, ConReset, dialid, acceptid);
142646ecee76SDavid du Colombier convsetstate(c, CClosed);
142746ecee76SDavid du Colombier }
142846ecee76SDavid du Colombier
142946ecee76SDavid du Colombier static void
convicontrol(Conv * c,int subtype,Block * b)143046ecee76SDavid du Colombier convicontrol(Conv *c, int subtype, Block *b)
143146ecee76SDavid du Colombier {
143246ecee76SDavid du Colombier ulong cseq;
143346ecee76SDavid du Colombier AckPkt *ack;
143446ecee76SDavid du Colombier int i;
143546ecee76SDavid du Colombier
143646ecee76SDavid du Colombier if(BLEN(b) < 4)
143746ecee76SDavid du Colombier return;
143846ecee76SDavid du Colombier cseq = nhgetl(b->rp);
143946ecee76SDavid du Colombier
144046ecee76SDavid du Colombier switch(subtype){
144146ecee76SDavid du Colombier case ControlMesg:
144246ecee76SDavid du Colombier if(cseq == c->in.controlseq) {
144346ecee76SDavid du Colombier if(0)print("duplicate control packet: %ulx\n", cseq);
144446ecee76SDavid du Colombier // duplicate control packet
144546ecee76SDavid du Colombier freeb(b);
144646ecee76SDavid du Colombier if(c->in.controlpkt == nil)
144746ecee76SDavid du Colombier convack(c);
144846ecee76SDavid du Colombier return;
144946ecee76SDavid du Colombier }
145046ecee76SDavid du Colombier
145146ecee76SDavid du Colombier if(cseq != c->in.controlseq+1)
145246ecee76SDavid du Colombier return;
145346ecee76SDavid du Colombier c->in.controlseq = cseq;
145446ecee76SDavid du Colombier b->rp += 4;
145546ecee76SDavid du Colombier if(BLEN(b) == 0) {
145646ecee76SDavid du Colombier // just a ping
145746ecee76SDavid du Colombier freeb(b);
145846ecee76SDavid du Colombier convack(c);
145946ecee76SDavid du Colombier } else {
146046ecee76SDavid du Colombier c->in.controlpkt = b;
146146ecee76SDavid du Colombier if(0) print("recv %ld size=%ld\n", cseq, BLEN(b));
146246ecee76SDavid du Colombier wakeup(&c->in.controlready);
146346ecee76SDavid du Colombier }
146446ecee76SDavid du Colombier return;
146546ecee76SDavid du Colombier case ControlAck:
146646ecee76SDavid du Colombier if(cseq != c->out.controlseq)
146746ecee76SDavid du Colombier return;
146846ecee76SDavid du Colombier if(BLEN(b) < sizeof(AckPkt))
146946ecee76SDavid du Colombier return;
147046ecee76SDavid du Colombier ack = (AckPkt*)(b->rp);
147146ecee76SDavid du Colombier c->rstats.outPackets = nhgetl(ack->outPackets);
147246ecee76SDavid du Colombier c->rstats.outDataPackets = nhgetl(ack->outDataPackets);
147346ecee76SDavid du Colombier c->rstats.outDataBytes = nhgetl(ack->outDataBytes);
147446ecee76SDavid du Colombier c->rstats.outCompDataBytes = nhgetl(ack->outCompDataBytes);
147546ecee76SDavid du Colombier for(i=0; i<NCompStats; i++)
147646ecee76SDavid du Colombier c->rstats.outCompStats[i] = nhgetl(ack->outCompStats + 4*i);
147746ecee76SDavid du Colombier c->rstats.inPackets = nhgetl(ack->inPackets);
147846ecee76SDavid du Colombier c->rstats.inDataPackets = nhgetl(ack->inDataPackets);
147946ecee76SDavid du Colombier c->rstats.inDataBytes = nhgetl(ack->inDataBytes);
148046ecee76SDavid du Colombier c->rstats.inCompDataBytes = nhgetl(ack->inCompDataBytes);
148146ecee76SDavid du Colombier c->rstats.inMissing = nhgetl(ack->inMissing);
148246ecee76SDavid du Colombier c->rstats.inDup = nhgetl(ack->inDup);
148346ecee76SDavid du Colombier c->rstats.inReorder = nhgetl(ack->inReorder);
148446ecee76SDavid du Colombier c->rstats.inBadComp = nhgetl(ack->inBadComp);
148546ecee76SDavid du Colombier c->rstats.inBadAuth = nhgetl(ack->inBadAuth);
148646ecee76SDavid du Colombier c->rstats.inBadSeq = nhgetl(ack->inBadSeq);
148746ecee76SDavid du Colombier c->rstats.inBadOther = nhgetl(ack->inBadOther);
148846ecee76SDavid du Colombier freeb(b);
148946ecee76SDavid du Colombier freeb(c->out.controlpkt);
149046ecee76SDavid du Colombier c->out.controlpkt = nil;
149146ecee76SDavid du Colombier c->timeout = c->lastrecv + KeepAlive;
149246ecee76SDavid du Colombier wakeup(&c->out.controlready);
149346ecee76SDavid du Colombier return;
149446ecee76SDavid du Colombier }
149546ecee76SDavid du Colombier }
149646ecee76SDavid du Colombier
149746ecee76SDavid du Colombier static Block*
convicomp(Conv * c,int subtype,ulong seq,Block * b)149846ecee76SDavid du Colombier convicomp(Conv *c, int subtype, ulong seq, Block *b)
149946ecee76SDavid du Colombier {
150046ecee76SDavid du Colombier if(c->in.comp == nil) {
150146ecee76SDavid du Colombier freeb(b);
150246ecee76SDavid du Colombier return nil;
150346ecee76SDavid du Colombier }
150446ecee76SDavid du Colombier if(!(*c->in.comp)(c, subtype, seq, &b))
150546ecee76SDavid du Colombier return nil;
150646ecee76SDavid du Colombier return b;
150746ecee76SDavid du Colombier }
150846ecee76SDavid du Colombier
150946ecee76SDavid du Colombier // c is locked
151046ecee76SDavid du Colombier static void
convwriteblock(Conv * c,Block * b)151146ecee76SDavid du Colombier convwriteblock(Conv *c, Block *b)
151246ecee76SDavid du Colombier {
151346ecee76SDavid du Colombier // simulated errors
151446ecee76SDavid du Colombier if(c->drop && nrand(c->drop) == 0)
151546ecee76SDavid du Colombier return;
151646ecee76SDavid du Colombier
151746ecee76SDavid du Colombier if(waserror()) {
151846ecee76SDavid du Colombier convsetstate(c, CClosed);
151946ecee76SDavid du Colombier nexterror();
152046ecee76SDavid du Colombier }
152146ecee76SDavid du Colombier devtab[c->chan->type]->bwrite(c->chan, b, 0);
152246ecee76SDavid du Colombier poperror();
152346ecee76SDavid du Colombier }
152446ecee76SDavid du Colombier
152546ecee76SDavid du Colombier
152646ecee76SDavid du Colombier // assume hold conv lock
152746ecee76SDavid du Colombier static void
convoput(Conv * c,int type,int subtype,Block * b)152846ecee76SDavid du Colombier convoput(Conv *c, int type, int subtype, Block *b)
152946ecee76SDavid du Colombier {
153046ecee76SDavid du Colombier int pad;
153146ecee76SDavid du Colombier
153246ecee76SDavid du Colombier c->lstats.outPackets++;
153346ecee76SDavid du Colombier /* Make room for sdp trailer */
153446ecee76SDavid du Colombier if(c->out.cipherblklen > 1)
153546ecee76SDavid du Colombier pad = c->out.cipherblklen - (BLEN(b) + c->out.cipherivlen) % c->out.cipherblklen;
153646ecee76SDavid du Colombier else
153746ecee76SDavid du Colombier pad = 0;
153846ecee76SDavid du Colombier
153946ecee76SDavid du Colombier b = padblock(b, -(pad+c->out.authlen));
154046ecee76SDavid du Colombier
154146ecee76SDavid du Colombier if(pad) {
154246ecee76SDavid du Colombier memset(b->wp, 0, pad-1);
154346ecee76SDavid du Colombier b->wp[pad-1] = pad;
154446ecee76SDavid du Colombier b->wp += pad;
154546ecee76SDavid du Colombier }
154646ecee76SDavid du Colombier
154746ecee76SDavid du Colombier /* Make space to fit sdp header */
154846ecee76SDavid du Colombier b = padblock(b, 4 + c->out.cipherivlen);
154946ecee76SDavid du Colombier b->rp[0] = (type << 4) | subtype;
155046ecee76SDavid du Colombier c->out.seq++;
155146ecee76SDavid du Colombier if(c->out.seq == (1<<24)) {
155246ecee76SDavid du Colombier c->out.seq = 0;
155346ecee76SDavid du Colombier c->out.seqwrap++;
155446ecee76SDavid du Colombier }
155546ecee76SDavid du Colombier b->rp[1] = c->out.seq>>16;
155646ecee76SDavid du Colombier b->rp[2] = c->out.seq>>8;
155746ecee76SDavid du Colombier b->rp[3] = c->out.seq;
155846ecee76SDavid du Colombier
155946ecee76SDavid du Colombier if(c->out.cipher)
156046ecee76SDavid du Colombier (*c->out.cipher)(&c->out, b->rp+4, BLEN(b)-4);
156146ecee76SDavid du Colombier
156246ecee76SDavid du Colombier // auth
156346ecee76SDavid du Colombier if(c->out.auth) {
156446ecee76SDavid du Colombier b->wp += c->out.authlen;
156546ecee76SDavid du Colombier (*c->out.auth)(&c->out, b->rp, BLEN(b));
156646ecee76SDavid du Colombier }
156746ecee76SDavid du Colombier
156846ecee76SDavid du Colombier convwriteblock(c, b);
156946ecee76SDavid du Colombier }
157046ecee76SDavid du Colombier
157146ecee76SDavid du Colombier // assume hold conv lock
157246ecee76SDavid du Colombier static void
convoconnect(Conv * c,int op,ulong dialid,ulong acceptid)157346ecee76SDavid du Colombier convoconnect(Conv *c, int op, ulong dialid, ulong acceptid)
157446ecee76SDavid du Colombier {
157546ecee76SDavid du Colombier Block *b;
157646ecee76SDavid du Colombier
157746ecee76SDavid du Colombier c->lstats.outPackets++;
157846ecee76SDavid du Colombier assert(c->chan != nil);
157946ecee76SDavid du Colombier b = allocb(9);
158046ecee76SDavid du Colombier b->wp[0] = (TConnect << 4) | op;
158146ecee76SDavid du Colombier hnputl(b->wp+1, dialid);
158246ecee76SDavid du Colombier hnputl(b->wp+5, acceptid);
158346ecee76SDavid du Colombier b->wp += 9;
158446ecee76SDavid du Colombier
158546ecee76SDavid du Colombier if(!waserror()) {
158646ecee76SDavid du Colombier convwriteblock(c, b);
158746ecee76SDavid du Colombier poperror();
158846ecee76SDavid du Colombier }
158946ecee76SDavid du Colombier }
159046ecee76SDavid du Colombier
159146ecee76SDavid du Colombier static Block *
convreadblock(Conv * c,int n)159246ecee76SDavid du Colombier convreadblock(Conv *c, int n)
159346ecee76SDavid du Colombier {
159446ecee76SDavid du Colombier Block *b;
159546ecee76SDavid du Colombier Chan *ch;
159646ecee76SDavid du Colombier
159746ecee76SDavid du Colombier qlock(&c->readlk);
159846ecee76SDavid du Colombier if(waserror()) {
159946ecee76SDavid du Colombier c->readproc = nil;
160046ecee76SDavid du Colombier qunlock(&c->readlk);
160146ecee76SDavid du Colombier nexterror();
160246ecee76SDavid du Colombier }
160346ecee76SDavid du Colombier qlock(c);
160446ecee76SDavid du Colombier if(c->state == CClosed) {
160546ecee76SDavid du Colombier qunlock(c);
160646ecee76SDavid du Colombier error("closed");
160746ecee76SDavid du Colombier }
160846ecee76SDavid du Colombier c->readproc = up;
160946ecee76SDavid du Colombier ch = c->chan;
161046ecee76SDavid du Colombier assert(c->ref > 0);
161146ecee76SDavid du Colombier qunlock(c);
161246ecee76SDavid du Colombier
161346ecee76SDavid du Colombier b = devtab[ch->type]->bread(ch, n, 0);
161446ecee76SDavid du Colombier c->readproc = nil;
161546ecee76SDavid du Colombier poperror();
161646ecee76SDavid du Colombier qunlock(&c->readlk);
161746ecee76SDavid du Colombier
161846ecee76SDavid du Colombier return b;
161946ecee76SDavid du Colombier }
162046ecee76SDavid du Colombier
162146ecee76SDavid du Colombier static int
readready(void * a)162246ecee76SDavid du Colombier readready(void *a)
162346ecee76SDavid du Colombier {
162446ecee76SDavid du Colombier Conv *c = a;
162546ecee76SDavid du Colombier
162646ecee76SDavid du Colombier return c->in.controlpkt != nil || (c->state == CClosed) || (c->state == CRemoteClose);
162746ecee76SDavid du Colombier }
162846ecee76SDavid du Colombier
162946ecee76SDavid du Colombier static Block *
readcontrol(Conv * c,int n)163046ecee76SDavid du Colombier readcontrol(Conv *c, int n)
163146ecee76SDavid du Colombier {
163246ecee76SDavid du Colombier Block *b;
163346ecee76SDavid du Colombier
163446ecee76SDavid du Colombier USED(n);
163546ecee76SDavid du Colombier
163646ecee76SDavid du Colombier qlock(&c->in.controllk);
163746ecee76SDavid du Colombier if(waserror()) {
163846ecee76SDavid du Colombier qunlock(&c->in.controllk);
163946ecee76SDavid du Colombier nexterror();
164046ecee76SDavid du Colombier }
164146ecee76SDavid du Colombier qlock(c); // this lock is not held during the sleep below
164246ecee76SDavid du Colombier
164346ecee76SDavid du Colombier for(;;) {
164446ecee76SDavid du Colombier if(c->chan == nil || c->state == CClosed) {
164546ecee76SDavid du Colombier qunlock(c);
164646ecee76SDavid du Colombier if(0)print("readcontrol: return error - state = %s\n", convstatename[c->state]);
164746ecee76SDavid du Colombier error("conversation closed");
164846ecee76SDavid du Colombier }
164946ecee76SDavid du Colombier
165046ecee76SDavid du Colombier if(c->in.controlpkt != nil)
165146ecee76SDavid du Colombier break;
165246ecee76SDavid du Colombier
165346ecee76SDavid du Colombier if(c->state == CRemoteClose) {
165446ecee76SDavid du Colombier qunlock(c);
165546ecee76SDavid du Colombier if(0)print("readcontrol: return nil - state = %s\n", convstatename[c->state]);
165646ecee76SDavid du Colombier poperror();
165746ecee76SDavid du Colombier return nil;
165846ecee76SDavid du Colombier }
165946ecee76SDavid du Colombier qunlock(c);
166046ecee76SDavid du Colombier sleep(&c->in.controlready, readready, c);
166146ecee76SDavid du Colombier qlock(c);
166246ecee76SDavid du Colombier }
166346ecee76SDavid du Colombier
166446ecee76SDavid du Colombier convack(c);
166546ecee76SDavid du Colombier
166646ecee76SDavid du Colombier b = c->in.controlpkt;
166746ecee76SDavid du Colombier c->in.controlpkt = nil;
166846ecee76SDavid du Colombier qunlock(c);
166946ecee76SDavid du Colombier poperror();
167046ecee76SDavid du Colombier qunlock(&c->in.controllk);
167146ecee76SDavid du Colombier return b;
167246ecee76SDavid du Colombier }
167346ecee76SDavid du Colombier
167446ecee76SDavid du Colombier
167546ecee76SDavid du Colombier static int
writeready(void * a)167646ecee76SDavid du Colombier writeready(void *a)
167746ecee76SDavid du Colombier {
167846ecee76SDavid du Colombier Conv *c = a;
167946ecee76SDavid du Colombier
168046ecee76SDavid du Colombier return c->out.controlpkt == nil || (c->state == CClosed) || (c->state == CRemoteClose);
168146ecee76SDavid du Colombier }
168246ecee76SDavid du Colombier
168346ecee76SDavid du Colombier // c is locked
168446ecee76SDavid du Colombier static void
writewait(Conv * c)168546ecee76SDavid du Colombier writewait(Conv *c)
168646ecee76SDavid du Colombier {
168746ecee76SDavid du Colombier for(;;) {
168846ecee76SDavid du Colombier if(c->state == CFree || c->state == CInit ||
168946ecee76SDavid du Colombier c->state == CClosed || c->state == CRemoteClose)
169046ecee76SDavid du Colombier error("conversation closed");
169146ecee76SDavid du Colombier
169246ecee76SDavid du Colombier if(c->state == COpen && c->out.controlpkt == nil)
169346ecee76SDavid du Colombier break;
169446ecee76SDavid du Colombier
169546ecee76SDavid du Colombier qunlock(c);
169646ecee76SDavid du Colombier if(waserror()) {
169746ecee76SDavid du Colombier qlock(c);
169846ecee76SDavid du Colombier nexterror();
169946ecee76SDavid du Colombier }
170046ecee76SDavid du Colombier sleep(&c->out.controlready, writeready, c);
170146ecee76SDavid du Colombier poperror();
170246ecee76SDavid du Colombier qlock(c);
170346ecee76SDavid du Colombier }
170446ecee76SDavid du Colombier }
170546ecee76SDavid du Colombier
170646ecee76SDavid du Colombier static void
writecontrol(Conv * c,void * p,int n,int wait)170746ecee76SDavid du Colombier writecontrol(Conv *c, void *p, int n, int wait)
170846ecee76SDavid du Colombier {
170946ecee76SDavid du Colombier Block *b;
171046ecee76SDavid du Colombier
171146ecee76SDavid du Colombier qlock(&c->out.controllk);
171246ecee76SDavid du Colombier qlock(c);
171346ecee76SDavid du Colombier if(waserror()) {
171446ecee76SDavid du Colombier qunlock(c);
171546ecee76SDavid du Colombier qunlock(&c->out.controllk);
171646ecee76SDavid du Colombier nexterror();
171746ecee76SDavid du Colombier }
171846ecee76SDavid du Colombier writewait(c);
171946ecee76SDavid du Colombier b = allocb(4+n);
172046ecee76SDavid du Colombier c->out.controlseq++;
172146ecee76SDavid du Colombier hnputl(b->wp, c->out.controlseq);
172246ecee76SDavid du Colombier memmove(b->wp+4, p, n);
172346ecee76SDavid du Colombier b->wp += 4+n;
172446ecee76SDavid du Colombier c->out.controlpkt = b;
172546ecee76SDavid du Colombier convretryinit(c);
172646ecee76SDavid du Colombier convoput(c, TControl, ControlMesg, copyblock(b, blocklen(b)));
172746ecee76SDavid du Colombier if(wait)
172846ecee76SDavid du Colombier writewait(c);
172946ecee76SDavid du Colombier poperror();
173046ecee76SDavid du Colombier qunlock(c);
173146ecee76SDavid du Colombier qunlock(&c->out.controllk);
173246ecee76SDavid du Colombier }
173346ecee76SDavid du Colombier
173446ecee76SDavid du Colombier static Block *
readdata(Conv * c,int n)173546ecee76SDavid du Colombier readdata(Conv *c, int n)
173646ecee76SDavid du Colombier {
173746ecee76SDavid du Colombier Block *b;
173846ecee76SDavid du Colombier int nn;
173946ecee76SDavid du Colombier
174046ecee76SDavid du Colombier for(;;) {
174146ecee76SDavid du Colombier
174246ecee76SDavid du Colombier // some slack for tunneling overhead
174346ecee76SDavid du Colombier nn = n + 100;
174446ecee76SDavid du Colombier
174546ecee76SDavid du Colombier // make sure size is big enough for control messages
174646ecee76SDavid du Colombier if(nn < 1000)
174746ecee76SDavid du Colombier nn = 1000;
174846ecee76SDavid du Colombier b = convreadblock(c, nn);
174946ecee76SDavid du Colombier if(b == nil)
175046ecee76SDavid du Colombier return nil;
175146ecee76SDavid du Colombier qlock(c);
175246ecee76SDavid du Colombier if(waserror()) {
175346ecee76SDavid du Colombier qunlock(c);
175446ecee76SDavid du Colombier return nil;
175546ecee76SDavid du Colombier }
175646ecee76SDavid du Colombier b = conviput(c, b, 0);
175746ecee76SDavid du Colombier poperror();
175846ecee76SDavid du Colombier qunlock(c);
175946ecee76SDavid du Colombier if(b != nil) {
176046ecee76SDavid du Colombier if(BLEN(b) > n)
176146ecee76SDavid du Colombier b->wp = b->rp + n;
176246ecee76SDavid du Colombier return b;
176346ecee76SDavid du Colombier }
176446ecee76SDavid du Colombier }
176546ecee76SDavid du Colombier }
176646ecee76SDavid du Colombier
176746ecee76SDavid du Colombier static long
writedata(Conv * c,Block * b)176846ecee76SDavid du Colombier writedata(Conv *c, Block *b)
176946ecee76SDavid du Colombier {
177046ecee76SDavid du Colombier int n;
177146ecee76SDavid du Colombier ulong seq;
177246ecee76SDavid du Colombier int subtype;
177346ecee76SDavid du Colombier
177446ecee76SDavid du Colombier qlock(c);
177546ecee76SDavid du Colombier if(waserror()) {
177646ecee76SDavid du Colombier qunlock(c);
177746ecee76SDavid du Colombier nexterror();
177846ecee76SDavid du Colombier }
177946ecee76SDavid du Colombier
178046ecee76SDavid du Colombier if(c->state != COpen) {
178146ecee76SDavid du Colombier freeb(b);
178246ecee76SDavid du Colombier error("conversation not open");
178346ecee76SDavid du Colombier }
178446ecee76SDavid du Colombier
178546ecee76SDavid du Colombier n = BLEN(b);
178646ecee76SDavid du Colombier c->lstats.outDataPackets++;
178746ecee76SDavid du Colombier c->lstats.outDataBytes += n;
178846ecee76SDavid du Colombier
178946ecee76SDavid du Colombier if(c->out.comp != nil) {
179046ecee76SDavid du Colombier // must generate same value as convoput
179146ecee76SDavid du Colombier seq = (c->out.seq + 1) & (SeqMax-1);
179246ecee76SDavid du Colombier
179346ecee76SDavid du Colombier subtype = (*c->out.comp)(c, 0, seq, &b);
179446ecee76SDavid du Colombier c->lstats.outCompDataBytes += BLEN(b);
179546ecee76SDavid du Colombier convoput(c, TCompData, subtype, b);
179646ecee76SDavid du Colombier } else
179746ecee76SDavid du Colombier convoput(c, TData, 0, b);
179846ecee76SDavid du Colombier
179946ecee76SDavid du Colombier poperror();
180046ecee76SDavid du Colombier qunlock(c);
180146ecee76SDavid du Colombier return n;
180246ecee76SDavid du Colombier }
180346ecee76SDavid du Colombier
180446ecee76SDavid du Colombier static void
convreader(void * a)180546ecee76SDavid du Colombier convreader(void *a)
180646ecee76SDavid du Colombier {
180746ecee76SDavid du Colombier Conv *c = a;
180846ecee76SDavid du Colombier Block *b;
180946ecee76SDavid du Colombier
181046ecee76SDavid du Colombier qlock(c);
181146ecee76SDavid du Colombier assert(c->reader == 1);
181246ecee76SDavid du Colombier while(c->dataopen == 0 && c->state != CClosed) {
181346ecee76SDavid du Colombier qunlock(c);
181446ecee76SDavid du Colombier b = nil;
181546ecee76SDavid du Colombier if(!waserror()) {
181646ecee76SDavid du Colombier b = convreadblock(c, 2000);
181746ecee76SDavid du Colombier poperror();
181846ecee76SDavid du Colombier }
181946ecee76SDavid du Colombier qlock(c);
182046ecee76SDavid du Colombier if(b == nil) {
182146ecee76SDavid du Colombier if(strcmp(up->errstr, Eintr) != 0) {
182246ecee76SDavid du Colombier convsetstate(c, CClosed);
182346ecee76SDavid du Colombier break;
182446ecee76SDavid du Colombier }
182546ecee76SDavid du Colombier } else if(!waserror()) {
182646ecee76SDavid du Colombier conviput(c, b, 1);
182746ecee76SDavid du Colombier poperror();
182846ecee76SDavid du Colombier }
182946ecee76SDavid du Colombier }
183046ecee76SDavid du Colombier c->reader = 0;
183146ecee76SDavid du Colombier convderef(c);
183246ecee76SDavid du Colombier qunlock(c);
183346ecee76SDavid du Colombier pexit("hangup", 1);
183446ecee76SDavid du Colombier }
183546ecee76SDavid du Colombier
183646ecee76SDavid du Colombier
183746ecee76SDavid du Colombier /* ciphers, authenticators, and compressors */
183846ecee76SDavid du Colombier
183946ecee76SDavid du Colombier static void
setalg(Conv * c,char * name,Algorithm * alg,Algorithm ** p)184046ecee76SDavid du Colombier setalg(Conv *c, char *name, Algorithm *alg, Algorithm **p)
184146ecee76SDavid du Colombier {
184246ecee76SDavid du Colombier for(; alg->name; alg++)
184346ecee76SDavid du Colombier if(strcmp(name, alg->name) == 0)
184446ecee76SDavid du Colombier break;
184546ecee76SDavid du Colombier if(alg->name == nil)
184646ecee76SDavid du Colombier error("unknown algorithm");
184746ecee76SDavid du Colombier
184846ecee76SDavid du Colombier *p = alg;
184946ecee76SDavid du Colombier alg->init(c);
185046ecee76SDavid du Colombier }
185146ecee76SDavid du Colombier
185246ecee76SDavid du Colombier static void
setsecret(OneWay * ow,char * secret)185346ecee76SDavid du Colombier setsecret(OneWay *ow, char *secret)
185446ecee76SDavid du Colombier {
185546ecee76SDavid du Colombier char *p;
185646ecee76SDavid du Colombier int i, c;
185746ecee76SDavid du Colombier
185846ecee76SDavid du Colombier i = 0;
185946ecee76SDavid du Colombier memset(ow->secret, 0, sizeof(ow->secret));
186046ecee76SDavid du Colombier for(p=secret; *p; p++) {
186146ecee76SDavid du Colombier if(i >= sizeof(ow->secret)*2)
186246ecee76SDavid du Colombier break;
186346ecee76SDavid du Colombier c = *p;
186446ecee76SDavid du Colombier if(c >= '0' && c <= '9')
186546ecee76SDavid du Colombier c -= '0';
186646ecee76SDavid du Colombier else if(c >= 'a' && c <= 'f')
186746ecee76SDavid du Colombier c -= 'a'-10;
186846ecee76SDavid du Colombier else if(c >= 'A' && c <= 'F')
186946ecee76SDavid du Colombier c -= 'A'-10;
187046ecee76SDavid du Colombier else
187146ecee76SDavid du Colombier error("bad character in secret");
187246ecee76SDavid du Colombier if((i&1) == 0)
187346ecee76SDavid du Colombier c <<= 4;
187446ecee76SDavid du Colombier ow->secret[i>>1] |= c;
187546ecee76SDavid du Colombier i++;
187646ecee76SDavid du Colombier }
187746ecee76SDavid du Colombier }
187846ecee76SDavid du Colombier
187946ecee76SDavid du Colombier static void
setkey(uchar * key,int n,OneWay * ow,char * prefix)188046ecee76SDavid du Colombier setkey(uchar *key, int n, OneWay *ow, char *prefix)
188146ecee76SDavid du Colombier {
188246ecee76SDavid du Colombier uchar ibuf[SHA1dlen], obuf[MD5dlen], salt[10];
188346ecee76SDavid du Colombier int i, round = 0;
188446ecee76SDavid du Colombier
188546ecee76SDavid du Colombier while(n > 0){
188646ecee76SDavid du Colombier for(i=0; i<round+1; i++)
188746ecee76SDavid du Colombier salt[i] = 'A'+round;
188846ecee76SDavid du Colombier sha1((uchar*)prefix, strlen(prefix), ibuf, sha1(salt, round+1, nil, nil));
188946ecee76SDavid du Colombier md5(ibuf, SHA1dlen, obuf, md5(ow->secret, sizeof(ow->secret), nil, nil));
189046ecee76SDavid du Colombier i = (n<MD5dlen) ? n : MD5dlen;
189146ecee76SDavid du Colombier memmove(key, obuf, i);
189246ecee76SDavid du Colombier key += i;
189346ecee76SDavid du Colombier n -= i;
189446ecee76SDavid du Colombier if(++round > sizeof salt)
189546ecee76SDavid du Colombier panic("setkey: you ask too much");
189646ecee76SDavid du Colombier }
189746ecee76SDavid du Colombier }
189846ecee76SDavid du Colombier
189946ecee76SDavid du Colombier static void
cipherfree(Conv * c)190046ecee76SDavid du Colombier cipherfree(Conv *c)
190146ecee76SDavid du Colombier {
190246ecee76SDavid du Colombier if(c->in.cipherstate) {
190346ecee76SDavid du Colombier free(c->in.cipherstate);
190446ecee76SDavid du Colombier c->in.cipherstate = nil;
190546ecee76SDavid du Colombier }
190646ecee76SDavid du Colombier if(c->out.cipherstate) {
190746ecee76SDavid du Colombier free(c->out.cipherstate);
190846ecee76SDavid du Colombier c->out.cipherstate = nil;
190946ecee76SDavid du Colombier }
191046ecee76SDavid du Colombier c->in.cipher = nil;
191146ecee76SDavid du Colombier c->in.cipherblklen = 0;
191246ecee76SDavid du Colombier c->out.cipherblklen = 0;
191346ecee76SDavid du Colombier c->in.cipherivlen = 0;
191446ecee76SDavid du Colombier c->out.cipherivlen = 0;
191546ecee76SDavid du Colombier }
191646ecee76SDavid du Colombier
191746ecee76SDavid du Colombier static void
authfree(Conv * c)191846ecee76SDavid du Colombier authfree(Conv *c)
191946ecee76SDavid du Colombier {
192046ecee76SDavid du Colombier if(c->in.authstate) {
192146ecee76SDavid du Colombier free(c->in.authstate);
192246ecee76SDavid du Colombier c->in.authstate = nil;
192346ecee76SDavid du Colombier }
192446ecee76SDavid du Colombier if(c->out.authstate) {
192546ecee76SDavid du Colombier free(c->out.authstate);
192646ecee76SDavid du Colombier c->out.authstate = nil;
192746ecee76SDavid du Colombier }
192846ecee76SDavid du Colombier c->in.auth = nil;
192946ecee76SDavid du Colombier c->in.authlen = 0;
193046ecee76SDavid du Colombier c->out.authlen = 0;
193146ecee76SDavid du Colombier }
193246ecee76SDavid du Colombier
193346ecee76SDavid du Colombier static void
compfree(Conv * c)193446ecee76SDavid du Colombier compfree(Conv *c)
193546ecee76SDavid du Colombier {
193646ecee76SDavid du Colombier if(c->in.compstate) {
193746ecee76SDavid du Colombier free(c->in.compstate);
193846ecee76SDavid du Colombier c->in.compstate = nil;
193946ecee76SDavid du Colombier }
194046ecee76SDavid du Colombier if(c->out.compstate) {
194146ecee76SDavid du Colombier free(c->out.compstate);
194246ecee76SDavid du Colombier c->out.compstate = nil;
194346ecee76SDavid du Colombier }
194446ecee76SDavid du Colombier c->in.comp = nil;
194546ecee76SDavid du Colombier }
194646ecee76SDavid du Colombier
194746ecee76SDavid du Colombier static void
nullcipherinit(Conv * c)194846ecee76SDavid du Colombier nullcipherinit(Conv *c)
194946ecee76SDavid du Colombier {
195046ecee76SDavid du Colombier cipherfree(c);
195146ecee76SDavid du Colombier }
195246ecee76SDavid du Colombier
195346ecee76SDavid du Colombier static int
desencrypt(OneWay * ow,uchar * p,int n)195446ecee76SDavid du Colombier desencrypt(OneWay *ow, uchar *p, int n)
195546ecee76SDavid du Colombier {
195646ecee76SDavid du Colombier uchar *pp, *ip, *eip, *ep;
195746ecee76SDavid du Colombier DESstate *ds = ow->cipherstate;
195846ecee76SDavid du Colombier
195946ecee76SDavid du Colombier if(n < 8 || (n & 0x7 != 0))
196046ecee76SDavid du Colombier return 0;
196146ecee76SDavid du Colombier ep = p + n;
196246ecee76SDavid du Colombier memmove(p, ds->ivec, 8);
196346ecee76SDavid du Colombier for(p += 8; p < ep; p += 8){
196446ecee76SDavid du Colombier pp = p;
196546ecee76SDavid du Colombier ip = ds->ivec;
196646ecee76SDavid du Colombier for(eip = ip+8; ip < eip; )
196746ecee76SDavid du Colombier *pp++ ^= *ip++;
196846ecee76SDavid du Colombier block_cipher(ds->expanded, p, 0);
196946ecee76SDavid du Colombier memmove(ds->ivec, p, 8);
197046ecee76SDavid du Colombier }
197146ecee76SDavid du Colombier return 1;
197246ecee76SDavid du Colombier }
197346ecee76SDavid du Colombier
197446ecee76SDavid du Colombier static int
desdecrypt(OneWay * ow,uchar * p,int n)197546ecee76SDavid du Colombier desdecrypt(OneWay *ow, uchar *p, int n)
197646ecee76SDavid du Colombier {
197746ecee76SDavid du Colombier uchar tmp[8];
197846ecee76SDavid du Colombier uchar *tp, *ip, *eip, *ep;
197946ecee76SDavid du Colombier DESstate *ds = ow->cipherstate;
198046ecee76SDavid du Colombier
198146ecee76SDavid du Colombier if(n < 8 || (n & 0x7 != 0))
198246ecee76SDavid du Colombier return 0;
198346ecee76SDavid du Colombier ep = p + n;
198446ecee76SDavid du Colombier memmove(ds->ivec, p, 8);
198546ecee76SDavid du Colombier p += 8;
198646ecee76SDavid du Colombier while(p < ep){
198746ecee76SDavid du Colombier memmove(tmp, p, 8);
198846ecee76SDavid du Colombier block_cipher(ds->expanded, p, 1);
198946ecee76SDavid du Colombier tp = tmp;
199046ecee76SDavid du Colombier ip = ds->ivec;
199146ecee76SDavid du Colombier for(eip = ip+8; ip < eip; ){
199246ecee76SDavid du Colombier *p++ ^= *ip;
199346ecee76SDavid du Colombier *ip++ = *tp++;
199446ecee76SDavid du Colombier }
199546ecee76SDavid du Colombier }
199646ecee76SDavid du Colombier return 1;
199746ecee76SDavid du Colombier }
199846ecee76SDavid du Colombier
199946ecee76SDavid du Colombier static void
descipherinit(Conv * c)200046ecee76SDavid du Colombier descipherinit(Conv *c)
200146ecee76SDavid du Colombier {
200246ecee76SDavid du Colombier uchar key[8];
200346ecee76SDavid du Colombier uchar ivec[8];
200446ecee76SDavid du Colombier int i;
200546ecee76SDavid du Colombier int n = c->cipher->keylen;
200646ecee76SDavid du Colombier
200746ecee76SDavid du Colombier cipherfree(c);
200846ecee76SDavid du Colombier
200946ecee76SDavid du Colombier if(n > sizeof(key))
201046ecee76SDavid du Colombier n = sizeof(key);
201146ecee76SDavid du Colombier
201246ecee76SDavid du Colombier /* in */
201346ecee76SDavid du Colombier memset(key, 0, sizeof(key));
201446ecee76SDavid du Colombier setkey(key, n, &c->in, "cipher");
201546ecee76SDavid du Colombier memset(ivec, 0, sizeof(ivec));
201646ecee76SDavid du Colombier c->in.cipherblklen = 8;
201746ecee76SDavid du Colombier c->in.cipherivlen = 8;
201846ecee76SDavid du Colombier c->in.cipher = desdecrypt;
201946ecee76SDavid du Colombier c->in.cipherstate = smalloc(sizeof(DESstate));
202046ecee76SDavid du Colombier setupDESstate(c->in.cipherstate, key, ivec);
202146ecee76SDavid du Colombier
202246ecee76SDavid du Colombier /* out */
202346ecee76SDavid du Colombier memset(key, 0, sizeof(key));
202446ecee76SDavid du Colombier setkey(key, n, &c->out, "cipher");
202546ecee76SDavid du Colombier for(i=0; i<8; i++)
202646ecee76SDavid du Colombier ivec[i] = nrand(256);
202746ecee76SDavid du Colombier c->out.cipherblklen = 8;
202846ecee76SDavid du Colombier c->out.cipherivlen = 8;
202946ecee76SDavid du Colombier c->out.cipher = desencrypt;
203046ecee76SDavid du Colombier c->out.cipherstate = smalloc(sizeof(DESstate));
203146ecee76SDavid du Colombier setupDESstate(c->out.cipherstate, key, ivec);
203246ecee76SDavid du Colombier }
203346ecee76SDavid du Colombier
203446ecee76SDavid du Colombier static int
rc4encrypt(OneWay * ow,uchar * p,int n)203546ecee76SDavid du Colombier rc4encrypt(OneWay *ow, uchar *p, int n)
203646ecee76SDavid du Colombier {
203746ecee76SDavid du Colombier CipherRc4 *cr = ow->cipherstate;
203846ecee76SDavid du Colombier
203946ecee76SDavid du Colombier if(n < 4)
204046ecee76SDavid du Colombier return 0;
204146ecee76SDavid du Colombier
204246ecee76SDavid du Colombier hnputl(p, cr->cseq);
204346ecee76SDavid du Colombier p += 4;
204446ecee76SDavid du Colombier n -= 4;
204546ecee76SDavid du Colombier rc4(&cr->current, p, n);
204646ecee76SDavid du Colombier cr->cseq += n;
204746ecee76SDavid du Colombier return 1;
204846ecee76SDavid du Colombier }
204946ecee76SDavid du Colombier
205046ecee76SDavid du Colombier static int
rc4decrypt(OneWay * ow,uchar * p,int n)205146ecee76SDavid du Colombier rc4decrypt(OneWay *ow, uchar *p, int n)
205246ecee76SDavid du Colombier {
205346ecee76SDavid du Colombier CipherRc4 *cr = ow->cipherstate;
205446ecee76SDavid du Colombier RC4state tmpstate;
205546ecee76SDavid du Colombier ulong seq;
205646ecee76SDavid du Colombier long d, dd;
205746ecee76SDavid du Colombier
205846ecee76SDavid du Colombier if(n < 4)
205946ecee76SDavid du Colombier return 0;
206046ecee76SDavid du Colombier
206146ecee76SDavid du Colombier seq = nhgetl(p);
206246ecee76SDavid du Colombier p += 4;
206346ecee76SDavid du Colombier n -= 4;
206446ecee76SDavid du Colombier d = seq-cr->cseq;
206546ecee76SDavid du Colombier if(d == 0) {
206646ecee76SDavid du Colombier rc4(&cr->current, p, n);
206746ecee76SDavid du Colombier cr->cseq += n;
206846ecee76SDavid du Colombier if(cr->ovalid) {
206946ecee76SDavid du Colombier dd = cr->cseq - cr->lgseq;
207046ecee76SDavid du Colombier if(dd > RC4back)
207146ecee76SDavid du Colombier cr->ovalid = 0;
207246ecee76SDavid du Colombier }
207346ecee76SDavid du Colombier } else if(d > 0) {
207446ecee76SDavid du Colombier //print("missing packet: %uld %ld\n", seq, d);
207546ecee76SDavid du Colombier // this link is hosed
207646ecee76SDavid du Colombier if(d > RC4forward)
207746ecee76SDavid du Colombier return 0;
207846ecee76SDavid du Colombier cr->lgseq = seq;
207946ecee76SDavid du Colombier if(!cr->ovalid) {
208046ecee76SDavid du Colombier cr->ovalid = 1;
208146ecee76SDavid du Colombier cr->oseq = cr->cseq;
208246ecee76SDavid du Colombier memmove(&cr->old, &cr->current, sizeof(RC4state));
208346ecee76SDavid du Colombier }
208446ecee76SDavid du Colombier rc4skip(&cr->current, d);
208546ecee76SDavid du Colombier rc4(&cr->current, p, n);
208646ecee76SDavid du Colombier cr->cseq = seq+n;
208746ecee76SDavid du Colombier } else {
208846ecee76SDavid du Colombier //print("reordered packet: %uld %ld\n", seq, d);
208946ecee76SDavid du Colombier dd = seq - cr->oseq;
209046ecee76SDavid du Colombier if(!cr->ovalid || -d > RC4back || dd < 0)
209146ecee76SDavid du Colombier return 0;
209246ecee76SDavid du Colombier memmove(&tmpstate, &cr->old, sizeof(RC4state));
209346ecee76SDavid du Colombier rc4skip(&tmpstate, dd);
209446ecee76SDavid du Colombier rc4(&tmpstate, p, n);
209546ecee76SDavid du Colombier return 1;
209646ecee76SDavid du Colombier }
209746ecee76SDavid du Colombier
209846ecee76SDavid du Colombier // move old state up
209946ecee76SDavid du Colombier if(cr->ovalid) {
210046ecee76SDavid du Colombier dd = cr->cseq - RC4back - cr->oseq;
210146ecee76SDavid du Colombier if(dd > 0) {
210246ecee76SDavid du Colombier rc4skip(&cr->old, dd);
210346ecee76SDavid du Colombier cr->oseq += dd;
210446ecee76SDavid du Colombier }
210546ecee76SDavid du Colombier }
210646ecee76SDavid du Colombier
210746ecee76SDavid du Colombier return 1;
210846ecee76SDavid du Colombier }
210946ecee76SDavid du Colombier
211046ecee76SDavid du Colombier static void
rc4cipherinit(Conv * c)211146ecee76SDavid du Colombier rc4cipherinit(Conv *c)
211246ecee76SDavid du Colombier {
211346ecee76SDavid du Colombier uchar key[32];
211446ecee76SDavid du Colombier CipherRc4 *cr;
211546ecee76SDavid du Colombier int n;
211646ecee76SDavid du Colombier
211746ecee76SDavid du Colombier cipherfree(c);
211846ecee76SDavid du Colombier
211946ecee76SDavid du Colombier n = c->cipher->keylen;
212046ecee76SDavid du Colombier if(n > sizeof(key))
212146ecee76SDavid du Colombier n = sizeof(key);
212246ecee76SDavid du Colombier
212346ecee76SDavid du Colombier /* in */
212446ecee76SDavid du Colombier memset(key, 0, sizeof(key));
212546ecee76SDavid du Colombier setkey(key, n, &c->in, "cipher");
212646ecee76SDavid du Colombier c->in.cipherblklen = 1;
212746ecee76SDavid du Colombier c->in.cipherivlen = 4;
212846ecee76SDavid du Colombier c->in.cipher = rc4decrypt;
212946ecee76SDavid du Colombier cr = smalloc(sizeof(CipherRc4));
213046ecee76SDavid du Colombier memset(cr, 0, sizeof(*cr));
213146ecee76SDavid du Colombier setupRC4state(&cr->current, key, n);
213246ecee76SDavid du Colombier c->in.cipherstate = cr;
213346ecee76SDavid du Colombier
213446ecee76SDavid du Colombier /* out */
213546ecee76SDavid du Colombier memset(key, 0, sizeof(key));
213646ecee76SDavid du Colombier setkey(key, n, &c->out, "cipher");
213746ecee76SDavid du Colombier c->out.cipherblklen = 1;
213846ecee76SDavid du Colombier c->out.cipherivlen = 4;
213946ecee76SDavid du Colombier c->out.cipher = rc4encrypt;
214046ecee76SDavid du Colombier cr = smalloc(sizeof(CipherRc4));
214146ecee76SDavid du Colombier memset(cr, 0, sizeof(*cr));
214246ecee76SDavid du Colombier setupRC4state(&cr->current, key, n);
214346ecee76SDavid du Colombier c->out.cipherstate = cr;
214446ecee76SDavid du Colombier }
214546ecee76SDavid du Colombier
214646ecee76SDavid du Colombier static void
nullauthinit(Conv * c)214746ecee76SDavid du Colombier nullauthinit(Conv *c)
214846ecee76SDavid du Colombier {
214946ecee76SDavid du Colombier authfree(c);
215046ecee76SDavid du Colombier }
215146ecee76SDavid du Colombier
215246ecee76SDavid du Colombier static void
shaauthinit(Conv * c)215346ecee76SDavid du Colombier shaauthinit(Conv *c)
215446ecee76SDavid du Colombier {
215546ecee76SDavid du Colombier authfree(c);
215646ecee76SDavid du Colombier }
215746ecee76SDavid du Colombier
215846ecee76SDavid du Colombier static void
seanq_hmac_md5(uchar hash[MD5dlen],ulong wrap,uchar * t,long tlen,uchar * key,long klen)215946ecee76SDavid du Colombier seanq_hmac_md5(uchar hash[MD5dlen], ulong wrap, uchar *t, long tlen, uchar *key, long klen)
216046ecee76SDavid du Colombier {
216146ecee76SDavid du Colombier uchar ipad[65], opad[65], wbuf[4];
216246ecee76SDavid du Colombier int i;
216346ecee76SDavid du Colombier DigestState *digest;
216446ecee76SDavid du Colombier uchar innerhash[MD5dlen];
216546ecee76SDavid du Colombier
216646ecee76SDavid du Colombier for(i=0; i<64; i++){
216746ecee76SDavid du Colombier ipad[i] = 0x36;
216846ecee76SDavid du Colombier opad[i] = 0x5c;
216946ecee76SDavid du Colombier }
217046ecee76SDavid du Colombier ipad[64] = opad[64] = 0;
217146ecee76SDavid du Colombier for(i=0; i<klen; i++){
217246ecee76SDavid du Colombier ipad[i] ^= key[i];
217346ecee76SDavid du Colombier opad[i] ^= key[i];
217446ecee76SDavid du Colombier }
217546ecee76SDavid du Colombier hnputl(wbuf, wrap);
217646ecee76SDavid du Colombier digest = md5(ipad, 64, nil, nil);
217746ecee76SDavid du Colombier digest = md5(wbuf, sizeof(wbuf), nil, digest);
217846ecee76SDavid du Colombier md5(t, tlen, innerhash, digest);
217946ecee76SDavid du Colombier digest = md5(opad, 64, nil, nil);
218046ecee76SDavid du Colombier md5(innerhash, MD5dlen, hash, digest);
218146ecee76SDavid du Colombier }
218246ecee76SDavid du Colombier
218346ecee76SDavid du Colombier static int
md5auth(OneWay * ow,uchar * t,int tlen)218446ecee76SDavid du Colombier md5auth(OneWay *ow, uchar *t, int tlen)
218546ecee76SDavid du Colombier {
218646ecee76SDavid du Colombier uchar hash[MD5dlen];
218746ecee76SDavid du Colombier int r;
218846ecee76SDavid du Colombier
218946ecee76SDavid du Colombier if(tlen < ow->authlen)
219046ecee76SDavid du Colombier return 0;
219146ecee76SDavid du Colombier tlen -= ow->authlen;
219246ecee76SDavid du Colombier
219346ecee76SDavid du Colombier memset(hash, 0, MD5dlen);
219446ecee76SDavid du Colombier seanq_hmac_md5(hash, ow->seqwrap, t, tlen, (uchar*)ow->authstate, 16);
219546ecee76SDavid du Colombier r = memcmp(t+tlen, hash, ow->authlen) == 0;
219646ecee76SDavid du Colombier memmove(t+tlen, hash, ow->authlen);
219746ecee76SDavid du Colombier return r;
219846ecee76SDavid du Colombier }
219946ecee76SDavid du Colombier
220046ecee76SDavid du Colombier static void
md5authinit(Conv * c)220146ecee76SDavid du Colombier md5authinit(Conv *c)
220246ecee76SDavid du Colombier {
220346ecee76SDavid du Colombier int keylen;
220446ecee76SDavid du Colombier
220546ecee76SDavid du Colombier authfree(c);
220646ecee76SDavid du Colombier
220746ecee76SDavid du Colombier keylen = c->auth->keylen;
220846ecee76SDavid du Colombier if(keylen > 16)
220946ecee76SDavid du Colombier keylen = 16;
221046ecee76SDavid du Colombier
221146ecee76SDavid du Colombier /* in */
221246ecee76SDavid du Colombier c->in.authstate = smalloc(16);
221346ecee76SDavid du Colombier memset(c->in.authstate, 0, 16);
221446ecee76SDavid du Colombier setkey(c->in.authstate, keylen, &c->in, "auth");
221546ecee76SDavid du Colombier c->in.authlen = 12;
221646ecee76SDavid du Colombier c->in.auth = md5auth;
221746ecee76SDavid du Colombier
221846ecee76SDavid du Colombier /* out */
221946ecee76SDavid du Colombier c->out.authstate = smalloc(16);
222046ecee76SDavid du Colombier memset(c->out.authstate, 0, 16);
222146ecee76SDavid du Colombier setkey(c->out.authstate, keylen, &c->out, "auth");
222246ecee76SDavid du Colombier c->out.authlen = 12;
222346ecee76SDavid du Colombier c->out.auth = md5auth;
222446ecee76SDavid du Colombier }
222546ecee76SDavid du Colombier
222646ecee76SDavid du Colombier static void
nullcompinit(Conv * c)222746ecee76SDavid du Colombier nullcompinit(Conv *c)
222846ecee76SDavid du Colombier {
222946ecee76SDavid du Colombier compfree(c);
223046ecee76SDavid du Colombier }
223146ecee76SDavid du Colombier
223246ecee76SDavid du Colombier static int
thwackcomp(Conv * c,int,ulong seq,Block ** bp)223346ecee76SDavid du Colombier thwackcomp(Conv *c, int, ulong seq, Block **bp)
223446ecee76SDavid du Colombier {
223546ecee76SDavid du Colombier Block *b, *bb;
223646ecee76SDavid du Colombier int nn;
223746ecee76SDavid du Colombier ulong ackseq;
223846ecee76SDavid du Colombier uchar mask;
223946ecee76SDavid du Colombier
224046ecee76SDavid du Colombier // add ack info
224146ecee76SDavid du Colombier b = padblock(*bp, 4);
224246ecee76SDavid du Colombier
224346ecee76SDavid du Colombier ackseq = unthwackstate(c->in.compstate, &mask);
224446ecee76SDavid du Colombier b->rp[0] = mask;
224546ecee76SDavid du Colombier b->rp[1] = ackseq>>16;
224646ecee76SDavid du Colombier b->rp[2] = ackseq>>8;
224746ecee76SDavid du Colombier b->rp[3] = ackseq;
224846ecee76SDavid du Colombier
224946ecee76SDavid du Colombier bb = allocb(BLEN(b));
225046ecee76SDavid du Colombier nn = thwack(c->out.compstate, bb->wp, b->rp, BLEN(b), seq, c->lstats.outCompStats);
225146ecee76SDavid du Colombier if(nn < 0) {
225246ecee76SDavid du Colombier freeb(bb);
225346ecee76SDavid du Colombier *bp = b;
225446ecee76SDavid du Colombier return ThwackU;
225546ecee76SDavid du Colombier } else {
225646ecee76SDavid du Colombier bb->wp += nn;
225746ecee76SDavid du Colombier freeb(b);
225846ecee76SDavid du Colombier *bp = bb;
225946ecee76SDavid du Colombier return ThwackC;
226046ecee76SDavid du Colombier }
226146ecee76SDavid du Colombier }
226246ecee76SDavid du Colombier
226346ecee76SDavid du Colombier static int
thwackuncomp(Conv * c,int subtype,ulong seq,Block ** bp)226446ecee76SDavid du Colombier thwackuncomp(Conv *c, int subtype, ulong seq, Block **bp)
226546ecee76SDavid du Colombier {
226646ecee76SDavid du Colombier Block *b, *bb;
226746ecee76SDavid du Colombier ulong mask;
226846ecee76SDavid du Colombier ulong mseq;
226946ecee76SDavid du Colombier int n;
227046ecee76SDavid du Colombier
227146ecee76SDavid du Colombier switch(subtype) {
227246ecee76SDavid du Colombier default:
227346ecee76SDavid du Colombier return 0;
227446ecee76SDavid du Colombier case ThwackU:
227546ecee76SDavid du Colombier b = *bp;
227646ecee76SDavid du Colombier mask = b->rp[0];
227746ecee76SDavid du Colombier mseq = (b->rp[1]<<16) | (b->rp[2]<<8) | b->rp[3];
227846ecee76SDavid du Colombier b->rp += 4;
227946ecee76SDavid du Colombier thwackack(c->out.compstate, mseq, mask);
228046ecee76SDavid du Colombier return 1;
228146ecee76SDavid du Colombier case ThwackC:
228246ecee76SDavid du Colombier bb = *bp;
228346ecee76SDavid du Colombier b = allocb(ThwMaxBlock);
228446ecee76SDavid du Colombier n = unthwack(c->in.compstate, b->wp, ThwMaxBlock, bb->rp, BLEN(bb), seq);
228546ecee76SDavid du Colombier freeb(bb);
2286d9814433SDavid du Colombier *bp = nil;
228746ecee76SDavid du Colombier if(n < 0) {
228846ecee76SDavid du Colombier if(0)print("unthwack failed: %d\n", n);
228946ecee76SDavid du Colombier freeb(b);
229046ecee76SDavid du Colombier return 0;
229146ecee76SDavid du Colombier }
229246ecee76SDavid du Colombier b->wp += n;
229346ecee76SDavid du Colombier mask = b->rp[0];
229446ecee76SDavid du Colombier mseq = (b->rp[1]<<16) | (b->rp[2]<<8) | b->rp[3];
229546ecee76SDavid du Colombier thwackack(c->out.compstate, mseq, mask);
229646ecee76SDavid du Colombier b->rp += 4;
229746ecee76SDavid du Colombier *bp = b;
229846ecee76SDavid du Colombier return 1;
229946ecee76SDavid du Colombier }
230046ecee76SDavid du Colombier }
230146ecee76SDavid du Colombier
230246ecee76SDavid du Colombier static void
thwackcompinit(Conv * c)230346ecee76SDavid du Colombier thwackcompinit(Conv *c)
230446ecee76SDavid du Colombier {
230546ecee76SDavid du Colombier compfree(c);
230646ecee76SDavid du Colombier
230746ecee76SDavid du Colombier c->in.compstate = malloc(sizeof(Unthwack));
230846ecee76SDavid du Colombier if(c->in.compstate == nil)
230946ecee76SDavid du Colombier error(Enomem);
231046ecee76SDavid du Colombier unthwackinit(c->in.compstate);
231146ecee76SDavid du Colombier c->out.compstate = malloc(sizeof(Thwack));
231246ecee76SDavid du Colombier if(c->out.compstate == nil)
231346ecee76SDavid du Colombier error(Enomem);
231446ecee76SDavid du Colombier thwackinit(c->out.compstate);
231546ecee76SDavid du Colombier c->in.comp = thwackuncomp;
231646ecee76SDavid du Colombier c->out.comp = thwackcomp;
231746ecee76SDavid du Colombier }
2318