]>
git.saurik.com Git - apple/xnu.git/blob - bsd/netinet6/ipcomp_input.c
43039d9c7ec00637cae16123e15c7bca005f06af
1 /* $KAME: ipcomp_input.c,v 1.11 2000/02/22 14:04:23 itojun Exp $ */
4 * Copyright (C) 1999 WIDE Project.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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. Neither the name of the project nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * RFC2393 IP payload compression protocol (IPComp).
37 #if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__)
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/malloc.h>
45 #include <sys/domain.h>
46 #include <sys/protosw.h>
47 #include <sys/socket.h>
48 #include <sys/errno.h>
50 #include <sys/kernel.h>
51 #include <sys/syslog.h>
54 #include <net/route.h>
55 #include <net/netisr.h>
57 #include <kern/cpu_number.h>
59 #include <netinet/in.h>
60 #include <netinet/in_systm.h>
61 #include <netinet/in_var.h>
62 #include <netinet/ip.h>
63 #include <netinet/ip_var.h>
64 #include <netinet/ip_ecn.h>
67 #include <netinet/ip6.h>
68 #include <netinet6/ip6_var.h>
70 #include <netinet6/ipcomp.h>
72 #include <netinet6/ipsec.h>
73 #include <netkey/key.h>
74 #include <netkey/keydb.h>
75 #include <netkey/key_debug.h>
77 #include <net/net_osdep.h>
83 extern struct protosw
* ip_protox
[];
84 #if defined(__bsdi__) || defined(__NetBSD__)
85 extern u_char ip_protox
[];
89 ipcomp4_input(struct mbuf
*m
, int off
)
92 struct ipcomp
*ipcomp
;
93 struct ipcomp_algorithm
*algo
;
94 u_int16_t cpi
; /* host order */
99 struct secasvar
*sav
= NULL
;
102 if (off
+ sizeof(struct ipcomp
) > MHLEN
) {
103 /*XXX the restriction should be relaxed*/
104 ipseclog((LOG_DEBUG
, "IPv4 IPComp input: assumption failed "
105 "(header too long)\n"));
106 ipsecstat
.in_inval
++;
109 if (m
->m_len
< off
+ sizeof(struct ipcomp
)) {
110 m
= m_pullup(m
, off
+ sizeof(struct ipcomp
));
112 ipseclog((LOG_DEBUG
, "IPv4 IPComp input: can't pullup;"
113 "dropping the packet for simplicity\n"));
114 ipsecstat
.in_nomem
++;
117 } else if (m
->m_len
> off
+ sizeof(struct ipcomp
)) {
118 /* chop header part from the packet header chain */
120 MGETHDR(n
, M_DONTWAIT
, MT_HEADER
);
122 ipsecstat
.in_nomem
++;
126 MH_ALIGN(n
, off
+ sizeof(struct ipcomp
));
127 n
->m_len
= off
+ sizeof(struct ipcomp
);
128 bcopy(mtod(m
, caddr_t
), mtod(n
, caddr_t
),
129 off
+ sizeof(struct ipcomp
));
130 m_adj(m
, off
+ sizeof(struct ipcomp
));
131 m
->m_flags
&= ~M_PKTHDR
;
136 ip
= mtod(m
, struct ip
*);
137 ipcomp
= (struct ipcomp
*)(((caddr_t
)ip
) + off
);
138 nxt
= ipcomp
->comp_nxt
;
140 hlen
= IP_VHL_HL(ip
->ip_vhl
) << 2;
142 hlen
= ip
->ip_hl
<< 2;
145 cpi
= ntohs(ipcomp
->comp_cpi
);
147 if (cpi
>= IPCOMP_CPI_NEGOTIATE_MIN
) {
148 sav
= key_allocsa(AF_INET
, (caddr_t
)&ip
->ip_src
,
149 (caddr_t
)&ip
->ip_dst
, IPPROTO_IPCOMP
, htonl(cpi
));
151 && (sav
->state
== SADB_SASTATE_MATURE
152 || sav
->state
== SADB_SASTATE_DYING
)) {
153 cpi
= sav
->alg_enc
; /*XXX*/
154 /* other parameters to look at? */
157 if (cpi
< IPCOMP_MAX
&& ipcomp_algorithms
[cpi
].decompress
!= NULL
)
158 algo
= &ipcomp_algorithms
[cpi
];
162 ipseclog((LOG_WARNING
, "IPv4 IPComp input: unknown cpi %u\n",
168 /* chop ipcomp header */
170 m
->m_len
-= sizeof(struct ipcomp
);
171 m
->m_pkthdr
.len
-= sizeof(struct ipcomp
);
173 ip
->ip_len
-= sizeof(struct ipcomp
);
175 ip
->ip_len
= htons(ntohs(ip
->ip_len
) - sizeof(struct ipcomp
));
178 olen
= m
->m_pkthdr
.len
;
179 newlen
= m
->m_pkthdr
.len
- off
;
180 error
= (*algo
->decompress
)(m
, m
->m_next
, &newlen
);
183 ipsecstat
.in_inval
++;
184 else if (error
== ENOBUFS
)
185 ipsecstat
.in_nomem
++;
189 ipsecstat
.in_comphist
[cpi
]++;
192 * returning decompressed packet onto icmp is meaningless.
193 * mark it decrypted to prevent icmp from attaching original packet.
195 m
->m_flags
|= M_DECRYPTED
;
197 m
->m_pkthdr
.len
= off
+ newlen
;
198 ip
= mtod(m
, struct ip
*);
204 len
= ntohs(ip
->ip_len
);
207 * be careful about underflow. also, do not assign exact value
208 * as ip_len is manipulated differently on *BSDs.
210 len
+= m
->m_pkthdr
.len
;
213 /* packet too big after decompress */
214 ipsecstat
.in_inval
++;
218 ip
->ip_len
= len
& 0xffff;
220 ip
->ip_len
= htons(len
& 0xffff);
226 key_sa_recordxfer(sav
, m
);
231 if (nxt
!= IPPROTO_DONE
)
232 (*ip_protox
[nxt
]->pr_input
)(m
, off
);
237 ipsecstat
.in_success
++;
251 ipcomp6_input(mp
, offp
)
258 struct mbuf
*ipcompm
;
259 struct ipcomp
*ipcomp
;
260 struct ipcomp_algorithm
*algo
;
261 u_int16_t cpi
; /* host order */
265 struct secasvar
*sav
= NULL
;
270 IP6_EXTHDR_CHECK(m
, off
, sizeof(struct ipcomp
), IPPROTO_DONE
);
279 for (n
= m
; n
&& skip
> 0; n
= n
->m_next
) {
280 if (n
->m_len
<= skip
) {
287 ipseclog((LOG_DEBUG
, "IPv6 IPComp input: wrong mbuf chain\n"));
288 ipsecstat
.in_inval
++;
291 if (n
->m_len
< skip
+ sizeof(struct ipcomp
)) {
292 ipseclog((LOG_DEBUG
, "IPv6 IPComp input: wrong mbuf chain\n"));
293 ipsecstat
.in_inval
++;
296 ip6
= mtod(m
, struct ip6_hdr
*);
298 ipcomp
= (struct ipcomp
*)(mtod(n
, caddr_t
) + skip
);
299 if (n
->m_len
> skip
+ sizeof(struct ipcomp
)) {
300 /* split mbuf to ease the following steps*/
301 l
= n
->m_len
- (skip
+ sizeof(struct ipcomp
));
302 p
= m_copym(n
, skip
+ sizeof(struct ipcomp
), l
, M_DONTWAIT
);
304 ipsecstat
.in_nomem
++;
307 for (q
= p
; q
&& q
->m_next
; q
= q
->m_next
)
309 q
->m_next
= n
->m_next
;
317 nxt
= ipcomp
->comp_nxt
;
318 cpi
= ntohs(ipcomp
->comp_cpi
);
320 if (cpi
>= IPCOMP_CPI_NEGOTIATE_MIN
) {
321 sav
= key_allocsa(AF_INET6
, (caddr_t
)&ip6
->ip6_src
,
322 (caddr_t
)&ip6
->ip6_dst
, IPPROTO_IPCOMP
, htonl(cpi
));
324 && (sav
->state
== SADB_SASTATE_MATURE
325 || sav
->state
== SADB_SASTATE_DYING
)) {
326 cpi
= sav
->alg_enc
; /*XXX*/
327 /* other parameters to look at? */
330 if (cpi
< IPCOMP_MAX
&& ipcomp_algorithms
[cpi
].decompress
!= NULL
)
331 algo
= &ipcomp_algorithms
[cpi
];
335 ipseclog((LOG_WARNING
, "IPv6 IPComp input: unknown cpi %u; "
336 "dropping the packet for simplicity\n", cpi
));
337 ipsec6stat
.in_nosa
++;
341 newlen
= m
->m_pkthdr
.len
- off
- sizeof(struct ipcomp
);
342 error
= (*algo
->decompress
)(m
, md
, &newlen
);
345 ipsec6stat
.in_inval
++;
346 else if (error
== ENOBUFS
)
347 ipsec6stat
.in_nomem
++;
351 ipsec6stat
.in_comphist
[cpi
]++;
352 m
->m_pkthdr
.len
= off
+ sizeof(struct ipcomp
) + newlen
;
355 * returning decompressed packet onto icmp is meaningless.
356 * mark it decrypted to prevent icmp from attaching original packet.
358 m
->m_flags
|= M_DECRYPTED
;
363 /* chop IPComp header */
364 prvnxtp
= ip6_get_prevhdr(m
, off
);
366 ipcompm
->m_len
-= sizeof(struct ipcomp
);
367 ipcompm
->m_pkthdr
.len
-= sizeof(struct ipcomp
);
369 /* adjust payload length */
370 ip6
= mtod(m
, struct ip6_hdr
*);
371 if (((m
->m_pkthdr
.len
- sizeof(struct ip6_hdr
)) & ~0xffff) != 0)
372 ip6
->ip6_plen
= 0; /*now a jumbogram*/
374 ip6
->ip6_plen
= htons(m
->m_pkthdr
.len
- sizeof(struct ip6_hdr
));
378 key_sa_recordxfer(sav
, m
);
384 ipsec6stat
.in_success
++;