xref: /freebsd/sys/netipsec/xform_ipcomp.c (revision 195ebc7e9e4b129de810833791a19dfb4349d6a9)
1 /*	$FreeBSD$	*/
2 /* $OpenBSD: ip_ipcomp.c,v 1.1 2001/07/05 12:08:52 jjbg Exp $ */
3 
4 /*-
5  * Copyright (c) 2001 Jean-Jacques Bernard-Gundol (jj@wabbitt.org)
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in the
15  *   documentation and/or other materials provided with the distribution.
16  * 3. The name of the author may not be used to endorse or promote products
17  *   derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 /* IP payload compression protocol (IPComp), see RFC 2393 */
32 #include "opt_inet.h"
33 #include "opt_inet6.h"
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/mbuf.h>
38 #include <sys/lock.h>
39 #include <sys/mutex.h>
40 #include <sys/socket.h>
41 #include <sys/kernel.h>
42 #include <sys/protosw.h>
43 #include <sys/sysctl.h>
44 #include <sys/vimage.h>
45 
46 #include <netinet/in.h>
47 #include <netinet/in_systm.h>
48 #include <netinet/ip.h>
49 #include <netinet/ip_var.h>
50 
51 #include <net/route.h>
52 #include <netipsec/ipsec.h>
53 #include <netipsec/xform.h>
54 
55 #ifdef INET6
56 #include <netinet/ip6.h>
57 #include <netipsec/ipsec6.h>
58 #endif
59 
60 #include <netipsec/ipcomp.h>
61 #include <netipsec/ipcomp_var.h>
62 
63 #include <netipsec/key.h>
64 #include <netipsec/key_debug.h>
65 
66 #include <opencrypto/cryptodev.h>
67 #include <opencrypto/deflate.h>
68 #include <opencrypto/xform.h>
69 
70 #ifdef VIMAGE_GLOBALS
71 int	ipcomp_enable;
72 struct	ipcompstat ipcompstat;
73 #endif
74 
75 SYSCTL_DECL(_net_inet_ipcomp);
76 SYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet_ipcomp, OID_AUTO,
77 	ipcomp_enable,	CTLFLAG_RW,	ipcomp_enable,	0, "");
78 SYSCTL_V_STRUCT(V_NET, vnet_ipsec, _net_inet_ipcomp, IPSECCTL_STATS,
79 	stats,		CTLFLAG_RD,	ipcompstat,	ipcompstat, "");
80 
81 static int ipcomp_input_cb(struct cryptop *crp);
82 static int ipcomp_output_cb(struct cryptop *crp);
83 static int ipcomp_iattach(const void *);
84 
85 #ifndef VIMAGE_GLOBALS
86 static const vnet_modinfo_t vnet_ipcomp_modinfo = {
87 	.vmi_id		= VNET_MOD_IPCOMP,
88 	.vmi_name	= "ipsec_ipcomp",
89 	.vmi_dependson	= VNET_MOD_IPSEC,
90 	.vmi_iattach	= ipcomp_iattach
91 };
92 #endif /* !VIMAGE_GLOBALS */
93 
94 struct comp_algo *
95 ipcomp_algorithm_lookup(int alg)
96 {
97 	if (alg >= IPCOMP_ALG_MAX)
98 		return NULL;
99 	switch (alg) {
100 	case SADB_X_CALG_DEFLATE:
101 		return &comp_algo_deflate;
102 	}
103 	return NULL;
104 }
105 
106 /*
107  * ipcomp_init() is called when an CPI is being set up.
108  */
109 static int
110 ipcomp_init(struct secasvar *sav, struct xformsw *xsp)
111 {
112 	INIT_VNET_IPSEC(curvnet);
113 	struct comp_algo *tcomp;
114 	struct cryptoini cric;
115 
116 	/* NB: algorithm really comes in alg_enc and not alg_comp! */
117 	tcomp = ipcomp_algorithm_lookup(sav->alg_enc);
118 	if (tcomp == NULL) {
119 		DPRINTF(("%s: unsupported compression algorithm %d\n", __func__,
120 			 sav->alg_comp));
121 		return EINVAL;
122 	}
123 	sav->alg_comp = sav->alg_enc;		/* set for doing histogram */
124 	sav->tdb_xform = xsp;
125 	sav->tdb_compalgxform = tcomp;
126 
127 	/* Initialize crypto session */
128 	bzero(&cric, sizeof (cric));
129 	cric.cri_alg = sav->tdb_compalgxform->type;
130 
131 	return crypto_newsession(&sav->tdb_cryptoid, &cric, V_crypto_support);
132 }
133 
134 /*
135  * ipcomp_zeroize() used when IPCA is deleted
136  */
137 static int
138 ipcomp_zeroize(struct secasvar *sav)
139 {
140 	int err;
141 
142 	err = crypto_freesession(sav->tdb_cryptoid);
143 	sav->tdb_cryptoid = 0;
144 	return err;
145 }
146 
147 /*
148  * ipcomp_input() gets called to uncompress an input packet
149  */
150 static int
151 ipcomp_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff)
152 {
153 	INIT_VNET_IPSEC(curvnet);
154 	struct tdb_crypto *tc;
155 	struct cryptodesc *crdc;
156 	struct cryptop *crp;
157 	int hlen = IPCOMP_HLENGTH;
158 
159 	/* Get crypto descriptors */
160 	crp = crypto_getreq(1);
161 	if (crp == NULL) {
162 		m_freem(m);
163 		DPRINTF(("%s: no crypto descriptors\n", __func__));
164 		V_ipcompstat.ipcomps_crypto++;
165 		return ENOBUFS;
166 	}
167 	/* Get IPsec-specific opaque pointer */
168 	tc = (struct tdb_crypto *) malloc(sizeof (*tc), M_XDATA, M_NOWAIT|M_ZERO);
169 	if (tc == NULL) {
170 		m_freem(m);
171 		crypto_freereq(crp);
172 		DPRINTF(("%s: cannot allocate tdb_crypto\n", __func__));
173 		V_ipcompstat.ipcomps_crypto++;
174 		return ENOBUFS;
175 	}
176 	crdc = crp->crp_desc;
177 
178 	crdc->crd_skip = skip + hlen;
179 	crdc->crd_len = m->m_pkthdr.len - (skip + hlen);
180 	crdc->crd_inject = skip;
181 
182 	tc->tc_ptr = 0;
183 
184 	/* Decompression operation */
185 	crdc->crd_alg = sav->tdb_compalgxform->type;
186 
187 	/* Crypto operation descriptor */
188 	crp->crp_ilen = m->m_pkthdr.len - (skip + hlen);
189 	crp->crp_flags = CRYPTO_F_IMBUF | CRYPTO_F_CBIFSYNC;
190 	crp->crp_buf = (caddr_t) m;
191 	crp->crp_callback = ipcomp_input_cb;
192 	crp->crp_sid = sav->tdb_cryptoid;
193 	crp->crp_opaque = (caddr_t) tc;
194 
195 	/* These are passed as-is to the callback */
196 	tc->tc_spi = sav->spi;
197 	tc->tc_dst = sav->sah->saidx.dst;
198 	tc->tc_proto = sav->sah->saidx.proto;
199 	tc->tc_protoff = protoff;
200 	tc->tc_skip = skip;
201 
202 	return crypto_dispatch(crp);
203 }
204 
205 #ifdef INET6
206 #define	IPSEC_COMMON_INPUT_CB(m, sav, skip, protoff, mtag) do {		     \
207 	if (saidx->dst.sa.sa_family == AF_INET6) {			     \
208 		error = ipsec6_common_input_cb(m, sav, skip, protoff, mtag); \
209 	} else {							     \
210 		error = ipsec4_common_input_cb(m, sav, skip, protoff, mtag); \
211 	}								     \
212 } while (0)
213 #else
214 #define	IPSEC_COMMON_INPUT_CB(m, sav, skip, protoff, mtag)		     \
215 	(error = ipsec4_common_input_cb(m, sav, skip, protoff, mtag))
216 #endif
217 
218 /*
219  * IPComp input callback from the crypto driver.
220  */
221 static int
222 ipcomp_input_cb(struct cryptop *crp)
223 {
224 	INIT_VNET_IPSEC(curvnet);
225 	struct cryptodesc *crd;
226 	struct tdb_crypto *tc;
227 	int skip, protoff;
228 	struct mtag *mtag;
229 	struct mbuf *m;
230 	struct secasvar *sav;
231 	struct secasindex *saidx;
232 	int hlen = IPCOMP_HLENGTH, error, clen;
233 	u_int8_t nproto;
234 	caddr_t addr;
235 
236 	crd = crp->crp_desc;
237 
238 	tc = (struct tdb_crypto *) crp->crp_opaque;
239 	IPSEC_ASSERT(tc != NULL, ("null opaque crypto data area!"));
240 	skip = tc->tc_skip;
241 	protoff = tc->tc_protoff;
242 	mtag = (struct mtag *) tc->tc_ptr;
243 	m = (struct mbuf *) crp->crp_buf;
244 
245 	sav = KEY_ALLOCSA(&tc->tc_dst, tc->tc_proto, tc->tc_spi);
246 	if (sav == NULL) {
247 		V_ipcompstat.ipcomps_notdb++;
248 		DPRINTF(("%s: SA expired while in crypto\n", __func__));
249 		error = ENOBUFS;		/*XXX*/
250 		goto bad;
251 	}
252 
253 	saidx = &sav->sah->saidx;
254 	IPSEC_ASSERT(saidx->dst.sa.sa_family == AF_INET ||
255 		saidx->dst.sa.sa_family == AF_INET6,
256 		("unexpected protocol family %u", saidx->dst.sa.sa_family));
257 
258 	/* Check for crypto errors */
259 	if (crp->crp_etype) {
260 		/* Reset the session ID */
261 		if (sav->tdb_cryptoid != 0)
262 			sav->tdb_cryptoid = crp->crp_sid;
263 
264 		if (crp->crp_etype == EAGAIN) {
265 			KEY_FREESAV(&sav);
266 			error = crypto_dispatch(crp);
267 			return error;
268 		}
269 
270 		V_ipcompstat.ipcomps_noxform++;
271 		DPRINTF(("%s: crypto error %d\n", __func__, crp->crp_etype));
272 		error = crp->crp_etype;
273 		goto bad;
274 	}
275 	/* Shouldn't happen... */
276 	if (m == NULL) {
277 		V_ipcompstat.ipcomps_crypto++;
278 		DPRINTF(("%s: null mbuf returned from crypto\n", __func__));
279 		error = EINVAL;
280 		goto bad;
281 	}
282 	V_ipcompstat.ipcomps_hist[sav->alg_comp]++;
283 
284 	clen = crp->crp_olen;		/* Length of data after processing */
285 
286 	/* Release the crypto descriptors */
287 	free(tc, M_XDATA), tc = NULL;
288 	crypto_freereq(crp), crp = NULL;
289 
290 	/* In case it's not done already, adjust the size of the mbuf chain */
291 	m->m_pkthdr.len = clen + hlen + skip;
292 
293 	if (m->m_len < skip + hlen && (m = m_pullup(m, skip + hlen)) == 0) {
294 		V_ipcompstat.ipcomps_hdrops++;		/*XXX*/
295 		DPRINTF(("%s: m_pullup failed\n", __func__));
296 		error = EINVAL;				/*XXX*/
297 		goto bad;
298 	}
299 
300 	/* Keep the next protocol field */
301 	addr = (caddr_t) mtod(m, struct ip *) + skip;
302 	nproto = ((struct ipcomp *) addr)->comp_nxt;
303 
304 	/* Remove the IPCOMP header */
305 	error = m_striphdr(m, skip, hlen);
306 	if (error) {
307 		V_ipcompstat.ipcomps_hdrops++;
308 		DPRINTF(("%s: bad mbuf chain, IPCA %s/%08lx\n", __func__,
309 			 ipsec_address(&sav->sah->saidx.dst),
310 			 (u_long) ntohl(sav->spi)));
311 		goto bad;
312 	}
313 
314 	/* Restore the Next Protocol field */
315 	m_copyback(m, protoff, sizeof (u_int8_t), (u_int8_t *) &nproto);
316 
317 	IPSEC_COMMON_INPUT_CB(m, sav, skip, protoff, NULL);
318 
319 	KEY_FREESAV(&sav);
320 	return error;
321 bad:
322 	if (sav)
323 		KEY_FREESAV(&sav);
324 	if (m)
325 		m_freem(m);
326 	if (tc != NULL)
327 		free(tc, M_XDATA);
328 	if (crp)
329 		crypto_freereq(crp);
330 	return error;
331 }
332 
333 /*
334  * IPComp output routine, called by ipsec[46]_process_packet()
335  */
336 static int
337 ipcomp_output(
338 	struct mbuf *m,
339 	struct ipsecrequest *isr,
340 	struct mbuf **mp,
341 	int skip,
342 	int protoff
343 )
344 {
345 	INIT_VNET_IPSEC(curvnet);
346 	struct secasvar *sav;
347 	struct comp_algo *ipcompx;
348 	int error, ralen, hlen, maxpacketsize, roff;
349 	u_int8_t prot;
350 	struct cryptodesc *crdc;
351 	struct cryptop *crp;
352 	struct tdb_crypto *tc;
353 	struct mbuf *mo;
354 	struct ipcomp *ipcomp;
355 
356 	sav = isr->sav;
357 	IPSEC_ASSERT(sav != NULL, ("null SA"));
358 	ipcompx = sav->tdb_compalgxform;
359 	IPSEC_ASSERT(ipcompx != NULL, ("null compression xform"));
360 
361 	ralen = m->m_pkthdr.len - skip;	/* Raw payload length before comp. */
362 	hlen = IPCOMP_HLENGTH;
363 
364 	V_ipcompstat.ipcomps_output++;
365 
366 	/* Check for maximum packet size violations. */
367 	switch (sav->sah->saidx.dst.sa.sa_family) {
368 #ifdef INET
369 	case AF_INET:
370 		maxpacketsize =  IP_MAXPACKET;
371 		break;
372 #endif /* INET */
373 #ifdef INET6
374 	case AF_INET6:
375 		maxpacketsize =  IPV6_MAXPACKET;
376 		break;
377 #endif /* INET6 */
378 	default:
379 		V_ipcompstat.ipcomps_nopf++;
380 		DPRINTF(("%s: unknown/unsupported protocol family %d, "
381 		    "IPCA %s/%08lx\n", __func__,
382 		    sav->sah->saidx.dst.sa.sa_family,
383 		    ipsec_address(&sav->sah->saidx.dst),
384 		    (u_long) ntohl(sav->spi)));
385 		error = EPFNOSUPPORT;
386 		goto bad;
387 	}
388 	if (skip + hlen + ralen > maxpacketsize) {
389 		V_ipcompstat.ipcomps_toobig++;
390 		DPRINTF(("%s: packet in IPCA %s/%08lx got too big "
391 		    "(len %u, max len %u)\n", __func__,
392 		    ipsec_address(&sav->sah->saidx.dst),
393 		    (u_long) ntohl(sav->spi),
394 		    skip + hlen + ralen, maxpacketsize));
395 		error = EMSGSIZE;
396 		goto bad;
397 	}
398 
399 	/* Update the counters */
400 	V_ipcompstat.ipcomps_obytes += m->m_pkthdr.len - skip;
401 
402 	m = m_unshare(m, M_NOWAIT);
403 	if (m == NULL) {
404 		V_ipcompstat.ipcomps_hdrops++;
405 		DPRINTF(("%s: cannot clone mbuf chain, IPCA %s/%08lx\n",
406 		    __func__, ipsec_address(&sav->sah->saidx.dst),
407 		    (u_long) ntohl(sav->spi)));
408 		error = ENOBUFS;
409 		goto bad;
410 	}
411 
412 	/* Inject IPCOMP header */
413 	mo = m_makespace(m, skip, hlen, &roff);
414 	if (mo == NULL) {
415 		V_ipcompstat.ipcomps_wrap++;
416 		DPRINTF(("%s: IPCOMP header inject failed for IPCA %s/%08lx\n",
417 		    __func__, ipsec_address(&sav->sah->saidx.dst),
418 		    (u_long) ntohl(sav->spi)));
419 		error = ENOBUFS;
420 		goto bad;
421 	}
422 	ipcomp = (struct ipcomp *)(mtod(mo, caddr_t) + roff);
423 
424 	/* Initialize the IPCOMP header */
425 	/* XXX alignment always correct? */
426 	switch (sav->sah->saidx.dst.sa.sa_family) {
427 #ifdef INET
428 	case AF_INET:
429 		ipcomp->comp_nxt = mtod(m, struct ip *)->ip_p;
430 		break;
431 #endif /* INET */
432 #ifdef INET6
433 	case AF_INET6:
434 		ipcomp->comp_nxt = mtod(m, struct ip6_hdr *)->ip6_nxt;
435 		break;
436 #endif
437 	}
438 	ipcomp->comp_flags = 0;
439 	ipcomp->comp_cpi = htons((u_int16_t) ntohl(sav->spi));
440 
441 	/* Fix Next Protocol in IPv4/IPv6 header */
442 	prot = IPPROTO_IPCOMP;
443 	m_copyback(m, protoff, sizeof(u_int8_t), (u_char *) &prot);
444 
445 	/* Ok now, we can pass to the crypto processing */
446 
447 	/* Get crypto descriptors */
448 	crp = crypto_getreq(1);
449 	if (crp == NULL) {
450 		V_ipcompstat.ipcomps_crypto++;
451 		DPRINTF(("%s: failed to acquire crypto descriptor\n",__func__));
452 		error = ENOBUFS;
453 		goto bad;
454 	}
455 	crdc = crp->crp_desc;
456 
457 	/* Compression descriptor */
458 	crdc->crd_skip = skip + hlen;
459 	crdc->crd_len = m->m_pkthdr.len - (skip + hlen);
460 	crdc->crd_flags = CRD_F_COMP;
461 	crdc->crd_inject = skip + hlen;
462 
463 	/* Compression operation */
464 	crdc->crd_alg = ipcompx->type;
465 
466 	/* IPsec-specific opaque crypto info */
467 	tc = (struct tdb_crypto *) malloc(sizeof(struct tdb_crypto),
468 		M_XDATA, M_NOWAIT|M_ZERO);
469 	if (tc == NULL) {
470 		V_ipcompstat.ipcomps_crypto++;
471 		DPRINTF(("%s: failed to allocate tdb_crypto\n", __func__));
472 		crypto_freereq(crp);
473 		error = ENOBUFS;
474 		goto bad;
475 	}
476 
477 	tc->tc_isr = isr;
478 	tc->tc_spi = sav->spi;
479 	tc->tc_dst = sav->sah->saidx.dst;
480 	tc->tc_proto = sav->sah->saidx.proto;
481 	tc->tc_skip = skip + hlen;
482 
483 	/* Crypto operation descriptor */
484 	crp->crp_ilen = m->m_pkthdr.len;	/* Total input length */
485 	crp->crp_flags = CRYPTO_F_IMBUF | CRYPTO_F_CBIFSYNC;
486 	crp->crp_buf = (caddr_t) m;
487 	crp->crp_callback = ipcomp_output_cb;
488 	crp->crp_opaque = (caddr_t) tc;
489 	crp->crp_sid = sav->tdb_cryptoid;
490 
491 	return crypto_dispatch(crp);
492 bad:
493 	if (m)
494 		m_freem(m);
495 	return (error);
496 }
497 
498 /*
499  * IPComp output callback from the crypto driver.
500  */
501 static int
502 ipcomp_output_cb(struct cryptop *crp)
503 {
504 	INIT_VNET_IPSEC(curvnet);
505 	struct tdb_crypto *tc;
506 	struct ipsecrequest *isr;
507 	struct secasvar *sav;
508 	struct mbuf *m;
509 	int error, skip, rlen;
510 
511 	tc = (struct tdb_crypto *) crp->crp_opaque;
512 	IPSEC_ASSERT(tc != NULL, ("null opaque data area!"));
513 	m = (struct mbuf *) crp->crp_buf;
514 	skip = tc->tc_skip;
515 	rlen = crp->crp_ilen - skip;
516 
517 	isr = tc->tc_isr;
518 	IPSECREQUEST_LOCK(isr);
519 	sav = KEY_ALLOCSA(&tc->tc_dst, tc->tc_proto, tc->tc_spi);
520 	if (sav == NULL) {
521 		V_ipcompstat.ipcomps_notdb++;
522 		DPRINTF(("%s: SA expired while in crypto\n", __func__));
523 		error = ENOBUFS;		/*XXX*/
524 		goto bad;
525 	}
526 	IPSEC_ASSERT(isr->sav == sav, ("SA changed\n"));
527 
528 	/* Check for crypto errors */
529 	if (crp->crp_etype) {
530 		/* Reset session ID */
531 		if (sav->tdb_cryptoid != 0)
532 			sav->tdb_cryptoid = crp->crp_sid;
533 
534 		if (crp->crp_etype == EAGAIN) {
535 			KEY_FREESAV(&sav);
536 			IPSECREQUEST_UNLOCK(isr);
537 			error = crypto_dispatch(crp);
538 			return error;
539 		}
540 		V_ipcompstat.ipcomps_noxform++;
541 		DPRINTF(("%s: crypto error %d\n", __func__, crp->crp_etype));
542 		error = crp->crp_etype;
543 		goto bad;
544 	}
545 	/* Shouldn't happen... */
546 	if (m == NULL) {
547 		V_ipcompstat.ipcomps_crypto++;
548 		DPRINTF(("%s: bogus return buffer from crypto\n", __func__));
549 		error = EINVAL;
550 		goto bad;
551 	}
552 	V_ipcompstat.ipcomps_hist[sav->alg_comp]++;
553 
554 	if (rlen > crp->crp_olen) {
555 		/* Adjust the length in the IP header */
556 		switch (sav->sah->saidx.dst.sa.sa_family) {
557 #ifdef INET
558 		case AF_INET:
559 			mtod(m, struct ip *)->ip_len = htons(m->m_pkthdr.len);
560 			break;
561 #endif /* INET */
562 #ifdef INET6
563 		case AF_INET6:
564 			mtod(m, struct ip6_hdr *)->ip6_plen =
565 				htons(m->m_pkthdr.len) - sizeof(struct ip6_hdr);
566 			break;
567 #endif /* INET6 */
568 		default:
569 			V_ipcompstat.ipcomps_nopf++;
570 			DPRINTF(("%s: unknown/unsupported protocol "
571 			    "family %d, IPCA %s/%08lx\n", __func__,
572 			    sav->sah->saidx.dst.sa.sa_family,
573 			    ipsec_address(&sav->sah->saidx.dst),
574 			    (u_long) ntohl(sav->spi)));
575 			error = EPFNOSUPPORT;
576 			goto bad;
577 		}
578 	} else {
579 		/* compression was useless, we have lost time */
580 		/* XXX add statistic */
581 	}
582 
583 	/* Release the crypto descriptor */
584 	free(tc, M_XDATA);
585 	crypto_freereq(crp);
586 
587 	/* NB: m is reclaimed by ipsec_process_done. */
588 	error = ipsec_process_done(m, isr);
589 	KEY_FREESAV(&sav);
590 	IPSECREQUEST_UNLOCK(isr);
591 	return error;
592 bad:
593 	if (sav)
594 		KEY_FREESAV(&sav);
595 	IPSECREQUEST_UNLOCK(isr);
596 	if (m)
597 		m_freem(m);
598 	free(tc, M_XDATA);
599 	crypto_freereq(crp);
600 	return error;
601 }
602 
603 static struct xformsw ipcomp_xformsw = {
604 	XF_IPCOMP,		XFT_COMP,		"IPcomp",
605 	ipcomp_init,		ipcomp_zeroize,		ipcomp_input,
606 	ipcomp_output
607 };
608 
609 static void
610 ipcomp_attach(void)
611 {
612 
613 	xform_register(&ipcomp_xformsw);
614 #ifndef VIMAGE_GLOBALS
615 	vnet_mod_register(&vnet_ipcomp_modinfo);
616 #else
617 	ipcomp_iattach(NULL);
618 #endif
619 }
620 
621 static int
622 ipcomp_iattach(const void *unused __unused)
623 {
624 	INIT_VNET_IPSEC(curvnet);
625 
626 	V_ipcomp_enable = 0;
627 	return (0);
628 }
629 SYSINIT(ipcomp_xform_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_MIDDLE, ipcomp_attach, NULL);
630