No empty .Rs/.Re
[netbsd-mini2440.git] / sys / netinet6 / ipcomp_input.c
blob57c2d8655763f8279cfebc7854dd03f9b389782b
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 $ */
4 /*
5 * Copyright (C) 1999 WIDE Project.
6 * All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
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
30 * SUCH DAMAGE.
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 $");
40 #include "opt_inet.h"
41 #include "opt_ipsec.h"
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/malloc.h>
46 #include <sys/mbuf.h>
47 #include <sys/domain.h>
48 #include <sys/protosw.h>
49 #include <sys/socket.h>
50 #include <sys/errno.h>
51 #include <sys/time.h>
52 #include <sys/kernel.h>
53 #include <sys/syslog.h>
55 #include <net/if.h>
56 #include <net/route.h>
57 #include <net/netisr.h>
58 #include <net/zlib.h>
59 #include <sys/cpu.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>
69 #ifdef INET6
70 #include <netinet/ip6.h>
71 #include <netinet6/ip6_var.h>
72 #endif
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*/
86 #ifdef INET
87 void
88 ipcomp4_init(void)
91 ipsec4_init();
94 void
95 #if __STDC__
96 ipcomp4_input(struct mbuf *m, ...)
97 #else
98 ipcomp4_input(m, va_alist)
99 struct mbuf *m;
100 va_dcl
101 #endif
103 struct mbuf *md;
104 struct ip *ip;
105 struct ipcomp *ipcomp;
106 const struct ipcomp_algorithm *algo;
107 u_int16_t cpi; /* host order */
108 u_int16_t nxt;
109 size_t hlen;
110 int error;
111 size_t newlen, olen;
112 struct secasvar *sav = NULL;
113 int off, proto;
114 va_list ap;
115 u_int16_t sport = 0;
116 u_int16_t dport = 0;
117 #ifdef IPSEC_NAT_T
118 struct m_tag *tag = NULL;
119 #endif
121 va_start(ap, m);
122 off = va_arg(ap, int);
123 proto = va_arg(ap, int);
124 va_end(ap);
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);
130 goto fail;
132 #ifdef IPSEC_NAT_T
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];
138 #endif
140 md = m_pulldown(m, off, sizeof(*ipcomp), NULL);
141 if (!md) {
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);
146 goto fail;
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),
158 sport, dport);
159 if (sav != NULL &&
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);
167 if (!algo) {
168 ipseclog((LOG_WARNING, "IPv4 IPComp input: unknown cpi %u\n",
169 cpi));
170 IPSEC_STATINC(IPSEC_STAT_IN_NOSA);
171 goto fail;
174 /* chop ipcomp header */
175 ipcomp = NULL;
176 md->m_data += sizeof(struct ipcomp);
177 md->m_len -= sizeof(struct ipcomp);
178 m->m_pkthdr.len -= sizeof(struct ipcomp);
179 #ifdef IPLEN_FLIPPED
180 ip->ip_len -= sizeof(struct ipcomp);
181 #else
182 ip->ip_len = htons(ntohs(ip->ip_len) - sizeof(struct ipcomp));
183 #endif
185 olen = m->m_pkthdr.len;
186 newlen = m->m_pkthdr.len - off;
187 error = (*algo->decompress)(m, m->m_next, &newlen);
188 if (error != 0) {
189 if (error == EINVAL)
190 IPSEC_STATINC(IPSEC_STAT_IN_INVAL);
191 else if (error == ENOBUFS)
192 IPSEC_STATINC(IPSEC_STAT_IN_NOMEM);
193 m = NULL;
194 goto fail;
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 *);
207 size_t len;
208 #ifdef IPLEN_FLIPPED
209 len = ip->ip_len;
210 #else
211 len = ntohs(ip->ip_len);
212 #endif
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;
218 len -= olen;
219 if (len & ~0xffff) {
220 /* packet too big after decompress */
221 IPSEC_STATINC(IPSEC_STAT_IN_INVAL);
222 goto fail;
224 #ifdef IPLEN_FLIPPED
225 ip->ip_len = len & 0xffff;
226 #else
227 ip->ip_len = htons(len & 0xffff);
228 #endif
229 ip->ip_p = nxt;
232 if (sav) {
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);
236 goto fail;
238 key_freesav(sav);
239 sav = NULL;
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);
246 goto fail;
248 (*inetsw[ip_protox[nxt]].pr_input)(m, off, nxt);
249 } else
250 m_freem(m);
251 m = NULL;
253 IPSEC_STATINC(IPSEC_STAT_IN_SUCCESS);
254 return;
256 fail:
257 if (sav)
258 key_freesav(sav);
259 if (m)
260 m_freem(m);
261 return;
263 #endif /* INET */
265 #ifdef INET6
266 void
267 ipcomp6_init(void)
270 ipsec6_init();
274 ipcomp6_input(struct mbuf **mp, int *offp, int proto)
276 struct mbuf *m, *md;
277 int off;
278 struct ip6_hdr *ip6;
279 struct ipcomp *ipcomp;
280 const struct ipcomp_algorithm *algo;
281 u_int16_t cpi; /* host order */
282 u_int16_t nxt;
283 int error;
284 size_t newlen;
285 struct secasvar *sav = NULL;
286 u_int8_t *prvnxtp;
288 m = *mp;
289 off = *offp;
291 md = m_pulldown(m, off, sizeof(*ipcomp), NULL);
292 if (!md) {
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);
297 goto fail;
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,
308 htonl(cpi), 0, 0);
309 if (sav != NULL &&
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);
317 if (!algo) {
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);
321 goto fail;
324 /* chop ipcomp header */
325 ipcomp = NULL;
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);
332 if (error != 0) {
333 if (error == EINVAL)
334 IPSEC6_STATINC(IPSEC_STAT_IN_INVAL);
335 else if (error == ENOBUFS)
336 IPSEC6_STATINC(IPSEC_STAT_IN_NOMEM);
337 m = NULL;
338 goto fail;
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);
351 *prvnxtp = nxt;
354 * no need to adjust payload length, as all the IPv6 protocols
355 * look at m->m_pkthdr.len
358 if (sav) {
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);
362 goto fail;
364 key_freesav(sav);
365 sav = NULL;
367 *offp = off;
368 *mp = m;
369 IPSEC6_STATINC(IPSEC_STAT_IN_SUCCESS);
370 return nxt;
372 fail:
373 if (m)
374 m_freem(m);
375 if (sav)
376 key_freesav(sav);
377 return IPPROTO_DONE;
379 #endif /* INET6 */