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