diff options
Diffstat (limited to 'src/pluto/timer.c')
-rw-r--r-- | src/pluto/timer.c | 875 |
1 files changed, 452 insertions, 423 deletions
diff --git a/src/pluto/timer.c b/src/pluto/timer.c index aea293098..ecbee740f 100644 --- a/src/pluto/timer.c +++ b/src/pluto/timer.c @@ -11,8 +11,6 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. - * - * RCSID $Id: timer.c 3252 2007-10-06 21:24:50Z andreas $ */ #include <stdio.h> @@ -26,36 +24,39 @@ #include <freeswan.h> +#include <library.h> +#include <crypto/rngs/rng.h> + #include "constants.h" #include "defs.h" #include "connections.h" #include "state.h" #include "demux.h" -#include "ipsec_doi.h" /* needs demux.h and state.h */ +#include "ipsec_doi.h" /* needs demux.h and state.h */ #include "kernel.h" #include "server.h" #include "log.h" -#include "rnd.h" #include "timer.h" #include "whack.h" #include "nat_traversal.h" -/* monotonic version of time(3) */ -time_t -now(void) +/** + * monotonic version of time(3) + */ +time_t now(void) { - static time_t delta = 0 - , last_time = 0; - time_t n = time((time_t)NULL); - - passert(n != (time_t)-1); - if (last_time > n) - { - plog("time moved backwards %ld seconds", (long)(last_time - n)); - delta += last_time - n; - } - last_time = n; - return n + delta; + static time_t delta = 0 + , last_time = 0; + time_t n = time((time_t)NULL); + + passert(n != (time_t)-1); + if (last_time > n) + { + plog("time moved backwards %ld seconds", (long)(last_time - n)); + delta += last_time - n; + } + last_time = n; + return n + delta; } /* This file has the event handling routines. Events are @@ -66,467 +67,495 @@ now(void) static struct event *evlist = (struct event *) NULL; -/* +/** * This routine places an event in the event list. */ -void -event_schedule(enum event_type type, time_t tm, struct state *st) +void event_schedule(enum event_type type, time_t tm, struct state *st) { - struct event *ev = alloc_thing(struct event, "struct event in event_schedule()"); - - ev->ev_type = type; - ev->ev_time = tm + now(); - ev->ev_state = st; - - /* If the event is associated with a state, put a backpointer to the - * event in the state object, so we can find and delete the event - * if we need to (for example, if we receive a reply). - */ - if (st != NULL) - { - if (type == EVENT_DPD || type == EVENT_DPD_TIMEOUT) + struct event *ev = malloc_thing(struct event); + + ev->ev_type = type; + ev->ev_time = tm + now(); + ev->ev_state = st; + + /* If the event is associated with a state, put a backpointer to the + * event in the state object, so we can find and delete the event + * if we need to (for example, if we receive a reply). + */ + if (st != NULL) + { + if (type == EVENT_DPD || type == EVENT_DPD_TIMEOUT) + { + passert(st->st_dpd_event == NULL); + st->st_dpd_event = ev; + } + else + { + passert(st->st_event == NULL); + st->st_event = ev; + } + } + + DBG(DBG_CONTROL, + if (st == NULL) + DBG_log("inserting event %N, timeout in %lu seconds" + , timer_event_names, type, (unsigned long)tm); + else + DBG_log("inserting event %N, timeout in %lu seconds for #%lu" + , timer_event_names, type, (unsigned long)tm + , ev->ev_state->st_serialno)); + + if (evlist == (struct event *) NULL + || evlist->ev_time >= ev->ev_time) { - passert(st->st_dpd_event == NULL); - st->st_dpd_event = ev; + ev->ev_next = evlist; + evlist = ev; } else { - passert(st->st_event == NULL); - st->st_event = ev; - } - } + struct event *evt; - DBG(DBG_CONTROL, - if (st == NULL) - DBG_log("inserting event %s, timeout in %lu seconds" - , enum_show(&timer_event_names, type), (unsigned long)tm); - else - DBG_log("inserting event %s, timeout in %lu seconds for #%lu" - , enum_show(&timer_event_names, type), (unsigned long)tm - , ev->ev_state->st_serialno)); - - if (evlist == (struct event *) NULL - || evlist->ev_time >= ev->ev_time) - { - ev->ev_next = evlist; - evlist = ev; - } - else - { - struct event *evt; - - for (evt = evlist; evt->ev_next != NULL; evt = evt->ev_next) - if (evt->ev_next->ev_time >= ev->ev_time) - break; - -#ifdef NEVER /* this seems to be overkill */ - DBG(DBG_CONTROL, - if (evt->ev_state == NULL) - DBG_log("event added after event %s" - , enum_show(&timer_event_names, evt->ev_type)); - else - DBG_log("event added after event %s for #%lu" - , enum_show(&timer_event_names, evt->ev_type) - , evt->ev_state->st_serialno)); + for (evt = evlist; evt->ev_next != NULL; evt = evt->ev_next) + if (evt->ev_next->ev_time >= ev->ev_time) + break; + +#ifdef NEVER /* this seems to be overkill */ + DBG(DBG_CONTROL, + if (evt->ev_state == NULL) + DBG_log("event added after event %N" + , timer_event_names, evt->ev_type); + else + DBG_log("event added after event %N for #%lu" + , timer_event_names, evt->ev_type, + , evt->ev_state->st_serialno)); #endif /* NEVER */ - ev->ev_next = evt->ev_next; - evt->ev_next = ev; - } + ev->ev_next = evt->ev_next; + evt->ev_next = ev; + } +} + +/** + * Generate the secret value for responder cookies, and + * schedule an event for refresh. + */ +void init_secret(void) +{ + rng_t *rng; + + rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG); + rng->get_bytes(rng, sizeof(secret_of_the_day), secret_of_the_day); + rng->destroy(rng); + event_schedule(EVENT_REINIT_SECRET, EVENT_REINIT_SECRET_DELAY, NULL); } -/* +/** * Handle the first event on the list. */ -void -handle_timer_event(void) +void handle_timer_event(void) { - time_t tm; - struct event *ev = evlist; - int type; - struct state *st; - struct connection *c = NULL; - ip_address peer; - - if (ev == (struct event *) NULL) /* Just paranoid */ - { - DBG(DBG_CONTROL, DBG_log("empty event list, yet we're called")); - return; - } - - type = ev->ev_type; - st = ev->ev_state; - - tm = now(); - - if (tm < ev->ev_time) - { - DBG(DBG_CONTROL, DBG_log("called while no event expired (%lu/%lu, %s)" - , (unsigned long)tm, (unsigned long)ev->ev_time - , enum_show(&timer_event_names, type))); - - /* This will happen if the most close-to-expire event was - * a retransmission or cleanup, and we received a packet - * at the same time as the event expired. Due to the processing - * order in call_server(), the packet processing will happen first, - * and the event will be removed. - */ - return; - } - - evlist = evlist->ev_next; /* Ok, we'll handle this event */ - - DBG(DBG_CONTROL, - if (evlist != (struct event *) NULL) - DBG_log("event after this is %s in %ld seconds" - , enum_show(&timer_event_names, evlist->ev_type) - , (long) (evlist->ev_time - tm))); - - /* for state-associated events, pick up the state pointer - * and remove the backpointer from the state object. - * We'll eventually either schedule a new event, or delete the state. - */ - passert(GLOBALS_ARE_RESET()); - if (st != NULL) - { - c = st->st_connection; - if (type == EVENT_DPD || type == EVENT_DPD_TIMEOUT) + time_t tm; + struct event *ev = evlist; + int type; + struct state *st; + struct connection *c = NULL; + ip_address peer; + + if (ev == (struct event *) NULL) /* Just paranoid */ { - passert(st->st_dpd_event == ev); - st->st_dpd_event = NULL; + DBG(DBG_CONTROL, DBG_log("empty event list, yet we're called")); + return; } - else + + type = ev->ev_type; + st = ev->ev_state; + + tm = now(); + + if (tm < ev->ev_time) { - passert(st->st_event == ev); - st->st_event = NULL; + DBG(DBG_CONTROL, DBG_log("called while no event expired (%lu/%lu, %N)" + , (unsigned long)tm, (unsigned long)ev->ev_time + , timer_event_names, type)); + + /* This will happen if the most close-to-expire event was + * a retransmission or cleanup, and we received a packet + * at the same time as the event expired. Due to the processing + * order in call_server(), the packet processing will happen first, + * and the event will be removed. + */ + return; } - peer = c->spd.that.host_addr; - set_cur_state(st); - } - - switch (type) - { - case EVENT_REINIT_SECRET: - passert(st == NULL); - DBG(DBG_CONTROL, DBG_log("event EVENT_REINIT_SECRET handled")); - init_secret(); - break; -#ifdef KLIPS - case EVENT_SHUNT_SCAN: - passert(st == NULL); - scan_proc_shunts(); - break; -#endif + evlist = evlist->ev_next; /* Ok, we'll handle this event */ - case EVENT_LOG_DAILY: - daily_log_event(); - break; - - case EVENT_RETRANSMIT: - /* Time to retransmit, or give up. - * - * Generally, we'll only try to send the message - * MAXIMUM_RETRANSMISSIONS times. Each time we double - * our patience. - * - * As a special case, if this is the first initiating message - * of a Main Mode exchange, and we have been directed to try - * forever, we'll extend the number of retransmissions to - * MAXIMUM_RETRANSMISSIONS_INITIAL times, with all these - * extended attempts having the same patience. The intention - * is to reduce the bother when nobody is home. - */ - { - time_t delay = 0; - - DBG(DBG_CONTROL, DBG_log( - "handling event EVENT_RETRANSMIT for %s \"%s\" #%lu" - , ip_str(&peer), c->name, st->st_serialno)); - - if (st->st_retransmit < MAXIMUM_RETRANSMISSIONS) - delay = EVENT_RETRANSMIT_DELAY_0 << (st->st_retransmit + 1); - else if (st->st_state == STATE_MAIN_I1 - && c->sa_keying_tries == 0 - && st->st_retransmit < MAXIMUM_RETRANSMISSIONS_INITIAL) - delay = EVENT_RETRANSMIT_DELAY_0 << MAXIMUM_RETRANSMISSIONS; - - if (delay != 0) + DBG(DBG_CONTROL, + if (evlist != (struct event *) NULL) + DBG_log("event after this is %N in %ld seconds" + , timer_event_names, evlist->ev_type + , (long) (evlist->ev_time - tm))); + + /* for state-associated events, pick up the state pointer + * and remove the backpointer from the state object. + * We'll eventually either schedule a new event, or delete the state. + */ + passert(GLOBALS_ARE_RESET()); + if (st != NULL) + { + c = st->st_connection; + if (type == EVENT_DPD || type == EVENT_DPD_TIMEOUT) { - st->st_retransmit++; - whack_log(RC_RETRANSMISSION - , "%s: retransmission; will wait %lus for response" - , enum_name(&state_names, st->st_state) - , (unsigned long)delay); - send_packet(st, "EVENT_RETRANSMIT"); - event_schedule(EVENT_RETRANSMIT, delay, st); + passert(st->st_dpd_event == ev); + st->st_dpd_event = NULL; } - else + else { - /* check if we've tried rekeying enough times. - * st->st_try == 0 means that this should be the only try. - * c->sa_keying_tries == 0 means that there is no limit. - */ - unsigned long try = st->st_try; - unsigned long try_limit = c->sa_keying_tries; - const char *details = ""; - - switch (st->st_state) - { - case STATE_MAIN_I3: - details = ". Possible authentication failure:" - " no acceptable response to our" - " first encrypted message"; - break; - case STATE_MAIN_I1: - details = ". No response (or no acceptable response) to our" - " first IKE message"; - break; - case STATE_QUICK_I1: - if (c->newest_ipsec_sa == SOS_NOBODY) - details = ". No acceptable response to our" - " first Quick Mode message:" - " perhaps peer likes no proposal"; + passert(st->st_event == ev); + st->st_event = NULL; + } + peer = c->spd.that.host_addr; + set_cur_state(st); + } + + switch (type) + { + case EVENT_REINIT_SECRET: + passert(st == NULL); + DBG(DBG_CONTROL, DBG_log("event EVENT_REINIT_SECRET handled")); + init_secret(); break; - default: + +#ifdef KLIPS + case EVENT_SHUNT_SCAN: + passert(st == NULL); + scan_proc_shunts(); break; - } - loglog(RC_NORETRANSMISSION - , "max number of retransmissions (%d) reached %s%s" - , st->st_retransmit - , enum_show(&state_names, st->st_state), details); - if (try != 0 && try != try_limit) - { - /* A lot like EVENT_SA_REPLACE, but over again. - * Since we know that st cannot be in use, - * we can delete it right away. - */ - char story[80]; /* arbitrary limit */ +#endif - try++; - snprintf(story, sizeof(story), try_limit == 0 - ? "starting keying attempt %ld of an unlimited number" - : "starting keying attempt %ld of at most %ld" - , try, try_limit); + case EVENT_LOG_DAILY: + daily_log_event(); + break; - if (st->st_whack_sock != NULL_FD) + case EVENT_RETRANSMIT: + /* Time to retransmit, or give up. + * + * Generally, we'll only try to send the message + * MAXIMUM_RETRANSMISSIONS times. Each time we double + * our patience. + * + * As a special case, if this is the first initiating message + * of a Main Mode exchange, and we have been directed to try + * forever, we'll extend the number of retransmissions to + * MAXIMUM_RETRANSMISSIONS_INITIAL times, with all these + * extended attempts having the same patience. The intention + * is to reduce the bother when nobody is home. + */ { - /* Release whack because the observer will get bored. */ - loglog(RC_COMMENT, "%s, but releasing whack" - , story); - release_pending_whacks(st, story); + time_t delay = 0; + + DBG(DBG_CONTROL, DBG_log( + "handling event EVENT_RETRANSMIT for %s \"%s\" #%lu" + , ip_str(&peer), c->name, st->st_serialno)); + + if (st->st_retransmit < MAXIMUM_RETRANSMISSIONS) + delay = EVENT_RETRANSMIT_DELAY_0 << (st->st_retransmit + 1); + else if (st->st_state == STATE_MAIN_I1 + && c->sa_keying_tries == 0 + && st->st_retransmit < MAXIMUM_RETRANSMISSIONS_INITIAL) + delay = EVENT_RETRANSMIT_DELAY_0 << MAXIMUM_RETRANSMISSIONS; + + if (delay != 0) + { + st->st_retransmit++; + whack_log(RC_RETRANSMISSION + , "%s: retransmission; will wait %lus for response" + , enum_name(&state_names, st->st_state) + , (unsigned long)delay); + send_packet(st, "EVENT_RETRANSMIT"); + event_schedule(EVENT_RETRANSMIT, delay, st); + } + else + { + /* check if we've tried rekeying enough times. + * st->st_try == 0 means that this should be the only try. + * c->sa_keying_tries == 0 means that there is no limit. + */ + unsigned long try = st->st_try; + unsigned long try_limit = c->sa_keying_tries; + const char *details = ""; + + switch (st->st_state) + { + case STATE_MAIN_I3: + details = ". Possible authentication failure:" + " no acceptable response to our" + " first encrypted message"; + break; + case STATE_MAIN_I1: + details = ". No response (or no acceptable response) to our" + " first IKE message"; + break; + case STATE_QUICK_I1: + if (c->newest_ipsec_sa == SOS_NOBODY) + details = ". No acceptable response to our" + " first Quick Mode message:" + " perhaps peer likes no proposal"; + break; + default: + break; + } + loglog(RC_NORETRANSMISSION + , "max number of retransmissions (%d) reached %s%s" + , st->st_retransmit + , enum_show(&state_names, st->st_state), details); + if (try != 0 && try != try_limit) + { + /* A lot like EVENT_SA_REPLACE, but over again. + * Since we know that st cannot be in use, + * we can delete it right away. + */ + char story[80]; /* arbitrary limit */ + + try++; + snprintf(story, sizeof(story), try_limit == 0 + ? "starting keying attempt %ld of an unlimited number" + : "starting keying attempt %ld of at most %ld" + , try, try_limit); + + if (st->st_whack_sock != NULL_FD) + { + /* Release whack because the observer will get bored. */ + loglog(RC_COMMENT, "%s, but releasing whack" + , story); + release_pending_whacks(st, story); + } + else + { + /* no whack: just log to syslog */ + plog("%s", story); + } + ipsecdoi_replace(st, try); + } + delete_state(st); + } } - else + break; + + case EVENT_SA_REPLACE: + case EVENT_SA_REPLACE_IF_USED: { - /* no whack: just log to syslog */ - plog("%s", story); + so_serial_t newest = IS_PHASE1(st->st_state) + ? c->newest_isakmp_sa : c->newest_ipsec_sa; + + if (newest != st->st_serialno + && newest != SOS_NOBODY) + { + /* not very interesting: no need to replace */ + DBG(DBG_LIFECYCLE + , plog("not replacing stale %s SA: #%lu will do" + , IS_PHASE1(st->st_state)? "ISAKMP" : "IPsec" + , newest)); + } + else if (type == EVENT_SA_REPLACE_IF_USED + && st->st_outbound_time <= tm - c->sa_rekey_margin) + { + /* we observed no recent use: no need to replace + * + * The sampling effects mean that st_outbound_time + * could be up to SHUNT_SCAN_INTERVAL more recent + * than actual traffic because the sampler looks at change + * over that interval. + * st_outbound_time could also not yet reflect traffic + * in the last SHUNT_SCAN_INTERVAL. + * We expect that SHUNT_SCAN_INTERVAL is smaller than + * c->sa_rekey_margin so that the effects of this will + * be unimportant. + * This is just an optimization: correctness is not + * at stake. + * + * Note: we are abusing the DBG mechanism to control + * normal log output. + */ + DBG(DBG_LIFECYCLE + , plog("not replacing stale %s SA: inactive for %lus" + , IS_PHASE1(st->st_state)? "ISAKMP" : "IPsec" + , (unsigned long)(tm - st->st_outbound_time))); + } + else + { + DBG(DBG_LIFECYCLE + , plog("replacing stale %s SA" + , IS_PHASE1(st->st_state)? "ISAKMP" : "IPsec")); + ipsecdoi_replace(st, 1); + } + delete_dpd_event(st); + event_schedule(EVENT_SA_EXPIRE, st->st_margin, st); } - ipsecdoi_replace(st, try); - } - delete_state(st); - } - } - break; - - case EVENT_SA_REPLACE: - case EVENT_SA_REPLACE_IF_USED: - { - so_serial_t newest = IS_PHASE1(st->st_state) - ? c->newest_isakmp_sa : c->newest_ipsec_sa; - - if (newest != st->st_serialno - && newest != SOS_NOBODY) - { - /* not very interesting: no need to replace */ - DBG(DBG_LIFECYCLE - , plog("not replacing stale %s SA: #%lu will do" - , IS_PHASE1(st->st_state)? "ISAKMP" : "IPsec" - , newest)); - } - else if (type == EVENT_SA_REPLACE_IF_USED - && st->st_outbound_time <= tm - c->sa_rekey_margin) - { - /* we observed no recent use: no need to replace - * - * The sampling effects mean that st_outbound_time - * could be up to SHUNT_SCAN_INTERVAL more recent - * than actual traffic because the sampler looks at change - * over that interval. - * st_outbound_time could also not yet reflect traffic - * in the last SHUNT_SCAN_INTERVAL. - * We expect that SHUNT_SCAN_INTERVAL is smaller than - * c->sa_rekey_margin so that the effects of this will - * be unimportant. - * This is just an optimization: correctness is not - * at stake. - * - * Note: we are abusing the DBG mechanism to control - * normal log output. - */ - DBG(DBG_LIFECYCLE - , plog("not replacing stale %s SA: inactive for %lus" - , IS_PHASE1(st->st_state)? "ISAKMP" : "IPsec" - , (unsigned long)(tm - st->st_outbound_time))); - } - else - { - DBG(DBG_LIFECYCLE - , plog("replacing stale %s SA" - , IS_PHASE1(st->st_state)? "ISAKMP" : "IPsec")); - ipsecdoi_replace(st, 1); - } - delete_dpd_event(st); - event_schedule(EVENT_SA_EXPIRE, st->st_margin, st); - } - break; + break; - case EVENT_SA_EXPIRE: - { - const char *satype; - so_serial_t latest; + case EVENT_SA_EXPIRE: + { + const char *satype; + so_serial_t latest; + + if (IS_PHASE1(st->st_state)) + { + satype = "ISAKMP"; + latest = c->newest_isakmp_sa; + } + else + { + satype = "IPsec"; + latest = c->newest_ipsec_sa; + } + + if (st->st_serialno != latest) + { + /* not very interesting: already superseded */ + DBG(DBG_LIFECYCLE + , plog("%s SA expired (superseded by #%lu)" + , satype, latest)); + } + else + { + plog("%s SA expired (%s)", satype + , (c->policy & POLICY_DONT_REKEY) + ? "--dontrekey" + : "LATEST!" + ); + } + } + /* FALLTHROUGH */ + case EVENT_SO_DISCARD: + /* Delete this state object. It must be in the hash table. */ + delete_state(st); + break; - if (IS_PHASE1(st->st_state)) - { - satype = "ISAKMP"; - latest = c->newest_isakmp_sa; - } - else - { - satype = "IPsec"; - latest = c->newest_ipsec_sa; - } + case EVENT_DPD: + dpd_outI(st); + break; + case EVENT_DPD_TIMEOUT: + dpd_timeout(st); + break; + case EVENT_NAT_T_KEEPALIVE: + nat_traversal_ka_event(); + break; + default: + loglog(RC_LOG_SERIOUS, "INTERNAL ERROR: ignoring unknown expiring event %N" + , timer_event_names, type); + } - if (st->st_serialno != latest) - { - /* not very interesting: already superseded */ - DBG(DBG_LIFECYCLE - , plog("%s SA expired (superseded by #%lu)" - , satype, latest)); - } - else - { - plog("%s SA expired (%s)", satype - , (c->policy & POLICY_DONT_REKEY) - ? "--dontrekey" - : "LATEST!" - ); - } - } - /* FALLTHROUGH */ - case EVENT_SO_DISCARD: - /* Delete this state object. It must be in the hash table. */ - delete_state(st); - break; - - case EVENT_DPD: - dpd_outI(st); - break; - case EVENT_DPD_TIMEOUT: - dpd_timeout(st); - break; - case EVENT_NAT_T_KEEPALIVE: - nat_traversal_ka_event(); - break; - default: - loglog(RC_LOG_SERIOUS, "INTERNAL ERROR: ignoring unknown expiring event %s" - , enum_show(&timer_event_names, type)); - } - - pfree(ev); - reset_cur_state(); + free(ev); + reset_cur_state(); } -/* +/** * Return the time until the next event in the queue * expires (never negative), or -1 if no jobs in queue. */ -long -next_event(void) +long next_event(void) { - time_t tm; + time_t tm; + + if (evlist == (struct event *) NULL) + return -1; - if (evlist == (struct event *) NULL) - return -1; + tm = now(); - tm = now(); + DBG(DBG_CONTROL, + if (evlist->ev_state == NULL) + DBG_log("next event %N in %ld seconds" + , timer_event_names, evlist->ev_type + , (long)evlist->ev_time - (long)tm); + else + DBG_log("next event %N in %ld seconds for #%lu" + , timer_event_names, evlist->ev_type + , (long)evlist->ev_time - (long)tm + , evlist->ev_state->st_serialno)); - DBG(DBG_CONTROL, - if (evlist->ev_state == NULL) - DBG_log("next event %s in %ld seconds" - , enum_show(&timer_event_names, evlist->ev_type) - , (long)evlist->ev_time - (long)tm); + if (evlist->ev_time - tm <= 0) + return 0; else - DBG_log("next event %s in %ld seconds for #%lu" - , enum_show(&timer_event_names, evlist->ev_type) - , (long)evlist->ev_time - (long)tm - , evlist->ev_state->st_serialno)); - - if (evlist->ev_time - tm <= 0) - return 0; - else - return evlist->ev_time - tm; + return evlist->ev_time - tm; } -/* +/** * Delete an event. */ -void -delete_event(struct state *st) +void delete_event(struct state *st) { - if (st->st_event != (struct event *) NULL) - { - struct event **ev; - - for (ev = &evlist; ; ev = &(*ev)->ev_next) + if (st->st_event != (struct event *) NULL) { - if (*ev == NULL) - { - DBG(DBG_CONTROL, DBG_log("event %s to be deleted not found", - enum_show(&timer_event_names, st->st_event->ev_type))); - break; - } - if ((*ev) == st->st_event) - { - *ev = (*ev)->ev_next; - - if (st->st_event->ev_type == EVENT_RETRANSMIT) - st->st_retransmit = 0; - pfree(st->st_event); - st->st_event = (struct event *) NULL; - - break; - } + struct event **ev; + + for (ev = &evlist; ; ev = &(*ev)->ev_next) + { + if (*ev == NULL) + { + DBG(DBG_CONTROL, DBG_log("event %N to be deleted not found", + timer_event_names, st->st_event->ev_type)); + break; + } + if ((*ev) == st->st_event) + { + *ev = (*ev)->ev_next; + + if (st->st_event->ev_type == EVENT_RETRANSMIT) + { + st->st_retransmit = 0; + } + free(st->st_event); + st->st_event = (struct event *) NULL; + + break; + } + } } - } } -/* +/** * Delete a DPD event. */ -void -delete_dpd_event(struct state *st) +void delete_dpd_event(struct state *st) { - if (st->st_dpd_event != (struct event *) NULL) - { - struct event **ev; - - for (ev = &evlist; ; ev = &(*ev)->ev_next) - { - if (*ev == NULL) - { - DBG(DBG_CONTROL, DBG_log("event %s to be deleted not found", - enum_show(&timer_event_names, st->st_dpd_event->ev_type))); - break; - } - if ((*ev) == st->st_dpd_event) - { - *ev = (*ev)->ev_next; - pfree(st->st_dpd_event); - st->st_dpd_event = (struct event *) NULL; - break; - } - } - } + if (st->st_dpd_event != (struct event *) NULL) + { + struct event **ev; + + for (ev = &evlist; ; ev = &(*ev)->ev_next) + { + if (*ev == NULL) + { + DBG(DBG_CONTROL, DBG_log("event %N to be deleted not found", + timer_event_names, st->st_dpd_event->ev_type)); + break; + } + if ((*ev) == st->st_dpd_event) + { + *ev = (*ev)->ev_next; + free(st->st_dpd_event); + st->st_dpd_event = (struct event *) NULL; + break; + } + } + } } +/** + * Free remaining events + */ +void free_events(void) +{ + struct event *ev_tmp, *ev; + + ev = evlist; + evlist = NULL; + + while (ev) + { + ev_tmp = ev; + ev = ev->ev_next; + free(ev_tmp); + } +} |