]> git.saurik.com Git - apple/xnu.git/blob - bsd/netinet6/esp_output.c
xnu-517.tar.gz
[apple/xnu.git] / bsd / netinet6 / esp_output.c
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 $ */
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
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>
59 #include <netinet/udp.h> /* for nat traversal */
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>
68 #if INET6
69 #include <netinet6/ipsec6.h>
70 #endif
71 #include <netinet6/ah.h>
72 #if INET6
73 #include <netinet6/ah6.h>
74 #endif
75 #include <netinet6/esp.h>
76 #if INET6
77 #include <netinet6/esp6.h>
78 #endif
79 #include <netkey/key.h>
80 #include <netkey/keydb.h>
81
82 #include <net/net_osdep.h>
83
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
90 static int esp_output __P((struct mbuf *, u_char *, struct mbuf *,
91 struct ipsecrequest *, int));
92
93 extern int esp_udp_encap_port;
94 extern u_int32_t natt_now;
95
96 /*
97 * compute ESP header size.
98 */
99 size_t
100 esp_hdrsiz(isr)
101 struct ipsecrequest *isr;
102 {
103 struct secasvar *sav;
104 const struct esp_algorithm *algo;
105 const struct ah_algorithm *aalgo;
106 size_t ivlen;
107 size_t authlen;
108 size_t hdrsiz;
109 size_t maxpad;
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. */
127 algo = esp_algorithm_lookup(sav->alg_enc);
128 if (!algo)
129 goto estimate;
130 ivlen = sav->ivlen;
131 if (ivlen < 0)
132 goto estimate;
133
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
140 if (sav->flags & SADB_X_EXT_OLD) {
141 /* RFC 1827 */
142 hdrsiz = sizeof(struct esp) + ivlen + maxpad;
143 } else {
144 /* RFC 2406 */
145 aalgo = ah_algorithm_lookup(sav->alg_auth);
146 if (aalgo && sav->replay && sav->key_auth)
147 authlen = (aalgo->sumsiz)(sav);
148 else
149 authlen = 0;
150 hdrsiz = sizeof(struct newesp) + ivlen + maxpad + authlen;
151 }
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;
158
159 return hdrsiz;
160
161 estimate:
162 /*
163 * ASSUMING:
164 * sizeof(struct newesp) > sizeof(struct esp). (8)
165 * esp_max_ivlen() = max ivlen for CBC mode
166 * 17 = (maximum padding length without random padding length)
167 * + (Pad Length field) + (Next Header field).
168 * 16 = maximum ICV we support.
169 * sizeof(struct udphdr) in case NAT traversal is used
170 */
171 return sizeof(struct newesp) + esp_max_ivlen() + 17 + 16 + sizeof(struct udphdr);
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 */
194 static int
195 esp_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;
207 const struct esp_algorithm *algo;
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;
216 struct ipsecstat *stat;
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);
220
221 KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_START, sav->ivlen,0,0,0,0);
222 switch (af) {
223 #if INET
224 case AF_INET:
225 afnumber = 4;
226 stat = &ipsecstat;
227 break;
228 #endif
229 #if INET6
230 case AF_INET6:
231 afnumber = 6;
232 stat = &ipsec6stat;
233 break;
234 #endif
235 default:
236 ipseclog((LOG_ERR, "esp_output: unsupported af %d\n", af));
237 KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_END, 1,0,0,0,0);
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++;
256 break;
257 }
258 #endif /*INET*/
259 #if INET6
260 case AF_INET6:
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++;
265 break;
266 #endif /*INET6*/
267 default:
268 panic("esp_output: should not reach here");
269 }
270 m_freem(m);
271 KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_END, 2,0,0,0,0);
272 return EINVAL;
273 }
274
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);
280 KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_END, 3,0,0,0,0);
281 return EINVAL;
282 }
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
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 */
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);
325 KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_END, 4,0,0,0,0);
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;
362
363 if (udp_encapsulate) {
364 esphlen += sizeof(struct udphdr);
365 espoff += sizeof(struct udphdr);
366 }
367
368 /*
369 * grow the mbuf to accomodate ESP header.
370 * before: IP ... payload
371 * after: IP ... [UDP] ESP IV payload
372 */
373 if (M_LEADINGSPACE(md) < esphlen || (md->m_flags & M_EXT) != 0) {
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;
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 }
390 } else {
391 md->m_len += esphlen;
392 md->m_data -= esphlen;
393 m->m_pkthdr.len += esphlen;
394 esp = mtod(md, struct esp *);
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 }
401 }
402
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)));
437 stat->out_inval++;
438 m_freem(m);
439 KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_END, 5,0,0,0,0);
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.
454 */
455 #if INET
456 struct ip *ip = NULL;
457 #endif
458 size_t padbound;
459 u_char *extend;
460 int i;
461 int randpadmax;
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
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
523 n = m;
524 while (n->m_next)
525 n = n->m_next;
526
527 /*
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.
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:
556 key_randomfill(extend, extendsiz);
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 }
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 }
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
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
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");
630 KERNEL_DEBUG(DBG_FNC_ENCRYPT | DBG_FUNC_START, 0,0,0,0,0);
631 if ((*algo->encrypt)(m, espoff, plen + extendsiz, sav, algo, ivlen)) {
632 /* m is already freed */
633 ipseclog((LOG_ERR, "packet encryption failure\n"));
634 stat->out_inval++;
635 error = EINVAL;
636 KERNEL_DEBUG(DBG_FNC_ENCRYPT | DBG_FUNC_END, 1,error,0,0,0);
637 goto fail;
638 }
639 KERNEL_DEBUG(DBG_FNC_ENCRYPT | DBG_FUNC_END, 2,0,0,0,0);
640
641 /*
642 * calculate ICV if required.
643 */
644 if (!sav->replay)
645 goto noantireplay;
646 if (!sav->key_auth)
647 goto noantireplay;
648 if (sav->key_auth == SADB_AALG_NONE)
649 goto noantireplay;
650
651 {
652 const struct ah_algorithm *aalgo;
653 u_char authbuf[AH_MAXSUMSIZE];
654 struct mbuf *n;
655 u_char *p;
656 size_t siz;
657 #if INET
658 struct ip *ip;
659 #endif
660
661 aalgo = ah_algorithm_lookup(sav->alg_auth);
662 if (!aalgo)
663 goto noantireplay;
664 siz = ((aalgo->sumsiz)(sav) + 3) & ~(4 - 1);
665 if (AH_MAXSUMSIZE < siz)
666 panic("assertion failed for AH_MAXSUMSIZE");
667
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 }
675
676 n = m;
677 while (n->m_next)
678 n = n->m_next;
679
680 if (!(n->m_flags & M_EXT) && siz < M_TRAILINGSPACE(n)) { /* XXX */
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 }
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
735
736 noantireplay:
737 if (!m) {
738 ipseclog((LOG_ERR,
739 "NULL mbuf after encryption in esp%d_output", afnumber));
740 } else
741 stat->out_success++;
742 stat->out_esphist[sav->alg_enc]++;
743 key_sa_recordxfer(sav, m);
744 KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_END, 6,0,0,0,0);
745 return 0;
746
747 fail:
748 #if 1
749 KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_END, 7,error,0,0,0);
750 return error;
751 #else
752 panic("something bad in esp_output");
753 #endif
754 }
755
756 #if INET
757 int
758 esp4_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);
766 return 0;
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
775 int
776 esp6_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);
785 return 0;
786 }
787 return esp_output(m, nexthdrp, md, isr, AF_INET6);
788 }
789 #endif /*INET6*/