1/*
2 * Copyright (c) 2008 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License").  You may not use this file except in compliance with the
9 * License.  Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22
23#include <sys/param.h>
24#include <sys/types.h>
25#include <sys/socket.h>
26#include <string.h>
27
28#include "var.h"
29#include "misc.h"
30#include "vmbuf.h"
31#include "plog.h"
32#include "sockmisc.h"
33#include "debug.h"
34#include "fsm.h"
35
36#include "isakmp_var.h"
37#include "isakmp.h"
38#include "ike_session.h"
39#include "handler.h"
40#include "gcmalloc.h"
41#include "nattraversal.h"
42#include "schedule.h"
43#include "pfkey.h"
44#include "ipsec_doi.h"
45#include "ipsecSessionTracer.h"
46#include "ipsecMessageTracer.h"
47#include "isakmp_inf.h"
48#include "localconf.h"
49#include "remoteconf.h"
50#include "vpn_control.h"
51#include "vpn_control_var.h"
52#include "proposal.h"
53#include "sainfo.h"
54#include "power_mgmt.h"
55
56#define GET_SAMPLE_PERIOD(s,m)	do {						\
57									s = m / 20;				\
58									if (s < 3) {			\
59										s = 3;				\
60										if (m < (s * 2)) {	\
61											s = 1; /* bad */\
62										}					\
63									}						\
64								} while(0);
65
66const char *ike_session_stopped_by_vpn_disconnect = "Stopped by VPN disconnect";
67const char *ike_session_stopped_by_controller_comm_lost = "Stopped by loss of controller communication";
68const char *ike_session_stopped_by_flush          = "Stopped by Flush";
69const char *ike_session_stopped_by_idle           = "Stopped by Idle";
70const char *ike_session_stopped_by_xauth_timeout  = "Stopped by XAUTH timeout";
71const char *ike_session_stopped_by_sleepwake      = "Stopped by Sleep-Wake";
72const char *ike_session_stopped_by_assert         = "Stopped by Assert";
73const char *ike_session_stopped_by_peer           = "Stopped by Peer";
74
75LIST_HEAD(_ike_session_tree_, ike_session) ike_session_tree = { NULL };
76
77static void ike_session_bindph12(phase1_handle_t *, phase2_handle_t *);
78static void ike_session_rebindph12(phase1_handle_t *, phase2_handle_t *);
79static void ike_session_unbind_all_ph2_from_ph1 (phase1_handle_t *);
80static void ike_session_rebind_all_ph12_to_new_ph1 (phase1_handle_t *, phase1_handle_t *);
81
82static ike_session_t *
83new_ike_session (ike_session_id_t *id)
84{
85	ike_session_t *session;
86
87	if (!id) {
88		plog(ASL_LEVEL_DEBUG, "Invalid parameters in %s.\n", __FUNCTION__);
89		return NULL;
90	}
91
92	session = racoon_calloc(1, sizeof(*session));
93	if (session) {
94		bzero(session, sizeof(*session));
95		memcpy(&session->session_id, id, sizeof(*id));
96		LIST_INIT(&session->ph1tree);
97		LIST_INIT(&session->ph2tree);
98		LIST_INSERT_HEAD(&ike_session_tree, session, chain);
99		IPSECSESSIONTRACERSTART(session);
100	}
101	return session;
102}
103
104static void
105free_ike_session (ike_session_t *session)
106{
107    int is_failure = TRUE;
108	if (session) {
109        SCHED_KILL(session->traffic_monitor.sc_mon);
110        SCHED_KILL(session->traffic_monitor.sc_idle);
111        SCHED_KILL(session->sc_xauth);
112		if (session->start_timestamp.tv_sec || session->start_timestamp.tv_usec) {
113			if (!(session->stop_timestamp.tv_sec || session->stop_timestamp.tv_usec)) {
114				gettimeofday(&session->stop_timestamp, NULL);
115			}
116            if (session->term_reason != ike_session_stopped_by_vpn_disconnect ||
117                session->term_reason != ike_session_stopped_by_controller_comm_lost ||
118                session->term_reason != ike_session_stopped_by_flush ||
119                session->term_reason != ike_session_stopped_by_idle) {
120                is_failure = FALSE;
121            }
122			IPSECSESSIONTRACERSTOP(session,
123								   is_failure,
124								   session->term_reason);
125		}
126		// do MessageTracer cleanup here
127		plog(ASL_LEVEL_DEBUG,
128			 "Freeing IKE-Session to %s.\n",
129			 saddr2str((struct sockaddr *)&session->session_id.remote));
130		LIST_REMOVE(session, chain);
131		racoon_free(session);
132	}
133}
134
135
136void
137ike_session_init (void)
138{
139	LIST_INIT(&ike_session_tree);
140}
141
142u_int
143ike_session_get_rekey_lifetime (int local_spi_is_higher, u_int expiry_lifetime)
144{
145	u_int rekey_lifetime = expiry_lifetime / 10;
146
147	if (rekey_lifetime) {
148		if (local_spi_is_higher) {
149			return (rekey_lifetime * 9);
150		} else {
151			return (rekey_lifetime * 8);
152		}
153	} else {
154		if (local_spi_is_higher) {
155			rekey_lifetime = expiry_lifetime - 1;
156		} else {
157			rekey_lifetime = expiry_lifetime - 2;
158		}
159	}
160	if (rekey_lifetime < expiry_lifetime) {
161		return rekey_lifetime;
162	}
163	return 0;
164}
165
166ike_session_t *
167ike_session_create_session (ike_session_id_t *session_id)
168{
169    if (!session_id)
170        return NULL;
171
172    plog(ASL_LEVEL_DEBUG, "New IKE Session to %s.\n", saddr2str((struct sockaddr *)&session_id->remote));
173
174    return new_ike_session(session_id);
175}
176
177void
178ike_session_release_session (ike_session_t *session)
179{
180    while (!LIST_EMPTY(&session->ph2tree)) {
181        phase2_handle_t *phase2 = LIST_FIRST(&session->ph2tree);
182        ike_session_unlink_phase2(phase2);
183    }
184
185    while (!LIST_EMPTY(&session->ph1tree)) {
186        phase1_handle_t *phase1 = LIST_FIRST(&session->ph1tree);
187        ike_session_unlink_phase1(phase1);
188    }
189}
190
191// %%%%%%%%% re-examine this - keep both floated and unfloated port when behind nat
192ike_session_t *
193ike_session_get_session (struct sockaddr_storage *local,
194						 struct sockaddr_storage *remote,
195						 int              alloc_if_absent,
196						 isakmp_index *optionalIndex)
197{
198	ike_session_t    *p = NULL;
199	ike_session_id_t  id;
200	ike_session_id_t  id_default;
201	ike_session_id_t  id_floated_default;
202	ike_session_id_t  id_wop;
203	ike_session_t    *best_match = NULL;
204	u_int16_t         remote_port;
205	int               is_isakmp_remote_port;
206
207	if (!local || !remote) {
208		plog(ASL_LEVEL_DEBUG, "invalid parameters in %s.\n", __FUNCTION__);
209		return NULL;
210	}
211
212	remote_port = extract_port(remote);
213	if (remote_port && remote_port != PORT_ISAKMP && remote_port != PORT_ISAKMP_NATT) {
214		is_isakmp_remote_port = 0;
215	} else {
216		is_isakmp_remote_port = 1;
217	}
218
219	/* we will try a couple of matches first: if the exact id isn't found, then we'll try for an id that has zero'd ports */
220	bzero(&id, sizeof(id));
221	bzero(&id_default, sizeof(id_default));
222	bzero(&id_floated_default, sizeof(id_floated_default));
223	bzero(&id_wop, sizeof(id_wop));
224	if (local->ss_family == AF_INET) {
225		memcpy(&id.local, local, sizeof(struct sockaddr_in));
226		memcpy(&id_default.local, local, sizeof(struct sockaddr_in));
227		memcpy(&id_floated_default.local, local, sizeof(struct sockaddr_in));
228		memcpy(&id_wop.local, local, sizeof(struct sockaddr_in));
229	} else if (local->ss_family == AF_INET6) {
230		memcpy(&id.local, local, sizeof(struct sockaddr_in6));
231		memcpy(&id_default.local, local, sizeof(struct sockaddr_in6));
232		memcpy(&id_floated_default.local, local, sizeof(struct sockaddr_in6));
233		memcpy(&id_wop.local, local, sizeof(struct sockaddr_in6));
234	}
235	set_port(&id_default.local, PORT_ISAKMP);
236	set_port(&id_floated_default.local, PORT_ISAKMP_NATT);
237	set_port(&id_wop.local, 0);
238	if (remote->ss_family == AF_INET) {
239		memcpy(&id.remote, remote, sizeof(struct sockaddr_in));
240		memcpy(&id_default.remote, remote, sizeof(struct sockaddr_in));
241		memcpy(&id_floated_default.remote, remote, sizeof(struct sockaddr_in));
242		memcpy(&id_wop.remote, remote, sizeof(struct sockaddr_in));
243	} else if (remote->ss_family == AF_INET6) {
244		memcpy(&id.remote, remote, sizeof(struct sockaddr_in6));
245		memcpy(&id_default.remote, remote, sizeof(struct sockaddr_in6));
246		memcpy(&id_floated_default.remote, remote, sizeof(struct sockaddr_in6));
247		memcpy(&id_wop.remote, remote, sizeof(struct sockaddr_in6));
248	}
249	set_port(&id_default.remote, PORT_ISAKMP);
250	set_port(&id_floated_default.remote, PORT_ISAKMP_NATT);
251	set_port(&id_wop.remote, 0);
252
253	plog(ASL_LEVEL_DEBUG,
254		 "start search for IKE-Session. target %s.\n",
255		 saddr2str((struct sockaddr *)remote));
256
257	LIST_FOREACH(p, &ike_session_tree, chain) {
258		plog(ASL_LEVEL_DEBUG,
259			 "still search for IKE-Session. this %s.\n",
260			 saddr2str((struct sockaddr *)&p->session_id.remote));
261
262		// for now: ignore any stopped sessions as they will go down
263		if (p->is_dying || p->stopped_by_vpn_controller || p->stop_timestamp.tv_sec || p->stop_timestamp.tv_usec) {
264			plog(ASL_LEVEL_DEBUG, "still searching. skipping... session to %s is already stopped, active ph1 %d ph2 %d.\n",
265				 saddr2str((struct sockaddr *)&p->session_id.remote),
266				 p->ikev1_state.active_ph1cnt, p->ikev1_state.active_ph2cnt);
267			continue;
268		}
269
270		// Skip if the spi doesn't match
271		if (optionalIndex != NULL && ike_session_getph1byindex(p, optionalIndex) == NULL) {
272			continue;
273		}
274
275		if (memcmp(&p->session_id, &id, sizeof(id)) == 0) {
276			plog(ASL_LEVEL_DEBUG,
277				 "Pre-existing IKE-Session to %s. case 1.\n",
278				 saddr2str((struct sockaddr *)remote));
279			return p;
280		} else if (is_isakmp_remote_port && memcmp(&p->session_id, &id_default, sizeof(id_default)) == 0) {
281			plog(ASL_LEVEL_DEBUG,
282				 "Pre-existing IKE-Session to %s. case 2.\n",
283				 saddr2str((struct sockaddr *)remote));
284			return p;
285		} else if (is_isakmp_remote_port && p->ports_floated && memcmp(&p->session_id, &id_floated_default, sizeof(id_floated_default)) == 0) {
286			plog(ASL_LEVEL_DEBUG,
287				 "Pre-existing IKE-Session to %s. case 3.\n",
288				 saddr2str((struct sockaddr *)remote));
289			return p;
290		} else if (is_isakmp_remote_port && memcmp(&p->session_id, &id_wop, sizeof(id_wop)) == 0) {
291			best_match = p;
292		} else if (optionalIndex != NULL) {
293			// If the SPI did match, this one counts as a best match
294			best_match = p;
295		}
296	}
297	if (best_match) {
298		plog(ASL_LEVEL_DEBUG,
299			 "Best-match IKE-Session to %s.\n",
300			 saddr2str((struct sockaddr *)&best_match->session_id.remote));
301		return best_match;
302	}
303	if (alloc_if_absent) {
304		plog(ASL_LEVEL_DEBUG,
305			 "New IKE-Session to %s.\n",
306			 saddr2str((struct sockaddr *)&id.remote));
307		return new_ike_session(&id);
308	} else {
309		return NULL;
310	}
311}
312
313void
314ike_session_init_traffic_cop_params (phase1_handle_t *iph1)
315{
316    if (!iph1 ||
317        !iph1->rmconf ||
318        (!iph1->rmconf->idle_timeout && !iph1->rmconf->dpd_interval)) {
319        return;
320    }
321
322    if (!iph1->parent_session->traffic_monitor.interv_idle) {
323        iph1->parent_session->traffic_monitor.interv_idle = iph1->rmconf->idle_timeout;
324    }
325    if (!iph1->parent_session->traffic_monitor.dir_idle) {
326        iph1->parent_session->traffic_monitor.dir_idle = iph1->rmconf->idle_timeout_dir;
327    }
328
329    if (!iph1->parent_session->traffic_monitor.interv_mon) {
330        int min_period, max_period, sample_period = 0;
331
332        /* calculate the sampling interval... half the smaller interval */
333        if (iph1->rmconf->dpd_interval &&
334            (iph1->rmconf->dpd_algo == DPD_ALGO_INBOUND_DETECT ||
335             iph1->rmconf->dpd_algo == DPD_ALGO_BLACKHOLE_DETECT)) {
336            // when certain types of dpd are enabled
337            min_period = MIN(iph1->rmconf->dpd_interval, iph1->rmconf->idle_timeout);
338            max_period = MAX(iph1->rmconf->dpd_interval, iph1->rmconf->idle_timeout);
339        } else if (iph1->rmconf->idle_timeout) {
340            min_period = max_period = iph1->rmconf->idle_timeout;
341        } else {
342            // DPD_ALGO_DEFAULT is configured and there's no idle timeout... we don't need to monitor traffic
343            return;
344        }
345        if (min_period) {
346            GET_SAMPLE_PERIOD(sample_period, min_period);
347        } else {
348            GET_SAMPLE_PERIOD(sample_period, max_period);
349        }
350        iph1->parent_session->traffic_monitor.interv_mon = sample_period;
351    }
352}
353
354void
355ike_session_update_mode (phase2_handle_t *iph2)
356{
357	if (!iph2 || !iph2->parent_session) {
358		return;
359	}
360    if (iph2->phase2_type != PHASE2_TYPE_SA)
361        return;
362	if (iph2->version == ISAKMP_VERSION_NUMBER_IKEV2) {
363		return; // for now
364	}
365	// exit early if we already detected cisco-ipsec
366	if (iph2->parent_session->is_cisco_ipsec) {
367		return;
368	}
369
370	if (iph2->approval) {
371		if (!ipsecdoi_any_transportmode(iph2->approval)) {
372			// cisco & btmm ipsec are pure tunnel-mode (but cisco ipsec is detected by ph1)
373			iph2->parent_session->is_cisco_ipsec = 0;
374			iph2->parent_session->is_l2tpvpn_ipsec = 0;
375			iph2->parent_session->is_btmm_ipsec = 1;
376			return;
377		} else if (ipsecdoi_transportmode(iph2->approval)) {
378			iph2->parent_session->is_cisco_ipsec = 0;
379			iph2->parent_session->is_l2tpvpn_ipsec = 1;
380			iph2->parent_session->is_btmm_ipsec = 0;
381			return;
382		}
383	} else if (iph2->proposal) {
384		if (!ipsecdoi_any_transportmode(iph2->proposal)) {
385			// cisco & btmm ipsec are pure tunnel-mode (but cisco ipsec is detected by ph1)
386			iph2->parent_session->is_cisco_ipsec = 0;
387			iph2->parent_session->is_l2tpvpn_ipsec = 0;
388			iph2->parent_session->is_btmm_ipsec = 1;
389			return;
390		} else if (ipsecdoi_transportmode(iph2->proposal)) {
391			iph2->parent_session->is_cisco_ipsec = 0;
392			iph2->parent_session->is_l2tpvpn_ipsec = 1;
393			iph2->parent_session->is_btmm_ipsec = 0;
394			return;
395		}
396	}
397}
398
399static void
400ike_session_cleanup_xauth_timeout (void *arg)
401{
402    ike_session_t *session = (ike_session_t *)arg;
403
404    SCHED_KILL(session->sc_xauth);
405    // if there are no more established ph2s, start a timer to teardown the session
406    if (!ike_session_has_established_ph2(session)) {
407        ike_session_cleanup(session, ike_session_stopped_by_xauth_timeout);
408    } else {
409        session->sc_xauth = sched_new(300 /* 5 mins */,
410                                      ike_session_cleanup_xauth_timeout,
411                                      session);
412    }
413}
414
415int
416ike_session_link_phase1 (ike_session_t *session, phase1_handle_t *iph1)
417{
418
419	if (!session || !iph1) {
420		plog(ASL_LEVEL_DEBUG, "invalid parameters in %s.\n", __FUNCTION__);
421		return -1;
422	}
423
424    gettimeofday(&session->start_timestamp, NULL);
425
426	if (iph1->started_by_api) {
427		session->is_cisco_ipsec = 1;
428        session->is_l2tpvpn_ipsec = 0;
429        session->is_btmm_ipsec = 0;
430	}
431	iph1->parent_session = session;
432	LIST_INSERT_HEAD(&session->ph1tree, iph1, ph1ofsession_chain);
433	session->ikev1_state.active_ph1cnt++;
434    if ((!session->ikev1_state.ph1cnt &&
435         iph1->side == INITIATOR) ||
436        iph1->started_by_api) {
437        // client initiates the first phase1 or, is started by controller api
438        session->is_client = 1;
439    }
440	if (session->established &&
441		session->ikev1_state.ph1cnt &&
442        iph1->version == ISAKMP_VERSION_NUMBER_IKEV1) {
443		iph1->is_rekey = 1;
444	}
445	session->ikev1_state.ph1cnt++;
446    ike_session_init_traffic_cop_params(iph1);
447
448	return 0;
449}
450
451int
452ike_session_link_phase2 (ike_session_t *session, phase2_handle_t *iph2)
453{
454	if (!iph2) {
455		plog(ASL_LEVEL_DEBUG, "Invalid parameters in %s.\n", __FUNCTION__);
456		return -1;
457	}
458    if (iph2->parent_session) {
459		plog(ASL_LEVEL_ERR, "Phase 2 already linked to session %s.\n", __FUNCTION__);
460	}
461
462	iph2->parent_session = session;
463	LIST_INSERT_HEAD(&session->ph2tree, iph2, ph2ofsession_chain);
464	session->ikev1_state.active_ph2cnt++;
465    if (!session->ikev1_state.ph2cnt &&
466        iph2->side == INITIATOR) {
467        // client initiates the first phase2
468        session->is_client = 1;
469    }
470	if (iph2->phase2_type == PHASE2_TYPE_SA &&
471        session->established &&
472		session->ikev1_state.ph2cnt &&
473        iph2->version == ISAKMP_VERSION_NUMBER_IKEV1) {
474		iph2->is_rekey = 1;
475	}
476	session->ikev1_state.ph2cnt++;
477	ike_session_update_mode(iph2);
478
479	return 0;
480}
481
482int
483ike_session_link_ph2_to_ph1 (phase1_handle_t *iph1, phase2_handle_t *iph2)
484{
485    struct sockaddr_storage *local;
486	struct sockaddr_storage *remote;
487    int error = 0;
488
489	if (!iph2) {
490		plog(ASL_LEVEL_DEBUG, "Invalid parameters in %s.\n", __FUNCTION__);
491		return -1;
492	}
493    if (iph2->ph1) {
494		plog(ASL_LEVEL_ERR, "Phase 2 already linked %s.\n", __FUNCTION__);
495        if (iph2->ph1 == iph1)
496            return 0;
497        else
498            return -1;  // This shouldn't happen
499	}
500
501    local = iph2->src;
502    remote = iph2->dst;
503
504    if (iph2->parent_session == NULL)
505        if ((error = ike_session_link_phase2(iph1->parent_session, iph2)))
506            return error;
507
508	ike_session_bindph12(iph1, iph2);
509    return 0;
510}
511
512int
513ike_session_unlink_phase1 (phase1_handle_t *iph1)
514{
515	ike_session_t *session;
516
517	if (!iph1 || !iph1->parent_session) {
518		plog(ASL_LEVEL_DEBUG, "invalid parameters in %s.\n", __FUNCTION__);
519		return -1;
520	}
521
522    if (iph1->version == ISAKMP_VERSION_NUMBER_IKEV1) {
523        if (LIST_FIRST(&iph1->bound_ph2tree)) {
524            // reparent any phase2 that may be hanging on to this phase1
525            ike_session_update_ph1_ph2tree(iph1);
526        }
527    }
528
529    sched_scrub_param(iph1);
530	session = iph1->parent_session;
531	LIST_REMOVE(iph1, ph1ofsession_chain);
532	iph1->parent_session = NULL;
533	session->ikev1_state.active_ph1cnt--;
534	if (session->ikev1_state.active_ph1cnt == 0 && session->ikev1_state.active_ph2cnt == 0) {
535		session->is_dying = 1;
536		free_ike_session(session);
537	}
538    ike_session_delph1(iph1);
539	return 0;
540}
541
542int
543ike_session_unlink_phase2 (phase2_handle_t *iph2)
544{
545	ike_session_t *session;
546
547	if (!iph2 || !iph2->parent_session) {
548		plog(ASL_LEVEL_DEBUG, "invalid parameters in %s.\n", __FUNCTION__);
549		return -1;
550	}
551    sched_scrub_param(iph2);
552    ike_session_unbindph12(iph2);
553
554    LIST_REMOVE(iph2, ph2ofsession_chain);
555    session = iph2->parent_session;
556    iph2->parent_session = NULL;
557    session->ikev1_state.active_ph2cnt--;
558    if (session->ikev1_state.active_ph1cnt == 0 && session->ikev1_state.active_ph2cnt == 0) {
559        session->is_dying = 1;
560        free_ike_session(session);
561    }
562	ike_session_delph2(iph2);
563	return 0;
564}
565
566
567phase1_handle_t *
568ike_session_update_ph1_ph2tree (phase1_handle_t *iph1)
569{
570	phase1_handle_t *new_iph1 = NULL;
571
572	if (!iph1) {
573		plog(ASL_LEVEL_DEBUG, "invalid parameters in %s.\n", __FUNCTION__);
574		return NULL;
575	}
576
577	if (iph1->parent_session) {
578		new_iph1 = ike_session_get_established_ph1(iph1->parent_session);
579
580		if (!new_iph1) {
581			plog(ASL_LEVEL_DEBUG, "no ph1bind replacement found. NULL ph1.\n");
582			ike_session_unbind_all_ph2_from_ph1(iph1);
583		} else if (iph1 == new_iph1) {
584			plog(ASL_LEVEL_DEBUG, "no ph1bind replacement found. same ph1.\n");
585			ike_session_unbind_all_ph2_from_ph1(iph1);
586		} else {
587			ike_session_rebind_all_ph12_to_new_ph1(iph1, new_iph1);
588		}
589	} else {
590		plog(ASL_LEVEL_DEBUG, "invalid parent session in %s.\n", __FUNCTION__);
591	}
592	return new_iph1;
593}
594
595phase1_handle_t *
596ike_session_update_ph2_ph1bind (phase2_handle_t *iph2)
597{
598	phase1_handle_t *iph1;
599
600	if (!iph2 || iph2->phase2_type != PHASE2_TYPE_SA) {
601		plog(ASL_LEVEL_DEBUG, "invalid parameters in %s.\n", __FUNCTION__);
602		return NULL;
603	}
604
605	iph1 = ike_session_get_established_ph1(iph2->parent_session);
606	if (iph1 && iph2->ph1 && iph1 != iph2->ph1) {
607		ike_session_rebindph12(iph1, iph2);
608	} else if (iph1 && !iph2->ph1) {
609		ike_session_bindph12(iph1, iph2);
610	}
611
612	return iph1;
613}
614
615phase1_handle_t *
616ike_session_get_established_or_negoing_ph1 (ike_session_t *session)
617{
618	phase1_handle_t *p, *iph1 = NULL;
619
620	if (!session) {
621		plog(ASL_LEVEL_DEBUG, "invalid parameters in %s.\n", __FUNCTION__);
622		return NULL;
623	}
624
625	// look for the most mature ph1 under the session
626	LIST_FOREACH(p, &session->ph1tree, ph1ofsession_chain) {
627		if (!p->is_dying && (FSM_STATE_IS_ESTABLISHED(p->status) || FSM_STATE_IS_NEGOTIATING(p->status))) {
628			if (!iph1 || p->status > iph1->status) {
629				iph1 = p;
630			} else if (iph1 && p->status == iph1->status) {
631				// TODO: pick better one based on farthest rekey/expiry remaining
632			}
633		}
634	}
635
636	return iph1;
637}
638
639phase1_handle_t *
640ike_session_get_established_ph1 (ike_session_t *session)
641{
642	phase1_handle_t *p;
643
644	if (!session) {
645		plog(ASL_LEVEL_DEBUG, "invalid parameters in %s.\n", __FUNCTION__);
646		return NULL;
647	}
648
649	LIST_FOREACH(p, &session->ph1tree, ph1ofsession_chain) {
650		if (!p->is_dying && FSM_STATE_IS_ESTABLISHED(p->status)) {
651            return p;
652		}
653	}
654
655	return NULL;
656}
657
658
659int
660ike_session_has_other_established_ph1 (ike_session_t *session, phase1_handle_t *iph1)
661{
662	phase1_handle_t *p;
663
664	if (!session) {
665		return 0;
666	}
667
668	LIST_FOREACH(p, &session->ph1tree, ph1ofsession_chain) {
669		if (iph1 != p && !p->is_dying) {
670			if (FSM_STATE_IS_ESTABLISHED(p->status) && p->sce_rekey) {
671				return 1;
672			}
673		}
674	}
675
676	return 0;
677}
678
679int
680ike_session_has_other_negoing_ph1 (ike_session_t *session, phase1_handle_t *iph1)
681{
682	phase1_handle_t *p;
683
684	if (!session) {
685		plog(ASL_LEVEL_DEBUG, "invalid parameters in %s.\n", __FUNCTION__);
686		return 0;
687	}
688
689	LIST_FOREACH(p, &session->ph1tree, ph1ofsession_chain) {
690		if (iph1 != p && !p->is_dying) {
691			if (FSM_STATE_IS_NEGOTIATING(p->status)) {
692				return 1;
693			}
694		}
695	}
696
697	return 0;
698}
699
700int
701ike_session_has_other_established_ph2 (ike_session_t *session, phase2_handle_t *iph2)
702{
703	phase2_handle_t *p;
704
705	if (!session) {
706		plog(ASL_LEVEL_DEBUG, "invalid parameters in %s.\n", __FUNCTION__);
707		return 0;
708	}
709
710	LIST_FOREACH(p, &session->ph2tree, ph2ofsession_chain) {
711		if (p->phase2_type == PHASE2_TYPE_SA && iph2 != p && !p->is_dying && iph2->spid == p->spid) {
712			if (FSM_STATE_IS_ESTABLISHED(p->status)) {
713				return 1;
714			}
715		}
716	}
717
718	return 0;
719}
720
721int
722ike_session_has_other_negoing_ph2 (ike_session_t *session, phase2_handle_t *iph2)
723{
724	phase2_handle_t *p;
725
726	if (!session) {
727		plog(ASL_LEVEL_DEBUG, "invalid parameters in %s.\n", __FUNCTION__);
728		return 0;
729	}
730
731	LIST_FOREACH(p, &session->ph2tree, ph2ofsession_chain) {
732		plog(ASL_LEVEL_DEBUG, "%s: ph2 sub spid %d, db spid %d\n", __FUNCTION__, iph2->spid, p->spid);
733		if (p->phase2_type == PHASE2_TYPE_SA && iph2 != p && !p->is_dying && iph2->spid == p->spid) {
734			if (FSM_STATE_IS_NEGOTIATING(p->status)) {
735				return 1;
736			}
737		}
738	}
739
740	return 0;
741}
742
743
744void
745ike_session_ikev1_float_ports (phase1_handle_t *iph1)
746{
747	struct sockaddr_storage  *local, *remote;
748	phase2_handle_t *p;
749
750	if (iph1->parent_session) {
751		local  = &iph1->parent_session->session_id.local;
752		remote = &iph1->parent_session->session_id.remote;
753
754        set_port(local, extract_port(iph1->local));
755        set_port(remote, extract_port(iph1->remote));
756		iph1->parent_session->ports_floated = 1;
757
758		LIST_FOREACH(p, &iph1->parent_session->ph2tree, ph2ofsession_chain) {
759
760            local  = p->src;
761            remote = p->dst;
762
763            set_port(local, extract_port(iph1->local));
764            set_port(remote, extract_port(iph1->remote));
765		}
766	} else {
767		plog(ASL_LEVEL_DEBUG, "invalid parent session in %s.\n", __FUNCTION__);
768	}
769}
770
771static void
772ike_session_traffic_cop (void *arg)
773{
774    ike_session_t *session = (__typeof__(session))arg;
775
776    if (session &&
777		(session->established && !session->stopped_by_vpn_controller && !session->stop_timestamp.tv_sec && !session->stop_timestamp.tv_usec)) {
778        SCHED_KILL(session->traffic_monitor.sc_mon);
779        /* get traffic query from kernel */
780        if (pk_sendget_inbound_sastats(session) < 0) {
781            // log message
782            plog(ASL_LEVEL_DEBUG, "pk_sendget_inbound_sastats failed in %s.\n", __FUNCTION__);
783        }
784        if (pk_sendget_outbound_sastats(session) < 0) {
785            // log message
786            plog(ASL_LEVEL_DEBUG, "pk_sendget_outbound_sastats failed in %s.\n", __FUNCTION__);
787        }
788        session->traffic_monitor.sc_mon = sched_new(session->traffic_monitor.interv_mon,
789                                                    ike_session_traffic_cop,
790                                                    session);
791    } else {
792        // log message
793		plog(ASL_LEVEL_DEBUG, "invalid parameters in %s.\n", __FUNCTION__);
794    }
795}
796
797static void
798ike_session_cleanup_idle (void *arg)
799{
800    ike_session_cleanup((ike_session_t *)arg, ike_session_stopped_by_idle);
801}
802
803static void
804ike_session_monitor_idle (ike_session_t *session)
805{
806	if (!session)
807		return;
808
809    if (session->traffic_monitor.dir_idle == IPSEC_DIR_INBOUND ||
810        session->traffic_monitor.dir_idle == IPSEC_DIR_ANY) {
811        if (session->peer_sent_data_sc_idle) {
812			plog(ASL_LEVEL_DEBUG, "%s: restart idle-timeout because peer sent data. monitoring dir %d.\n",
813				 __FUNCTION__, session->traffic_monitor.dir_idle);
814            SCHED_KILL(session->traffic_monitor.sc_idle);
815			if (session->traffic_monitor.interv_idle) {
816				session->traffic_monitor.sc_idle = sched_new(session->traffic_monitor.interv_idle,
817															 ike_session_cleanup_idle,
818															 session);
819			}
820            session->peer_sent_data_sc_idle = 0;
821            session->i_sent_data_sc_idle = 0;
822            return;
823        }
824    }
825    if (session->traffic_monitor.dir_idle == IPSEC_DIR_OUTBOUND ||
826        session->traffic_monitor.dir_idle == IPSEC_DIR_ANY) {
827        if (session->i_sent_data_sc_idle) {
828			plog(ASL_LEVEL_DEBUG, "%s: restart idle-timeout because i sent data. monitoring dir %d.\n",
829				 __FUNCTION__, session->traffic_monitor.dir_idle);
830            SCHED_KILL(session->traffic_monitor.sc_idle);
831			if (session->traffic_monitor.interv_idle) {
832				session->traffic_monitor.sc_idle = sched_new(session->traffic_monitor.interv_idle,
833															 ike_session_cleanup_idle,
834															 session);
835			}
836            session->peer_sent_data_sc_idle = 0;
837            session->i_sent_data_sc_idle = 0;
838            return;
839        }
840    }
841}
842
843static void
844ike_session_start_traffic_mon (ike_session_t *session)
845{
846	if (session->traffic_monitor.interv_mon) {
847		session->traffic_monitor.sc_mon = sched_new(session->traffic_monitor.interv_mon,
848															ike_session_traffic_cop,
849															session);
850	}
851	if (session->traffic_monitor.interv_idle) {
852		session->traffic_monitor.sc_idle = sched_new(session->traffic_monitor.interv_idle,
853															ike_session_cleanup_idle,
854															session);
855	}
856}
857
858void
859ike_session_ph2_established (phase2_handle_t *iph2)
860{
861	if (!iph2->parent_session || iph2->phase2_type != PHASE2_TYPE_SA) {
862		plog(ASL_LEVEL_DEBUG, "invalid parameters in %s.\n", __FUNCTION__);
863		return;
864	}
865	SCHED_KILL(iph2->parent_session->sc_xauth);
866	if (!iph2->parent_session->established) {
867		gettimeofday(&iph2->parent_session->estab_timestamp, NULL);
868		iph2->parent_session->established = 1;
869		IPSECSESSIONTRACERESTABLISHED(iph2->parent_session);
870		ike_session_start_traffic_mon(iph2->parent_session);
871	} else if (iph2->parent_session->is_asserted) {
872		ike_session_start_traffic_mon(iph2->parent_session);
873	}
874	iph2->parent_session->is_asserted = 0;
875    // nothing happening to this session
876    iph2->parent_session->term_reason = NULL;
877
878	ike_session_update_mode(iph2);
879    if (iph2->version == ISAKMP_VERSION_NUMBER_IKEV1)
880        ike_session_unbindph12(iph2);
881
882#ifdef ENABLE_VPNCONTROL_PORT
883	vpncontrol_notify_peer_resp_ph2(1, iph2);
884#endif /* ENABLE_VPNCONTROL_PORT */
885	plog(ASL_LEVEL_DEBUG, "%s: ph2 established, spid %d\n", __FUNCTION__, iph2->spid);
886}
887
888void
889ike_session_cleanup_ph1 (phase1_handle_t *iph1)
890{
891    if (FSM_STATE_IS_EXPIRED(iph1->status)) {
892		// since this got here via ike_session_cleanup_other_established_ph1s, assumes LIST_FIRST(&iph1->ph2tree) == NULL
893		iph1->sce = sched_new(1, isakmp_ph1delete_stub, iph1);
894		return;
895    }
896
897	/* send delete information */
898	if (FSM_STATE_IS_ESTABLISHED(iph1->status)) {
899		isakmp_info_send_d1(iph1);
900    }
901
902    isakmp_ph1expire(iph1);
903}
904
905void
906ike_session_cleanup_ph1_stub (void *p)
907{
908
909	ike_session_cleanup_ph1((phase1_handle_t *)p);
910}
911
912void
913ike_session_replace_other_ph1 (phase1_handle_t *new_iph1,
914                               phase1_handle_t *old_iph1)
915{
916	char *local, *remote, *index;
917    ike_session_t *session = NULL;
918
919    if (new_iph1)
920        session = new_iph1->parent_session;
921
922	if (!session || !new_iph1 || !old_iph1 || session != old_iph1->parent_session || new_iph1 == old_iph1) {
923		plog(ASL_LEVEL_DEBUG, "invalid parameters in %s.\n", __FUNCTION__);
924		return;
925	}
926
927	/*
928	 * if we are responder, then we should wait until the server sends a delete notification.
929	 */
930	if ((new_iph1->version == ISAKMP_VERSION_NUMBER_IKEV2 || session->is_client) &&
931		new_iph1->side == RESPONDER) {
932		return;
933	}
934
935    SCHED_KILL(old_iph1->sce);
936    SCHED_KILL(old_iph1->sce_rekey);
937    old_iph1->is_dying = 1;
938
939    //log deletion
940    local  = racoon_strdup(saddr2str((struct sockaddr *)old_iph1->local));
941    remote = racoon_strdup(saddr2str((struct sockaddr *)old_iph1->remote));
942    index = racoon_strdup(isakmp_pindex(&old_iph1->index, 0));
943    STRDUP_FATAL(local);
944    STRDUP_FATAL(remote);
945    STRDUP_FATAL(index);
946    plog(ASL_LEVEL_DEBUG, "ISAKMP-SA %s-%s (spi:%s) needs to be deleted, replaced by (spi:%s)\n", local, remote, index, isakmp_pindex(&new_iph1->index, 0));
947    racoon_free(local);
948    racoon_free(remote);
949    racoon_free(index);
950
951    // first rebind the children ph2s of this dying ph1 to the new ph1.
952    ike_session_rebind_all_ph12_to_new_ph1 (old_iph1, new_iph1);
953
954    if (old_iph1->side == INITIATOR) {
955        /* everyone deletes old outbound SA */
956        old_iph1->sce = sched_new(5, ike_session_cleanup_ph1_stub, old_iph1);
957    } else {
958        /* responder sets up timer to delete old inbound SAs... say 7 secs later and flags them as rekeyed */
959        old_iph1->sce = sched_new(7, ike_session_cleanup_ph1_stub, old_iph1);
960    }
961}
962
963void
964ike_session_cleanup_other_established_ph1s (ike_session_t    *session,
965											phase1_handle_t *new_iph1)
966{
967	phase1_handle_t *p, *next;
968	char             *local, *remote;
969
970	if (!session || !new_iph1 || session != new_iph1->parent_session) {
971		plog(ASL_LEVEL_DEBUG, "invalid parameters in %s.\n", __FUNCTION__);
972		return;
973	}
974
975	/*
976	 * if we are responder, then we should wait until the server sends a delete notification.
977	 */
978	if ((new_iph1->version == ISAKMP_VERSION_NUMBER_IKEV2 || session->is_client) &&
979		new_iph1->side == RESPONDER) {
980		return;
981	}
982
983	LIST_FOREACH_SAFE(p, &session->ph1tree, ph1ofsession_chain, next) {
984		/*
985		 * TODO: currently, most recently established SA wins. Need to revisit to see if
986		 * alternative selections is better (e.g. largest p->index stays).
987		 */
988		if (p != new_iph1 && !p->is_dying) {
989			SCHED_KILL(p->sce);
990			SCHED_KILL(p->sce_rekey);
991			p->is_dying = 1;
992
993			//log deletion
994			local  = racoon_strdup(saddr2str((struct sockaddr *)p->local));
995			remote = racoon_strdup(saddr2str((struct sockaddr *)p->remote));
996			STRDUP_FATAL(local);
997			STRDUP_FATAL(remote);
998			plog(ASL_LEVEL_DEBUG,
999				 "ISAKMP-SA needs to be deleted %s-%s spi:%s\n",
1000				 local, remote, isakmp_pindex(&p->index, 0));
1001			racoon_free(local);
1002			racoon_free(remote);
1003
1004            // first rebind the children ph2s of this dying ph1 to the new ph1.
1005            ike_session_rebind_all_ph12_to_new_ph1 (p, new_iph1);
1006
1007			if (p->side == INITIATOR) {
1008				/* everyone deletes old outbound SA */
1009				p->sce = sched_new(5, ike_session_cleanup_ph1_stub, p);
1010			} else {
1011				/* responder sets up timer to delete old inbound SAs... say 7 secs later and flags them as rekeyed */
1012				p->sce = sched_new(7, ike_session_cleanup_ph1_stub, p);
1013			}
1014		}
1015	}
1016}
1017
1018void
1019ike_session_cleanup_ph2 (phase2_handle_t *iph2)
1020{
1021    if (iph2->phase2_type != PHASE2_TYPE_SA)
1022        return;
1023	if (FSM_STATE_IS_EXPIRED(iph2->status)) {
1024		return;
1025	}
1026
1027	SCHED_KILL(iph2->sce);
1028
1029	plog(ASL_LEVEL_ERR,
1030		 "about to cleanup ph2: status %d, seq %d dying %d\n",
1031		 iph2->status, iph2->seq, iph2->is_dying);
1032
1033	/* send delete information */
1034	if (FSM_STATE_IS_ESTABLISHED(iph2->status)) {
1035		isakmp_info_send_d2(iph2);
1036
1037		// delete outgoing SAs
1038		if (iph2->approval) {
1039			struct saproto *pr;
1040
1041			for (pr = iph2->approval->head; pr != NULL; pr = pr->next) {
1042				if (pr->ok) {
1043					pfkey_send_delete(lcconf->sock_pfkey,
1044                                  ipsecdoi2pfkey_proto(pr->proto_id),
1045                                  IPSEC_MODE_ANY,
1046                                  iph2->src, iph2->dst, pr->spi_p /* pr->reqid_out */);
1047				}
1048			}
1049		}
1050	}
1051
1052	delete_spd(iph2);
1053	ike_session_unlink_phase2(iph2);
1054}
1055
1056void
1057ike_session_cleanup_ph2_stub (void *p)
1058{
1059
1060	ike_session_cleanup_ph2((phase2_handle_t *)p);
1061}
1062
1063void
1064ike_session_cleanup_other_established_ph2s (ike_session_t    *session,
1065											phase2_handle_t *new_iph2)
1066{
1067	phase2_handle_t *p, *next;
1068
1069	if (!session || !new_iph2 || session != new_iph2->parent_session || new_iph2->phase2_type != PHASE2_TYPE_SA) {
1070		plog(ASL_LEVEL_DEBUG, "invalid parameters in %s.\n", __FUNCTION__);
1071		return;
1072	}
1073
1074	/*
1075	 * if we are responder, then we should wait until the server sends a delete notification.
1076	 */
1077	if (session->is_client && new_iph2->side == RESPONDER) {
1078		return;
1079	}
1080
1081	LIST_FOREACH_SAFE(p, &session->ph2tree, ph2ofsession_chain, next) {
1082		/*
1083		 * TODO: currently, most recently established SA wins. Need to revisit to see if
1084		 * alternative selections is better.
1085		 */
1086		if (p != new_iph2 && p->spid == new_iph2->spid && !p->is_dying) {
1087			SCHED_KILL(p->sce);
1088			p->is_dying = 1;
1089
1090			//log deletion
1091			plog(ASL_LEVEL_DEBUG,
1092				 "IPsec-SA needs to be deleted: %s\n",
1093				 sadbsecas2str(p->src, p->dst,
1094							   p->satype, p->spid, 0));
1095
1096			if (p->side == INITIATOR) {
1097				/* responder sets up timer to delete old inbound SAs... say 5 secs later and flags them as rekeyed */
1098				p->sce = sched_new(3, ike_session_cleanup_ph2_stub, p);
1099			} else {
1100				/* responder sets up timer to delete old inbound SAs... say 5 secs later and flags them as rekeyed */
1101				p->sce = sched_new(5, ike_session_cleanup_ph2_stub, p);
1102			}
1103		}
1104	}
1105}
1106
1107void
1108ike_session_stopped_by_controller (ike_session_t *session,
1109								   const char    *reason)
1110{
1111	if (!session) {
1112		plog(ASL_LEVEL_DEBUG, "invalid parameters in %s.\n", __FUNCTION__);
1113		return;
1114	}
1115	if (session->stop_timestamp.tv_sec ||
1116		session->stop_timestamp.tv_usec) {
1117		plog(ASL_LEVEL_DEBUG, "already stopped %s.\n", __FUNCTION__);
1118		return;
1119	}
1120	session->stopped_by_vpn_controller = 1;
1121	gettimeofday(&session->stop_timestamp, NULL);
1122	if (!session->term_reason) {
1123		session->term_reason = (__typeof__(session->term_reason))reason;
1124	}
1125}
1126
1127void
1128ike_sessions_stopped_by_controller (struct sockaddr_storage *remote,
1129                                    int              withport,
1130								    const char      *reason)
1131{
1132	ike_session_t *p = NULL;
1133	ike_session_t *next_session = NULL;
1134
1135	if (!remote) {
1136		plog(ASL_LEVEL_DEBUG, "invalid parameters in %s.\n", __FUNCTION__);
1137		return;
1138	}
1139
1140	LIST_FOREACH_SAFE(p, &ike_session_tree, chain, next_session) {
1141        if ((withport && cmpsaddrstrict(&p->session_id.remote, remote) == 0) ||
1142            (!withport && cmpsaddrwop(&p->session_id.remote, remote) == 0)) {
1143                ike_session_stopped_by_controller(p, reason);
1144		}
1145	}
1146}
1147
1148void
1149ike_session_purge_ph2s_by_ph1 (phase1_handle_t *iph1)
1150{
1151	phase2_handle_t *p, *next;
1152
1153	if (!iph1 || !iph1->parent_session) {
1154		plog(ASL_LEVEL_DEBUG, "invalid parameters in %s.\n", __FUNCTION__);
1155		return;
1156	}
1157
1158	LIST_FOREACH_SAFE(p, &iph1->parent_session->ph2tree, ph2ofsession_chain, next) {
1159		if (p->is_dying) {
1160			continue;
1161		}
1162        SCHED_KILL(p->sce);
1163        p->is_dying = 1;
1164
1165        //log deletion
1166        plog(ASL_LEVEL_DEBUG,
1167             "IPsec-SA needs to be purged: %s\n",
1168             sadbsecas2str(p->src, p->dst,
1169                           p->satype, p->spid, 0));
1170
1171        ike_session_cleanup_ph2(p);
1172	}
1173}
1174
1175void
1176ike_session_update_ph2_ports (phase2_handle_t *iph2)
1177{
1178    struct sockaddr_storage *local;
1179    struct sockaddr_storage *remote;
1180
1181	if (iph2->parent_session) {
1182		local  = &iph2->parent_session->session_id.local;
1183		remote = &iph2->parent_session->session_id.remote;
1184
1185        set_port(iph2->src, extract_port(local));
1186        set_port(iph2->dst, extract_port(remote));
1187	} else {
1188		plog(ASL_LEVEL_DEBUG, "invalid parent session in %s.\n", __FUNCTION__);
1189	}
1190}
1191
1192u_int32_t
1193ike_session_get_sas_for_stats (ike_session_t *session,
1194                               u_int8_t       dir,
1195                               u_int32_t     *seq,
1196                               struct sastat *stats,
1197                               u_int32_t      max_stats)
1198{
1199    int               found = 0;
1200	phase2_handle_t *iph2;
1201
1202    if (!session || !seq || !stats || !max_stats || (dir != IPSEC_DIR_INBOUND && dir != IPSEC_DIR_OUTBOUND)) {
1203		plog(ASL_LEVEL_DEBUG, "invalid args in %s.\n", __FUNCTION__);
1204        return found;
1205    }
1206
1207    *seq = 0;
1208    LIST_FOREACH(iph2, &session->ph2tree, ph2ofsession_chain) {
1209        if (iph2->approval) {
1210            struct saproto *pr;
1211
1212            for (pr = iph2->approval->head; pr != NULL; pr = pr->next) {
1213                if (pr->ok && pr->proto_id == IPSECDOI_PROTO_IPSEC_ESP) {
1214                    if (!*seq) {
1215                        *seq = iph2->seq;
1216                    }
1217                    if (dir == IPSEC_DIR_INBOUND) {
1218                        stats[found].spi = pr->spi;
1219                    } else {
1220                        stats[found].spi = pr->spi_p;
1221                    }
1222                    if (++found == max_stats) {
1223                        return found;
1224                    }
1225                }
1226            }
1227        }
1228    }
1229    return found;
1230}
1231
1232void
1233ike_session_update_traffic_idle_status (ike_session_t *session,
1234                                        u_int32_t      dir,
1235                                        struct sastat *new_stats,
1236                                        u_int32_t      max_stats)
1237{
1238    int i, j, found = 0, idle = 1;
1239
1240    if (!session || !new_stats || (dir != IPSEC_DIR_INBOUND && dir != IPSEC_DIR_OUTBOUND)) {
1241		plog(ASL_LEVEL_DEBUG, "invalid args in %s.\n", __FUNCTION__);
1242        return;
1243    }
1244
1245    if (!session->established || session->stopped_by_vpn_controller || session->stop_timestamp.tv_sec || session->stop_timestamp.tv_usec) {
1246        plog(ASL_LEVEL_DEBUG, "dropping update on invalid session in %s.\n", __FUNCTION__);
1247        return;
1248    }
1249
1250    for (i = 0; i < max_stats; i++) {
1251        if (dir == IPSEC_DIR_INBOUND) {
1252            for (j = 0; j < session->traffic_monitor.num_in_last_poll; j++) {
1253                if (new_stats[i].spi != session->traffic_monitor.in_last_poll[j].spi) {
1254                    continue;
1255                }
1256                found = 1;
1257                if (new_stats[i].lft_c.sadb_lifetime_bytes != session->traffic_monitor.in_last_poll[j].lft_c.sadb_lifetime_bytes) {
1258                    idle = 0;
1259                }
1260            }
1261        } else {
1262            for (j = 0; j < session->traffic_monitor.num_out_last_poll; j++) {
1263                if (new_stats[i].spi != session->traffic_monitor.out_last_poll[j].spi) {
1264                    continue;
1265                }
1266                found = 1;
1267                if (new_stats[i].lft_c.sadb_lifetime_bytes != session->traffic_monitor.out_last_poll[j].lft_c.sadb_lifetime_bytes) {
1268                    idle = 0;
1269                }
1270            }
1271        }
1272        // new SA.... check for any activity
1273        if (!found) {
1274            if (new_stats[i].lft_c.sadb_lifetime_bytes) {
1275                plog(ASL_LEVEL_DEBUG, "new SA: dir %d....\n", dir);
1276                idle = 0;
1277            }
1278        }
1279    }
1280    if (dir == IPSEC_DIR_INBOUND) {
1281        // overwrite old stats
1282        bzero(session->traffic_monitor.in_last_poll, sizeof(session->traffic_monitor.in_last_poll));
1283        bcopy(new_stats, session->traffic_monitor.in_last_poll, (max_stats * sizeof(*new_stats)));
1284        session->traffic_monitor.num_in_last_poll = max_stats;
1285        if (!idle) {
1286            //plog(ASL_LEVEL_DEBUG, "peer sent data....\n");
1287            session->peer_sent_data_sc_dpd = 1;
1288            session->peer_sent_data_sc_idle = 1;
1289        }
1290    } else {
1291        // overwrite old stats
1292        bzero(session->traffic_monitor.out_last_poll, sizeof(session->traffic_monitor.out_last_poll));
1293        bcopy(new_stats, session->traffic_monitor.out_last_poll, (max_stats * sizeof(*new_stats)));
1294        session->traffic_monitor.num_out_last_poll = max_stats;
1295        if (!idle) {
1296            //plog(ASL_LEVEL_DEBUG, "i sent data....\n");
1297            session->i_sent_data_sc_dpd = 1;
1298            session->i_sent_data_sc_idle = 1;
1299        }
1300    }
1301	if (!idle)
1302		session->last_time_data_sc_detected = time(NULL);
1303
1304	ike_session_monitor_idle(session);
1305}
1306
1307void
1308ike_session_cleanup (ike_session_t *session,
1309                     const char    *reason)
1310{
1311    phase2_handle_t *iph2 = NULL;
1312    phase2_handle_t *next_iph2 = NULL;
1313    phase1_handle_t *iph1 = NULL;
1314    phase1_handle_t *next_iph1 = NULL;
1315
1316    if (!session)
1317        return;
1318
1319    session->is_dying = 1;
1320	ike_session_stopped_by_controller(session, reason);
1321
1322	SCHED_KILL(session->traffic_monitor.sc_idle);
1323    // do ph2's first... we need the ph1s for notifications
1324    LIST_FOREACH_SAFE(iph2, &session->ph2tree, ph2ofsession_chain, next_iph2) {
1325        if (FSM_STATE_IS_ESTABLISHED(iph2->status)) {
1326            isakmp_info_send_d2(iph2);
1327        }
1328        isakmp_ph2expire(iph2); // iph2 will go down 1 second later.
1329    }
1330
1331    // do the ph1s last.
1332    LIST_FOREACH_SAFE(iph1, &session->ph1tree, ph1ofsession_chain, next_iph1) {
1333        if (FSM_STATE_IS_ESTABLISHED(iph1->status)) {
1334            isakmp_info_send_d1(iph1);
1335        }
1336        isakmp_ph1expire(iph1);
1337    }
1338
1339    // send ipsecManager a notification
1340    if (session->is_cisco_ipsec && reason && reason != ike_session_stopped_by_vpn_disconnect
1341            && reason != ike_session_stopped_by_controller_comm_lost) {
1342        u_int32_t address;
1343        if ((&session->session_id.remote)->ss_family == AF_INET) {
1344            address = ((struct sockaddr_in *)&session->session_id.remote)->sin_addr.s_addr;
1345        } else {
1346            address = 0;
1347        }
1348        // TODO: log
1349        if (reason == ike_session_stopped_by_idle) {
1350            (void)vpncontrol_notify_ike_failed(VPNCTL_NTYPE_IDLE_TIMEOUT, FROM_LOCAL, address, 0, NULL);
1351        } else {
1352            (void)vpncontrol_notify_ike_failed(VPNCTL_NTYPE_INTERNAL_ERROR, FROM_LOCAL, address, 0, NULL);
1353        }
1354    }
1355}
1356
1357int
1358ike_session_has_negoing_ph1 (ike_session_t *session)
1359{
1360	phase1_handle_t *p;
1361
1362	if (!session) {
1363		plog(ASL_LEVEL_DEBUG, "invalid parameters in %s.\n", __FUNCTION__);
1364		return 0;
1365	}
1366
1367	LIST_FOREACH(p, &session->ph1tree, ph1ofsession_chain) {
1368		if (!p->is_dying && FSM_STATE_IS_NEGOTIATING(p->status)) {
1369			return 1;
1370		}
1371	}
1372
1373	return 0;
1374}
1375
1376int
1377ike_session_has_established_ph1 (ike_session_t *session)
1378{
1379	phase1_handle_t *p;
1380
1381	if (!session) {
1382		plog(ASL_LEVEL_DEBUG, "invalid parameters in %s.\n", __FUNCTION__);
1383		return 0;
1384	}
1385
1386	LIST_FOREACH(p, &session->ph1tree, ph1ofsession_chain) {
1387		if (!p->is_dying && FSM_STATE_IS_ESTABLISHED(p->status)) {
1388			return 1;
1389		}
1390	}
1391
1392	return 0;
1393}
1394
1395int
1396ike_session_has_negoing_ph2 (ike_session_t *session)
1397{
1398	phase2_handle_t *p;
1399
1400	if (!session) {
1401		plog(ASL_LEVEL_DEBUG, "invalid parameters in %s.\n", __FUNCTION__);
1402		return 0;
1403	}
1404
1405	LIST_FOREACH(p, &session->ph2tree, ph2ofsession_chain) {
1406		if (!p->is_dying && FSM_STATE_IS_NEGOTIATING(p->status)) {
1407            return 1;
1408		}
1409	}
1410
1411	return 0;
1412}
1413
1414int
1415ike_session_has_established_ph2 (ike_session_t *session)
1416{
1417	phase2_handle_t *p;
1418
1419	if (!session) {
1420		plog(ASL_LEVEL_DEBUG, "invalid parameters in %s.\n", __FUNCTION__);
1421		return 0;
1422	}
1423
1424	LIST_FOREACH(p, &session->ph2tree, ph2ofsession_chain) {
1425		if (!p->is_dying && FSM_STATE_IS_ESTABLISHED(p->status)) {
1426            return 1;
1427		}
1428	}
1429
1430	return 0;
1431}
1432
1433void
1434ike_session_cleanup_ph1s_by_ph2 (phase2_handle_t *iph2)
1435{
1436	phase1_handle_t *iph1 = NULL;
1437	phase1_handle_t *next_iph1 = NULL;
1438
1439	if (!iph2 || !iph2->parent_session) {
1440		plog(ASL_LEVEL_DEBUG, "invalid parameters in %s.\n", __FUNCTION__);
1441		return;
1442	}
1443
1444	// phase1 is no longer useful
1445	LIST_FOREACH_SAFE(iph1, &iph2->parent_session->ph1tree, ph1ofsession_chain, next_iph1) {
1446		if (FSM_STATE_IS_ESTABLISHED(iph1->status)) {
1447			isakmp_info_send_d1(iph1);
1448		}
1449		isakmp_ph1expire(iph1);
1450	}
1451}
1452
1453int
1454ike_session_is_client_ph2_rekey (phase2_handle_t *iph2)
1455{
1456    if (iph2->parent_session &&
1457        iph2->parent_session->is_client &&
1458        iph2->is_rekey &&
1459        iph2->parent_session->is_cisco_ipsec) {
1460        return 1;
1461    }
1462    return 0;
1463}
1464
1465int
1466ike_session_is_client_ph1_rekey (phase1_handle_t *iph1)
1467{
1468    if (iph1->parent_session &&
1469        iph1->parent_session->is_client &&
1470        iph1->is_rekey &&
1471        iph1->parent_session->is_cisco_ipsec) {
1472        return 1;
1473    }
1474    return 0;
1475}
1476
1477int
1478ike_session_is_client_ph1 (phase1_handle_t *iph1)
1479{
1480	if (iph1->parent_session &&
1481		iph1->parent_session->is_client) {
1482		return 1;
1483	}
1484	return 0;
1485}
1486
1487int
1488ike_session_is_client_ph2 (phase2_handle_t *iph2)
1489{
1490	if (iph2->parent_session &&
1491		iph2->parent_session->is_client) {
1492		return 1;
1493	}
1494	return 0;
1495}
1496
1497void
1498ike_session_start_xauth_timer (phase1_handle_t *iph1)
1499{
1500    // if there are no more established ph2s, start a timer to teardown the session
1501    if (iph1->parent_session &&
1502        iph1->parent_session->is_client &&
1503        iph1->parent_session->is_cisco_ipsec &&
1504        !iph1->parent_session->sc_xauth) {
1505        iph1->parent_session->sc_xauth = sched_new(300 /* 5 mins */,
1506                                                   ike_session_cleanup_xauth_timeout,
1507                                                   iph1->parent_session);
1508    }
1509}
1510
1511void
1512ike_session_stop_xauth_timer (phase1_handle_t *iph1)
1513{
1514    if (iph1->parent_session) {
1515        SCHED_KILL(iph1->parent_session->sc_xauth);
1516    }
1517}
1518
1519static int
1520ike_session_is_id_ipany (vchar_t *ext_id)
1521{
1522	struct id {
1523		u_int8_t type;		/* ID Type */
1524		u_int8_t proto_id;	/* Protocol ID */
1525		u_int16_t port;		/* Port */
1526		u_int32_t addr;		/* IPv4 address */
1527		u_int32_t mask;
1528	} *id_ptr;
1529
1530	/* ignore protocol and port */
1531	id_ptr = ALIGNED_CAST(struct id *)ext_id->v;
1532	if (id_ptr->type == IPSECDOI_ID_IPV4_ADDR &&
1533	    id_ptr->addr == 0) {
1534		return 1;
1535	} else if (id_ptr->type == IPSECDOI_ID_IPV4_ADDR_SUBNET &&
1536			   id_ptr->mask == 0 &&
1537			   id_ptr->addr == 0) {
1538		return 1;
1539	}
1540	plog(ASL_LEVEL_DEBUG, "not ipany_ids in %s: type %d, addr %x, mask %x.\n",
1541		 __FUNCTION__, id_ptr->type, id_ptr->addr, id_ptr->mask);
1542	return 0;
1543}
1544
1545static int
1546ike_session_is_id_portany (vchar_t *ext_id)
1547{
1548	struct id {
1549		u_int8_t type;		/* ID Type */
1550		u_int8_t proto_id;	/* Protocol ID */
1551		u_int16_t port;		/* Port */
1552		u_int32_t addr;		/* IPv4 address */
1553		u_int32_t mask;
1554	} *id_ptr;
1555
1556	/* ignore addr */
1557	id_ptr = ALIGNED_CAST(struct id *)ext_id->v;
1558	if (id_ptr->type == IPSECDOI_ID_IPV4_ADDR &&
1559	    id_ptr->port == 0) {
1560		return 1;
1561	}
1562	plog(ASL_LEVEL_DEBUG, "not portany_ids in %s: type %d, port %x.\n",
1563		 __FUNCTION__, id_ptr->type, id_ptr->port);
1564	return 0;
1565}
1566
1567static void
1568ike_session_set_id_portany (vchar_t *ext_id)
1569{
1570	struct id {
1571		u_int8_t type;		/* ID Type */
1572		u_int8_t proto_id;	/* Protocol ID */
1573		u_int16_t port;		/* Port */
1574		u_int32_t addr;		/* IPv4 address */
1575		u_int32_t mask;
1576	} *id_ptr;
1577
1578	/* ignore addr */
1579	id_ptr = ALIGNED_CAST(struct id *)ext_id->v;
1580	if (id_ptr->type == IPSECDOI_ID_IPV4_ADDR) {
1581	    id_ptr->port = 0;
1582		return;
1583	}
1584}
1585
1586static int
1587ike_session_cmp_ph2_ids_ipany (vchar_t *ext_id,
1588							   vchar_t *ext_id_p)
1589{
1590	if (ike_session_is_id_ipany(ext_id) &&
1591	    ike_session_is_id_ipany(ext_id_p)) {
1592		return 1;
1593	}
1594	return 0;
1595}
1596
1597/*
1598 * ipsec rekeys for l2tp-over-ipsec fail particularly when client is behind nat because the client's configs and policies don't
1599 * match the server's view of the client's address and port.
1600 * servers behave differently when using this address-port info to generate ids during phase2 rekeys, so try to match the incoming id to
1601 * a variety of info saved in the older phase2.
1602 */
1603int
1604ike_session_cmp_ph2_ids (phase2_handle_t *iph2,
1605						 phase2_handle_t *older_ph2)
1606{
1607	vchar_t *portany_id = NULL;
1608	vchar_t *portany_id_p = NULL;
1609
1610	if (iph2->id && older_ph2->id &&
1611	    iph2->id->l == older_ph2->id->l &&
1612	    memcmp(iph2->id->v, older_ph2->id->v, iph2->id->l) == 0 &&
1613	    iph2->id_p && older_ph2->id_p &&
1614	    iph2->id_p->l == older_ph2->id_p->l &&
1615	    memcmp(iph2->id_p->v, older_ph2->id_p->v, iph2->id_p->l) == 0) {
1616		return 0;
1617	}
1618	if (iph2->ext_nat_id && older_ph2->ext_nat_id &&
1619	    iph2->ext_nat_id->l == older_ph2->ext_nat_id->l &&
1620	    memcmp(iph2->ext_nat_id->v, older_ph2->ext_nat_id->v, iph2->ext_nat_id->l) == 0 &&
1621	    iph2->ext_nat_id_p && older_ph2->ext_nat_id_p &&
1622	    iph2->ext_nat_id_p->l == older_ph2->ext_nat_id_p->l &&
1623	    memcmp(iph2->ext_nat_id_p->v, older_ph2->ext_nat_id_p->v, iph2->ext_nat_id_p->l) == 0) {
1624		return 0;
1625	}
1626	if (iph2->id && older_ph2->ext_nat_id &&
1627	    iph2->id->l == older_ph2->ext_nat_id->l &&
1628	    memcmp(iph2->id->v, older_ph2->ext_nat_id->v, iph2->id->l) == 0 &&
1629	    iph2->id_p && older_ph2->ext_nat_id_p &&
1630	    iph2->id_p->l == older_ph2->ext_nat_id_p->l &&
1631	    memcmp(iph2->id_p->v, older_ph2->ext_nat_id_p->v, iph2->id_p->l) == 0) {
1632		return 0;
1633	}
1634	if (iph2->id && older_ph2->ext_nat_id &&
1635	    iph2->id->l == older_ph2->ext_nat_id->l &&
1636	    memcmp(iph2->id->v, older_ph2->ext_nat_id->v, iph2->id->l) == 0 &&
1637	    iph2->id_p && older_ph2->id_p &&
1638	    iph2->id_p->l == older_ph2->id_p->l &&
1639	    memcmp(iph2->id_p->v, older_ph2->id_p->v, iph2->id_p->l) == 0) {
1640		return 0;
1641	}
1642	if (iph2->id && older_ph2->id &&
1643	    iph2->id->l == older_ph2->id->l &&
1644	    memcmp(iph2->id->v, older_ph2->id->v, iph2->id->l) == 0 &&
1645	    iph2->id_p && older_ph2->ext_nat_id_p &&
1646	    iph2->id_p->l == older_ph2->ext_nat_id_p->l &&
1647	    memcmp(iph2->id_p->v, older_ph2->ext_nat_id_p->v, iph2->id_p->l) == 0) {
1648		return 0;
1649	}
1650
1651	/* check if the external id has a wildcard port and compare ids accordingly */
1652	if ((older_ph2->ext_nat_id && ike_session_is_id_portany(older_ph2->ext_nat_id)) ||
1653		(older_ph2->ext_nat_id_p && ike_session_is_id_portany(older_ph2->ext_nat_id_p))) {
1654		// try ignoring ports in iph2->id and iph2->id
1655		if (iph2->id && (portany_id = vdup(iph2->id))) {
1656			ike_session_set_id_portany(portany_id);
1657		}
1658		if (iph2->id_p && (portany_id_p = vdup(iph2->id_p))) {
1659			ike_session_set_id_portany(portany_id_p);
1660		}
1661		if (portany_id && older_ph2->ext_nat_id &&
1662			portany_id->l == older_ph2->ext_nat_id->l &&
1663			memcmp(portany_id->v, older_ph2->ext_nat_id->v, portany_id->l) == 0 &&
1664			portany_id_p && older_ph2->ext_nat_id_p &&
1665			portany_id_p->l == older_ph2->ext_nat_id_p->l &&
1666			memcmp(portany_id_p->v, older_ph2->ext_nat_id_p->v, portany_id_p->l) == 0) {
1667			if (portany_id) {
1668				vfree(portany_id);
1669			}
1670			if (portany_id_p) {
1671				vfree(portany_id_p);
1672			}
1673			return 0;
1674		}
1675		if (portany_id && iph2->id && older_ph2->ext_nat_id &&
1676			iph2->id->l == older_ph2->ext_nat_id->l &&
1677			memcmp(portany_id->v, older_ph2->ext_nat_id->v, portany_id->l) == 0 &&
1678			iph2->id_p && older_ph2->id_p &&
1679			iph2->id_p->l == older_ph2->id_p->l &&
1680			memcmp(iph2->id_p->v, older_ph2->id_p->v, iph2->id_p->l) == 0) {
1681			if (portany_id) {
1682				vfree(portany_id);
1683			}
1684			if (portany_id_p) {
1685				vfree(portany_id_p);
1686			}
1687			return 0;
1688		}
1689		if (portany_id_p && iph2->id && older_ph2->id &&
1690			iph2->id->l == older_ph2->id->l &&
1691			memcmp(iph2->id->v, older_ph2->id->v, iph2->id->l) == 0 &&
1692			iph2->id_p && older_ph2->ext_nat_id_p &&
1693			iph2->id_p->l == older_ph2->ext_nat_id_p->l &&
1694			memcmp(portany_id_p->v, older_ph2->ext_nat_id_p->v, portany_id_p->l) == 0) {
1695			if (portany_id) {
1696				vfree(portany_id);
1697			}
1698			if (portany_id_p) {
1699				vfree(portany_id_p);
1700			}
1701			return 0;
1702		}
1703		if (portany_id) {
1704			vfree(portany_id);
1705		}
1706		if (portany_id_p) {
1707			vfree(portany_id_p);
1708		}
1709	}
1710	return -1;
1711}
1712
1713int
1714ike_session_get_sainfo_r (phase2_handle_t *iph2)
1715{
1716    if (iph2->parent_session &&
1717        iph2->parent_session->is_client &&
1718        iph2->id && iph2->id_p) {
1719        phase2_handle_t *p;
1720        int ipany_ids = ike_session_cmp_ph2_ids_ipany(iph2->id, iph2->id_p);
1721        plog(ASL_LEVEL_DEBUG, "ipany_ids %d in %s.\n", ipany_ids, __FUNCTION__);
1722
1723        LIST_FOREACH(p, &iph2->parent_session->ph2tree, ph2ofsession_chain) {
1724            if (iph2 != p && !p->is_dying && FSM_STATE_IS_ESTABLISHED_OR_EXPIRED(p->status) && p->sainfo) {
1725                plog(ASL_LEVEL_DEBUG, "candidate ph2 found in %s.\n", __FUNCTION__);
1726                if (ipany_ids ||
1727                    ike_session_cmp_ph2_ids(iph2, p) == 0) {
1728                    plog(ASL_LEVEL_DEBUG, "candidate ph2 matched in %s.\n", __FUNCTION__);
1729                    iph2->sainfo = p->sainfo;
1730                    if (iph2->sainfo)
1731                        retain_sainfo(iph2->sainfo);
1732                    if (!iph2->spid) {
1733                        iph2->spid = p->spid;
1734                    } else {
1735                        plog(ASL_LEVEL_DEBUG, "%s: pre-assigned spid %d.\n", __FUNCTION__, iph2->spid);
1736                    }
1737                    if (p->ext_nat_id) {
1738                        if (iph2->ext_nat_id) {
1739                            vfree(iph2->ext_nat_id);
1740                        }
1741                        iph2->ext_nat_id = vdup(p->ext_nat_id);
1742                    }
1743                    if (p->ext_nat_id_p) {
1744                        if (iph2->ext_nat_id_p) {
1745                            vfree(iph2->ext_nat_id_p);
1746                        }
1747                        iph2->ext_nat_id_p = vdup(p->ext_nat_id_p);
1748                    }
1749                    return 0;
1750                }
1751            }
1752        }
1753    }
1754    return -1;
1755}
1756
1757int
1758ike_session_get_proposal_r (phase2_handle_t *iph2)
1759{
1760	if (iph2->parent_session &&
1761	    iph2->parent_session->is_client &&
1762	    iph2->id && iph2->id_p) {
1763		phase2_handle_t *p;
1764		int ipany_ids = ike_session_cmp_ph2_ids_ipany(iph2->id, iph2->id_p);
1765		plog(ASL_LEVEL_DEBUG, "ipany_ids %d in %s.\n", ipany_ids, __FUNCTION__);
1766
1767		LIST_FOREACH(p, &iph2->parent_session->ph2tree, ph2ofsession_chain) {
1768			if (iph2 != p && !p->is_dying && FSM_STATE_IS_ESTABLISHED_OR_EXPIRED(p->status) &&
1769			    p->approval) {
1770				plog(ASL_LEVEL_DEBUG, "candidate ph2 found in %s.\n", __FUNCTION__);
1771				if (ipany_ids ||
1772				    ike_session_cmp_ph2_ids(iph2, p) == 0) {
1773					plog(ASL_LEVEL_DEBUG, "candidate ph2 matched in %s.\n", __FUNCTION__);
1774					iph2->proposal = dupsaprop(p->approval, 1);
1775					if (!iph2->spid) {
1776						iph2->spid = p->spid;
1777					} else {
1778						plog(ASL_LEVEL_DEBUG, "%s: pre-assigned spid %d.\n", __FUNCTION__, iph2->spid);
1779					}
1780					return 0;
1781				}
1782			}
1783		}
1784	}
1785	return -1;
1786}
1787
1788void
1789ike_session_update_natt_version (phase1_handle_t *iph1)
1790{
1791	if (iph1->parent_session) {
1792		if (iph1->natt_options) {
1793			iph1->parent_session->natt_version = iph1->natt_options->version;
1794		} else {
1795			iph1->parent_session->natt_version = 0;
1796		}
1797	}
1798}
1799
1800int
1801ike_session_get_natt_version (phase1_handle_t *iph1)
1802{
1803	if (iph1->parent_session) {
1804		return(iph1->parent_session->natt_version);
1805	}
1806	return 0;
1807}
1808
1809int
1810ike_session_drop_rekey (ike_session_t *session, ike_session_rekey_type_t rekey_type)
1811{
1812	if (session) {
1813		if (session->is_btmm_ipsec &&
1814			session->last_time_data_sc_detected &&
1815			session->traffic_monitor.interv_mon &&
1816			session->traffic_monitor.interv_idle) {
1817			// for btmm: drop ph1/ph2 rekey if session is idle
1818			time_t now = time(NULL);
1819
1820			if ((now - session->last_time_data_sc_detected) > (session->traffic_monitor.interv_mon << 1)) {
1821				plog(ASL_LEVEL_DEBUG, "btmm session is idle: drop ph%drekey.\n",
1822					 rekey_type);
1823				return 1;
1824			}
1825		} else if (!session->is_btmm_ipsec) {
1826			if (rekey_type == IKE_SESSION_REKEY_TYPE_PH1 &&
1827				!ike_session_has_negoing_ph2(session) && !ike_session_has_established_ph2(session)) {
1828				// for vpn: only drop ph1 if there are no more ph2s.
1829				plog(ASL_LEVEL_DEBUG, "vpn session is idle: drop ph1 rekey.\n");
1830				return 1;
1831			}
1832		}
1833	}
1834	return 0;
1835}
1836
1837/*
1838 * this is called after racooon receives a 'kIOMessageSystemHasPoweredOn'
1839 * a lot is done to make sure that we don't sweep a session that's already been asserted.
1840 * however, it'll be too bad if the assertion comes after the session has already been swept.
1841 */
1842void
1843ike_session_sweep_sleepwake (void)
1844{
1845	ike_session_t *p = NULL;
1846	ike_session_t *next_session = NULL;
1847
1848	// flag session as dying if all ph1/ph2 are dead/dying
1849	LIST_FOREACH_SAFE(p, &ike_session_tree, chain, next_session) {
1850		if (p->is_dying) {
1851			plog(ASL_LEVEL_DEBUG, "skipping sweep of dying session.\n");
1852			continue;
1853		}
1854		SCHED_KILL(p->sc_xauth);
1855		if (p->is_asserted) {
1856			// for asserted session, traffic monitors will be restared after phase2 becomes established.
1857			SCHED_KILL(p->traffic_monitor.sc_mon);
1858			SCHED_KILL(p->traffic_monitor.sc_idle);
1859			plog(ASL_LEVEL_DEBUG, "skipping sweep of asserted session.\n");
1860			continue;
1861		}
1862
1863		// cleanup any stopped sessions as they will go down
1864                if (p->stopped_by_vpn_controller || p->stop_timestamp.tv_sec || p->stop_timestamp.tv_usec) {
1865			plog(ASL_LEVEL_DEBUG, "sweeping stopped session.\n");
1866			ike_session_cleanup(p, ike_session_stopped_by_sleepwake);
1867			continue;
1868                }
1869
1870		if (!ike_session_has_established_ph1(p) && !ike_session_has_established_ph2(p)) {
1871			plog(ASL_LEVEL_DEBUG, "session died while sleeping.\n");
1872			ike_session_cleanup(p, ike_session_stopped_by_sleepwake);
1873			continue;
1874		}
1875		if (p->traffic_monitor.sc_mon) {
1876            time_t xtime;
1877            if (sched_get_time(p->traffic_monitor.sc_mon, &xtime)) {
1878                if (xtime <= swept_at) {
1879                    SCHED_KILL(p->traffic_monitor.sc_mon);
1880                    if (!p->is_dying && p->traffic_monitor.interv_mon) {
1881                        p->traffic_monitor.sc_mon = sched_new(p->traffic_monitor.interv_mon,
1882														  ike_session_traffic_cop,
1883														  p);
1884                    }
1885                }
1886			}
1887		}
1888		if (p->traffic_monitor.sc_idle) {
1889            time_t xtime;
1890            if (sched_get_time(p->traffic_monitor.sc_idle, &xtime)) {
1891                if (xtime <= swept_at) {
1892                    SCHED_KILL(p->traffic_monitor.sc_idle);
1893                    if (!p->is_dying && p->traffic_monitor.interv_idle) {
1894                        p->traffic_monitor.sc_idle = sched_new(p->traffic_monitor.interv_idle,
1895														   ike_session_cleanup_idle,
1896														   p);
1897                    }
1898                }
1899			}
1900		}
1901	}
1902}
1903
1904/*
1905 * this is called after racooon receives an assert command from the controller/pppd.
1906 * this is intended to make racoon prepare to rekey both SAs because a network event occurred.
1907 * in the event of a sleepwake, the assert could happen before or after 'ike_session_sweep_sleepwake'.
1908 */
1909int
1910ike_session_assert_session (ike_session_t *session)
1911{
1912	phase2_handle_t *iph2 = NULL;
1913	phase2_handle_t *iph2_next = NULL;
1914	phase1_handle_t *iph1 = NULL;
1915	phase1_handle_t *iph1_next = NULL;
1916
1917	if (!session || session->is_dying) {
1918		plog(ASL_LEVEL_DEBUG, "Invalid parameters in %s.\n", __FUNCTION__);
1919		return -1;
1920	}
1921
1922	// the goal is to prepare the session for fresh rekeys by silently deleting the currently active phase2s
1923	LIST_FOREACH_SAFE(iph2, &session->ph2tree, ph2ofsession_chain, iph2_next) {
1924		if (!iph2->is_dying && !FSM_STATE_IS_EXPIRED(iph2->status)) {
1925			SCHED_KILL(iph2->sce);
1926			iph2->is_dying = 1;
1927
1928			// delete SAs (in the kernel)
1929			if (FSM_STATE_IS_ESTABLISHED(iph2->status) && iph2->approval) {
1930				struct saproto *pr;
1931
1932				for (pr = iph2->approval->head; pr != NULL; pr = pr->next) {
1933					if (pr->ok) {
1934						//log deletion
1935						plog(ASL_LEVEL_DEBUG,
1936							 "Assert: Phase 2 %s deleted\n",
1937							 sadbsecas2str(iph2->src, iph2->dst, iph2->satype, iph2->spid, ipsecdoi2pfkey_mode(pr->encmode)));
1938
1939						pfkey_send_delete(lcconf->sock_pfkey,
1940										  ipsecdoi2pfkey_proto(pr->proto_id),
1941										  ipsecdoi2pfkey_mode(pr->encmode),
1942										  iph2->src, iph2->dst, pr->spi_p);
1943					}
1944				}
1945			}
1946
1947			fsm_set_state(&iph2->status, IKEV1_STATE_PHASE2_EXPIRED); 	// we want to delete SAs without telling the PEER
1948			iph2->sce = sched_new(3, ike_session_cleanup_ph2_stub, iph2);
1949		}
1950	}
1951
1952	// the goal is to prepare the session for fresh rekeys by silently deleting the currently active phase1s
1953	LIST_FOREACH_SAFE(iph1, &session->ph1tree, ph1ofsession_chain, iph1_next) {
1954		if (!iph1->is_dying && !FSM_STATE_IS_EXPIRED(iph1->status)) {
1955			SCHED_KILL(iph1->sce);
1956			SCHED_KILL(iph1->sce_rekey);
1957			iph1->is_dying = 1;
1958
1959			//log deletion
1960			plog(ASL_LEVEL_DEBUG,
1961				 "Assert: Phase 1 %s deleted\n",
1962				 isakmp_pindex(&iph1->index, 0));
1963
1964			ike_session_unbind_all_ph2_from_ph1(iph1);
1965
1966			fsm_set_state(&iph1->status, IKEV1_STATE_PHASE1_EXPIRED); 	// we want to delete SAs without telling the PEER
1967			/* responder sets up timer to delete old inbound SAs... say 7 secs later and flags them as rekeyed */
1968			iph1->sce = sched_new(5, ike_session_cleanup_ph1_stub, iph1);
1969		}
1970	}
1971	session->is_asserted = 1;
1972
1973	return 0;
1974}
1975
1976int
1977ike_session_assert (struct sockaddr_storage *local,
1978					struct sockaddr_storage *remote)
1979{
1980	ike_session_t *sess;
1981
1982	if (!local || !remote) {
1983		plog(ASL_LEVEL_DEBUG, "invalid parameters in %s.\n", __FUNCTION__);
1984		return -1;
1985	}
1986
1987	if ((sess = ike_session_get_session(local, remote, FALSE, NULL))) {
1988		return(ike_session_assert_session(sess));
1989	}
1990	return -1;
1991}
1992
1993void
1994ike_session_ph2_retransmits (phase2_handle_t *iph2)
1995{
1996	int num_retransmits;
1997
1998	if (!iph2->is_dying &&
1999		iph2->is_rekey &&
2000		iph2->ph1 &&
2001		iph2->ph1->sce_rekey && !sched_is_dead(iph2->ph1->sce_rekey) &&
2002		iph2->side == INITIATOR &&
2003		iph2->parent_session &&
2004		!iph2->parent_session->is_cisco_ipsec && /* not for Cisco */
2005		iph2->parent_session->is_client) {
2006		num_retransmits = iph2->ph1->rmconf->retry_counter - iph2->retry_counter;
2007		if (num_retransmits == 3) {
2008			/*
2009			 * phase2 negotiation is stalling on retransmits, inspite of a valid ph1.
2010			 * one of the following is possible:
2011			 * - (0) severe packet loss.
2012			 * - (1) the peer is dead.
2013			 * - (2) the peer is out of sync hence dropping this phase2 rekey (and perhaps responding with insecure
2014			 *       invalid-cookie notifications... but those are untrusted and so we can't rekey phase1 off that)
2015			 *		(2.1) the peer rebooted (or process restarted) and is now alive.
2016			 *     (2.2) the peer has deleted phase1 without notifying us (or the notification got dropped somehow).
2017			 *     (2.3) the peer has a policy/bug stopping this phase2 rekey
2018			 *
2019			 * in all these cases, one sure way to know is to trigger a phase1 rekey early.
2020			 */
2021			plog(ASL_LEVEL_DEBUG, "Many Phase 2 retransmits: try Phase 1 rekey and this Phase 2 to quit earlier.\n");
2022			isakmp_ph1rekeyexpire(iph2->ph1, TRUE);
2023			iph2->retry_counter = 0;
2024		}
2025	}
2026}
2027
2028void
2029ike_session_ph1_retransmits (phase1_handle_t *iph1)
2030{
2031	int num_retransmits;
2032
2033	if (!iph1->is_dying &&
2034		iph1->is_rekey &&
2035		!iph1->sce_rekey &&
2036		FSM_STATE_IS_NEGOTIATING(iph1->status) &&
2037		iph1->side == INITIATOR &&
2038		iph1->parent_session &&
2039		iph1->parent_session->is_client &&
2040		!ike_session_has_other_negoing_ph1(iph1->parent_session, iph1)) {
2041		num_retransmits = iph1->rmconf->retry_counter - iph1->retry_counter;
2042		if (num_retransmits == 3) {
2043			plog(ASL_LEVEL_DEBUG, "Many Phase 1 retransmits: try quit earlier.\n");
2044			iph1->retry_counter = 0;
2045		}
2046	}
2047}
2048
2049static void
2050ike_session_bindph12(phase1_handle_t *iph1, phase2_handle_t *iph2)
2051{
2052	if (iph2->ph1) {
2053		plog(ASL_LEVEL_ERR, "Phase 2 already bound %s.\n", __FUNCTION__);
2054	}
2055	iph2->ph1 = iph1;
2056    LIST_INSERT_HEAD(&iph1->bound_ph2tree, iph2, ph1bind_chain);
2057}
2058
2059void
2060ike_session_unbindph12(phase2_handle_t *iph2)
2061{
2062	if (iph2->ph1 != NULL) {
2063		iph2->ph1 = NULL;
2064        LIST_REMOVE(iph2, ph1bind_chain);
2065	}
2066}
2067
2068static void
2069ike_session_rebindph12(phase1_handle_t *new_ph1, phase2_handle_t *iph2)
2070{
2071	if (!new_ph1) {
2072		return;
2073	}
2074
2075	// reconcile the ph1-to-ph2 binding
2076	ike_session_unbindph12(iph2);
2077	ike_session_bindph12(new_ph1, iph2);
2078	// recalculate ivm since ph1 binding has changed
2079	if (iph2->ivm != NULL) {
2080		oakley_delivm(iph2->ivm);
2081		if (FSM_STATE_IS_ESTABLISHED(new_ph1->status)) {
2082			iph2->ivm = oakley_newiv2(new_ph1, iph2->msgid);
2083			plog(ASL_LEVEL_DEBUG, "Phase 1-2 binding changed... recalculated ivm.\n");
2084		} else {
2085			iph2->ivm = NULL;
2086		}
2087	}
2088}
2089
2090static void
2091ike_session_unbind_all_ph2_from_ph1 (phase1_handle_t *iph1)
2092{
2093	phase2_handle_t *p = NULL;
2094	phase2_handle_t *next = NULL;
2095
2096	LIST_FOREACH_SAFE(p, &iph1->bound_ph2tree, ph1bind_chain, next) {
2097		ike_session_unbindph12(p);
2098	}
2099}
2100
2101static void
2102ike_session_rebind_all_ph12_to_new_ph1 (phase1_handle_t *old_iph1,
2103                                        phase1_handle_t *new_iph1)
2104{
2105	phase2_handle_t *p = NULL;
2106	phase2_handle_t *next = NULL;
2107
2108	if (old_iph1 == new_iph1 || !old_iph1 || !new_iph1) {
2109		plog(ASL_LEVEL_DEBUG, "Invalid parameters in %s.\n", __FUNCTION__);
2110		return;
2111	}
2112
2113	if (old_iph1->parent_session != new_iph1->parent_session) {
2114		plog(ASL_LEVEL_DEBUG, "Invalid parent sessions in %s.\n", __FUNCTION__);
2115		return;
2116	}
2117
2118	LIST_FOREACH_SAFE(p, &old_iph1->bound_ph2tree, ph1bind_chain, next) {
2119		if (p->parent_session != new_iph1->parent_session) {
2120			plog(ASL_LEVEL_ERR, "Mismatched parent session in ph1bind replacement.\n");
2121		}
2122		if (p->ph1 == new_iph1) {
2123			plog(ASL_LEVEL_ERR, "Same Phase 2 in ph1bind replacement in %s.\n",__FUNCTION__);
2124		}
2125        ike_session_rebindph12(new_iph1, p);
2126	}
2127}
2128
2129