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