+
+static int
+key_send_delsp (struct secpolicy *sp)
+{
+ struct mbuf *result = NULL, *m;
+
+ if (sp == NULL)
+ goto fail;
+
+ /* set msg header */
+ m = key_setsadbmsg(SADB_X_SPDDELETE, 0, 0, 0, 0, 0);
+ if (!m) {
+ goto fail;
+ }
+ result = m;
+
+ /* set sadb_address(es) for source */
+ if (sp->spidx.src_range.start.ss_len > 0) {
+ m = key_setsadbaddr(SADB_X_EXT_ADDR_RANGE_SRC_START,
+ (struct sockaddr *)&sp->spidx.src_range.start, sp->spidx.prefs,
+ sp->spidx.ul_proto);
+ if (!m)
+ goto fail;
+ m_cat(result, m);
+
+ m = key_setsadbaddr(SADB_X_EXT_ADDR_RANGE_SRC_END,
+ (struct sockaddr *)&sp->spidx.src_range.end, sp->spidx.prefs,
+ sp->spidx.ul_proto);
+ if (!m)
+ goto fail;
+ m_cat(result, m);
+ } else {
+ m = key_setsadbaddr(SADB_EXT_ADDRESS_SRC,
+ (struct sockaddr *)&sp->spidx.src, sp->spidx.prefs,
+ sp->spidx.ul_proto);
+ if (!m)
+ goto fail;
+ m_cat(result, m);
+ }
+
+ /* set sadb_address(es) for destination */
+ if (sp->spidx.dst_range.start.ss_len > 0) {
+ m = key_setsadbaddr(SADB_X_EXT_ADDR_RANGE_DST_START,
+ (struct sockaddr *)&sp->spidx.dst_range.start, sp->spidx.prefd,
+ sp->spidx.ul_proto);
+ if (!m)
+ goto fail;
+ m_cat(result, m);
+
+ m = key_setsadbaddr(SADB_X_EXT_ADDR_RANGE_DST_END,
+ (struct sockaddr *)&sp->spidx.dst_range.end, sp->spidx.prefd,
+ sp->spidx.ul_proto);
+ if (!m)
+ goto fail;
+ m_cat(result, m);
+ } else {
+ m = key_setsadbaddr(SADB_EXT_ADDRESS_DST,
+ (struct sockaddr *)&sp->spidx.dst, sp->spidx.prefd,
+ sp->spidx.ul_proto);
+ if (!m)
+ goto fail;
+ m_cat(result, m);
+ }
+
+ /* set secpolicy */
+ m = key_sp2msg(sp);
+ if (!m) {
+ goto fail;
+ }
+ m_cat(result, m);
+
+ if ((result->m_flags & M_PKTHDR) == 0) {
+ goto fail;
+ }
+
+ if (result->m_len < sizeof(struct sadb_msg)) {
+ result = m_pullup(result, sizeof(struct sadb_msg));
+ if (result == NULL) {
+ goto fail;
+ }
+ }
+
+ result->m_pkthdr.len = 0;
+ for (m = result; m; m = m->m_next)
+ result->m_pkthdr.len += m->m_len;
+
+ mtod(result, struct sadb_msg *)->sadb_msg_len = PFKEY_UNIT64(result->m_pkthdr.len);
+
+ return key_sendup_mbuf(NULL, result, KEY_SENDUP_REGISTERED);
+
+fail:
+ if (result)
+ m_free(result);
+ return -1;
+}
+
+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;
+
+ if (ipsec_if == NULL)
+ return;
+
+ lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
+
+ lck_mtx_lock(sadb_mutex);
+
+ for (dir = 0; dir < IPSEC_DIR_MAX; dir++) {
+ for (sp = LIST_FIRST(&sptree[dir]);
+ sp != NULL;
+ sp = nextsp) {
+
+ nextsp = LIST_NEXT(sp, chain);
+
+ if (sp->ipsec_if == ipsec_if) {
+ ifnet_release(sp->ipsec_if);
+ sp->ipsec_if = NULL;
+
+ key_send_delsp(sp);
+
+ sp->state = IPSEC_SPSTATE_DEAD;
+ key_freesp(sp, KEY_SADB_LOCKED);
+ }
+ }
+ }
+
+ 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 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);
+}