## diffname port/devsdp.c 1999/0824
## diff -e /dev/null /n/emeliedump/1999/0824/sys/src/brazil/port/devsdp.c
0a
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "../port/netif.h"
#include "../port/error.h"
#include <libcrypt.h>
typedef struct Sdp Sdp;
typedef struct Port Port;
enum
{
Qtopdir= 1, /* top level directory */
Qsdpdir, /* sdp directory */
Qclone,
Qstats,
Qlog,
Qportdir, /* directory for a protocol */
Qctl,
Qdata, /* reliable control channel */
Qpacket, /* unreliable packet channel */
Qerr,
Qlisten,
Qlocal,
Qremote,
Qstatus,
MaxQ,
Maxport= 256, // power of 2
Nfs= 4, // number of file systems
};
#define TYPE(x) ((x).path & 0xff)
#define PORT(x) (((x).path >> 8)&(Maxport-1))
#define QID(x, y) (((x)<<8) | (y))
struct Port {
int id;
Sdp *sdp;
int ref;
int closed;
};
struct Sdp {
QLock;
Log;
int nport;
Port *port[Maxport];
};
static Dirtab sdpdirtab[]={
"ctl", {Qctl}, 0, 0666,
"stats", {Qstats}, 0, 0444,
"log", {Qlog}, 0, 0666,
};
static Dirtab portdirtab[]={
"ctl", {Qctl}, 0, 0666,
"data", {Qdata}, 0, 0666,
"packet", {Qpacket}, 0, 0666,
"listen", {Qlisten}, 0, 0666,
"local", {Qlocal}, 0, 0444,
"remote", {Qlocal}, 0, 0444,
"status", {Qstatus}, 0, 0444,
};
static int m2p[] = {
[OREAD] 4,
[OWRITE] 2,
[ORDWR] 6
};
enum {
Logcompress= (1<<0),
Logauth= (1<<1),
Loghmac= (1<<2),
};
static Logflag logflags[] =
{
{ "compress", Logcompress, },
{ "auth", Logauth, },
{ "hmac", Loghmac, },
{ nil, 0, },
};
static Dirtab *dirtab[MaxQ];
static Sdp sdptab[Nfs];
static int sdpgen(Chan *c, Dirtab*, int, int s, Dir *dp);
static void
sdpinit(void)
{
int i;
Dirtab *dt;
// setup dirtab with non directory entries
for(i=0; i<nelem(sdpdirtab); i++) {
dt = sdpdirtab + i;
dirtab[TYPE(dt->qid)] = dt;
}
for(i=0; i<nelem(portdirtab); i++) {
dt = portdirtab + i;
dirtab[TYPE(dt->qid)] = dt;
}
}
static Chan*
sdpattach(char* spec)
{
Chan *c;
int dev;
dev = atoi(spec);
if(dev<0 || dev >= Nfs)
error("bad specification");
c = devattach('B', spec);
c->qid = (Qid){QID(0, Qtopdir)|CHDIR, 0};
c->dev = dev;
return c;
}
static int
sdpwalk(Chan *c, char *name)
{
if(strcmp(name, "..") == 0){
switch(TYPE(c->qid)){
case Qtopdir:
case Qsdpdir:
c->qid = (Qid){CHDIR|Qtopdir, 0};
break;
case Qportdir:
c->qid = (Qid){CHDIR|Qsdpdir, 0};
break;
default:
panic("sdpwalk %lux", c->qid.path);
}
return 1;
}
return devwalk(c, name, 0, 0, sdpgen);
}
static void
sdpstat(Chan* c, char* db)
{
devstat(c, db, nil, 0, sdpgen);
}
static Chan*
sdpopen(Chan* c, int omode)
{
int perm;
Sdp *sdp;
omode &= 3;
perm = m2p[omode];
USED(perm);
sdp = sdptab + c->dev;
switch(TYPE(c->qid)) {
default:
break;
case Qtopdir:
case Qsdpdir:
case Qportdir:
case Qstatus:
case Qlocal:
case Qstats:
if(omode != OREAD)
error(Eperm);
break;
case Qlog:
logopen(sdp);
break;
}
c->mode = openmode(omode);
c->flag |= COPEN;
c->offset = 0;
return c;
}
static void
sdpclose(Chan* c)
{
Sdp *sdp = sdptab + c->dev;
switch(TYPE(c->qid)) {
case Qlog:
if(c->flag & COPEN)
logclose(sdp);
break;
}
}
static long
sdpread(Chan *c, void *a, long n, vlong off)
{
char buf[256];
Sdp *sdp = sdptab + c->dev;
Port *port;
USED(off);
switch(TYPE(c->qid)) {
default:
error(Eperm);
case Qtopdir:
case Qsdpdir:
case Qportdir:
return devdirread(c, a, n, 0, 0, sdpgen);
case Qlog:
return logread(sdp, a, off, n);
case Qstatus:
qlock(sdp);
port = sdp->port[PORT(c->qid)];
if(port == 0)
strcpy(buf, "unbound\n");
else {
}
n = readstr(off, a, n, buf);
qunlock(sdp);
return n;
}
}
static long
sdpwrite(Chan *c, void *a, long n, vlong off)
{
Sdp *sdp = sdptab + c->dev;
Cmdbuf *cb;
char *arg0;
char *p;
USED(off);
switch(TYPE(c->qid)) {
default:
error(Eperm);
case Qctl:
cb = parsecmd(a, n);
qlock(sdp);
if(waserror()) {
qunlock(sdp);
free(cb);
nexterror();
}
if(cb->nf == 0)
error("short write");
arg0 = cb->f[0];
if(strcmp(arg0, "xxx") == 0) {
print("xxx\n");
} else
error("unknown control request");
poperror();
qunlock(sdp);
free(cb);
return n;
case Qlog:
cb = parsecmd(a, n);
p = logctl(sdp, cb->nf, cb->f, logflags);
free(cb);
if(p != nil)
error(p);
return n;
}
}
static int
sdpgen(Chan *c, Dirtab*, int, int s, Dir *dp)
{
Sdp *sdp = sdptab + c->dev;
int type = TYPE(c->qid);
char buf[32];
Dirtab *dt;
Qid qid;
switch(type) {
default:
// non directory entries end up here
if(c->qid.path & CHDIR)
panic("sdpgen: unexpected directory");
if(s != 0)
return -1;
dt = dirtab[TYPE(c->qid)];
if(dt == nil)
panic("sdpgen: unknown type: %d", TYPE(c->qid));
devdir(c, c->qid, dt->name, dt->length, eve, dt->perm, dp);
return 1;
case Qtopdir:
if(s != 0)
return -1;
devdir(c, (Qid){QID(0,Qsdpdir)|CHDIR,0}, "sdp", 0, eve, 0555, dp);
return 1;
case Qsdpdir:
if(s<nelem(sdpdirtab)) {
dt = sdpdirtab+s;
devdir(c, dt->qid, dt->name, dt->length, eve, dt->perm, dp);
return 1;
}
s -= nelem(sdpdirtab);
if(s >= sdp->nport)
return -1;
qid = (Qid){QID(s,Qportdir)|CHDIR, 0};
snprint(buf, sizeof(buf), "%d", s);
devdir(c, qid, buf, 0, eve, 0555, dp);
return 1;
case Qportdir:
if(s>=nelem(portdirtab))
return -1;
dt = portdirtab+s;
qid = (Qid){QID(PORT(c->qid),TYPE(dt->qid)),0};
devdir(c, qid, dt->name, dt->length, eve, dt->perm, dp);
return 1;
}
}
Dev sdpdevtab = {
'T',
"sdp",
devreset,
sdpinit,
sdpattach,
devclone,
sdpwalk,
sdpstat,
sdpopen,
devcreate,
sdpclose,
sdpread,
devbread,
sdpwrite,
devbwrite,
devremove,
devwstat,
};
.
## diffname port/devsdp.c 1999/0901
## diff -e /n/emeliedump/1999/0824/sys/src/brazil/port/devsdp.c /n/emeliedump/1999/0901/sys/src/brazil/port/devsdp.c
325a
}
static Conv*
sdpclone(Sdp *sdp)
{
Conv *c, **pp, **ep;
c = nil;
ep = sdp->conv + nelem(sdp->conv);
for(pp = sdp->conv; pp < ep; pp++) {
c = *pp;
if(c == nil){
c = malloc(sizeof(Conv));
if(c == nil)
error(Enomem);
qlock(c);
c->sdp = sdp;
c->id = pp - sdp->conv;
*pp = c;
sdp->nconv++;
break;
}
if(canqlock(c)){
if(c->inuse == 0)
break;
qunlock(c);
}
}
if(pp >= ep) {
return nil;
}
c->inuse = 1;
strncpy(c->user, up->user, sizeof(c->user));
c->perm = 0660;
c->state = 0;
qunlock(c);
return c;
.
321,322c
dt = convdirtab+s;
qid = (Qid){QID(CONV(c->qid),TYPE(dt->qid)),0};
.
318,319c
case Qconvdir:
if(s>=nelem(convdirtab))
.
314c
qid = (Qid){QID(s,Qconvdir)|CHDIR, 0};
.
312c
if(s >= sdp->nconv)
.
260a
print("cmd = %s\n", arg0);
.
247c
switch(TYPE(ch->qid)) {
.
241c
Sdp *sdp = sdptab + ch->dev;
.
239c
sdpwrite(Chan *ch, void *a, long n, vlong off)
.
235d
233a
case Qctl:
sprint(buf, "%lud", CONV(ch->qid));
return readstr(off, a, n, buf);
.
226,227c
c = sdp->conv[CONV(ch->qid)];
if(c == 0)
.
220,221c
case Qconvdir:
return devdirread(ch, a, n, 0, 0, sdpgen);
.
215c
switch(TYPE(ch->qid)) {
.
211,212c
Sdp *sdp = sdptab + ch->dev;
Conv *c;
.
208c
sdpread(Chan *ch, void *a, long n, vlong off)
.
188,191c
ch->mode = openmode(omode);
ch->flag |= COPEN;
ch->offset = 0;
return ch;
.
186a
case Qclone:
c = sdpclone(sdp);
if(c == nil)
error(Enodev);
ch->qid.path = QID(c->id, Qctl);
break;
.
179d
177c
case Qconvdir:
.
172c
switch(TYPE(ch->qid)) {
.
170c
sdp = sdptab + ch->dev;
.
164a
Conv *c;
.
161c
sdpopen(Chan* ch, int omode)
.
142c
case Qconvdir:
.
126c
c = devattach('T', spec);
.
110,111c
for(i=0; i<nelem(convdirtab); i++) {
dt = convdirtab + i;
.
96a
static Conv *sdpclone(Sdp *sdp);
.
67,69d
63c
static Dirtab convdirtab[]={
.
60a
"clone", {Qclone}, 0, 0666,
.
58d
53,54c
int nconv;
Conv *conv[Maxconv];
.
46,47c
Chan chan; // packet channel
char user[NAMELEN]; /* protections */
int perm;
int inuse;
int length;
int state;
OneWay in;
OneWay out;
.
43c
struct OneWay
{
ulong seqwrap; // number of wraps of the sequence number
ulong seq;
ulong window; // for replay attacks
char *calg;
void *cstate; // state cipher
int civlen; // in bytes
int (*cipher)(OneWay*, uchar *buf, int len);
char *aalg;
void *astate; // auth state
int alen; // auth data length in bytes
int (*auth)(OneWay*, uchar *buf, int len, uchar *hash);
};
struct Conv {
QLock;
.
40c
#define CONV(x) (((x).path >> 8)&(Maxconv-1))
.
35c
Maxconv= 256, // power of 2
.
27,30d
23c
Qconvdir, /* directory per conversation */
.
12c
typedef struct Conv Conv;
typedef struct OneWay OneWay;
.
## diffname port/devsdp.c 1999/0902
## diff -e /n/emeliedump/1999/0901/sys/src/brazil/port/devsdp.c /n/emeliedump/1999/0902/sys/src/brazil/port/devsdp.c
400a
static void
sdpconvfree(Conv *c)
{
qlock(c);
c->ref--;
if(c->ref < 0)
panic("convfree: bad ref");
if(c->ref > 0) {
qunlock(c);
return;
}
memset(&c->in, 0, sizeof(c->in));
memset(&c->out, 0, sizeof(c->out));
if(c->chan) {
cclose(c->chan);
c->chan = 0;
}
qunlock(c);
}
.
397a
.
395,396d
392c
c->ref++;
c->state = COpening;
.
390d
388c
if(pp >= ep)
.
386a
poperror();
qunlock(sdp);
.
383d
381c
if(c->state == CClosed)
.
366a
qlock(sdp);
if(waserror()) {
qunlock(sdp);
nexterror();
}
.
260,261c
n = readstr(off, a, n, s);
qunlock(c);
.
256,258c
qlock(c);
switch(c->state) {
default:
panic("unknown state");
case CClosed:
s = "closed";
break;
case COpening:
s = "opening";
break;
case COpen:
s = "open";
break;
case CClosing:
s = "closing";
break;
.
254d
240a
char *s;
.
230c
if(ch->flag & COPEN)
.
228c
switch(TYPE(ch->qid)) {
.
226c
Sdp *sdp = sdptab + ch->dev;
.
224c
sdpclose(Chan* ch)
.
215a
case Qdata:
case Qctl:
case Qstatus:
case Qcontrol:
c = sdp->conv[CONV(ch->qid)];
qlock(c);
if(waserror()) {
qunlock(c);
nexterror();
}
if((perm & (c->perm>>6)) != perm)
if(strcmp(up->user, c->user) != 0 || (perm & c->perm) != perm)
error(Eperm);
c->ref++;
qunlock(c);
poperror();
break;
.
202d
91c
"control", {Qcontrol}, 0, 0666,
.
79c
Conv *conv[Maxconv];
.
71,72c
In in;
Out out;
.
67,69d
64a
Chan *chan; // packet channel
.
63c
int state;
ulong session;
.
60a
int ref;
.
59d
56a
struct In
{
ulong seqwrap; // number of wraps of the sequence number
ulong seq;
ulong window;
Block *controlpkt;
ulong controlseq;
void *cipherstate; // state cipher
int ivlen; // in bytes
int (*decrypt)(In*, uchar *buf, int len);
void *authstate; // auth state
int authlen; // auth data length in bytes
int (*auth)(In*, uchar *buf, int len);
void *uncompstate;
int (*uncomp)(In*, uchar *dst, uchar *src, int n);
};
enum {
CClosed,
COpening,
COpen,
CClosing,
};
.
51,54c
void *cipherstate; // state cipher
int ivlen; // in bytes
int (*encrypt)(Out*, uchar *buf, int len);
void *authstate; // auth state
int authlen; // auth data length in bytes
int (*auth)(Out*, uchar *buf, int len);
void *compstate;
int (*comp)(Out*, uchar *dst, uchar *src, int n);
.
46,49c
Block *controlpkt; // control channel
ulong *controlseq;
ulong controltimeout; // timeout when it will be resent
int controlretries;
.
44d
40c
struct Out
.
26,27c
Qdata, /* unreliable packet channel */
Qcontrol, /* reliable control channel */
.
11,13c
typedef struct Sdp Sdp;
typedef struct Conv Conv;
typedef struct Out Out;
typedef struct In In;
.
## diffname port/devsdp.c 1999/0906
## diff -e /n/emeliedump/1999/0902/sys/src/brazil/port/devsdp.c /n/emeliedump/1999/0906/sys/src/brazil/port/devsdp.c
511a
// assume hold lock on c
static void
convsetstate(Conv *c, int state)
{
switch(state) {
default:
panic("setstate: bad state: %d", state);
case COpening:
if(c->state != CInit)
error("convsetstate: illegal transition");
c->dialid = (rand()<<16) + rand();
c->timeout = TK2SEC(m->ticks) + 2;
c->retries = 0;
sendconnect(c, ConOpen, c->dialid, 0);
break;
case COpen:
switch(c->state) {
default:
error("convsetstate: illegal transition");
case CInit:
c->acceptid = (rand()<<16) + rand();
sendconnect(c, ConOpenAck, c->dialid, c->acceptid);
break;
case COpening:
break;
}
// setup initial key and auth method
break;
case CClosing:
c->timeout = TK2SEC(m->ticks) + 2;
c->retries = 0;
break;
case CClosed:
break;
}
c->state = state;
}
static void
sendconnect(Conv *c, int op, ulong dialid, ulong acceptid)
{
ConPkt con;
if(c->chan == nil) {
print("chan = nil\n");
error("no channel attached");
}
memset(&con, 0, sizeof(con));
con.type = TConnect;
con.op = op;
hnputl(con.dialid, dialid);
hnputl(con.acceptid, acceptid);
// simulated errors
if(c->drop && c->drop > nrand(c->drop))
return;
devtab[c->chan->type]->write(c->chan, &con, sizeof(con), 0);
}
.
489d
485,487c
static void
sdpackproc(void *a)
{
Sdp *sdp = a;
ulong sec;
int i;
Conv *c;
for(;;) {
tsleep(&sdp->vous, return0, 0, 1000);
sec = TK2SEC(m->ticks);
qlock(sdp);
for(i=0; i<sdp->nconv; i++) {
c = sdp->conv[i];
if(!waserror()) {
convtimer(c, sec);
poperror();
}
}
qunlock(sdp);
.
482,483d
480a
switch(c->state) {
case COpening:
print("COpening timeout\n");
if(convretry(c))
sendconnect(c, ConOpen, c->dialid, 0);
break;
case COpen:
// check for control packet
break;
case CClosing:
print("CClosing timeout\n");
if(convretry(c))
sendconnect(c, ConClose, c->dialid, c->acceptid);
break;
}
qunlock(c);
}
.
479c
nexterror();
.
474,477c
if(waserror()) {
.
472a
if(c->timeout == 0 || c->timeout > sec)
return;
.
471c
convtimer(Conv *c, ulong sec)
.
469a
// assume c is locked
static int
convretry(Conv *c)
{
c->retries++;
if(c->retries > Maxretries) {
print("convretry: giving up\n");
convsetstate(c, CClosed);
return 0;
}
c->timeout = TK2SEC(m->ticks) + (1<<c->retries);
return 1;
}
.
461c
c->state = CInit;
.
361c
qunlock(c);
.
356,357c
if(strcmp(arg0, "chan") == 0) {
if(cb->nf != 2)
error("usage: chan file");
if(c->chan != nil)
error("chan already set");
c->chan = namec(cb->f[1], Aopen, ORDWR, 0);
} else if(strcmp(arg0, "accept") == 0) {
if(cb->nf != 2)
error("usage: accect id");
c->dialid = atoi(cb->f[1]);
convsetstate(c, COpen);
} else if(strcmp(arg0, "dial") == 0) {
if(cb->nf != 1)
error("usage: dial");
convsetstate(c, COpening);
} else if(strcmp(arg0, "drop") == 0) {
if(cb->nf != 2)
error("usage: drop permil");
c->drop = atoi(cb->f[1]);
.
348c
qunlock(c);
.
346c
qlock(c);
.
344a
c = sdp->conv[CONV(ch->qid)];
print("Qctl write : conv->id = %d\n", c->id);
.
338a
Conv *c;
.
186a
sdp = sdptab + dev;
qlock(sdp);
start = sdp->ackproc == 0;
sdp->ackproc = 1;
qunlock(sdp);
if(start) {
snprint(buf, sizeof(buf), "sdpackproc%d", dev);
kproc(buf, sdpackproc, sdp);
}
.
177a
char buf[100];
Sdp *sdp;
int start;
.
170a
.
153a
static void convsetstate(Conv *c, int state);
static void sendconnect(Conv *c, int op, ulong dialid, ulong acceptid);
static void sdpackproc(void *a);
.
115a
enum {
TConnect,
TControl,
TControlAck,
TData,
TThwackC,
TThwackU,
};
enum {
ConOpen,
ConOpenAck,
ConOpenNack,
ConClose,
ConCloseAck,
};
struct ConPkt
{
uchar type; // always zero = connection packet
uchar op;
uchar pad[2];
uchar dialid[4];
uchar acceptid[4];
};
.
113a
int ackproc;
.
111a
Rendez vous; /* used by sdpackproc */
.
104a
int drop;
.
99a
Proc *readproc;
ulong timeout;
int retries;
// the following pair uniquely define conversation on this port
ulong dialid;
ulong acceptid;
.
98c
int dataopen;
.
94c
int ref; // number of times the conv is opened
.
88a
CClosed,
.
85c
CInit,
.
48,49d
34a
Maxretries= 4,
.
14a
typedef struct ConPkt ConPkt;
.
## diffname port/devsdp.c 1999/0907
## diff -e /n/emeliedump/1999/0906/sys/src/brazil/port/devsdp.c /n/emeliedump/1999/0907/sys/src/brazil/port/devsdp.c
691a
}
static int
readready(void *a)
{
Conv *c = a;
return (c->state == CClosed) || c->in.controlpkt != nil || c->dataopen == 0;
}
static Block *
readcontrol(Conv *c, int n)
{
Block *b;
for(;;) {
qlock(c);
if(c->state == CClosed || c->state == CInit) {
qunlock(c);
return nil;
}
if(c->in.controlpkt != nil) {
b = c->in.controlpkt;
c->in.controlpkt = nil;
qunlock(c);
return b;
}
qunlock(c);
// hack - this is to avoid gating onto the
// read which will in general result in excessive
// context switches.
// The assumed behavior is that the client will read
// from the control channel until the session is authenticated
// at which point it will open the data channel and
// start reading on that. After the data channel is opened,
// read on the channel are required for packets to
// be delivered to the control channel
if(c->dataopen) {
sleep(&c->in.controlready, readready, c);
} else {
b = convreadblock(c, n);
if(b == nil)
return nil;
qlock(c);
if(waserror()) {
qunlock(c);
return nil;
}
b = conviput(c, b, 1);
poperror();
qunlock(c);
if(b != nil)
return b;
}
}
}
static Block *
readdata(Conv *c, int n)
{
Block *b;
for(;;) {
b = convreadblock(c, n);
if(b == nil)
return nil;
qlock(c);
if(waserror()) {
qunlock(c);
return nil;
}
b = conviput(c, b, 0);
poperror();
qunlock(c);
if(b != nil)
return b;
}
.
677a
static Block *
convreadblock(Conv *c, int n)
{
Block *b;
qlock(&c->readlk);
if(waserror()) {
c->readproc = nil;
qunlock(&c->readlk);
nexterror();
}
qlock(c);
if(c->state == CClosed) {
qunlock(c);
poperror();
qunlock(&c->readlk);
return 0;
}
c->readproc = up;
qunlock(c);
b = devtab[c->chan->type]->bread(c->chan, n, 0);
c->readproc = nil;
poperror();
qunlock(&c->readlk);
return b;
}
// assume we hold lock for c
static Block *
conviput(Conv *c, Block *b, int control)
{
int type;
ulong seq, cseq;
if(BLEN(b) < 4) {
freeb(b);
return nil;
}
type = b->rp[0];
if(type == TConnect) {
conviput2(c, b);
return nil;
}
seq = (b->rp[1]<<16) + (b->rp[2]<<8) + b->rp[3];
b->rp += 4;
USED(seq);
// auth
// decrypt
// ok the packet is good
switch(type) {
case TControl:
if(BLEN(b) <= 4)
break;
cseq = nhgetl(b->rp);
if(cseq == c->in.controlseq) {
// duplicate control packet
// send ack
b->wp = b->rp + 4;
convoput(c, TControlAck, b);
return nil;
}
if(cseq != c->in.controlseq+1)
break;
c->in.controlseq = cseq;
b->rp += 4;
if(control)
return b;
c->in.controlpkt = b;
wakeup(&c->in.controlready);
return nil;
case TControlAck:
if(BLEN(b) != 4)
break;
cseq = nhgetl(b->rp);
if(cseq != c->out.controlseq)
break;
freeb(b);
freeb(c->out.controlpkt);
c->out.controlpkt = 0;
wakeup(&c->out.controlready);
return nil;
case TData:
if(control)
break;
return b;
}
print("droping packet %d n=%ld\n", type, BLEN(b));
freeb(b);
return nil;
}
// assume hold conv lock
static void
conviput2(Conv *c, Block *b)
{
ConnectPkt *con;
ulong dialid;
ulong acceptid;
if(BLEN(b) != sizeof(ConnectPkt)) {
freeb(b);
return;
}
con = (ConnectPkt*)b->rp;
dialid = nhgetl(con->dialid);
acceptid = nhgetl(con->acceptid);
print("conviput2: %d %uld %uld\n", con->op, dialid, acceptid);
switch(con->op) {
case ConOpen:
if(c->state != COpen || dialid != c->dialid || acceptid != c->acceptid)
convoput2(c, ConOpenNack, dialid, acceptid);
else
convoput2(c, ConOpenAck, dialid, acceptid);
break;
case ConOpenAck:
if(c->state != COpening || dialid != c->dialid)
break;
c->acceptid = acceptid;
convsetstate(c, COpen);
break;
case ConOpenNack:
if(c->state != COpening || dialid != c->dialid)
break;
convsetstate(c, CClosed);
break;
case ConClose:
if(dialid != c->dialid || acceptid != c->acceptid)
break;
convsetstate(c, CClosed);
break;
case ConCloseAck:
if(c->state != CClosing || dialid != c->dialid || acceptid != c->acceptid)
break;
convsetstate(c, CClosed);
break;
}
}
// assume hold conv lock
static void
convoput(Conv *c, int type, Block *b)
{
// try and compress
/* Make space to fit sdp header */
b = padblock(b, 4 + c->out.cipherivlen);
b->rp[0] = type;
c->out.seq++;
if(c->out.seq == (1<<24)) {
c->out.seq = 0;
c->out.seqwrap++;
}
b->rp[1] = c->out.seq>>16;
b->rp[2] = c->out.seq>>8;
b->rp[3] = c->out.seq;
// encrypt
// auth
// simulated errors
if(c->drop && c->drop > nrand(c->drop))
return;
devtab[c->chan->type]->bwrite(c->chan, b, 0);
}
// assume hold conv lock
static void
convoput2(Conv *c, int op, ulong dialid, ulong acceptid)
{
ConnectPkt con;
.
676c
if(ow->controlpkt)
freeb(ow->controlpkt);
if(ow->authstate)
free(ow->authstate);
if(ow->cipherstate)
free(ow->cipherstate);
if(ow->compstate)
free(ow->compstate);
memset(ow, 0, sizeof(OneWay));
}
.
674c
onewaycleanup(OneWay *ow)
.
667a
if(c->readproc)
postnote(c->readproc, 1, "interrupt", 0);
if(c->ref)
break;
if(c->chan) {
cclose(c->chan);
c->chan = nil;
}
strcpy(c->owner, "network");
c->perm = 0660;
c->dialid = 0;
c->acceptid = 0;
c->timeout = 0;
c->retries = 0;
c->drop = 0;
memset(c->masterkey, 0, sizeof(c->masterkey));
onewaycleanup(&c->in);
onewaycleanup(&c->out);
.
663a
convoput2(c, ConClose, c->dialid, c->acceptid);
.
656c
convoput2(c, ConOpenAck, c->dialid, c->acceptid);
.
648c
convoput2(c, ConOpen, c->dialid, 0);
.
638a
print("convsetstate %d -> %d\n", c->state, state);
.
584c
convoput2(c, ConClose, c->dialid, c->acceptid);
.
576c
convoput2(c, ConOpen, c->dialid, 0);
.
541c
strncpy(c->owner, up->user, sizeof(c->owner));
.
389a
static Block*
sdpbread(Chan* ch, long n, ulong offset)
{
Sdp *sdp = sdptab + ch->dev;
if(TYPE(ch->qid) != Qdata)
return devbread(ch, n, offset);
return readdata(sdp->conv[CONV(ch->qid)], n);
}
.
386a
case Qcontrol:
b = readcontrol(sdp->conv[CONV(ch->qid)], n);
if(b == nil)
return 0;
if(BLEN(b) < n)
n = BLEN(b);
memmove(a, b->rp, n);
freeb(b);
return n;
case Qdata:
b = readdata(sdp->conv[CONV(ch->qid)], n);
if(b == nil)
return 0;
if(BLEN(b) < n)
n = BLEN(b);
memmove(a, b->rp, n);
freeb(b);
return n;
.
350a
Block *b;
.
340a
case Qdata:
case Qctl:
case Qstatus:
case Qcontrol:
if(!(ch->flag & COPEN))
break;
c = sdp->conv[CONV(ch->qid)];
qlock(c);
if(waserror()) {
qunlock(c);
nexterror();
}
c->ref--;
if(TYPE(ch->qid) == Qdata) {
c->dataopen--;
if(c->dataopen == 0)
wakeup(&c->in.controlready);
}
if(c->ref == 0) {
switch(c->state) {
default:
convsetstate(c, CClosed);
break;
case COpen:
convsetstate(c, CClosing);
break;
case CClosing:
break;
}
}
qunlock(c);
poperror();
break;
.
334a
Conv *c;
.
320a
if(TYPE(ch->qid) == Qdata)
c->dataopen++;
.
318c
if(strcmp(up->user, c->owner) != 0 || (perm & c->perm) != perm)
.
197a
.
196a
static void onewaycleanup(OneWay *ow);
static int readready(void *a);
static int controlread();
static Block *conviput(Conv *c, Block *b, int control);
static void conviput2(Conv *c, Block *b);
static Block *readcontrol(Conv *c, int n);
static Block *readdata(Conv *c, int n);
static void convoput(Conv *c, int type, Block *b);
static void convoput2(Conv *c, int op, ulong dialid, ulong acceptid);
.
195d
155a
.
147c
struct ConnectPkt
.
117,118c
OneWay in;
OneWay out;
.
114a
uchar masterkey[KeyLength];
.
112c
char owner[NAMELEN]; /* protections */
.
109a
Proc *readproc;
QLock readlk;
.
101d
63,83c
// conv states
.
60c
int (*comp)(OneWay*, uchar *dst, uchar *src, int n);
.
57c
int (*auth)(OneWay*, uchar *buf, int len);
.
52,53c
int cipherivlen; // initial vector length
int cipherblklen; // block length
int (*cipher)(OneWay*, uchar *buf, int len);
.
49c
ulong controlseq;
.
47a
Rendez controlready;
.
46a
ulong window;
.
43c
struct OneWay
.
36a
KeyLength= 32,
.
34,35c
Maxconv= 256, // power of 2
Nfs= 4, // number of file systems
.
13,15c
typedef struct OneWay OneWay;
typedef struct ConnectPkt ConnectPkt;
.
10a
/*
* sdp - secure datagram protocol
*/
.
## diffname port/devsdp.c 1999/0908
## diff -e /n/emeliedump/1999/0907/sys/src/brazil/port/devsdp.c /n/emeliedump/1999/0908/sys/src/brazil/port/devsdp.c
706c
print("convsetstate %s -> %s\n", convstatename[c->state], convstatename[state]);
.
362c
print("close c->ref = %d\n", c->ref);
.
320a
print(c->ref = %d\n", c->ref);
.
181a
static char *convstatename[] = {
[CInit] "Init",
[COpening] "Opening",
[COpen] "Open",
[CClosing] "Closing",
[CClosed] "Closed",
};
.
## diffname port/devsdp.c 1999/0909
## diff -e /n/emeliedump/1999/0908/sys/src/brazil/port/devsdp.c /n/emeliedump/1999/0909/sys/src/brazil/port/devsdp.c
928c
}
case ConCloseAck:
if(c->state == CClosing && dialid == c->dialid && acceptid == c->acceptid)
convsetstate(c, CClosed);
.
923,926c
case CAccept:
case COpen:
case CClosing:
if(dialid == c->dialid && acceptid == c->acceptid)
convsetstate(c, CClosed);
.
921c
convoput2(c, ConCloseAck, dialid, acceptid);
// fall though
case ConReset:
switch(c->state) {
case CDial:
if(dialid == c->dialid)
convsetstate(c, CClosed);
.
915,919d
912,913c
case CAccept:
if(dialid != c->dialid || acceptid != c->acceptid) {
convoput2(c, ConReset, dialid, acceptid);
break;
}
convsetstate(c, COpen);
}
.
910c
switch(c->state) {
case CDial:
if(dialid != c->dialid) {
convoput2(c, ConReset, dialid, acceptid);
break;
}
c->acceptid = acceptid;
convsetstate(c, COpen);
.
903,907c
case ConOpenRequest:
switch(c->state) {
default:
convoput2(c, ConReset, dialid, acceptid);
break;
case CInit:
c->dialid = dialid;
convsetstate(c, CAccept);
break;
case CAccept:
case COpen:
if(dialid != c->dialid || acceptid != c->acceptid)
convoput2(c, ConReset, dialid, acceptid);
break;
}
.
742,743d
740a
assert(c->state == COpen);
convretryinit(c);
.
734,736d
728,732c
assert(c->state == CDial || c->state == CAccept);
if(c->state == CDial) {
convretryinit(c);
.
726a
case CAccept:
assert(c->state == CInit);
c->acceptid = (rand()<<16) + rand();
convretryinit(c);
convoput2(c, ConOpenAck, c->dialid, c->acceptid);
break;
.
723,725c
convretryinit(c);
convoput2(c, ConOpenRequest, c->dialid, 0);
.
719,721c
case CDial:
assert(c->state == CInit);
.
656d
653c
// check for control packet and keepalive
.
651a
case CAccept:
if(convretry(c))
convoput2(c, ConOpenAck, c->dialid, c->acceptid);
break;
.
650c
convoput2(c, ConOpenRequest, c->dialid, 0);
.
647,648c
case CDial:
.
645a
print("convtimer: %s\n", convstatename[c->state]);
.
632c
c->timeout = TK2SEC(m->ticks) + (c->retries+1);
.
627c
if(c->retries > MaxRetries) {
.
622a
static void
convretryinit(Conv *c)
{
c->retries = 0;
// +2 to avoid rounding effects.
c->timeout = TK2SEC(m->ticks) + 2;
};
// assume c is locked
.
505c
convsetstate(c, CDial);
.
501c
convsetstate(c, CAccept);
.
411,427c
n = readstr(off, a, n, convstatename[c->state]);
.
394d
375a
case CAccept:
.
328d
184c
[CDial] "Dial",
[CAccept] "Accept",
.
134a
ConReset,
.
132d
130c
ConOpenRequest,
.
73c
CDial,
CAccept,
.
39c
MaxRetries= 8,
KeepAlive = 60, // keep alive in seconds
.
## diffname port/devsdp.c 1999/0910
## diff -e /n/emeliedump/1999/0909/sys/src/brazil/port/devsdp.c /n/emeliedump/1999/0910/sys/src/brazil/port/devsdp.c
1083a
}
static void
convreader(void *a)
{
Conv *c = a;
Block *b;
qlock(c);
assert(c->reader == 1);
while(c->dataopen == 0) {
qunlock(c);
b = nil;
if(!waserror()) {
b = convreadblock(c, 2000);
poperror();
}
qlock(c);
if(b == nil) {
convsetstate(c, CClosed);
break;
}
if(!waserror()) {
conviput(c, b, 1);
poperror();
}
}
c->reader = 0;
qunlock(c);
pexit("hangup", 1);
.
1071,1072d
1061a
return 0;
.
1034,1060c
sleep(&c->in.controlready, readready, c);
.
1021c
if(c->state == CInit || c->state == CClosed) {
.
1018a
USED(n);
.
1011c
return (c->state == CClosed) || c->in.controlpkt != nil;
.
1005a
static Block *
convreadblock(Conv *c, int n)
{
Block *b;
Chan *ch = nil;
qlock(&c->readlk);
if(waserror()) {
c->readproc = nil;
if(ch)
cclose(ch);
qunlock(&c->readlk);
nexterror();
}
qlock(c);
if(c->state == CClosed) {
qunlock(c);
error("closed");
}
c->readproc = up;
ch = c->chan;
incref(ch);
qunlock(c);
b = devtab[ch->type]->bread(ch, n, 0);
c->readproc = nil;
cclose(ch);
poperror();
qunlock(&c->readlk);
return b;
}
.
954a
Reset:
// invalid connection message - reset to sender
convoput2(c, ConReset, dialid, acceptid);
.
953c
return;
case CRemoteClose:
return;
}
return;
.
950,951c
return;
case ConReset:
switch(c->state) {
case CInit:
case CDial:
case CAccept:
case COpen:
case CLocalClose:
.
945,948c
convsetstate(c, CRemoteClose);
return;
case CRemoteClose:
return;
.
943a
case CLocalClose:
convsetstate(c, CClosed);
return;
.
940,942d
938a
case CInit:
.
935,937c
convoput2(c, ConReset, dialid, acceptid);
.
931a
return;
case COpen:
// duplicate that we ignore
return;
.
927,930d
925c
return;
case COpen:
// duplicate that we have to ack
convoput2(c, ConOpenAckAck, acceptid, dialid);
return;
}
break;
case ConOpenAckAck:
switch(c->state) {
.
919,922d
911,913c
// duplicate ConOpenRequest that we ignore
return;
.
908c
return;
.
902,904d
898c
switch(c->state) {
default:
panic("unknown state: %d", c->state);
case CInit:
break;
case CDial:
if(dialid != c->dialid)
goto Reset;
break;
case CAccept:
case COpen:
case CLocalClose:
case CRemoteClose:
if(dialid != c->dialid || acceptid != c->acceptid)
goto Reset;
break;
case CClosed:
goto Reset;
}
print("conviput2: %s: %d %uld %uld\n", convstatename[c->state], con->op, dialid, acceptid);
.
856,857d
802,810d
786,800d
781,784d
750a
if(c->channame) {
free(c->channame);
c->channame = nil;
}
.
741a
case CRemoteClose:
convoput2(c, ConReset, c->dialid, c->acceptid);
break;
.
737,738c
case CLocalClose:
assert(c->state == CAccept || c->state == COpen);
.
733c
convoput2(c, ConOpenAckAck, c->dialid, c->acceptid);
.
654c
case CLocalClose:
.
649a
else
convoput2(c, ConReset, c->dialid, c->acceptid);
.
600c
if(!waserror()) {
kproc("convreader", convreader, c);
c->reader = 1;
}
.
587c
if(c->state == CClosed && c->reader == 0)
.
489,490c
if(cb->nf != 2)
error("usage: accect file");
if(c->chan != nil)
error("already connected");
c->chan = namec(cb->f[1], Aopen, ORDWR, 0);
c->channame = malloc(strlen(cb->f[1])+1);
strcpy(c->channame, cb->f[1]);
.
483,487c
c->channame = malloc(strlen(cb->f[1])+1);
strcpy(c->channame, cb->f[1]);
.
481c
error("already connected");
.
479c
error("usage: accect file");
.
477c
if(strcmp(arg0, "accept") == 0) {
.
382,383c
case CLocalClose:
panic("local close already happened");
.
380c
convsetstate(c, CLocalClose);
.
332a
}
.
331c
if(TYPE(ch->qid) == Qdata) {
if(c->dataopen == 0)
if(c->readproc != nil)
postnote(c->readproc, 1, "interrupt", 0);
.
205a
static void convreader(void *a);
.
189c
[CLocalClose] "LocalClose",
[CRemoteClose] "RemoteClose",
.
135d
133a
ConOpenAckAck,
.
100a
char *channame;
.
99c
.
97a
QLock readlk; // protects readproc
.
90d
88a
int reader; // reader proc has been started
.
77c
CLocalClose,
CRemoteClose,
.
## diffname port/devsdp.c 1999/0914
## diff -e /n/emeliedump/1999/0910/sys/src/brazil/port/devsdp.c /n/emeliedump/1999/0914/sys/src/brazil/port/devsdp.c
1143a
print("convreader exiting\n");
.
1124a
print("convreader\n");
.
1098a
static int
writeready(void *a)
{
Conv *c = a;
return c->out.controlpkt == nil || (c->state == CClosed) || (c->state == CRemoteClose);
}
static void
writecontrol(Conv *c, void *p, int n)
{
Block *b;
qlock(c);
for(;;) {
if(c->state == CInit || c->state == CClosed || c->state == CRemoteClose) {
qunlock(c);
print("writecontrol: return error - state = %s\n", convstatename[c->state]);
error("conversation closed");
}
if(c->state == COpen && c->out.controlpkt == nil)
break;
qunlock(c);
sleep(&c->out.controlready, writeready, c);
qlock(c);
}
b = allocb(4+n);
c->out.controlseq++;
hnputl(b->wp, c->out.controlseq);
memmove(b->wp+4, p, n);
b->wp += 4+n;
c->out.controlpkt = b;
convretryinit(c);
print("send %ld size=%ld\n", c->out.controlseq, BLEN(b));
convoput(c, TControl, copyblock(b, blocklen(b)));
qunlock(c);
}
.
1096c
// send ack
b = allocb(4);
hnputl(b->wp, c->in.controlseq);
b->wp += 4;
convoput(c, TControlAck, b);
b = c->in.controlpkt;
c->in.controlpkt = nil;
qunlock(c);
return b;
.
1094a
qlock(c);
.
1093d
1090c
print("readcontrol: return nil - state = %s\n", convstatename[c->state]);
return nil;
.
1086,1088c
if(c->in.controlpkt != nil)
break;
if(c->state == CRemoteClose) {
.
1083c
print("readcontrol: return error - state = %s\n", convstatename[c->state]);
error("conversation closed");
.
1080d
1078a
qlock(c);
.
1070c
return c->in.controlpkt != nil || (c->state == CClosed) || (c->state == CRemoteClose);
.
979a
print("invalid conviput2 - sending reset\n");
.
912d
890a
print("conviput2: %s: %d %uld %uld\n", convstatename[c->state], con->op, dialid, acceptid);
.
862c
c->out.controlpkt = nil;
.
857a
print("ControlAck expected %ulx got %ulx\n", c->out.controlseq, cseq);
.
851a
print("recv %ld size=%ld\n", cseq, BLEN(b));
.
848d
840,842c
if(c->in.controlpkt == nil) {
// send ack
b->wp = b->rp + 4;
convoput(c, TControlAck, b);
} else
freeb(b);
.
838a
print("duplicate control packet: %ulx\n", cseq);
.
827a
print("coniput seq=%ulx\n", seq);
.
803a
// assumes conv is locked
static void
convopenchan(Conv *c, char *path)
{
if(c->chan != nil)
error("already connected");
c->chan = namec(path, Aopen, ORDWR, 0);
c->channame = malloc(strlen(path)+1);
strcpy(c->channame, path);
if(waserror()) {
cclose(c->chan);
c->chan = nil;
free(c->channame);
c->channame = nil;
nexterror();
}
kproc("convreader", convreader, c);
c->reader = 1;
poperror();
}
.
761a
wakeup(&c->in.controlready);
.
758a
wakeup(&c->in.controlready);
.
674a
poperror();
.
673a
case CRemoteClose:
case CClosed:
c->timeout = 0;
break;
.
671c
if(convretry(c, 0))
.
668c
b = c->out.controlpkt;
if(b != nil) {
if(convretry(c, 1))
convoput(c, TControl, copyblock(b, blocklen(b)));
} else {
c->timeout = 0;
}
// keepalive
.
664,665d
662c
if(convretry(c, 1))
.
658c
if(convretry(c, 1))
.
655d
647a
Block *b;
.
637a
if(reset)
convoput2(c, ConReset, c->dialid, c->acceptid);
.
635a
print("convretry: %s: %d\n", convstatename[c->state], c->retries);
.
633c
convretry(Conv *c, int reset)
.
611,614d
519a
case Qcontrol:
print("writecontrol %ld\n", n);
writecontrol(sdp->conv[CONV(ch->qid)], a, n);
return n;
.
497,501c
convopenchan(c, cb->f[1]);
.
489,493c
convopenchan(c, cb->f[1]);
.
485d
474d
458a
.
437a
print("readdata\n");
.
431a
print("readcontrol asked %ld got %ld\n", n, BLEN(b));
.
381d
210a
static void convopenchan(Conv *c, char *path);
.
205a
static void writecontrol(Conv *c, void *p, int n);
.
39c
MaxRetries= 4,
.
## diffname port/devsdp.c 1999/0915
## diff -e /n/emeliedump/1999/0914/sys/src/brazil/port/devsdp.c /n/emeliedump/1999/0915/sys/src/brazil/port/devsdp.c
1229,1232c
print("up->error = %s\n", up->error);
if(strcmp(up->error, Eintr) != 0) {
if(!waserror()) {
convsetstate(c, CClosed);
poperror();
}
break;
}
} else if(!waserror()) {
.
1220c
while(c->dataopen == 0 && c->state != CClosed) {
.
1210a
static long
writedata(Conv *c, Block *b)
{
int n;
qlock(c);
print("writedata %ulx state=%s\n", b, convstatename[c->state]);
if(waserror()) {
qunlock(c);
nexterror();
}
if(c->state != COpen) {
freeb(b);
error("conversation not open");
}
n = BLEN(b);
convoput(c, TData, b);
poperror();
qunlock(c);
return n;
}
.
1188a
poperror();
qunlock(&c->out.controllk);
.
1164c
qlock(&c->out.controllk);
if(waserror()) {
qunlock(&c->out.controllk);
nexterror();
}
qlock(c); // this lock is not held in the sleep below
.
1146a
poperror();
qunlock(&c->in.controllk);
.
1130a
poperror();
.
1117c
qlock(&c->in.controllk);
if(waserror()) {
qunlock(&c->in.controllk);
nexterror();
}
qlock(c); // this lock is not held during the sleep below
.
1044a
print("convoput\n");
.
818c
if(c->state != CInit || c->chan != nil)
.
779a
if(c->ref)
break;
.
774,775c
print("CClosed -> ref = %d\n", c->ref);
.
771a
wakeup(&c->out.controlready);
.
520a
long
sdpbwrite(Chan *ch, Block *bp, ulong offset)
{
Sdp *sdp = sdptab + ch->dev;
if(TYPE(ch->qid) != Qdata)
return devbwrite(ch, bp, offset);
return writedata(sdp->conv[CONV(ch->qid)], bp);
}
.
517a
case Qdata:
b = allocb(n);
memmove(b->wp, a, n);
b->wp += n;
return writedata(sdp->conv[CONV(ch->qid)], b);
.
470a
Block *b;
.
380,381c
if(c->dataopen == 0 && c->reader == 0) {
kproc("convreader", convreader, c);
c->reader = 1;
}
.
208a
static long writedata(Conv *c, Block *b);
.
53a
QLock controllk;
.
## diffname port/devsdp.c 1999/0929
## diff -e /n/emeliedump/1999/0915/sys/src/brazil/port/devsdp.c /n/emeliedump/1999/0929/sys/src/brazil/port/devsdp.c
1269a
c->outDataPackets++;
c->outDataBytes += n;
c->outCompDataBytes += n;
.
1228a
qunlock(c);
.
1227c
if(wait)
writewait(c);
.
1217a
}
static void
writecontrol(Conv *c, void *p, int n, int wait)
{
Block *b;
qlock(&c->out.controllk);
qlock(c);
if(waserror()) {
qunlock(c);
qunlock(&c->out.controllk);
nexterror();
}
writewait(c);
.
1215a
poperror();
.
1214a
if(waserror()) {
qlock(c);
nexterror();
}
.
1206d
1195,1203d
1193c
writewait(Conv *c)
.
1191a
// c is locked
.
1169,1173c
convack(c);
.
1076a
c->lstats.outPackets++;
.
1048c
c->lstats.outPackets++;
.
923a
c->lstats.inDataPackets++;
c->lstats.inDataBytes += BLEN(b);
c->lstats.inCompDataBytes += BLEN(b);
.
917a
c->rstat.outPackets = nhgetl(ack->outPackets);
c->rstat.outDataPackets = nhgetl(ack->outDataPackets);
c->rstat.outDataBytes = nhgetl(ack->outDataBytes);
c->rstat.outCompDataBytes = nhgetl(ack->outCompDataBytes);
c->rstat.inPackets = nhgetl(ack->inPackets);
c->rstat.inDataPackets = nhgetl(ack->inDataPackets);
c->rstat.inDataBytes = nhgetl(ack->inDataBytes);
c->rstat.inCompDataBytes = nhgetl(ack->inCompDataBytes);
c->rstat.inMissing = nhgetl(ack->inMissing);
c->rstat.inDup = nhgetl(ack->inDup);
c->rstat.inReorder = nhgetl(ack->inReorder);
c->rstat.inBadAuth = nhgetl(ack->inBadAuth);
c->rstat.inBadSeq = nhgetl(ack->inBadSeq);
.
914c
ack = (AckPkt*)(b->rp);
cseq = nhgetl(ack->cseq);
.
912c
if(BLEN(b) != sizeof(AckPkt))
.
909c
wakeup(&c->in.controlready);
}
.
907c
if(BLEN(b) == 0) {
// just a ping
freeb(b);
convack(c);
} else {
c->in.controlpkt = b;
.
894,899c
freeb(b);
if(c->in.controlpkt == nil)
convack(c);
.
888c
if(BLEN(b) < 4)
.
864a
c->lstat.inPackets++;
.
863a
AckPkt *ack;
.
857a
qlock(c);
if(local) {
stats = &c->lstats;
} else {
if(!waserror()) {
writecontrol(c, 0, 0, 1);
poperror();
}
stats = &c->rstats;
}
p = buf;
ep = buf + n;
p += snprint(p, ep-p, "outPackets: %ld\n", stats->outPackets);
p += snprint(p, ep-p, "outDataPackets: %ld\n", stats->outDataPackets);
p += snprint(p, ep-p, "outDataBytes: %ld\n", stats->outDataBytes);
p += snprint(p, ep-p, "outCompDataBytes: %ld\n", stats->outCompDataBytes);
p += snprint(p, ep-p, "inPackets: %ld\n", stats->inPackets);
p += snprint(p, ep-p, "inDataPackets: %ld\n", stats->inDataPackets);
p += snprint(p, ep-p, "inCompDataBytes: %ld\n", stats->inCompDataBytes);
p += snprint(p, ep-p, "inMissing: %ld\n", stats->inMissing);
p += snprint(p, ep-p, "inDup: %ld\n", stats->inDup);
p += snprint(p, ep-p, "inReorder: %ld\n", stats->inReorder);
p += snprint(p, ep-p, "inBadAuth: %ld\n", stats->inBadAuth);
p += snprint(p, ep-p, "inBadSeq: %ld\n", stats->inBadSeq);
USED(p);
qunlock(c);
}
// c is locked
static void
convack(Conv *c)
{
Block *b;
AckPkt *ack;
Stats *s;
b = allocb(sizeof(AckPkt));
ack = (Ack)b->wp;
b->wp += sizeof(AckPkt);
s = &c->lstats;
hnputl(ack->cseq, c->in.controlseq);
hnputl(ack->outPackets, s->outPackets);
hnputl(ack->outDataPackets, s->outDataPackets);
hnputl(ack->outDataBytes, s->outDataBytes);
hnputl(ack->outCompDataBytes, s->outCompDataBytes);
hnputl(ack->inPackets, s->inPackets);
hnputl(ack->inDataPackets, s->inDataPackets);
hnputl(ack->inDataBytes, s->inDataBytes);
hnputl(ack->inCompDataBytes, s->inCompDataBytes);
hnputl(ack->inMissing, s->inMissing);
hnputl(ack->inDup, s->inDup);
hnputl(ack->inReorder, s->inReorder);
hnputl(ack->inBadAuth, s->inBadAuth);
hnputl(ack->inBadSeq, s->inBadSeq);
convoput(c, TControlAck, b);
}
.
856a
static void
convstats(Conv *c, int local, char *buf, int n)
{
Stats *stats;
char *p, *ep;
.
521c
writecontrol(sdp->conv[CONV(ch->qid)], a, n, 0);
.
452a
case Qstats:
case Qrstats:
c = sdp->conv[CONV(ch->qid)];
s = smalloc(1000);
convstats(c, TYPE(ch->qid) == Qstats, s, 1000);
rv = readstr(off, a, n, s);
free(s);
return rv;
.
412a
int rv;
.
409a
char *s;
.
329a
case Qstats:
case Qrstats:
.
313d
216d
214a
static void convstats(Conv *c, int local, char *buf, int n);
.
207c
static void writecontrol(Conv *c, void *p, int n, int wait);
.
163a
"stats", {Qstats}, 0, 0444,
"rstats", {Qrstats}, 0, 0444,
.
154d
152a
.
151a
struct AckPkt
{
uchar cseq[4];
uchar outPackets[4];
uchar outDataPackets[4];
uchar outDataBytes[4];
uchar outCompDataBytes[4];
uchar inPackets[4];
uchar inDataPackets[4];
uchar inDataBytes[4];
uchar inCompDataBytes[4];
uchar inMissing[4];
uchar inDup[4];
uchar inReorder[4];
uchar inBadAuth[4];
uchar inBadSeq[4];
};
.
92a
Stats lstats;
Stats rstats;
.
49a
Rendez statsready;
.
47a
struct Stats
{
ulong outPackets;
ulong outDataPackets;
ulong outDataBytes;
ulong outCompDataBytes;
ulong outCompBytes;
ulong inPackets;
ulong inDataPackets;
ulong inDataBytes;
ulong inCompDataBytes;
ulong inMissing;
ulong inDup;
ulong inReorder;
ulong inBadAuth;
ulong inBadSeq;
};
.
33a
Qstats,
Qrstats,
.
26d
18a
typedef struct AckPkt AckPkt;
.
17a
typedef struct Stats Stats;
.
## diffname port/devsdp.c 1999/0930
## diff -e /n/emeliedump/1999/0929/sys/src/brazil/port/devsdp.c /n/emeliedump/1999/0930/sys/src/brazil/port/devsdp.c
1423,1425c
c->lstats.outDataPackets++;
c->lstats.outDataBytes += n;
c->lstats.outCompDataBytes += n;
.
1411d
1391a
if(b == nil)
return nil;
.
1379a
}
.
1378c
if(wait) {
print("writecontrol wait!\n");
.
1230,1233c
convwriteblock(c, b);
.
1224,1228c
b = allocb(sizeof(ConnectPkt));
con = (ConnectPkt*)b->wp;
b->wp += sizeof(ConnectPkt);
con->type = TConnect;
con->op = op;
hnputl(con->dialid, dialid);
hnputl(con->acceptid, acceptid);
.
1217c
Block *b;
ConnectPkt *con;
.
1205,1210c
convwriteblock(c, b);
.
1184a
// c is locked
static void
convwriteblock(Conv *c, Block *b)
{
// simulated errors
if(c->drop && c->drop > nrand(c->drop))
return;
if(waserror()) {
convsetstate(c, CClosed);
nexterror();
}
devtab[c->chan->type]->bwrite(c->chan, b, 0);
poperror();
}
.
1044,1056c
}
c->rstats.outPackets = nhgetl(ack->outPackets);
c->rstats.outDataPackets = nhgetl(ack->outDataPackets);
c->rstats.outDataBytes = nhgetl(ack->outDataBytes);
c->rstats.outCompDataBytes = nhgetl(ack->outCompDataBytes);
c->rstats.inPackets = nhgetl(ack->inPackets);
c->rstats.inDataPackets = nhgetl(ack->inDataPackets);
c->rstats.inDataBytes = nhgetl(ack->inDataBytes);
c->rstats.inCompDataBytes = nhgetl(ack->inCompDataBytes);
c->rstats.inMissing = nhgetl(ack->inMissing);
c->rstats.inDup = nhgetl(ack->inDup);
c->rstats.inReorder = nhgetl(ack->inReorder);
c->rstats.inBadAuth = nhgetl(ack->inBadAuth);
c->rstats.inBadSeq = nhgetl(ack->inBadSeq);
.
1042d
1040a
if(cseq != c->out.controlseq) {
.
1032c
if(0) print("recv %ld size=%ld\n", cseq, BLEN(b));
.
1002c
if(0) print("coniput seq=%ulx\n", seq);
.
985c
c->lstats.inPackets++;
.
956c
ack = (AckPkt*)b->wp;
.
936a
p += snprint(p, ep-p, "inDataBytes: %ld\n", stats->inDataBytes);
.
928a
qlock(c);
.
919d
492d
## diffname port/devsdp.c 1999/1001
## diff -e /n/emeliedump/1999/0930/sys/src/brazil/port/devsdp.c /n/emeliedump/1999/1001/sys/src/brazil/port/devsdp.c
1443,1444c
if(0) {
c->lstats.outCompDataBytes += n;
convoput(c, TData, b);
poperror();
qunlock(c);
return n;
}
b = padblock(b, 4);
b->rp[0] = (c->in.window>>1) & 0xff;
b->rp[1] = c->in.seq>>16;
b->rp[2] = c->in.seq>>8;
b->rp[3] = c->in.seq;
// must generate same value as convoput
seq = (c->out.seq + 1) & (SeqMax-1);
bb = allocb(BLEN(b));
nn = thwack(c->out.compstate, bb->wp, b->rp, BLEN(b), seq);
if(nn < 0) {
c->lstats.outCompDataBytes += BLEN(b);
convoput(c, TThwackU, b);
freeb(bb);
} else {
c->lstats.outCompDataBytes += nn;
bb->wp += nn;
convoput(c, TThwackC, bb);
freeb(b);
}
.
1427c
int n, nn;
ulong seq;
Block *bb;
.
1396d
1393,1394c
if(wait)
.
1391d
1192c
if(c->drop && nrand(c->drop) == 0)
.
1115d
1070a
case TThwackU:
c->lstats.inDataPackets++;
c->lstats.inCompDataBytes += BLEN(b);
mask = b->rp[0];
mseq = (b->rp[1]<<16) | (b->rp[2]<<8) | b->rp[3];
b->rp += 4;
thwackack(c->out.compstate, mseq, mask);
c->lstats.inDataBytes += BLEN(b);
if(control)
break;
return b;
case TThwackC:
c->lstats.inDataPackets++;
c->lstats.inCompDataBytes += BLEN(b);
bb = b;
b = allocb(ThwMaxBlock);
n = unthwack(c->in.compstate, b->wp, ThwMaxBlock, bb->rp, BLEN(bb), seq);
freeb(bb);
if(n < 0)
break;
b->wp += n;
mask = b->rp[0];
mseq = (b->rp[1]<<16) | (b->rp[2]<<8) | b->rp[3];
thwackack(c->out.compstate, mseq, mask);
b->rp += 4;
c->lstats.inDataBytes += BLEN(b);
if(control)
break;
return b;
.
1061a
c->timeout = c->lastrecv + KeepAlive;
.
1007a
if(seqdiff > 0) {
while(seqdiff > 0 && c->in.window != 0) {
if((c->in.window & (1<<(SeqWindow-1))) == 0) {
print("missing packet: %ld\n", seq - seqdiff);
c->lstats.inMissing++;
}
c->in.window <<= 1;
seqdiff--;
}
if(seqdiff > 0) {
print("missing packets: %ld-%ld\n", seq - SeqWindow - seqdiff+1, seq-SeqWindow);
c->lstats.inMissing += seqdiff;
}
c->in.seq = seq;
c->in.seqwrap = seqwrap;
c->in.window |= 1;
}
c->lastrecv = TK2SEC(m->ticks);
.
1002c
seqwrap = c->in.seqwrap;
seqdiff = seq - c->in.seq;
if(seqdiff < -(SeqMax*3/4)) {
seqwrap++;
seqdiff += SeqMax;
} else if(seqdiff > SeqMax*3/4) {
seqwrap--;
seqdiff -= SeqMax;
}
if(seqdiff <= 0) {
if(seqdiff <= -SeqWindow) {
print("old sequence number: %ld (%ld %ld)\n", seq, c->in.seqwrap, seqdiff);
c->lstats.inBadSeq++;
freeb(b);
return nil;
}
if(c->in.window & (1<<-seqdiff)) {
print("dup sequence number: %ld (%ld %ld)\n", seq, c->in.seqwrap, seqdiff);
c->lstats.inDup++;
freeb(b);
return nil;
}
c->lstats.inReorder++;
}
// ok the sequence number looks ok
.
984a
ulong mseq, mask;
Block *bb;
.
982,983c
int type, n;
ulong seq, seqwrap, cseq;
long seqdiff;
.
870a
memset(&c->lstats, 0, sizeof(Stats));
memset(&c->rstats, 0, sizeof(Stats));
.
865c
c->timeout = ~0;
.
861c
if(c->ciphername) {
free(c->ciphername);
c->ciphername = nil;
}
if(c->authname) {
free(c->authname);
c->authname = nil;
}
if(c->compname) {
free(c->compname);
c->compname = nil;
}
strcpy(c->owner, "network");
.
754c
c->timeout = ~0;
.
746c
c->timeout = c->lastrecv + KeepAlive;
if(c->timeout > sec)
break;
// keepalive - randomly spaced between KeepAlive and 2*KeepAlive
if(c->timeout + KeepAlive > sec && nrand(c->lastrecv + 2*KeepAlive - sec) > 0)
break;
print("sending keep alive: %ld\n", sec - c->lastrecv);
// can not use writecontrol
b = allocb(4);
c->out.controlseq++;
hnputl(b->wp, c->out.controlseq);
b->wp += 4;
c->out.controlpkt = b;
convretryinit(c);
if(!waserror()) {
convoput(c, TControl, copyblock(b, blocklen(b)));
poperror();
}
.
743,744c
break;
.
722c
if(c->timeout > sec)
.
683a
c->in.window = ~0;
c->in.compstate = malloc(sizeof(Unthwack));
unthwackinit(c->in.compstate);
c->out.compstate = malloc(sizeof(Thwack));
thwackinit(c->out.compstate);
.
662a
memset(c, 0, sizeof(Conv));
.
575d
210a
#ifdef XXX
static Algorithm cipheralg[] =
{
"null", 0, nullcipherinit,
"des_56_cbc", 7, descipherinit,
"rc4_128", 16, rc4cipherinit,
nil, 0, nil,
};
static Algorithm authalg[] =
{
"null", 0, nullauthinit,
"hmac_sha_96", 16, shaauthinit,
"hmac_md5_96", 16, md5authinit,
nil, 0, nil,
};
static Algorithm compalg[] =
{
"null", 0, nullcompinit,
"thwack", 0, thwackcompinit,
nil, 0, nil,
};
#endif
.
195a
struct Algorithm
{
char *name;
int keylen; // in bytes
void (*init)(Conv*, char* name, int keylen);
};
.
135a
char *authname;
char *ciphername;
char *compname;
.
118c
ulong lastrecv; // time last packet was received
.
44a
SeqMax = (1<<24),
SeqWindow = 32,
.
42c
MaxRetries= 8,
.
20a
typedef struct Algorithm Algorithm;
.
9a
#include "../port/thwack.h"
.
## diffname port/devsdp.c 1999/1015
## diff -e /n/emeliedump/1999/1001/sys/src/brazil/port/devsdp.c /n/emeliedump/1999/1015/sys/src/brazil/port/devsdp.c
1665a
/* ciphers, authenticators, and compressors */
static void
setalg(Conv *c, char *name, Algorithm *alg)
{
for(; alg->name; alg++)
if(strcmp(name, alg->name) == 0)
break;
if(alg->name == nil)
error("unknown algorithm");
alg->init(c, alg->name, alg->keylen);
}
static void
setsecret(OneWay *ow, char *secret)
{
char *p;
int i, c;
i = 0;
memset(ow->secret, 0, sizeof(ow->secret));
for(p=secret; *p; p++) {
if(i >= sizeof(ow->secret)*2)
break;
c = *p;
if(c >= '0' && c <= '9')
c -= '0';
else if(c >= 'a' && c <= 'f')
c -= 'a'-10;
else if(c >= 'A' && c <= 'F')
c -= 'A'-10;
else
error("bad character in secret");
if((i&1) == 0)
c <<= 4;
ow->secret[i>>1] |= c;
i++;
}
}
static void
setkey(uchar *key, int n, OneWay *ow, char *prefix)
{
uchar ibuf[SHAdlen], obuf[MD5dlen], salt[10];
int i, round = 0;
while(n > 0){
for(i=0; i<round+1; i++)
salt[i] = 'A'+round;
sha((uchar*)prefix, strlen(prefix), ibuf, sha(salt, round+1, nil, nil));
md5(ibuf, SHAdlen, obuf, md5(ow->secret, sizeof(ow->secret), nil, nil));
i = (n<MD5dlen) ? n : MD5dlen;
memmove(key, obuf, i);
key += i;
n -= i;
if(++round > sizeof salt)
panic("setkey: you ask too much");
}
}
static void
cipherfree(Conv *c)
{
if(c->ciphername) {
free(c->ciphername);
c->ciphername = nil;
}
if(c->in.cipherstate) {
free(c->in.cipherstate);
c->in.cipherstate = nil;
}
if(c->out.cipherstate) {
free(c->out.cipherstate);
c->out.cipherstate = nil;
}
c->in.cipher = nil;
}
static void
authfree(Conv *c)
{
if(c->authname) {
free(c->authname);
c->authname = nil;
}
if(c->in.authstate) {
free(c->in.authstate);
c->in.authstate = nil;
}
if(c->out.authstate) {
free(c->out.authstate);
c->out.authstate = nil;
}
c->in.auth = nil;
}
static void
compfree(Conv *c)
{
if(c->compname) {
free(c->compname);
c->compname = nil;
}
if(c->in.compstate) {
free(c->in.compstate);
c->in.compstate = nil;
}
if(c->out.compstate) {
free(c->out.compstate);
c->out.compstate = nil;
}
c->in.comp = nil;
}
static void
nullcipherinit(Conv *c, char *, int)
{
cipherfree(c);
}
static int
desencrypt(OneWay *ow, uchar *p, int n)
{
uchar *pp, *ip, *eip, *ep;
DESstate *ds = ow->cipherstate;
ep = p + n;
memmove(p, ds->ivec, 8);
for(p += 8; p < ep; p += 8){
pp = p;
ip = ds->ivec;
for(eip = ip+8; ip < eip; )
*pp++ ^= *ip++;
block_cipher(ds->expanded, p, 0);
memmove(ds->ivec, p, 8);
}
return 1;
}
static int
desdecrypt(OneWay *ow, uchar *p, int n)
{
uchar tmp[8];
uchar *tp, *ip, *eip, *ep;
DESstate *ds = ow->cipherstate;
ep = p + n;
memmove(ds->ivec, p, 8);
p += 8;
while(p < ep){
memmove(tmp, p, 8);
block_cipher(ds->expanded, p, 1);
tp = tmp;
ip = ds->ivec;
for(eip = ip+8; ip < eip; ){
*p++ ^= *ip;
*ip++ = *tp++;
}
}
return 1;
}
static void
descipherinit(Conv *c, char *name, int n)
{
uchar key[8];
uchar ivec[8];
int i;
cipherfree(c);
c->ciphername = malloc(strlen(name)+1);
strcpy(c->ciphername, name);
if(n > sizeof(key))
n = sizeof(key);
/* in */
memset(key, 0, sizeof(key));
setkey(key, n, &c->in, "cipher");
memset(ivec, 0, sizeof(ivec));
c->in.cipherblklen = 8;
c->in.cipherivlen = 8;
c->in.cipher = desdecrypt;
c->in.cipherstate = smalloc(sizeof(DESstate));
setupDESstate(c->in.cipherstate, key, ivec);
/* out */
memset(key, 0, sizeof(key));
setkey(key, n, &c->out, "cipher");
for(i=0; i<8; i++)
ivec[i] = nrand(256);
c->out.cipherblklen = 8;
c->out.cipherivlen = 8;
c->out.cipher = desencrypt;
c->out.cipherstate = smalloc(sizeof(DESstate));
setupDESstate(c->out.cipherstate, key, ivec);
}
static void
rc4cipherinit(Conv *c, char *name, int keylen)
{
}
static void
nullauthinit(Conv *c, char *name, int keylen)
{
authfree(c);
}
static void
shaauthinit(Conv *c, char *name, int keylen)
{
authfree(c);
}
static void
hmac_md5(uchar hash[MD5dlen], ulong wrap, uchar *t, long tlen, uchar *key, long klen)
{
uchar ipad[65], opad[65], wbuf[4];
int i;
DigestState *digest;
uchar innerhash[MD5dlen];
for(i=0; i<64; i++){
ipad[i] = 0x36;
opad[i] = 0x5c;
}
ipad[64] = opad[64] = 0;
for(i=0; i<klen; i++){
ipad[i] ^= key[i];
opad[i] ^= key[i];
}
hnputl(wbuf, wrap);
digest = md5(ipad, 64, nil, nil);
digest = md5(wbuf, sizeof(wbuf), nil, digest);
md5(t, tlen, innerhash, digest);
digest = md5(opad, 64, nil, nil);
md5(innerhash, MD5dlen, hash, digest);
}
static int
md5auth(OneWay *ow, uchar *t, int tlen)
{
uchar hash[MD5dlen];
int r;
if(tlen < ow->authlen)
return 0;
tlen -= ow->authlen;
memset(hash, 0, MD5dlen);
hmac_md5(hash, ow->seqwrap, t, tlen, (uchar*)ow->authstate, 16);
r = memcmp(t+tlen, hash, ow->authlen) == 0;
memmove(t+tlen, hash, ow->authlen);
return r;
}
static void
md5authinit(Conv *c, char *name, int keylen)
{
authfree(c);
c->authname = malloc(strlen(name)+1);
strcpy(c->authname, name);
if(keylen > 16)
keylen = 16;
/* in */
c->in.authstate = smalloc(16);
memset(c->in.authstate, 0, 16);
setkey(c->in.authstate, keylen, &c->in, "auth");
c->in.authlen = 12;
c->in.auth = md5auth;
/* out */
c->out.authstate = smalloc(16);
memset(c->out.authstate, 0, 16);
setkey(c->out.authstate, keylen, &c->out, "auth");
c->out.authlen = 12;
c->out.auth = md5auth;
}
static void
nullcompinit(Conv *c, char *name, int keylen)
{
}
static void
thwackcompinit(Conv *c, char *name, int keylen)
{
}
#ifdef XXX
case TThwackU:
mask = b->rp[0];
mseq = (b->rp[1]<<16) | (b->rp[2]<<8) | b->rp[3];
b->rp += 4;
thwackack(c->out.compstate, mseq, mask);
c->lstats.inDataBytes += BLEN(b);
if(control)
break;
return b;
case TThwackC:
c->lstats.inDataPackets++;
c->lstats.inCompDataBytes += BLEN(b);
bb = b;
b = allocb(ThwMaxBlock);
n = unthwack(c->in.compstate, b->wp, ThwMaxBlock, bb->rp, BLEN(bb), seq);
freeb(bb);
if(n < 0)
break;
b->wp += n;
mask = b->rp[0];
mseq = (b->rp[1]<<16) | (b->rp[2]<<8) | b->rp[3];
thwackack(c->out.compstate, mseq, mask);
b->rp += 4;
c->lstats.inDataBytes += BLEN(b);
if(control)
break;
return b;
}
b = padblock(b, 4);
b->rp[0] = (c->in.window>>1) & 0xff;
b->rp[1] = c->in.seq>>16;
b->rp[2] = c->in.seq>>8;
b->rp[3] = c->in.seq;
// must generate same value as convoput
seq = (c->out.seq + 1) & (SeqMax-1);
bb = allocb(BLEN(b));
nn = thwack(c->out.compstate, bb->wp, b->rp, BLEN(b), seq);
if(nn < 0) {
c->lstats.outCompDataBytes += BLEN(b);
convoput(c, TThwackU, b);
freeb(bb);
} else {
c->lstats.outCompDataBytes += nn;
bb->wp += nn;
convoput(c, TThwackC, bb);
freeb(b);
}
#endif
.
1616,1623c
convoput(c, TCompData, subtype, b);
} else
convoput(c, TData, 0, b);
.
1596,1614c
if(c->out.comp != nil) {
int subtype = (*c->out.comp)(&c->out, 0, &b);
.
1577,1579c
int n;
.
1544c
convoput(c, TControl, ControlMesg, copyblock(b, blocklen(b)));
.
1528d
1393,1399c
b = allocb(9);
b->wp[0] = (TConnect << 4) | op;
hnputl(b->wp+1, dialid);
hnputl(b->wp+5, acceptid);
b->wp += 9;
.
1386d
1383c
convoconnect(Conv *c, int op, ulong dialid, ulong acceptid)
.
1376a
if(c->out.auth) {
b = padblock(b, -c->out.authlen);
b->wp += c->out.authlen;
(*c->out.auth)(&c->out, b->rp, BLEN(b));
}
.
1365c
b->rp[0] = (type << 4) | subtype;
.
1359c
convoput(Conv *c, int type, int subtype, Block *b)
.
1339a
static void
convicontrol(Conv *c, int subtype, Block *b)
{
ulong cseq;
AckPkt *ack;
if(BLEN(b) < 4)
return;
cseq = nhgetl(b->rp);
switch(subtype){
case ControlMesg:
if(cseq == c->in.controlseq) {
print("duplicate control packet: %ulx\n", cseq);
// duplicate control packet
freeb(b);
if(c->in.controlpkt == nil)
convack(c);
return;
}
if(cseq != c->in.controlseq+1)
return;
c->in.controlseq = cseq;
b->rp += 4;
if(BLEN(b) == 0) {
// just a ping
freeb(b);
convack(c);
} else {
c->in.controlpkt = b;
if(0) print("recv %ld size=%ld\n", cseq, BLEN(b));
wakeup(&c->in.controlready);
}
return;
case ControlAck:
if(cseq != c->out.controlseq) {
print("ControlAck expected %ulx got %ulx\n", c->out.controlseq, cseq);
return;
}
if(BLEN(b) < sizeof(AckPkt))
return;
ack = (AckPkt*)(b->rp);
c->rstats.outPackets = nhgetl(ack->outPackets);
c->rstats.outDataPackets = nhgetl(ack->outDataPackets);
c->rstats.outDataBytes = nhgetl(ack->outDataBytes);
c->rstats.outCompDataBytes = nhgetl(ack->outCompDataBytes);
c->rstats.inPackets = nhgetl(ack->inPackets);
c->rstats.inDataPackets = nhgetl(ack->inDataPackets);
c->rstats.inDataBytes = nhgetl(ack->inDataBytes);
c->rstats.inCompDataBytes = nhgetl(ack->inCompDataBytes);
c->rstats.inMissing = nhgetl(ack->inMissing);
c->rstats.inDup = nhgetl(ack->inDup);
c->rstats.inReorder = nhgetl(ack->inReorder);
c->rstats.inBadAuth = nhgetl(ack->inBadAuth);
c->rstats.inBadSeq = nhgetl(ack->inBadSeq);
freeb(b);
freeb(c->out.controlpkt);
c->out.controlpkt = nil;
c->timeout = c->lastrecv + KeepAlive;
wakeup(&c->out.controlready);
return;
}
}
static Block*
convicomp(Conv *c, int subtype, Block *b)
{
if(c->in.comp == nil) {
freeb(b);
return nil;
}
if((*c->in.comp)(&c->in, subtype, &b) < 0)
return nil;
return b;
}
.
1336,1337c
print("invalid conviconnect - sending reset\n");
convoconnect(c, ConReset, dialid, acceptid);
.
1332c
break;
.
1319c
break;
.
1305c
convoconnect(c, ConReset, dialid, acceptid);
.
1290c
convoconnect(c, ConOpenAckAck, acceptid, dialid);
.
1269c
switch(subtype) {
.
1262c
if(dialid != c->dialid
|| subtype != ConOpenRequest && acceptid != c->acceptid)
.
1247c
print("conviconnect: %s: %d %uld %uld\n", convstatename[c->state], subtype, dialid, acceptid);
.
1243,1245c
dialid = nhgetl(b->rp);
acceptid = nhgetl(b->rp + 4);
freeb(b);
.
1239c
if(BLEN(b) != 8) {
.
1235d
1233c
conviconnect(Conv *c, int subtype, Block *b)
.
1207,1224d
1199,1202c
b = convicomp(c, subtype, b);
if(b == nil);
return nil;
.
1196c
case TCompData:
.
1192d
1161,1188d
1135,1159c
convicontrol(c, subtype, b);
.
1110c
if(c->in.auth != 0) {
if(!(*c->in.auth)(&c->in, b->rp-4, BLEN(b)+4)) {
print("bad auth\n");
c->lstats.inBadAuth++;
freeb(b);
return nil;
}
b->wp -= c->in.authlen;
}
.
1077,1078c
seq = (b->rp[0]<<16) + (b->rp[1]<<8) + b->rp[2];
b->rp += 3;
.
1073c
conviconnect(c, subtype, b);
.
1071c
type = b->rp[0] >> 4;
subtype = type & 0xf;
b->rp += 1;
.
1060,1062d
1057,1058c
int type, subtype;
ulong seq, seqwrap;
.
1049c
convoput(c, TControl, ControlAck, b);
.
941d
904c
convoconnect(c, ConReset, c->dialid, c->acceptid);
.
900c
convoconnect(c, ConClose, c->dialid, c->acceptid);
.
895c
md5authinit(c, "hmac_md5_96", 16);
.
893c
convoconnect(c, ConOpenAckAck, c->dialid, c->acceptid);
hnputl(c->in.secret, c->acceptid);
hnputl(c->in.secret+4, c->dialid);
hnputl(c->out.secret, c->dialid);
hnputl(c->out.secret+4, c->acceptid);
} else {
hnputl(c->in.secret, c->dialid);
hnputl(c->in.secret+4, c->acceptid);
hnputl(c->out.secret, c->acceptid);
hnputl(c->out.secret+4, c->dialid);
.
887c
convoconnect(c, ConOpenAck, c->dialid, c->acceptid);
.
881c
convoconnect(c, ConOpenRequest, c->dialid, 0);
.
811c
convoconnect(c, ConClose, c->dialid, c->acceptid);
.
805c
convoput(c, TControl, ControlMesg, copyblock(b, blocklen(b)));
.
786c
convoput(c, TControl, ControlMesg, copyblock(b, blocklen(b)));
.
780c
convoconnect(c, ConOpenAck, c->dialid, c->acceptid);
.
776c
convoconnect(c, ConOpenRequest, c->dialid, 0);
.
753c
convoconnect(c, ConReset, c->dialid, c->acceptid);
.
742c
}
.
599a
} else if(strcmp(arg0, "cipher") == 0) {
if(cb->nf != 2)
error("usage: cipher alg");
setalg(c, cb->f[1], cipheralg);
} else if(strcmp(arg0, "auth") == 0) {
if(cb->nf != 2)
error("usage: auth alg");
setalg(c, cb->f[1], authalg);
} else if(strcmp(arg0, "comp") == 0) {
if(cb->nf != 2)
error("usage: comp alg");
setalg(c, cb->f[1], compalg);
} else if(strcmp(arg0, "insecret") == 0) {
if(cb->nf != 2)
error("usage: insecret secret");
setsecret(&c->in, cb->f[1]);
} else if(strcmp(arg0, "outsecret") == 0) {
if(cb->nf != 2)
error("usage: outsecret secret");
setsecret(&c->out, cb->f[1]);
.
300a
static void setalg(Conv *c, char *name, Algorithm *tab);
static void setsecret(OneWay *cc, char *secret);
static void nullcipherinit(Conv*c, char *name, int keylen);
static void descipherinit(Conv*c, char *name, int keylen);
static void rc4cipherinit(Conv*c, char *name, int keylen);
static void nullauthinit(Conv*c, char *name, int keylen);
static void shaauthinit(Conv*c, char *name, int keylen);
static void md5authinit(Conv*c, char *name, int keylen);
static void nullcompinit(Conv*c, char *name, int keylen);
static void thwackcompinit(Conv*c, char *name, int keylen);
static Algorithm cipheralg[] =
{
"null", 0, nullcipherinit,
"des_56_cbc", 7, descipherinit,
"rc4_128", 16, rc4cipherinit,
nil, 0, nil,
};
static Algorithm authalg[] =
{
"null", 0, nullauthinit,
"hmac_sha_96", 16, shaauthinit,
"hmac_md5_96", 16, md5authinit,
nil, 0, nil,
};
static Algorithm compalg[] =
{
"null", 0, nullcompinit,
"thwack", 0, thwackcompinit,
nil, 0, nil,
};
.
295,296c
static void convoput(Conv *c, int type, int subtype, Block *b);
static void convoconnect(Conv *c, int op, ulong dialid, ulong acceptid);
.
290c
static void conviconnect(Conv *c, int op, Block *b);
static void convicontrol(Conv *c, int op, Block *b);
static Block *convicomp(Conv *c, int op, Block *b);
.
225,249d
177,185d
169a
ControlMesg,
ControlAck,
};
enum {
.
165,166c
TCompData,
.
163d
140d
96c
int (*comp)(OneWay*, int subtype, Block **);
.
80a
uchar secret[SecretLength];
.
46c
SecretLength= 32, // a secret per direction
.
20d
## diffname port/devsdp.c 1999/1016
## diff -e /n/emeliedump/1999/1015/sys/src/brazil/port/devsdp.c /n/emeliedump/1999/1016/sys/src/brazil/port/devsdp.c
2028,2040c
c->compname = name;
c->in.compstate = malloc(sizeof(Unthwack));
unthwackinit(c->in.compstate);
c->out.compstate = malloc(sizeof(Thwack));
thwackinit(c->out.compstate);
c->in.comp = thwackuncomp;
c->out.comp = thwackcomp;
}
.
2025,2026c
static void
thwackcompinit(Conv *c, char *name, int keylen)
{
compfree(c);
.
2019,2023c
}
.
2014,2017c
*bp = b;
return 1;
.
2007,2008c
if(n < 0) {
print("unthwack failed: %r!\n");
freeb(b);
return 0;
}
.
1996,2003c
return 1;
case ThwackC:
bb = *bp;
.
1990,1991c
switch(subtype) {
default:
return 0;
case ThwackU:
b = *bp;
.
1988a
static int
thwackuncomp(Conv *c, int subtype, ulong seq, Block **bp)
{
Block *b, *bb;
ulong mask;
ulong mseq;
int n;
.
1986a
Block *b, *bb;
int nn;
// add ack info
b = padblock(*bp, 4);
b->rp[0] = (c->in.window>>1) & 0xff;
b->rp[1] = c->in.seq>>16;
b->rp[2] = c->in.seq>>8;
b->rp[3] = c->in.seq;
bb = allocb(BLEN(b));
nn = thwack(c->out.compstate, bb->wp, b->rp, BLEN(b), seq);
if(nn < 0) {
freeb(bb);
*bp = b;
return ThwackU;
} else {
bb->wp += nn;
freeb(b);
*bp = bb;
return ThwackC;
}
.
1984,1985c
static int
thwackcomp(Conv *c, int, ulong seq, Block **bp)
.
1981a
compfree(c);
.
1980c
nullcompinit(Conv *c, char*, int)
.
1958,1959c
c->authname = name;
.
1896a
cipherfree(c);
.
1866,1867c
c->ciphername = name;
.
1809d
1794,1797c
c->compname = nil;
.
1776,1779c
c->authname = nil;
.
1758,1761c
c->ciphername = nil;
.
1754d
1644c
// must generate same value as convoput
seq = (c->out.seq + 1) & (SeqMax-1);
subtype = (*c->out.comp)(c, 0, seq, &b);
.
1626a
ulong seq;
int subtype;
.
1383c
if(!(*c->in.comp)(c, subtype, seq, &b))
.
1377c
convicomp(Conv *c, int subtype, ulong seq, Block *b)
.
1364a
c->rstats.inBadComp = nhgetl(ack->inBadComp);
.
1191a
}
.
1189,1190c
b = convicomp(c, subtype, seq, b);
if(b == nil) {
c->lstats.inBadComp++;
.
1104c
subtype = b->rp[0] & 0xf;
.
1081a
hnputl(ack->inBadComp, s->inBadComp);
.
1051a
p += snprint(p, ep-p, "inBadComp: %ld\n", stats->inBadComp);
.
958,969c
c->ciphername = nil;
c->authname = nil;
c->compname = nil;
.
751,754d
261c
static Block *convicomp(Conv *c, int op, ulong, Block *b);
.
193a
uchar inBadComp[4];
.
172a
ThwackU,
ThwackC,
};
enum {
.
97c
int (*comp)(Conv*, int subtype, ulong seq, Block **);
.
67a
ulong inBadComp;
.
## diffname port/devsdp.c 1999/1019
## diff -e /n/emeliedump/1999/1016/sys/src/brazil/port/devsdp.c /n/emeliedump/1999/1019/sys/src/brazil/port/devsdp.c
1991c
nn = thwack(c->out.compstate, bb->wp, b->rp, BLEN(b), seq, c->lstats.outCompStats);
.
1313a
int i;
.
1069a
for(i=0; i<NCompStat; i++)
hnputl(ack->outCompStats+i*4, s->outCompStats[i]);
.
1059a
int i;
.
1035,1048c
p += snprint(p, ep-p, "outPackets: %lud\n", stats->outPackets);
p += snprint(p, ep-p, "outDataPackets: %lud\n", stats->outDataPackets);
p += snprint(p, ep-p, "outDataBytes: %lud\n", stats->outDataBytes);
p += snprint(p, ep-p, "outCompDataBytes: %lud\n", stats->outCompDataBytes);
for(i=0; i<NCompStat; i++) {
if(stat->outCompStats[i] == 0)
continue;
p += snprint(p, ep-p, "outCompStats[%d]: %lud\n", i, stats->outCompStats[i]);
}
p += snprint(p, ep-p, "outCompDataBytes: %lud\n", stats->outCompDataBytes);
p += snprint(p, ep-p, "inPackets: %lud\n", stats->inPackets);
p += snprint(p, ep-p, "inDataPackets: %lud\n", stats->inDataPackets);
p += snprint(p, ep-p, "inDataBytes: %lud\n", stats->inDataBytes);
p += snprint(p, ep-p, "inCompDataBytes: %lud\n", stats->inCompDataBytes);
p += snprint(p, ep-p, "inMissing: %lud\n", stats->inMissing);
p += snprint(p, ep-p, "inDup: %lud\n", stats->inDup);
p += snprint(p, ep-p, "inReorder: %lud\n", stats->inReorder);
p += snprint(p, ep-p, "inBadComp: %lud\n", stats->inBadComp);
p += snprint(p, ep-p, "inBadAuth: %lud\n", stats->inBadAuth);
p += snprint(p, ep-p, "inBadSeq: %lud\n", stats->inBadSeq);
.
1020a
int i;
.
192a
uchar outCompStats[4*NCompStats];
.
60a
ulong outCompStats[NCompStats];
.
47a
NCompStats = 8,
.
## diffname port/devsdp.c 1999/1021
## diff -e /n/emeliedump/1999/1019/sys/src/brazil/port/devsdp.c /n/emeliedump/1999/1021/sys/src/brazil/port/devsdp.c
2005c
nn = thwack(c->out.compstate, bb->wp, b->rp, BLEN(b), seq);
.
1327d
1081c
for(i=0; i<NCompStats; i++)
.
1043,1044c
for(i=0; i<NCompStats; i++) {
if(stats->outCompStats[i] == 0)
.
## diffname port/devsdp.c 1999/1022
## diff -e /n/emeliedump/1999/1021/sys/src/brazil/port/devsdp.c /n/emeliedump/1999/1022/sys/src/brazil/port/devsdp.c
2060d
2056c
thwackcompinit(Conv *c)
.
2004c
nn = thwack(c->out.compstate, bb->wp, b->rp, BLEN(b), seq, c->lstats.outCompStats);
.
1985c
nullcompinit(Conv *c)
.
1964,1965c
keylen = c->auth->keylen;
.
1961a
int keylen;
.
1960c
md5authinit(Conv *c)
.
1912c
shaauthinit(Conv *c)
.
1906c
nullauthinit(Conv *c)
.
1902a
n = c->cipher->keylen;
if(n > sizeof(key))
n = sizeof(key);
/* in */
memset(key, 0, sizeof(key));
setkey(key, n, &c->in, "cipher");
c->in.cipherblklen = 1;
c->in.cipherivlen = 4;
c->in.cipher = rc4decrypt;
cr = smalloc(sizeof(CipherRc4));
memset(cr, 0, sizeof(*cr));
setupRC4state(&cr->current, key, n);
c->in.cipherstate = cr;
/* out */
memset(key, 0, sizeof(key));
setkey(key, n, &c->out, "cipher");
c->out.cipherblklen = 1;
c->out.cipherivlen = 4;
c->out.cipher = rc4encrypt;
cr = smalloc(sizeof(CipherRc4));
memset(cr, 0, sizeof(*cr));
setupRC4state(&cr->current, key, n);
c->out.cipherstate = cr;
.
1901a
uchar key[32];
CipherRc4 *cr;
int n;
.
1900c
rc4cipherinit(Conv *c)
.
1898a
static int
rc4encrypt(OneWay *ow, uchar *p, int n)
{
CipherRc4 *cr = ow->cipherstate;
if(n < 4)
return 0;
hnputl(p, cr->cseq);
p += 4;
n -= 4;
rc4(&cr->current, p, n);
cr->cseq += n;
return 1;
}
static int
rc4decrypt(OneWay *ow, uchar *p, int n)
{
CipherRc4 *cr = ow->cipherstate;
RC4state tmpstate;
ulong seq;
long d, dd;
if(n < 4)
return 0;
seq = nhgetl(p);
p += 4;
n -= 4;
d = seq-cr->cseq;
if(d == 0) {
rc4(&cr->current, p, n);
cr->cseq += n;
if(cr->ovalid) {
dd = cr->cseq - cr->lgseq;
if(dd > RC4back)
cr->ovalid = 0;
}
} else if(d > 0) {
print("missing packet: %uld %ld\n", seq, d);
// this link is hosed
if(d > RC4forward)
return 0;
cr->lgseq = seq;
if(!cr->ovalid) {
cr->ovalid = 1;
cr->oseq = cr->cseq;
memmove(&cr->old, &cr->current, sizeof(RC4state));
}
rc4skip(&cr->current, d);
rc4(&cr->current, p, n);
cr->cseq = seq+n;
} else {
print("reordered packet: %uld %ld\n", seq, d);
dd = seq - cr->oseq;
if(!cr->ovalid || -d > RC4back || dd < 0)
return 0;
memmove(&tmpstate, &cr->old, sizeof(RC4state));
rc4skip(&tmpstate, dd);
rc4(&tmpstate, p, n);
return 1;
}
// move old state up
if(cr->ovalid) {
dd = cr->cseq - RC4back - cr->oseq;
if(dd > 0) {
rc4skip(&cr->old, dd);
cr->oseq += dd;
}
}
return 1;
}
.
1872d
1869a
int n = c->cipher->keylen;
.
1865c
descipherinit(Conv *c)
.
1847a
if(n < 8 || (n & 0x7 != 0))
return 0;
.
1827a
if(n < 8 || (n & 0x7 != 0))
return 0;
.
1817c
nullcipherinit(Conv *c)
.
1804d
1798a
c->in.authlen = 0;
c->out.authlen = 0;
.
1789d
1783a
c->in.cipherblklen = 0;
c->out.cipherblklen = 0;
c->in.cipherivlen = 0;
c->out.cipherivlen = 0;
.
1774d
1721c
*p = alg;
alg->init(c);
.
1713c
setalg(Conv *c, char *name, Algorithm *alg, Algorithm **p)
.
1438d
1435c
if(c->out.cipher)
(*c->out.cipher)(&c->out, b->rp+4, BLEN(b)-4);
.
1422a
/* Make room for sdp trailer */
if(c->out.cipherblklen > 1)
pad = c->out.cipherblklen - (BLEN(b) + c->out.cipherivlen) % c->out.cipherblklen;
else
pad = 0;
b = padblock(b, -(pad+c->out.authlen));
if(pad) {
memset(b->wp, 0, pad-1);
b->wp[pad-1] = pad;
b->wp += pad;
}
.
1421c
int pad;
.
1378a
c->rstats.inBadOther = nhgetl(ack->inBadOther);
.
1368a
for(i=0; i<NCompStats; i++)
c->rstats.outCompStats[i] = nhgetl(ack->outCompStats + 4*i);
.
1326a
int i;
.
1208a
c->lstats.inBadOther++;
.
1163c
if(c->in.cipher != 0) {
if(!(*c->in.cipher)(&c->in, b->rp, BLEN(b))) {
print("bad cipher\n");
c->lstats.inBadOther++;
freeb(b);
return nil;
}
b->rp += c->in.cipherivlen;
if(c->in.cipherblklen > 1) {
pad = b->wp[-1];
if(pad > BLEN(b)) {
print("pad too big\n");
c->lstats.inBadOther++;
freeb(b);
return nil;
}
b->wp -= pad;
}
}
.
1107a
c->lstats.inBadOther++;
.
1103a
int pad;
.
1092a
hnputl(ack->inBadOther, s->inBadOther);
.
1058a
p += snprint(p, ep-p, "inBadOther: %lud\n", stats->inBadOther);
.
1048d
964,966c
c->cipher = nil;
c->auth = nil;
c->comp = nil;
.
937c
setalg(c, "hmac_md5_96", authalg, &c->auth);
.
636a
if(c->cipher)
c->cipher->init(c);
if(c->auth)
c->auth->init(c);
.
632a
if(c->cipher)
c->cipher->init(c);
if(c->auth)
c->auth->init(c);
.
628c
setalg(c, cb->f[1], compalg, &c->comp);
.
624c
setalg(c, cb->f[1], authalg, &c->auth);
.
620c
setalg(c, cb->f[1], cipheralg, &c->cipher);
.
298a
"rc4_256", 32, rc4cipherinit,
.
285,292c
static void nullcipherinit(Conv*c);
static void descipherinit(Conv*c);
static void rc4cipherinit(Conv*c);
static void nullauthinit(Conv*c);
static void shaauthinit(Conv*c);
static void md5authinit(Conv*c);
static void nullcompinit(Conv*c);
static void thwackcompinit(Conv*c);
.
282c
static void setalg(Conv *c, char *name, Algorithm *tab, Algorithm **);
.
214a
enum {
RC4forward = 10*1024*1024, // maximum skip forward
RC4back = 100*1024, // maximum look back
};
struct CipherRc4
{
ulong cseq; // current byte sequence number
RC4state current;
int ovalid; // old is valid
ulong lgseq; // last good sequence
ulong oseq; // old byte sequence number
RC4state old;
};
.
212c
void (*init)(Conv*);
.
205a
uchar inBadOther[4];
.
144,146c
Algorithm *auth;
Algorithm *cipher;
Algorithm *comp;
.
72a
ulong inBadOther;
.
21a
typedef struct CipherRc4 CipherRc4;
.
## diffname port/devsdp.c 1999/1027
## diff -e /n/emeliedump/1999/1022/sys/src/brazil/port/devsdp.c /n/emeliedump/1999/1027/sys/src/brazil/port/devsdp.c
974c
// convoconnect(c, ConReset, c->dialid, c->acceptid);
.
908c
'E',
.
558a
print("readcontrol asked %ld\n", n);
.
370c
c = devattach('E', spec);
.
342a
return;
.
333c
// "thwack", 0, thwackcompinit,
.
## diffname port/devsdp.c 1999/1028
## diff -e /n/emeliedump/1999/1027/sys/src/brazil/port/devsdp.c /n/emeliedump/1999/1028/sys/src/brazil/port/devsdp.c
561d
333c
"thwack", 0, thwackcompinit,
.
## diffname port/devsdp.c 1999/1031
## diff -e /n/emeliedump/1999/1028/sys/src/brazil/port/devsdp.c /n/emeliedump/1999/1031/sys/src/9/port/devsdp.c
1729c
if(c->out.comp != nil && 0) {
.
1188c
print("bad auth %d\n", BLEN(b)+4);
.
## diffname port/devsdp.c 1999/1106
## diff -e /n/emeliedump/1999/1031/sys/src/9/port/devsdp.c /n/emeliedump/1999/1106/sys/src/9/port/devsdp.c
1729c
if(0 && c->out.comp != nil) {
.
1703a
}
.
1702c
if(b != nil) {
if(BLEN(b) > n)
b->wp = b->rp + n;
.
1691c
// some slack for tunneling overhead
nn = n + 100;
// make sure size is big enough for control messages
if(nn < 1000)
nn = 1000;
b = convreadblock(c, nn);
.
1688a
int nn;
.
1188c
print("bad auth %ld\n", BLEN(b)+4);
.
## diffname port/devsdp.c 1999/1111
## diff -e /n/emeliedump/1999/1106/sys/src/9/port/devsdp.c /n/emeliedump/1999/1111/sys/src/9/port/devsdp.c
1740c
if(c->out.comp != nil) {
.
## diffname port/devsdp.c 1999/1116
## diff -e /n/emeliedump/1999/1111/sys/src/9/port/devsdp.c /n/emeliedump/1999/1116/sys/src/9/port/devsdp.c
777c
if(c->state == CClosed && c->reader == 0 && c->ref == 0)
.
344,345d
## diffname port/devsdp.c 1999/1211
## diff -e /n/emeliedump/1999/1116/sys/src/9/port/devsdp.c /n/emeliedump/1999/1211/sys/src/9/port/devsdp.c
2042c
//print("reordered packet: %uld %ld\n", seq, d);
.
2028c
//print("missing packet: %uld %ld\n", seq, d);
.
1785a
convderef(c);
.
1773,1776c
convsetstate(c, CClosed);
.
1562d
1557c
assert(c->ref > 0);
.
1545,1546d
1540c
Chan *ch;
.
1533c
if(!waserror()) {
convwriteblock(c, b);
poperror();
}
.
1523,1526c
assert(c->chan != nil);
.
1225c
//print("missing packets: %ld-%ld\n", seq - SeqWindow - seqdiff+1, seq-SeqWindow);
.
1218c
//print("missing packet: %ld\n", seq - seqdiff);
.
1043a
c->ref++;
.
1042a
assert(c->reader == 0 && c->ref > 0);
// after kproc in case it fails
.
1011a
convderef(Conv *c)
{
c->ref--;
print("convderef: %d: ref == %d\n", c->id, c->ref);
if(c->ref > 0)
return;
assert(c->ref == 0);
assert(c->dataopen == 0);
assert(c->controlopen == 0);
//print("convderef: %d: ref == 0!\n", c->id);
c->state = CFree;
if(c->chan) {
cclose(c->chan);
c->chan = nil;
}
if(c->channame) {
free(c->channame);
c->channame = nil;
}
c->cipher = nil;
c->auth = nil;
c->comp = nil;
strcpy(c->owner, "network");
c->perm = 0660;
c->dialid = 0;
c->acceptid = 0;
c->timeout = 0;
c->retries = 0;
c->drop = 0;
onewaycleanup(&c->in);
onewaycleanup(&c->out);
memset(&c->lstats, 0, sizeof(Stats));
memset(&c->rstats, 0, sizeof(Stats));
}
static void
.
1010a
//assumes c is locked
.
981,1005c
if(c->state != CClosed)
convderef(c);
.
974c
wakeup(&c->out.controlready);
.
951a
c->lastrecv = TK2SEC(m->ticks);
.
901a
qunlock(c);
qlock(sdp);
.
898c
if(c->ref == 0)
continue;
qunlock(sdp);
qlock(c);
if(c->ref > 0 && !waserror()) {
.
879,880d
876d
834a
case CInit:
break;
.
829,833c
.
821a
// assumes c is locked
.
786c
assert(c->state == CFree);
// set ref to 2 - 1 ref for open - 1 ref for channel state
c->ref = 2;
.
774,775c
if(c->ref == 0 && canqlock(c)){
print("%d: state=%d reader=%d ref=%d\n", c->id, c->state, c->reader, c->ref);
if(c->ref == 0)
.
518,519d
501,509c
qunlock(c);
break;
case Qcontrol:
c = sdp->conv[CONV(ch->qid)];
qlock(c);
c->controlopen--;
convderef(c);
if(c->controlopen == 0 && c->ref != 0) {
.
497,499c
convderef(c);
qunlock(c);
break;
case Qdata:
c = sdp->conv[CONV(ch->qid)];
qlock(c);
c->dataopen--;
convderef(c);
if(c->dataopen == 0)
if(c->reader == 0)
if(c->chan != nil)
if(!waserror()) {
kproc("convreader", convreader, c);
c->reader = 1;
c->ref++;
poperror();
.
492,494c
case Qstats:
case Qrstats:
.
489d
486,487c
logclose(sdp);
.
483a
if(!(ch->flag & COPEN))
return;
.
466c
} else if(TYPE(ch->qid) == Qcontrol) {
c->controlopen++;
.
463c
c->dataopen++;
// kill reader if Qdata is opened for the first time
if(c->dataopen == 1)
.
460a
.
452a
print("open %d:%d: ref=%d\n", c->id, TYPE(ch->qid), c->ref);
.
414a
.
299a
static void convreader(void *a);
.
297d
291,294d
286a
static void convsetstate(Conv *c, int state);
static Block *readcontrol(Conv *c, int n);
static void writecontrol(Conv *c, void *p, int n, int wait);
static Block *readdata(Conv *c, int n);
static long writedata(Conv *c, Block *b);
static void convderef(Conv *c);
.
282d
277c
[CClosed] "Closed",
.
271,274c
[CFree] "Free",
[CInit] "Init",
[CDial] "Dial",
[CAccept] "Accept",
[COpen] "Open",
.
140c
Chan *chan; // packet channel
.
123c
int dataopen; // ref count of opens on Qdata
int controlopen; // ref count of opens on Qcontrol
.
121a
int ref; // holds conv up
.
120a
int id;
.
118,119d
106a
CFree,
.
44,45c
MaxRetries= 4,
KeepAlive = 10, // keep alive in seconds
.
## diffname port/devsdp.c 1999/1221
## diff -e /n/emeliedump/1999/1211/sys/src/9/port/devsdp.c /n/emeliedump/1999/1221/sys/src/9/port/devsdp.c
44,45c
MaxRetries= 12,
KeepAlive = 120, // keep alive in seconds
.
## diffname port/devsdp.c 1999/1230
## diff -e /n/emeliedump/1999/1221/sys/src/9/port/devsdp.c /n/emeliedump/1999/1230/sys/src/9/port/devsdp.c
729a
if(s == DEVDOTDOT){
switch(TYPE(c->qid)){
case Qtopdir:
case Qsdpdir:
snprint(buf, sizeof(buf), "#E%d", c->dev);
devdir(c, (Qid){CHDIR|Qtopdir, 0}, buf, 0, eve, 0555, dp);
break;
case Qconvdir:
snprint(buf, sizeof(buf), "%d", s);
devdir(c, (Qid){CHDIR|Qsdpdir, 0}, buf, 0, eve, 0555, dp);
break;
default:
panic("sdpwalk %lux", c->qid.path);
}
return 1;
}
.
397,411d
## diffname port/devsdp.c 2000/0112
## diff -e /n/emeliedump/1999/1230/sys/src/9/port/devsdp.c /n/emeliedump/2000/0112/sys/src/9/port/devsdp.c
2194c
seanq_hmac_md5(hash, ow->seqwrap, t, tlen, (uchar*)ow->authstate, 16);
.
2159c
seanq_hmac_md5(uchar hash[MD5dlen], ulong wrap, uchar *t, long tlen, uchar *key, long klen)
.
1888,1889c
sha1((uchar*)prefix, strlen(prefix), ibuf, sha1(salt, round+1, nil, nil));
md5(ibuf, SHA1dlen, obuf, md5(ow->secret, sizeof(ow->secret), nil, nil));
.
1882c
uchar ibuf[SHA1dlen], obuf[MD5dlen], salt[10];
.
996c
setalg(c, "seanq_hmac_md5_96", authalg, &c->auth);
.
331,332c
"seanq_hmac_sha1_96", 16, shaauthinit,
"seanq_hmac_md5_96", 16, md5authinit,
.
9c
#include <libsec.h>
.
## diffname port/devsdp.c 2000/0115
## diff -e /n/emeliedump/2000/0112/sys/src/9/port/devsdp.c /n/emeliedump/2000/0115/sys/src/9/port/devsdp.c
996c
setalg(c, "hmac_md5_96", authalg, &c->auth);
.
331,332c
"hmac_sha1_96", 16, shaauthinit,
"hmac_md5_96", 16, md5authinit,
.
## diffname port/devsdp.c 2000/0215
## diff -e /n/emeliedump/2000/0115/sys/src/9/port/devsdp.c /n/emeliedump/2000/0215/sys/src/9/port/devsdp.c
1640c
if(c->chan == nil || c->state == CClosed) {
.
1420a
convsetstate(c, CClosed);
.
1412,1413d
1405,1408d
1403c
case ConCloseAck:
.
1399a
// duplicate ConClose
convoconnect(c, ConCloseAck, dialid, acceptid);
.
1396a
convoconnect(c, ConCloseAck, dialid, acceptid);
.
1390,1395d
1388d
1382a
case CLocalClose:
case CRemoteClose:
.
1330a
if(subtype == ConReset) {
convsetstate(c, CClosed);
return;
}
.
1201a
switch(c->state) {
case CInit:
case CDial:
c->lstats.inBadOther++;
convoconnect(c, ConReset, c->dialid, c->acceptid);
convsetstate(c, CClosed);
break;
case CAccept:
case CRemoteClose:
case CLocalClose:
c->lstats.inBadOther++;
freeb(b);
return nil;
}
.
720c
snprint(buf, sizeof(buf), "#E%ld", c->dev);
.
445c
print("open %d:%ld: ref=%d\n", c->id, TYPE(ch->qid), c->ref);
.
190a
ConCloseAck,
.
## diffname port/devsdp.c 2000/0222
## diff -e /n/emeliedump/2000/0215/sys/src/9/port/devsdp.c /n/emeliedump/2000/0222/sys/src/9/port/devsdp.c
1843d
1833d
1821d
1701d
1698,1699c
if(c->state == CInit || c->state == CClosed || c->state == CRemoteClose)
.
1665c
if(0)print("readcontrol: return nil - state = %s\n", convstatename[c->state]);
.
1656c
if(0)print("readcontrol: return error - state = %s\n", convstatename[c->state]);
.
1477d
1474,1475c
if(cseq != c->out.controlseq)
.
1432c
if(0)print("invalid conviconnect - sending reset\n");
.
1345c
if(0)print("conviconnect: %s: %d %uld %uld\n", convstatename[c->state], subtype, dialid, acceptid);
.
1026d
964c
if(0)print("convsetstate %s -> %s\n", convstatename[c->state], convstatename[state]);
.
885d
841d
839d
801d
570d
446d
## diffname port/devsdp.c 2000/0425
## diff -e /n/emeliedump/2000/0222/sys/src/9/port/devsdp.c /n/emeliedump/2000/0425/sys/src/9/port/devsdp.c
2304a
if(c->out.compstate == nil)
error(Enomem);
.
2302a
if(c->in.compstate == nil)
error(Enomem);
.
1073c
c->channame = smalloc(strlen(path)+1);
.
1025c
if(0)print("convderef: %d: ref == 0!\n", c->id);
.
1021a
}
.
1020c
if(c->ref > 0) {
.
958c
if(1)print("convsetstate %d: %s -> %s\n", c->id, convstatename[c->state], convstatename[state]);
.
## diffname port/devsdp.c 2000/0617
## diff -e /n/emeliedump/2000/0425/sys/src/9/port/devsdp.c /n/emeliedump/2000/0617/sys/src/9/port/devsdp.c
531d
## diffname port/devsdp.c 2001/0213
## diff -e /n/emeliedump/2000/0617/sys/src/9/port/devsdp.c /n/emeliedump/2001/0213/sys/src/9/port/devsdp.c
2283c
print("unthwack failed: %d\n", n);
.
2240,2243c
b->rp[0] = (c->in.compwindow>>1) & 0xff;
b->rp[1] = c->in.compseq>>16;
b->rp[2] = c->in.compseq>>8;
b->rp[3] = c->in.compseq;
.
1689c
if(c->state == CFree || c->state == CInit ||
c->state == CClosed || c->state == CRemoteClose)
.
1317c
print("dropping packet id=%d: type=%d n=%ld control=%d\n", c->id, type, BLEN(b), control);
.
1311a
c->in.compseq = c->in.seq;
c->in.compwindow = c->in.window;
.
1291a
c->in.window |= 1<<-seqdiff;
.
1290d
1286a
seqdiff = 0;
.
1285d
1278d
101a
ulong compseq;
ulong compwindow;
.
## diffname port/devsdp.c 2001/0214
## diff -e /n/emeliedump/2001/0213/sys/src/9/port/devsdp.c /n/emeliedump/2001/0214/sys/src/9/port/devsdp.c
2244,2247c
ackseq = unthwackstate(c->in.compstate, &mask);
b->rp[0] = mask;
b->rp[1] = ackseq>>16;
b->rp[2] = ackseq>>8;
b->rp[3] = ackseq;
.
2240a
ulong ackseq;
uchar mask;
.
1313,1314d
102,103d
## diffname port/devsdp.c 2001/0918
## diff -e /n/emeliedump/2001/0214/sys/src/9/port/devsdp.c /n/emeliedump/2001/0918/sys/src/9/port/devsdp.c
938d
765c
mkqid(&qid, QID(CONV(c->qid),TYPE(dt->qid)), 0, QTFILE);
.
757,759c
mkqid(&qid, QID(s, Qconvdir), 0, QTDIR);
snprint(up->genbuf, sizeof(up->genbuf), "%d", s);
devdir(c, qid, up->genbuf, 0, eve, 0555, dp);
.
746c
mkqid(&qid, QID(0, Qsdpdir), 0, QTDIR);
devdir(c, qid, "sdp", 0, eve, 0555, dp);
.
734c
if(c->qid.type & QTDIR)
.
722,723c
snprint(up->genbuf, sizeof(up->genbuf), "%d", s);
mkqid(&qid, Qsdpdir, 0, QTDIR);
devdir(c, qid, up->genbuf, 0, eve, 0555, dp);
.
718,719c
snprint(up->genbuf, sizeof(up->genbuf), "#E%ld", c->dev);
mkqid(&qid, Qtopdir, 0, QTDIR);
devdir(c, qid, up->genbuf, 0, eve, 0555, dp);
.
710d
706c
sdpgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp)
.
407d
404c
return devstat(c, db, n, nil, 0, sdpgen);
.
401,402c
static int
sdpstat(Chan* c, uchar* db, int n)
.
398c
return devwalk(c, nc, name, nname, 0, 0, sdpgen);
.
395,396c
static Walkqid*
sdpwalk(Chan *c, Chan *nc, char **name, int nname)
.
378c
c->qid = (Qid){QID(0, Qtopdir), 0, QTDIR};
.
286c
static int sdpgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp);
.
147c
char owner[KNAMELEN]; /* protections */
.
52,53c
#define TYPE(x) (((ulong)(x).path) & 0xff)
#define CONV(x) ((((ulong)(x).path) >> 8)&(Maxconv-1))
.
## diffname port/devsdp.c 2001/0926
## diff -e /n/emeliedump/2001/0918/sys/src/9/port/devsdp.c /n/emeliedump/2001/0926/sys/src/9/port/devsdp.c
1821c
if(strcmp(up->errstr, Eintr) != 0) {
.
## diffname port/devsdp.c 2002/0109
## diff -e /n/emeliedump/2001/0926/sys/src/9/port/devsdp.c /n/emeliedump/2002/0109/sys/src/9/port/devsdp.c
937a
devshutdown,
.
## diffname port/devsdp.c 2002/0125
## diff -e /n/emeliedump/2002/0109/sys/src/9/port/devsdp.c /n/emeliedump/2002/0125/sys/src/9/port/devsdp.c
740c
panic("sdpgen: unknown type: %lud", TYPE(c->qid));
.
726c
panic("sdpwalk %llux", c->qid.path);
.
## diffname port/devsdp.c 2002/0326
## diff -e /n/emeliedump/2002/0125/sys/src/9/port/devsdp.c /n/emeliedump/2002/0326/sys/src/9/port/devsdp.c
2288c
if(0)print("unthwack failed: %d\n", n);
.
1444c
if(0)print("duplicate control packet: %ulx\n", cseq);
.
1317c
if(0)print("dropping packet id=%d: type=%d n=%ld control=%d\n", c->id, type, BLEN(b), control);
.
1266c
if(0)print("pad too big\n");
.
1257c
if(0)print("bad cipher\n");
.
1247c
if(0)print("bad auth %ld\n", BLEN(b)+4);
.
1234c
if(0)print("dup sequence number: %ld (%ld %ld)\n", seq, c->in.seqwrap, seqdiff);
.
1227c
if(0)print("old sequence number: %ld (%ld %ld)\n", seq, c->in.seqwrap, seqdiff);
.
958c
if(0)print("convsetstate %d: %s -> %s\n", c->id, convstatename[c->state], convstatename[state]);
.
## diffname port/devsdp.c 2002/0612
## diff -e /n/emeliedump/2002/0326/sys/src/9/port/devsdp.c /n/emeliedump/2002/0612/sys/src/9/port/devsdp.c
1425c
if(1)print("invalid conviconnect - sending reset\n");
.
45c
KeepAlive = 60, // keep alive in seconds
.
43c
Nfs= 4, // number of file systems
.
## diffname port/devsdp.c 2002/0625
## diff -e /n/emeliedump/2002/0612/sys/src/9/port/devsdp.c /n/emeliedump/2002/0625/sys/src/9/port/devsdp.c
45c
KeepAlive = 300, // keep alive in seconds - should probably be about 60 but is higher to avoid linksys bug
.
## diffname port/devsdp.c 2003/0407
## diff -e /n/emeliedump/2002/0625/sys/src/9/port/devsdp.c /n/emeliedump/2003/0407/sys/src/9/port/devsdp.c
912c
tsleep(&up->sleep, return0, 0, 1000);
.
163d
|