]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/netkey/key.c
xnu-3248.60.10.tar.gz
[apple/xnu.git] / bsd / netkey / key.c
index f80c0c0adbd3186e3db6bb6651854c3eb4077ecd..7a0c50b89fee71461ec8cdccb7b1a69272d1903e 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2008-2013 Apple Inc. All rights reserved.
+ * Copyright (c) 2008-2016 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  *
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  *
 #include <netinet6/ip6_var.h>
 #endif /* INET6 */
 
 #include <netinet6/ip6_var.h>
 #endif /* INET6 */
 
-#if INET
-#include <netinet/in_pcb.h>
-#endif
-#if INET6
-#include <netinet6/in6_pcb.h>
-#endif /* INET6 */
-
 #include <net/pfkeyv2.h>
 #include <netkey/keydb.h>
 #include <netkey/key.h>
 #include <net/pfkeyv2.h>
 #include <netkey/keydb.h>
 #include <netkey/key.h>
@@ -241,6 +234,9 @@ static const int minsize[] = {
        sizeof(struct sadb_address),    /* SADB_X_EXT_ADDR_RANGE_SRC_END */
     sizeof(struct sadb_address),       /* SADB_X_EXT_ADDR_RANGE_DST_START */
        sizeof(struct sadb_address),    /* SADB_X_EXT_ADDR_RANGE_DST_END */
        sizeof(struct sadb_address),    /* SADB_X_EXT_ADDR_RANGE_SRC_END */
     sizeof(struct sadb_address),       /* SADB_X_EXT_ADDR_RANGE_DST_START */
        sizeof(struct sadb_address),    /* SADB_X_EXT_ADDR_RANGE_DST_END */
+       sizeof(struct sadb_address),    /* SADB_EXT_MIGRATE_ADDRESS_SRC */
+       sizeof(struct sadb_address),    /* SADB_EXT_MIGRATE_ADDRESS_DST */
+       sizeof(struct sadb_x_ipsecif),  /* SADB_X_EXT_MIGRATE_IPSECIF */
 };
 static const int maxsize[] = {
        sizeof(struct sadb_msg),        /* SADB_EXT_RESERVED */
 };
 static const int maxsize[] = {
        sizeof(struct sadb_msg),        /* SADB_EXT_RESERVED */
@@ -270,6 +266,9 @@ static const int maxsize[] = {
        0,              /* SADB_X_EXT_ADDR_RANGE_SRC_END */
     0,              /* SADB_X_EXT_ADDR_RANGE_DST_START */
        0,              /* SADB_X_EXT_ADDR_RANGE_DST_END */
        0,              /* SADB_X_EXT_ADDR_RANGE_SRC_END */
     0,              /* SADB_X_EXT_ADDR_RANGE_DST_START */
        0,              /* SADB_X_EXT_ADDR_RANGE_DST_END */
+       0,              /* SADB_EXT_MIGRATE_ADDRESS_SRC */
+       0,              /* SADB_EXT_MIGRATE_ADDRESS_DST */
+       sizeof(struct sadb_x_ipsecif), /* SADB_X_EXT_MIGRATE_IPSECIF */
 };
 
 static int ipsec_esp_keymin = 256;
 };
 
 static int ipsec_esp_keymin = 256;
@@ -422,7 +421,7 @@ if (d_e) bcopy((d_e), &(idx)->dst_range.end, ((struct sockaddr *)(d_e))->sa_len)
  * set parameters into secasindex buffer.
  * Must allocate secasindex buffer before calling this function.
  */
  * set parameters into secasindex buffer.
  * Must allocate secasindex buffer before calling this function.
  */
-#define KEY_SETSECASIDX(p, m, r, s, d, idx) \
+#define KEY_SETSECASIDX(p, m, r, s, d, ifi, idx) \
 do { \
 bzero((idx), sizeof(struct secasindex));                             \
 (idx)->proto = (p);                                                  \
 do { \
 bzero((idx), sizeof(struct secasindex));                             \
 (idx)->proto = (p);                                                  \
@@ -430,6 +429,7 @@ bzero((idx), sizeof(struct secasindex));                             \
 (idx)->reqid = (r);                                                  \
 bcopy((s), &(idx)->src, ((const struct sockaddr *)(s))->sa_len);           \
 bcopy((d), &(idx)->dst, ((const struct sockaddr *)(d))->sa_len);           \
 (idx)->reqid = (r);                                                  \
 bcopy((s), &(idx)->src, ((const struct sockaddr *)(s))->sa_len);           \
 bcopy((d), &(idx)->dst, ((const struct sockaddr *)(d))->sa_len);           \
+(idx)->ipsec_ifindex = (ifi);                                                                          \
 } while (0)
 
 /* key statistics */
 } while (0)
 
 /* key statistics */
@@ -473,9 +473,10 @@ static struct mbuf *key_setdumpsp(struct secpolicy *,
                                                                  u_int8_t, u_int32_t, u_int32_t);
 static u_int key_getspreqmsglen(struct secpolicy *);
 static int key_spdexpire(struct secpolicy *);
                                                                  u_int8_t, u_int32_t, u_int32_t);
 static u_int key_getspreqmsglen(struct secpolicy *);
 static int key_spdexpire(struct secpolicy *);
-static struct secashead *key_newsah(struct secasindex *, u_int8_t);
+static struct secashead *key_newsah(struct secasindex *, ifnet_t, u_int, u_int8_t);
 static struct secasvar *key_newsav(struct mbuf *,
 static struct secasvar *key_newsav(struct mbuf *,
-                                                                  const struct sadb_msghdr *, struct secashead *, int *);
+                                                                  const struct sadb_msghdr *, struct secashead *, int *,
+                                                                  struct socket *);
 static struct secashead *key_getsah(struct secasindex *);
 static struct secasvar *key_checkspidup(struct secasindex *, u_int32_t);
 static void key_setspi __P((struct secasvar *, u_int32_t));
 static struct secashead *key_getsah(struct secasindex *);
 static struct secasvar *key_checkspidup(struct secasindex *, u_int32_t);
 static void key_setspi __P((struct secasvar *, u_int32_t));
@@ -495,7 +496,7 @@ static struct mbuf *key_setsadbipsecif(ifnet_t, ifnet_t, ifnet_t, int);
 static struct mbuf *key_setsadbident(u_int16_t, u_int16_t, caddr_t,
                                                                         int, u_int64_t);
 #endif
 static struct mbuf *key_setsadbident(u_int16_t, u_int16_t, caddr_t,
                                                                         int, u_int64_t);
 #endif
-static struct mbuf *key_setsadbxsa2(u_int8_t, u_int32_t, u_int32_t);
+static struct mbuf *key_setsadbxsa2(u_int8_t, u_int32_t, u_int32_t, u_int16_t);
 static struct mbuf *key_setsadbxpolicy(u_int16_t, u_int8_t,
                                                                           u_int32_t);
 static void *key_newbuf(const void *, u_int);
 static struct mbuf *key_setsadbxpolicy(u_int16_t, u_int8_t,
                                                                           u_int32_t);
 static void *key_newbuf(const void *, u_int);
@@ -570,6 +571,7 @@ static int key_validate_ext(const struct sadb_ext *, int);
 static int key_align(struct mbuf *, struct sadb_msghdr *);
 static struct mbuf *key_alloc_mbuf(int);
 static int key_getsastat (struct socket *, struct mbuf *, const struct sadb_msghdr *);
 static int key_align(struct mbuf *, struct sadb_msghdr *);
 static struct mbuf *key_alloc_mbuf(int);
 static int key_getsastat (struct socket *, struct mbuf *, const struct sadb_msghdr *);
+static int key_migrate (struct socket *, struct mbuf *, const struct sadb_msghdr *);
 static int key_setsaval2(struct secasvar      *sav,
                                                 u_int8_t              satype,
                                                 u_int8_t              alg_auth,
 static int key_setsaval2(struct secasvar      *sav,
                                                 u_int8_t              satype,
                                                 u_int8_t              alg_auth,
@@ -586,10 +588,13 @@ static int key_setsaval2(struct secasvar      *sav,
                                                 u_int32_t             pid,
                                                 struct sadb_lifetime *lifetime_hard,
                                                 struct sadb_lifetime *lifetime_soft);
                                                 u_int32_t             pid,
                                                 struct sadb_lifetime *lifetime_hard,
                                                 struct sadb_lifetime *lifetime_soft);
+static void bzero_keys(const struct sadb_msghdr *);
 
 extern int ipsec_bypass;
 extern int esp_udp_encap_port;
 int ipsec_send_natt_keepalive(struct secasvar *sav);
 
 extern int ipsec_bypass;
 extern int esp_udp_encap_port;
 int ipsec_send_natt_keepalive(struct secasvar *sav);
+bool ipsec_fill_offload_frame(ifnet_t ifp, struct secasvar *sav, struct ifnet_keepalive_offload_frame *frame, size_t frame_data_offset);
+u_int32_t key_fill_offload_frames_for_savs (ifnet_t ifp, struct ifnet_keepalive_offload_frame *frames_array, u_int32_t frames_array_count, size_t frame_data_offset);
 
 void key_init(struct protosw *, struct domain *);
 
 
 void key_init(struct protosw *, struct domain *);
 
@@ -673,12 +678,14 @@ key_start_timehandler(void)
 {
        /* must be called while locked */
        lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
 {
        /* must be called while locked */
        lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
-#ifndef IPSEC_DEBUG2
        if (key_timehandler_running == 0) {
                key_timehandler_running = 1;
                (void)timeout((void *)key_timehandler, (void *)0, hz);
        }
        if (key_timehandler_running == 0) {
                key_timehandler_running = 1;
                (void)timeout((void *)key_timehandler, (void *)0, hz);
        }
-#endif /*IPSEC_DEBUG2*/
+       
+       /* Turn off the ipsec bypass */
+       if (ipsec_bypass != 0)
+               ipsec_bypass = 0;
 }
 
 /* %%% IPsec policy management */
 }
 
 /* %%% IPsec policy management */
@@ -831,6 +838,59 @@ found:
        return sp;
 }
 
        return sp;
 }
 
