The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/port/devsdp.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 #include "u.h"
    2 #include "../port/lib.h"
    3 #include "mem.h"
    4 #include "dat.h"
    5 #include "fns.h"
    6 #include "../port/netif.h"
    7 #include "../port/error.h"
    8 
    9 #include        <libsec.h>
   10 #include "../port/thwack.h"
   11 
   12 /*
   13  * sdp - secure datagram protocol
   14  */
   15 
   16 typedef struct Sdp Sdp;
   17 typedef struct Conv Conv;
   18 typedef struct OneWay OneWay;
   19 typedef struct Stats Stats;
   20 typedef struct AckPkt AckPkt;
   21 typedef struct Algorithm Algorithm;
   22 typedef struct CipherRc4 CipherRc4;
   23 
   24 enum
   25 {
   26         Qtopdir=        1,              /* top level directory */
   27 
   28         Qsdpdir,                        /* sdp directory */
   29         Qclone,
   30         Qlog,
   31 
   32         Qconvdir,                       /* directory per conversation */
   33         Qctl,
   34         Qdata,                          /* unreliable packet channel */
   35         Qcontrol,                       /* reliable control channel */
   36         Qstatus,
   37         Qstats,
   38         Qrstats,
   39 
   40         MaxQ,
   41 
   42         Maxconv= 256,           // power of 2
   43         Nfs= 4,                 // number of file systems
   44         MaxRetries=     12,
   45         KeepAlive = 300,        // keep alive in seconds - should probably be about 60 but is higher to avoid linksys bug
   46         SecretLength= 32,       // a secret per direction
   47         SeqMax = (1<<24),
   48         SeqWindow = 32,
   49         NCompStats = 8,
   50 };
   51 
   52 #define TYPE(x)         (((ulong)(x).path) & 0xff)
   53 #define CONV(x)         ((((ulong)(x).path) >> 8)&(Maxconv-1))
   54 #define QID(x, y)       (((x)<<8) | (y))
   55 
   56 struct Stats
   57 {
   58         ulong   outPackets;
   59         ulong   outDataPackets;
   60         ulong   outDataBytes;
   61         ulong   outCompDataBytes;
   62         ulong   outCompBytes;
   63         ulong   outCompStats[NCompStats];
   64         ulong   inPackets;
   65         ulong   inDataPackets;
   66         ulong   inDataBytes;
   67         ulong   inCompDataBytes;
   68         ulong   inMissing;
   69         ulong   inDup;
   70         ulong   inReorder;
   71         ulong   inBadComp;
   72         ulong   inBadAuth;
   73         ulong   inBadSeq;
   74         ulong   inBadOther;
   75 };
   76 
   77 struct OneWay
   78 {
   79         Rendez  statsready;
   80 
   81         ulong   seqwrap;        // number of wraps of the sequence number
   82         ulong   seq;
   83         ulong   window;
   84 
   85         uchar   secret[SecretLength];
   86 
   87         QLock   controllk;
   88         Rendez  controlready;
   89         Block   *controlpkt;            // control channel
   90         ulong   controlseq;
   91 
   92         void    *cipherstate;   // state cipher
   93         int             cipherivlen;    // initial vector length
   94         int             cipherblklen;   // block length
   95         int             (*cipher)(OneWay*, uchar *buf, int len);
   96 
   97         void    *authstate;             // auth state
   98         int             authlen;                // auth data length in bytes
   99         int             (*auth)(OneWay*, uchar *buf, int len);
  100 
  101         void    *compstate;
  102         int             (*comp)(Conv*, int subtype, ulong seq, Block **);
  103 };
  104 
  105 // conv states
  106 enum {
  107         CFree,
  108         CInit,
  109         CDial,
  110         CAccept,
  111         COpen,
  112         CLocalClose,
  113         CRemoteClose,
  114         CClosed,
  115 };
  116 
  117 struct Conv {
  118         QLock;
  119         Sdp     *sdp;
  120         int     id;
  121 
  122         int ref;        // holds conv up
  123 
  124         int state;
  125 
  126         int dataopen;   // ref count of opens on Qdata
  127         int controlopen;        // ref count of opens on Qcontrol
  128         int reader;             // reader proc has been started
  129 
  130         Stats   lstats;
  131         Stats   rstats;
  132         
  133         ulong   lastrecv;       // time last packet was received 
  134         ulong   timeout;
  135         int             retries;
  136 
  137         // the following pair uniquely define conversation on this port
  138         ulong dialid;
  139         ulong acceptid;
  140 
  141         QLock readlk;           // protects readproc
  142         Proc *readproc;
  143 
  144         Chan *chan;             // packet channel
  145         char *channame;
  146 
  147         char owner[KNAMELEN];           /* protections */
  148         int     perm;
  149 
  150         Algorithm *auth;
  151         Algorithm *cipher;
  152         Algorithm *comp;
  153 
  154         int drop;
  155 
  156         OneWay  in;
  157         OneWay  out;
  158 };
  159 
  160 struct Sdp {
  161         QLock;
  162         Log;
  163         int     nconv;
  164         Conv *conv[Maxconv];
  165         int ackproc;
  166 };
  167 
  168 enum {
  169         TConnect,
  170         TControl,
  171         TData,
  172         TCompData,
  173 };
  174 
  175 enum {
  176         ControlMesg,
  177         ControlAck,
  178 };
  179 
  180 enum {
  181         ThwackU,
  182         ThwackC,
  183 };
  184 
  185 enum {
  186         ConOpenRequest,
  187         ConOpenAck,
  188         ConOpenAckAck,
  189         ConClose,
  190         ConCloseAck,
  191         ConReset,
  192 };
  193 
  194 struct AckPkt
  195 {
  196         uchar   cseq[4];
  197         uchar   outPackets[4];
  198         uchar   outDataPackets[4];
  199         uchar   outDataBytes[4];
  200         uchar   outCompDataBytes[4];
  201         uchar   outCompStats[4*NCompStats];
  202         uchar   inPackets[4];
  203         uchar   inDataPackets[4];
  204         uchar   inDataBytes[4];
  205         uchar   inCompDataBytes[4];
  206         uchar   inMissing[4];
  207         uchar   inDup[4];
  208         uchar   inReorder[4];
  209         uchar   inBadComp[4];
  210         uchar   inBadAuth[4];
  211         uchar   inBadSeq[4];
  212         uchar   inBadOther[4];
  213 };
  214 
  215 struct Algorithm
  216 {
  217         char    *name;
  218         int             keylen;         // in bytes
  219         void    (*init)(Conv*);
  220 };
  221 
  222 enum {
  223         RC4forward      = 10*1024*1024, // maximum skip forward
  224         RC4back = 100*1024,             // maximum look back
  225 };
  226 
  227 struct CipherRc4
  228 {
  229         ulong cseq;     // current byte sequence number
  230         RC4state current;
  231 
  232         int ovalid;     // old is valid
  233         ulong lgseq; // last good sequence
  234         ulong oseq;     // old byte sequence number
  235         RC4state old;
  236 };
  237 
  238 static Dirtab sdpdirtab[]={
  239         "log",          {Qlog},         0,      0666,
  240         "clone",        {Qclone},               0,      0666,
  241 };
  242 
  243 static Dirtab convdirtab[]={
  244         "ctl",          {Qctl}, 0,      0666,
  245         "data",         {Qdata},        0,      0666,
  246         "control",      {Qcontrol},     0,      0666,
  247         "status",       {Qstatus},      0,      0444,
  248         "stats",        {Qstats},       0,      0444,
  249         "rstats",       {Qrstats},      0,      0444,
  250 };
  251 
  252 static int m2p[] = {
  253         [OREAD]         4,
  254         [OWRITE]        2,
  255         [ORDWR]         6
  256 };
  257 
  258 enum {
  259         Logcompress=    (1<<0),
  260         Logauth=        (1<<1),
  261         Loghmac=        (1<<2),
  262 };
  263 
  264 static Logflag logflags[] =
  265 {
  266         { "compress",   Logcompress, },
  267         { "auth",       Logauth, },
  268         { "hmac",       Loghmac, },
  269         { nil,          0, },
  270 };
  271 
  272 static Dirtab   *dirtab[MaxQ];
  273 static Sdp sdptab[Nfs];
  274 static char *convstatename[] = {
  275         [CFree]         "Free",
  276         [CInit]         "Init",
  277         [CDial]         "Dial",
  278         [CAccept]       "Accept",
  279         [COpen]         "Open",
  280         [CLocalClose] "LocalClose",
  281         [CRemoteClose] "RemoteClose",
  282         [CClosed]       "Closed",
  283 };
  284 
  285 static int sdpgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp);
  286 static Conv *sdpclone(Sdp *sdp);
  287 static void sdpackproc(void *a);
  288 static void onewaycleanup(OneWay *ow);
  289 static int readready(void *a);
  290 static int controlread();
  291 static void convsetstate(Conv *c, int state);
  292 static Block *readcontrol(Conv *c, int n);
  293 static void writecontrol(Conv *c, void *p, int n, int wait);
  294 static Block *readdata(Conv *c, int n);
  295 static long writedata(Conv *c, Block *b);
  296 static void convderef(Conv *c);
  297 static Block *conviput(Conv *c, Block *b, int control);
  298 static void conviconnect(Conv *c, int op, Block *b);
  299 static void convicontrol(Conv *c, int op, Block *b);
  300 static Block *convicomp(Conv *c, int op, ulong, Block *b);
  301 static void convoput(Conv *c, int type, int subtype, Block *b);
  302 static void convoconnect(Conv *c, int op, ulong dialid, ulong acceptid);
  303 static void convopenchan(Conv *c, char *path);
  304 static void convstats(Conv *c, int local, char *buf, int n);
  305 static void convreader(void *a);
  306 
  307 static void setalg(Conv *c, char *name, Algorithm *tab, Algorithm **);
  308 static void setsecret(OneWay *cc, char *secret);
  309 
  310 static void nullcipherinit(Conv*c);
  311 static void descipherinit(Conv*c);
  312 static void rc4cipherinit(Conv*c);
  313 static void nullauthinit(Conv*c);
  314 static void shaauthinit(Conv*c);
  315 static void md5authinit(Conv*c);
  316 static void nullcompinit(Conv*c);
  317 static void thwackcompinit(Conv*c);
  318 
  319 static Algorithm cipheralg[] =
  320 {
  321         "null",                 0,      nullcipherinit,
  322         "des_56_cbc",   7,      descipherinit,
  323         "rc4_128",              16,     rc4cipherinit,
  324         "rc4_256",              32,     rc4cipherinit,
  325         nil,                    0,      nil,
  326 };
  327 
  328 static Algorithm authalg[] =
  329 {
  330         "null",                 0,      nullauthinit,
  331         "hmac_sha1_96", 16,     shaauthinit,
  332         "hmac_md5_96",  16,     md5authinit,
  333         nil,                    0,      nil,
  334 };
  335 
  336 static Algorithm compalg[] =
  337 {
  338         "null",                 0,      nullcompinit,
  339         "thwack",               0,      thwackcompinit,
  340         nil,                    0,      nil,
  341 };
  342 
  343 
  344 static void
  345 sdpinit(void)
  346 {
  347         int i;
  348         Dirtab *dt;
  349         
  350         // setup dirtab with non directory entries
  351         for(i=0; i<nelem(sdpdirtab); i++) {
  352                 dt = sdpdirtab + i;
  353                 dirtab[TYPE(dt->qid)] = dt;
  354         }
  355 
  356         for(i=0; i<nelem(convdirtab); i++) {
  357                 dt = convdirtab + i;
  358                 dirtab[TYPE(dt->qid)] = dt;
  359         }
  360 
  361 }
  362 
  363 static Chan*
  364 sdpattach(char* spec)
  365 {
  366         Chan *c;
  367         int dev;
  368         char buf[100];
  369         Sdp *sdp;
  370         int start;
  371 
  372         dev = atoi(spec);
  373         if(dev<0 || dev >= Nfs)
  374                 error("bad specification");
  375 
  376         c = devattach('E', spec);
  377         c->qid = (Qid){QID(0, Qtopdir), 0, QTDIR};
  378         c->dev = dev;
  379 
  380         sdp = sdptab + dev;
  381         qlock(sdp);
  382         start = sdp->ackproc == 0;
  383         sdp->ackproc = 1;
  384         qunlock(sdp);
  385 
  386         if(start) {
  387                 snprint(buf, sizeof(buf), "sdpackproc%d", dev);
  388                 kproc(buf, sdpackproc, sdp);
  389         }
  390         
  391         return c;
  392 }
  393 
  394 static Walkqid*
  395 sdpwalk(Chan *c, Chan *nc, char **name, int nname)
  396 {
  397         return devwalk(c, nc, name, nname, 0, 0, sdpgen);
  398 }
  399 
  400 static int
  401 sdpstat(Chan* c, uchar* db, int n)
  402 {
  403         return devstat(c, db, n, nil, 0, sdpgen);
  404 }
  405 
  406 static Chan*
  407 sdpopen(Chan* ch, int omode)
  408 {
  409         int perm;
  410         Sdp *sdp;
  411         Conv *c;
  412 
  413         omode &= 3;
  414         perm = m2p[omode];
  415         USED(perm);
  416 
  417         sdp = sdptab + ch->dev;
  418 
  419         switch(TYPE(ch->qid)) {
  420         default:
  421                 break;
  422         case Qtopdir:
  423         case Qsdpdir:
  424         case Qconvdir:
  425                 if(omode != OREAD)
  426                         error(Eperm);
  427                 break;
  428         case Qlog:
  429                 logopen(sdp);
  430                 break;
  431         case Qclone:
  432                 c = sdpclone(sdp);
  433                 if(c == nil)
  434                         error(Enodev);
  435                 ch->qid.path = QID(c->id, Qctl);
  436                 break;
  437         case Qdata:
  438         case Qctl:
  439         case Qstatus:
  440         case Qcontrol:
  441         case Qstats:
  442         case Qrstats:
  443                 c = sdp->conv[CONV(ch->qid)];
  444                 qlock(c);
  445                 if(waserror()) {
  446                         qunlock(c);
  447                         nexterror();
  448                 }
  449                 if((perm & (c->perm>>6)) != perm)
  450                 if(strcmp(up->user, c->owner) != 0 || (perm & c->perm) != perm)
  451                                 error(Eperm);
  452 
  453                 c->ref++;
  454                 if(TYPE(ch->qid) == Qdata) {
  455                         c->dataopen++;
  456                         // kill reader if Qdata is opened for the first time
  457                         if(c->dataopen == 1)
  458                         if(c->readproc != nil)
  459                                 postnote(c->readproc, 1, "interrupt", 0);
  460                 } else if(TYPE(ch->qid) == Qcontrol) {  
  461                         c->controlopen++;
  462                 }
  463                 qunlock(c);
  464                 poperror();
  465                 break;
  466         }
  467         ch->mode = openmode(omode);
  468         ch->flag |= COPEN;
  469         ch->offset = 0;
  470         return ch;
  471 }
  472 
  473 static void
  474 sdpclose(Chan* ch)
  475 {
  476         Sdp *sdp  = sdptab + ch->dev;
  477         Conv *c;
  478 
  479         if(!(ch->flag & COPEN))
  480                 return;
  481         switch(TYPE(ch->qid)) {
  482         case Qlog:
  483                 logclose(sdp);
  484                 break;
  485         case Qctl:
  486         case Qstatus:
  487         case Qstats:
  488         case Qrstats:
  489                 c = sdp->conv[CONV(ch->qid)];
  490                 qlock(c);
  491                 convderef(c);
  492                 qunlock(c);
  493                 break;
  494 
  495         case Qdata:
  496                 c = sdp->conv[CONV(ch->qid)];
  497                 qlock(c);
  498                 c->dataopen--;
  499                 convderef(c);
  500                 if(c->dataopen == 0)
  501                 if(c->reader == 0)
  502                 if(c->chan != nil)
  503                 if(!waserror()) {
  504                         kproc("convreader", convreader, c);
  505                         c->reader = 1;
  506                         c->ref++;
  507                         poperror();
  508                 }
  509                 qunlock(c);
  510                 break;
  511 
  512         case Qcontrol:
  513                 c = sdp->conv[CONV(ch->qid)];
  514                 qlock(c);
  515                 c->controlopen--;
  516                 convderef(c);
  517                 if(c->controlopen == 0 && c->ref != 0) {
  518                         switch(c->state) {
  519                         default:
  520                                 convsetstate(c, CClosed);
  521                                 break;
  522                         case CAccept:
  523                         case COpen:
  524                                 convsetstate(c, CLocalClose);
  525                                 break;
  526                         }
  527                 }
  528                 qunlock(c);
  529                 break;
  530         }
  531 }
  532 
  533 static long
  534 sdpread(Chan *ch, void *a, long n, vlong off)
  535 {
  536         char buf[256];
  537         char *s;
  538         Sdp *sdp = sdptab + ch->dev;
  539         Conv *c;
  540         Block *b;
  541         int rv;
  542 
  543         USED(off);
  544         switch(TYPE(ch->qid)) {
  545         default:
  546                 error(Eperm);
  547         case Qtopdir:
  548         case Qsdpdir:
  549         case Qconvdir:
  550                 return devdirread(ch, a, n, 0, 0, sdpgen);
  551         case Qlog:
  552                 return logread(sdp, a, off, n);
  553         case Qstatus:
  554                 c = sdp->conv[CONV(ch->qid)];
  555                 qlock(c);
  556                 n = readstr(off, a, n, convstatename[c->state]);
  557                 qunlock(c);
  558                 return n;
  559         case Qctl:
  560                 sprint(buf, "%lud", CONV(ch->qid));
  561                 return readstr(off, a, n, buf);
  562         case Qcontrol:
  563                 b = readcontrol(sdp->conv[CONV(ch->qid)], n);
  564                 if(b == nil)
  565                         return 0;
  566                 if(BLEN(b) < n)
  567                         n = BLEN(b);
  568                 memmove(a, b->rp, n);
  569                 freeb(b);
  570                 return n;
  571         case Qdata:
  572                 b = readdata(sdp->conv[CONV(ch->qid)], n);
  573                 if(b == nil)
  574                         return 0;
  575                 if(BLEN(b) < n)
  576                         n = BLEN(b);
  577                 memmove(a, b->rp, n);
  578                 freeb(b);
  579                 return n;
  580         case Qstats:
  581         case Qrstats:
  582                 c = sdp->conv[CONV(ch->qid)];
  583                 s = smalloc(1000);
  584                 convstats(c, TYPE(ch->qid) == Qstats, s, 1000);
  585                 rv = readstr(off, a, n, s);
  586                 free(s);
  587                 return rv;
  588         }
  589 }
  590 
  591 static Block*
  592 sdpbread(Chan* ch, long n, ulong offset)
  593 {
  594         Sdp *sdp = sdptab + ch->dev;
  595 
  596         if(TYPE(ch->qid) != Qdata)
  597                 return devbread(ch, n, offset);
  598         return readdata(sdp->conv[CONV(ch->qid)], n);
  599 }
  600 
  601 
  602 static long
  603 sdpwrite(Chan *ch, void *a, long n, vlong off)
  604 {
  605         Sdp *sdp = sdptab + ch->dev;
  606         Cmdbuf *cb;
  607         char *arg0;
  608         char *p;
  609         Conv *c;
  610         Block *b;
  611         
  612         USED(off);
  613         switch(TYPE(ch->qid)) {
  614         default:
  615                 error(Eperm);
  616         case Qctl:
  617                 c = sdp->conv[CONV(ch->qid)];
  618                 cb = parsecmd(a, n);
  619                 qlock(c);
  620                 if(waserror()) {
  621                         qunlock(c);
  622                         free(cb);
  623                         nexterror();
  624                 }
  625                 if(cb->nf == 0)
  626                         error("short write");
  627                 arg0 = cb->f[0];
  628                 if(strcmp(arg0, "accept") == 0) {
  629                         if(cb->nf != 2)
  630                                 error("usage: accept file");
  631                         convopenchan(c, cb->f[1]);
  632                 } else if(strcmp(arg0, "dial") == 0) {
  633                         if(cb->nf != 2)
  634                                 error("usage: dial file");
  635                         convopenchan(c, cb->f[1]);
  636                         convsetstate(c, CDial);
  637                 } else if(strcmp(arg0, "drop") == 0) {
  638                         if(cb->nf != 2)
  639                                 error("usage: drop permil");
  640                         c->drop = atoi(cb->f[1]);
  641                 } else if(strcmp(arg0, "cipher") == 0) {
  642                         if(cb->nf != 2)
  643                                 error("usage: cipher alg");
  644                         setalg(c, cb->f[1], cipheralg, &c->cipher);
  645                 } else if(strcmp(arg0, "auth") == 0) {
  646                         if(cb->nf != 2)
  647                                 error("usage: auth alg");
  648                         setalg(c, cb->f[1], authalg, &c->auth);
  649                 } else if(strcmp(arg0, "comp") == 0) {
  650                         if(cb->nf != 2)
  651                                 error("usage: comp alg");
  652                         setalg(c, cb->f[1], compalg, &c->comp);
  653                 } else if(strcmp(arg0, "insecret") == 0) {
  654                         if(cb->nf != 2)
  655                                 error("usage: insecret secret");
  656                         setsecret(&c->in, cb->f[1]);
  657                         if(c->cipher)
  658                                 c->cipher->init(c);
  659                         if(c->auth)
  660                                 c->auth->init(c);
  661                 } else if(strcmp(arg0, "outsecret") == 0) {
  662                         if(cb->nf != 2)
  663                                 error("usage: outsecret secret");
  664                         setsecret(&c->out, cb->f[1]);
  665                         if(c->cipher)
  666                                 c->cipher->init(c);
  667                         if(c->auth)
  668                                 c->auth->init(c);
  669                 } else
  670                         error("unknown control request");
  671                 poperror();
  672                 qunlock(c);
  673                 free(cb);
  674                 return n;
  675         case Qlog:
  676                 cb = parsecmd(a, n);
  677                 p = logctl(sdp, cb->nf, cb->f, logflags);
  678                 free(cb);
  679                 if(p != nil)
  680                         error(p);
  681                 return n;
  682         case Qcontrol:
  683                 writecontrol(sdp->conv[CONV(ch->qid)], a, n, 0);
  684                 return n;
  685         case Qdata:
  686                 b = allocb(n);
  687                 memmove(b->wp, a, n);
  688                 b->wp += n;
  689                 return writedata(sdp->conv[CONV(ch->qid)], b);
  690         }
  691 }
  692 
  693 long
  694 sdpbwrite(Chan *ch, Block *bp, ulong offset)
  695 {
  696         Sdp *sdp = sdptab + ch->dev;
  697 
  698         if(TYPE(ch->qid) != Qdata)
  699                 return devbwrite(ch, bp, offset);
  700         return writedata(sdp->conv[CONV(ch->qid)], bp);
  701 }
  702 
  703 static int
  704 sdpgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp)
  705 {
  706         Sdp *sdp = sdptab + c->dev;
  707         int type = TYPE(c->qid);
  708         Dirtab *dt;
  709         Qid qid;
  710 
  711         if(s == DEVDOTDOT){
  712                 switch(TYPE(c->qid)){
  713                 case Qtopdir:
  714                 case Qsdpdir:
  715                         snprint(up->genbuf, sizeof(up->genbuf), "#E%ld", c->dev);
  716                         mkqid(&qid, Qtopdir, 0, QTDIR);
  717                         devdir(c, qid, up->genbuf, 0, eve, 0555, dp);
  718                         break;
  719                 case Qconvdir:
  720                         snprint(up->genbuf, sizeof(up->genbuf), "%d", s);
  721                         mkqid(&qid, Qsdpdir, 0, QTDIR);
  722                         devdir(c, qid, up->genbuf, 0, eve, 0555, dp);
  723                         break;
  724                 default:
  725                         panic("sdpwalk %llux", c->qid.path);
  726                 }
  727                 return 1;
  728         }
  729 
  730         switch(type) {
  731         default:
  732                 // non directory entries end up here
  733                 if(c->qid.type & QTDIR)
  734                         panic("sdpgen: unexpected directory");  
  735                 if(s != 0)
  736                         return -1;
  737                 dt = dirtab[TYPE(c->qid)];
  738                 if(dt == nil)
  739                         panic("sdpgen: unknown type: %lud", TYPE(c->qid));
  740                 devdir(c, c->qid, dt->name, dt->length, eve, dt->perm, dp);
  741                 return 1;
  742         case Qtopdir:
  743                 if(s != 0)
  744                         return -1;
  745                 mkqid(&qid, QID(0, Qsdpdir), 0, QTDIR);
  746                 devdir(c, qid, "sdp", 0, eve, 0555, dp);
  747                 return 1;
  748         case Qsdpdir:
  749                 if(s<nelem(sdpdirtab)) {
  750                         dt = sdpdirtab+s;
  751                         devdir(c, dt->qid, dt->name, dt->length, eve, dt->perm, dp);
  752                         return 1;
  753                 }
  754                 s -= nelem(sdpdirtab);
  755                 if(s >= sdp->nconv)
  756                         return -1;
  757                 mkqid(&qid, QID(s, Qconvdir), 0, QTDIR);
  758                 snprint(up->genbuf, sizeof(up->genbuf), "%d", s);
  759                 devdir(c, qid, up->genbuf, 0, eve, 0555, dp);
  760                 return 1;
  761         case Qconvdir:
  762                 if(s>=nelem(convdirtab))
  763                         return -1;
  764                 dt = convdirtab+s;
  765                 mkqid(&qid, QID(CONV(c->qid),TYPE(dt->qid)), 0, QTFILE);
  766                 devdir(c, qid, dt->name, dt->length, eve, dt->perm, dp);
  767                 return 1;
  768         }
  769 }
  770 
  771 static Conv*
  772 sdpclone(Sdp *sdp)
  773 {
  774         Conv *c, **pp, **ep;
  775 
  776         c = nil;
  777         ep = sdp->conv + nelem(sdp->conv);
  778         qlock(sdp);
  779         if(waserror()) {
  780                 qunlock(sdp);
  781                 nexterror();
  782         }
  783         for(pp = sdp->conv; pp < ep; pp++) {
  784                 c = *pp;
  785                 if(c == nil){
  786                         c = malloc(sizeof(Conv));
  787                         if(c == nil)
  788                                 error(Enomem);
  789                         memset(c, 0, sizeof(Conv));
  790                         qlock(c);
  791                         c->sdp = sdp;
  792                         c->id = pp - sdp->conv;
  793                         *pp = c;
  794                         sdp->nconv++;
  795                         break;
  796                 }
  797                 if(c->ref == 0 && canqlock(c)){
  798                         if(c->ref == 0)
  799                                 break;
  800                         qunlock(c);
  801                 }
  802         }
  803         poperror();
  804         qunlock(sdp);
  805 
  806         if(pp >= ep)
  807                 return nil;
  808 
  809         assert(c->state == CFree);
  810         // set ref to 2 - 1 ref for open - 1 ref for channel state
  811         c->ref = 2;
  812         c->state = CInit;
  813         c->in.window = ~0;
  814         strncpy(c->owner, up->user, sizeof(c->owner));
  815         c->perm = 0660;
  816         qunlock(c);
  817 
  818         return c;
  819 }
  820 
  821 // assume c is locked
  822 static void
  823 convretryinit(Conv *c)
  824 {
  825         c->retries = 0;
  826         // +2 to avoid rounding effects.
  827         c->timeout = TK2SEC(m->ticks) + 2;
  828 }
  829 
  830 // assume c is locked
  831 static int
  832 convretry(Conv *c, int reset)
  833 {
  834         c->retries++;
  835         if(c->retries > MaxRetries) {
  836                 if(reset)
  837                         convoconnect(c, ConReset, c->dialid, c->acceptid);
  838                 convsetstate(c, CClosed);
  839                 return 0;
  840         }
  841         c->timeout = TK2SEC(m->ticks) + (c->retries+1);
  842         return 1;
  843 }
  844 
  845 // assumes c is locked
  846 static void
  847 convtimer(Conv *c, ulong sec)
  848 {
  849         Block *b;
  850 
  851         if(c->timeout > sec)
  852                 return;
  853 
  854         switch(c->state) {
  855         case CInit:
  856                 break;
  857         case CDial:
  858                 if(convretry(c, 1))
  859                         convoconnect(c, ConOpenRequest, c->dialid, 0);
  860                 break;
  861         case CAccept:
  862                 if(convretry(c, 1))
  863                         convoconnect(c, ConOpenAck, c->dialid, c->acceptid);
  864                 break;
  865         case COpen:
  866                 b = c->out.controlpkt;
  867                 if(b != nil) {
  868                         if(convretry(c, 1))
  869                                 convoput(c, TControl, ControlMesg, copyblock(b, blocklen(b)));
  870                         break;
  871                 }
  872 
  873                 c->timeout = c->lastrecv + KeepAlive;
  874                 if(c->timeout > sec)
  875                         break;
  876                 // keepalive - randomly spaced between KeepAlive and 2*KeepAlive
  877                 if(c->timeout + KeepAlive > sec && nrand(c->lastrecv + 2*KeepAlive - sec) > 0)
  878                         break;
  879                 // can not use writecontrol
  880                 b = allocb(4);
  881                 c->out.controlseq++;
  882                 hnputl(b->wp, c->out.controlseq);
  883                 b->wp += 4;
  884                 c->out.controlpkt = b;
  885                 convretryinit(c);
  886                 if(!waserror()) {
  887                         convoput(c, TControl, ControlMesg, copyblock(b, blocklen(b)));
  888                         poperror();
  889                 }
  890                 break;
  891         case CLocalClose:
  892                 if(convretry(c, 0))
  893                         convoconnect(c, ConClose, c->dialid, c->acceptid);
  894                 break;
  895         case CRemoteClose:
  896         case CClosed:
  897                 break;
  898         }
  899 }
  900 
  901 
  902 static void
  903 sdpackproc(void *a)
  904 {
  905         Sdp *sdp = a;
  906         ulong sec;
  907         int i;
  908         Conv *c;
  909 
  910         for(;;) {
  911                 tsleep(&up->sleep, return0, 0, 1000);
  912                 sec = TK2SEC(m->ticks);
  913                 qlock(sdp);
  914                 for(i=0; i<sdp->nconv; i++) {
  915                         c = sdp->conv[i];
  916                         if(c->ref == 0)
  917                                 continue;
  918                         qunlock(sdp);
  919                         qlock(c);
  920                         if(c->ref > 0 && !waserror()) {
  921                                 convtimer(c, sec);
  922                                 poperror();
  923                         }
  924                         qunlock(c);
  925                         qlock(sdp);
  926                 }
  927                 qunlock(sdp);
  928         }
  929 }
  930 
  931 Dev sdpdevtab = {
  932         'E',
  933         "sdp",
  934 
  935         devreset,
  936         sdpinit,
  937         devshutdown,
  938         sdpattach,
  939         sdpwalk,
  940         sdpstat,
  941         sdpopen,
  942         devcreate,
  943         sdpclose,
  944         sdpread,
  945         devbread,
  946         sdpwrite,
  947         devbwrite,
  948         devremove,
  949         devwstat,
  950 };
  951 
  952 // assume hold lock on c
  953 static void
  954 convsetstate(Conv *c, int state)
  955 {
  956 
  957 if(0)print("convsetstate %d: %s -> %s\n", c->id, convstatename[c->state], convstatename[state]);
  958 
  959         switch(state) {
  960         default:
  961                 panic("setstate: bad state: %d", state);
  962         case CDial:
  963                 assert(c->state == CInit);
  964                 c->dialid = (rand()<<16) + rand();
  965                 convretryinit(c);
  966                 convoconnect(c, ConOpenRequest, c->dialid, 0);
  967                 break;
  968         case CAccept:
  969                 assert(c->state == CInit);
  970                 c->acceptid = (rand()<<16) + rand();
  971                 convretryinit(c);
  972                 convoconnect(c, ConOpenAck, c->dialid, c->acceptid);
  973                 break;
  974         case COpen:
  975                 assert(c->state == CDial || c->state == CAccept);
  976                 c->lastrecv = TK2SEC(m->ticks);
  977                 if(c->state == CDial) {
  978                         convretryinit(c);
  979                         convoconnect(c, ConOpenAckAck, c->dialid, c->acceptid);
  980                         hnputl(c->in.secret, c->acceptid);
  981                         hnputl(c->in.secret+4, c->dialid);
  982                         hnputl(c->out.secret, c->dialid);
  983                         hnputl(c->out.secret+4, c->acceptid);
  984                 } else {
  985                         hnputl(c->in.secret, c->dialid);
  986                         hnputl(c->in.secret+4, c->acceptid);
  987                         hnputl(c->out.secret, c->acceptid);
  988                         hnputl(c->out.secret+4, c->dialid);
  989                 }
  990                 setalg(c, "hmac_md5_96", authalg, &c->auth);
  991                 break;
  992         case CLocalClose:
  993                 assert(c->state == CAccept || c->state == COpen);
  994                 convretryinit(c);
  995                 convoconnect(c, ConClose, c->dialid, c->acceptid);
  996                 break;
  997         case CRemoteClose:
  998                 wakeup(&c->in.controlready);
  999                 wakeup(&c->out.controlready);
 1000                 break;
 1001         case CClosed:
 1002                 wakeup(&c->in.controlready);
 1003                 wakeup(&c->out.controlready);
 1004                 if(c->readproc)
 1005                         postnote(c->readproc, 1, "interrupt", 0);
 1006                 if(c->state != CClosed)
 1007                         convderef(c);
 1008                 break;
 1009         }
 1010         c->state = state;
 1011 }
 1012 
 1013 
 1014 //assumes c is locked
 1015 static void
 1016 convderef(Conv *c)
 1017 {
 1018         c->ref--;
 1019         if(c->ref > 0) {
 1020                 return;
 1021         }
 1022         assert(c->ref == 0);
 1023         assert(c->dataopen == 0);
 1024         assert(c->controlopen == 0);
 1025 if(0)print("convderef: %d: ref == 0!\n", c->id);
 1026         c->state = CFree;
 1027         if(c->chan) {   
 1028                 cclose(c->chan);
 1029                 c->chan = nil;
 1030         }
 1031         if(c->channame) {
 1032                 free(c->channame);
 1033                 c->channame = nil;
 1034         }
 1035         c->cipher = nil;
 1036         c->auth = nil;
 1037         c->comp = nil;
 1038         strcpy(c->owner, "network");
 1039         c->perm = 0660;
 1040         c->dialid = 0;
 1041         c->acceptid = 0;
 1042         c->timeout = 0;
 1043         c->retries = 0;
 1044         c->drop = 0;
 1045         onewaycleanup(&c->in);
 1046         onewaycleanup(&c->out);
 1047         memset(&c->lstats, 0, sizeof(Stats));
 1048         memset(&c->rstats, 0, sizeof(Stats));
 1049 }
 1050 
 1051 static void
 1052 onewaycleanup(OneWay *ow)
 1053 {
 1054         if(ow->controlpkt)
 1055                 freeb(ow->controlpkt);
 1056         if(ow->authstate)
 1057                 free(ow->authstate);
 1058         if(ow->cipherstate)
 1059                 free(ow->cipherstate);
 1060         if(ow->compstate)
 1061                 free(ow->compstate);
 1062         memset(ow, 0, sizeof(OneWay));
 1063 }
 1064 
 1065 
 1066 // assumes conv is locked
 1067 static void
 1068 convopenchan(Conv *c, char *path)
 1069 {
 1070         if(c->state != CInit || c->chan != nil)
 1071                 error("already connected");
 1072         c->chan = namec(path, Aopen, ORDWR, 0);
 1073         c->channame = smalloc(strlen(path)+1);
 1074         strcpy(c->channame, path);
 1075         if(waserror()) {
 1076                 cclose(c->chan);
 1077                 c->chan = nil;
 1078                 free(c->channame);
 1079                 c->channame = nil;
 1080                 nexterror();
 1081         }
 1082         kproc("convreader", convreader, c);
 1083 
 1084         assert(c->reader == 0 && c->ref > 0);
 1085         // after kproc in case it fails
 1086         c->reader = 1;
 1087         c->ref++;
 1088 
 1089         poperror();
 1090 }
 1091 
 1092 static void
 1093 convstats(Conv *c, int local, char *buf, int n)
 1094 {
 1095         Stats *stats;
 1096         char *p, *ep;
 1097         int i;
 1098 
 1099         if(local) {
 1100                 stats = &c->lstats;
 1101         } else {
 1102                 if(!waserror()) {
 1103                         writecontrol(c, 0, 0, 1);
 1104                         poperror();
 1105                 }
 1106                 stats = &c->rstats;
 1107         }
 1108 
 1109         qlock(c);
 1110         p = buf;
 1111         ep = buf + n;
 1112         p += snprint(p, ep-p, "outPackets: %lud\n", stats->outPackets);
 1113         p += snprint(p, ep-p, "outDataPackets: %lud\n", stats->outDataPackets);
 1114         p += snprint(p, ep-p, "outDataBytes: %lud\n", stats->outDataBytes);
 1115         p += snprint(p, ep-p, "outCompDataBytes: %lud\n", stats->outCompDataBytes);
 1116         for(i=0; i<NCompStats; i++) {
 1117                 if(stats->outCompStats[i] == 0)
 1118                         continue;
 1119                 p += snprint(p, ep-p, "outCompStats[%d]: %lud\n", i, stats->outCompStats[i]);
 1120         }
 1121         p += snprint(p, ep-p, "inPackets: %lud\n", stats->inPackets);
 1122         p += snprint(p, ep-p, "inDataPackets: %lud\n", stats->inDataPackets);
 1123         p += snprint(p, ep-p, "inDataBytes: %lud\n", stats->inDataBytes);
 1124         p += snprint(p, ep-p, "inCompDataBytes: %lud\n", stats->inCompDataBytes);
 1125         p += snprint(p, ep-p, "inMissing: %lud\n", stats->inMissing);
 1126         p += snprint(p, ep-p, "inDup: %lud\n", stats->inDup);
 1127         p += snprint(p, ep-p, "inReorder: %lud\n", stats->inReorder);
 1128         p += snprint(p, ep-p, "inBadComp: %lud\n", stats->inBadComp);
 1129         p += snprint(p, ep-p, "inBadAuth: %lud\n", stats->inBadAuth);
 1130         p += snprint(p, ep-p, "inBadSeq: %lud\n", stats->inBadSeq);
 1131         p += snprint(p, ep-p, "inBadOther: %lud\n", stats->inBadOther);
 1132         USED(p);
 1133         qunlock(c);
 1134 }
 1135 
 1136 // c is locked
 1137 static void
 1138 convack(Conv *c)
 1139 {
 1140         Block *b;
 1141         AckPkt *ack;
 1142         Stats *s;
 1143         int i;
 1144 
 1145         b = allocb(sizeof(AckPkt));
 1146         ack = (AckPkt*)b->wp;
 1147         b->wp += sizeof(AckPkt);
 1148         s = &c->lstats;
 1149         hnputl(ack->cseq, c->in.controlseq);
 1150         hnputl(ack->outPackets, s->outPackets);
 1151         hnputl(ack->outDataPackets, s->outDataPackets);
 1152         hnputl(ack->outDataBytes, s->outDataBytes);
 1153         hnputl(ack->outCompDataBytes, s->outCompDataBytes);
 1154         for(i=0; i<NCompStats; i++)
 1155                 hnputl(ack->outCompStats+i*4, s->outCompStats[i]);
 1156         hnputl(ack->inPackets, s->inPackets);
 1157         hnputl(ack->inDataPackets, s->inDataPackets);
 1158         hnputl(ack->inDataBytes, s->inDataBytes);
 1159         hnputl(ack->inCompDataBytes, s->inCompDataBytes);
 1160         hnputl(ack->inMissing, s->inMissing);
 1161         hnputl(ack->inDup, s->inDup);
 1162         hnputl(ack->inReorder, s->inReorder);
 1163         hnputl(ack->inBadComp, s->inBadComp);
 1164         hnputl(ack->inBadAuth, s->inBadAuth);
 1165         hnputl(ack->inBadSeq, s->inBadSeq);
 1166         hnputl(ack->inBadOther, s->inBadOther);
 1167         convoput(c, TControl, ControlAck, b);
 1168 }
 1169 
 1170 
 1171 // assume we hold lock for c
 1172 static Block *
 1173 conviput(Conv *c, Block *b, int control)
 1174 {
 1175         int type, subtype;
 1176         ulong seq, seqwrap;
 1177         long seqdiff;
 1178         int pad;
 1179 
 1180         c->lstats.inPackets++;
 1181 
 1182         if(BLEN(b) < 4) {
 1183                 c->lstats.inBadOther++;
 1184                 freeb(b);
 1185                 return nil;
 1186         }
 1187         
 1188         type = b->rp[0] >> 4;
 1189         subtype = b->rp[0] & 0xf;
 1190         b->rp += 1;
 1191         if(type == TConnect) {
 1192                 conviconnect(c, subtype, b);
 1193                 return nil;
 1194         }
 1195 
 1196         switch(c->state) {
 1197         case CInit:
 1198         case CDial:
 1199                 c->lstats.inBadOther++;
 1200                 convoconnect(c, ConReset, c->dialid, c->acceptid);
 1201                 convsetstate(c, CClosed);
 1202                 break;
 1203         case CAccept:
 1204         case CRemoteClose:
 1205         case CLocalClose:
 1206                 c->lstats.inBadOther++;
 1207                 freeb(b);
 1208                 return nil;
 1209         }
 1210 
 1211         seq = (b->rp[0]<<16) + (b->rp[1]<<8) + b->rp[2];
 1212         b->rp += 3;
 1213 
 1214         seqwrap = c->in.seqwrap;
 1215         seqdiff = seq - c->in.seq;
 1216         if(seqdiff < -(SeqMax*3/4)) {
 1217                 seqwrap++;
 1218                 seqdiff += SeqMax;
 1219         } else if(seqdiff > SeqMax*3/4) {
 1220                 seqwrap--;
 1221                 seqdiff -= SeqMax;
 1222         }
 1223 
 1224         if(seqdiff <= 0) {
 1225                 if(seqdiff <= -SeqWindow) {
 1226 if(0)print("old sequence number: %ld (%ld %ld)\n", seq, c->in.seqwrap, seqdiff);
 1227                         c->lstats.inBadSeq++;
 1228                         freeb(b);
 1229                         return nil;
 1230                 }
 1231 
 1232                 if(c->in.window & (1<<-seqdiff)) {
 1233 if(0)print("dup sequence number: %ld (%ld %ld)\n", seq, c->in.seqwrap, seqdiff);
 1234                         c->lstats.inDup++;
 1235                         freeb(b);
 1236                         return nil;
 1237                 }
 1238 
 1239                 c->lstats.inReorder++;
 1240         }
 1241 
 1242         // ok the sequence number looks ok
 1243 if(0) print("coniput seq=%ulx\n", seq);
 1244         if(c->in.auth != 0) {
 1245                 if(!(*c->in.auth)(&c->in, b->rp-4, BLEN(b)+4)) {
 1246 if(0)print("bad auth %ld\n", BLEN(b)+4);
 1247                         c->lstats.inBadAuth++;
 1248                         freeb(b);
 1249                         return nil;
 1250                 }
 1251                 b->wp -= c->in.authlen;
 1252         }
 1253 
 1254         if(c->in.cipher != 0) {
 1255                 if(!(*c->in.cipher)(&c->in, b->rp, BLEN(b))) {
 1256 if(0)print("bad cipher\n");
 1257                         c->lstats.inBadOther++;
 1258                         freeb(b);
 1259                         return nil;
 1260                 }
 1261                 b->rp += c->in.cipherivlen;
 1262                 if(c->in.cipherblklen > 1) {
 1263                         pad = b->wp[-1];
 1264                         if(pad > BLEN(b)) {
 1265 if(0)print("pad too big\n");
 1266                                 c->lstats.inBadOther++;
 1267                                 freeb(b);
 1268                                 return nil;
 1269                         }
 1270                         b->wp -= pad;
 1271                 }
 1272         }
 1273 
 1274         // ok the packet is good
 1275         if(seqdiff > 0) {
 1276                 while(seqdiff > 0 && c->in.window != 0) {
 1277                         if((c->in.window & (1<<(SeqWindow-1))) == 0) {
 1278                                 c->lstats.inMissing++;
 1279                         }
 1280                         c->in.window <<= 1;
 1281                         seqdiff--;
 1282                 }
 1283                 if(seqdiff > 0) {
 1284                         c->lstats.inMissing += seqdiff;
 1285                         seqdiff = 0;
 1286                 }
 1287                 c->in.seq = seq;
 1288                 c->in.seqwrap = seqwrap;
 1289         }
 1290         c->in.window |= 1<<-seqdiff;
 1291         c->lastrecv = TK2SEC(m->ticks);
 1292 
 1293         switch(type) {
 1294         case TControl:
 1295                 convicontrol(c, subtype, b);
 1296                 return nil;
 1297         case TData:
 1298                 c->lstats.inDataPackets++;
 1299                 c->lstats.inDataBytes += BLEN(b);
 1300                 if(control)
 1301                         break;
 1302                 return b;
 1303         case TCompData:
 1304                 c->lstats.inDataPackets++;
 1305                 c->lstats.inCompDataBytes += BLEN(b);
 1306                 b = convicomp(c, subtype, seq, b);
 1307                 if(b == nil) {
 1308                         c->lstats.inBadComp++;
 1309                         return nil;
 1310                 }
 1311                 c->lstats.inDataBytes += BLEN(b);
 1312                 if(control)
 1313                         break;
 1314                 return b;
 1315         }
 1316 if(0)print("dropping packet id=%d: type=%d n=%ld control=%d\n", c->id, type, BLEN(b), control);
 1317         c->lstats.inBadOther++;
 1318         freeb(b);
 1319         return nil;
 1320 }
 1321 
 1322 // assume hold conv lock
 1323 static void
 1324 conviconnect(Conv *c, int subtype, Block *b)
 1325 {
 1326         ulong dialid;
 1327         ulong acceptid;
 1328 
 1329         if(BLEN(b) != 8) {
 1330                 freeb(b);
 1331                 return;
 1332         }
 1333         dialid = nhgetl(b->rp);
 1334         acceptid = nhgetl(b->rp + 4);
 1335         freeb(b);
 1336 
 1337 if(0)print("conviconnect: %s: %d %uld %uld\n", convstatename[c->state], subtype, dialid, acceptid);
 1338 
 1339         if(subtype == ConReset) {
 1340                 convsetstate(c, CClosed);
 1341                 return;
 1342         }
 1343 
 1344         switch(c->state) {
 1345         default:
 1346                 panic("unknown state: %d", c->state);
 1347         case CInit:
 1348                 break;
 1349         case CDial:
 1350                 if(dialid != c->dialid)
 1351                         goto Reset;
 1352                 break;
 1353         case CAccept:
 1354         case COpen:
 1355         case CLocalClose:
 1356         case CRemoteClose:
 1357                 if(dialid != c->dialid
 1358                 || subtype != ConOpenRequest && acceptid != c->acceptid)
 1359                         goto Reset;
 1360                 break;
 1361         case CClosed:
 1362                 goto Reset;
 1363         }
 1364 
 1365         switch(subtype) {
 1366         case ConOpenRequest:
 1367                 switch(c->state) {
 1368                 case CInit:
 1369                         c->dialid = dialid;
 1370                         convsetstate(c, CAccept);
 1371                         return;
 1372                 case CAccept:
 1373                 case COpen:
 1374                         // duplicate ConOpenRequest that we ignore
 1375                         return;
 1376                 }
 1377                 break;
 1378         case ConOpenAck:
 1379                 switch(c->state) {
 1380                 case CDial:
 1381                         c->acceptid = acceptid;
 1382                         convsetstate(c, COpen);
 1383                         return;
 1384                 case COpen:
 1385                         // duplicate that we have to ack
 1386                         convoconnect(c, ConOpenAckAck, acceptid, dialid);
 1387                         return;
 1388                 }
 1389                 break;
 1390         case ConOpenAckAck:
 1391                 switch(c->state) {
 1392                 case CAccept:
 1393                         convsetstate(c, COpen);
 1394                         return;
 1395                 case COpen:
 1396                 case CLocalClose:
 1397                 case CRemoteClose:
 1398                         // duplicate that we ignore
 1399                         return;
 1400                 }
 1401                 break;
 1402         case ConClose:
 1403                 switch(c->state) {
 1404                 case COpen:
 1405                         convoconnect(c, ConCloseAck, dialid, acceptid);
 1406                         convsetstate(c, CRemoteClose);
 1407                         return;
 1408                 case CRemoteClose:
 1409                         // duplicate ConClose
 1410                         convoconnect(c, ConCloseAck, dialid, acceptid);
 1411                         return;
 1412                 }
 1413                 break;
 1414         case ConCloseAck:
 1415                 switch(c->state) {
 1416                 case CLocalClose:
 1417                         convsetstate(c, CClosed);
 1418                         return;
 1419                 }
 1420                 break;
 1421         }
 1422 Reset:
 1423         // invalid connection message - reset to sender
 1424 if(1)print("invalid conviconnect - sending reset\n");
 1425         convoconnect(c, ConReset, dialid, acceptid);
 1426         convsetstate(c, CClosed);
 1427 }
 1428 
 1429 static void
 1430 convicontrol(Conv *c, int subtype, Block *b)
 1431 {
 1432         ulong cseq;
 1433         AckPkt *ack;
 1434         int i;
 1435 
 1436         if(BLEN(b) < 4)
 1437                 return;
 1438         cseq = nhgetl(b->rp);
 1439         
 1440         switch(subtype){
 1441         case ControlMesg:
 1442                 if(cseq == c->in.controlseq) {
 1443 if(0)print("duplicate control packet: %ulx\n", cseq);
 1444                         // duplicate control packet
 1445                         freeb(b);
 1446                         if(c->in.controlpkt == nil)
 1447                                 convack(c);
 1448                         return;
 1449                 }
 1450 
 1451                 if(cseq != c->in.controlseq+1)
 1452                         return;
 1453                 c->in.controlseq = cseq;
 1454                 b->rp += 4;
 1455                 if(BLEN(b) == 0) {
 1456                         // just a ping
 1457                         freeb(b);
 1458                         convack(c);
 1459                 } else {
 1460                         c->in.controlpkt = b;
 1461 if(0) print("recv %ld size=%ld\n", cseq, BLEN(b));
 1462                         wakeup(&c->in.controlready);
 1463                 }
 1464                 return;
 1465         case ControlAck:
 1466                 if(cseq != c->out.controlseq)
 1467                         return;
 1468                 if(BLEN(b) < sizeof(AckPkt))
 1469                         return;
 1470                 ack = (AckPkt*)(b->rp);
 1471                 c->rstats.outPackets = nhgetl(ack->outPackets);
 1472                 c->rstats.outDataPackets = nhgetl(ack->outDataPackets);
 1473                 c->rstats.outDataBytes = nhgetl(ack->outDataBytes);
 1474                 c->rstats.outCompDataBytes = nhgetl(ack->outCompDataBytes);
 1475                 for(i=0; i<NCompStats; i++)
 1476                         c->rstats.outCompStats[i] = nhgetl(ack->outCompStats + 4*i);
 1477                 c->rstats.inPackets = nhgetl(ack->inPackets);
 1478                 c->rstats.inDataPackets = nhgetl(ack->inDataPackets);
 1479                 c->rstats.inDataBytes = nhgetl(ack->inDataBytes);
 1480                 c->rstats.inCompDataBytes = nhgetl(ack->inCompDataBytes);
 1481                 c->rstats.inMissing = nhgetl(ack->inMissing);
 1482                 c->rstats.inDup = nhgetl(ack->inDup);
 1483                 c->rstats.inReorder = nhgetl(ack->inReorder);
 1484                 c->rstats.inBadComp = nhgetl(ack->inBadComp);
 1485                 c->rstats.inBadAuth = nhgetl(ack->inBadAuth);
 1486                 c->rstats.inBadSeq = nhgetl(ack->inBadSeq);
 1487                 c->rstats.inBadOther = nhgetl(ack->inBadOther);
 1488                 freeb(b);
 1489                 freeb(c->out.controlpkt);
 1490                 c->out.controlpkt = nil;
 1491                 c->timeout = c->lastrecv + KeepAlive;
 1492                 wakeup(&c->out.controlready);
 1493                 return;
 1494         }
 1495 }
 1496 
 1497 static Block*
 1498 convicomp(Conv *c, int subtype, ulong seq, Block *b)
 1499 {
 1500         if(c->in.comp == nil) {
 1501                 freeb(b);
 1502                 return nil;
 1503         }
 1504         if(!(*c->in.comp)(c, subtype, seq, &b))
 1505                 return nil;
 1506         return b;
 1507 }
 1508 
 1509 // c is locked
 1510 static void
 1511 convwriteblock(Conv *c, Block *b)
 1512 {
 1513         // simulated errors
 1514         if(c->drop && nrand(c->drop) == 0)
 1515                 return;
 1516 
 1517         if(waserror()) {
 1518                 convsetstate(c, CClosed);
 1519                 nexterror();
 1520         }
 1521         devtab[c->chan->type]->bwrite(c->chan, b, 0);
 1522         poperror();
 1523 }
 1524 
 1525 
 1526 // assume hold conv lock
 1527 static void
 1528 convoput(Conv *c, int type, int subtype, Block *b)
 1529 {
 1530         int pad;
 1531         
 1532         c->lstats.outPackets++;
 1533         /* Make room for sdp trailer */
 1534         if(c->out.cipherblklen > 1)
 1535                 pad = c->out.cipherblklen - (BLEN(b) + c->out.cipherivlen) % c->out.cipherblklen;
 1536         else
 1537                 pad = 0;
 1538 
 1539         b = padblock(b, -(pad+c->out.authlen));
 1540 
 1541         if(pad) {
 1542                 memset(b->wp, 0, pad-1);
 1543                 b->wp[pad-1] = pad;
 1544                 b->wp += pad;
 1545         }
 1546 
 1547         /* Make space to fit sdp header */
 1548         b = padblock(b, 4 + c->out.cipherivlen);
 1549         b->rp[0] = (type << 4) | subtype;
 1550         c->out.seq++;
 1551         if(c->out.seq == (1<<24)) {
 1552                 c->out.seq = 0;
 1553                 c->out.seqwrap++;
 1554         }
 1555         b->rp[1] = c->out.seq>>16;
 1556         b->rp[2] = c->out.seq>>8;
 1557         b->rp[3] = c->out.seq;
 1558         
 1559         if(c->out.cipher)
 1560                 (*c->out.cipher)(&c->out, b->rp+4, BLEN(b)-4);
 1561 
 1562         // auth
 1563         if(c->out.auth) {
 1564                 b->wp += c->out.authlen;
 1565                 (*c->out.auth)(&c->out, b->rp, BLEN(b));
 1566         }
 1567         
 1568         convwriteblock(c, b);
 1569 }
 1570 
 1571 // assume hold conv lock
 1572 static void
 1573 convoconnect(Conv *c, int op, ulong dialid, ulong acceptid)
 1574 {
 1575         Block *b;
 1576 
 1577         c->lstats.outPackets++;
 1578         assert(c->chan != nil);
 1579         b = allocb(9);
 1580         b->wp[0] = (TConnect << 4) | op;
 1581         hnputl(b->wp+1, dialid);
 1582         hnputl(b->wp+5, acceptid);
 1583         b->wp += 9;
 1584 
 1585         if(!waserror()) {
 1586                 convwriteblock(c, b);
 1587                 poperror();
 1588         }
 1589 }
 1590 
 1591 static Block *
 1592 convreadblock(Conv *c, int n)
 1593 {
 1594         Block *b;
 1595         Chan *ch;
 1596 
 1597         qlock(&c->readlk);
 1598         if(waserror()) {
 1599                 c->readproc = nil;
 1600                 qunlock(&c->readlk);
 1601                 nexterror();
 1602         }
 1603         qlock(c);
 1604         if(c->state == CClosed) {
 1605                 qunlock(c);
 1606                 error("closed");
 1607         }
 1608         c->readproc = up;
 1609         ch = c->chan;
 1610         assert(c->ref > 0);
 1611         qunlock(c);
 1612 
 1613         b = devtab[ch->type]->bread(ch, n, 0);
 1614         c->readproc = nil;
 1615         poperror();
 1616         qunlock(&c->readlk);
 1617 
 1618         return b;
 1619 }
 1620 
 1621 static int
 1622 readready(void *a)
 1623 {
 1624         Conv *c = a;
 1625 
 1626         return c->in.controlpkt != nil || (c->state == CClosed) || (c->state == CRemoteClose);
 1627 }
 1628 
 1629 static Block *
 1630 readcontrol(Conv *c, int n)
 1631 {
 1632         Block *b;
 1633 
 1634         USED(n);
 1635 
 1636         qlock(&c->in.controllk);
 1637         if(waserror()) {
 1638                 qunlock(&c->in.controllk);
 1639                 nexterror();
 1640         }
 1641         qlock(c);       // this lock is not held during the sleep below
 1642 
 1643         for(;;) {
 1644                 if(c->chan == nil || c->state == CClosed) {
 1645                         qunlock(c);
 1646 if(0)print("readcontrol: return error - state = %s\n", convstatename[c->state]);
 1647                         error("conversation closed");
 1648                 }
 1649 
 1650                 if(c->in.controlpkt != nil)
 1651                         break;
 1652 
 1653                 if(c->state == CRemoteClose) {
 1654                         qunlock(c);
 1655 if(0)print("readcontrol: return nil - state = %s\n", convstatename[c->state]);
 1656                         poperror();
 1657                         return nil;
 1658                 }
 1659                 qunlock(c);
 1660                 sleep(&c->in.controlready, readready, c);
 1661                 qlock(c);
 1662         }
 1663 
 1664         convack(c);
 1665 
 1666         b = c->in.controlpkt;
 1667         c->in.controlpkt = nil;
 1668         qunlock(c);
 1669         poperror();
 1670         qunlock(&c->in.controllk);
 1671         return b;
 1672 }
 1673 
 1674 
 1675 static int
 1676 writeready(void *a)
 1677 {
 1678         Conv *c = a;
 1679 
 1680         return c->out.controlpkt == nil || (c->state == CClosed) || (c->state == CRemoteClose);
 1681 }
 1682 
 1683 // c is locked
 1684 static void
 1685 writewait(Conv *c)
 1686 {
 1687         for(;;) {
 1688                 if(c->state == CFree || c->state == CInit ||
 1689                    c->state == CClosed || c->state == CRemoteClose)
 1690                         error("conversation closed");
 1691 
 1692                 if(c->state == COpen && c->out.controlpkt == nil)
 1693                         break;
 1694 
 1695                 qunlock(c);
 1696                 if(waserror()) {
 1697                         qlock(c);
 1698                         nexterror();
 1699                 }
 1700                 sleep(&c->out.controlready, writeready, c);
 1701                 poperror();
 1702                 qlock(c);
 1703         }
 1704 }
 1705 
 1706 static void
 1707 writecontrol(Conv *c, void *p, int n, int wait)
 1708 {
 1709         Block *b;
 1710 
 1711         qlock(&c->out.controllk);
 1712         qlock(c);
 1713         if(waserror()) {
 1714                 qunlock(c);
 1715                 qunlock(&c->out.controllk);
 1716                 nexterror();
 1717         }
 1718         writewait(c);
 1719         b = allocb(4+n);
 1720         c->out.controlseq++;
 1721         hnputl(b->wp, c->out.controlseq);
 1722         memmove(b->wp+4, p, n);
 1723         b->wp += 4+n;
 1724         c->out.controlpkt = b;
 1725         convretryinit(c);
 1726         convoput(c, TControl, ControlMesg, copyblock(b, blocklen(b)));
 1727         if(wait)
 1728                 writewait(c);
 1729         poperror();
 1730         qunlock(c);
 1731         qunlock(&c->out.controllk);
 1732 }
 1733 
 1734 static Block *
 1735 readdata(Conv *c, int n)
 1736 {
 1737         Block *b;
 1738         int nn;
 1739 
 1740         for(;;) {
 1741 
 1742                 // some slack for tunneling overhead
 1743                 nn = n + 100;
 1744 
 1745                 // make sure size is big enough for control messages
 1746                 if(nn < 1000)
 1747                         nn = 1000;
 1748                 b = convreadblock(c, nn);
 1749                 if(b == nil)
 1750                         return nil;
 1751                 qlock(c);
 1752                 if(waserror()) {
 1753                         qunlock(c);
 1754                         return nil;
 1755                 }
 1756                 b = conviput(c, b, 0);
 1757                 poperror();
 1758                 qunlock(c);
 1759                 if(b != nil) {
 1760                         if(BLEN(b) > n)
 1761                                 b->wp = b->rp + n;
 1762                         return b;
 1763                 }
 1764         }
 1765 }
 1766 
 1767 static long
 1768 writedata(Conv *c, Block *b)
 1769 {
 1770         int n;
 1771         ulong seq;
 1772         int subtype;
 1773 
 1774         qlock(c);
 1775         if(waserror()) {
 1776                 qunlock(c);
 1777                 nexterror();
 1778         }
 1779 
 1780         if(c->state != COpen) {
 1781                 freeb(b);
 1782                 error("conversation not open");
 1783         }
 1784 
 1785         n = BLEN(b);
 1786         c->lstats.outDataPackets++;
 1787         c->lstats.outDataBytes += n;
 1788 
 1789         if(c->out.comp != nil) {
 1790                 // must generate same value as convoput
 1791                 seq = (c->out.seq + 1) & (SeqMax-1);
 1792 
 1793                 subtype = (*c->out.comp)(c, 0, seq, &b);
 1794                 c->lstats.outCompDataBytes += BLEN(b);
 1795                 convoput(c, TCompData, subtype, b);
 1796         } else
 1797                 convoput(c, TData, 0, b);
 1798 
 1799         poperror();
 1800         qunlock(c);
 1801         return n;
 1802 }
 1803 
 1804 static void
 1805 convreader(void *a)
 1806 {
 1807         Conv *c = a;
 1808         Block *b;
 1809 
 1810         qlock(c);
 1811         assert(c->reader == 1);
 1812         while(c->dataopen == 0 && c->state != CClosed) {
 1813                 qunlock(c);
 1814                 b = nil;
 1815                 if(!waserror()) {
 1816                         b = convreadblock(c, 2000);
 1817                         poperror();
 1818                 }
 1819                 qlock(c);
 1820                 if(b == nil) {
 1821                         if(strcmp(up->errstr, Eintr) != 0) {
 1822                                 convsetstate(c, CClosed);
 1823                                 break;
 1824                         }
 1825                 } else if(!waserror()) {
 1826                         conviput(c, b, 1);
 1827                         poperror();
 1828                 }
 1829         }
 1830         c->reader = 0;
 1831         convderef(c);
 1832         qunlock(c);
 1833         pexit("hangup", 1);
 1834 }
 1835 
 1836 
 1837 /* ciphers, authenticators, and compressors  */
 1838 
 1839 static void
 1840 setalg(Conv *c, char *name, Algorithm *alg, Algorithm **p)
 1841 {
 1842         for(; alg->name; alg++)
 1843                 if(strcmp(name, alg->name) == 0)
 1844                         break;
 1845         if(alg->name == nil)
 1846                 error("unknown algorithm");
 1847 
 1848         *p = alg;
 1849         alg->init(c);
 1850 }
 1851 
 1852 static void
 1853 setsecret(OneWay *ow, char *secret)
 1854 {
 1855         char *p;
 1856         int i, c;
 1857         
 1858         i = 0;
 1859         memset(ow->secret, 0, sizeof(ow->secret));
 1860         for(p=secret; *p; p++) {
 1861                 if(i >= sizeof(ow->secret)*2)
 1862                         break;
 1863                 c = *p;
 1864                 if(c >= '' && c <= '9')
 1865                         c -= '';
 1866                 else if(c >= 'a' && c <= 'f')
 1867                         c -= 'a'-10;
 1868                 else if(c >= 'A' && c <= 'F')
 1869                         c -= 'A'-10;
 1870                 else
 1871                         error("bad character in secret");
 1872                 if((i&1) == 0)
 1873                         c <<= 4;
 1874                 ow->secret[i>>1] |= c;
 1875                 i++;
 1876         }
 1877 }
 1878 
 1879 static void
 1880 setkey(uchar *key, int n, OneWay *ow, char *prefix)
 1881 {
 1882         uchar ibuf[SHA1dlen], obuf[MD5dlen], salt[10];
 1883         int i, round = 0;
 1884 
 1885         while(n > 0){
 1886                 for(i=0; i<round+1; i++)
 1887                         salt[i] = 'A'+round;
 1888                 sha1((uchar*)prefix, strlen(prefix), ibuf, sha1(salt, round+1, nil, nil));
 1889                 md5(ibuf, SHA1dlen, obuf, md5(ow->secret, sizeof(ow->secret), nil, nil));
 1890                 i = (n<MD5dlen) ? n : MD5dlen;
 1891                 memmove(key, obuf, i);
 1892                 key += i;
 1893                 n -= i;
 1894                 if(++round > sizeof salt)
 1895                         panic("setkey: you ask too much");
 1896         }
 1897 }
 1898 
 1899 static void
 1900 cipherfree(Conv *c)
 1901 {
 1902         if(c->in.cipherstate) {
 1903                 free(c->in.cipherstate);
 1904                 c->in.cipherstate = nil;
 1905         }
 1906         if(c->out.cipherstate) {
 1907                 free(c->out.cipherstate);
 1908                 c->out.cipherstate = nil;
 1909         }
 1910         c->in.cipher = nil;
 1911         c->in.cipherblklen = 0;
 1912         c->out.cipherblklen = 0;
 1913         c->in.cipherivlen = 0;
 1914         c->out.cipherivlen = 0;
 1915 }
 1916 
 1917 static void
 1918 authfree(Conv *c)
 1919 {
 1920         if(c->in.authstate) {
 1921                 free(c->in.authstate);
 1922                 c->in.authstate = nil;
 1923         }
 1924         if(c->out.authstate) {
 1925                 free(c->out.authstate);
 1926                 c->out.authstate = nil;
 1927         }
 1928         c->in.auth = nil;
 1929         c->in.authlen = 0;
 1930         c->out.authlen = 0;
 1931 }
 1932 
 1933 static void
 1934 compfree(Conv *c)
 1935 {
 1936         if(c->in.compstate) {
 1937                 free(c->in.compstate);
 1938                 c->in.compstate = nil;
 1939         }
 1940         if(c->out.compstate) {
 1941                 free(c->out.compstate);
 1942                 c->out.compstate = nil;
 1943         }
 1944         c->in.comp = nil;
 1945 }
 1946 
 1947 static void
 1948 nullcipherinit(Conv *c)
 1949 {
 1950         cipherfree(c);
 1951 }
 1952 
 1953 static int
 1954 desencrypt(OneWay *ow, uchar *p, int n)
 1955 {
 1956         uchar *pp, *ip, *eip, *ep;
 1957         DESstate *ds = ow->cipherstate;
 1958 
 1959         if(n < 8 || (n & 0x7 != 0))
 1960                 return 0;
 1961         ep = p + n;
 1962         memmove(p, ds->ivec, 8);
 1963         for(p += 8; p < ep; p += 8){
 1964                 pp = p;
 1965                 ip = ds->ivec;
 1966                 for(eip = ip+8; ip < eip; )
 1967                         *pp++ ^= *ip++;
 1968                 block_cipher(ds->expanded, p, 0);
 1969                 memmove(ds->ivec, p, 8);
 1970         }
 1971         return 1;
 1972 }
 1973 
 1974 static int
 1975 desdecrypt(OneWay *ow, uchar *p, int n)
 1976 {
 1977         uchar tmp[8];
 1978         uchar *tp, *ip, *eip, *ep;
 1979         DESstate *ds = ow->cipherstate;
 1980 
 1981         if(n < 8 || (n & 0x7 != 0))
 1982                 return 0;
 1983         ep = p + n;
 1984         memmove(ds->ivec, p, 8);
 1985         p += 8;
 1986         while(p < ep){
 1987                 memmove(tmp, p, 8);
 1988                 block_cipher(ds->expanded, p, 1);
 1989                 tp = tmp;
 1990                 ip = ds->ivec;
 1991                 for(eip = ip+8; ip < eip; ){
 1992                         *p++ ^= *ip;
 1993                         *ip++ = *tp++;
 1994                 }
 1995         }
 1996         return 1;
 1997 }
 1998 
 1999 static void
 2000 descipherinit(Conv *c)
 2001 {
 2002         uchar key[8];
 2003         uchar ivec[8];
 2004         int i;
 2005         int n = c->cipher->keylen;
 2006 
 2007         cipherfree(c);
 2008         
 2009         if(n > sizeof(key))
 2010                 n = sizeof(key);
 2011 
 2012         /* in */
 2013         memset(key, 0, sizeof(key));
 2014         setkey(key, n, &c->in, "cipher");
 2015         memset(ivec, 0, sizeof(ivec));
 2016         c->in.cipherblklen = 8;
 2017         c->in.cipherivlen = 8;
 2018         c->in.cipher = desdecrypt;
 2019         c->in.cipherstate = smalloc(sizeof(DESstate));
 2020         setupDESstate(c->in.cipherstate, key, ivec);
 2021         
 2022         /* out */
 2023         memset(key, 0, sizeof(key));
 2024         setkey(key, n, &c->out, "cipher");
 2025         for(i=0; i<8; i++)
 2026                 ivec[i] = nrand(256);
 2027         c->out.cipherblklen = 8;
 2028         c->out.cipherivlen = 8;
 2029         c->out.cipher = desencrypt;
 2030         c->out.cipherstate = smalloc(sizeof(DESstate));
 2031         setupDESstate(c->out.cipherstate, key, ivec);
 2032 }
 2033 
 2034 static int
 2035 rc4encrypt(OneWay *ow, uchar *p, int n)
 2036 {
 2037         CipherRc4 *cr = ow->cipherstate;
 2038 
 2039         if(n < 4)
 2040                 return 0;
 2041 
 2042         hnputl(p, cr->cseq);
 2043         p += 4;
 2044         n -= 4;
 2045         rc4(&cr->current, p, n);
 2046         cr->cseq += n;
 2047         return 1;
 2048 }
 2049 
 2050 static int
 2051 rc4decrypt(OneWay *ow, uchar *p, int n)
 2052 {
 2053         CipherRc4 *cr = ow->cipherstate;
 2054         RC4state tmpstate;
 2055         ulong seq;
 2056         long d, dd;
 2057 
 2058         if(n < 4)
 2059                 return 0;
 2060 
 2061         seq = nhgetl(p);
 2062         p += 4;
 2063         n -= 4;
 2064         d = seq-cr->cseq;
 2065         if(d == 0) {
 2066                 rc4(&cr->current, p, n);
 2067                 cr->cseq += n;
 2068                 if(cr->ovalid) {
 2069                         dd = cr->cseq - cr->lgseq;
 2070                         if(dd > RC4back)
 2071                                 cr->ovalid = 0;
 2072                 }
 2073         } else if(d > 0) {
 2074 //print("missing packet: %uld %ld\n", seq, d);
 2075                 // this link is hosed 
 2076                 if(d > RC4forward)
 2077                         return 0;
 2078                 cr->lgseq = seq;
 2079                 if(!cr->ovalid) {
 2080                         cr->ovalid = 1;
 2081                         cr->oseq = cr->cseq;
 2082                         memmove(&cr->old, &cr->current, sizeof(RC4state));
 2083                 }
 2084                 rc4skip(&cr->current, d);
 2085                 rc4(&cr->current, p, n);
 2086                 cr->cseq = seq+n;
 2087         } else {
 2088 //print("reordered packet: %uld %ld\n", seq, d);
 2089                 dd = seq - cr->oseq;
 2090                 if(!cr->ovalid || -d > RC4back || dd < 0)
 2091                         return 0;
 2092                 memmove(&tmpstate, &cr->old, sizeof(RC4state));
 2093                 rc4skip(&tmpstate, dd);
 2094                 rc4(&tmpstate, p, n);
 2095                 return 1;
 2096         }
 2097 
 2098         // move old state up
 2099         if(cr->ovalid) {
 2100                 dd = cr->cseq - RC4back - cr->oseq;
 2101                 if(dd > 0) {
 2102                         rc4skip(&cr->old, dd);
 2103                         cr->oseq += dd;
 2104                 }
 2105         }
 2106 
 2107         return 1;
 2108 }
 2109 
 2110 static void
 2111 rc4cipherinit(Conv *c)
 2112 {
 2113         uchar key[32];
 2114         CipherRc4 *cr;
 2115         int n;
 2116 
 2117         cipherfree(c);
 2118 
 2119         n = c->cipher->keylen;
 2120         if(n > sizeof(key))
 2121                 n = sizeof(key);
 2122 
 2123         /* in */
 2124         memset(key, 0, sizeof(key));
 2125         setkey(key, n, &c->in, "cipher");
 2126         c->in.cipherblklen = 1;
 2127         c->in.cipherivlen = 4;
 2128         c->in.cipher = rc4decrypt;
 2129         cr = smalloc(sizeof(CipherRc4));
 2130         memset(cr, 0, sizeof(*cr));
 2131         setupRC4state(&cr->current, key, n);
 2132         c->in.cipherstate = cr;
 2133 
 2134         /* out */
 2135         memset(key, 0, sizeof(key));
 2136         setkey(key, n, &c->out, "cipher");
 2137         c->out.cipherblklen = 1;
 2138         c->out.cipherivlen = 4;
 2139         c->out.cipher = rc4encrypt;
 2140         cr = smalloc(sizeof(CipherRc4));
 2141         memset(cr, 0, sizeof(*cr));
 2142         setupRC4state(&cr->current, key, n);
 2143         c->out.cipherstate = cr;
 2144 }
 2145 
 2146 static void
 2147 nullauthinit(Conv *c)
 2148 {
 2149         authfree(c);
 2150 }
 2151 
 2152 static void
 2153 shaauthinit(Conv *c)
 2154 {
 2155         authfree(c);
 2156 }
 2157 
 2158 static void
 2159 seanq_hmac_md5(uchar hash[MD5dlen], ulong wrap, uchar *t, long tlen, uchar *key, long klen)
 2160 {
 2161         uchar ipad[65], opad[65], wbuf[4];
 2162         int i;
 2163         DigestState *digest;
 2164         uchar innerhash[MD5dlen];
 2165 
 2166         for(i=0; i<64; i++){
 2167                 ipad[i] = 0x36;
 2168                 opad[i] = 0x5c;
 2169         }
 2170         ipad[64] = opad[64] = 0;
 2171         for(i=0; i<klen; i++){
 2172                 ipad[i] ^= key[i];
 2173                 opad[i] ^= key[i];
 2174         }
 2175         hnputl(wbuf, wrap);
 2176         digest = md5(ipad, 64, nil, nil);
 2177         digest = md5(wbuf, sizeof(wbuf), nil, digest);
 2178         md5(t, tlen, innerhash, digest);
 2179         digest = md5(opad, 64, nil, nil);
 2180         md5(innerhash, MD5dlen, hash, digest);
 2181 }
 2182 
 2183 static int
 2184 md5auth(OneWay *ow, uchar *t, int tlen)
 2185 {
 2186         uchar hash[MD5dlen];
 2187         int r;
 2188 
 2189         if(tlen < ow->authlen)
 2190                 return 0;
 2191         tlen -= ow->authlen;
 2192 
 2193         memset(hash, 0, MD5dlen);
 2194         seanq_hmac_md5(hash, ow->seqwrap, t, tlen, (uchar*)ow->authstate, 16);
 2195         r = memcmp(t+tlen, hash, ow->authlen) == 0;
 2196         memmove(t+tlen, hash, ow->authlen);
 2197         return r;
 2198 }
 2199 
 2200 static void
 2201 md5authinit(Conv *c)
 2202 {
 2203         int keylen;
 2204 
 2205         authfree(c);
 2206 
 2207         keylen = c->auth->keylen;
 2208         if(keylen > 16)
 2209                 keylen = 16;
 2210 
 2211         /* in */
 2212         c->in.authstate = smalloc(16);
 2213         memset(c->in.authstate, 0, 16);
 2214         setkey(c->in.authstate, keylen, &c->in, "auth");
 2215         c->in.authlen = 12;
 2216         c->in.auth = md5auth;
 2217         
 2218         /* out */
 2219         c->out.authstate = smalloc(16);
 2220         memset(c->out.authstate, 0, 16);
 2221         setkey(c->out.authstate, keylen, &c->out, "auth");
 2222         c->out.authlen = 12;
 2223         c->out.auth = md5auth;
 2224 }
 2225 
 2226 static void
 2227 nullcompinit(Conv *c)
 2228 {
 2229         compfree(c);
 2230 }
 2231 
 2232 static int
 2233 thwackcomp(Conv *c, int, ulong seq, Block **bp)
 2234 {
 2235         Block *b, *bb;
 2236         int nn;
 2237         ulong ackseq;
 2238         uchar mask;
 2239 
 2240         // add ack info
 2241         b = padblock(*bp, 4);
 2242 
 2243         ackseq = unthwackstate(c->in.compstate, &mask);
 2244         b->rp[0] = mask;
 2245         b->rp[1] = ackseq>>16;
 2246         b->rp[2] = ackseq>>8;
 2247         b->rp[3] = ackseq;
 2248 
 2249         bb = allocb(BLEN(b));
 2250         nn = thwack(c->out.compstate, bb->wp, b->rp, BLEN(b), seq, c->lstats.outCompStats);
 2251         if(nn < 0) {
 2252                 freeb(bb);
 2253                 *bp = b;
 2254                 return ThwackU;
 2255         } else {
 2256                 bb->wp += nn;
 2257                 freeb(b);
 2258                 *bp = bb;
 2259                 return ThwackC;
 2260         }
 2261 }
 2262 
 2263 static int
 2264 thwackuncomp(Conv *c, int subtype, ulong seq, Block **bp)
 2265 {
 2266         Block *b, *bb;
 2267         ulong mask;
 2268         ulong mseq;
 2269         int n;
 2270 
 2271         switch(subtype) {
 2272         default:
 2273                 return 0;
 2274         case ThwackU:
 2275                 b = *bp;
 2276                 mask = b->rp[0];
 2277                 mseq = (b->rp[1]<<16) | (b->rp[2]<<8) | b->rp[3];
 2278                 b->rp += 4;
 2279                 thwackack(c->out.compstate, mseq, mask);
 2280                 return 1;
 2281         case ThwackC:
 2282                 bb = *bp;
 2283                 b = allocb(ThwMaxBlock);
 2284                 n = unthwack(c->in.compstate, b->wp, ThwMaxBlock, bb->rp, BLEN(bb), seq);
 2285                 freeb(bb);
 2286                 if(n < 0) {
 2287 if(0)print("unthwack failed: %d\n", n);
 2288                         freeb(b);
 2289                         return 0;
 2290                 }
 2291                 b->wp += n;
 2292                 mask = b->rp[0];
 2293                 mseq = (b->rp[1]<<16) | (b->rp[2]<<8) | b->rp[3];
 2294                 thwackack(c->out.compstate, mseq, mask);
 2295                 b->rp += 4;
 2296                 *bp = b;
 2297                 return 1;
 2298         }
 2299 }
 2300 
 2301 static void
 2302 thwackcompinit(Conv *c)
 2303 {
 2304         compfree(c);
 2305 
 2306         c->in.compstate = malloc(sizeof(Unthwack));
 2307         if(c->in.compstate == nil)
 2308                 error(Enomem);
 2309         unthwackinit(c->in.compstate);
 2310         c->out.compstate = malloc(sizeof(Thwack));
 2311         if(c->out.compstate == nil)
 2312                 error(Enomem);
 2313         thwackinit(c->out.compstate);
 2314         c->in.comp = thwackuncomp;
 2315         c->out.comp = thwackcomp;
 2316 }

Cache object: 1f6ec704b44a413973cdde4b7caf1e6b


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.