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