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