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