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