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