Annotation of src/sys/netipsec/ipsec_output.c, Revision 1.27
1.27 ! thorpej 1: /* $NetBSD: ipsec_output.c,v 1.26 2007/12/29 16:43:17 degroote Exp $ */
1.9 thorpej 2:
3: /*-
4: * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
5: * All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: *
16: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26: * SUCH DAMAGE.
27: *
28: * $FreeBSD: /repoman/r/ncvs/src/sys/netipsec/ipsec_output.c,v 1.3.2.2 2003/03/28 20:32:53 sam Exp $
29: */
1.1 jonathan 30:
31: #include <sys/cdefs.h>
1.27 ! thorpej 32: __KERNEL_RCSID(0, "$NetBSD: ipsec_output.c,v 1.26 2007/12/29 16:43:17 degroote Exp $");
1.1 jonathan 33:
34: /*
35: * IPsec output processing.
36: */
37: #include "opt_inet.h"
1.4 jonathan 38: #ifdef __FreeBSD__
1.1 jonathan 39: #include "opt_inet6.h"
1.4 jonathan 40: #endif
1.1 jonathan 41: #include "opt_ipsec.h"
42:
43: #include <sys/param.h>
44: #include <sys/systm.h>
45: #include <sys/mbuf.h>
46: #include <sys/domain.h>
47: #include <sys/protosw.h>
48: #include <sys/socket.h>
49: #include <sys/errno.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/ip_var.h>
59: #include <netinet/in_var.h>
60: #include <netinet/ip_ecn.h>
61: #ifdef INET6
1.12 jonathan 62: # ifdef __FreeBSD__
63: # include <netinet6/ip6_ecn.h>
64: # endif
1.1 jonathan 65: #endif
66:
67: #include <netinet/ip6.h>
68: #ifdef INET6
69: #include <netinet6/ip6_var.h>
70: #endif
71: #include <netinet/in_pcb.h>
72: #ifdef INET6
73: #include <netinet/icmp6.h>
74: #endif
1.22 degroote 75: #ifdef IPSEC_NAT_T
76: #include <netinet/udp.h>
77: #endif
1.1 jonathan 78:
79: #include <netipsec/ipsec.h>
1.13 jonathan 80: #include <netipsec/ipsec_var.h>
1.27 ! thorpej 81: #include <netipsec/ipsec_private.h>
1.1 jonathan 82: #ifdef INET6
83: #include <netipsec/ipsec6.h>
84: #endif
85: #include <netipsec/ah_var.h>
86: #include <netipsec/esp_var.h>
87: #include <netipsec/ipcomp_var.h>
88:
89: #include <netipsec/xform.h>
90:
1.7 tls 91: #include <netipsec/key.h>
92: #include <netipsec/keydb.h>
93: #include <netipsec/key_debug.h>
1.1 jonathan 94: #include <netipsec/ipsec_osdep.h>
95:
1.10 jonathan 96: #include <net/net_osdep.h> /* ovbcopy() in ipsec6_encapsulate() */
97:
1.25 degroote 98:
99: /*
100: * Add a IPSEC_OUT_DONE tag to mark that we have finished the ipsec processing
101: * It will be used by ip{,6}_output to check if we have already or not
102: * processed this packet.
103: */
104: static int
105: ipsec_register_done(struct mbuf *m, int * error)
106: {
107: struct m_tag *mtag;
108:
109: mtag = m_tag_get(PACKET_TAG_IPSEC_OUT_DONE, 0, M_NOWAIT);
110: if (mtag == NULL) {
111: DPRINTF(("ipsec_register_done: could not get packet tag\n"));
112: *error = ENOMEM;
113: return -1;
114: }
115:
116: m_tag_prepend(m, mtag);
117: return 0;
118: }
119:
1.26 degroote 120: static int
121: ipsec_reinject_ipstack(struct mbuf *m, int af)
122: {
123: #ifdef INET
124: struct ip * ip;
125: #endif /* INET */
126:
127: switch (af) {
128: #ifdef INET
129: case AF_INET:
130: ip = mtod(m, struct ip *);
131: #ifdef __FreeBSD__
132: /* FreeBSD ip_output() expects ip_len, ip_off in host endian */
133: ip->ip_len = ntohs(ip->ip_len);
134: ip->ip_off = ntohs(ip->ip_off);
135: #endif /* __FreeBSD_ */
136: return ip_output(m, NULL, NULL, IP_RAWOUTPUT,
137: (struct ip_moptions *)NULL, (struct socket *)NULL);
138:
139: #endif /* INET */
140: #ifdef INET6
141: case AF_INET6:
142: /*
143: * We don't need massage, IPv6 header fields are always in
144: * net endian.
145: */
146: return ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
147: #endif /* INET6 */
148: }
149:
150: panic("ipsec_reinject_ipstack : iunknown protocol family %u\n", af);
151: return -1; /* NOTREACHED */
152: }
153:
1.1 jonathan 154: int
155: ipsec_process_done(struct mbuf *m, struct ipsecrequest *isr)
156: {
157: struct secasvar *sav;
158: struct secasindex *saidx;
159: int error;
1.22 degroote 160: #ifdef INET
161: struct ip * ip;
162: #endif /* INET */
163: #ifdef INET6
164: struct ip6_hdr * ip6;
165: #endif /* INET6 */
166: #ifdef IPSEC_NAT_T
167: struct mbuf * mo;
168: struct udphdr *udp = NULL;
169: uint64_t * data = NULL;
170: int hlen, roff;
171: #endif /* IPSEC_NAT_T */
1.1 jonathan 172:
173: IPSEC_SPLASSERT_SOFTNET("ipsec_process_done");
174:
175: IPSEC_ASSERT(m != NULL, ("ipsec_process_done: null mbuf"));
176: IPSEC_ASSERT(isr != NULL, ("ipsec_process_done: null ISR"));
177: sav = isr->sav;
178: IPSEC_ASSERT(sav != NULL, ("ipsec_process_done: null SA"));
179: IPSEC_ASSERT(sav->sah != NULL, ("ipsec_process_done: null SAH"));
180:
181: saidx = &sav->sah->saidx;
1.22 degroote 182:
183: #ifdef IPSEC_NAT_T
184: if(sav->natt_type != 0) {
185: ip = mtod(m, struct ip *);
186:
187: hlen = sizeof(struct udphdr);
188: if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE)
189: hlen += sizeof(uint64_t);
190:
191: mo = m_makespace(m, sizeof(struct ip), hlen, &roff);
192: if (mo == NULL) {
193: DPRINTF(("ipsec_process_done : failed to inject"
194: "%u byte UDP for SA %s/%08lx\n",
195: hlen, ipsec_address(&saidx->dst),
196: (u_long) ntohl(sav->spi)));
197: error = ENOBUFS;
198: goto bad;
199: }
200:
201: udp = (struct udphdr*) (mtod(mo, char*) + roff);
202: data = (uint64_t*) (udp + 1);
203:
204: if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE)
205: *data = 0; /* NON-IKE Marker */
206:
207: if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE)
208: udp->uh_sport = htons(UDP_ENCAP_ESPINUDP_PORT);
209: else
210: udp->uh_sport = key_portfromsaddr(&saidx->src);
211:
212: udp->uh_dport = key_portfromsaddr(&saidx->dst);
213: udp->uh_sum = 0;
1.24 degroote 214: udp->uh_ulen = htons(m->m_pkthdr.len - (ip->ip_hl << 2));
1.22 degroote 215: }
216: #endif /* IPSEC_NAT_T */
217:
1.1 jonathan 218: switch (saidx->dst.sa.sa_family) {
219: #ifdef INET
220: case AF_INET:
221: /* Fix the header length, for AH processing. */
1.22 degroote 222: ip = mtod(m, struct ip *);
223: ip->ip_len = htons(m->m_pkthdr.len);
224: #ifdef IPSEC_NAT_T
225: if (sav->natt_type != 0)
226: ip->ip_p = IPPROTO_UDP;
227: #endif /* IPSEC_NAT_T */
1.1 jonathan 228: break;
229: #endif /* INET */
230: #ifdef INET6
231: case AF_INET6:
232: /* Fix the header length, for AH processing. */
233: if (m->m_pkthdr.len < sizeof (struct ip6_hdr)) {
234: error = ENXIO;
235: goto bad;
236: }
237: if (m->m_pkthdr.len - sizeof (struct ip6_hdr) > IPV6_MAXPACKET) {
238: /* No jumbogram support. */
239: error = ENXIO; /*?*/
240: goto bad;
241: }
1.22 degroote 242: ip6 = mtod(m, struct ip6_hdr *);
243: ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr));
244: #ifdef IPSEC_NAT_T
245: if (sav->natt_type != 0)
246: ip6->ip6_nxt = IPPROTO_UDP;
247: #endif /* IPSEC_NAT_T */
1.1 jonathan 248: break;
249: #endif /* INET6 */
250: default:
251: DPRINTF(("ipsec_process_done: unknown protocol family %u\n",
252: saidx->dst.sa.sa_family));
253: error = ENXIO;
254: goto bad;
255: }
256:
257: /*
258: * If there's another (bundled) SA to apply, do so.
259: * Note that this puts a burden on the kernel stack size.
260: * If this is a problem we'll need to introduce a queue
261: * to set the packet on so we can unwind the stack before
262: * doing further processing.
263: */
264: if (isr->next) {
1.27 ! thorpej 265: IPSEC_STATINC(IPSEC_STAT_OUT_BUNDLESA);
1.21 degroote 266: switch ( saidx->dst.sa.sa_family ) {
267: #ifdef INET
268: case AF_INET:
269: return ipsec4_process_packet(m, isr->next, 0,0);
270: #endif /* INET */
271: #ifdef INET6
272: case AF_INET6:
273: return ipsec6_process_packet(m,isr->next);
274: #endif /* INET6 */
275: default :
276: DPRINTF(("ipsec_process_done: unknown protocol family %u\n",
277: saidx->dst.sa.sa_family));
278: error = ENXIO;
279: goto bad;
280: }
1.1 jonathan 281: }
282:
283: /*
1.25 degroote 284: * We're done with IPsec processing,
285: * mark that we have already processed the packet
286: * transmit it packet using the appropriate network protocol (IP or IPv6).
1.1 jonathan 287: */
1.25 degroote 288:
289: if (ipsec_register_done(m, &error) < 0)
290: goto bad;
291:
1.26 degroote 292: return ipsec_reinject_ipstack(m, saidx->dst.sa.sa_family);
1.1 jonathan 293: bad:
294: m_freem(m);
295: KEY_FREESAV(&sav);
296: return (error);
297: }
298:
1.26 degroote 299: /*
300: * ipsec_nextisr can return :
301: * - isr == NULL and error != 0 => something is bad : the packet must be
302: * discarded
303: * - isr == NULL and error == 0 => no more rules to apply, ipsec processing
304: * is done, reinject it in ip stack
305: * - isr != NULL (error == 0) => we need to apply one rule to the packet
306: */
1.1 jonathan 307: static struct ipsecrequest *
308: ipsec_nextisr(
309: struct mbuf *m,
310: struct ipsecrequest *isr,
311: int af,
312: struct secasindex *saidx,
313: int *error
314: )
315: {
1.27 ! thorpej 316: #define IPSEC_OSTAT(x, y, z) \
! 317: do { \
! 318: switch (isr->saidx.proto) { \
! 319: case IPPROTO_ESP: \
! 320: ESP_STATINC(x); \
! 321: break; \
! 322: case IPPROTO_AH: \
! 323: AH_STATINC(y); \
! 324: break; \
! 325: default: \
! 326: IPCOMP_STATINC(z); \
! 327: break; \
! 328: } \
! 329: } while (/*CONSTCOND*/0)
! 330:
1.1 jonathan 331: struct secasvar *sav;
332:
333: IPSEC_SPLASSERT_SOFTNET("ipsec_nextisr");
334: IPSEC_ASSERT(af == AF_INET || af == AF_INET6,
335: ("ipsec_nextisr: invalid address family %u", af));
336: again:
337: /*
338: * Craft SA index to search for proper SA. Note that
339: * we only fillin unspecified SA peers for transport
340: * mode; for tunnel mode they must already be filled in.
341: */
342: *saidx = isr->saidx;
343: if (isr->saidx.mode == IPSEC_MODE_TRANSPORT) {
344: /* Fillin unspecified SA peers only for transport mode */
345: if (af == AF_INET) {
346: struct sockaddr_in *sin;
347: struct ip *ip = mtod(m, struct ip *);
348:
349: if (saidx->src.sa.sa_len == 0) {
350: sin = &saidx->src.sin;
351: sin->sin_len = sizeof(*sin);
352: sin->sin_family = AF_INET;
353: sin->sin_port = IPSEC_PORT_ANY;
354: sin->sin_addr = ip->ip_src;
355: }
356: if (saidx->dst.sa.sa_len == 0) {
357: sin = &saidx->dst.sin;
358: sin->sin_len = sizeof(*sin);
359: sin->sin_family = AF_INET;
360: sin->sin_port = IPSEC_PORT_ANY;
361: sin->sin_addr = ip->ip_dst;
362: }
363: } else {
364: struct sockaddr_in6 *sin6;
365: struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
366:
367: if (saidx->src.sin6.sin6_len == 0) {
368: sin6 = (struct sockaddr_in6 *)&saidx->src;
369: sin6->sin6_len = sizeof(*sin6);
370: sin6->sin6_family = AF_INET6;
371: sin6->sin6_port = IPSEC_PORT_ANY;
372: sin6->sin6_addr = ip6->ip6_src;
373: if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) {
374: /* fix scope id for comparing SPD */
375: sin6->sin6_addr.s6_addr16[1] = 0;
376: sin6->sin6_scope_id =
377: ntohs(ip6->ip6_src.s6_addr16[1]);
378: }
379: }
380: if (saidx->dst.sin6.sin6_len == 0) {
381: sin6 = (struct sockaddr_in6 *)&saidx->dst;
382: sin6->sin6_len = sizeof(*sin6);
383: sin6->sin6_family = AF_INET6;
384: sin6->sin6_port = IPSEC_PORT_ANY;
385: sin6->sin6_addr = ip6->ip6_dst;
386: if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) {
387: /* fix scope id for comparing SPD */
388: sin6->sin6_addr.s6_addr16[1] = 0;
389: sin6->sin6_scope_id =
390: ntohs(ip6->ip6_dst.s6_addr16[1]);
391: }
392: }
393: }
394: }
395:
396: /*
397: * Lookup SA and validate it.
398: */
399: *error = key_checkrequest(isr, saidx);
400: if (*error != 0) {
401: /*
402: * IPsec processing is required, but no SA found.
403: * I assume that key_acquire() had been called
404: * to get/establish the SA. Here I discard
405: * this packet because it is responsibility for
406: * upper layer to retransmit the packet.
407: */
1.27 ! thorpej 408: IPSEC_STATINC(IPSEC_STAT_OUT_NOSA);
1.1 jonathan 409: goto bad;
410: }
411: sav = isr->sav;
1.26 degroote 412: /* sav may be NULL here if we have an USE rule */
413: if (sav == NULL) {
1.1 jonathan 414: IPSEC_ASSERT(ipsec_get_reqlevel(isr) == IPSEC_LEVEL_USE,
415: ("ipsec_nextisr: no SA found, but required; level %u",
416: ipsec_get_reqlevel(isr)));
417: isr = isr->next;
1.26 degroote 418: /*
419: * No more rules to apply, return NULL isr and no error
420: * It can happen when the last rules are USE rules
421: * */
1.1 jonathan 422: if (isr == NULL) {
1.26 degroote 423: *error = 0;
1.1 jonathan 424: return isr;
425: }
426: goto again;
427: }
428:
429: /*
430: * Check system global policy controls.
431: */
432: if ((isr->saidx.proto == IPPROTO_ESP && !esp_enable) ||
433: (isr->saidx.proto == IPPROTO_AH && !ah_enable) ||
434: (isr->saidx.proto == IPPROTO_IPCOMP && !ipcomp_enable)) {
435: DPRINTF(("ipsec_nextisr: IPsec outbound packet dropped due"
436: " to policy (check your sysctls)\n"));
1.27 ! thorpej 437: IPSEC_OSTAT(ESP_STAT_PDROPS, AH_STAT_PDROPS,
! 438: IPCOMP_STAT_PDROPS);
1.1 jonathan 439: *error = EHOSTUNREACH;
440: goto bad;
441: }
442:
443: /*
444: * Sanity check the SA contents for the caller
445: * before they invoke the xform output method.
446: */
447: if (sav->tdb_xform == NULL) {
448: DPRINTF(("ipsec_nextisr: no transform for SA\n"));
1.27 ! thorpej 449: IPSEC_OSTAT(ESP_STAT_NOXFORM, AH_STAT_NOXFORM,
! 450: IPCOMP_STAT_NOXFORM);
1.1 jonathan 451: *error = EHOSTUNREACH;
452: goto bad;
453: }
454: return isr;
455: bad:
456: IPSEC_ASSERT(*error != 0, ("ipsec_nextisr: error return w/ no error code"));
457: return NULL;
458: #undef IPSEC_OSTAT
459: }
460:
461: #ifdef INET
462: /*
463: * IPsec output logic for IPv4.
464: */
465: int
466: ipsec4_process_packet(
1.15 christos 467: struct mbuf *m,
468: struct ipsecrequest *isr,
1.16 christos 469: int flags,
1.15 christos 470: int tunalready
471: )
1.1 jonathan 472: {
473: struct secasindex saidx;
474: struct secasvar *sav;
475: struct ip *ip;
476: int s, error, i, off;
477:
478: IPSEC_ASSERT(m != NULL, ("ipsec4_process_packet: null mbuf"));
479: IPSEC_ASSERT(isr != NULL, ("ipsec4_process_packet: null isr"));
480:
481: s = splsoftnet(); /* insure SA contents don't change */
482:
483: isr = ipsec_nextisr(m, isr, AF_INET, &saidx, &error);
1.26 degroote 484: if (isr == NULL) {
485: if (error != 0) {
486: goto bad;
487: } else {
488: if (ipsec_register_done(m, &error) < 0)
489: goto bad;
490:
491: splx(s);
492: return ipsec_reinject_ipstack(m, AF_INET);
493: }
494: }
1.1 jonathan 495:
496: sav = isr->sav;
497: if (!tunalready) {
498: union sockaddr_union *dst = &sav->sah->saidx.dst;
499: int setdf;
500:
501: /*
502: * Collect IP_DF state from the outer header.
503: */
504: if (dst->sa.sa_family == AF_INET) {
505: if (m->m_len < sizeof (struct ip) &&
506: (m = m_pullup(m, sizeof (struct ip))) == NULL) {
507: error = ENOBUFS;
508: goto bad;
509: }
510: ip = mtod(m, struct ip *);
511: /* Honor system-wide control of how to handle IP_DF */
512: switch (ip4_ipsec_dfbit) {
513: case 0: /* clear in outer header */
514: case 1: /* set in outer header */
515: setdf = ip4_ipsec_dfbit;
516: break;
517: default: /* propagate to outer header */
1.3 jonathan 518: setdf = ip->ip_off;
519: #ifndef __FreeBSD__
520: /* On FreeBSD, ip_off and ip_len assumed in host endian. */
521: setdf = ntohs(setdf);
522: #endif
523: setdf = htons(setdf & IP_DF);
1.1 jonathan 524: break;
525: }
526: } else {
527: ip = NULL; /* keep compiler happy */
528: setdf = 0;
529: }
530: /* Do the appropriate encapsulation, if necessary */
531: if (isr->saidx.mode == IPSEC_MODE_TUNNEL || /* Tunnel requ'd */
532: dst->sa.sa_family != AF_INET || /* PF mismatch */
533: #if 0
534: (sav->flags & SADB_X_SAFLAGS_TUNNEL) || /* Tunnel requ'd */
535: sav->tdb_xform->xf_type == XF_IP4 || /* ditto */
536: #endif
537: (dst->sa.sa_family == AF_INET && /* Proxy */
538: dst->sin.sin_addr.s_addr != INADDR_ANY &&
539: dst->sin.sin_addr.s_addr != ip->ip_dst.s_addr)) {
540: struct mbuf *mp;
541:
542: /* Fix IPv4 header checksum and length */
543: if (m->m_len < sizeof (struct ip) &&
544: (m = m_pullup(m, sizeof (struct ip))) == NULL) {
545: error = ENOBUFS;
546: goto bad;
547: }
548: ip = mtod(m, struct ip *);
549: ip->ip_len = htons(m->m_pkthdr.len);
550: ip->ip_sum = 0;
551: ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
552:
553: /* Encapsulate the packet */
554: error = ipip_output(m, isr, &mp, 0, 0);
555: if (mp == NULL && !error) {
556: /* Should never happen. */
557: DPRINTF(("ipsec4_process_packet: ipip_output "
558: "returns no mbuf and no error!"));
559: error = EFAULT;
560: }
561: if (error) {
1.8 scw 562: if (mp) {
563: /* XXX: Should never happen! */
1.1 jonathan 564: m_freem(mp);
1.8 scw 565: }
566: m = NULL; /* ipip_output() already freed it */
1.1 jonathan 567: goto bad;
568: }
569: m = mp, mp = NULL;
570: /*
571: * ipip_output clears IP_DF in the new header. If
572: * we need to propagate IP_DF from the outer header,
573: * then we have to do it here.
574: *
575: * XXX shouldn't assume what ipip_output does.
576: */
577: if (dst->sa.sa_family == AF_INET && setdf) {
578: if (m->m_len < sizeof (struct ip) &&
579: (m = m_pullup(m, sizeof (struct ip))) == NULL) {
580: error = ENOBUFS;
581: goto bad;
582: }
583: ip = mtod(m, struct ip *);
1.23 adrianp 584: ip->ip_off |= IP_OFF_CONVERT(IP_DF);
1.1 jonathan 585: }
586: }
587: }
588:
589: /*
590: * Dispatch to the appropriate IPsec transform logic. The
591: * packet will be returned for transmission after crypto
592: * processing, etc. are completed. For encapsulation we
593: * bypass this call because of the explicit call done above
594: * (necessary to deal with IP_DF handling for IPv4).
595: *
596: * NB: m & sav are ``passed to caller'' who's reponsible for
597: * for reclaiming their resources.
598: */
599: if (sav->tdb_xform->xf_type != XF_IP4) {
600: ip = mtod(m, struct ip *);
601: i = ip->ip_hl << 2;
602: off = offsetof(struct ip, ip_p);
603: error = (*sav->tdb_xform->xf_output)(m, isr, NULL, i, off);
604: } else {
605: error = ipsec_process_done(m, isr);
606: }
607: splx(s);
608: return error;
609: bad:
610: splx(s);
611: if (m)
612: m_freem(m);
613: return error;
614: }
615: #endif
616:
617: #ifdef INET6
618: int
1.21 degroote 619: ipsec6_process_packet(
620: struct mbuf *m,
621: struct ipsecrequest *isr
622: )
1.1 jonathan 623: {
624: struct secasindex saidx;
1.21 degroote 625: struct secasvar *sav;
626: struct ip6_hdr *ip6;
627: int s, error, i, off;
1.1 jonathan 628:
1.21 degroote 629: IPSEC_ASSERT(m != NULL, ("ipsec6_process_packet: null mbuf"));
630: IPSEC_ASSERT(isr != NULL, ("ipsec6_process_packet: null isr"));
1.1 jonathan 631:
1.21 degroote 632: s = splsoftnet(); /* insure SA contents don't change */
1.1 jonathan 633: isr = ipsec_nextisr(m, isr, AF_INET6, &saidx, &error);
634: if (isr == NULL) {
1.26 degroote 635: if (error != 0) {
636: // XXX Should we send a notification ?
637: goto bad;
638: } else {
639: if (ipsec_register_done(m, &error) < 0)
640: goto bad;
641:
642: splx(s);
643: return ipsec_reinject_ipstack(m, AF_INET);
644: }
1.1 jonathan 645: }
646:
1.21 degroote 647: sav = isr->sav;
648: if (sav->tdb_xform->xf_type != XF_IP4) {
649: i = sizeof(struct ip6_hdr);
650: off = offsetof(struct ip6_hdr, ip6_nxt);
651: error = (*sav->tdb_xform->xf_output)(m, isr, NULL, i, off);
652: } else {
653: union sockaddr_union *dst = &sav->sah->saidx.dst;
1.1 jonathan 654:
1.21 degroote 655: ip6 = mtod(m, struct ip6_hdr *);
1.1 jonathan 656:
1.21 degroote 657: /* Do the appropriate encapsulation, if necessary */
658: if (isr->saidx.mode == IPSEC_MODE_TUNNEL || /* Tunnel requ'd */
659: dst->sa.sa_family != AF_INET6 || /* PF mismatch */
660: ((dst->sa.sa_family == AF_INET6) &&
661: (!IN6_IS_ADDR_UNSPECIFIED(&dst->sin6.sin6_addr)) &&
662: (!IN6_ARE_ADDR_EQUAL(&dst->sin6.sin6_addr,
663: &ip6->ip6_dst)))
664: )
665: {
666: struct mbuf *mp;
667: /* Fix IPv6 header payload length. */
668: if (m->m_len < sizeof(struct ip6_hdr))
669: if ((m = m_pullup(m,sizeof(struct ip6_hdr))) == NULL)
670: return ENOBUFS;
671:
672: if (m->m_pkthdr.len - sizeof(*ip6) > IPV6_MAXPACKET) {
673: /* No jumbogram support. */
674: m_freem(m);
675: return ENXIO; /*XXX*/
676: }
677: ip6 = mtod(m, struct ip6_hdr *);
678: ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6));
1.1 jonathan 679:
1.21 degroote 680: /* Encapsulate the packet */
681: error = ipip_output(m, isr, &mp, 0, 0);
682: if (mp == NULL && !error) {
683: /* Should never happen. */
684: DPRINTF(("ipsec6_process_packet: ipip_output "
685: "returns no mbuf and no error!"));
686: error = EFAULT;
687: }
1.1 jonathan 688:
1.21 degroote 689: if (error) {
690: if (mp) {
691: /* XXX: Should never happen! */
692: m_freem(mp);
693: }
694: m = NULL; /* ipip_output() already freed it */
1.19 joerg 695: goto bad;
696: }
1.21 degroote 697:
698: m = mp;
699: mp = NULL;
1.1 jonathan 700: }
1.21 degroote 701:
702: error = ipsec_process_done(m,isr);
1.1 jonathan 703: }
1.21 degroote 704: splx(s);
705: return error;
1.1 jonathan 706: bad:
1.21 degroote 707: splx(s);
1.1 jonathan 708: if (m)
709: m_freem(m);
710: return error;
711: }
712: #endif /*INET6*/
CVSweb <webmaster@jp.NetBSD.org>