/*
- * Copyright (c) 2008-2013 Apple Inc. All rights reserved.
+ * Copyright (c) 2008-2014 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
#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>
* 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); \
(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 */
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 *,
- 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 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);
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 ipsec_offload_frame *frame, size_t frame_data_offset);
+u_int32_t key_fill_offload_frames_for_savs (ifnet_t ifp, struct ipsec_offload_frame *frames_array, u_int32_t frames_array_count, size_t frame_data_offset);
void key_init(struct protosw *, struct domain *);
{
/* 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);
}
-#endif /*IPSEC_DEBUG2*/
+
+ /* Turn off the ipsec bypass */
+ if (ipsec_bypass != 0)
+ ipsec_bypass = 0;
}
/* %%% IPsec policy management */
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 || sah->saidx.dst.ss_family == family) && /* IPv6 can go over IPv4 */
+ 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.
/*
* Must be called after calling key_allocsp().
- * For both the packet without socket and key_freeso().
*/
void
key_freesp(
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
}
}
- /* checking the direciton. */
+ /* checking the direction. */
switch (xpl0->sadb_x_policy_dir) {
case IPSEC_DIR_INBOUND:
case IPSEC_DIR_OUTBOUND:
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:
* 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;
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();
+
return(newsah);
}
ROUTE_RELEASE(&sah->sa_route);
+ if (sah->ipsec_if) {
+ ifnet_release(sah->ipsec_if);
+ sah->ipsec_if = NULL;
+ }
+
if (sah->idents) {
KFREE(sah->idents);
}
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;
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;
newsav->seq = mhp->msg->sadb_msg_seq;
break;
default:
- KFREE(newsav);
+ key_delsav(newsav);
*errp = EINVAL;
return NULL;
}
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) {
- if (newsav->spihash.le_prev || newsav->spihash.le_next)
- LIST_REMOVE(newsav, spihash);
- KFREE(newsav);
+ key_delsav(newsav);
return NULL;
}
} else {
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;
}
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"));
- KFREE(newsav);
+ key_delsav(newsav);
*errp = ENOBUFS;
return NULL;
}
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;
}
* others : found, pointer to a SA.
*/
static struct secashead *
-key_getsah(
- struct secasindex *saidx)
+key_getsah(struct secasindex *saidx)
{
struct secashead *sah;
sah = key_getsah(saidx);
if (!sah) {
- return(key_newsah(saidx, dir));
+ return(key_newsah(saidx, NULL, 0, dir));
}
return sah;
}
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;
}
/*
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;
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)
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)
- 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)
- 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;
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;
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;
}
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 (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;
KFREE(savexbuf);
}
-#ifndef IPSEC_DEBUG2
- if (stop_handler)
+ if (stop_handler) {
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);
}
-#endif /* IPSEC_DEBUG2 */
lck_mtx_unlock(sadb_mutex);
return;
/* NOTREACHED */
}
+static ifnet_t
+key_get_ipsec_if_from_message (const struct sadb_msghdr *mhp)
+{
+ struct sadb_x_ipsecif *ipsecifopts = NULL;
+ ifnet_t ipsec_if = NULL;
+
+ ipsecifopts = (struct sadb_x_ipsecif *)(void *)mhp->ext[SADB_X_EXT_IPSECIF];
+ if (ipsecifopts != NULL) {
+ if (ipsecifopts->sadb_x_ipsecif_internal_if) {
+ 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)
+{
+ struct sadb_x_ipsecif *ipsecifopts = NULL;
+ ifnet_t outgoing_if = NULL;
+
+ ipsecifopts = (struct sadb_x_ipsecif *)(void *)mhp->ext[SADB_X_EXT_IPSECIF];
+ if (ipsecifopts != NULL) {
+ if (ipsecifopts->sadb_x_ipsecif_outgoing_if) {
+ 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
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;
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);
+
/* map satype to proto */
if ((proto = key_satype2proto(mhp->msg->sadb_msg_satype)) == 0) {
ipseclog((LOG_DEBUG, "key_getspi: invalid satype is passed.\n"));
}
/* 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 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), IPSEC_DIR_INBOUND)) == NULL) {
lck_mtx_unlock(sadb_mutex);
ipseclog((LOG_DEBUG, "key_getspi: No more memory.\n"));
return key_senderror(so, m, ENOBUFS);
/* 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);
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) {
{
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;
+ u_int16_t flags2;
int error;
lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
(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;
+ 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]);
+ ipsec_if = key_get_ipsec_if_from_message(mhp);
/* 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_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.
{
struct sadb_sa *sa0;
struct sadb_address *src0, *dst0;
+ ifnet_t ipsec_if = NULL;
struct secasindex saidx;
struct secashead *newsah;
struct secasvar *newsav;
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);
/* 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 */
- if ((newsah = key_newsah(&saidx, IPSEC_DIR_OUTBOUND)) == NULL) {
+ if ((newsah = key_newsah(&saidx, ipsec_if, key_get_outgoing_ifindex_from_message(mhp), IPSEC_DIR_OUTBOUND)) == NULL) {
lck_mtx_unlock(sadb_mutex);
ipseclog((LOG_DEBUG, "key_add: No more memory.\n"));
return key_senderror(so, m, ENOBUFS);
ipseclog((LOG_DEBUG, "key_add: SA already exists.\n"));
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);
return key_senderror(so, m, error);
{
struct sadb_sa *sa0;
struct sadb_address *src0, *dst0;
+ ifnet_t ipsec_if = NULL;
struct secasindex saidx;
struct secashead *sah;
struct secasvar *sav = NULL;
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);
/* 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) {
u_int16_t proto)
{
struct sadb_address *src0, *dst0;
+ ifnet_t ipsec_if = NULL;
struct secasindex saidx;
struct secashead *sah;
struct secasvar *sav, *nextsav;
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);
/* 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)
{
struct sadb_sa *sa0;
struct sadb_address *src0, *dst0;
+ ifnet_t ipsec_if = NULL;
struct secasindex saidx;
struct secashead *sah;
struct secasvar *sav = NULL;
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);
/* 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);
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;
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);
/* 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) {
}
}
+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.
* 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, ®tree[i], chain) {
if (reg->so == so
/* 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;
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;
}
}
+ 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);
-
+}
+
+__private_extern__ u_int32_t
+key_fill_offload_frames_for_savs (ifnet_t ifp,
+ struct ipsec_offload_frame *frames_array,
+ u_int32_t frames_array_count,
+ size_t frame_data_offset)
+{
+ struct secashead *sah = NULL;
+ struct secasvar *sav = NULL;
+ struct ipsec_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);
}