ac(8): Staticize and raise WARNS to 6.
[dragonfly.git] / sys / netinet6 / ipcomp_output.c
blob44d29d4e3e3f970417f89c7040f414e74a4bd8b8
1 /* $FreeBSD: src/sys/netinet6/ipcomp_output.c,v 1.1.2.4 2003/04/29 08:33:50 suz Exp $ */
2 /* $KAME: ipcomp_output.c,v 1.25 2002/06/09 14:44:00 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 "opt_inet.h"
38 #include "opt_inet6.h"
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/malloc.h>
43 #include <sys/mbuf.h>
44 #include <sys/domain.h>
45 #include <sys/protosw.h>
46 #include <sys/socket.h>
47 #include <sys/errno.h>
48 #include <sys/time.h>
49 #include <sys/syslog.h>
51 #include <net/if.h>
52 #include <net/route.h>
53 #include <net/netisr.h>
54 #include <machine/cpu.h>
56 #include <netinet/in.h>
57 #include <netinet/in_systm.h>
58 #include <netinet/in_var.h>
59 #include <netinet/ip.h>
60 #include <netinet/ip_var.h>
61 #include <netinet/ip_ecn.h>
63 #ifdef INET6
64 #include <netinet/ip6.h>
65 #include <netinet6/ip6_var.h>
66 #endif
67 #include <netinet6/ipcomp.h>
68 #ifdef INET6
69 #include <netinet6/ipcomp6.h>
70 #endif
72 #include <netinet6/ipsec.h>
73 #ifdef INET6
74 #include <netinet6/ipsec6.h>
75 #endif
76 #include <netproto/key/key.h>
77 #include <netproto/key/keydb.h>
79 #include <machine/stdarg.h>
81 #include <net/net_osdep.h>
83 static int ipcomp_output (struct mbuf *, u_char *, struct mbuf *,
84 struct ipsecrequest *, int);
87 * Modify the packet so that the payload is compressed.
88 * The mbuf (m) must start with IPv4 or IPv6 header.
89 * On failure, free the given mbuf and return non-zero.
91 * on invocation:
92 * m nexthdrp md
93 * v v v
94 * IP ......... payload
95 * during the encryption:
96 * m nexthdrp mprev md
97 * v v v v
98 * IP ............... ipcomp payload
99 * <-----><----->
100 * complen plen
101 * <-> hlen
102 * <-----------------> compoff
104 static int
105 ipcomp_output(struct mbuf *m, u_char *nexthdrp, struct mbuf *md,
106 struct ipsecrequest *isr, int af)
108 struct mbuf *n;
109 struct mbuf *md0;
110 struct mbuf *mcopy;
111 struct mbuf *mprev;
112 struct ipcomp *ipcomp;
113 struct secasvar *sav = isr->sav;
114 const struct ipcomp_algorithm *algo;
115 u_int16_t cpi; /* host order */
116 size_t plen0, plen; /* payload length to be compressed */
117 size_t compoff;
118 int afnumber;
119 int error = 0;
120 struct ipsecstat *stat;
122 switch (af) {
123 #ifdef INET
124 case AF_INET:
125 afnumber = 4;
126 stat = &ipsecstat;
127 break;
128 #endif
129 #ifdef INET6
130 case AF_INET6:
131 afnumber = 6;
132 stat = &ipsec6stat;
133 break;
134 #endif
135 default:
136 ipseclog((LOG_ERR, "ipcomp_output: unsupported af %d\n", af));
137 return 0; /* no change at all */
140 /* grab parameters */
141 algo = ipcomp_algorithm_lookup(sav->alg_enc);
142 if ((ntohl(sav->spi) & ~0xffff) != 0 || !algo) {
143 stat->out_inval++;
144 m_freem(m);
145 return EINVAL;
147 if ((sav->flags & SADB_X_EXT_RAWCPI) == 0)
148 cpi = sav->alg_enc;
149 else
150 cpi = ntohl(sav->spi) & 0xffff;
152 /* compute original payload length */
153 plen = 0;
154 for (n = md; n; n = n->m_next)
155 plen += n->m_len;
157 /* if the payload is short enough, we don't need to compress */
158 if (plen < algo->minplen)
159 return 0;
162 * retain the original packet for two purposes:
163 * (1) we need to backout our changes when compression is not necessary.
164 * (2) byte lifetime computation should use the original packet.
165 * see RFC2401 page 23.
166 * compromise two m_copym(). we will be going through every byte of
167 * the payload during compression process anyways.
169 mcopy = m_copym(m, 0, M_COPYALL, M_NOWAIT);
170 if (mcopy == NULL) {
171 error = ENOBUFS;
172 return 0;
174 md0 = m_copym(md, 0, M_COPYALL, M_NOWAIT);
175 if (md0 == NULL) {
176 m_freem(mcopy);
177 error = ENOBUFS;
178 return 0;
180 plen0 = plen;
182 /* make the packet over-writable */
183 for (mprev = m; mprev && mprev->m_next != md; mprev = mprev->m_next)
185 if (mprev == NULL || mprev->m_next != md) {
186 ipseclog((LOG_DEBUG, "ipcomp%d_output: md is not in chain\n",
187 afnumber));
188 stat->out_inval++;
189 m_freem(m);
190 m_freem(md0);
191 m_freem(mcopy);
192 return EINVAL;
194 mprev->m_next = NULL;
195 if ((md = ipsec_copypkt(md)) == NULL) {
196 m_freem(m);
197 m_freem(md0);
198 m_freem(mcopy);
199 error = ENOBUFS;
200 goto fail;
202 mprev->m_next = md;
204 /* compress data part */
205 if ((*algo->compress)(m, md, &plen) || mprev->m_next == NULL) {
206 ipseclog((LOG_ERR, "packet compression failure\n"));
207 m = NULL;
208 m_freem(md0);
209 m_freem(mcopy);
210 stat->out_inval++;
211 error = EINVAL;
212 goto fail;
214 stat->out_comphist[sav->alg_enc]++;
215 md = mprev->m_next;
218 * if the packet became bigger, meaningless to use IPComp.
219 * we've only wasted our cpu time.
221 if (plen0 < plen) {
222 m_freem(md);
223 m_freem(mcopy);
224 mprev->m_next = md0;
225 return 0;
229 * no need to backout change beyond here.
231 m_freem(md0);
232 md0 = NULL;
234 m->m_pkthdr.len -= plen0;
235 m->m_pkthdr.len += plen;
239 * insert IPComp header.
241 #ifdef INET
242 struct ip *ip = NULL;
243 #endif
244 size_t complen = sizeof(struct ipcomp);
246 switch (af) {
247 #ifdef INET
248 case AF_INET:
249 ip = mtod(m, struct ip *);
250 break;
251 #endif
252 #ifdef INET6
253 case AF_INET6:
254 break;
255 #endif
258 compoff = m->m_pkthdr.len - plen;
261 * grow the mbuf to accomodate ipcomp header.
262 * before: IP ... payload
263 * after: IP ... ipcomp payload
265 if (M_LEADINGSPACE(md) < complen) {
266 MGET(n, M_NOWAIT, MT_DATA);
267 if (!n) {
268 m_freem(m);
269 error = ENOBUFS;
270 goto fail;
272 n->m_len = complen;
273 mprev->m_next = n;
274 n->m_next = md;
275 m->m_pkthdr.len += complen;
276 ipcomp = mtod(n, struct ipcomp *);
277 } else {
278 md->m_len += complen;
279 md->m_data -= complen;
280 m->m_pkthdr.len += complen;
281 ipcomp = mtod(md, struct ipcomp *);
284 bzero(ipcomp, sizeof(*ipcomp));
285 ipcomp->comp_nxt = *nexthdrp;
286 *nexthdrp = IPPROTO_IPCOMP;
287 ipcomp->comp_cpi = htons(cpi);
288 switch (af) {
289 #ifdef INET
290 case AF_INET:
291 if (compoff + complen + plen < IP_MAXPACKET)
292 ip->ip_len = htons(compoff + complen + plen);
293 else {
294 ipseclog((LOG_ERR,
295 "IPv4 ESP output: size exceeds limit\n"));
296 ipsecstat.out_inval++;
297 m_freem(m);
298 error = EMSGSIZE;
299 goto fail;
301 break;
302 #endif
303 #ifdef INET6
304 case AF_INET6:
305 /* total packet length will be computed in ip6_output() */
306 break;
307 #endif
311 if (!m) {
312 ipseclog((LOG_DEBUG,
313 "NULL mbuf after compression in ipcomp%d_output",
314 afnumber));
315 stat->out_inval++;
317 stat->out_success++;
319 /* compute byte lifetime against original packet */
320 key_sa_recordxfer(sav, mcopy);
321 m_freem(mcopy);
323 return 0;
325 fail:
326 #if 1
327 return error;
328 #else
329 panic("something bad in ipcomp_output");
330 #endif
333 #ifdef INET
335 ipcomp4_output(struct mbuf *m, struct ipsecrequest *isr)
337 struct ip *ip;
338 if (m->m_len < sizeof(struct ip)) {
339 ipseclog((LOG_DEBUG, "ipcomp4_output: first mbuf too short\n"));
340 ipsecstat.out_inval++;
341 m_freem(m);
342 return 0;
344 ip = mtod(m, struct ip *);
345 /* XXX assumes that m->m_next points to payload */
346 return ipcomp_output(m, &ip->ip_p, m->m_next, isr, AF_INET);
348 #endif /* INET */
350 #ifdef INET6
352 ipcomp6_output(struct mbuf *m, u_char *nexthdrp, struct mbuf *md,
353 struct ipsecrequest *isr)
355 if (m->m_len < sizeof(struct ip6_hdr)) {
356 ipseclog((LOG_DEBUG, "ipcomp6_output: first mbuf too short\n"));
357 ipsec6stat.out_inval++;
358 m_freem(m);
359 return 0;
361 return ipcomp_output(m, nexthdrp, md, isr, AF_INET6);
363 #endif /* INET6 */