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