1*fb8de0f1Sclaudio /* $OpenBSD: ip_ipcomp.c,v 1.92 2022/05/03 09:18:11 claudio Exp $ */
21aaeb53aSjjbg
31aaeb53aSjjbg /*
41aaeb53aSjjbg * Copyright (c) 2001 Jean-Jacques Bernard-Gundol (jj@wabbitt.org)
51aaeb53aSjjbg *
61aaeb53aSjjbg * Redistribution and use in source and binary forms, with or without
71aaeb53aSjjbg * modification, are permitted provided that the following conditions
81aaeb53aSjjbg * are met:
91aaeb53aSjjbg *
101aaeb53aSjjbg * 1. Redistributions of source code must retain the above copyright
111aaeb53aSjjbg * notice, this list of conditions and the following disclaimer.
121aaeb53aSjjbg * 2. Redistributions in binary form must reproduce the above copyright
131aaeb53aSjjbg * notice, this list of conditions and the following disclaimer in the
141aaeb53aSjjbg * documentation and/or other materials provided with the distribution.
151aaeb53aSjjbg * 3. The name of the author may not be used to endorse or promote products
161aaeb53aSjjbg * derived from this software without specific prior written permission.
171aaeb53aSjjbg *
181aaeb53aSjjbg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
191aaeb53aSjjbg * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
201aaeb53aSjjbg * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
211aaeb53aSjjbg * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
221aaeb53aSjjbg * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
231aaeb53aSjjbg * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
241aaeb53aSjjbg * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
251aaeb53aSjjbg * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
261aaeb53aSjjbg * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
271aaeb53aSjjbg * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
281aaeb53aSjjbg */
291aaeb53aSjjbg
301aaeb53aSjjbg /* IP payload compression protocol (IPComp), see RFC 2393 */
311aaeb53aSjjbg
321aaeb53aSjjbg #include <sys/param.h>
331aaeb53aSjjbg #include <sys/systm.h>
341aaeb53aSjjbg #include <sys/mbuf.h>
351aaeb53aSjjbg #include <sys/socket.h>
361aaeb53aSjjbg
371aaeb53aSjjbg #include <net/if.h>
380deb6685Smpi #include <net/if_var.h>
391aaeb53aSjjbg #include <net/bpf.h>
401aaeb53aSjjbg
411aaeb53aSjjbg #include <netinet/in.h>
421aaeb53aSjjbg #include <netinet/ip.h>
4344570b44Smpi #include <netinet/ip_var.h>
441aaeb53aSjjbg
451aaeb53aSjjbg #ifdef INET6
461aaeb53aSjjbg #include <netinet/ip6.h>
471aaeb53aSjjbg #endif /* INET6 */
481aaeb53aSjjbg
491aaeb53aSjjbg #include <netinet/ip_ipsp.h>
501aaeb53aSjjbg #include <netinet/ip_ipcomp.h>
511aaeb53aSjjbg #include <net/pfkeyv2.h>
521aaeb53aSjjbg #include <net/if_enc.h>
531aaeb53aSjjbg
541aaeb53aSjjbg #include <crypto/cryptodev.h>
551aaeb53aSjjbg #include <crypto/xform.h>
561aaeb53aSjjbg
571aaeb53aSjjbg #include "bpfilter.h"
581aaeb53aSjjbg
591aaeb53aSjjbg #ifdef ENCDEBUG
60698a75ddSbluhm #define DPRINTF(fmt, args...) \
61698a75ddSbluhm do { \
62698a75ddSbluhm if (encdebug) \
63698a75ddSbluhm printf("%s: " fmt "\n", __func__, ## args); \
64698a75ddSbluhm } while (0)
651aaeb53aSjjbg #else
66698a75ddSbluhm #define DPRINTF(fmt, args...) \
67698a75ddSbluhm do { } while (0)
681aaeb53aSjjbg #endif
691aaeb53aSjjbg
701aaeb53aSjjbg /*
711aaeb53aSjjbg * ipcomp_attach() is called from the transformation code
721aaeb53aSjjbg */
731aaeb53aSjjbg int
ipcomp_attach(void)741aaeb53aSjjbg ipcomp_attach(void)
751aaeb53aSjjbg {
761aaeb53aSjjbg return 0;
771aaeb53aSjjbg }
781aaeb53aSjjbg
791aaeb53aSjjbg /*
801aaeb53aSjjbg * ipcomp_init() is called when an CPI is being set up.
811aaeb53aSjjbg */
821aaeb53aSjjbg int
ipcomp_init(struct tdb * tdbp,const struct xformsw * xsp,struct ipsecinit * ii)835e3836acSbluhm ipcomp_init(struct tdb *tdbp, const struct xformsw *xsp, struct ipsecinit *ii)
841aaeb53aSjjbg {
854d13edafSbluhm const struct comp_algo *tcomp = NULL;
861aaeb53aSjjbg struct cryptoini cric;
87b7be02dcSbluhm int error;
881aaeb53aSjjbg
891aaeb53aSjjbg switch (ii->ii_compalg) {
901aaeb53aSjjbg case SADB_X_CALG_DEFLATE:
911aaeb53aSjjbg tcomp = &comp_algo_deflate;
921aaeb53aSjjbg break;
931aaeb53aSjjbg default:
94698a75ddSbluhm DPRINTF("unsupported compression algorithm %d specified",
95698a75ddSbluhm ii->ii_compalg);
961aaeb53aSjjbg return EINVAL;
971aaeb53aSjjbg }
981aaeb53aSjjbg
991aaeb53aSjjbg tdbp->tdb_compalgxform = tcomp;
1001aaeb53aSjjbg
101698a75ddSbluhm DPRINTF("initialized TDB with ipcomp algorithm %s", tcomp->name);
1021aaeb53aSjjbg
1031aaeb53aSjjbg tdbp->tdb_xform = xsp;
1041aaeb53aSjjbg
1051aaeb53aSjjbg /* Initialize crypto session */
106f8575965Stedu memset(&cric, 0, sizeof(cric));
1071aaeb53aSjjbg cric.cri_alg = tdbp->tdb_compalgxform->type;
1081aaeb53aSjjbg
109b7be02dcSbluhm KERNEL_LOCK();
110b7be02dcSbluhm error = crypto_newsession(&tdbp->tdb_cryptoid, &cric, 0);
111b7be02dcSbluhm KERNEL_UNLOCK();
112b7be02dcSbluhm return error;
1131aaeb53aSjjbg }
1141aaeb53aSjjbg
1151aaeb53aSjjbg /*
1161aaeb53aSjjbg * ipcomp_zeroize() used when IPCA is deleted
1171aaeb53aSjjbg */
1181aaeb53aSjjbg int
ipcomp_zeroize(struct tdb * tdbp)119288aa5efSnaddy ipcomp_zeroize(struct tdb *tdbp)
1201aaeb53aSjjbg {
121b7be02dcSbluhm int error;
1221aaeb53aSjjbg
123b7be02dcSbluhm KERNEL_LOCK();
124b7be02dcSbluhm error = crypto_freesession(tdbp->tdb_cryptoid);
125b7be02dcSbluhm KERNEL_UNLOCK();
1261aaeb53aSjjbg tdbp->tdb_cryptoid = 0;
127b7be02dcSbluhm return error;
1281aaeb53aSjjbg }
1291aaeb53aSjjbg
1301aaeb53aSjjbg /*
1311aaeb53aSjjbg * ipcomp_input() gets called to uncompress an input packet
1321aaeb53aSjjbg */
1331aaeb53aSjjbg int
ipcomp_input(struct mbuf ** mp,struct tdb * tdb,int skip,int protoff)134d5072c26Sbluhm ipcomp_input(struct mbuf **mp, struct tdb *tdb, int skip, int protoff)
1351aaeb53aSjjbg {
1364d13edafSbluhm const struct comp_algo *ipcompx = tdb->tdb_compalgxform;
137d5072c26Sbluhm struct mbuf *m = *mp;
1381aaeb53aSjjbg struct cryptodesc *crdc = NULL;
1391aaeb53aSjjbg struct cryptop *crp;
1404f56c6f5Stobhe int hlen, error, clen, roff;
1414f56c6f5Stobhe u_int8_t nproto;
1424f56c6f5Stobhe u_int64_t ibytes;
1434f56c6f5Stobhe struct mbuf *m1, *mo;
1444f56c6f5Stobhe struct ipcomp *ipcomp;
1454f56c6f5Stobhe caddr_t addr;
1464f56c6f5Stobhe #ifdef ENCDEBUG
1474f56c6f5Stobhe char buf[INET6_ADDRSTRLEN];
1484f56c6f5Stobhe #endif
1491aaeb53aSjjbg
1501aaeb53aSjjbg hlen = IPCOMP_HLENGTH;
1511aaeb53aSjjbg
1521aaeb53aSjjbg /* Get crypto descriptors */
1531aaeb53aSjjbg crp = crypto_getreq(1);
1541aaeb53aSjjbg if (crp == NULL) {
155698a75ddSbluhm DPRINTF("failed to acquire crypto descriptors");
1566460338bSvisa ipcompstat_inc(ipcomps_crypto);
157d5072c26Sbluhm goto drop;
1581aaeb53aSjjbg }
159e410e70dSpatrick crdc = &crp->crp_desc[0];
1601aaeb53aSjjbg
1611aaeb53aSjjbg crdc->crd_skip = skip + hlen;
1621aaeb53aSjjbg crdc->crd_len = m->m_pkthdr.len - (skip + hlen);
1631aaeb53aSjjbg crdc->crd_inject = skip;
1641aaeb53aSjjbg
1651aaeb53aSjjbg /* Decompression operation */
1661aaeb53aSjjbg crdc->crd_alg = ipcompx->type;
1671aaeb53aSjjbg
1681aaeb53aSjjbg /* Crypto operation descriptor */
1691aaeb53aSjjbg crp->crp_ilen = m->m_pkthdr.len - (skip + hlen);
170*fb8de0f1Sclaudio crp->crp_flags = CRYPTO_F_IMBUF;
1711aaeb53aSjjbg crp->crp_buf = (caddr_t)m;
1721aaeb53aSjjbg crp->crp_sid = tdb->tdb_cryptoid;
1731aaeb53aSjjbg
17487edded1Stobhe while ((error = crypto_invoke(crp)) == EAGAIN) {
17512758001Stobhe /* Reset the session ID */
17612758001Stobhe if (tdb->tdb_cryptoid != 0)
17712758001Stobhe tdb->tdb_cryptoid = crp->crp_sid;
17812758001Stobhe }
17987edded1Stobhe if (error) {
18087edded1Stobhe DPRINTF("crypto error %d", error);
18112758001Stobhe ipsecstat_inc(ipsec_noxform);
182d5072c26Sbluhm goto drop;
18312758001Stobhe }
18412758001Stobhe
18512758001Stobhe clen = crp->crp_olen;
18612758001Stobhe
18712758001Stobhe /* Release the crypto descriptors */
18812758001Stobhe crypto_freereq(crp);
1894f56c6f5Stobhe crp = NULL;
1901e2c197eSmpi
1911aaeb53aSjjbg /* update the counters */
1922edaa7baSmpi ibytes = m->m_pkthdr.len - (skip + hlen);
1932edaa7baSmpi tdb->tdb_cur_bytes += ibytes;
194d997d144Smvs tdbstat_add(tdb, tdb_ibytes, ibytes);
1952edaa7baSmpi ipcompstat_add(ipcomps_ibytes, ibytes);
1961aaeb53aSjjbg
1971aaeb53aSjjbg /* Hard expiration */
1981aaeb53aSjjbg if ((tdb->tdb_flags & TDBF_BYTES) &&
1991aaeb53aSjjbg (tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes)) {
2006b86e016Smvs ipsecstat_inc(ipsec_exctdb);
2011aaeb53aSjjbg pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD);
2021aaeb53aSjjbg tdb_delete(tdb);
2034f56c6f5Stobhe goto drop;
2041aaeb53aSjjbg }
2051aaeb53aSjjbg /* Notify on soft expiration */
20659b9936bSbluhm mtx_enter(&tdb->tdb_mtx);
2071aaeb53aSjjbg if ((tdb->tdb_flags & TDBF_SOFT_BYTES) &&
2081aaeb53aSjjbg (tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes)) {
2091aaeb53aSjjbg tdb->tdb_flags &= ~TDBF_SOFT_BYTES; /* Turn off checking */
21059b9936bSbluhm mtx_leave(&tdb->tdb_mtx);
21159b9936bSbluhm /* may sleep in solock() for the pfkey socket */
21259b9936bSbluhm pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT);
21359b9936bSbluhm } else
21459b9936bSbluhm mtx_leave(&tdb->tdb_mtx);
2151aaeb53aSjjbg
2161aaeb53aSjjbg /* In case it's not done already, adjust the size of the mbuf chain */
2171aaeb53aSjjbg m->m_pkthdr.len = clen + hlen + skip;
2181aaeb53aSjjbg
219e63ce21bSbluhm if (m->m_len < skip + hlen &&
220e63ce21bSbluhm (m = *mp = m_pullup(m, skip + hlen)) == NULL) {
221448c5f3fSbluhm ipcompstat_inc(ipcomps_hdrops);
2224f56c6f5Stobhe goto drop;
22390596d0eSmillert }
2241aaeb53aSjjbg
2251aaeb53aSjjbg /* Find the beginning of the IPCOMP header */
2261aaeb53aSjjbg m1 = m_getptr(m, skip, &roff);
2271aaeb53aSjjbg if (m1 == NULL) {
228698a75ddSbluhm DPRINTF("bad mbuf chain, IPCA %s/%08x",
2293514aacbSmikeb ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
230698a75ddSbluhm ntohl(tdb->tdb_spi));
231448c5f3fSbluhm ipcompstat_inc(ipcomps_hdrops);
2324f56c6f5Stobhe goto drop;
2331aaeb53aSjjbg }
2341aaeb53aSjjbg /* Keep the next protocol field */
2351aaeb53aSjjbg addr = (caddr_t) mtod(m, struct ip *) + skip;
2361aaeb53aSjjbg ipcomp = (struct ipcomp *) addr;
2371aaeb53aSjjbg nproto = ipcomp->ipcomp_nh;
2381aaeb53aSjjbg
2391aaeb53aSjjbg /* Remove the IPCOMP header from the mbuf */
2401aaeb53aSjjbg if (roff == 0) {
2411aaeb53aSjjbg /* The IPCOMP header is at the beginning of m1 */
2421aaeb53aSjjbg m_adj(m1, hlen);
24323702ca1Sbluhm /*
24423702ca1Sbluhm * If m1 is the first mbuf, it has set M_PKTHDR and m_adj()
24523702ca1Sbluhm * has already adjusted the packet header length for us.
24623702ca1Sbluhm */
24723702ca1Sbluhm if (m1 != m)
2481aaeb53aSjjbg m->m_pkthdr.len -= hlen;
2491aaeb53aSjjbg } else if (roff + hlen >= m1->m_len) {
25023702ca1Sbluhm int adjlen;
25123702ca1Sbluhm
2521aaeb53aSjjbg if (roff + hlen > m1->m_len) {
25323702ca1Sbluhm adjlen = roff + hlen - m1->m_len;
25423702ca1Sbluhm
2551aaeb53aSjjbg /* Adjust the next mbuf by the remainder */
25623702ca1Sbluhm m_adj(m1->m_next, adjlen);
2571aaeb53aSjjbg
2581aaeb53aSjjbg /*
2591aaeb53aSjjbg * The second mbuf is guaranteed not to have a
2601aaeb53aSjjbg * pkthdr...
2611aaeb53aSjjbg */
26223702ca1Sbluhm m->m_pkthdr.len -= adjlen;
2631aaeb53aSjjbg }
2641aaeb53aSjjbg /* Now, let's unlink the mbuf chain for a second... */
2651aaeb53aSjjbg mo = m1->m_next;
2661aaeb53aSjjbg m1->m_next = NULL;
2671aaeb53aSjjbg
2681aaeb53aSjjbg /* ...and trim the end of the first part of the chain...sick */
26923702ca1Sbluhm adjlen = m1->m_len - roff;
27023702ca1Sbluhm m_adj(m1, -adjlen);
27123702ca1Sbluhm /*
27223702ca1Sbluhm * If m1 is the first mbuf, it has set M_PKTHDR and m_adj()
27323702ca1Sbluhm * has already adjusted the packet header length for us.
27423702ca1Sbluhm */
27523702ca1Sbluhm if (m1 != m)
27623702ca1Sbluhm m->m_pkthdr.len -= adjlen;
2771aaeb53aSjjbg
2781aaeb53aSjjbg /* Finally, let's relink */
2791aaeb53aSjjbg m1->m_next = mo;
2801aaeb53aSjjbg } else {
2812d0f50edSdhill memmove(mtod(m1, u_char *) + roff,
2822d0f50edSdhill mtod(m1, u_char *) + roff + hlen,
2831aaeb53aSjjbg m1->m_len - (roff + hlen));
2841aaeb53aSjjbg m1->m_len -= hlen;
2851aaeb53aSjjbg m->m_pkthdr.len -= hlen;
2861aaeb53aSjjbg }
2871aaeb53aSjjbg
2881aaeb53aSjjbg /* Restore the Next Protocol field */
28941b18b7eSblambert m_copyback(m, protoff, sizeof(u_int8_t), &nproto, M_NOWAIT);
2901aaeb53aSjjbg
2911aaeb53aSjjbg /* Back to generic IPsec input processing */
292e63ce21bSbluhm return ipsec_common_input_cb(mp, tdb, skip, protoff);
2931aaeb53aSjjbg
2944f56c6f5Stobhe drop:
295e63ce21bSbluhm m_freemp(mp);
2964f56c6f5Stobhe crypto_freereq(crp);
297bec0ed23Sbluhm return IPPROTO_DONE;
2981aaeb53aSjjbg }
2991aaeb53aSjjbg
3001aaeb53aSjjbg /*
3011aaeb53aSjjbg * IPComp output routine, called by ipsp_process_packet()
3021aaeb53aSjjbg */
3031aaeb53aSjjbg int
ipcomp_output(struct mbuf * m,struct tdb * tdb,int skip,int protoff)304ead5a062Sbluhm ipcomp_output(struct mbuf *m, struct tdb *tdb, int skip, int protoff)
3051aaeb53aSjjbg {
3064d13edafSbluhm const struct comp_algo *ipcompx = tdb->tdb_compalgxform;
3074f56c6f5Stobhe int error, hlen, ilen, olen, rlen, roff;
3081aaeb53aSjjbg struct cryptodesc *crdc = NULL;
309448c5f3fSbluhm struct cryptop *crp = NULL;
3104f56c6f5Stobhe struct mbuf *mi, *mo;
3114f56c6f5Stobhe struct ip *ip;
3124f56c6f5Stobhe u_int16_t cpi;
3134f56c6f5Stobhe #ifdef INET6
3144f56c6f5Stobhe struct ip6_hdr *ip6;
3154f56c6f5Stobhe #endif
3163514aacbSmikeb #ifdef ENCDEBUG
3173514aacbSmikeb char buf[INET6_ADDRSTRLEN];
3183514aacbSmikeb #endif
3191aaeb53aSjjbg #if NBPFILTER > 0
3208ddcae73Sreyk struct ifnet *encif;
3214f56c6f5Stobhe struct ipcomp *ipcomp;
32263df607fSpascoe
323a43d4d9bSreyk if ((encif = enc_getif(0, tdb->tdb_tap)) != NULL) {
3248ddcae73Sreyk encif->if_opackets++;
3258ddcae73Sreyk encif->if_obytes += m->m_pkthdr.len;
3268ddcae73Sreyk
3278ddcae73Sreyk if (encif->if_bpf) {
3281aaeb53aSjjbg struct enchdr hdr;
3291aaeb53aSjjbg
330f8575965Stedu memset(&hdr, 0, sizeof(hdr));
3311aaeb53aSjjbg
3321aaeb53aSjjbg hdr.af = tdb->tdb_dst.sa.sa_family;
3331aaeb53aSjjbg hdr.spi = tdb->tdb_spi;
3341aaeb53aSjjbg
3358ddcae73Sreyk bpf_mtap_hdr(encif->if_bpf, (char *)&hdr,
336f1d9eb97Sdlg ENC_HDRLEN, m, BPF_DIRECTION_OUT);
3378ddcae73Sreyk }
3381aaeb53aSjjbg }
3391aaeb53aSjjbg #endif
3401aaeb53aSjjbg hlen = IPCOMP_HLENGTH;
3411aaeb53aSjjbg
3426460338bSvisa ipcompstat_inc(ipcomps_output);
3431aaeb53aSjjbg
3441aaeb53aSjjbg switch (tdb->tdb_dst.sa.sa_family) {
3451aaeb53aSjjbg case AF_INET:
3461aaeb53aSjjbg /* Check for IPv4 maximum packet size violations */
3471aaeb53aSjjbg /*
3481aaeb53aSjjbg * Since compression is going to reduce the size, no need to
3491aaeb53aSjjbg * worry
3501aaeb53aSjjbg */
351ccfb3f57Sho if (m->m_pkthdr.len + hlen > IP_MAXPACKET) {
352698a75ddSbluhm DPRINTF("packet in IPCA %s/%08x got too big",
353698a75ddSbluhm ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
354698a75ddSbluhm ntohl(tdb->tdb_spi));
3556460338bSvisa ipcompstat_inc(ipcomps_toobig);
356448c5f3fSbluhm error = EMSGSIZE;
357448c5f3fSbluhm goto drop;
3581aaeb53aSjjbg }
3591aaeb53aSjjbg break;
3601aaeb53aSjjbg
3611aaeb53aSjjbg #ifdef INET6
3621aaeb53aSjjbg case AF_INET6:
3631aaeb53aSjjbg /* Check for IPv6 maximum packet size violations */
364ccfb3f57Sho if (m->m_pkthdr.len + hlen > IPV6_MAXPACKET) {
365698a75ddSbluhm DPRINTF("packet in IPCA %s/%08x got too big",
366698a75ddSbluhm ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
367698a75ddSbluhm ntohl(tdb->tdb_spi));
3686460338bSvisa ipcompstat_inc(ipcomps_toobig);
369448c5f3fSbluhm error = EMSGSIZE;
370448c5f3fSbluhm goto drop;
3711aaeb53aSjjbg }
372a10a4f65Sbluhm break;
3731aaeb53aSjjbg #endif /* INET6 */
3741aaeb53aSjjbg
3751aaeb53aSjjbg default:
376698a75ddSbluhm DPRINTF("unknown/unsupported protocol family %d, IPCA %s/%08x",
377698a75ddSbluhm tdb->tdb_dst.sa.sa_family,
3783514aacbSmikeb ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
379698a75ddSbluhm ntohl(tdb->tdb_spi));
3806460338bSvisa ipcompstat_inc(ipcomps_nopf);
381448c5f3fSbluhm error = EPFNOSUPPORT;
382448c5f3fSbluhm goto drop;
3831aaeb53aSjjbg }
3841aaeb53aSjjbg
3851aaeb53aSjjbg /* Update the counters */
3861aaeb53aSjjbg tdb->tdb_cur_bytes += m->m_pkthdr.len - skip;
3876460338bSvisa ipcompstat_add(ipcomps_obytes, m->m_pkthdr.len - skip);
3881aaeb53aSjjbg
3891aaeb53aSjjbg /* Hard byte expiration */
3901aaeb53aSjjbg if ((tdb->tdb_flags & TDBF_BYTES) &&
3911aaeb53aSjjbg (tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes)) {
3926b86e016Smvs ipsecstat_inc(ipsec_exctdb);
3931aaeb53aSjjbg pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD);
3941aaeb53aSjjbg tdb_delete(tdb);
395448c5f3fSbluhm error = EINVAL;
396448c5f3fSbluhm goto drop;
3971aaeb53aSjjbg }
39859b9936bSbluhm
3991aaeb53aSjjbg /* Soft byte expiration */
40059b9936bSbluhm mtx_enter(&tdb->tdb_mtx);
4011aaeb53aSjjbg if ((tdb->tdb_flags & TDBF_SOFT_BYTES) &&
4021aaeb53aSjjbg (tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes)) {
4031aaeb53aSjjbg tdb->tdb_flags &= ~TDBF_SOFT_BYTES; /* Turn off checking */
40459b9936bSbluhm mtx_leave(&tdb->tdb_mtx);
40559b9936bSbluhm /* may sleep in solock() for the pfkey socket */
40659b9936bSbluhm pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT);
40759b9936bSbluhm } else
40859b9936bSbluhm mtx_leave(&tdb->tdb_mtx);
40959b9936bSbluhm
4101aaeb53aSjjbg /*
41138d7d608Smarkus * Loop through mbuf chain; if we find a readonly mbuf,
4122be2e590Sdlg * copy the packet.
4131aaeb53aSjjbg */
4141aaeb53aSjjbg mi = m;
4152be2e590Sdlg while (mi != NULL && !M_READONLY(mi))
4161aaeb53aSjjbg mi = mi->m_next;
4171aaeb53aSjjbg
4181aaeb53aSjjbg if (mi != NULL) {
4192be2e590Sdlg struct mbuf *n = m_dup_pkt(m, 0, M_DONTWAIT);
4201aaeb53aSjjbg
4211aaeb53aSjjbg if (n == NULL) {
422698a75ddSbluhm DPRINTF("bad mbuf chain, IPCA %s/%08x",
4233514aacbSmikeb ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
424698a75ddSbluhm ntohl(tdb->tdb_spi));
4256460338bSvisa ipcompstat_inc(ipcomps_hdrops);
426448c5f3fSbluhm error = ENOBUFS;
427448c5f3fSbluhm goto drop;
4281aaeb53aSjjbg }
4291aaeb53aSjjbg
4302be2e590Sdlg m_freem(m);
4312be2e590Sdlg m = n;
4321aaeb53aSjjbg }
4331aaeb53aSjjbg /* Ok now, we can pass to the crypto processing */
4341aaeb53aSjjbg
4351aaeb53aSjjbg /* Get crypto descriptors */
4361aaeb53aSjjbg crp = crypto_getreq(1);
4371aaeb53aSjjbg if (crp == NULL) {
438698a75ddSbluhm DPRINTF("failed to acquire crypto descriptors");
4396460338bSvisa ipcompstat_inc(ipcomps_crypto);
440448c5f3fSbluhm error = ENOBUFS;
441448c5f3fSbluhm goto drop;
4421aaeb53aSjjbg }
443e410e70dSpatrick crdc = &crp->crp_desc[0];
4441aaeb53aSjjbg
4451aaeb53aSjjbg /* Compression descriptor */
4468ba4ecc8Smarkus crdc->crd_skip = skip;
4478ba4ecc8Smarkus crdc->crd_len = m->m_pkthdr.len - skip;
4481aaeb53aSjjbg crdc->crd_flags = CRD_F_COMP;
4498ba4ecc8Smarkus crdc->crd_inject = skip;
4501aaeb53aSjjbg
4511aaeb53aSjjbg /* Compression operation */
4521aaeb53aSjjbg crdc->crd_alg = ipcompx->type;
4531aaeb53aSjjbg
4541aaeb53aSjjbg /* Crypto operation descriptor */
4551aaeb53aSjjbg crp->crp_ilen = m->m_pkthdr.len; /* Total input length */
456*fb8de0f1Sclaudio crp->crp_flags = CRYPTO_F_IMBUF;
4571aaeb53aSjjbg crp->crp_buf = (caddr_t)m;
4581aaeb53aSjjbg crp->crp_sid = tdb->tdb_cryptoid;
4591aaeb53aSjjbg
46087edded1Stobhe while ((error = crypto_invoke(crp)) == EAGAIN) {
46112758001Stobhe /* Reset the session ID */
46212758001Stobhe if (tdb->tdb_cryptoid != 0)
46312758001Stobhe tdb->tdb_cryptoid = crp->crp_sid;
46412758001Stobhe }
46587edded1Stobhe if (error) {
46687edded1Stobhe DPRINTF("crypto error %d", error);
46712758001Stobhe ipsecstat_inc(ipsec_noxform);
4684f56c6f5Stobhe goto drop;
46912758001Stobhe }
47012758001Stobhe
47112758001Stobhe ilen = crp->crp_ilen;
47212758001Stobhe olen = crp->crp_olen;
47312758001Stobhe
47412758001Stobhe /* Release the crypto descriptors */
47512758001Stobhe crypto_freereq(crp);
4764f56c6f5Stobhe crp = NULL;
47712758001Stobhe
4787ced204eSmpi rlen = ilen - skip;
479e53dc863Sangelos
480a4f90811Sangelos /* Check sizes. */
4814b5fa55eSmpi if (rlen <= olen + IPCOMP_HLENGTH) {
482a4f90811Sangelos /* Compression was useless, we have lost time. */
483448c5f3fSbluhm ipcompstat_inc(ipcomps_minlen); /* misnomer, but like to count */
4847ced204eSmpi goto skiphdr;
4851aaeb53aSjjbg }
4861aaeb53aSjjbg
4878ba4ecc8Smarkus /* Inject IPCOMP header */
4885db30710Smarkus mo = m_makespace(m, skip, IPCOMP_HLENGTH, &roff);
4898ba4ecc8Smarkus if (mo == NULL) {
490698a75ddSbluhm DPRINTF("ailed to inject IPCOMP header for IPCA %s/%08x",
491698a75ddSbluhm ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
492698a75ddSbluhm ntohl(tdb->tdb_spi));
4936460338bSvisa ipcompstat_inc(ipcomps_wrap);
494bc489a1cSbluhm error = ENOBUFS;
495bc489a1cSbluhm goto drop;
4968ba4ecc8Smarkus }
4978ba4ecc8Smarkus
4988ba4ecc8Smarkus /* Initialize the IPCOMP header */
4995db30710Smarkus ipcomp = (struct ipcomp *)(mtod(mo, caddr_t) + roff);
500f8575965Stedu memset(ipcomp, 0, sizeof(struct ipcomp));
5018ba4ecc8Smarkus cpi = (u_int16_t) ntohl(tdb->tdb_spi);
5028ba4ecc8Smarkus ipcomp->ipcomp_cpi = htons(cpi);
5038ba4ecc8Smarkus
5048ba4ecc8Smarkus /* m_pullup before ? */
5051aaeb53aSjjbg switch (tdb->tdb_dst.sa.sa_family) {
5061aaeb53aSjjbg case AF_INET:
5071aaeb53aSjjbg ip = mtod(m, struct ip *);
5088ba4ecc8Smarkus ipcomp->ipcomp_nh = ip->ip_p;
5098ba4ecc8Smarkus ip->ip_p = IPPROTO_IPCOMP;
5101aaeb53aSjjbg break;
5111aaeb53aSjjbg #ifdef INET6
5121aaeb53aSjjbg case AF_INET6:
5131aaeb53aSjjbg ip6 = mtod(m, struct ip6_hdr *);
5148ba4ecc8Smarkus ipcomp->ipcomp_nh = ip6->ip6_nxt;
5158ba4ecc8Smarkus ip6->ip6_nxt = IPPROTO_IPCOMP;
5161aaeb53aSjjbg break;
5178ba4ecc8Smarkus #endif
5181aaeb53aSjjbg default:
519698a75ddSbluhm DPRINTF("unsupported protocol family %d, IPCA %s/%08x",
520698a75ddSbluhm tdb->tdb_dst.sa.sa_family,
5213514aacbSmikeb ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
522698a75ddSbluhm ntohl(tdb->tdb_spi));
5236460338bSvisa ipcompstat_inc(ipcomps_nopf);
524bc489a1cSbluhm error = EPFNOSUPPORT;
525bc489a1cSbluhm goto drop;
5261aaeb53aSjjbg }
5271aaeb53aSjjbg
5287ced204eSmpi skiphdr:
529bc489a1cSbluhm error = ipsp_process_done(m, tdb);
530bc489a1cSbluhm if (error)
5316460338bSvisa ipcompstat_inc(ipcomps_outfail);
532bc489a1cSbluhm return error;
5331aaeb53aSjjbg
534bc489a1cSbluhm drop:
5351aaeb53aSjjbg m_freem(m);
5364f56c6f5Stobhe crypto_freereq(crp);
537bc489a1cSbluhm return error;
5381aaeb53aSjjbg }
539