1 /* $NetBSD: ipcomp_input.c,v 1.35 2008/05/04 23:07:09 ad Exp $ */
2 /* $KAME: ipcomp_input.c,v 1.29 2001/09/04 08:43:19 itojun Exp $ */
5 * Copyright (C) 1999 WIDE Project.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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. Neither the name of the project nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * RFC2393 IP payload compression protocol (IPComp).
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: ipcomp_input.c,v 1.34 2008/04/23 06:09:05 thorpej Exp $");
41 #include "opt_ipsec.h"
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/malloc.h>
47 #include <sys/domain.h>
48 #include <sys/protosw.h>
49 #include <sys/socket.h>
50 #include <sys/errno.h>
52 #include <sys/kernel.h>
53 #include <sys/syslog.h>
56 #include <net/route.h>
57 #include <net/netisr.h>
61 #include <netinet/in.h>
62 #include <netinet/in_systm.h>
63 #include <netinet/in_var.h>
64 #include <netinet/in_proto.h>
65 #include <netinet/ip.h>
66 #include <netinet/ip_var.h>
67 #include <netinet/ip_ecn.h>
70 #include <netinet/ip6.h>
71 #include <netinet6/ip6_var.h>
73 #include <netinet6/ipcomp.h>
75 #include <netinet6/ipsec.h>
76 #include <netinet6/ipsec_private.h>
77 #include <netkey/key.h>
78 #include <netkey/keydb.h>
80 #include <machine/stdarg.h>
82 #include <net/net_osdep.h>
84 /*#define IPLEN_FLIPPED*/
96 ipcomp4_input(struct mbuf
*m
, ...)
98 ipcomp4_input(m
, va_alist
)
105 struct ipcomp
*ipcomp
;
106 const struct ipcomp_algorithm
*algo
;
107 u_int16_t cpi
; /* host order */
112 struct secasvar
*sav
= NULL
;
118 struct m_tag
*tag
= NULL
;
122 off
= va_arg(ap
, int);
123 proto
= va_arg(ap
, int);
126 if (m
->m_pkthdr
.len
< off
+ sizeof(struct ipcomp
)) {
127 ipseclog((LOG_DEBUG
, "IPv4 IPComp input: assumption failed "
128 "(packet too short)\n"));
129 IPSEC_STATINC(IPSEC_STAT_IN_INVAL
);
133 /* find the source port for NAT-T */
134 if ((tag
= m_tag_find(m
, PACKET_TAG_IPSEC_NAT_T_PORTS
, NULL
)) != NULL
) {
135 sport
= ((u_int16_t
*)(tag
+ 1))[0];
136 dport
= ((u_int16_t
*)(tag
+ 1))[1];
140 md
= m_pulldown(m
, off
, sizeof(*ipcomp
), NULL
);
142 m
= NULL
; /* already freed */
143 ipseclog((LOG_DEBUG
, "IPv4 IPComp input: assumption failed "
144 "(pulldown failure)\n"));
145 IPSEC_STATINC(IPSEC_STAT_IN_INVAL
);
148 ipcomp
= mtod(md
, struct ipcomp
*);
149 ip
= mtod(m
, struct ip
*);
150 nxt
= ipcomp
->comp_nxt
;
151 hlen
= ip
->ip_hl
<< 2;
153 cpi
= ntohs(ipcomp
->comp_cpi
);
155 if (cpi
>= IPCOMP_CPI_NEGOTIATE_MIN
) {
156 sav
= key_allocsa(AF_INET
, (void *)&ip
->ip_src
,
157 (void *)&ip
->ip_dst
, IPPROTO_IPCOMP
, htonl(cpi
),
160 (sav
->state
== SADB_SASTATE_MATURE
||
161 sav
->state
== SADB_SASTATE_DYING
)) {
162 cpi
= sav
->alg_enc
; /* XXX */
163 /* other parameters to look at? */
166 algo
= ipcomp_algorithm_lookup(cpi
);
168 ipseclog((LOG_WARNING
, "IPv4 IPComp input: unknown cpi %u\n",
170 IPSEC_STATINC(IPSEC_STAT_IN_NOSA
);
174 /* chop ipcomp header */
176 md
->m_data
+= sizeof(struct ipcomp
);
177 md
->m_len
-= sizeof(struct ipcomp
);
178 m
->m_pkthdr
.len
-= sizeof(struct ipcomp
);
180 ip
->ip_len
-= sizeof(struct ipcomp
);
182 ip
->ip_len
= htons(ntohs(ip
->ip_len
) - sizeof(struct ipcomp
));
185 olen
= m
->m_pkthdr
.len
;
186 newlen
= m
->m_pkthdr
.len
- off
;
187 error
= (*algo
->decompress
)(m
, m
->m_next
, &newlen
);
190 IPSEC_STATINC(IPSEC_STAT_IN_INVAL
);
191 else if (error
== ENOBUFS
)
192 IPSEC_STATINC(IPSEC_STAT_IN_NOMEM
);
196 IPSEC_STATINC(IPSEC_STAT_IN_COMPHIST
+ cpi
);
199 * returning decompressed packet onto icmp is meaningless.
200 * mark it decrypted to prevent icmp from attaching original packet.
202 m
->m_flags
|= M_DECRYPTED
;
204 m
->m_pkthdr
.len
= off
+ newlen
;
205 ip
= mtod(m
, struct ip
*);
211 len
= ntohs(ip
->ip_len
);
214 * be careful about underflow. also, do not assign exact value
215 * as ip_len is manipulated differently on *BSDs.
217 len
+= m
->m_pkthdr
.len
;
220 /* packet too big after decompress */
221 IPSEC_STATINC(IPSEC_STAT_IN_INVAL
);
225 ip
->ip_len
= len
& 0xffff;
227 ip
->ip_len
= htons(len
& 0xffff);
233 key_sa_recordxfer(sav
, m
);
234 if (ipsec_addhist(m
, IPPROTO_IPCOMP
, (u_int32_t
)cpi
) != 0) {
235 IPSEC_STATINC(IPSEC_STAT_IN_NOMEM
);
242 if (nxt
!= IPPROTO_DONE
) {
243 if ((inetsw
[ip_protox
[nxt
]].pr_flags
& PR_LASTHDR
) != 0 &&
244 ipsec4_in_reject(m
, NULL
)) {
245 IPSEC_STATINC(IPSEC_STAT_IN_POLVIO
);
248 (*inetsw
[ip_protox
[nxt
]].pr_input
)(m
, off
, nxt
);
253 IPSEC_STATINC(IPSEC_STAT_IN_SUCCESS
);
274 ipcomp6_input(struct mbuf
**mp
, int *offp
, int proto
)
279 struct ipcomp
*ipcomp
;
280 const struct ipcomp_algorithm
*algo
;
281 u_int16_t cpi
; /* host order */
285 struct secasvar
*sav
= NULL
;
291 md
= m_pulldown(m
, off
, sizeof(*ipcomp
), NULL
);
293 m
= NULL
; /* already freed */
294 ipseclog((LOG_DEBUG
, "IPv6 IPComp input: assumption failed "
295 "(pulldown failure)\n"));
296 IPSEC6_STATINC(IPSEC_STAT_IN_INVAL
);
299 ipcomp
= mtod(md
, struct ipcomp
*);
300 ip6
= mtod(m
, struct ip6_hdr
*);
301 nxt
= ipcomp
->comp_nxt
;
303 cpi
= ntohs(ipcomp
->comp_cpi
);
305 if (cpi
>= IPCOMP_CPI_NEGOTIATE_MIN
) {
306 sav
= key_allocsa(AF_INET6
, (void *)&ip6
->ip6_src
,
307 (void *)&ip6
->ip6_dst
, IPPROTO_IPCOMP
,
310 (sav
->state
== SADB_SASTATE_MATURE
||
311 sav
->state
== SADB_SASTATE_DYING
)) {
312 cpi
= sav
->alg_enc
; /* XXX */
313 /* other parameters to look at? */
316 algo
= ipcomp_algorithm_lookup(cpi
);
318 ipseclog((LOG_WARNING
, "IPv6 IPComp input: unknown cpi %u; "
319 "dropping the packet for simplicity\n", cpi
));
320 IPSEC6_STATINC(IPSEC_STAT_IN_NOSA
);
324 /* chop ipcomp header */
326 md
->m_data
+= sizeof(struct ipcomp
);
327 md
->m_len
-= sizeof(struct ipcomp
);
328 m
->m_pkthdr
.len
-= sizeof(struct ipcomp
);
330 newlen
= m
->m_pkthdr
.len
- off
;
331 error
= (*algo
->decompress
)(m
, md
, &newlen
);
334 IPSEC6_STATINC(IPSEC_STAT_IN_INVAL
);
335 else if (error
== ENOBUFS
)
336 IPSEC6_STATINC(IPSEC_STAT_IN_NOMEM
);
340 IPSEC6_STATINC(IPSEC_STAT_IN_COMPHIST
+ cpi
);
341 m
->m_pkthdr
.len
= off
+ newlen
;
344 * returning decompressed packet onto icmp is meaningless.
345 * mark it decrypted to prevent icmp from attaching original packet.
347 m
->m_flags
|= M_DECRYPTED
;
349 /* update next header field */
350 prvnxtp
= ip6_get_prevhdr(m
, off
);
354 * no need to adjust payload length, as all the IPv6 protocols
355 * look at m->m_pkthdr.len
359 key_sa_recordxfer(sav
, m
);
360 if (ipsec_addhist(m
, IPPROTO_IPCOMP
, (u_int32_t
)cpi
) != 0) {
361 IPSEC6_STATINC(IPSEC_STAT_IN_NOMEM
);
369 IPSEC6_STATINC(IPSEC_STAT_IN_SUCCESS
);