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