Adds chaninfo()
[akaros.git] / kern / src / net / esp.c
1 #include        "u.h"
2 #include        "../port/lib.h"
3 #include        "mem.h"
4 #include        "dat.h"
5 #include        "fns.h"
6 #include        "../port/error.h"
7
8 #include        "ip.h"
9
10 #include        "libsec.h"
11
12 typedef struct Esphdr Esphdr;
13 typedef struct Esptail Esptail;
14 typedef struct Userhdr Userhdr;
15 typedef struct Esppriv Esppriv;
16 typedef struct Espcb Espcb;
17 typedef struct Algorithm Algorithm;
18 typedef struct Esprc4 Esprc4;
19
20 #define DPRINT if(0)print
21
22 enum
23 {
24         IP_ESPPROTO     = 50,
25         EsphdrSize      = 28,   // includes IP header
26         IphdrSize       = 20,   // options have been striped
27         EsptailSize     = 2,    // does not include pad or auth data
28         UserhdrSize     = 4,    // user visable header size - if enabled
29 };
30
31 struct Esphdr
32 {
33         /* ip header */
34         uchar   vihl;           /* Version and header length */
35         uchar   tos;            /* Type of service */
36         uchar   length[2];      /* packet length */
37         uchar   id[2];          /* Identification */
38         uchar   frag[2];        /* Fragment information */
39         uchar   Unused; 
40         uchar   espproto;       /* Protocol */
41         uchar   espplen[2];     /* Header plus data length */
42         uchar   espsrc[4];      /* Ip source */
43         uchar   espdst[4];      /* Ip destination */
44
45         /* esp header */
46         uchar   espspi[4];      /* Security parameter index */
47         uchar   espseq[4];      /* Sequence number */
48 };
49
50 struct Esptail
51 {
52         uchar   pad;
53         uchar   nexthdr;
54 };
55
56 /* header as seen by the user */
57 struct Userhdr
58 {
59         uchar   nexthdr;        // next protocol
60         uchar   unused[3];
61 };
62
63 struct Esppriv
64 {
65         ulong   in;
66         ulong   inerrors;
67 };
68
69 /*
70  *  protocol specific part of Conv
71  */
72 struct Espcb
73 {
74         int     incoming;
75         int     header;         // user user level header
76         ulong   spi;
77         ulong   seq;            // last seq sent
78         ulong   window;         // for replay attacks
79         char    *espalg;
80         void    *espstate;      // other state for esp
81         int     espivlen;       // in bytes
82         int     espblklen;
83         int     (*cipher)(Espcb*, uchar *buf, int len);
84         char    *ahalg;
85         void    *ahstate;       // other state for esp
86         int     ahlen;          // auth data length in bytes
87         int     ahblklen;
88         int     (*auth)(Espcb*, uchar *buf, int len, uchar *hash);
89 };
90
91 struct Algorithm
92 {
93         char    *name;
94         int     keylen;         // in bits
95         void    (*init)(Espcb*, char* name, uchar *key, int keylen);
96 };
97
98
99 enum {
100         RC4forward      = 10*1024*1024, // maximum skip forward
101         RC4back = 100*1024,             // maximum look back
102 };
103
104 struct Esprc4
105 {
106         ulong cseq;     // current byte sequence number
107         RC4state current;
108
109         int ovalid;     // old is valid
110         ulong lgseq; // last good sequence
111         ulong oseq;     // old byte sequence number
112         RC4state old;
113 };
114
115 static  Conv* convlookup(Proto *esp, ulong spi);
116 static  char *setalg(Espcb *ecb, char **f, int n, Algorithm *alg);
117 static  void nullespinit(Espcb*, char*, uchar *key, int keylen);
118 static  void nullahinit(Espcb*, char*, uchar *key, int keylen);
119 static  void shaahinit(Espcb*, char*, uchar *key, int keylen);
120 static  void md5ahinit(Espcb*, char*, uchar *key, int keylen);
121 static  void desespinit(Espcb *ecb, char *name, uchar *k, int n);
122 static  void rc4espinit(Espcb *ecb, char *name, uchar *k, int n);
123 static  void espkick(void *x);
124
125 static Algorithm espalg[] =
126 {
127         "null",                 0,      nullespinit,
128         "des_56_cbc",           64,     desespinit,
129         "rc4_128",              128,    rc4espinit,
130         nil,                    0,      nil,
131 };
132
133 static Algorithm ahalg[] =
134 {
135         "null",                 0,      nullahinit,
136         "hmac_sha1_96",         128,    shaahinit,
137         "hmac_md5_96",          128,    md5ahinit,
138         nil,                    0,      nil,
139 };
140
141 static char*
142 espconnect(Conv *c, char **argv, int argc)
143 {
144         char *p, *pp;
145         char *e = nil;
146         ulong spi;
147         Espcb *ecb = (Espcb*)c->ptcl;
148
149         switch(argc) {
150         default:
151                 e = "bad args to connect";
152                 break;
153         case 2:
154                 p = strchr(argv[1], '!');
155                 if(p == nil){
156                         e = "malformed address";
157                         break;
158                 }
159                 *p++ = 0;
160                 parseip(c->raddr, argv[1]);
161                 findlocalip(c->p->f, c->laddr, c->raddr);
162                 ecb->incoming = 0;
163                 ecb->seq = 0;
164                 if(strcmp(p, "*") == 0) {
165                         qlock(c->p);
166                         for(;;) {
167                                 spi = nrand(1<<16) + 256;
168                                 if(convlookup(c->p, spi) == nil)
169                                         break;
170                         }
171                         qunlock(c->p);
172                         ecb->spi = spi;
173                         ecb->incoming = 1;
174                         qhangup(c->wq, nil);
175                 } else {
176                         spi = strtoul(p, &pp, 10);
177                         if(pp == p) {
178                                 e = "malformed address";
179                                 break;
180                         }
181                         ecb->spi = spi;
182                         qhangup(c->rq, nil);
183                 }
184                 nullespinit(ecb, "null", nil, 0);
185                 nullahinit(ecb, "null", nil, 0);
186         }
187         Fsconnected(c, e);
188
189         return e;
190 }
191
192
193 static int
194 espstate(Conv *c, char *state, int n)
195 {
196         return snprint(state, n, "%s", c->inuse?"Open\n":"Closed\n");
197 }
198
199 static void
200 espcreate(Conv *c)
201 {
202         c->rq = qopen(64*1024, Qmsg, 0, 0);
203         c->wq = qopen(64*1024, Qkick, espkick, c);
204 }
205
206 static void
207 espclose(Conv *c)
208 {
209         Espcb *ecb;
210
211         qclose(c->rq);
212         qclose(c->wq);
213         qclose(c->eq);
214         ipmove(c->laddr, IPnoaddr);
215         ipmove(c->raddr, IPnoaddr);
216
217         ecb = (Espcb*)c->ptcl;
218         free(ecb->espstate);
219         free(ecb->ahstate);
220         memset(ecb, 0, sizeof(Espcb));
221 }
222
223 static void
224 espkick(void *x)
225 {
226         Conv *c = x;
227         Esphdr *eh;
228         Esptail *et;
229         Userhdr *uh;
230         Espcb *ecb;
231         Block *bp;
232         int nexthdr;
233         int payload;
234         int pad;
235         int align;
236         uchar *auth;
237
238         bp = qget(c->wq);
239         if(bp == nil)
240                 return;
241
242         qlock(c);
243         ecb = c->ptcl;
244
245         if(ecb->header) {
246                 /* make sure the message has a User header */
247                 bp = pullupblock(bp, UserhdrSize);
248                 if(bp == nil) {
249                         qunlock(c);
250                         return;
251                 }
252                 uh = (Userhdr*)bp->rp;
253                 nexthdr = uh->nexthdr;
254                 bp->rp += UserhdrSize;
255         } else {
256                 nexthdr = 0;  // what should this be?
257         }
258
259         payload = BLEN(bp) + ecb->espivlen;
260
261         /* Make space to fit ip header */
262         bp = padblock(bp, EsphdrSize + ecb->espivlen);
263
264         align = 4;
265         if(ecb->espblklen > align)
266                 align = ecb->espblklen;
267         if(align % ecb->ahblklen != 0)
268                 panic("espkick: ahblklen is important after all");
269         pad = (align-1) - (payload + EsptailSize-1)%align;
270
271         /*
272          * Make space for tail
273          * this is done by calling padblock with a negative size
274          * Padblock does not change bp->wp!
275          */
276         bp = padblock(bp, -(pad+EsptailSize+ecb->ahlen));
277         bp->wp += pad+EsptailSize+ecb->ahlen;
278
279         eh = (Esphdr *)(bp->rp);
280         et = (Esptail*)(bp->rp + EsphdrSize + payload + pad);
281
282         // fill in tail
283         et->pad = pad;
284         et->nexthdr = nexthdr;
285
286         ecb->cipher(ecb, bp->rp+EsphdrSize, payload+pad+EsptailSize);
287         auth = bp->rp + EsphdrSize + payload + pad + EsptailSize;
288
289         // fill in head
290         eh->vihl = IP_VER4;
291         hnputl(eh->espspi, ecb->spi);
292         hnputl(eh->espseq, ++ecb->seq);
293         v6tov4(eh->espsrc, c->laddr);
294         v6tov4(eh->espdst, c->raddr);
295         eh->espproto = IP_ESPPROTO;
296         eh->frag[0] = 0;
297         eh->frag[1] = 0;
298
299         ecb->auth(ecb, bp->rp+IphdrSize, (EsphdrSize-IphdrSize)+payload+pad+EsptailSize, auth);
300
301         qunlock(c);
302         //print("esp: pass down: %uld\n", BLEN(bp));
303         ipoput4(c->p->f, bp, 0, c->ttl, c->tos, c);
304 }
305
306 void
307 espiput(Proto *esp, Ipifc*, Block *bp)
308 {
309         Esphdr *eh;
310         Esptail *et;
311         Userhdr *uh;
312         Conv *c;
313         Espcb *ecb;
314         uchar raddr[IPaddrlen], laddr[IPaddrlen];
315         Fs *f;
316         uchar *auth;
317         ulong spi;
318         int payload, nexthdr;
319
320         f = esp->f;
321
322         bp = pullupblock(bp, EsphdrSize+EsptailSize);
323         if(bp == nil) {
324                 netlog(f, Logesp, "esp: short packet\n");
325                 return;
326         }
327
328         eh = (Esphdr*)(bp->rp);
329         spi = nhgetl(eh->espspi);
330         v4tov6(raddr, eh->espsrc);
331         v4tov6(laddr, eh->espdst);
332
333         qlock(esp);
334         /* Look for a conversation structure for this port */
335         c = convlookup(esp, spi);
336         if(c == nil) {
337                 qunlock(esp);
338                 netlog(f, Logesp, "esp: no conv %I -> %I!%d\n", raddr,
339                         laddr, spi);
340                 icmpnoconv(f, bp);
341                 freeblist(bp);
342                 return;
343         }
344
345         qlock(c);
346         qunlock(esp);
347
348         ecb = c->ptcl;
349         // too hard to do decryption/authentication on block lists
350         if(bp->next)
351                 bp = concatblock(bp);
352
353         if(BLEN(bp) < EsphdrSize + ecb->espivlen + EsptailSize + ecb->ahlen) {
354                 qunlock(c);
355                 netlog(f, Logesp, "esp: short block %I -> %I!%d\n", raddr,
356                         laddr, spi);
357                 freeb(bp);
358                 return;
359         }
360
361         eh = (Esphdr*)(bp->rp);
362         auth = bp->wp - ecb->ahlen;
363         if(!ecb->auth(ecb, eh->espspi, auth-eh->espspi, auth)) {
364                 qunlock(c);
365 print("esp: bad auth %I -> %I!%ld\n", raddr, laddr, spi);
366                 netlog(f, Logesp, "esp: bad auth %I -> %I!%d\n", raddr,
367                         laddr, spi);
368                 freeb(bp);
369                 return;
370         }
371
372         payload = BLEN(bp)-EsphdrSize-ecb->ahlen;
373         if(payload<=0 || payload%4 != 0 || payload%ecb->espblklen!=0) {
374                 qunlock(c);
375                 netlog(f, Logesp, "esp: bad length %I -> %I!%d payload=%d BLEN=%d\n", raddr,
376                         laddr, spi, payload, BLEN(bp));
377                 freeb(bp);
378                 return;
379         }
380         if(!ecb->cipher(ecb, bp->rp+EsphdrSize, payload)) {
381                 qunlock(c);
382 print("esp: cipher failed %I -> %I!%ld: %r\n", raddr, laddr, spi);
383                 netlog(f, Logesp, "esp: cipher failed %I -> %I!%d: %r\n", raddr,
384                         laddr, spi);
385                 freeb(bp);
386                 return;
387         }
388
389         payload -= EsptailSize;
390         et = (Esptail*)(bp->rp + EsphdrSize + payload);
391         payload -= et->pad + ecb->espivlen;
392         nexthdr = et->nexthdr;
393         if(payload <= 0) {
394                 qunlock(c);
395                 netlog(f, Logesp, "esp: short packet after decrypt %I -> %I!%d\n", raddr,
396                         laddr, spi);
397                 freeb(bp);
398                 return;
399         }
400
401         // trim packet
402         bp->rp += EsphdrSize + ecb->espivlen;
403         bp->wp = bp->rp + payload;
404         if(ecb->header) {
405                 // assume UserhdrSize < EsphdrSize
406                 bp->rp -= UserhdrSize;
407                 uh = (Userhdr*)bp->rp;
408                 memset(uh, 0, UserhdrSize);
409                 uh->nexthdr = nexthdr;
410         }
411
412         if(qfull(c->rq)){
413                 netlog(f, Logesp, "esp: qfull %I -> %I.%uld\n", raddr,
414                         laddr, spi);
415                 freeblist(bp);
416         }else {
417 //print("esp: pass up: %uld\n", BLEN(bp));
418                 qpass(c->rq, bp);
419         }
420
421         qunlock(c);
422 }
423
424 char*
425 espctl(Conv *c, char **f, int n)
426 {
427         Espcb *ecb = c->ptcl;
428         char *e = nil;
429
430         if(strcmp(f[0], "esp") == 0)
431                 e = setalg(ecb, f, n, espalg);
432         else if(strcmp(f[0], "ah") == 0)
433                 e = setalg(ecb, f, n, ahalg);
434         else if(strcmp(f[0], "header") == 0)
435                 ecb->header = 1;
436         else if(strcmp(f[0], "noheader") == 0)
437                 ecb->header = 0;
438         else
439                 e = "unknown control request";
440         return e;
441 }
442
443 void
444 espadvise(Proto *esp, Block *bp, char *msg)
445 {
446         Esphdr *h;
447         Conv *c;
448         ulong spi;
449
450         h = (Esphdr*)(bp->rp);
451
452         spi = nhgets(h->espspi);
453         qlock(esp);
454         c = convlookup(esp, spi);
455         if(c != nil) {
456                 qhangup(c->rq, msg);
457                 qhangup(c->wq, msg);
458         }
459         qunlock(esp);
460         freeblist(bp);
461 }
462
463 int
464 espstats(Proto *esp, char *buf, int len)
465 {
466         Esppriv *upriv;
467
468         upriv = esp->priv;
469         return snprint(buf, len, "%lu %lu\n",
470                 upriv->in,
471                 upriv->inerrors);
472 }
473
474 static int
475 esplocal(Conv *c, char *buf, int len)
476 {
477         Espcb *ecb = c->ptcl;
478         int n;
479
480         qlock(c);
481         if(ecb->incoming)
482                 n = snprint(buf, len, "%I!%lu\n", c->laddr, ecb->spi);
483         else
484                 n = snprint(buf, len, "%I\n", c->laddr);
485         qunlock(c);
486         return n;
487 }
488
489 static int
490 espremote(Conv *c, char *buf, int len)
491 {
492         Espcb *ecb = c->ptcl;
493         int n;
494
495         qlock(c);
496         if(ecb->incoming)
497                 n = snprint(buf, len, "%I\n", c->raddr);
498         else
499                 n = snprint(buf, len, "%I!%uld\n", c->raddr, ecb->spi);
500         qunlock(c);
501         return n;
502 }
503
504 static  Conv*
505 convlookup(Proto *esp, ulong spi)
506 {
507         Conv *c, **p;
508         Espcb *ecb;
509
510         for(p=esp->conv; *p; p++){
511                 c = *p;
512                 ecb = c->ptcl;
513                 if(ecb->incoming && ecb->spi == spi)
514                         return c;
515         }
516         return nil;
517 }
518
519 static char *
520 setalg(Espcb *ecb, char **f, int n, Algorithm *alg)
521 {
522         uchar *key;
523         int i, nbyte, nchar;
524         int c;
525
526         if(n < 2)
527                 return "bad format";
528         for(; alg->name; alg++)
529                 if(strcmp(f[1], alg->name) == 0)
530                         break;
531         if(alg->name == nil)
532                 return "unknown algorithm";
533
534         if(n != 3)
535                 return "bad format";
536         nbyte = (alg->keylen + 7) >> 3;
537         nchar = strlen(f[2]);
538         for(i=0; i<nchar; i++) {
539                 c = f[2][i];
540                 if(c >= '0' && c <= '9')
541                         f[2][i] -= '0';
542                 else if(c >= 'a' && c <= 'f')
543                         f[2][i] -= 'a'-10;
544                 else if(c >= 'A' && c <= 'F')
545                         f[2][i] -= 'A'-10;
546                 else
547                         return "bad character in key";
548         }
549         key = smalloc(nbyte);
550         for(i=0; i<nchar && i*2<nbyte; i++) {
551                 c = f[2][nchar-i-1];
552                 if(i&1)
553                         c <<= 4;
554                 key[i>>1] |= c;
555         }
556
557         alg->init(ecb, alg->name, key, alg->keylen);
558         free(key);
559         return nil;
560 }
561
562 static int
563 nullcipher(Espcb*, uchar*, int)
564 {
565         return 1;
566 }
567
568 static void
569 nullespinit(Espcb *ecb, char *name, uchar*, int)
570 {
571         ecb->espalg = name;
572         ecb->espblklen = 1;
573         ecb->espivlen = 0;
574         ecb->cipher = nullcipher;
575 }
576
577 static int
578 nullauth(Espcb*, uchar*, int, uchar*)
579 {
580         return 1;
581 }
582
583 static void
584 nullahinit(Espcb *ecb, char *name, uchar*, int)
585 {
586         ecb->ahalg = name;
587         ecb->ahblklen = 1;
588         ecb->ahlen = 0;
589         ecb->auth = nullauth;
590 }
591
592 void
593 seanq_hmac_sha1(uchar hash[SHA1dlen], uchar *t, long tlen, uchar *key, long klen)
594 {
595         uchar ipad[65], opad[65];
596         int i;
597         DigestState *digest;
598         uchar innerhash[SHA1dlen];
599
600         for(i=0; i<64; i++){
601                 ipad[i] = 0x36;
602                 opad[i] = 0x5c;
603         }
604         ipad[64] = opad[64] = 0;
605         for(i=0; i<klen; i++){
606                 ipad[i] ^= key[i];
607                 opad[i] ^= key[i];
608         }
609         digest = sha1(ipad, 64, nil, nil);
610         sha1(t, tlen, innerhash, digest);
611         digest = sha1(opad, 64, nil, nil);
612         sha1(innerhash, SHA1dlen, hash, digest);
613 }
614
615 static int
616 shaauth(Espcb *ecb, uchar *t, int tlen, uchar *auth)
617 {
618         uchar hash[SHA1dlen];
619         int r;
620
621         memset(hash, 0, SHA1dlen);
622         seanq_hmac_sha1(hash, t, tlen, (uchar*)ecb->ahstate, 16);
623         r = memcmp(auth, hash, ecb->ahlen) == 0;
624         memmove(auth, hash, ecb->ahlen);
625         return r;
626 }
627
628 static void
629 shaahinit(Espcb *ecb, char *name, uchar *key, int klen)
630 {
631         if(klen != 128)
632                 panic("shaahinit: bad keylen");
633         klen >>= 8;     // convert to bytes
634
635         ecb->ahalg = name;
636         ecb->ahblklen = 1;
637         ecb->ahlen = 12;
638         ecb->auth = shaauth;
639         ecb->ahstate = smalloc(klen);
640         memmove(ecb->ahstate, key, klen);
641 }
642
643 void
644 seanq_hmac_md5(uchar hash[MD5dlen], uchar *t, long tlen, uchar *key, long klen)
645 {
646         uchar ipad[65], opad[65];
647         int i;
648         DigestState *digest;
649         uchar innerhash[MD5dlen];
650
651         for(i=0; i<64; i++){
652                 ipad[i] = 0x36;
653                 opad[i] = 0x5c;
654         }
655         ipad[64] = opad[64] = 0;
656         for(i=0; i<klen; i++){
657                 ipad[i] ^= key[i];
658                 opad[i] ^= key[i];
659         }
660         digest = md5(ipad, 64, nil, nil);
661         md5(t, tlen, innerhash, digest);
662         digest = md5(opad, 64, nil, nil);
663         md5(innerhash, MD5dlen, hash, digest);
664 }
665
666 static int
667 md5auth(Espcb *ecb, uchar *t, int tlen, uchar *auth)
668 {
669         uchar hash[MD5dlen];
670         int r;
671
672         memset(hash, 0, MD5dlen);
673         seanq_hmac_md5(hash, t, tlen, (uchar*)ecb->ahstate, 16);
674         r = memcmp(auth, hash, ecb->ahlen) == 0;
675         memmove(auth, hash, ecb->ahlen);
676         return r;
677 }
678
679 static void
680 md5ahinit(Espcb *ecb, char *name, uchar *key, int klen)
681 {
682         if(klen != 128)
683                 panic("md5ahinit: bad keylen");
684         klen >>= 3;     // convert to bytes
685
686
687         ecb->ahalg = name;
688         ecb->ahblklen = 1;
689         ecb->ahlen = 12;
690         ecb->auth = md5auth;
691         ecb->ahstate = smalloc(klen);
692         memmove(ecb->ahstate, key, klen);
693 }
694
695 static int
696 descipher(Espcb *ecb, uchar *p, int n)
697 {
698         uchar tmp[8];
699         uchar *pp, *tp, *ip, *eip, *ep;
700         DESstate *ds = ecb->espstate;
701
702         ep = p + n;
703         if(ecb->incoming) {
704                 memmove(ds->ivec, p, 8);
705                 p += 8;
706                 while(p < ep){
707                         memmove(tmp, p, 8);
708                         block_cipher(ds->expanded, p, 1);
709                         tp = tmp;
710                         ip = ds->ivec;
711                         for(eip = ip+8; ip < eip; ){
712                                 *p++ ^= *ip;
713                                 *ip++ = *tp++;
714                         }
715                 }
716         } else {
717                 memmove(p, ds->ivec, 8);
718                 for(p += 8; p < ep; p += 8){
719                         pp = p;
720                         ip = ds->ivec;
721                         for(eip = ip+8; ip < eip; )
722                                 *pp++ ^= *ip++;
723                         block_cipher(ds->expanded, p, 0);
724                         memmove(ds->ivec, p, 8);
725                 }
726         }
727         return 1;
728 }
729         
730 static void
731 desespinit(Espcb *ecb, char *name, uchar *k, int n)
732 {
733         uchar key[8];
734         uchar ivec[8];
735         int i;
736         
737         // bits to bytes
738         n = (n+7)>>3;
739         if(n > 8)
740                 n = 8;
741         memset(key, 0, sizeof(key));
742         memmove(key, k, n);
743         for(i=0; i<8; i++)
744                 ivec[i] = nrand(256);
745         ecb->espalg = name;
746         ecb->espblklen = 8;
747         ecb->espivlen = 8;
748         ecb->cipher = descipher;
749         ecb->espstate = smalloc(sizeof(DESstate));
750         setupDESstate(ecb->espstate, key, ivec);
751 }
752
753 static int
754 rc4cipher(Espcb *ecb, uchar *p, int n)
755 {
756         Esprc4 *esprc4;
757         RC4state tmpstate;
758         ulong seq;
759         long d, dd;
760
761         if(n < 4)
762                 return 0;
763
764         esprc4 = ecb->espstate;
765         if(ecb->incoming) {
766                 seq = nhgetl(p);
767                 p += 4;
768                 n -= 4;
769                 d = seq-esprc4->cseq;
770                 if(d == 0) {
771                         rc4(&esprc4->current, p, n);
772                         esprc4->cseq += n;
773                         if(esprc4->ovalid) {
774                                 dd = esprc4->cseq - esprc4->lgseq;
775                                 if(dd > RC4back)
776                                         esprc4->ovalid = 0;
777                         }
778                 } else if(d > 0) {
779 print("missing packet: %uld %ld\n", seq, d);
780                         // this link is hosed
781                         if(d > RC4forward) {
782                                 strcpy(up->errstr, "rc4cipher: skipped too much");
783                                 return 0;
784                         }
785                         esprc4->lgseq = seq;
786                         if(!esprc4->ovalid) {
787                                 esprc4->ovalid = 1;
788                                 esprc4->oseq = esprc4->cseq;
789                                 memmove(&esprc4->old, &esprc4->current, sizeof(RC4state));
790                         }
791                         rc4skip(&esprc4->current, d);
792                         rc4(&esprc4->current, p, n);
793                         esprc4->cseq = seq+n;
794                 } else {
795 print("reordered packet: %uld %ld\n", seq, d);
796                         dd = seq - esprc4->oseq;
797                         if(!esprc4->ovalid || -d > RC4back || dd < 0) {
798                                 strcpy(up->errstr, "rc4cipher: too far back");
799                                 return 0;
800                         }
801                         memmove(&tmpstate, &esprc4->old, sizeof(RC4state));
802                         rc4skip(&tmpstate, dd);
803                         rc4(&tmpstate, p, n);
804                         return 1;
805                 }
806
807                 // move old state up
808                 if(esprc4->ovalid) {
809                         dd = esprc4->cseq - RC4back - esprc4->oseq;
810                         if(dd > 0) {
811                                 rc4skip(&esprc4->old, dd);
812                                 esprc4->oseq += dd;
813                         }
814                 }
815         } else {
816                 hnputl(p, esprc4->cseq);
817                 p += 4;
818                 n -= 4;
819                 rc4(&esprc4->current, p, n);
820                 esprc4->cseq += n;
821         }
822         return 1;
823 }
824
825 static void
826 rc4espinit(Espcb *ecb, char *name, uchar *k, int n)
827 {       
828         Esprc4 *esprc4;
829
830         // bits to bytes
831         n = (n+7)>>3;
832         esprc4 = smalloc(sizeof(Esprc4));
833         memset(esprc4, 0, sizeof(Esprc4));
834         setupRC4state(&esprc4->current, k, n);
835         ecb->espalg = name;
836         ecb->espblklen = 4;
837         ecb->espivlen = 4;
838         ecb->cipher = rc4cipher;
839         ecb->espstate = esprc4;
840 }
841         
842 void
843 espinit(Fs *fs)
844 {
845         Proto *esp;
846
847         esp = smalloc(sizeof(Proto));
848         esp->priv = smalloc(sizeof(Esppriv));
849         esp->name = "esp";
850         esp->connect = espconnect;
851         esp->announce = nil;
852         esp->ctl = espctl;
853         esp->state = espstate;
854         esp->create = espcreate;
855         esp->close = espclose;
856         esp->rcv = espiput;
857         esp->advise = espadvise;
858         esp->stats = espstats;
859         esp->local = esplocal;
860         esp->remote = espremote;
861         esp->ipproto = IP_ESPPROTO;
862         esp->nc = Nchans;
863         esp->ptclsize = sizeof(Espcb);
864
865         Fsproto(fs, esp);
866 }