]> git.saurik.com Git - apple/xnu.git/blame - bsd/netinet6/esp_output.c
xnu-517.12.7.tar.gz
[apple/xnu.git] / bsd / netinet6 / esp_output.c
CommitLineData
55e303ae
A
1/* $FreeBSD: src/sys/netinet6/esp_output.c,v 1.1.2.3 2002/04/28 05:40:26 suz Exp $ */
2/* $KAME: esp_output.c,v 1.44 2001/07/26 06:53:15 jinmei Exp $ */
1c79356b
A
3
4/*
5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6 * All rights reserved.
7 *
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.
19 *
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.
31 */
32
33#define _IP_VHL
1c79356b
A
34
35/*
36 * RFC1827/2406 Encapsulated Security Payload.
37 */
38
39#include <sys/param.h>
40#include <sys/systm.h>
41#include <sys/malloc.h>
42#include <sys/mbuf.h>
43#include <sys/domain.h>
44#include <sys/protosw.h>
45#include <sys/socket.h>
46#include <sys/socketvar.h>
47#include <sys/errno.h>
48#include <sys/time.h>
49#include <sys/kernel.h>
50#include <sys/syslog.h>
51
52#include <net/if.h>
53#include <net/route.h>
54
55#include <netinet/in.h>
56#include <netinet/in_systm.h>
57#include <netinet/ip.h>
58#include <netinet/in_var.h>
55e303ae 59#include <netinet/udp.h> /* for nat traversal */
1c79356b
A
60
61#if INET6
62#include <netinet/ip6.h>
63#include <netinet6/ip6_var.h>
64#include <netinet/icmp6.h>
65#endif
66
67#include <netinet6/ipsec.h>
9bccf70c
A
68#if INET6
69#include <netinet6/ipsec6.h>
70#endif
1c79356b 71#include <netinet6/ah.h>
9bccf70c
A
72#if INET6
73#include <netinet6/ah6.h>
74#endif
1c79356b 75#include <netinet6/esp.h>
9bccf70c
A
76#if INET6
77#include <netinet6/esp6.h>
78#endif
1c79356b
A
79#include <netkey/key.h>
80#include <netkey/keydb.h>
1c79356b
A
81
82#include <net/net_osdep.h>
83
55e303ae
A
84#include <sys/kdebug.h>
85#define DBG_LAYER_BEG NETDBG_CODE(DBG_NETIPSEC, 1)
86#define DBG_LAYER_END NETDBG_CODE(DBG_NETIPSEC, 3)
87#define DBG_FNC_ESPOUT NETDBG_CODE(DBG_NETIPSEC, (4 << 8))
88#define DBG_FNC_ENCRYPT NETDBG_CODE(DBG_NETIPSEC, (5 << 8))
89
1c79356b
A
90static int esp_output __P((struct mbuf *, u_char *, struct mbuf *,
91 struct ipsecrequest *, int));
92
55e303ae
A
93extern int esp_udp_encap_port;
94extern u_int32_t natt_now;
95
1c79356b
A
96/*
97 * compute ESP header size.
98 */
99size_t
100esp_hdrsiz(isr)
101 struct ipsecrequest *isr;
102{
103 struct secasvar *sav;
9bccf70c
A
104 const struct esp_algorithm *algo;
105 const struct ah_algorithm *aalgo;
1c79356b
A
106 size_t ivlen;
107 size_t authlen;
108 size_t hdrsiz;
55e303ae 109 size_t maxpad;
1c79356b
A
110
111 /* sanity check */
112 if (isr == NULL)
113 panic("esp_hdrsiz: NULL was passed.\n");
114
115 sav = isr->sav;
116
117 if (isr->saidx.proto != IPPROTO_ESP)
118 panic("unsupported mode passed to esp_hdrsiz");
119
120 if (sav == NULL)
121 goto estimate;
122 if (sav->state != SADB_SASTATE_MATURE
123 && sav->state != SADB_SASTATE_DYING)
124 goto estimate;
125
126 /* we need transport mode ESP. */
9bccf70c 127 algo = esp_algorithm_lookup(sav->alg_enc);
1c79356b
A
128 if (!algo)
129 goto estimate;
130 ivlen = sav->ivlen;
131 if (ivlen < 0)
132 goto estimate;
133
55e303ae
A
134 if (algo->padbound)
135 maxpad = algo->padbound;
136 else
137 maxpad = 4;
138 maxpad += 1; /* maximum 'extendsiz' is padbound + 1, see esp_output */
139
1c79356b
A
140 if (sav->flags & SADB_X_EXT_OLD) {
141 /* RFC 1827 */
55e303ae 142 hdrsiz = sizeof(struct esp) + ivlen + maxpad;
1c79356b
A
143 } else {
144 /* RFC 2406 */
9bccf70c
A
145 aalgo = ah_algorithm_lookup(sav->alg_auth);
146 if (aalgo && sav->replay && sav->key_auth)
147 authlen = (aalgo->sumsiz)(sav);
1c79356b
A
148 else
149 authlen = 0;
55e303ae 150 hdrsiz = sizeof(struct newesp) + ivlen + maxpad + authlen;
1c79356b 151 }
55e303ae
A
152
153 /*
154 * If the security association indicates that NATT is required,
155 * add the size of the NATT encapsulation header:
156 */
157 if ((sav->flags & SADB_X_EXT_NATT) != 0) hdrsiz += sizeof(struct udphdr) + 4;
1c79356b
A
158
159 return hdrsiz;
160
161 estimate:
162 /*
163 * ASSUMING:
55e303ae 164 * sizeof(struct newesp) > sizeof(struct esp). (8)
9bccf70c 165 * esp_max_ivlen() = max ivlen for CBC mode
55e303ae 166 * 17 = (maximum padding length without random padding length)
1c79356b
A
167 * + (Pad Length field) + (Next Header field).
168 * 16 = maximum ICV we support.
55e303ae 169 * sizeof(struct udphdr) in case NAT traversal is used
1c79356b 170 */
55e303ae 171 return sizeof(struct newesp) + esp_max_ivlen() + 17 + 16 + sizeof(struct udphdr);
1c79356b
A
172}
173
174/*
175 * Modify the packet so that the payload is encrypted.
176 * The mbuf (m) must start with IPv4 or IPv6 header.
177 * On failure, free the given mbuf and return NULL.
178 *
179 * on invocation:
180 * m nexthdrp md
181 * v v v
182 * IP ......... payload
183 * during the encryption:
184 * m nexthdrp mprev md
185 * v v v v
186 * IP ............... esp iv payload pad padlen nxthdr
187 * <--><-><------><--------------->
188 * esplen plen extendsiz
189 * ivlen
190 * <-----> esphlen
191 * <-> hlen
192 * <-----------------> espoff
193 */
194static int
195esp_output(m, nexthdrp, md, isr, af)
196 struct mbuf *m;
197 u_char *nexthdrp;
198 struct mbuf *md;
199 struct ipsecrequest *isr;
200 int af;
201{
202 struct mbuf *n;
203 struct mbuf *mprev;
204 struct esp *esp;
205 struct esptail *esptail;
206 struct secasvar *sav = isr->sav;
9bccf70c 207 const struct esp_algorithm *algo;
1c79356b
A
208 u_int32_t spi;
209 u_int8_t nxt = 0;
210 size_t plen; /*payload length to be encrypted*/
211 size_t espoff;
212 int ivlen;
213 int afnumber;
214 size_t extendsiz;
215 int error = 0;
9bccf70c 216 struct ipsecstat *stat;
55e303ae
A
217 struct udphdr *udp = NULL;
218 int udp_encapsulate = (sav->flags & SADB_X_EXT_NATT && af == AF_INET &&
219 (esp_udp_encap_port & 0xFFFF) != 0);
1c79356b 220
55e303ae 221 KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_START, sav->ivlen,0,0,0,0);
1c79356b
A
222 switch (af) {
223#if INET
224 case AF_INET:
225 afnumber = 4;
9bccf70c 226 stat = &ipsecstat;
1c79356b
A
227 break;
228#endif
229#if INET6
230 case AF_INET6:
231 afnumber = 6;
9bccf70c 232 stat = &ipsec6stat;
1c79356b
A
233 break;
234#endif
235 default:
236 ipseclog((LOG_ERR, "esp_output: unsupported af %d\n", af));
55e303ae 237 KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_END, 1,0,0,0,0);
1c79356b
A
238 return 0; /* no change at all */
239 }
240
241 /* some sanity check */
242 if ((sav->flags & SADB_X_EXT_OLD) == 0 && !sav->replay) {
243 switch (af) {
244#if INET
245 case AF_INET:
246 {
247 struct ip *ip;
248
249 ip = mtod(m, struct ip *);
250 ipseclog((LOG_DEBUG, "esp4_output: internal error: "
251 "sav->replay is null: %x->%x, SPI=%u\n",
252 (u_int32_t)ntohl(ip->ip_src.s_addr),
253 (u_int32_t)ntohl(ip->ip_dst.s_addr),
254 (u_int32_t)ntohl(sav->spi)));
255 ipsecstat.out_inval++;
9bccf70c 256 break;
1c79356b
A
257 }
258#endif /*INET*/
259#if INET6
260 case AF_INET6:
1c79356b
A
261 ipseclog((LOG_DEBUG, "esp6_output: internal error: "
262 "sav->replay is null: SPI=%u\n",
263 (u_int32_t)ntohl(sav->spi)));
264 ipsec6stat.out_inval++;
9bccf70c 265 break;
1c79356b 266#endif /*INET6*/
9bccf70c
A
267 default:
268 panic("esp_output: should not reach here");
1c79356b 269 }
9bccf70c 270 m_freem(m);
55e303ae 271 KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_END, 2,0,0,0,0);
9bccf70c 272 return EINVAL;
1c79356b
A
273 }
274
9bccf70c
A
275 algo = esp_algorithm_lookup(sav->alg_enc);
276 if (!algo) {
277 ipseclog((LOG_ERR, "esp_output: unsupported algorithm: "
278 "SPI=%u\n", (u_int32_t)ntohl(sav->spi)));
279 m_freem(m);
55e303ae 280 KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_END, 3,0,0,0,0);
9bccf70c
A
281 return EINVAL;
282 }
1c79356b
A
283 spi = sav->spi;
284 ivlen = sav->ivlen;
285 /* should be okey */
286 if (ivlen < 0) {
287 panic("invalid ivlen");
288 }
289
290 {
291 /*
292 * insert ESP header.
293 * XXX inserts ESP header right after IPv4 header. should
294 * chase the header chain.
295 * XXX sequential number
296 */
297#if INET
298 struct ip *ip = NULL;
299#endif
300#if INET6
301 struct ip6_hdr *ip6 = NULL;
302#endif
55e303ae
A
303 size_t esplen; /* sizeof(struct esp/newesp) */
304 size_t esphlen; /* sizeof(struct esp/newesp) + ivlen */
305 size_t hlen = 0; /* ip header len */
1c79356b
A
306
307 if (sav->flags & SADB_X_EXT_OLD) {
308 /* RFC 1827 */
309 esplen = sizeof(struct esp);
310 } else {
311 /* RFC 2406 */
312 if (sav->flags & SADB_X_EXT_DERIV)
313 esplen = sizeof(struct esp);
314 else
315 esplen = sizeof(struct newesp);
316 }
317 esphlen = esplen + ivlen;
318
319 for (mprev = m; mprev && mprev->m_next != md; mprev = mprev->m_next)
320 ;
321 if (mprev == NULL || mprev->m_next != md) {
322 ipseclog((LOG_DEBUG, "esp%d_output: md is not in chain\n",
323 afnumber));
324 m_freem(m);
55e303ae 325 KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_END, 4,0,0,0,0);
1c79356b
A
326 return EINVAL;
327 }
328
329 plen = 0;
330 for (n = md; n; n = n->m_next)
331 plen += n->m_len;
332
333 switch (af) {
334#if INET
335 case AF_INET:
336 ip = mtod(m, struct ip *);
337#ifdef _IP_VHL
338 hlen = IP_VHL_HL(ip->ip_vhl) << 2;
339#else
340 hlen = ip->ip_hl << 2;
341#endif
342 break;
343#endif
344#if INET6
345 case AF_INET6:
346 ip6 = mtod(m, struct ip6_hdr *);
347 hlen = sizeof(*ip6);
348 break;
349#endif
350 }
351
352 /* make the packet over-writable */
353 mprev->m_next = NULL;
354 if ((md = ipsec_copypkt(md)) == NULL) {
355 m_freem(m);
356 error = ENOBUFS;
357 goto fail;
358 }
359 mprev->m_next = md;
360
361 espoff = m->m_pkthdr.len - plen;
55e303ae
A
362
363 if (udp_encapsulate) {
364 esphlen += sizeof(struct udphdr);
365 espoff += sizeof(struct udphdr);
366 }
1c79356b
A
367
368 /*
369 * grow the mbuf to accomodate ESP header.
370 * before: IP ... payload
55e303ae 371 * after: IP ... [UDP] ESP IV payload
1c79356b 372 */
9bccf70c 373 if (M_LEADINGSPACE(md) < esphlen || (md->m_flags & M_EXT) != 0) {
1c79356b
A
374 MGET(n, M_DONTWAIT, MT_DATA);
375 if (!n) {
376 m_freem(m);
377 error = ENOBUFS;
378 goto fail;
379 }
380 n->m_len = esphlen;
381 mprev->m_next = n;
382 n->m_next = md;
383 m->m_pkthdr.len += esphlen;
55e303ae
A
384 if (udp_encapsulate) {
385 udp = mtod(n, struct udphdr *);
386 esp = (struct esp *)((caddr_t)udp + sizeof(struct udphdr));
387 } else {
388 esp = mtod(n, struct esp *);
389 }
1c79356b
A
390 } else {
391 md->m_len += esphlen;
392 md->m_data -= esphlen;
393 m->m_pkthdr.len += esphlen;
394 esp = mtod(md, struct esp *);
55e303ae
A
395 if (udp_encapsulate) {
396 udp = mtod(md, struct udphdr *);
397 esp = (struct esp *)((caddr_t)udp + sizeof(struct udphdr));
398 } else {
399 esp = mtod(md, struct esp *);
400 }
1c79356b
A
401 }
402
1c79356b
A
403 switch (af) {
404#if INET
405 case AF_INET:
406 if (esphlen < (IP_MAXPACKET - ntohs(ip->ip_len)))
407 ip->ip_len = htons(ntohs(ip->ip_len) + esphlen);
408 else {
409 ipseclog((LOG_ERR,
410 "IPv4 ESP output: size exceeds limit\n"));
411 ipsecstat.out_inval++;
412 m_freem(m);
413 error = EMSGSIZE;
414 goto fail;
415 }
416 break;
417#endif
418#if INET6
419 case AF_INET6:
420 /* total packet length will be computed in ip6_output() */
421 break;
422#endif
423 }
424 }
425
426 /* initialize esp header. */
427 esp->esp_spi = spi;
428 if ((sav->flags & SADB_X_EXT_OLD) == 0) {
429 struct newesp *nesp;
430 nesp = (struct newesp *)esp;
431 if (sav->replay->count == ~0) {
432 if ((sav->flags & SADB_X_EXT_CYCSEQ) == 0) {
433 /* XXX Is it noisy ? */
434 ipseclog((LOG_WARNING,
435 "replay counter overflowed. %s\n",
436 ipsec_logsastr(sav)));
9bccf70c 437 stat->out_inval++;
1c79356b 438 m_freem(m);
55e303ae 439 KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_END, 5,0,0,0,0);
1c79356b
A
440 return EINVAL;
441 }
442 }
443 sav->replay->count++;
444 /*
445 * XXX sequence number must not be cycled, if the SA is
446 * installed by IKE daemon.
447 */
448 nesp->esp_seq = htonl(sav->replay->count);
449 }
450
451 {
452 /*
453 * find the last mbuf. make some room for ESP trailer.
1c79356b
A
454 */
455#if INET
456 struct ip *ip = NULL;
457#endif
458 size_t padbound;
459 u_char *extend;
460 int i;
9bccf70c 461 int randpadmax;
1c79356b
A
462
463 if (algo->padbound)
464 padbound = algo->padbound;
465 else
466 padbound = 4;
467 /* ESP packet, including nxthdr field, must be length of 4n */
468 if (padbound < 4)
469 padbound = 4;
470
471 extendsiz = padbound - (plen % padbound);
472 if (extendsiz == 1)
473 extendsiz = padbound + 1;
474
9bccf70c
A
475 /* random padding */
476 switch (af) {
477#if INET
478 case AF_INET:
479 randpadmax = ip4_esp_randpad;
480 break;
481#endif
482#if INET6
483 case AF_INET6:
484 randpadmax = ip6_esp_randpad;
485 break;
486#endif
487 default:
488 randpadmax = -1;
489 break;
490 }
491 if (randpadmax < 0 || plen + extendsiz >= randpadmax)
492 ;
493 else {
494 int n;
495
496 /* round */
497 randpadmax = (randpadmax / padbound) * padbound;
498 n = (randpadmax - plen + extendsiz) / padbound;
499
500 if (n > 0)
501 n = (random() % n) * padbound;
502 else
503 n = 0;
504
505 /*
506 * make sure we do not pad too much.
507 * MLEN limitation comes from the trailer attachment
508 * code below.
509 * 256 limitation comes from sequential padding.
510 * also, the 1-octet length field in ESP trailer imposes
511 * limitation (but is less strict than sequential padding
512 * as length field do not count the last 2 octets).
513 */
514 if (extendsiz + n <= MLEN && extendsiz + n < 256)
515 extendsiz += n;
516 }
517
518#if DIAGNOSTIC
519 if (extendsiz > MLEN || extendsiz >= 256)
520 panic("extendsiz too big in esp_output");
521#endif
522
1c79356b
A
523 n = m;
524 while (n->m_next)
525 n = n->m_next;
526
527 /*
9bccf70c
A
528 * if M_EXT, the external mbuf data may be shared among
529 * two consequtive TCP packets, and it may be unsafe to use the
530 * trailing space.
1c79356b
A
531 */
532 if (!(n->m_flags & M_EXT) && extendsiz < M_TRAILINGSPACE(n)) {
533 extend = mtod(n, u_char *) + n->m_len;
534 n->m_len += extendsiz;
535 m->m_pkthdr.len += extendsiz;
536 } else {
537 struct mbuf *nn;
538
539 MGET(nn, M_DONTWAIT, MT_DATA);
540 if (!nn) {
541 ipseclog((LOG_DEBUG, "esp%d_output: can't alloc mbuf",
542 afnumber));
543 m_freem(m);
544 error = ENOBUFS;
545 goto fail;
546 }
547 extend = mtod(nn, u_char *);
548 nn->m_len = extendsiz;
549 nn->m_next = NULL;
550 n->m_next = nn;
551 n = nn;
552 m->m_pkthdr.len += extendsiz;
553 }
554 switch (sav->flags & SADB_X_EXT_PMASK) {
555 case SADB_X_EXT_PRAND:
9bccf70c 556 key_randomfill(extend, extendsiz);
1c79356b
A
557 break;
558 case SADB_X_EXT_PZERO:
559 bzero(extend, extendsiz);
560 break;
561 case SADB_X_EXT_PSEQ:
562 for (i = 0; i < extendsiz; i++)
563 extend[i] = (i + 1) & 0xff;
564 break;
565 }
55e303ae
A
566
567 nxt = *nexthdrp;
568 if (udp_encapsulate) {
569 *nexthdrp = IPPROTO_UDP;
570
571 /* Fill out the UDP header */
572 udp->uh_sport = ntohs((u_short)esp_udp_encap_port);
573 udp->uh_dport = ntohs(sav->remote_ike_port);
574// udp->uh_len set later, after all length tweaks are complete
575 udp->uh_sum = 0;
576
577 /* Update last sent so we know if we need to send keepalive */
578 sav->natt_last_activity = natt_now;
579 } else {
580 *nexthdrp = IPPROTO_ESP;
581 }
1c79356b
A
582
583 /* initialize esp trailer. */
584 esptail = (struct esptail *)
585 (mtod(n, u_int8_t *) + n->m_len - sizeof(struct esptail));
586 esptail->esp_nxt = nxt;
587 esptail->esp_padlen = extendsiz - 2;
588
589 /* modify IP header (for ESP header part only) */
590 switch (af) {
591#if INET
592 case AF_INET:
593 ip = mtod(m, struct ip *);
594 if (extendsiz < (IP_MAXPACKET - ntohs(ip->ip_len)))
595 ip->ip_len = htons(ntohs(ip->ip_len) + extendsiz);
596 else {
597 ipseclog((LOG_ERR,
598 "IPv4 ESP output: size exceeds limit\n"));
599 ipsecstat.out_inval++;
600 m_freem(m);
601 error = EMSGSIZE;
602 goto fail;
603 }
604 break;
605#endif
606#if INET6
607 case AF_INET6:
608 /* total packet length will be computed in ip6_output() */
609 break;
610#endif
611 }
612 }
613
9bccf70c
A
614 /*
615 * pre-compute and cache intermediate key
616 */
617 error = esp_schedule(algo, sav);
618 if (error) {
619 m_freem(m);
620 stat->out_inval++;
621 goto fail;
622 }
623
1c79356b
A
624 /*
625 * encrypt the packet, based on security association
626 * and the algorithm specified.
627 */
628 if (!algo->encrypt)
629 panic("internal error: no encrypt function");
55e303ae 630 KERNEL_DEBUG(DBG_FNC_ENCRYPT | DBG_FUNC_START, 0,0,0,0,0);
1c79356b 631 if ((*algo->encrypt)(m, espoff, plen + extendsiz, sav, algo, ivlen)) {
9bccf70c 632 /* m is already freed */
1c79356b 633 ipseclog((LOG_ERR, "packet encryption failure\n"));
9bccf70c 634 stat->out_inval++;
1c79356b 635 error = EINVAL;
55e303ae 636 KERNEL_DEBUG(DBG_FNC_ENCRYPT | DBG_FUNC_END, 1,error,0,0,0);
1c79356b
A
637 goto fail;
638 }
55e303ae 639 KERNEL_DEBUG(DBG_FNC_ENCRYPT | DBG_FUNC_END, 2,0,0,0,0);
1c79356b
A
640
641 /*
642 * calculate ICV if required.
643 */
644 if (!sav->replay)
645 goto noantireplay;
646 if (!sav->key_auth)
647 goto noantireplay;
9bccf70c 648 if (sav->key_auth == SADB_AALG_NONE)
1c79356b 649 goto noantireplay;
9bccf70c 650
1c79356b 651 {
9bccf70c 652 const struct ah_algorithm *aalgo;
1c79356b
A
653 u_char authbuf[AH_MAXSUMSIZE];
654 struct mbuf *n;
655 u_char *p;
656 size_t siz;
9bccf70c 657#if INET
1c79356b 658 struct ip *ip;
9bccf70c 659#endif
1c79356b 660
9bccf70c
A
661 aalgo = ah_algorithm_lookup(sav->alg_auth);
662 if (!aalgo)
663 goto noantireplay;
664 siz = ((aalgo->sumsiz)(sav) + 3) & ~(4 - 1);
1c79356b
A
665 if (AH_MAXSUMSIZE < siz)
666 panic("assertion failed for AH_MAXSUMSIZE");
667
9bccf70c
A
668 if (esp_auth(m, espoff, m->m_pkthdr.len - espoff, sav, authbuf)) {
669 ipseclog((LOG_ERR, "ESP checksum generation failure\n"));
670 m_freem(m);
671 error = EINVAL;
672 stat->out_inval++;
673 goto fail;
674 }
1c79356b
A
675
676 n = m;
677 while (n->m_next)
678 n = n->m_next;
679
55e303ae 680 if (!(n->m_flags & M_EXT) && siz < M_TRAILINGSPACE(n)) { /* XXX */
1c79356b
A
681 n->m_len += siz;
682 m->m_pkthdr.len += siz;
683 p = mtod(n, u_char *) + n->m_len - siz;
684 } else {
685 struct mbuf *nn;
686
687 MGET(nn, M_DONTWAIT, MT_DATA);
688 if (!nn) {
689 ipseclog((LOG_DEBUG, "can't alloc mbuf in esp%d_output",
690 afnumber));
691 m_freem(m);
692 error = ENOBUFS;
693 goto fail;
694 }
695 nn->m_len = siz;
696 nn->m_next = NULL;
697 n->m_next = nn;
698 n = nn;
699 m->m_pkthdr.len += siz;
700 p = mtod(nn, u_char *);
701 }
702 bcopy(authbuf, p, siz);
703
704 /* modify IP header (for ESP header part only) */
705 switch (af) {
706#if INET
707 case AF_INET:
708 ip = mtod(m, struct ip *);
709 if (siz < (IP_MAXPACKET - ntohs(ip->ip_len)))
710 ip->ip_len = htons(ntohs(ip->ip_len) + siz);
711 else {
712 ipseclog((LOG_ERR,
713 "IPv4 ESP output: size exceeds limit\n"));
714 ipsecstat.out_inval++;
715 m_freem(m);
716 error = EMSGSIZE;
717 goto fail;
718 }
719 break;
720#endif
721#if INET6
722 case AF_INET6:
723 /* total packet length will be computed in ip6_output() */
724 break;
725#endif
726 }
727 }
55e303ae
A
728
729 if (udp_encapsulate) {
730 struct ip *ip;
731 ip = mtod(m, struct ip *);
732 udp->uh_ulen = htons(ntohs(ip->ip_len) - (IP_VHL_HL(ip->ip_vhl) << 2));
733 }
734
1c79356b
A
735
736noantireplay:
737 if (!m) {
738 ipseclog((LOG_ERR,
739 "NULL mbuf after encryption in esp%d_output", afnumber));
9bccf70c
A
740 } else
741 stat->out_success++;
742 stat->out_esphist[sav->alg_enc]++;
1c79356b 743 key_sa_recordxfer(sav, m);
55e303ae 744 KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_END, 6,0,0,0,0);
1c79356b
A
745 return 0;
746
747fail:
748#if 1
55e303ae 749 KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_END, 7,error,0,0,0);
1c79356b
A
750 return error;
751#else
752 panic("something bad in esp_output");
753#endif
754}
755
756#if INET
757int
758esp4_output(m, isr)
759 struct mbuf *m;
760 struct ipsecrequest *isr;
761{
762 struct ip *ip;
763 if (m->m_len < sizeof(struct ip)) {
764 ipseclog((LOG_DEBUG, "esp4_output: first mbuf too short\n"));
765 m_freem(m);
9bccf70c 766 return 0;
1c79356b
A
767 }
768 ip = mtod(m, struct ip *);
769 /* XXX assumes that m->m_next points to payload */
770 return esp_output(m, &ip->ip_p, m->m_next, isr, AF_INET);
771}
772#endif /*INET*/
773
774#if INET6
775int
776esp6_output(m, nexthdrp, md, isr)
777 struct mbuf *m;
778 u_char *nexthdrp;
779 struct mbuf *md;
780 struct ipsecrequest *isr;
781{
782 if (m->m_len < sizeof(struct ip6_hdr)) {
783 ipseclog((LOG_DEBUG, "esp6_output: first mbuf too short\n"));
784 m_freem(m);
9bccf70c 785 return 0;
1c79356b
A
786 }
787 return esp_output(m, nexthdrp, md, isr, AF_INET6);
788}
789#endif /*INET6*/