+struct secasvar *key_alloc_outbound_sav_for_interface(ifnet_t interface, int family)
+{
+       struct secashead *sah;
+       struct secasvar *sav;
+       u_int stateidx;
+       u_int state;
+       const u_int *saorder_state_valid;
+       int arraysize;
+       struct sockaddr_in *sin;
+       u_int16_t dstport;
+    
+       if (interface == NULL)
+        return NULL;
+       
+       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
+       
+       lck_mtx_lock(sadb_mutex);
+       
+       LIST_FOREACH(sah, &sahtree, chain) {
+               if (sah->ipsec_if == interface &&
+                       (family == AF_INET6 || family == AF_INET) &&
+                       sah->dir == IPSEC_DIR_OUTBOUND) {
+                       /* This SAH is linked to the IPSec interface, and the right family. We found it! */
+                       if (key_preferred_oldsa) {
+                               saorder_state_valid = saorder_state_valid_prefer_old;
+                               arraysize = _ARRAYLEN(saorder_state_valid_prefer_old);
+                       } else {
+                               saorder_state_valid = saorder_state_valid_prefer_new;
+                               arraysize = _ARRAYLEN(saorder_state_valid_prefer_new);
+                       }
+                       
+                       sin = (struct sockaddr_in *)&sah->saidx.dst;
+                       dstport = sin->sin_port;
+                       if (sah->saidx.mode == IPSEC_MODE_TRANSPORT)
+                               sin->sin_port = IPSEC_PORT_ANY;
+                       
+                       for (stateidx = 0; stateidx < arraysize; stateidx++) {
+                               state = saorder_state_valid[stateidx];
+                               sav = key_do_allocsa_policy(sah, state, dstport);
+                               if (sav != NULL) {
+                                       lck_mtx_unlock(sadb_mutex);
+                                       return sav;
+                               }
+                       }
+                       
+                       break;
+               }
+       }
+       
+       lck_mtx_unlock(sadb_mutex);
+       return NULL;
+}
+
 /*
  * allocating an SA entry for an *OUTBOUND* packet.
  * checking each request entries in SP, and acquire an SA if need.
 /*
  * allocating an SA entry for an *OUTBOUND* packet.
  * checking each request entries in SP, and acquire an SA if need.
@@ -1441,7 +1501,6 @@ key_do_get_translated_port(
 
 /*
  * Must be called after calling key_allocsp().
 
 /*
  * Must be called after calling key_allocsp().
- * For both the packet without socket and key_freeso().
  */
 void
 key_freesp(
  */
 void
 key_freesp(
@@ -1469,102 +1528,6 @@ key_freesp(
        return;
 }
 
        return;
 }
 
-#if 0
-static void key_freesp_so(struct secpolicy **);
-
-/*
- * Must be called after calling key_allocsp().
- * For the packet with socket.
- */
-void
-key_freeso(
-                  struct socket *so)
-{
-       
-       /* sanity check */
-       if (so == NULL)
-               panic("key_freeso: NULL pointer is passed.\n");
-       
-       lck_mtx_lock(sadb_mutex);
-       switch (SOCK_DOM(so)) {
-#if INET
-               case PF_INET:
-           {
-                       struct inpcb *pcb = sotoinpcb(so);
-                       
-                       /* Does it have a PCB ? */
-                       if (pcb == NULL || pcb->inp_sp == NULL)
-                               goto done;
-                       key_freesp_so(&pcb->inp_sp->sp_in);
-                       key_freesp_so(&pcb->inp_sp->sp_out);
-           }
-                       break;
-#endif
-#if INET6
-               case PF_INET6:
-           {
-#if HAVE_NRL_INPCB
-                       struct inpcb *pcb  = sotoinpcb(so);
-                       
-                       /* Does it have a PCB ? */
-                       if (pcb == NULL || pcb->inp_sp == NULL)
-                               goto done;
-                       key_freesp_so(&pcb->inp_sp->sp_in);
-                       key_freesp_so(&pcb->inp_sp->sp_out);
-#else
-                       struct in6pcb *pcb  = sotoin6pcb(so);
-                       
-                       /* Does it have a PCB ? */
-                       if (pcb == NULL || pcb->in6p_sp == NULL)
-                               goto done;
-                       key_freesp_so(&pcb->in6p_sp->sp_in);
-                       key_freesp_so(&pcb->in6p_sp->sp_out);
-#endif
-           }
-                       break;
-#endif /* INET6 */
-               default:
-                       ipseclog((LOG_DEBUG, "key_freeso: unknown address family=%d.\n",
-                           SOCK_DOM(so)));
-                       break;
-       }
-done:
-       lck_mtx_unlock(sadb_mutex);
-       
-       return;
-}
-
-static void
-key_freesp_so(
-                         struct secpolicy **sp)
-{
-       
-       /* sanity check */
-       if (sp == NULL || *sp == NULL)
-               panic("key_freesp_so: sp == NULL\n");
-       
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
-       
-       switch ((*sp)->policy) {
-               case IPSEC_POLICY_IPSEC:
-                       KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
-                           printf("DP freeso calls free SP:0x%llx\n",
-                           (uint64_t)VM_KERNEL_ADDRPERM(*sp)));
-                       key_freesp(*sp, KEY_SADB_LOCKED);
-                       *sp = NULL;
-                       break;
-               case IPSEC_POLICY_ENTRUST:
-               case IPSEC_POLICY_BYPASS:
-                       return;
-               default:
-                       panic("key_freesp_so: Invalid policy found %d", (*sp)->policy);
-       }
-       
-       return;
-}
-
-#endif
-
 /*
  * Must be called after calling key_allocsa().
  * This function is called by key_freesp() to free some SA allocated
 /*
  * Must be called after calling key_allocsa().
  * This function is called by key_freesp() to free some SA allocated
@@ -2267,7 +2230,7 @@ key_spdadd(
         }
     }
     
         }
     }
     
-    /* checking the direciton. */
+    /* checking the direction. */
        switch (xpl0->sadb_x_policy_dir) {
         case IPSEC_DIR_INBOUND:
         case IPSEC_DIR_OUTBOUND:
        switch (xpl0->sadb_x_policy_dir) {
         case IPSEC_DIR_INBOUND:
         case IPSEC_DIR_OUTBOUND:
@@ -2296,13 +2259,13 @@ key_spdadd(
     
     /* Process interfaces */
     if (ipsecifopts != NULL) {
     
     /* Process interfaces */
     if (ipsecifopts != NULL) {
-        if (ipsecifopts->sadb_x_ipsecif_internal_if) {
+        if (ipsecifopts->sadb_x_ipsecif_internal_if[0]) {
             ifnet_find_by_name(ipsecifopts->sadb_x_ipsecif_internal_if, &internal_if);
         }
             ifnet_find_by_name(ipsecifopts->sadb_x_ipsecif_internal_if, &internal_if);
         }
-        if (ipsecifopts->sadb_x_ipsecif_outgoing_if) {
+        if (ipsecifopts->sadb_x_ipsecif_outgoing_if[0]) {
             outgoing_if = ipsecifopts->sadb_x_ipsecif_outgoing_if;
         }
             outgoing_if = ipsecifopts->sadb_x_ipsecif_outgoing_if;
         }
-        if (ipsecifopts->sadb_x_ipsecif_ipsec_if) {
+        if (ipsecifopts->sadb_x_ipsecif_ipsec_if[0]) {
             ipsec_if = ipsecifopts->sadb_x_ipsecif_ipsec_if;
         }
                init_disabled = ipsecifopts->sadb_x_ipsecif_init_disabled;
             ipsec_if = ipsecifopts->sadb_x_ipsecif_ipsec_if;
         }
                init_disabled = ipsecifopts->sadb_x_ipsecif_init_disabled;
@@ -2384,15 +2347,14 @@ key_spdadd(
        
 #if 1
        /*
        
 #if 1
        /*
-        * allow IPv6 over IPv4 tunnels using ESP -
+        * allow IPv6 over IPv4 or IPv4 over IPv6 tunnels using ESP -
         * otherwise reject if inner and outer address families not equal
         */
        if (newsp->req && newsp->req->saidx.src.ss_family) {
                struct sockaddr *sa;
                sa = (struct sockaddr *)(src0 + 1);
                if (sa->sa_family != newsp->req->saidx.src.ss_family) {
         * otherwise reject if inner and outer address families not equal
         */
        if (newsp->req && newsp->req->saidx.src.ss_family) {
                struct sockaddr *sa;
                sa = (struct sockaddr *)(src0 + 1);
                if (sa->sa_family != newsp->req->saidx.src.ss_family) {
-                       if (newsp->req->saidx.mode != IPSEC_MODE_TUNNEL || newsp->req->saidx.proto != IPPROTO_ESP
-                           || sa->sa_family != AF_INET6 || newsp->req->saidx.src.ss_family != AF_INET) {
+                       if (newsp->req->saidx.mode != IPSEC_MODE_TUNNEL || newsp->req->saidx.proto != IPPROTO_ESP) {
                                keydb_delsecpolicy(newsp);
                 if (internal_if) {
                     ifnet_release(internal_if);
                                keydb_delsecpolicy(newsp);
                 if (internal_if) {
                     ifnet_release(internal_if);
@@ -2406,8 +2368,7 @@ key_spdadd(
                struct sockaddr *sa;
                sa = (struct sockaddr *)(dst0 + 1);
                if (sa->sa_family != newsp->req->saidx.dst.ss_family) {
                struct sockaddr *sa;
                sa = (struct sockaddr *)(dst0 + 1);
                if (sa->sa_family != newsp->req->saidx.dst.ss_family) {
-                       if (newsp->req->saidx.mode != IPSEC_MODE_TUNNEL || newsp->req->saidx.proto != IPPROTO_ESP
-                           || sa->sa_family != AF_INET6 || newsp->req->saidx.dst.ss_family != AF_INET) {
+                       if (newsp->req->saidx.mode != IPSEC_MODE_TUNNEL || newsp->req->saidx.proto != IPPROTO_ESP) {
                                keydb_delsecpolicy(newsp);
                 if (internal_if) {
                     ifnet_release(internal_if);
                                keydb_delsecpolicy(newsp);
                 if (internal_if) {
                     ifnet_release(internal_if);
@@ -2629,7 +2590,7 @@ key_spddelete(
        xpl0 = (struct sadb_x_policy *)(void *)mhp->ext[SADB_X_EXT_POLICY];
     ipsecifopts = (struct sadb_x_ipsecif *)(void *)mhp->ext[SADB_X_EXT_IPSECIF];
     
        xpl0 = (struct sadb_x_policy *)(void *)mhp->ext[SADB_X_EXT_POLICY];
     ipsecifopts = (struct sadb_x_ipsecif *)(void *)mhp->ext[SADB_X_EXT_IPSECIF];
     
-    /* checking the direciton. */
+    /* checking the direction. */
        switch (xpl0->sadb_x_policy_dir) {
         case IPSEC_DIR_INBOUND:
         case IPSEC_DIR_OUTBOUND:
        switch (xpl0->sadb_x_policy_dir) {
         case IPSEC_DIR_INBOUND:
         case IPSEC_DIR_OUTBOUND:
@@ -2641,7 +2602,7 @@ key_spddelete(
     
     /* Process interfaces */
     if (ipsecifopts != NULL) {
     
     /* Process interfaces */
     if (ipsecifopts != NULL) {
-        if (ipsecifopts->sadb_x_ipsecif_internal_if) {
+        if (ipsecifopts->sadb_x_ipsecif_internal_if[0]) {
             ifnet_find_by_name(ipsecifopts->sadb_x_ipsecif_internal_if, &internal_if);
         }
     }
             ifnet_find_by_name(ipsecifopts->sadb_x_ipsecif_internal_if, &internal_if);
         }
     }
@@ -3487,9 +3448,10 @@ fail:
  *     others  : pointer to new SA head.
  */
 static struct secashead *
  *     others  : pointer to new SA head.
  */
 static struct secashead *
-key_newsah(
-                  struct secasindex *saidx,
-                  u_int8_t           dir)
+key_newsah(struct secasindex *saidx,
+                  ifnet_t ipsec_if,
+                  u_int outgoing_if,
+                  u_int8_t dir)
 {
        struct secashead *newsah;
        
 {
        struct secashead *newsah;
        
@@ -3525,11 +3487,17 @@ key_newsah(
                        break;
        }
        
                        break;
        }
        
+       newsah->outgoing_if = outgoing_if;
+       if (ipsec_if) {
+               ifnet_reference(ipsec_if);
+               newsah->ipsec_if = ipsec_if;
+       }
        newsah->dir = dir;
        /* add to saidxtree */
        newsah->state = SADB_SASTATE_MATURE;
        LIST_INSERT_HEAD(&sahtree, newsah, chain);
        key_start_timehandler();
        newsah->dir = dir;
        /* add to saidxtree */
        newsah->state = SADB_SASTATE_MATURE;
        LIST_INSERT_HEAD(&sahtree, newsah, chain);
        key_start_timehandler();
+
        return(newsah);
 }
 
        return(newsah);
 }
 
@@ -3585,6 +3553,11 @@ key_delsah(
        
        ROUTE_RELEASE(&sah->sa_route);
     
        
        ROUTE_RELEASE(&sah->sa_route);
     
+       if (sah->ipsec_if) {
+               ifnet_release(sah->ipsec_if);
+               sah->ipsec_if = NULL;
+       }
+       
     if (sah->idents) {
         KFREE(sah->idents);
     }
     if (sah->idents) {
         KFREE(sah->idents);
     }
@@ -3619,7 +3592,8 @@ key_newsav(
                   struct mbuf *m,
                   const struct sadb_msghdr *mhp,
                   struct secashead *sah,
                   struct mbuf *m,
                   const struct sadb_msghdr *mhp,
                   struct secashead *sah,
-                  int *errp)
+                  int *errp,
+                  struct socket *so)
 {
        struct secasvar *newsav;
        const struct sadb_sa *xsa;
 {
        struct secasvar *newsav;
        const struct sadb_sa *xsa;
@@ -3660,7 +3634,7 @@ key_newsav(
                case SADB_ADD:
                        /* sanity check */
                        if (mhp->ext[SADB_EXT_SA] == NULL) {
                case SADB_ADD:
                        /* sanity check */
                        if (mhp->ext[SADB_EXT_SA] == NULL) {
-                               KFREE(newsav);
+                               key_delsav(newsav);
                                ipseclog((LOG_DEBUG, "key_newsa: invalid message is passed.\n"));
                                *errp = EINVAL;
                                return NULL;
                                ipseclog((LOG_DEBUG, "key_newsa: invalid message is passed.\n"));
                                *errp = EINVAL;
                                return NULL;
@@ -3670,7 +3644,7 @@ key_newsav(
                        newsav->seq = mhp->msg->sadb_msg_seq;
                        break;
                default:
                        newsav->seq = mhp->msg->sadb_msg_seq;
                        break;
                default:
-                       KFREE(newsav);
+                       key_delsav(newsav);
                        *errp = EINVAL;
                        return NULL;
        }
                        *errp = EINVAL;
                        return NULL;
        }
@@ -3678,15 +3652,17 @@ key_newsav(
        if (mhp->ext[SADB_X_EXT_SA2] != NULL) {
                if (((struct sadb_x_sa2 *)(void *)mhp->ext[SADB_X_EXT_SA2])->sadb_x_sa2_alwaysexpire)
                        newsav->always_expire = 1;
        if (mhp->ext[SADB_X_EXT_SA2] != NULL) {
                if (((struct sadb_x_sa2 *)(void *)mhp->ext[SADB_X_EXT_SA2])->sadb_x_sa2_alwaysexpire)
                        newsav->always_expire = 1;
+               newsav->flags2 = ((struct sadb_x_sa2 *)(void *)mhp->ext[SADB_X_EXT_SA2])->sadb_x_sa2_flags;
+               if (newsav->flags2 & SADB_X_EXT_SA2_DELETE_ON_DETACH) {
+                       newsav->so = so;
+               }
        }
        
        /* copy sav values */
        if (mhp->msg->sadb_msg_type != SADB_GETSPI) {
                *errp = key_setsaval(newsav, m, mhp);
                if (*errp) {
        }
        
        /* copy sav values */
        if (mhp->msg->sadb_msg_type != SADB_GETSPI) {
                *errp = key_setsaval(newsav, m, mhp);
                if (*errp) {
-                       if (newsav->spihash.le_prev || newsav->spihash.le_next)
-                               LIST_REMOVE(newsav, spihash);
-                       KFREE(newsav);
+                       key_delsav(newsav);
                        return NULL;
                }
        } else {
                        return NULL;
                }
        } else {
@@ -3706,7 +3682,7 @@ key_newsav(
                                lck_mtx_lock(sadb_mutex);
                                if (newsav->lft_c == NULL) {
                                        ipseclog((LOG_DEBUG, "key_newsa: No more memory.\n"));
                                lck_mtx_lock(sadb_mutex);
                                if (newsav->lft_c == NULL) {
                                        ipseclog((LOG_DEBUG, "key_newsa: No more memory.\n"));
-                                       KFREE(newsav);
+                                       key_delsav(newsav);
                                        *errp = ENOBUFS;
                                        return NULL;
                                }
                                        *errp = ENOBUFS;
                                        return NULL;
                                }
@@ -3723,14 +3699,14 @@ key_newsav(
                        
                        if (mhp->extlen[SADB_EXT_LIFETIME_HARD] < sizeof(*lft0)) {
                                ipseclog((LOG_DEBUG, "key_newsa: invalid hard lifetime ext len.\n"));
                        
                        if (mhp->extlen[SADB_EXT_LIFETIME_HARD] < sizeof(*lft0)) {
                                ipseclog((LOG_DEBUG, "key_newsa: invalid hard lifetime ext len.\n"));
-                               KFREE(newsav);
+                               key_delsav(newsav);
                                *errp = EINVAL;
                                return NULL;
                        }
                        newsav->lft_h = (struct sadb_lifetime *)key_newbuf(lft0, sizeof(*lft0));
                        if (newsav->lft_h == NULL) {
                                ipseclog((LOG_DEBUG, "key_newsa: No more memory.\n"));
                                *errp = EINVAL;
                                return NULL;
                        }
                        newsav->lft_h = (struct sadb_lifetime *)key_newbuf(lft0, sizeof(*lft0));
                        if (newsav->lft_h == NULL) {
                                ipseclog((LOG_DEBUG, "key_newsa: No more memory.\n"));
-                               KFREE(newsav);
+                               key_delsav(newsav);
                                *errp = ENOBUFS;
                                return NULL;
                        }
                                *errp = ENOBUFS;
                                return NULL;
                        }
@@ -3830,9 +3806,7 @@ key_newsav2(struct secashead     *sah,
                                          pid,
                                          lifetime_hard,
                                          lifetime_soft)) {
                                          pid,
                                          lifetime_hard,
                                          lifetime_soft)) {
-               if (newsav->spihash.le_prev || newsav->spihash.le_next)
-                       LIST_REMOVE(newsav, spihash);
-               KFREE(newsav);
+               key_delsav(newsav);
                return NULL;
        }
        
                return NULL;
        }
        
@@ -3862,6 +3836,23 @@ key_newsav2(struct secashead     *sah,
        return newsav;
 }
 
        return newsav;
 }
 
+static int
+key_migratesav(struct secasvar *sav,
+                          struct secashead *newsah)
+{
+       if (sav == NULL || newsah == NULL || sav->state != SADB_SASTATE_MATURE) {
+               return EINVAL;
+       }
+       
+       /* remove from SA header */
+       if (__LIST_CHAINED(sav))
+               LIST_REMOVE(sav, chain);
+       
+       sav->sah = newsah;
+       LIST_INSERT_TAIL(&newsah->savtree[SADB_SASTATE_MATURE], sav, secasvar, chain);
+       return 0;
+}
+
 /*
  * free() SA variable entry.
  */
 /*
  * free() SA variable entry.
  */
@@ -3935,8 +3926,7 @@ key_delsav(
  *     others  : found, pointer to a SA.
  */
 static struct secashead *
  *     others  : found, pointer to a SA.
  */
 static struct secashead *
-key_getsah(
-                  struct secasindex *saidx)
+key_getsah(struct secasindex *saidx)
 {
        struct secashead *sah;
        
 {
        struct secashead *sah;
        
@@ -3962,7 +3952,7 @@ key_newsah2 (struct secasindex *saidx,
        
        sah = key_getsah(saidx);
        if (!sah) {
        
        sah = key_getsah(saidx);
        if (!sah) {
-               return(key_newsah(saidx, dir));
+               return(key_newsah(saidx, NULL, 0, dir));
        }
        return sah;
 }
        }
        return sah;
 }
@@ -4122,6 +4112,8 @@ key_setsaval(
                                goto fail;
                        }
                        sav->remote_ike_port = ((const struct sadb_sa_2*)(sa0))->sadb_sa_natt_port;
                                goto fail;
                        }
                        sav->remote_ike_port = ((const struct sadb_sa_2*)(sa0))->sadb_sa_natt_port;
+                       sav->natt_interval = ((const struct sadb_sa_2*)(sa0))->sadb_sa_natt_interval;
+                       sav->natt_offload_interval = ((const struct sadb_sa_2*)(sa0))->sadb_sa_natt_offload_interval;
                }
                
                /*
                }
                
                /*
@@ -4819,7 +4811,8 @@ key_setdumpsa(
                        case SADB_X_EXT_SA2:
                                m = key_setsadbxsa2(sav->sah->saidx.mode,
                                                                        sav->replay ? sav->replay->count : 0,
                        case SADB_X_EXT_SA2:
                                m = key_setsadbxsa2(sav->sah->saidx.mode,
                                                                        sav->replay ? sav->replay->count : 0,
-                                                                       sav->sah->saidx.reqid);
+                                                                       sav->sah->saidx.reqid,
+                                                                       sav->flags2);
                                if (!m)
                                        goto fail;
                                break;
                                if (!m)
                                        goto fail;
                                break;
@@ -4887,7 +4880,7 @@ key_setdumpsa(
                if ((!m && !p) || (m && p))
                        goto fail;
                if (p && tres) {
                if ((!m && !p) || (m && p))
                        goto fail;
                if (p && tres) {
-                       M_PREPEND(tres, l, M_WAITOK);
+                       M_PREPEND(tres, l, M_WAITOK, 1);
                        if (!tres)
                                goto fail;
                        bcopy(p, mtod(tres, caddr_t), l);
                        if (!tres)
                                goto fail;
                        bcopy(p, mtod(tres, caddr_t), l);
@@ -4907,6 +4900,13 @@ key_setdumpsa(
        
        m_cat(result, tres);
        
        
        m_cat(result, tres);
        
+       if (sav->sah && (sav->sah->outgoing_if || sav->sah->ipsec_if)) {
+        m = key_setsadbipsecif(NULL, ifindex2ifnet[sav->sah->outgoing_if], sav->sah->ipsec_if, 0);
+        if (!m)
+            goto fail;
+        m_cat(result, m);
+    }
+       
        if (result->m_len < sizeof(struct sadb_msg)) {
                result = m_pullup(result, sizeof(struct sadb_msg));
                if (result == NULL)
        if (result->m_len < sizeof(struct sadb_msg)) {
                result = m_pullup(result, sizeof(struct sadb_msg));
                if (result == NULL)
@@ -5085,11 +5085,11 @@ key_setsadbipsecif(ifnet_t internal_if,
        p->sadb_x_ipsecif_exttype = SADB_X_EXT_IPSECIF;
     
     if (internal_if && internal_if->if_xname)
        p->sadb_x_ipsecif_exttype = SADB_X_EXT_IPSECIF;
     
     if (internal_if && internal_if->if_xname)
-        strncpy(p->sadb_x_ipsecif_internal_if, internal_if->if_xname, IFXNAMSIZ);
+        strlcpy(p->sadb_x_ipsecif_internal_if, internal_if->if_xname, IFXNAMSIZ);
     if (outgoing_if && outgoing_if->if_xname)
     if (outgoing_if && outgoing_if->if_xname)
-        strncpy(p->sadb_x_ipsecif_outgoing_if, outgoing_if->if_xname, IFXNAMSIZ);
+        strlcpy(p->sadb_x_ipsecif_outgoing_if, outgoing_if->if_xname, IFXNAMSIZ);
     if (ipsec_if && ipsec_if->if_xname)
     if (ipsec_if && ipsec_if->if_xname)
-        strncpy(p->sadb_x_ipsecif_ipsec_if, ipsec_if->if_xname, IFXNAMSIZ);
+        strlcpy(p->sadb_x_ipsecif_ipsec_if, ipsec_if->if_xname, IFXNAMSIZ);
     
        p->sadb_x_ipsecif_init_disabled = init_disabled;
     
     
        p->sadb_x_ipsecif_init_disabled = init_disabled;
     
@@ -5214,7 +5214,8 @@ static struct mbuf *
 key_setsadbxsa2(
                                u_int8_t mode,
                                u_int32_t seq,
 key_setsadbxsa2(
                                u_int8_t mode,
                                u_int32_t seq,
-                               u_int32_t reqid)
+                               u_int32_t reqid,
+                               u_int16_t flags)
 {
        struct mbuf *m;
        struct sadb_x_sa2 *p;
 {
        struct mbuf *m;
        struct sadb_x_sa2 *p;
@@ -5238,6 +5239,7 @@ key_setsadbxsa2(
        p->sadb_x_sa2_reserved2 = 0;
        p->sadb_x_sa2_sequence = seq;
        p->sadb_x_sa2_reqid = reqid;
        p->sadb_x_sa2_reserved2 = 0;
        p->sadb_x_sa2_sequence = seq;
        p->sadb_x_sa2_reqid = reqid;
+       p->sadb_x_sa2_flags = flags;
        
        return m;
 }
        
        return m;
 }
@@ -5427,6 +5429,9 @@ key_cmpsaidx(
        if (saidx0 == NULL || saidx1 == NULL)
                return 0;
        
        if (saidx0 == NULL || saidx1 == NULL)
                return 0;
        
+       if (saidx0->ipsec_ifindex != 0 && saidx0->ipsec_ifindex != saidx1->ipsec_ifindex)
+               return 0;
+       
        if (saidx0->proto != saidx1->proto)
                return 0;
        
        if (saidx0->proto != saidx1->proto)
                return 0;
        
@@ -5976,7 +5981,7 @@ key_timehandler(void)
                         */
                        if (savkabuf && savkacount < savbufcount) {
                                sav = LIST_FIRST(&sah->savtree[SADB_SASTATE_MATURE]);   //%%% should we check dying list if this is empty???
                         */
                        if (savkabuf && savkacount < savbufcount) {
                                sav = LIST_FIRST(&sah->savtree[SADB_SASTATE_MATURE]);   //%%% should we check dying list if this is empty???
-                               if (natt_keepalive_interval && sav &&
+                               if (sav && (natt_keepalive_interval || sav->natt_interval) &&
                                        (sav->flags & (SADB_X_EXT_NATT_KEEPALIVE | SADB_X_EXT_ESP_KEEPALIVE)) != 0) {
                                        sav->refcnt++;
                                        *savkaptr++ = sav;
                                        (sav->flags & (SADB_X_EXT_NATT_KEEPALIVE | SADB_X_EXT_ESP_KEEPALIVE)) != 0) {
                                        sav->refcnt++;
                                        *savkaptr++ = sav;
@@ -6260,14 +6265,14 @@ key_timehandler(void)
                KFREE(savexbuf);
        }
        
                KFREE(savexbuf);
        }
        
-#ifndef IPSEC_DEBUG2
-       if (stop_handler)
+       if (stop_handler) {
                key_timehandler_running = 0;
                key_timehandler_running = 0;
-       else {
+               /* Turn on the ipsec bypass */
+               ipsec_bypass = 1;
+       } else {
                /* do exchange to tick time !! */
                (void)timeout((void *)key_timehandler, (void *)0, hz);
        }
                /* do exchange to tick time !! */
                (void)timeout((void *)key_timehandler, (void *)0, hz);
        }
-#endif /* IPSEC_DEBUG2 */
 
        lck_mtx_unlock(sadb_mutex);
        return;
 
        lck_mtx_unlock(sadb_mutex);
        return;
@@ -6382,6 +6387,38 @@ key_proto2satype(
        /* NOTREACHED */
 }
 
        /* NOTREACHED */
 }
 
+static ifnet_t
+key_get_ipsec_if_from_message (const struct sadb_msghdr *mhp, int message_type)
+{
+       struct sadb_x_ipsecif *ipsecifopts = NULL;
+       ifnet_t ipsec_if = NULL;
+       
+       ipsecifopts = (struct sadb_x_ipsecif *)(void *)mhp->ext[message_type];
+       if (ipsecifopts != NULL) {
+               if (ipsecifopts->sadb_x_ipsecif_ipsec_if[0]) {
+                       ifnet_find_by_name(ipsecifopts->sadb_x_ipsecif_ipsec_if, &ipsec_if);
+               }
+       }
+       
+       return ipsec_if;
+}
+
+static u_int
+key_get_outgoing_ifindex_from_message (const struct sadb_msghdr *mhp, int message_type)
+{
+       struct sadb_x_ipsecif *ipsecifopts = NULL;
+       ifnet_t outgoing_if = NULL;
+       
+       ipsecifopts = (struct sadb_x_ipsecif *)(void *)mhp->ext[message_type];
+       if (ipsecifopts != NULL) {
+               if (ipsecifopts->sadb_x_ipsecif_outgoing_if[0]) {
+                       ifnet_find_by_name(ipsecifopts->sadb_x_ipsecif_outgoing_if, &outgoing_if);
+        }
+    }
+       
+       return outgoing_if ? outgoing_if->if_index : 0;
+}
+
 /* %%% PF_KEY */
 /*
  * SADB_GETSPI processing is to receive
 /* %%% PF_KEY */
 /*
  * SADB_GETSPI processing is to receive
@@ -6405,6 +6442,7 @@ key_getspi(
        struct secasindex saidx;
        struct secashead *newsah;
        struct secasvar *newsav;
        struct secasindex saidx;
        struct secashead *newsah;
        struct secasvar *newsav;
+       ifnet_t ipsec_if = NULL;
        u_int8_t proto;
        u_int32_t spi;
        u_int8_t mode;
        u_int8_t proto;
        u_int32_t spi;
        u_int8_t mode;
@@ -6440,6 +6478,8 @@ key_getspi(
        src0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_SRC]);
        dst0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_DST]);
        
        src0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_SRC]);
        dst0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_DST]);
        
+       ipsec_if = key_get_ipsec_if_from_message(mhp, SADB_X_EXT_IPSECIF);
+       
        /* map satype to proto */
        if ((proto = key_satype2proto(mhp->msg->sadb_msg_satype)) == 0) {
                ipseclog((LOG_DEBUG, "key_getspi: invalid satype is passed.\n"));
        /* map satype to proto */
        if ((proto = key_satype2proto(mhp->msg->sadb_msg_satype)) == 0) {
                ipseclog((LOG_DEBUG, "key_getspi: invalid satype is passed.\n"));
@@ -6481,7 +6521,7 @@ key_getspi(
        }
        
        /* XXX boundary check against sa_len */
        }
        
        /* XXX boundary check against sa_len */
-       KEY_SETSECASIDX(proto, mode, reqid, src0 + 1, dst0 + 1, &saidx);
+       KEY_SETSECASIDX(proto, mode, reqid, src0 + 1, dst0 + 1, ipsec_if ? ipsec_if->if_index : 0, &saidx);
        
        lck_mtx_lock(sadb_mutex);
        
        
        lck_mtx_lock(sadb_mutex);
        
@@ -6496,7 +6536,7 @@ key_getspi(
        /* get a SA index */
        if ((newsah = key_getsah(&saidx)) == NULL) {
                /* create a new SA index: key_addspi is always used for inbound spi */
        /* get a SA index */
        if ((newsah = key_getsah(&saidx)) == NULL) {
                /* create a new SA index: key_addspi is always used for inbound spi */
-               if ((newsah = key_newsah(&saidx, IPSEC_DIR_INBOUND)) == NULL) {
+               if ((newsah = key_newsah(&saidx, ipsec_if, key_get_outgoing_ifindex_from_message(mhp, SADB_X_EXT_IPSECIF), IPSEC_DIR_INBOUND)) == NULL) {
                        lck_mtx_unlock(sadb_mutex);
                        ipseclog((LOG_DEBUG, "key_getspi: No more memory.\n"));
                        return key_senderror(so, m, ENOBUFS);
                        lck_mtx_unlock(sadb_mutex);
                        ipseclog((LOG_DEBUG, "key_getspi: No more memory.\n"));
                        return key_senderror(so, m, ENOBUFS);
@@ -6505,7 +6545,7 @@ key_getspi(
        
        /* get a new SA */
        /* XXX rewrite */
        
        /* get a new SA */
        /* XXX rewrite */
-       newsav = key_newsav(m, mhp, newsah, &error);
+       newsav = key_newsav(m, mhp, newsah, &error, so);
        if (newsav == NULL) {
                /* XXX don't free new SA index allocated in above. */
                lck_mtx_unlock(sadb_mutex);
        if (newsav == NULL) {
                /* XXX don't free new SA index allocated in above. */
                lck_mtx_unlock(sadb_mutex);
@@ -6614,7 +6654,7 @@ key_getspi2(struct sockaddr      *src,
        lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
        
        /* XXX boundary check against sa_len */
        lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
        
        /* XXX boundary check against sa_len */
-       KEY_SETSECASIDX(proto, mode, reqid, src, dst, &saidx);
+       KEY_SETSECASIDX(proto, mode, reqid, src, dst, 0, &saidx);
        
        /* make sure if port number is zero. */
        switch (((struct sockaddr *)&saidx.src)->sa_family) {
        
        /* make sure if port number is zero. */
        switch (((struct sockaddr *)&saidx.src)->sa_family) {
@@ -6755,12 +6795,14 @@ key_update(
 {
        struct sadb_sa *sa0;
        struct sadb_address *src0, *dst0;
 {
        struct sadb_sa *sa0;
        struct sadb_address *src0, *dst0;
+       ifnet_t ipsec_if = NULL;
        struct secasindex saidx;
        struct secashead *sah;
        struct secasvar *sav;
        u_int16_t proto;
        u_int8_t mode;
        u_int32_t reqid;
        struct secasindex saidx;
        struct secashead *sah;
        struct secasvar *sav;
        u_int16_t proto;
        u_int8_t mode;
        u_int32_t reqid;
+       u_int16_t flags2;
        int error;
        
        lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
        int error;
        
        lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
@@ -6800,18 +6842,21 @@ key_update(
                                (void *)mhp->ext[SADB_X_EXT_SA2])->sadb_x_sa2_mode;
                reqid = ((struct sadb_x_sa2 *)
                                 (void *)mhp->ext[SADB_X_EXT_SA2])->sadb_x_sa2_reqid;
                                (void *)mhp->ext[SADB_X_EXT_SA2])->sadb_x_sa2_mode;
                reqid = ((struct sadb_x_sa2 *)
                                 (void *)mhp->ext[SADB_X_EXT_SA2])->sadb_x_sa2_reqid;
+               flags2 = ((struct sadb_x_sa2 *)(void *)mhp->ext[SADB_X_EXT_SA2])->sadb_x_sa2_flags;
        } else {
                mode = IPSEC_MODE_ANY;
                reqid = 0;
        } else {
                mode = IPSEC_MODE_ANY;
                reqid = 0;
+               flags2 = 0;
        }
        /* XXX boundary checking for other extensions */
        
        sa0 = (struct sadb_sa *)(void *)mhp->ext[SADB_EXT_SA];
        src0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_SRC]);
        dst0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_DST]);
        }
        /* XXX boundary checking for other extensions */
        
        sa0 = (struct sadb_sa *)(void *)mhp->ext[SADB_EXT_SA];
        src0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_SRC]);
        dst0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_DST]);
+       ipsec_if = key_get_ipsec_if_from_message(mhp, SADB_X_EXT_IPSECIF);
        
        /* XXX boundary check against sa_len */
        
        /* XXX boundary check against sa_len */
-       KEY_SETSECASIDX(proto, mode, reqid, src0 + 1, dst0 + 1, &saidx);
+       KEY_SETSECASIDX(proto, mode, reqid, src0 + 1, dst0 + 1, ipsec_if ? ipsec_if->if_index : 0, &saidx);
        
        lck_mtx_lock(sadb_mutex);
        
        
        lck_mtx_lock(sadb_mutex);
        
@@ -6883,7 +6928,12 @@ key_update(
                lck_mtx_unlock(sadb_mutex);
                return key_senderror(so, m, error);
        }
                lck_mtx_unlock(sadb_mutex);
                return key_senderror(so, m, error);
        }
-       
+
+       sav->flags2 = flags2;
+       if (flags2 & SADB_X_EXT_SA2_DELETE_ON_DETACH) {
+               sav->so = so;
+       }
+
        /*
         * Verify if SADB_X_EXT_NATT_MULTIPLEUSERS flag is set that
         * this SA is for transport mode - otherwise clear it.
        /*
         * Verify if SADB_X_EXT_NATT_MULTIPLEUSERS flag is set that
         * this SA is for transport mode - otherwise clear it.
@@ -6917,6 +6967,152 @@ key_update(
     }
 }
 
     }
 }
 
+static int
+key_migrate(struct socket *so,
+                       struct mbuf *m,
+                       const struct sadb_msghdr *mhp)
+{
+       struct sadb_sa *sa0 = NULL;
+       struct sadb_address *src0 = NULL;
+       struct sadb_address *dst0 = NULL;
+       struct sadb_address *src1 = NULL;
+       struct sadb_address *dst1 = NULL;
+       ifnet_t ipsec_if0 = NULL;
+       ifnet_t ipsec_if1 = NULL;
+       struct secasindex saidx0;
+       struct secasindex saidx1;
+       struct secashead *sah = NULL;
+       struct secashead *newsah = NULL;
+       struct secasvar *sav = NULL;
+       u_int16_t proto;
+       
+       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
+       
+       /* sanity check */
+       if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
+               panic("key_migrate: NULL pointer is passed.\n");
+       
+       /* map satype to proto */
+       if ((proto = key_satype2proto(mhp->msg->sadb_msg_satype)) == 0) {
+               ipseclog((LOG_DEBUG, "key_migrate: invalid satype is passed.\n"));
+               return key_senderror(so, m, EINVAL);
+       }
+       
+       if (mhp->ext[SADB_EXT_SA] == NULL ||
+               mhp->ext[SADB_EXT_ADDRESS_SRC] == NULL ||
+               mhp->ext[SADB_EXT_ADDRESS_DST] == NULL ||
+               mhp->ext[SADB_EXT_MIGRATE_ADDRESS_SRC] == NULL ||
+               mhp->ext[SADB_EXT_MIGRATE_ADDRESS_DST] == NULL) {
+               ipseclog((LOG_DEBUG, "key_migrate: invalid message is passed.\n"));
+               return key_senderror(so, m, EINVAL);
+       }
+       
+       if (mhp->extlen[SADB_EXT_SA] < sizeof(struct sadb_sa) ||
+               mhp->extlen[SADB_EXT_ADDRESS_SRC] < sizeof(struct sadb_address) ||
+               mhp->extlen[SADB_EXT_ADDRESS_DST] < sizeof(struct sadb_address) ||
+               mhp->extlen[SADB_EXT_MIGRATE_ADDRESS_SRC] < sizeof(struct sadb_address) ||
+               mhp->extlen[SADB_EXT_MIGRATE_ADDRESS_DST] < sizeof(struct sadb_address)) {
+               ipseclog((LOG_DEBUG, "key_migrate: invalid message is passed.\n"));
+               return key_senderror(so, m, EINVAL);
+       }
+       
+       lck_mtx_lock(sadb_mutex);
+       
+       sa0 = (struct sadb_sa *)(void *)mhp->ext[SADB_EXT_SA];
+       src0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_SRC]);
+       dst0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_DST]);
+       src1 = (struct sadb_address *)(mhp->ext[SADB_EXT_MIGRATE_ADDRESS_SRC]);
+       dst1 = (struct sadb_address *)(mhp->ext[SADB_EXT_MIGRATE_ADDRESS_DST]);
+       ipsec_if0 = key_get_ipsec_if_from_message(mhp, SADB_X_EXT_IPSECIF);
+       ipsec_if1 = key_get_ipsec_if_from_message(mhp, SADB_X_EXT_MIGRATE_IPSECIF);
+       
+       /* Find existing SAH and SAV */
+       KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, ipsec_if0 ? ipsec_if0->if_index : 0, &saidx0);
+       
+       LIST_FOREACH(sah, &sahtree, chain) {
+               if (sah->state != SADB_SASTATE_MATURE)
+                       continue;
+               if (key_cmpsaidx(&sah->saidx, &saidx0, CMP_HEAD) == 0)
+                       continue;
+               
+               sav = key_getsavbyspi(sah, sa0->sadb_sa_spi);
+               if (sav && sav->state == SADB_SASTATE_MATURE)
+                       break;
+       }
+       if (sah == NULL) {
+               lck_mtx_unlock(sadb_mutex);
+               ipseclog((LOG_DEBUG, "key_migrate: no mature SAH found.\n"));
+               return key_senderror(so, m, ENOENT);
+       }
+       
+       if (sav == NULL) {
+               lck_mtx_unlock(sadb_mutex);
+               ipseclog((LOG_DEBUG, "key_migrate: no SA found.\n"));
+               return key_senderror(so, m, ENOENT);
+       }
+       
+       /* Find or create new SAH */
+       KEY_SETSECASIDX(proto, sah->saidx.mode, sah->saidx.reqid, src1 + 1, dst1 + 1, ipsec_if1 ? ipsec_if1->if_index : 0, &saidx1);
+       
+       if ((newsah = key_getsah(&saidx1)) == NULL) {
+               if ((newsah = key_newsah(&saidx1, ipsec_if1, key_get_outgoing_ifindex_from_message(mhp, SADB_X_EXT_MIGRATE_IPSECIF), sah->dir)) == NULL) {
+                       lck_mtx_unlock(sadb_mutex);
+                       ipseclog((LOG_DEBUG, "key_migrate: No more memory.\n"));
+                       return key_senderror(so, m, ENOBUFS);
+               }
+       }
+       
+       /* Migrate SAV in to new SAH */
+       if (key_migratesav(sav, newsah) != 0) {
+               lck_mtx_unlock(sadb_mutex);
+               ipseclog((LOG_DEBUG, "key_migrate: Failed to migrate SA to new SAH.\n"));
+               return key_senderror(so, m, EINVAL);
+       }
+       
+       /* Reset NAT values */
+       sav->flags = sa0->sadb_sa_flags;
+       sav->remote_ike_port = ((const struct sadb_sa_2*)(sa0))->sadb_sa_natt_port;
+       sav->natt_interval = ((const struct sadb_sa_2*)(sa0))->sadb_sa_natt_interval;
+       sav->natt_offload_interval = ((const struct sadb_sa_2*)(sa0))->sadb_sa_natt_offload_interval;
+       sav->natt_last_activity = natt_now;
+       
+       /*
+        * Verify if SADB_X_EXT_NATT_MULTIPLEUSERS flag is set that
+        * SADB_X_EXT_NATT is set and SADB_X_EXT_NATT_KEEPALIVE is not
+        * set (we're not behind nat) - otherwise clear it.
+        */
+       if ((sav->flags & SADB_X_EXT_NATT_MULTIPLEUSERS) != 0)
+               if ((sav->flags & SADB_X_EXT_NATT) == 0 ||
+                       (sav->flags & SADB_X_EXT_NATT_KEEPALIVE) != 0)
+                       sav->flags &= ~SADB_X_EXT_NATT_MULTIPLEUSERS;
+       
+       lck_mtx_unlock(sadb_mutex);
+       {
+               struct mbuf *n;
+               struct sadb_msg *newmsg;
+               int mbufItems[] = {SADB_EXT_RESERVED, SADB_EXT_SA,
+                       SADB_EXT_ADDRESS_SRC, SADB_EXT_ADDRESS_DST, SADB_X_EXT_IPSECIF,
+                       SADB_EXT_MIGRATE_ADDRESS_SRC, SADB_EXT_MIGRATE_ADDRESS_DST, SADB_X_EXT_MIGRATE_IPSECIF};
+               
+               /* create new sadb_msg to reply. */
+               n = key_gather_mbuf(m, mhp, 1, sizeof(mbufItems)/sizeof(int), mbufItems);
+               if (!n)
+                       return key_senderror(so, m, ENOBUFS);
+               
+               if (n->m_len < sizeof(struct sadb_msg)) {
+                       n = m_pullup(n, sizeof(struct sadb_msg));
+                       if (n == NULL)
+                               return key_senderror(so, m, ENOBUFS);
+               }
+               newmsg = mtod(n, struct sadb_msg *);
+               newmsg->sadb_msg_errno = 0;
+               newmsg->sadb_msg_len = PFKEY_UNIT64(n->m_pkthdr.len);
+               
+               m_freem(m);
+               return key_sendup_mbuf(so, n, KEY_SENDUP_ALL);
+       }
+}
+
 /*
  * search SAD with sequence for a SA which state is SADB_SASTATE_LARVAL.
  * only called by key_update().
 /*
  * search SAD with sequence for a SA which state is SADB_SASTATE_LARVAL.
  * only called by key_update().
@@ -6979,6 +7175,7 @@ key_add(
 {
        struct sadb_sa *sa0;
        struct sadb_address *src0, *dst0;
 {
        struct sadb_sa *sa0;
        struct sadb_address *src0, *dst0;
+       ifnet_t ipsec_if = NULL;
        struct secasindex saidx;
        struct secashead *newsah;
        struct secasvar *newsav;
        struct secasindex saidx;
        struct secashead *newsah;
        struct secasvar *newsav;
@@ -6996,6 +7193,7 @@ key_add(
        /* map satype to proto */
        if ((proto = key_satype2proto(mhp->msg->sadb_msg_satype)) == 0) {
                ipseclog((LOG_DEBUG, "key_add: invalid satype is passed.\n"));
        /* map satype to proto */
        if ((proto = key_satype2proto(mhp->msg->sadb_msg_satype)) == 0) {
                ipseclog((LOG_DEBUG, "key_add: invalid satype is passed.\n"));
+               bzero_keys(mhp);
                return key_senderror(so, m, EINVAL);
        }
        
                return key_senderror(so, m, EINVAL);
        }
        
@@ -7011,6 +7209,7 @@ key_add(
            (mhp->ext[SADB_EXT_LIFETIME_HARD] == NULL &&
             mhp->ext[SADB_EXT_LIFETIME_SOFT] != NULL)) {
                        ipseclog((LOG_DEBUG, "key_add: invalid message is passed.\n"));
            (mhp->ext[SADB_EXT_LIFETIME_HARD] == NULL &&
             mhp->ext[SADB_EXT_LIFETIME_SOFT] != NULL)) {
                        ipseclog((LOG_DEBUG, "key_add: invalid message is passed.\n"));
+                       bzero_keys(mhp);
                        return key_senderror(so, m, EINVAL);
                }
        if (mhp->extlen[SADB_EXT_SA] < sizeof(struct sadb_sa) ||
                        return key_senderror(so, m, EINVAL);
                }
        if (mhp->extlen[SADB_EXT_SA] < sizeof(struct sadb_sa) ||
@@ -7018,6 +7217,7 @@ key_add(
            mhp->extlen[SADB_EXT_ADDRESS_DST] < sizeof(struct sadb_address)) {
                /* XXX need more */
                ipseclog((LOG_DEBUG, "key_add: invalid message is passed.\n"));
            mhp->extlen[SADB_EXT_ADDRESS_DST] < sizeof(struct sadb_address)) {
                /* XXX need more */
                ipseclog((LOG_DEBUG, "key_add: invalid message is passed.\n"));
+               bzero_keys(mhp);
                return key_senderror(so, m, EINVAL);
        }
        if (mhp->ext[SADB_X_EXT_SA2] != NULL) {
                return key_senderror(so, m, EINVAL);
        }
        if (mhp->ext[SADB_X_EXT_SA2] != NULL) {
@@ -7033,18 +7233,20 @@ key_add(
        sa0 = (struct sadb_sa *)(void *)mhp->ext[SADB_EXT_SA];
        src0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_SRC];
        dst0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_DST];
        sa0 = (struct sadb_sa *)(void *)mhp->ext[SADB_EXT_SA];
        src0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_SRC];
        dst0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_DST];
+       ipsec_if = key_get_ipsec_if_from_message(mhp, SADB_X_EXT_IPSECIF);
        
        /* XXX boundary check against sa_len */
        
        /* XXX boundary check against sa_len */
-       KEY_SETSECASIDX(proto, mode, reqid, src0 + 1, dst0 + 1, &saidx);
+       KEY_SETSECASIDX(proto, mode, reqid, src0 + 1, dst0 + 1, ipsec_if ? ipsec_if->if_index : 0, &saidx);
        
        lck_mtx_lock(sadb_mutex);
        
        /* get a SA header */
        if ((newsah = key_getsah(&saidx)) == NULL) {
                /* create a new SA header: key_addspi is always used for outbound spi */
        
        lck_mtx_lock(sadb_mutex);
        
        /* get a SA header */
        if ((newsah = key_getsah(&saidx)) == NULL) {
                /* create a new SA header: key_addspi is always used for outbound spi */
-               if ((newsah = key_newsah(&saidx, IPSEC_DIR_OUTBOUND)) == NULL) {
+               if ((newsah = key_newsah(&saidx, ipsec_if, key_get_outgoing_ifindex_from_message(mhp, SADB_X_EXT_IPSECIF), IPSEC_DIR_OUTBOUND)) == NULL) {
                        lck_mtx_unlock(sadb_mutex);
                        ipseclog((LOG_DEBUG, "key_add: No more memory.\n"));
                        lck_mtx_unlock(sadb_mutex);
                        ipseclog((LOG_DEBUG, "key_add: No more memory.\n"));
+                       bzero_keys(mhp);
                        return key_senderror(so, m, ENOBUFS);
                }
        }
                        return key_senderror(so, m, ENOBUFS);
                }
        }
@@ -7054,6 +7256,7 @@ key_add(
        error = key_setident(newsah, m, mhp);
        if (error) {
                lck_mtx_unlock(sadb_mutex);
        error = key_setident(newsah, m, mhp);
        if (error) {
                lck_mtx_unlock(sadb_mutex);
+               bzero_keys(mhp);
                return key_senderror(so, m, error);
        }
        
                return key_senderror(so, m, error);
        }
        
@@ -7062,11 +7265,13 @@ key_add(
        if (key_getsavbyspi(newsah, sa0->sadb_sa_spi)) {
                lck_mtx_unlock(sadb_mutex);
                ipseclog((LOG_DEBUG, "key_add: SA already exists.\n"));
        if (key_getsavbyspi(newsah, sa0->sadb_sa_spi)) {
                lck_mtx_unlock(sadb_mutex);
                ipseclog((LOG_DEBUG, "key_add: SA already exists.\n"));
+               bzero_keys(mhp);
                return key_senderror(so, m, EEXIST);
        }
                return key_senderror(so, m, EEXIST);
        }
-       newsav = key_newsav(m, mhp, newsah, &error);
+       newsav = key_newsav(m, mhp, newsah, &error, so);
        if (newsav == NULL) {
                lck_mtx_unlock(sadb_mutex);
        if (newsav == NULL) {
                lck_mtx_unlock(sadb_mutex);
+               bzero_keys(mhp);
                return key_senderror(so, m, error);
        }
        
                return key_senderror(so, m, error);
        }
        
@@ -7083,6 +7288,7 @@ key_add(
        if ((error = key_mature(newsav)) != 0) {
                key_freesav(newsav, KEY_SADB_LOCKED);
                lck_mtx_unlock(sadb_mutex);
        if ((error = key_mature(newsav)) != 0) {
                key_freesav(newsav, KEY_SADB_LOCKED);
                lck_mtx_unlock(sadb_mutex);
+               bzero_keys(mhp);
                return key_senderror(so, m, error);
        }
        
                return key_senderror(so, m, error);
        }
        
@@ -7100,9 +7306,13 @@ key_add(
                n = key_getmsgbuf_x1(m, mhp);
                if (n == NULL) {
                        ipseclog((LOG_DEBUG, "key_update: No more memory.\n"));
                n = key_getmsgbuf_x1(m, mhp);
                if (n == NULL) {
                        ipseclog((LOG_DEBUG, "key_update: No more memory.\n"));
+                       bzero_keys(mhp);
                        return key_senderror(so, m, ENOBUFS);
                }
                
                        return key_senderror(so, m, ENOBUFS);
                }
                
+               // mh.ext points to the mbuf content.
+               // Zero out Encryption and Integrity keys if present.
+               bzero_keys(mhp);
                m_freem(m);
                return key_sendup_mbuf(so, n, KEY_SENDUP_ALL);
     }
                m_freem(m);
                return key_sendup_mbuf(so, n, KEY_SENDUP_ALL);
     }
@@ -7250,6 +7460,7 @@ key_delete(
 {
        struct sadb_sa *sa0;
        struct sadb_address *src0, *dst0;
 {
        struct sadb_sa *sa0;
        struct sadb_address *src0, *dst0;
+       ifnet_t ipsec_if = NULL;
        struct secasindex saidx;
        struct secashead *sah;
        struct secasvar *sav = NULL;
        struct secasindex saidx;
        struct secashead *sah;
        struct secasvar *sav = NULL;
@@ -7299,9 +7510,10 @@ key_delete(
        sa0 = (struct sadb_sa *)(void *)mhp->ext[SADB_EXT_SA];
        src0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_SRC]);
        dst0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_DST]);
        sa0 = (struct sadb_sa *)(void *)mhp->ext[SADB_EXT_SA];
        src0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_SRC]);
        dst0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_DST]);
+       ipsec_if = key_get_ipsec_if_from_message(mhp, SADB_X_EXT_IPSECIF);
        
        /* XXX boundary check against sa_len */
        
        /* XXX boundary check against sa_len */
-       KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, &saidx);
+       KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, ipsec_if ? ipsec_if->if_index : 0, &saidx);
        
        /* get a SA header */
        LIST_FOREACH(sah, &sahtree, chain) {
        
        /* get a SA header */
        LIST_FOREACH(sah, &sahtree, chain) {
@@ -7363,6 +7575,7 @@ key_delete_all(
                           u_int16_t proto)
 {
        struct sadb_address *src0, *dst0;
                           u_int16_t proto)
 {
        struct sadb_address *src0, *dst0;
+       ifnet_t ipsec_if = NULL;
        struct secasindex saidx;
        struct secashead *sah;
        struct secasvar *sav, *nextsav;
        struct secasindex saidx;
        struct secashead *sah;
        struct secasvar *sav, *nextsav;
@@ -7372,9 +7585,10 @@ key_delete_all(
        
        src0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_SRC]);
        dst0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_DST]);
        
        src0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_SRC]);
        dst0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_DST]);
+       ipsec_if = key_get_ipsec_if_from_message(mhp, SADB_X_EXT_IPSECIF);
        
        /* XXX boundary check against sa_len */
        
        /* XXX boundary check against sa_len */
-       KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, &saidx);
+       KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, ipsec_if ? ipsec_if->if_index : 0, &saidx);
        
        LIST_FOREACH(sah, &sahtree, chain) {
                if (sah->state == SADB_SASTATE_DEAD)
        
        LIST_FOREACH(sah, &sahtree, chain) {
                if (sah->state == SADB_SASTATE_DEAD)
@@ -7453,6 +7667,7 @@ key_get(
 {
        struct sadb_sa *sa0;
        struct sadb_address *src0, *dst0;
 {
        struct sadb_sa *sa0;
        struct sadb_address *src0, *dst0;
+       ifnet_t ipsec_if = NULL;
        struct secasindex saidx;
        struct secashead *sah;
        struct secasvar *sav = NULL;
        struct secasindex saidx;
        struct secashead *sah;
        struct secasvar *sav = NULL;
@@ -7486,9 +7701,10 @@ key_get(
        sa0 = (struct sadb_sa *)(void *)mhp->ext[SADB_EXT_SA];
        src0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_SRC];
        dst0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_DST];
        sa0 = (struct sadb_sa *)(void *)mhp->ext[SADB_EXT_SA];
        src0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_SRC];
        dst0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_DST];
+       ipsec_if = key_get_ipsec_if_from_message(mhp, SADB_X_EXT_IPSECIF);
        
        /* XXX boundary check against sa_len */
        
        /* XXX boundary check against sa_len */
-       KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, &saidx);
+       KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, ipsec_if ? ipsec_if->if_index : 0, &saidx);
        
        lck_mtx_lock(sadb_mutex);
        
        
        lck_mtx_lock(sadb_mutex);
        
@@ -7756,7 +7972,7 @@ key_getcomb_ah(void)
                                m->m_next = NULL;
                        }
                } else
                                m->m_next = NULL;
                        }
                } else
-                       M_PREPEND(m, l, M_WAITOK);
+                       M_PREPEND(m, l, M_WAITOK, 1);
                if (!m)
                        return NULL;
                
                if (!m)
                        return NULL;
                
@@ -7802,7 +8018,7 @@ key_getcomb_ipcomp(void)
                                m->m_next = NULL;
                        }
                } else
                                m->m_next = NULL;
                        }
                } else
-                       M_PREPEND(m, l, M_WAITOK);
+                       M_PREPEND(m, l, M_WAITOK, 1);
                if (!m)
                        return NULL;
                
                if (!m)
                        return NULL;
                
@@ -7848,7 +8064,7 @@ key_getprop(
        
        if (!m)
                return NULL;
        
        if (!m)
                return NULL;
-       M_PREPEND(m, l, M_WAITOK);
+       M_PREPEND(m, l, M_WAITOK, 1);
        if (!m)
                return NULL;
        
        if (!m)
                return NULL;
        
@@ -8200,6 +8416,7 @@ key_acquire2(
                         const struct sadb_msghdr *mhp)
 {
        const struct sadb_address *src0, *dst0;
                         const struct sadb_msghdr *mhp)
 {
        const struct sadb_address *src0, *dst0;
+       ifnet_t ipsec_if = NULL;
        struct secasindex saidx;
        struct secashead *sah;
        u_int16_t proto;
        struct secasindex saidx;
        struct secashead *sah;
        u_int16_t proto;
@@ -8281,10 +8498,11 @@ key_acquire2(
        
        src0 = (const struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_SRC];
        dst0 = (const struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_DST];
        
        src0 = (const struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_SRC];
        dst0 = (const struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_DST];
+       ipsec_if = key_get_ipsec_if_from_message(mhp, SADB_X_EXT_IPSECIF);
        
        /* XXX boundary check against sa_len */
        /* cast warnings */
        
        /* XXX boundary check against sa_len */
        /* cast warnings */
-       KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, &saidx);
+       KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, ipsec_if ? ipsec_if->if_index : 0, &saidx);
        
        /* get a SA index */
        LIST_FOREACH(sah, &sahtree, chain) {
        
        /* get a SA index */
        LIST_FOREACH(sah, &sahtree, chain) {
@@ -8489,6 +8707,32 @@ setmsg:
     }
 }
 
     }
 }
 
+static void
+key_delete_all_for_socket (struct socket *so)
+{
+       struct secashead *sah, *nextsah;
+       struct secasvar *sav, *nextsav;
+       u_int stateidx;
+       u_int state;
+
+       for (sah = LIST_FIRST(&sahtree);
+                sah != NULL;
+                sah = nextsah) {
+               nextsah = LIST_NEXT(sah, chain);
+               for (stateidx = 0; stateidx < _ARRAYLEN(saorder_state_alive); stateidx++) {
+                       state = saorder_state_any[stateidx];
+                       for (sav = LIST_FIRST(&sah->savtree[state]); sav != NULL; sav = nextsav) {
+                               nextsav = LIST_NEXT(sav, chain);
+                               if (sav->flags2 & SADB_X_EXT_SA2_DELETE_ON_DETACH &&
+                                       sav->so == so) {
+                                       key_sa_chgstate(sav, SADB_SASTATE_DEAD);
+                                       key_freesav(sav, KEY_SADB_LOCKED);
+                               }
+                       }
+               }
+       }
+}
+
 /*
  * free secreg entry registered.
  * XXX: I want to do free a socket marked done SADB_RESIGER to socket.
 /*
  * free secreg entry registered.
  * XXX: I want to do free a socket marked done SADB_RESIGER to socket.
@@ -8510,6 +8754,7 @@ key_freereg(
         * one socket is registered to multiple type of SA.
         */
        lck_mtx_lock(sadb_mutex);
         * one socket is registered to multiple type of SA.
         */
        lck_mtx_lock(sadb_mutex);
+       key_delete_all_for_socket(so);
        for (i = 0; i <= SADB_SATYPE_MAX; i++) {
                LIST_FOREACH(reg, &regtree[i], chain) {
                        if (reg->so == so
        for (i = 0; i <= SADB_SATYPE_MAX; i++) {
                LIST_FOREACH(reg, &regtree[i], chain) {
                        if (reg->so == so
@@ -8573,7 +8818,8 @@ key_expire(
        /* create SA extension */
        m = key_setsadbxsa2(sav->sah->saidx.mode,
                                                sav->replay ? sav->replay->count : 0,
        /* create SA extension */
        m = key_setsadbxsa2(sav->sah->saidx.mode,
                                                sav->replay ? sav->replay->count : 0,
-                                               sav->sah->saidx.reqid);
+                                               sav->sah->saidx.reqid,
+                                               sav->flags2);
        if (!m) {
                error = ENOBUFS;
                goto fail;
        if (!m) {
                error = ENOBUFS;
                goto fail;
@@ -8950,8 +9196,69 @@ static int (*key_typesw[])(struct socket *, struct mbuf *,
        key_getsastat,   /* SADB_GETSASTAT */
        key_spdenable,   /* SADB_X_SPDENABLE */
        key_spddisable,   /* SADB_X_SPDDISABLE */
        key_getsastat,   /* SADB_GETSASTAT */
        key_spdenable,   /* SADB_X_SPDENABLE */
        key_spddisable,   /* SADB_X_SPDDISABLE */
+       key_migrate,   /* SADB_MIGRATE */
 };
 
 };
 
+static void
+bzero_mbuf(struct mbuf *m)
+{
+       struct mbuf *mptr  = m;
+       struct sadb_msg *msg = NULL;
+       int offset = 0;
+
+       if (!mptr) {
+               return;
+       }
+
+       if (mptr->m_len >= sizeof(struct sadb_msg)) {
+               msg = mtod(mptr, struct sadb_msg *);
+               if (msg->sadb_msg_type != SADB_ADD &&
+                   msg->sadb_msg_type != SADB_UPDATE) {
+                       return;
+               }
+               offset = sizeof(struct sadb_msg);
+       }
+       bzero(mptr->m_data+offset, mptr->m_len-offset);
+       mptr = mptr->m_next;
+       while (mptr != NULL) {
+               bzero(mptr->m_data, mptr->m_len);
+               mptr = mptr->m_next;
+       }
+}
+
+static void
+bzero_keys(const struct sadb_msghdr *mh)
+{
+       int extlen = 0;
+       int offset = 0;
+
+       if (!mh) {
+               return;
+       }
+       offset = sizeof(struct sadb_key);
+
+       if (mh->ext[SADB_EXT_KEY_ENCRYPT]) {
+               struct sadb_key *key = (struct sadb_key*)mh->ext[SADB_EXT_KEY_ENCRYPT];
+               extlen = key->sadb_key_bits >> 3;
+
+               if (mh->extlen[SADB_EXT_KEY_ENCRYPT] >= offset + extlen) {
+                       bzero((uint8_t *)mh->ext[SADB_EXT_KEY_ENCRYPT]+offset, extlen);
+               } else {
+                       bzero(mh->ext[SADB_EXT_KEY_ENCRYPT], mh->extlen[SADB_EXT_KEY_ENCRYPT]);
+               }
+       }
+       if (mh->ext[SADB_EXT_KEY_AUTH]) {
+               struct sadb_key *key = (struct sadb_key*)mh->ext[SADB_EXT_KEY_AUTH];
+               extlen = key->sadb_key_bits >> 3;
+
+               if (mh->extlen[SADB_EXT_KEY_AUTH] >= offset + extlen) {
+                       bzero((uint8_t *)mh->ext[SADB_EXT_KEY_AUTH]+offset, extlen);
+               } else {
+                       bzero(mh->ext[SADB_EXT_KEY_AUTH], mh->extlen[SADB_EXT_KEY_AUTH]);
+               }
+       }
+}
+
 /*
  * parse sadb_msg buffer to process PFKEYv2,
  * and create a data to response if needed.
 /*
  * parse sadb_msg buffer to process PFKEYv2,
  * and create a data to response if needed.
@@ -8973,7 +9280,8 @@ key_parse(
        u_int orglen;
        int error;
        int target;
        u_int orglen;
        int error;
        int target;
-       
+       Boolean keyAligned = FALSE;
+
        lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
        
        /* sanity check */
        lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
        
        /* sanity check */
@@ -9037,12 +9345,14 @@ key_parse(
                        }
                }
                if (!n) {
                        }
                }
                if (!n) {
+                       bzero_mbuf(m);
                        m_freem(m);
                        return ENOBUFS;
                }
                m_copydata(m, 0, m->m_pkthdr.len, mtod(n, caddr_t));
                n->m_pkthdr.len = n->m_len = m->m_pkthdr.len;
                n->m_next = NULL;
                        m_freem(m);
                        return ENOBUFS;
                }
                m_copydata(m, 0, m->m_pkthdr.len, mtod(n, caddr_t));
                n->m_pkthdr.len = n->m_len = m->m_pkthdr.len;
                n->m_next = NULL;
+               bzero_mbuf(m);
                m_freem(m);
                m = n;
        }
                m_freem(m);
                m = n;
        }
@@ -9053,10 +9363,12 @@ key_parse(
                return error;
        
        if (m->m_next) {        /*XXX*/
                return error;
        
        if (m->m_next) {        /*XXX*/
+               bzero_mbuf(m);
                m_freem(m);
                return ENOBUFS;
        }
        
                m_freem(m);
                return ENOBUFS;
        }
        
+       keyAligned = TRUE;
        msg = mh.msg;
        
        /* check SA type */
        msg = mh.msg;
        
        /* check SA type */
@@ -9213,9 +9525,16 @@ key_parse(
                goto senderror;
        }
        
                goto senderror;
        }
        
-       return (*key_typesw[msg->sadb_msg_type])(so, m, &mh);
-       
+       error = (*key_typesw[msg->sadb_msg_type])(so, m, &mh);
+
+       return error;
+
 senderror:
 senderror:
+       if (keyAligned) {
+               bzero_keys(&mh);
+       } else {
+               bzero_mbuf(m);
+       }
        msg->sadb_msg_errno = error;
        return key_sendup_mbuf(so, m, target);
 }
        msg->sadb_msg_errno = error;
        return key_sendup_mbuf(so, m, target);
 }
@@ -9303,6 +9622,9 @@ key_align(
                        case SADB_X_EXT_ADDR_RANGE_SRC_END:
                        case SADB_X_EXT_ADDR_RANGE_DST_START:
                        case SADB_X_EXT_ADDR_RANGE_DST_END:
                        case SADB_X_EXT_ADDR_RANGE_SRC_END:
                        case SADB_X_EXT_ADDR_RANGE_DST_START:
                        case SADB_X_EXT_ADDR_RANGE_DST_END:
+                       case SADB_EXT_MIGRATE_ADDRESS_SRC:
+                       case SADB_EXT_MIGRATE_ADDRESS_DST:
+                       case SADB_X_EXT_MIGRATE_IPSECIF:
                                /* duplicate check */
                                /*
                                 * XXX Are there duplication payloads of either
                                /* duplicate check */
                                /*
                                 * XXX Are there duplication payloads of either
@@ -9312,6 +9634,7 @@ key_align(
                                        ipseclog((LOG_DEBUG,
                                                          "key_align: duplicate ext_type %u "
                                                          "is passed.\n", ext->sadb_ext_type));
                                        ipseclog((LOG_DEBUG,
                                                          "key_align: duplicate ext_type %u "
                                                          "is passed.\n", ext->sadb_ext_type));
+                                       bzero_mbuf(m);
                                        m_freem(m);
                                        PFKEY_STAT_INCREMENT(pfkeystat.out_dupext);
                                        return EINVAL;
                                        m_freem(m);
                                        PFKEY_STAT_INCREMENT(pfkeystat.out_dupext);
                                        return EINVAL;
@@ -9321,6 +9644,7 @@ key_align(
                                ipseclog((LOG_DEBUG,
                                                  "key_align: invalid ext_type %u is passed.\n",
                                                  ext->sadb_ext_type));
                                ipseclog((LOG_DEBUG,
                                                  "key_align: invalid ext_type %u is passed.\n",
                                                  ext->sadb_ext_type));
+                               bzero_mbuf(m);
                                m_freem(m);
                                PFKEY_STAT_INCREMENT(pfkeystat.out_invexttype);
                                return EINVAL;
                                m_freem(m);
                                PFKEY_STAT_INCREMENT(pfkeystat.out_invexttype);
                                return EINVAL;
@@ -9329,6 +9653,7 @@ key_align(
                extlen = PFKEY_UNUNIT64(ext->sadb_ext_len);
                
                if (key_validate_ext(ext, extlen)) {
                extlen = PFKEY_UNUNIT64(ext->sadb_ext_len);
                
                if (key_validate_ext(ext, extlen)) {
+                       bzero_mbuf(m);
                        m_freem(m);
                        PFKEY_STAT_INCREMENT(pfkeystat.out_invlen);
                        return EINVAL;
                        m_freem(m);
                        PFKEY_STAT_INCREMENT(pfkeystat.out_invlen);
                        return EINVAL;
@@ -9347,6 +9672,7 @@ key_align(
        }
        
        if (off != end) {
        }
        
        if (off != end) {
+               bzero_mbuf(m);
                m_freem(m);
                PFKEY_STAT_INCREMENT(pfkeystat.out_invlen);
                return EINVAL;
                m_freem(m);
                PFKEY_STAT_INCREMENT(pfkeystat.out_invlen);
                return EINVAL;
@@ -9386,6 +9712,8 @@ key_validate_ext(
                case SADB_X_EXT_ADDR_RANGE_SRC_END:
                case SADB_X_EXT_ADDR_RANGE_DST_START:
                case SADB_X_EXT_ADDR_RANGE_DST_END:
                case SADB_X_EXT_ADDR_RANGE_SRC_END:
                case SADB_X_EXT_ADDR_RANGE_DST_START:
                case SADB_X_EXT_ADDR_RANGE_DST_END:
+               case SADB_EXT_MIGRATE_ADDRESS_SRC:
+               case SADB_EXT_MIGRATE_ADDRESS_DST:
                        baselen = PFKEY_ALIGN8(sizeof(struct sadb_address));
                        checktype = ADDR;
                        break;
                        baselen = PFKEY_ALIGN8(sizeof(struct sadb_address));
                        checktype = ADDR;
                        break;
@@ -9885,6 +10213,10 @@ fail:
 void
 key_delsp_for_ipsec_if (ifnet_t ipsec_if)
 {
 void
 key_delsp_for_ipsec_if (ifnet_t ipsec_if)
 {
+       struct secashead *sah;
+       struct secasvar *sav, *nextsav;
+       u_int stateidx;
+       u_int state;
        struct secpolicy *sp, *nextsp;
        int dir;
     
        struct secpolicy *sp, *nextsp;
        int dir;
     
@@ -9914,6 +10246,58 @@ key_delsp_for_ipsec_if (ifnet_t ipsec_if)
                }
        }
        
                }
        }
        
+       LIST_FOREACH(sah, &sahtree, chain) {
+               if (sah->ipsec_if == ipsec_if) {
+                       /* This SAH is linked to the IPSec interface. It now needs to close. */
+                       ifnet_release(sah->ipsec_if);
+                       sah->ipsec_if = NULL;
+                       
+                       for (stateidx = 0; stateidx < _ARRAYLEN(saorder_state_alive); stateidx++) {
+                               state = saorder_state_any[stateidx];
+                               for (sav = LIST_FIRST(&sah->savtree[state]); sav != NULL; sav = nextsav) {
+                                       nextsav = LIST_NEXT(sav, chain);
+                                       
+                                       key_sa_chgstate(sav, SADB_SASTATE_DEAD);
+                                       key_freesav(sav, KEY_SADB_LOCKED);
+                               }
+                       }
+                       
+                       sah->state = SADB_SASTATE_DEAD;
+               }
+       }
+       
        lck_mtx_unlock(sadb_mutex);
        lck_mtx_unlock(sadb_mutex);
-    
+}
+
+__private_extern__ u_int32_t
+key_fill_offload_frames_for_savs (ifnet_t ifp,
+    struct ifnet_keepalive_offload_frame *frames_array,
+    u_int32_t frames_array_count,
+    size_t frame_data_offset)
+{
+       struct secashead *sah = NULL;
+       struct secasvar *sav = NULL;
+       struct ifnet_keepalive_offload_frame *frame = frames_array;
+       u_int32_t frame_index = 0;
+
+       if (frame == NULL || frames_array_count == 0) {
+               return (frame_index);
+       }
+
+       lck_mtx_lock(sadb_mutex);
+       LIST_FOREACH(sah, &sahtree, chain) {
+               LIST_FOREACH(sav, &sah->savtree[SADB_SASTATE_MATURE], chain) {
+                       if (ipsec_fill_offload_frame(ifp, sav, frame, frame_data_offset)) {
+                               frame_index++;
+                               if (frame_index >= frames_array_count) {
+                                       lck_mtx_unlock(sadb_mutex);
+                                       return (frame_index);
+                               }
+                               frame = &(frames_array[frame_index]);
+                       }
+               }
+       }
+       lck_mtx_unlock(sadb_mutex);
+
+       return (frame_index);
 }
 }