1 /* $OpenBSD: ip_ipcomp.c,v 1.15 2003/08/14 19:00:12 jason Exp $ */
2
3 /*
4 * Copyright (c) 2001 Jean-Jacques Bernard-Gundol (jj@wabbitt.org)
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 /* IP payload compression protocol (IPComp), see RFC 2393 */
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/mbuf.h>
35 #include <sys/socket.h>
36
37 #include <net/if.h>
38 #include <net/bpf.h>
39
40 #include <dev/rndvar.h>
41
42 #ifdef INET
43 #include <netinet/in.h>
44 #include <netinet/in_systm.h>
45 #include <netinet/ip.h>
46 #endif /* INET */
47
48 #ifdef INET6
49 #ifndef INET
50 #include <netinet/in.h>
51 #endif
52 #include <netinet/ip6.h>
53 #endif /* INET6 */
54
55 #include <netinet/ip_ipsp.h>
56 #include <netinet/ip_ipcomp.h>
57 #include <net/pfkeyv2.h>
58 #include <net/if_enc.h>
59
60 #include <crypto/cryptodev.h>
61 #include <crypto/deflate.h>
62 #include <crypto/xform.h>
63
64 #include "bpfilter.h"
65
66 #ifdef ENCDEBUG
67 #define DPRINTF(x) if (encdebug) printf x
68 #else
69 #define DPRINTF(x)
70 #endif
71
72 struct ipcompstat ipcompstat;
73
74 /*
75 * ipcomp_attach() is called from the transformation code
76 */
77 int
ipcomp_attach(void)78 ipcomp_attach(void)
79 {
80 return 0;
81 }
82
83 /*
84 * ipcomp_init() is called when an CPI is being set up.
85 */
86 int
ipcomp_init(tdbp,xsp,ii)87 ipcomp_init(tdbp, xsp, ii)
88 struct tdb *tdbp;
89 struct xformsw *xsp;
90 struct ipsecinit *ii;
91 {
92 struct comp_algo *tcomp = NULL;
93 struct cryptoini cric;
94
95 switch (ii->ii_compalg) {
96 case SADB_X_CALG_DEFLATE:
97 tcomp = &comp_algo_deflate;
98 break;
99 case SADB_X_CALG_LZS:
100 tcomp = &comp_algo_lzs;
101 break;
102
103 default:
104 DPRINTF(("ipcomp_init(): unsupported compression algorithm %d specified\n",
105 ii->ii_compalg));
106 return EINVAL;
107 }
108
109 tdbp->tdb_compalgxform = tcomp;
110
111 DPRINTF(("ipcomp_init(): initialized TDB with ipcomp algorithm %s\n",
112 tcomp->name));
113
114 tdbp->tdb_xform = xsp;
115 tdbp->tdb_bitmap = 0;
116
117 /* Initialize crypto session */
118 bzero(&cric, sizeof(cric));
119 cric.cri_alg = tdbp->tdb_compalgxform->type;
120
121 return crypto_newsession(&tdbp->tdb_cryptoid, &cric, 0);
122 }
123
124 /*
125 * ipcomp_zeroize() used when IPCA is deleted
126 */
127 int
ipcomp_zeroize(tdbp)128 ipcomp_zeroize(tdbp)
129 struct tdb *tdbp;
130 {
131 int err;
132
133 err = crypto_freesession(tdbp->tdb_cryptoid);
134 tdbp->tdb_cryptoid = 0;
135 return err;
136 }
137
138 /*
139 * ipcomp_input() gets called to uncompress an input packet
140 */
141 int
ipcomp_input(m,tdb,skip,protoff)142 ipcomp_input(m, tdb, skip, protoff)
143 struct mbuf *m;
144 struct tdb *tdb;
145 int skip;
146 int protoff;
147 {
148 struct comp_algo *ipcompx = (struct comp_algo *) tdb->tdb_compalgxform;
149 struct tdb_crypto *tc;
150 int hlen;
151
152 struct cryptodesc *crdc = NULL;
153 struct cryptop *crp;
154
155 hlen = IPCOMP_HLENGTH;
156
157 /* Get crypto descriptors */
158 crp = crypto_getreq(1);
159 if (crp == NULL) {
160 m_freem(m);
161 DPRINTF(("ipcomp_input(): failed to acquire crypto descriptors\n"));
162 ipcompstat.ipcomps_crypto++;
163 return ENOBUFS;
164 }
165 /* Get IPsec-specific opaque pointer */
166 MALLOC(tc, struct tdb_crypto *, sizeof(struct tdb_crypto),
167 M_XDATA, M_NOWAIT);
168 if (tc == NULL) {
169 m_freem(m);
170 crypto_freereq(crp);
171 DPRINTF(("ipcomp_input(): failed to allocate tdb_crypto\n"));
172 ipcompstat.ipcomps_crypto++;
173 return ENOBUFS;
174 }
175 bzero(tc, sizeof(struct tdb_crypto));
176 crdc = crp->crp_desc;
177
178 crdc->crd_skip = skip + hlen;
179 crdc->crd_len = m->m_pkthdr.len - (skip + hlen);
180 crdc->crd_inject = skip;
181
182 tc->tc_ptr = 0;
183
184 /* Decompression operation */
185 crdc->crd_alg = ipcompx->type;
186
187 /* Crypto operation descriptor */
188 crp->crp_ilen = m->m_pkthdr.len - (skip + hlen);
189 crp->crp_flags = CRYPTO_F_IMBUF;
190 crp->crp_buf = (caddr_t) m;
191 crp->crp_callback = (int (*) (struct cryptop *)) ipcomp_input_cb;
192 crp->crp_sid = tdb->tdb_cryptoid;
193 crp->crp_opaque = (caddr_t) tc;
194
195 /* These are passed as-is to the callback */
196 tc->tc_skip = skip;
197 tc->tc_protoff = protoff;
198 tc->tc_spi = tdb->tdb_spi;
199 tc->tc_proto = IPPROTO_IPCOMP;
200 bcopy(&tdb->tdb_dst, &tc->tc_dst, sizeof(union sockaddr_union));
201
202 return crypto_dispatch(crp);
203 }
204
205 /*
206 * IPComp input callback, called directly by the crypto driver
207 */
208 int
ipcomp_input_cb(op)209 ipcomp_input_cb(op)
210 void *op;
211 {
212 int error = 0, s, skip, protoff, roff, hlen = IPCOMP_HLENGTH, clen;
213 u_int8_t nproto;
214 struct mbuf *m, *m1, *mo;
215 struct cryptodesc *crd;
216 struct comp_algo *ipcompx;
217 struct tdb_crypto *tc;
218 struct cryptop *crp;
219 struct tdb *tdb;
220 struct ipcomp *ipcomp;
221 caddr_t addr;
222
223 crp = (struct cryptop *) op;
224 crd = crp->crp_desc;
225
226 tc = (struct tdb_crypto *) crp->crp_opaque;
227 skip = tc->tc_skip;
228 protoff = tc->tc_protoff;
229
230 m = (struct mbuf *) crp->crp_buf;
231 if (m == NULL) {
232 /* Shouldn't happen... */
233 FREE(tc, M_XDATA);
234 crypto_freereq(crp);
235 ipcompstat.ipcomps_crypto++;
236 DPRINTF(("ipcomp_input_cb(): bogus returned buffer from crypto\n"));
237 return (EINVAL);
238 }
239
240 s = spltdb();
241
242 tdb = gettdb(tc->tc_spi, &tc->tc_dst, tc->tc_proto);
243 if (tdb == NULL) {
244 FREE(tc, M_XDATA);
245 ipcompstat.ipcomps_notdb++;
246 DPRINTF(("ipcomp_input_cb(): TDB expired while in crypto"));
247 error = EPERM;
248 goto baddone;
249 }
250 ipcompx = (struct comp_algo *) tdb->tdb_compalgxform;
251
252 /* update the counters */
253 tdb->tdb_cur_bytes += m->m_pkthdr.len - (skip + hlen);
254 ipcompstat.ipcomps_ibytes += m->m_pkthdr.len - (skip + hlen);
255
256 /* Hard expiration */
257 if ((tdb->tdb_flags & TDBF_BYTES) &&
258 (tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes)) {
259 FREE(tc, M_XDATA);
260 pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD);
261 tdb_delete(tdb);
262 error = ENXIO;
263 goto baddone;
264 }
265 /* Notify on soft expiration */
266 if ((tdb->tdb_flags & TDBF_SOFT_BYTES) &&
267 (tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes)) {
268 pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT);
269 tdb->tdb_flags &= ~TDBF_SOFT_BYTES; /* Turn off checking */
270 }
271
272 /* Check for crypto errors */
273 if (crp->crp_etype) {
274 if (crp->crp_etype == EAGAIN) {
275 /* Reset the session ID */
276 if (tdb->tdb_cryptoid != 0)
277 tdb->tdb_cryptoid = crp->crp_sid;
278 splx(s);
279 return crypto_dispatch(crp);
280 }
281 FREE(tc, M_XDATA);
282 ipcompstat.ipcomps_noxform++;
283 DPRINTF(("ipcomp_input_cb(): crypto error %d\n",
284 crp->crp_etype));
285 error = crp->crp_etype;
286 goto baddone;
287 }
288 FREE(tc, M_XDATA);
289
290 /* Length of data after processing */
291 clen = crp->crp_olen;
292
293 /* In case it's not done already, adjust the size of the mbuf chain */
294 m->m_pkthdr.len = clen + hlen + skip;
295
296 if ((m->m_len < skip + hlen) && (m = m_pullup(m, skip + hlen)) == 0) {
297 error = ENOBUFS;
298 goto baddone;
299 }
300
301 /* Find the beginning of the IPCOMP header */
302 m1 = m_getptr(m, skip, &roff);
303 if (m1 == NULL) {
304 ipcompstat.ipcomps_hdrops++;
305 DPRINTF(("ipcomp_input_cb(): bad mbuf chain, IPCA %s/%08x\n",
306 ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
307 error = EINVAL;
308 goto baddone;
309 }
310 /* Keep the next protocol field */
311 addr = (caddr_t) mtod(m, struct ip *) + skip;
312 ipcomp = (struct ipcomp *) addr;
313 nproto = ipcomp->ipcomp_nh;
314
315 /* Remove the IPCOMP header from the mbuf */
316 if (roff == 0) {
317 /* The IPCOMP header is at the beginning of m1 */
318 m_adj(m1, hlen);
319 if (!(m1->m_flags & M_PKTHDR))
320 m->m_pkthdr.len -= hlen;
321 } else if (roff + hlen >= m1->m_len) {
322 if (roff + hlen > m1->m_len) {
323 /* Adjust the next mbuf by the remainder */
324 m_adj(m1->m_next, roff + hlen - m1->m_len);
325
326 /*
327 * The second mbuf is guaranteed not to have a
328 * pkthdr...
329 */
330 m->m_pkthdr.len -= (roff + hlen - m1->m_len);
331 }
332 /* Now, let's unlink the mbuf chain for a second... */
333 mo = m1->m_next;
334 m1->m_next = NULL;
335
336 /* ...and trim the end of the first part of the chain...sick */
337 m_adj(m1, -(m1->m_len - roff));
338 if (!(m1->m_flags & M_PKTHDR))
339 m->m_pkthdr.len -= (m1->m_len - roff);
340
341 /* Finally, let's relink */
342 m1->m_next = mo;
343 } else {
344 bcopy(mtod(m1, u_char *) + roff + hlen,
345 mtod(m1, u_char *) + roff,
346 m1->m_len - (roff + hlen));
347 m1->m_len -= hlen;
348 m->m_pkthdr.len -= hlen;
349 }
350
351 /* Release the crypto descriptors */
352 crypto_freereq(crp);
353
354 /* Restore the Next Protocol field */
355 m_copyback(m, protoff, sizeof(u_int8_t), &nproto);
356
357 /* Back to generic IPsec input processing */
358 error = ipsec_common_input_cb(m, tdb, skip, protoff, NULL);
359 splx(s);
360 return error;
361
362 baddone:
363 splx(s);
364
365 if (m)
366 m_freem(m);
367
368 crypto_freereq(crp);
369
370 return error;
371 }
372
373 /*
374 * IPComp output routine, called by ipsp_process_packet()
375 */
376 int
ipcomp_output(m,tdb,mp,skip,protoff)377 ipcomp_output(m, tdb, mp, skip, protoff)
378 struct mbuf *m;
379 struct tdb *tdb;
380 struct mbuf **mp;
381 int skip;
382 int protoff;
383 {
384 struct comp_algo *ipcompx = (struct comp_algo *) tdb->tdb_compalgxform;
385 int hlen;
386 u_int8_t prot;
387 u_int16_t cpi;
388 struct cryptodesc *crdc = NULL;
389 struct cryptop *crp;
390 struct tdb_crypto *tc;
391 struct mbuf *mi, *mo;
392 struct ipcomp *ipcomp;
393 #ifdef INET
394 struct ip *ip;
395 #endif
396 #ifdef INET6
397 struct ip6_hdr *ip6;
398 #endif
399
400 #if NBPFILTER > 0
401 {
402 struct ifnet *ifn;
403 struct enchdr hdr;
404 struct mbuf m1;
405
406 bzero(&hdr, sizeof(hdr));
407
408 hdr.af = tdb->tdb_dst.sa.sa_family;
409 hdr.spi = tdb->tdb_spi;
410 hdr.flags |= M_COMP;
411
412 m1.m_next = m;
413 m1.m_len = ENC_HDRLEN;
414 m1.m_data = (char *) &hdr;
415
416 ifn = &(encif[0].sc_if);
417
418 if (ifn->if_bpf)
419 bpf_mtap(ifn->if_bpf, &m1);
420 }
421 #endif
422
423 hlen = IPCOMP_HLENGTH;
424
425 ipcompstat.ipcomps_output++;
426
427 switch (tdb->tdb_dst.sa.sa_family) {
428 #ifdef INET
429 case AF_INET:
430 /* Check for IPv4 maximum packet size violations */
431 /*
432 * Since compression is going to reduce the size, no need to
433 * worry
434 */
435 if (m->m_pkthdr.len + hlen > IP_MAXPACKET) {
436 DPRINTF(("ipcomp_output(): packet in IPCA %s/%08x got too big\n",
437 ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
438 m_freem(m);
439 ipcompstat.ipcomps_toobig++;
440 return EMSGSIZE;
441 }
442 break;
443 #endif /* INET */
444
445 #ifdef INET6
446 case AF_INET6:
447 /* Check for IPv6 maximum packet size violations */
448 if (m->m_pkthdr.len + hlen > IPV6_MAXPACKET) {
449 DPRINTF(("ipcomp_output(): packet in IPCA %s/%08x got too big\n",
450 ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
451 m_freem(m);
452 ipcompstat.ipcomps_toobig++;
453 return EMSGSIZE;
454 }
455 #endif /* INET6 */
456
457 default:
458 DPRINTF(("ipcomp_output(): unknown/unsupported protocol family %d, IPCA %s/%08x\n",
459 tdb->tdb_dst.sa.sa_family, ipsp_address(tdb->tdb_dst),
460 ntohl(tdb->tdb_spi)));
461 m_freem(m);
462 ipcompstat.ipcomps_nopf++;
463 return EPFNOSUPPORT;
464 }
465
466 /* Update the counters */
467
468 tdb->tdb_cur_bytes += m->m_pkthdr.len - skip;
469 ipcompstat.ipcomps_obytes += m->m_pkthdr.len - skip;
470
471 /* Hard byte expiration */
472 if ((tdb->tdb_flags & TDBF_BYTES) &&
473 (tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes)) {
474 pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD);
475 tdb_delete(tdb);
476 m_freem(m);
477 return EINVAL;
478 }
479 /* Soft byte expiration */
480 if ((tdb->tdb_flags & TDBF_SOFT_BYTES) &&
481 (tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes)) {
482 pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT);
483 tdb->tdb_flags &= ~TDBF_SOFT_BYTES; /* Turn off checking */
484 }
485 /*
486 * Loop through mbuf chain; if we find an M_EXT mbuf with
487 * more than one reference, replace the rest of the chain.
488 */
489 mo = NULL;
490 mi = m;
491 while (mi != NULL &&
492 (!(mi->m_flags & M_EXT) || !MCLISREFERENCED(mi))) {
493 mo = mi;
494 mi = mi->m_next;
495 }
496
497 if (mi != NULL) {
498 /* Replace the rest of the mbuf chain. */
499 struct mbuf *n = m_copym2(mi, 0, M_COPYALL, M_DONTWAIT);
500
501 if (n == NULL) {
502 DPRINTF(("ipcomp_output(): bad mbuf chain, IPCA %s/%08x\n",
503 ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
504 ipcompstat.ipcomps_hdrops++;
505 m_freem(m);
506 return ENOBUFS;
507 }
508 if (mo != NULL)
509 mo->m_next = n;
510 else
511 m = n;
512
513 m_freem(mi);
514 }
515 /* Inject IPCOMP header */
516 mo = m_inject(m, skip, hlen, M_DONTWAIT);
517 if (mo == NULL) {
518 DPRINTF(("ipcomp_output(): failed to inject IPCOMP header for IPCA %s/%08x\n",
519 ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
520 m_freem(m);
521 ipcompstat.ipcomps_wrap++;
522 return ENOBUFS;
523 }
524 ipcomp = mtod(mo, struct ipcomp *);
525
526 /* Initialize the IPCOMP header */
527
528 bzero(ipcomp, sizeof(struct ipcomp));
529
530 cpi = (u_int16_t) ntohl(tdb->tdb_spi);
531 ipcomp->ipcomp_cpi = htons(cpi);
532
533 /* m_pullup before ? */
534
535 switch (tdb->tdb_dst.sa.sa_family) {
536 #ifdef INET
537 case AF_INET:
538 ip = mtod(m, struct ip *);
539 ipcomp->ipcomp_nh = ip->ip_p;
540 break;
541 #endif /* INET */
542
543 #ifdef INET6
544 case AF_INET6:
545 ip6 = mtod(m, struct ip6_hdr *);
546 ipcomp->ipcomp_nh = ip6->ip6_nxt;
547 break;
548 #endif
549
550 default:
551 DPRINTF(("ipcomp_output(): unknown/unsupported protocol family %d, IPCA %s/%08x\n",
552 tdb->tdb_dst.sa.sa_family, ipsp_address(tdb->tdb_dst),
553 ntohl(tdb->tdb_spi)));
554 m_freem(m);
555 ipcompstat.ipcomps_nopf++;
556 return EPFNOSUPPORT;
557 break;
558 }
559
560 /* Fix Next Protocol in IPv4/IPv6 header */
561 prot = IPPROTO_IPCOMP;
562 m_copyback(m, protoff, sizeof(u_int8_t), &prot);
563
564 /* Ok now, we can pass to the crypto processing */
565
566 /* Get crypto descriptors */
567 crp = crypto_getreq(1);
568 if (crp == NULL) {
569 m_freem(m);
570 DPRINTF(("ipcomp_output(): failed to acquire crypto descriptors\n"));
571 ipcompstat.ipcomps_crypto++;
572 return ENOBUFS;
573 }
574 crdc = crp->crp_desc;
575
576 /* Compression descriptor */
577 crdc->crd_skip = skip + hlen;
578 crdc->crd_len = m->m_pkthdr.len - (skip + hlen);
579 crdc->crd_flags = CRD_F_COMP;
580 crdc->crd_inject = skip + hlen;
581
582 /* Compression operation */
583 crdc->crd_alg = ipcompx->type;
584
585 /* IPsec-specific opaque crypto info */
586 MALLOC(tc, struct tdb_crypto *, sizeof(struct tdb_crypto),
587 M_XDATA, M_NOWAIT);
588 if (tc == NULL) {
589 m_freem(m);
590 crypto_freereq(crp);
591 DPRINTF(("ipcomp_output(): failed to allocate tdb_crypto\n"));
592 ipcompstat.ipcomps_crypto++;
593 return ENOBUFS;
594 }
595 bzero(tc, sizeof(struct tdb_crypto));
596
597 tc->tc_spi = tdb->tdb_spi;
598 tc->tc_proto = tdb->tdb_sproto;
599 tc->tc_skip = skip + hlen;
600 bcopy(&tdb->tdb_dst, &tc->tc_dst, sizeof(union sockaddr_union));
601
602 /* Crypto operation descriptor */
603 crp->crp_ilen = m->m_pkthdr.len; /* Total input length */
604 crp->crp_flags = CRYPTO_F_IMBUF;
605 crp->crp_buf = (caddr_t) m;
606 crp->crp_callback = (int (*) (struct cryptop *)) ipcomp_output_cb;
607 crp->crp_opaque = (caddr_t) tc;
608 crp->crp_sid = tdb->tdb_cryptoid;
609
610 return crypto_dispatch(crp);
611 }
612
613 /*
614 * IPComp output callback, called directly from the crypto driver
615 */
616 int
ipcomp_output_cb(cp)617 ipcomp_output_cb(cp)
618 void *cp;
619 {
620 struct cryptop *crp = (struct cryptop *) cp;
621 struct tdb_crypto *tc;
622 struct tdb *tdb;
623 struct mbuf *m;
624 int error = 0, s, skip, rlen;
625 #ifdef INET
626 struct ip *ip;
627 #endif
628 #ifdef INET6
629 struct ip6_hdr *ip6;
630 #endif
631
632 tc = (struct tdb_crypto *) crp->crp_opaque;
633 skip = tc->tc_skip;
634 rlen = crp->crp_ilen - skip;
635
636 m = (struct mbuf *) crp->crp_buf;
637 if (m == NULL) {
638 /* Shouldn't happen... */
639 FREE(tc, M_XDATA);
640 crypto_freereq(crp);
641 ipcompstat.ipcomps_crypto++;
642 DPRINTF(("ipcomp_output_cb(): bogus returned buffer from "
643 "crypto\n"));
644 return (EINVAL);
645 }
646
647 s = spltdb();
648
649 tdb = gettdb(tc->tc_spi, &tc->tc_dst, tc->tc_proto);
650 if (tdb == NULL) {
651 FREE(tc, M_XDATA);
652 ipcompstat.ipcomps_notdb++;
653 DPRINTF(("ipcomp_output_cb(): TDB expired while in crypto\n"));
654 error = EPERM;
655 goto baddone;
656 }
657
658 /* Check for crypto errors. */
659 if (crp->crp_etype) {
660 if (crp->crp_etype == EAGAIN) {
661 /* Reset the session ID */
662 if (tdb->tdb_cryptoid != 0)
663 tdb->tdb_cryptoid = crp->crp_sid;
664 splx(s);
665 return crypto_dispatch(crp);
666 }
667 FREE(tc, M_XDATA);
668 ipcompstat.ipcomps_noxform++;
669 DPRINTF(("ipcomp_output_cb(): crypto error %d\n",
670 crp->crp_etype));
671 error = crp->crp_etype;
672 goto baddone;
673 }
674 FREE(tc, M_XDATA);
675
676 /* Check sizes. */
677 if (rlen < crp->crp_olen) {
678 /* Compression was useless, we have lost time. */
679 crypto_freereq(crp);
680 error = ipsp_process_done(m, tdb);
681 splx(s);
682 return error;
683 }
684
685 /* Adjust the length in the IP header. */
686 switch (tdb->tdb_dst.sa.sa_family) {
687 #ifdef INET
688 case AF_INET:
689 ip = mtod(m, struct ip *);
690 ip->ip_len = htons(m->m_pkthdr.len);
691 break;
692 #endif /* INET */
693
694 #ifdef INET6
695 case AF_INET6:
696 ip6 = mtod(m, struct ip6_hdr *);
697 ip6->ip6_plen = htons(m->m_pkthdr.len) - sizeof(struct ip6_hdr);
698 break;
699 #endif /* INET6 */
700
701 default:
702 m_freem(m);
703 DPRINTF(("ipcomp_output(): unknown/unsupported protocol "
704 "family %d, IPCA %s/%08x\n",
705 tdb->tdb_dst.sa.sa_family, ipsp_address(tdb->tdb_dst),
706 ntohl(tdb->tdb_spi)));
707 crypto_freereq(crp);
708 ipcompstat.ipcomps_nopf++;
709 splx(s);
710 return EPFNOSUPPORT;
711 break;
712 }
713
714 /* Release the crypto descriptor. */
715 crypto_freereq(crp);
716
717 error = ipsp_process_done(m, tdb);
718 splx(s);
719 return error;
720
721 baddone:
722 splx(s);
723
724 if (m)
725 m_freem(m);
726
727 crypto_freereq(crp);
728
729 return error;
730 }
731