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