xref: /openbsd-src/sys/netinet/ip_ipcomp.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /* $OpenBSD: ip_ipcomp.c,v 1.23 2008/09/15 21:46:01 chl 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 	tc = malloc(sizeof(*tc), M_XDATA, M_NOWAIT | M_ZERO);
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 	crdc = crp->crp_desc;
175 
176 	crdc->crd_skip = skip + hlen;
177 	crdc->crd_len = m->m_pkthdr.len - (skip + hlen);
178 	crdc->crd_inject = skip;
179 
180 	tc->tc_ptr = 0;
181 
182 	/* Decompression operation */
183 	crdc->crd_alg = ipcompx->type;
184 
185 	/* Crypto operation descriptor */
186 	crp->crp_ilen = m->m_pkthdr.len - (skip + hlen);
187 	crp->crp_flags = CRYPTO_F_IMBUF;
188 	crp->crp_buf = (caddr_t) m;
189 	crp->crp_callback = (int (*) (struct cryptop *)) ipcomp_input_cb;
190 	crp->crp_sid = tdb->tdb_cryptoid;
191 	crp->crp_opaque = (caddr_t) tc;
192 
193 	/* These are passed as-is to the callback */
194 	tc->tc_skip = skip;
195 	tc->tc_protoff = protoff;
196 	tc->tc_spi = tdb->tdb_spi;
197 	tc->tc_proto = IPPROTO_IPCOMP;
198 	bcopy(&tdb->tdb_dst, &tc->tc_dst, sizeof(union sockaddr_union));
199 
200 	return crypto_dispatch(crp);
201 }
202 
203 /*
204  * IPComp input callback, called directly by the crypto driver
205  */
206 int
207 ipcomp_input_cb(op)
208 	void *op;
209 {
210 	int error, s, skip, protoff, roff, hlen = IPCOMP_HLENGTH, clen;
211 	u_int8_t nproto;
212 	struct mbuf *m, *m1, *mo;
213 	struct tdb_crypto *tc;
214 	struct cryptop *crp;
215 	struct tdb *tdb;
216 	struct ipcomp  *ipcomp;
217 	caddr_t addr;
218 
219 	crp = (struct cryptop *) op;
220 
221 	tc = (struct tdb_crypto *) crp->crp_opaque;
222 	skip = tc->tc_skip;
223 	protoff = tc->tc_protoff;
224 
225 	m = (struct mbuf *) crp->crp_buf;
226 	if (m == NULL) {
227 		/* Shouldn't happen... */
228 		free(tc, M_XDATA);
229 		crypto_freereq(crp);
230 		ipcompstat.ipcomps_crypto++;
231 		DPRINTF(("ipcomp_input_cb(): bogus returned buffer from crypto\n"));
232 		return (EINVAL);
233 	}
234 
235 	s = spltdb();
236 
237 	tdb = gettdb(tc->tc_spi, &tc->tc_dst, tc->tc_proto);
238 	if (tdb == NULL) {
239 		free(tc, M_XDATA);
240 		ipcompstat.ipcomps_notdb++;
241 		DPRINTF(("ipcomp_input_cb(): TDB expired while in crypto"));
242 		error = EPERM;
243 		goto baddone;
244 	}
245 
246 	/* update the counters */
247 	tdb->tdb_cur_bytes += m->m_pkthdr.len - (skip + hlen);
248 	ipcompstat.ipcomps_ibytes += m->m_pkthdr.len - (skip + hlen);
249 
250 	/* Hard expiration */
251 	if ((tdb->tdb_flags & TDBF_BYTES) &&
252 	    (tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes)) {
253 		free(tc, M_XDATA);
254 		pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD);
255 		tdb_delete(tdb);
256 		error = ENXIO;
257 		goto baddone;
258 	}
259 	/* Notify on soft expiration */
260 	if ((tdb->tdb_flags & TDBF_SOFT_BYTES) &&
261 	    (tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes)) {
262 		pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT);
263 		tdb->tdb_flags &= ~TDBF_SOFT_BYTES;	/* Turn off checking */
264 	}
265 
266 	/* Check for crypto errors */
267 	if (crp->crp_etype) {
268 		if (crp->crp_etype == EAGAIN) {
269 			/* Reset the session ID */
270 			if (tdb->tdb_cryptoid != 0)
271 				tdb->tdb_cryptoid = crp->crp_sid;
272 			splx(s);
273 			return crypto_dispatch(crp);
274 		}
275 		free(tc, M_XDATA);
276 		ipcompstat.ipcomps_noxform++;
277 		DPRINTF(("ipcomp_input_cb(): crypto error %d\n",
278 		    crp->crp_etype));
279 		error = crp->crp_etype;
280 		goto baddone;
281 	}
282 	free(tc, M_XDATA);
283 
284 	/* Length of data after processing */
285 	clen = crp->crp_olen;
286 
287 	/* In case it's not done already, adjust the size of the mbuf chain */
288 	m->m_pkthdr.len = clen + hlen + skip;
289 
290 	if ((m->m_len < skip + hlen) && (m = m_pullup(m, skip + hlen)) == 0) {
291 		error = ENOBUFS;
292 		goto baddone;
293 	}
294 
295 	/* Find the beginning of the IPCOMP header */
296 	m1 = m_getptr(m, skip, &roff);
297 	if (m1 == NULL) {
298 		ipcompstat.ipcomps_hdrops++;
299 		DPRINTF(("ipcomp_input_cb(): bad mbuf chain, IPCA %s/%08x\n",
300 		    ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
301 		error = EINVAL;
302 		goto baddone;
303 	}
304 	/* Keep the next protocol field */
305 	addr = (caddr_t) mtod(m, struct ip *) + skip;
306 	ipcomp = (struct ipcomp *) addr;
307 	nproto = ipcomp->ipcomp_nh;
308 
309 	/* Remove the IPCOMP header from the mbuf */
310 	if (roff == 0) {
311 		/* The IPCOMP header is at the beginning of m1 */
312 		m_adj(m1, hlen);
313 		if (!(m1->m_flags & M_PKTHDR))
314 			m->m_pkthdr.len -= hlen;
315 	} else if (roff + hlen >= m1->m_len) {
316 		if (roff + hlen > m1->m_len) {
317 			/* Adjust the next mbuf by the remainder */
318 			m_adj(m1->m_next, roff + hlen - m1->m_len);
319 
320 			/*
321 			 * The second mbuf is guaranteed not to have a
322 			 * pkthdr...
323 			 */
324 			m->m_pkthdr.len -= (roff + hlen - m1->m_len);
325 		}
326 		/* Now, let's unlink the mbuf chain for a second... */
327 		mo = m1->m_next;
328 		m1->m_next = NULL;
329 
330 		/* ...and trim the end of the first part of the chain...sick */
331 		m_adj(m1, -(m1->m_len - roff));
332 		if (!(m1->m_flags & M_PKTHDR))
333 			m->m_pkthdr.len -= (m1->m_len - roff);
334 
335 		/* Finally, let's relink */
336 		m1->m_next = mo;
337 	} else {
338 		bcopy(mtod(m1, u_char *) + roff + hlen,
339 		    mtod(m1, u_char *) + roff,
340 		    m1->m_len - (roff + hlen));
341 		m1->m_len -= hlen;
342 		m->m_pkthdr.len -= hlen;
343 	}
344 
345 	/* Release the crypto descriptors */
346 	crypto_freereq(crp);
347 
348 	/* Restore the Next Protocol field */
349 	m_copyback(m, protoff, sizeof(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 
362 	crypto_freereq(crp);
363 
364 	return error;
365 }
366 
367 /*
368  * IPComp output routine, called by ipsp_process_packet()
369  */
370 int
371 ipcomp_output(m, tdb, mp, skip, protoff)
372 	struct mbuf    *m;
373 	struct tdb     *tdb;
374 	struct mbuf   **mp;
375 	int             skip;
376 	int             protoff;
377 {
378 	struct comp_algo *ipcompx = (struct comp_algo *) tdb->tdb_compalgxform;
379 	int             hlen;
380 	struct cryptodesc *crdc = NULL;
381 	struct cryptop *crp;
382 	struct tdb_crypto *tc;
383 	struct mbuf    *mi, *mo;
384 #if NBPFILTER > 0
385 	struct ifnet   *ifn = &(encif[0].sc_if);
386 
387 	if (ifn->if_bpf) {
388 		struct enchdr   hdr;
389 
390 		bzero(&hdr, sizeof(hdr));
391 
392 		hdr.af = tdb->tdb_dst.sa.sa_family;
393 		hdr.spi = tdb->tdb_spi;
394 
395 		bpf_mtap_hdr(ifn->if_bpf, (char *)&hdr, ENC_HDRLEN, m,
396 		    BPF_DIRECTION_OUT);
397 	}
398 #endif
399 	hlen = IPCOMP_HLENGTH;
400 
401 	ipcompstat.ipcomps_output++;
402 
403 	switch (tdb->tdb_dst.sa.sa_family) {
404 #ifdef INET
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 got too big\n",
413 			    ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
414 			m_freem(m);
415 			ipcompstat.ipcomps_toobig++;
416 			return EMSGSIZE;
417 		}
418 		break;
419 #endif /* INET */
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 got too big\n",
426 			    ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
427 			m_freem(m);
428 			ipcompstat.ipcomps_toobig++;
429 			return EMSGSIZE;
430 		}
431 #endif /* INET6 */
432 
433 	default:
434 		DPRINTF(("ipcomp_output(): unknown/unsupported protocol family %d, IPCA %s/%08x\n",
435 		    tdb->tdb_dst.sa.sa_family, ipsp_address(tdb->tdb_dst),
436 		    ntohl(tdb->tdb_spi)));
437 		m_freem(m);
438 		ipcompstat.ipcomps_nopf++;
439 		return EPFNOSUPPORT;
440 	}
441 
442 	/* Update the counters */
443 
444 	tdb->tdb_cur_bytes += m->m_pkthdr.len - skip;
445 	ipcompstat.ipcomps_obytes += m->m_pkthdr.len - skip;
446 
447 	/* Hard byte expiration */
448 	if ((tdb->tdb_flags & TDBF_BYTES) &&
449 	    (tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes)) {
450 		pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD);
451 		tdb_delete(tdb);
452 		m_freem(m);
453 		return EINVAL;
454 	}
455 	/* Soft byte expiration */
456 	if ((tdb->tdb_flags & TDBF_SOFT_BYTES) &&
457 	    (tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes)) {
458 		pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT);
459 		tdb->tdb_flags &= ~TDBF_SOFT_BYTES;	/* Turn off checking */
460 	}
461 	/*
462 	 * Loop through mbuf chain; if we find a readonly mbuf,
463 	 * replace the rest of the chain.
464 	 */
465 	mo = NULL;
466 	mi = m;
467 	while (mi != NULL && !M_READONLY(mi)) {
468 		mo = mi;
469 		mi = mi->m_next;
470 	}
471 
472 	if (mi != NULL) {
473 		/* Replace the rest of the mbuf chain. */
474 		struct mbuf    *n = m_copym2(mi, 0, M_COPYALL, M_DONTWAIT);
475 
476 		if (n == NULL) {
477 			DPRINTF(("ipcomp_output(): bad mbuf chain, IPCA %s/%08x\n",
478 			    ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
479 			ipcompstat.ipcomps_hdrops++;
480 			m_freem(m);
481 			return ENOBUFS;
482 		}
483 		if (mo != NULL)
484 			mo->m_next = n;
485 		else
486 			m = n;
487 
488 		m_freem(mi);
489 	}
490 	/* Ok now, we can pass to the crypto processing */
491 
492 	/* Get crypto descriptors */
493 	crp = crypto_getreq(1);
494 	if (crp == NULL) {
495 		m_freem(m);
496 		DPRINTF(("ipcomp_output(): failed to acquire crypto descriptors\n"));
497 		ipcompstat.ipcomps_crypto++;
498 		return ENOBUFS;
499 	}
500 	crdc = crp->crp_desc;
501 
502 	/* Compression descriptor */
503 	crdc->crd_skip = skip;
504 	crdc->crd_len = m->m_pkthdr.len - skip;
505 	crdc->crd_flags = CRD_F_COMP;
506 	crdc->crd_inject = skip;
507 
508 	/* Compression operation */
509 	crdc->crd_alg = ipcompx->type;
510 
511 	/* IPsec-specific opaque crypto info */
512 	tc = malloc(sizeof(*tc), M_XDATA, M_NOWAIT | M_ZERO);
513 	if (tc == NULL) {
514 		m_freem(m);
515 		crypto_freereq(crp);
516 		DPRINTF(("ipcomp_output(): failed to allocate tdb_crypto\n"));
517 		ipcompstat.ipcomps_crypto++;
518 		return ENOBUFS;
519 	}
520 
521 	tc->tc_spi = tdb->tdb_spi;
522 	tc->tc_proto = tdb->tdb_sproto;
523 	tc->tc_skip = skip;
524 	bcopy(&tdb->tdb_dst, &tc->tc_dst, sizeof(union sockaddr_union));
525 
526 	/* Crypto operation descriptor */
527 	crp->crp_ilen = m->m_pkthdr.len;	/* Total input length */
528 	crp->crp_flags = CRYPTO_F_IMBUF;
529 	crp->crp_buf = (caddr_t) m;
530 	crp->crp_callback = (int (*) (struct cryptop *)) ipcomp_output_cb;
531 	crp->crp_opaque = (caddr_t) tc;
532 	crp->crp_sid = tdb->tdb_cryptoid;
533 
534 	return crypto_dispatch(crp);
535 }
536 
537 /*
538  * IPComp output callback, called directly from the crypto driver
539  */
540 int
541 ipcomp_output_cb(cp)
542 	void *cp;
543 {
544 	struct cryptop *crp = (struct cryptop *) cp;
545 	struct tdb_crypto *tc;
546 	struct tdb *tdb;
547 	struct mbuf *m, *mo;
548 	int error, s, skip, rlen;
549 	u_int16_t cpi;
550 #ifdef INET
551 	struct ip *ip;
552 #endif
553 #ifdef INET6
554 	struct ip6_hdr *ip6;
555 #endif
556 	struct ipcomp  *ipcomp;
557 
558 	tc = (struct tdb_crypto *) crp->crp_opaque;
559 	skip = tc->tc_skip;
560 	rlen = crp->crp_ilen - skip;
561 
562 	m = (struct mbuf *) crp->crp_buf;
563 	if (m == NULL) {
564 		/* Shouldn't happen... */
565 		free(tc, M_XDATA);
566 		crypto_freereq(crp);
567 		ipcompstat.ipcomps_crypto++;
568 		DPRINTF(("ipcomp_output_cb(): bogus returned buffer from "
569 		    "crypto\n"));
570 		return (EINVAL);
571 	}
572 
573 	s = spltdb();
574 
575 	tdb = gettdb(tc->tc_spi, &tc->tc_dst, tc->tc_proto);
576 	if (tdb == NULL) {
577 		free(tc, M_XDATA);
578 		ipcompstat.ipcomps_notdb++;
579 		DPRINTF(("ipcomp_output_cb(): TDB expired while in crypto\n"));
580 		error = EPERM;
581 		goto baddone;
582 	}
583 
584 	/* Check for crypto errors. */
585 	if (crp->crp_etype) {
586 		if (crp->crp_etype == EAGAIN) {
587 			/* Reset the session ID */
588 			if (tdb->tdb_cryptoid != 0)
589 				tdb->tdb_cryptoid = crp->crp_sid;
590 			splx(s);
591 			return crypto_dispatch(crp);
592 		}
593 		free(tc, M_XDATA);
594 		ipcompstat.ipcomps_noxform++;
595 		DPRINTF(("ipcomp_output_cb(): crypto error %d\n",
596 		    crp->crp_etype));
597 		error = crp->crp_etype;
598 		goto baddone;
599 	}
600 	free(tc, M_XDATA);
601 
602 	/* Check sizes. */
603 	if (rlen < crp->crp_olen) {
604 		/* Compression was useless, we have lost time. */
605 		crypto_freereq(crp);
606 		error = ipsp_process_done(m, tdb);
607 		splx(s);
608 		return error;
609 	}
610 
611 	/* Inject IPCOMP header */
612 	mo = m_inject(m, skip, IPCOMP_HLENGTH, M_DONTWAIT);
613 	if (mo == NULL) {
614 		DPRINTF(("ipcomp_output_cb(): failed to inject IPCOMP header "
615 		    "for IPCA %s/%08x\n",
616 		    ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
617 		ipcompstat.ipcomps_wrap++;
618 		error = ENOBUFS;
619 		goto baddone;
620 	}
621 
622 	/* Initialize the IPCOMP header */
623 	ipcomp = mtod(mo, struct ipcomp *);
624 	bzero(ipcomp, sizeof(struct ipcomp));
625 	cpi = (u_int16_t) ntohl(tdb->tdb_spi);
626 	ipcomp->ipcomp_cpi = htons(cpi);
627 
628 	/* m_pullup before ? */
629 	switch (tdb->tdb_dst.sa.sa_family) {
630 #ifdef INET
631 	case AF_INET:
632 		ip = mtod(m, struct ip *);
633 		ipcomp->ipcomp_nh = ip->ip_p;
634 		ip->ip_p = IPPROTO_IPCOMP;
635 		break;
636 #endif /* INET */
637 #ifdef INET6
638 	case AF_INET6:
639 		ip6 = mtod(m, struct ip6_hdr *);
640 		ipcomp->ipcomp_nh = ip6->ip6_nxt;
641 		ip6->ip6_nxt = IPPROTO_IPCOMP;
642 		break;
643 #endif
644 	default:
645 		DPRINTF(("ipcomp_output_cb(): unsupported protocol family %d, "
646 		    "IPCA %s/%08x\n",
647 		    tdb->tdb_dst.sa.sa_family, ipsp_address(tdb->tdb_dst),
648 		    ntohl(tdb->tdb_spi)));
649 		ipcompstat.ipcomps_nopf++;
650 		error = EPFNOSUPPORT;
651 		goto baddone;
652 		break;
653 	}
654 
655 	/* Release the crypto descriptor. */
656 	crypto_freereq(crp);
657 
658 	error = ipsp_process_done(m, tdb);
659 	splx(s);
660 	return error;
661 
662 baddone:
663 	splx(s);
664 
665 	if (m)
666 		m_freem(m);
667 
668 	crypto_freereq(crp);
669 
670 	return error;
671 }
672