diff --git a/src/gb/gprs_ns2.c b/src/gb/gprs_ns2.c index 45cdfcc13..83a8ca074 100644 --- a/src/gb/gprs_ns2.c +++ b/src/gb/gprs_ns2.c @@ -674,8 +674,12 @@ void gprs_ns2_free_nsvcs(struct gprs_ns2_nse *nse) if (!nse || nse->freed) return; - llist_for_each_entry_safe(nsvc, tmp, &nse->nsvc, list) { - gprs_ns2_free_nsvc(nsvc); + if (nse->bss_sns_fi) { + osmo_fsm_inst_dispatch(nse->bss_sns_fi, NS2_SNS_EV_REQ_FREE_NSVCS, NULL); + } else { + llist_for_each_entry_safe(nsvc, tmp, &nse->nsvc, list) { + gprs_ns2_free_nsvc(nsvc); + } } } diff --git a/src/gb/gprs_ns2_internal.h b/src/gb/gprs_ns2_internal.h index 60962639f..d2407f663 100644 --- a/src/gb/gprs_ns2_internal.h +++ b/src/gb/gprs_ns2_internal.h @@ -332,6 +332,7 @@ enum ns2_sns_event { NS2_SNS_EV_RX_CHANGE_WEIGHT, NS2_SNS_EV_RX_ACK, /*!< Rx of SNS-ACK (response to ADD/DELETE/CHG_WEIGHT */ NS2_SNS_EV_REQ_NO_NSVC, /*!< no more NS-VC remaining (all dead) */ + NS2_SNS_EV_REQ_FREE_NSVCS, /*!< free all NS-VCs */ NS2_SNS_EV_REQ_NSVC_ALIVE, /*!< a NS-VC became alive */ NS2_SNS_EV_REQ_ADD_BIND, /*!< add a new local bind to this NSE */ NS2_SNS_EV_REQ_DELETE_BIND, /*!< remove a local bind from this NSE */ diff --git a/src/gb/gprs_ns2_sns.c b/src/gb/gprs_ns2_sns.c index 1b2864ef5..e96f6b3f2 100644 --- a/src/gb/gprs_ns2_sns.c +++ b/src/gb/gprs_ns2_sns.c @@ -84,6 +84,7 @@ static const struct value_string gprs_sns_event_names[] = { { NS2_SNS_EV_RX_ACK, "RX_ACK" }, { NS2_SNS_EV_RX_CHANGE_WEIGHT, "RX_CHANGE_WEIGHT" }, { NS2_SNS_EV_REQ_NO_NSVC, "REQ_NO_NSVC" }, + { NS2_SNS_EV_REQ_FREE_NSVCS, "REQ_FREE_NSVCS" }, { NS2_SNS_EV_REQ_NSVC_ALIVE, "REQ_NSVC_ALIVE"}, { NS2_SNS_EV_REQ_ADD_BIND, "REQ_ADD_BIND"}, { NS2_SNS_EV_REQ_DELETE_BIND, "REQ_DELETE_BIND"}, @@ -1564,6 +1565,7 @@ static void ns2_sns_st_all_action_bss(struct osmo_fsm_inst *fi, uint32_t event, { struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv; struct gprs_ns2_nse *nse = nse_inst_from_fi(fi); + struct gprs_ns2_vc *nsvc, *nsvc2; /* reset when receiving NS2_SNS_EV_REQ_NO_NSVC */ switch (event) { @@ -1574,11 +1576,14 @@ static void ns2_sns_st_all_action_bss(struct osmo_fsm_inst *fi, uint32_t event, sns_failed(fi, "no remaining NSVC, resetting SNS FSM"); break; + case NS2_SNS_EV_REQ_FREE_NSVCS: case NS2_SNS_EV_REQ_SELECT_ENDPOINT: /* tear down previous state * gprs_ns2_free_nsvcs() will trigger NO_NSVC, prevent this from triggering a reselection */ gss->reselection_running = true; - gprs_ns2_free_nsvcs(nse); + llist_for_each_entry_safe(nsvc, nsvc2, &nse->nsvc, list) { + gprs_ns2_free_nsvc(nsvc); + } ns2_clear_elems(&gss->local); ns2_clear_elems(&gss->remote); @@ -1613,6 +1618,7 @@ static struct osmo_fsm gprs_ns2_sns_bss_fsm = { .states = ns2_sns_bss_states, .num_states = ARRAY_SIZE(ns2_sns_bss_states), .allstate_event_mask = S(NS2_SNS_EV_REQ_NO_NSVC) | + S(NS2_SNS_EV_REQ_FREE_NSVCS) | S(NS2_SNS_EV_REQ_SELECT_ENDPOINT) | S(NS2_SNS_EV_REQ_ADD_BIND) | S(NS2_SNS_EV_REQ_DELETE_BIND), @@ -2329,6 +2335,9 @@ static void ns2_sns_st_all_action_sgsn(struct osmo_fsm_inst *fi, uint32_t event, if (flag & 1) osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_SGSN_WAIT_CONFIG, 0, 0); break; + case NS2_SNS_EV_REQ_FREE_NSVCS: + sns_failed(fi, "On user request to free all NSVCs"); + break; default: ns2_sns_st_all_action(fi, event, data); break; @@ -2341,6 +2350,7 @@ static struct osmo_fsm gprs_ns2_sns_sgsn_fsm = { .num_states = ARRAY_SIZE(ns2_sns_sgsn_states), .allstate_event_mask = S(NS2_SNS_EV_RX_SIZE) | S(NS2_SNS_EV_REQ_NO_NSVC) | + S(NS2_SNS_EV_REQ_FREE_NSVCS) | S(NS2_SNS_EV_REQ_ADD_BIND) | S(NS2_SNS_EV_REQ_DELETE_BIND), .allstate_action = ns2_sns_st_all_action_sgsn,