xref: /openbsd-src/sys/netinet/ip_ipcomp.c (revision 8500990981f885cbe5e6a4958549cacc238b5ae6)
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
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
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
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
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
209 ipcomp_input_cb(op)
210 	void *op;
211 {
212 	int error, 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
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
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, 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