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