dgsm Proxy Cache design WIP
Change-Id: Ifa322e84fadd3b04943c8c7024c0e2de4935bed0
diff --git a/src/Makefile.am b/src/Makefile.am
index 94575ad..c340983 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -54,6 +54,9 @@
gsup_send.c \
hlr_ussd.c \
proxy.c \
+ proxy_mm.c \
+ proxy_to_home.c \
+ proxy_db.c \
dgsm.c \
remote_hlr.c \
lu_fsm.c \
diff --git a/src/proxy.c b/src/proxy.c
index b9cd313..27cdc85 100644
--- a/src/proxy.c
+++ b/src/proxy.c
@@ -403,6 +403,18 @@
);
break;
+ case OSMO_GSUP_MSGT_SEND_AUTH_INFO_RESULT:
+ /* Remember the auth tuples: if the remote HLR becomes unreachable for an intermediate period, we can
+ * still re-use this auth information a number of times and keep the subscriber attached (on this
+ * roaming/proxy HLR). */
+#if 0
+ for (i = 0; i < gsup->num_auth_vectors; i++)
+ proxy_subscr_new.auth_vectors[i] = gsup->auth_vectors[i];
+ proxy_subscr_new.num_auth_vectors = gsup->num_auth_vectors;
+ rc = proxy_subscr_create_or_update(proxy, &proxy_subscr_new);
+#endif
+ break;
+
default:
break;
}
diff --git a/src/proxy_mm.c b/src/proxy_mm.c
new file mode 100644
index 0000000..12d3e5c
--- /dev/null
+++ b/src/proxy_mm.c
@@ -0,0 +1,417 @@
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/core/fsm.h>
+#include <osmocom/core/tdef.h>
+#include <osmocom/gsm/apn.h>
+#include <osmocom/hlr/hlr.h>
+#include <osmocom/hlr/proxy_mm.h>
+#include <osmocom/hlr/proxy_db.h>
+
+enum proxy_mm_fsm_state {
+ PROXY_MM_ST_READY,
+ PROXY_MM_ST_WAIT_SUBSCR_DATA,
+ PROXY_MM_ST_WAIT_GSUP_ISD_RESULT,
+ PROXY_MM_ST_WAIT_AUTH_TUPLES,
+};
+
+static const struct value_string proxy_mm_fsm_event_names[] = {
+ OSMO_VALUE_STRING(PROXY_MM_EV_SUBSCR_INVALID),
+ OSMO_VALUE_STRING(PROXY_MM_EV_RX_GSUP_LU),
+ OSMO_VALUE_STRING(PROXY_MM_EV_RX_GSUP_SAI),
+ OSMO_VALUE_STRING(PROXY_MM_EV_RX_SUBSCR_DATA),
+ OSMO_VALUE_STRING(PROXY_MM_EV_RX_GSUP_ISD_RESULT),
+ OSMO_VALUE_STRING(PROXY_MM_EV_RX_AUTH_TUPLES),
+ {}
+};
+
+static struct osmo_fsm proxy_mm_fsm;
+static struct osmo_fsm proxy_to_home_fsm;
+
+struct osmo_tdef proxy_mm_tdefs[] = {
+// FIXME
+ { .T=-1, .default_val=5, .desc="proxy_mm ready timeout" },
+ { .T=-2, .default_val=5, .desc="proxy_mm wait_subscr_data timeout" },
+ { .T=-3, .default_val=5, .desc="proxy_mm wait_gsup_isd_result timeout" },
+ { .T=-4, .default_val=5, .desc="proxy_mm wait_auth_tuples timeout" },
+ {}
+};
+
+static const struct osmo_tdef_state_timeout proxy_mm_fsm_timeouts[32] = {
+// FIXME
+ [PROXY_MM_ST_READY] = { .T=-1 },
+ [PROXY_MM_ST_WAIT_SUBSCR_DATA] = { .T=-2 },
+ [PROXY_MM_ST_WAIT_GSUP_ISD_RESULT] = { .T=-3 },
+ [PROXY_MM_ST_WAIT_AUTH_TUPLES] = { .T=-4 },
+};
+
+#define proxy_mm_fsm_state_chg(state) \
+ osmo_tdef_fsm_inst_state_chg(mm_fi, state, \
+ proxy_mm_fsm_timeouts, \
+ proxy_mm_tdefs, \
+ 5)
+
+LLIST_HEAD(proxy_mm_list);
+
+struct proxy_mm *proxy_mm_alloc(const struct osmo_gsup_peer_id *vlr_name,
+ bool is_ps,
+ const char *imsi)
+{
+ struct proxy_mm *proxy_mm;
+
+ struct osmo_fsm_inst *mm_fi = osmo_fsm_inst_alloc(&proxy_mm_fsm, g_hlr, NULL, LOGL_DEBUG, imsi);
+ OSMO_ASSERT(mm_fi);
+
+ proxy_mm = talloc(mm_fi, struct proxy_mm);
+ OSMO_ASSERT(proxy_mm);
+ mm_fi->priv = proxy_mm;
+ *proxy_mm = (struct proxy_mm){
+ .mm_fi = mm_fi,
+ .is_ps = is_ps,
+ };
+ OSMO_STRLCPY_ARRAY(proxy_mm->imsi, imsi);
+ INIT_LLIST_HEAD(&proxy_mm->auth_cache);
+
+ llist_add(&proxy_mm->entry, &proxy_mm_list);
+
+ proxy_mm->to_home_fi = osmo_fsm_inst_alloc_child(&proxy_to_home_fsm, mm_fi, PROXY_MM_EV_SUBSCR_INVALID);
+ proxy_mm->to_home_fi->priv = proxy_mm;
+
+ /* Do a state change to activate timeout */
+ proxy_mm_fsm_state_chg(PROXY_MM_ST_READY);
+
+ return proxy_mm;
+}
+
+void proxy_mm_add_auth_vectors(struct proxy_mm *proxy_mm,
+ const struct osmo_auth_vector *auth_vectors, size_t num_auth_vectors)
+{
+ struct proxy_mm_auth_cache *ac = talloc_zero(proxy_mm, struct proxy_mm_auth_cache);
+ int i;
+ OSMO_ASSERT(ac);
+ ac->num_auth_vectors = num_auth_vectors;
+ for (i = 0; i < num_auth_vectors; i++)
+ ac->auth_vectors[i] = auth_vectors[i];
+ if (proxy_db_add_auth_vectors(&proxy_mm->vlr_name, ac)) {
+ talloc_free(ac);
+ return;
+ }
+ llist_add(&ac->entry, &proxy_mm->auth_cache);
+}
+
+struct proxy_mm_auth_cache *proxy_mm_get_auth_vectors(struct proxy_mm *proxy_mm)
+{
+ struct proxy_mm_auth_cache *i;
+ struct proxy_mm_auth_cache *ac = NULL;
+
+ llist_for_each_entry(i, &proxy_mm->auth_cache, entry) {
+ if (!ac || i->sent_to_vlr_count < ac->sent_to_vlr_count) {
+ ac = i;
+ }
+ }
+
+ /* ac now points to (one of) the least used auth cache entries (or NULL if none). */
+ return ac;
+}
+
+void proxy_mm_discard_auth_vectors(struct proxy_mm *proxy_mm, struct proxy_mm_auth_cache *ac)
+{
+ proxy_db_drop_auth_vectors(ac->db_id);
+ llist_del(&ac->entry);
+ talloc_free(ac);
+}
+
+/* Mark given auth cache entries as sent to the VLR and clean up if necessary. */
+void proxy_mm_use_auth_vectors(struct proxy_mm *proxy_mm, struct proxy_mm_auth_cache *ac)
+{
+ struct proxy_mm_auth_cache *i, *i_next;
+ bool found_fresh_ac = false;
+
+ /* The aim is to keep at least one set of already used auth tuples in the cache. If there are still fresh ones,
+ * all used auth vectors can be discarded. If there are no fresh ones left, keep only this last set. */
+
+ llist_for_each_entry_safe(i, i_next, &proxy_mm->auth_cache, entry) {
+ if (i == ac)
+ continue;
+ if (i->sent_to_vlr_count) {
+ /* An auth entry other than this freshly used one, which has been used before.
+ * No need to keep it. */
+ proxy_mm_discard_auth_vectors(proxy_mm, i);
+ continue;
+ }
+ if (!i->sent_to_vlr_count)
+ found_fresh_ac = true;
+ }
+
+ if (found_fresh_ac) {
+ /* There are still other, fresh auth vectors. */
+ proxy_mm_discard_auth_vectors(proxy_mm, ac);
+ } else {
+ /* else, only this ac remains in the list */
+ ac->sent_to_vlr_count++;
+ proxy_db_auth_vectors_update_sent_count(ac);
+ }
+}
+
+static void proxy_mm_ready_action(struct osmo_fsm_inst *mm_fi, uint32_t event, void *data)
+{
+ struct proxy *proxy = g_hlr->gs->proxy;
+ struct proxy_mm *proxy_mm = mm_fi->priv;
+
+ switch (event) {
+
+ case PROXY_MM_EV_SUBSCR_INVALID:
+ /* Home HLR has responded and rejected a Location Updating, or no home HLR could be found. The
+ * subscriber is invalid, remove it from the cache. */
+ proxy_subscr_del(proxy, proxy_mm->imsi);
+ osmo_fsm_inst_term(mm_fi, OSMO_FSM_TERM_REGULAR, NULL);
+ break;
+
+ case PROXY_MM_EV_RX_GSUP_LU:
+ /* The MSC asks for a LU. If we don't know details about this subscriber, then we'll have to wait for the
+ * home HLR to respond. If we already know details about the subscriber, we respond immediately (with
+ * Insert Subscriber Data and accept the LU), but also ask the home HLR to confirm the LU later. */
+ osmo_fsm_inst_dispatch(proxy_mm->to_home_fi, PROXY_TO_HOME_EV_CONFIRM_LU, NULL);
+
+ if (proxy_mm_subscriber_data_known(proxy_mm))
+ proxy_mm_fsm_state_chg(PROXY_MM_ST_WAIT_GSUP_ISD_RESULT);
+ else
+ proxy_mm_fsm_state_chg(PROXY_MM_ST_WAIT_SUBSCR_DATA);
+ break;
+
+ case PROXY_MM_EV_RX_GSUP_SAI:
+ // FIXME
+ break;
+
+ default:
+ OSMO_ASSERT(false);
+ }
+}
+
+static int proxy_mm_ready_timeout(struct osmo_fsm_inst *mm_fi)
+{
+ /* Return 1 to terminate FSM instance, 0 to keep running */
+ return 1;
+}
+
+void proxy_mm_wait_subscr_data_onenter(struct osmo_fsm_inst *mm_fi, uint32_t prev_state)
+{
+ //struct proxy_mm *proxy_mm = mm_fi->priv;
+ // FIXME
+}
+
+static void proxy_mm_wait_subscr_data_action(struct osmo_fsm_inst *mm_fi, uint32_t event, void *data)
+{
+ //struct proxy_mm *proxy_mm = mm_fi->priv;
+
+ switch (event) {
+
+ case PROXY_MM_EV_RX_SUBSCR_DATA:
+ // FIXME
+ break;
+
+ default:
+ OSMO_ASSERT(false);
+ }
+}
+
+static int proxy_mm_wait_subscr_data_timeout(struct osmo_fsm_inst *mm_fi)
+{
+ /* Return 1 to terminate FSM instance, 0 to keep running */
+ return 1;
+}
+
+static void proxy_mm_lu_error(struct osmo_fsm_inst *mm_fi)
+{
+ osmo_gsup_req_respond_err(req, GMM_CAUSE_ROAMING_NOTALLOWED,
+ "LU does not accept GSUP rx");
+
+}
+
+void proxy_mm_wait_gsup_isd_result_onenter(struct osmo_fsm_inst *mm_fi, uint32_t prev_state)
+{
+ struct proxy_mm *proxy_mm = mm_fi->priv;
+ struct proxy_subscr proxy_subscr;
+ struct osmo_gsup_message isd_req;
+
+ uint8_t msisdn_enc[OSMO_GSUP_MAX_CALLED_PARTY_BCD_LEN];
+ uint8_t apn[APN_MAXLEN];
+
+ isd_req.message_type = OSMO_GSUP_MSGT_INSERT_DATA_REQUEST;
+
+ if (proxy_subscr_get_by_imsi(&proxy_subscr, g_hlr->gs->proxy, proxy_mm->imsi)) {
+ LOGPFSML(mm_fi, LOGL_ERROR,
+ "Proxy: trying to send cached Subscriber Data, but there is no proxy entry\n");
+ proxy_mm_lu_error(mm_fi);
+ return;
+ }
+
+ if (proxy_subscr.msisdn[0] == '\0') {
+ LOGPFSML(mm_fi, LOGL_ERROR,
+ "Proxy: trying to send cached Subscriber Data, but subscriber has no MSISDN in proxy cache\n");
+ proxy_mm_lu_error(mm_fi);
+ return;
+ }
+
+ if (osmo_gsup_create_insert_subscriber_data_msg(&isd_req, proxy_mm->imsi,
+ proxy_subscr->msisdn, msisdn_enc, sizeof(msisdn_enc),
+ apn, sizeof(apn),
+ proxy_mm->is_ps? OSMO_GSUP_CN_DOMAIN_PS : OSMO_GSUP_CN_DOMAIN_CS)) {
+ LOGPFSML(mm_fi, LOGL_ERROR, "Proxy: failed to send cached Subscriber Data\n");
+ proxy_mm_lu_error(mm_fi);
+ return;
+ }
+}
+
+static void proxy_mm_wait_gsup_isd_result_action(struct osmo_fsm_inst *mm_fi, uint32_t event, void *data)
+{
+ //struct proxy_mm *proxy_mm = mm_fi->priv;
+
+ switch (event) {
+
+ case PROXY_MM_EV_RX_GSUP_ISD_RESULT:
+ // FIXME
+ break;
+
+ default:
+ OSMO_ASSERT(false);
+ }
+}
+
+static int proxy_mm_wait_gsup_isd_result_timeout(struct osmo_fsm_inst *mm_fi)
+{
+ /* Return 1 to terminate FSM instance, 0 to keep running */
+ return 1;
+}
+
+void proxy_mm_wait_auth_tuples_onenter(struct osmo_fsm_inst *mm_fi, uint32_t prev_state)
+{
+ //struct proxy_mm *proxy_mm = mm_fi->priv;
+ // FIXME
+}
+
+static void proxy_mm_wait_auth_tuples_action(struct osmo_fsm_inst *mm_fi, uint32_t event, void *data)
+{
+ //struct proxy_mm *proxy_mm = mm_fi->priv;
+
+ switch (event) {
+
+ case PROXY_MM_EV_RX_AUTH_TUPLES:
+ // FIXME
+ break;
+
+ default:
+ OSMO_ASSERT(false);
+ }
+}
+
+static int proxy_mm_wait_auth_tuples_timeout(struct osmo_fsm_inst *mm_fi)
+{
+ /* Return 1 to terminate FSM instance, 0 to keep running */
+ return 1;
+}
+
+#define S(x) (1 << (x))
+
+static const struct osmo_fsm_state proxy_mm_fsm_states[] = {
+ [PROXY_MM_ST_READY] = {
+ .name = "ready",
+ .in_event_mask = 0
+ | S(PROXY_MM_EV_SUBSCR_INVALID)
+ | S(PROXY_MM_EV_RX_GSUP_LU)
+ | S(PROXY_MM_EV_RX_GSUP_SAI)
+ ,
+ .out_state_mask = 0
+ | S(PROXY_MM_ST_READY)
+ | S(PROXY_MM_ST_WAIT_SUBSCR_DATA)
+ | S(PROXY_MM_ST_WAIT_GSUP_ISD_RESULT)
+ | S(PROXY_MM_ST_WAIT_AUTH_TUPLES)
+ ,
+ .action = proxy_mm_ready_action,
+ },
+ [PROXY_MM_ST_WAIT_SUBSCR_DATA] = {
+ .name = "wait_subscr_data",
+ .in_event_mask = 0
+ | S(PROXY_MM_EV_RX_SUBSCR_DATA)
+ ,
+ .out_state_mask = 0
+ | S(PROXY_MM_ST_WAIT_GSUP_ISD_RESULT)
+ | S(PROXY_MM_ST_READY)
+ ,
+ .onenter = proxy_mm_wait_subscr_data_onenter,
+ .action = proxy_mm_wait_subscr_data_action,
+ },
+ [PROXY_MM_ST_WAIT_GSUP_ISD_RESULT] = {
+ .name = "wait_gsup_isd_result",
+ .in_event_mask = 0
+ | S(PROXY_MM_EV_RX_GSUP_ISD_RESULT)
+ ,
+ .out_state_mask = 0
+ | S(PROXY_MM_ST_READY)
+ ,
+ .onenter = proxy_mm_wait_gsup_isd_result_onenter,
+ .action = proxy_mm_wait_gsup_isd_result_action,
+ },
+ [PROXY_MM_ST_WAIT_AUTH_TUPLES] = {
+ .name = "wait_auth_tuples",
+ .in_event_mask = 0
+ | S(PROXY_MM_EV_RX_AUTH_TUPLES)
+ ,
+ .out_state_mask = 0
+ | S(PROXY_MM_ST_READY)
+ ,
+ .onenter = proxy_mm_wait_auth_tuples_onenter,
+ .action = proxy_mm_wait_auth_tuples_action,
+ },
+};
+
+static int proxy_mm_fsm_timer_cb(struct osmo_fsm_inst *mm_fi)
+{
+ //struct proxy_mm *proxy_mm = mm_fi->priv;
+ switch (mm_fi->state) {
+
+ case PROXY_MM_ST_READY:
+ return proxy_mm_ready_timeout(mm_fi);
+
+ case PROXY_MM_ST_WAIT_SUBSCR_DATA:
+ return proxy_mm_wait_subscr_data_timeout(mm_fi);
+
+ case PROXY_MM_ST_WAIT_GSUP_ISD_RESULT:
+ return proxy_mm_wait_gsup_isd_result_timeout(mm_fi);
+
+ case PROXY_MM_ST_WAIT_AUTH_TUPLES:
+ return proxy_mm_wait_auth_tuples_timeout(mm_fi);
+
+ default:
+ /* Return 1 to terminate FSM instance, 0 to keep running */
+ return 1;
+ }
+}
+
+void proxy_mm_fsm_cleanup(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)
+{
+ struct proxy_mm *proxy_mm = fi->priv;
+ llist_del(&proxy_mm->entry);
+}
+
+static struct osmo_fsm proxy_mm_fsm = {
+ .name = "proxy_mm",
+ .states = proxy_mm_fsm_states,
+ .num_states = ARRAY_SIZE(proxy_mm_fsm_states),
+ .log_subsys = DLGLOBAL, // FIXME
+ .event_names = proxy_mm_fsm_event_names,
+ .timer_cb = proxy_mm_fsm_timer_cb,
+ .cleanup = proxy_mm_fsm_cleanup,
+};
+
+static __attribute__((constructor)) void proxy_mm_fsm_register(void)
+{
+ OSMO_ASSERT(osmo_fsm_register(&proxy_mm_fsm) == 0);
+}
+
+bool proxy_mm_subscriber_data_known(const struct proxy_mm *proxy_mm)
+{
+ struct proxy_subscr proxy_subscr;
+ if (proxy_subscr_get_by_imsi(&proxy_subscr, g_hlr->gs->proxy, proxy_mm->imsi))
+ return false;
+ return proxy_subscr.msisdn[0] != '\0';
+}
diff --git a/src/proxy_to_home.c b/src/proxy_to_home.c
new file mode 100644
index 0000000..19dd7fa
--- /dev/null
+++ b/src/proxy_to_home.c
@@ -0,0 +1,439 @@
+
+#include <osmocom/hlr/proxy_mm.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/core/fsm.h>
+#include <osmocom/core/tdef.h>
+
+enum proxy_to_home_fsm_state {
+ PROXY_TO_HOME_ST_WAIT_HOME_HLR_RESOLVED,
+ PROXY_TO_HOME_ST_WAIT_UPDATE_LOCATION_RESULT,
+ PROXY_TO_HOME_ST_WAIT_SEND_AUTH_INFO_RESULT,
+ PROXY_TO_HOME_ST_IDLE,
+ PROXY_TO_HOME_ST_CLEAR,
+};
+
+static const struct value_string proxy_to_home_fsm_event_names[] = {
+ OSMO_VALUE_STRING(PROXY_TO_HOME_EV_HOME_HLR_RESOLVED),
+ OSMO_VALUE_STRING(PROXY_TO_HOME_EV_RX_INSERT_SUBSCRIBER_DATA_REQ),
+ OSMO_VALUE_STRING(PROXY_TO_HOME_EV_RX_UPDATE_LOCATION_RESULT),
+ OSMO_VALUE_STRING(PROXY_TO_HOME_EV_RX_SEND_AUTH_INFO_RESULT),
+ OSMO_VALUE_STRING(PROXY_TO_HOME_EV_CHECK_TUPLES),
+ OSMO_VALUE_STRING(PROXY_TO_HOME_EV_CONFIRM_LU),
+ {}
+};
+
+static struct osmo_fsm proxy_to_home_fsm;
+
+struct osmo_tdef proxy_to_home_tdefs[] = {
+// FIXME
+ { .T=-1, .default_val=5, .desc="proxy_to_home wait_home_hlr_resolved timeout" },
+ { .T=-2, .default_val=5, .desc="proxy_to_home wait_update_location_result timeout" },
+ { .T=-3, .default_val=5, .desc="proxy_to_home wait_send_auth_info_result timeout" },
+ { .T=-4, .default_val=5, .desc="proxy_to_home idle timeout" },
+ { .T=-5, .default_val=5, .desc="proxy_to_home clear timeout" },
+ {}
+};
+
+#if 0
+static const struct osmo_tdef_state_timeout proxy_to_home_fsm_timeouts[32] = {
+// FIXME
+ [PROXY_TO_HOME_ST_WAIT_HOME_HLR_RESOLVED] = { .T=-1 },
+ [PROXY_TO_HOME_ST_WAIT_UPDATE_LOCATION_RESULT] = { .T=-2 },
+ [PROXY_TO_HOME_ST_WAIT_SEND_AUTH_INFO_RESULT] = { .T=-3 },
+ [PROXY_TO_HOME_ST_IDLE] = { .T=-4 },
+ [PROXY_TO_HOME_ST_CLEAR] = { .T=-5 },
+};
+#endif
+
+#define proxy_to_home_fsm_state_chg(state) \
+ osmo_tdef_fsm_inst_state_chg(fi, state, \
+ proxy_to_home_fsm_timeouts, \
+ proxy_to_home_tdefs, \
+ 5)
+
+void proxy_to_home_wait_home_hlr_resolved_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ //struct proxy_mm *proxy_mm = fi->priv;
+ // FIXME
+}
+
+static void proxy_to_home_wait_home_hlr_resolved_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ //struct proxy_mm *proxy_mm = fi->priv;
+
+ switch (event) {
+
+ case PROXY_TO_HOME_EV_HOME_HLR_RESOLVED:
+ // FIXME
+ break;
+
+ case PROXY_TO_HOME_EV_RX_INSERT_SUBSCRIBER_DATA_REQ:
+ // FIXME
+ break;
+
+ case PROXY_TO_HOME_EV_RX_UPDATE_LOCATION_RESULT:
+ // FIXME
+ break;
+
+ case PROXY_TO_HOME_EV_RX_SEND_AUTH_INFO_RESULT:
+ // FIXME
+ break;
+
+ case PROXY_TO_HOME_EV_CHECK_TUPLES:
+ // FIXME
+ break;
+
+ case PROXY_TO_HOME_EV_CONFIRM_LU:
+ // FIXME
+ break;
+
+ default:
+ OSMO_ASSERT(false);
+ }
+}
+
+static int proxy_to_home_wait_home_hlr_resolved_timeout(struct osmo_fsm_inst *fi)
+{
+ /* Return 1 to terminate FSM instance, 0 to keep running */
+ return 1;
+}
+
+void proxy_to_home_wait_update_location_result_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ //struct proxy_mm *proxy_mm = fi->priv;
+ // FIXME
+}
+
+static void proxy_to_home_wait_update_location_result_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ //struct proxy_mm *proxy_mm = fi->priv;
+
+ switch (event) {
+
+ case PROXY_TO_HOME_EV_HOME_HLR_RESOLVED:
+ // FIXME
+ break;
+
+ case PROXY_TO_HOME_EV_RX_INSERT_SUBSCRIBER_DATA_REQ:
+ // FIXME
+ break;
+
+ case PROXY_TO_HOME_EV_RX_UPDATE_LOCATION_RESULT:
+ // FIXME
+ break;
+
+ case PROXY_TO_HOME_EV_RX_SEND_AUTH_INFO_RESULT:
+ // FIXME
+ break;
+
+ case PROXY_TO_HOME_EV_CHECK_TUPLES:
+ // FIXME
+ break;
+
+ case PROXY_TO_HOME_EV_CONFIRM_LU:
+ // FIXME
+ break;
+
+ default:
+ OSMO_ASSERT(false);
+ }
+}
+
+static int proxy_to_home_wait_update_location_result_timeout(struct osmo_fsm_inst *fi)
+{
+ /* Return 1 to terminate FSM instance, 0 to keep running */
+ return 1;
+}
+
+void proxy_to_home_wait_send_auth_info_result_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ //struct proxy_mm *proxy_mm = fi->priv;
+ // FIXME
+}
+
+static void proxy_to_home_wait_send_auth_info_result_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ //struct proxy_mm *proxy_mm = fi->priv;
+
+ switch (event) {
+
+ case PROXY_TO_HOME_EV_HOME_HLR_RESOLVED:
+ // FIXME
+ break;
+
+ case PROXY_TO_HOME_EV_RX_INSERT_SUBSCRIBER_DATA_REQ:
+ // FIXME
+ break;
+
+ case PROXY_TO_HOME_EV_RX_UPDATE_LOCATION_RESULT:
+ // FIXME
+ break;
+
+ case PROXY_TO_HOME_EV_RX_SEND_AUTH_INFO_RESULT:
+ // FIXME
+ break;
+
+ case PROXY_TO_HOME_EV_CHECK_TUPLES:
+ // FIXME
+ break;
+
+ case PROXY_TO_HOME_EV_CONFIRM_LU:
+ // FIXME
+ break;
+
+ default:
+ OSMO_ASSERT(false);
+ }
+}
+
+static int proxy_to_home_wait_send_auth_info_result_timeout(struct osmo_fsm_inst *fi)
+{
+ /* Return 1 to terminate FSM instance, 0 to keep running */
+ return 1;
+}
+
+void proxy_to_home_idle_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ //struct proxy_mm *proxy_mm = fi->priv;
+ // FIXME
+}
+
+static void proxy_to_home_idle_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ //struct proxy_mm *proxy_mm = fi->priv;
+
+ switch (event) {
+
+ case PROXY_TO_HOME_EV_HOME_HLR_RESOLVED:
+ // FIXME
+ break;
+
+ case PROXY_TO_HOME_EV_RX_INSERT_SUBSCRIBER_DATA_REQ:
+ // FIXME
+ break;
+
+ case PROXY_TO_HOME_EV_RX_UPDATE_LOCATION_RESULT:
+ // FIXME
+ break;
+
+ case PROXY_TO_HOME_EV_RX_SEND_AUTH_INFO_RESULT:
+ // FIXME
+ break;
+
+ case PROXY_TO_HOME_EV_CHECK_TUPLES:
+ // FIXME
+ break;
+
+ case PROXY_TO_HOME_EV_CONFIRM_LU:
+ // FIXME
+ break;
+
+ default:
+ OSMO_ASSERT(false);
+ }
+}
+
+static int proxy_to_home_idle_timeout(struct osmo_fsm_inst *fi)
+{
+ /* Return 1 to terminate FSM instance, 0 to keep running */
+ return 1;
+}
+
+void proxy_to_home_clear_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ //struct proxy_mm *proxy_mm = fi->priv;
+ // FIXME
+}
+
+static void proxy_to_home_clear_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ //struct proxy_mm *proxy_mm = fi->priv;
+
+ switch (event) {
+
+ case PROXY_TO_HOME_EV_HOME_HLR_RESOLVED:
+ // FIXME
+ break;
+
+ case PROXY_TO_HOME_EV_RX_INSERT_SUBSCRIBER_DATA_REQ:
+ // FIXME
+ break;
+
+ case PROXY_TO_HOME_EV_RX_UPDATE_LOCATION_RESULT:
+ // FIXME
+ break;
+
+ case PROXY_TO_HOME_EV_RX_SEND_AUTH_INFO_RESULT:
+ // FIXME
+ break;
+
+ case PROXY_TO_HOME_EV_CHECK_TUPLES:
+ // FIXME
+ break;
+
+ case PROXY_TO_HOME_EV_CONFIRM_LU:
+ // FIXME
+ break;
+
+ default:
+ OSMO_ASSERT(false);
+ }
+}
+
+static int proxy_to_home_clear_timeout(struct osmo_fsm_inst *fi)
+{
+ /* Return 1 to terminate FSM instance, 0 to keep running */
+ return 1;
+}
+
+#define S(x) (1 << (x))
+
+static const struct osmo_fsm_state proxy_to_home_fsm_states[] = {
+ [PROXY_TO_HOME_ST_WAIT_HOME_HLR_RESOLVED] = {
+ .name = "wait_home_hlr_resolved",
+ .in_event_mask = 0
+ | S(PROXY_TO_HOME_EV_HOME_HLR_RESOLVED)
+ | S(PROXY_TO_HOME_EV_RX_INSERT_SUBSCRIBER_DATA_REQ)
+ | S(PROXY_TO_HOME_EV_RX_UPDATE_LOCATION_RESULT)
+ | S(PROXY_TO_HOME_EV_RX_SEND_AUTH_INFO_RESULT)
+ | S(PROXY_TO_HOME_EV_CHECK_TUPLES)
+ | S(PROXY_TO_HOME_EV_CONFIRM_LU)
+ ,
+ .out_state_mask = 0
+ | S(PROXY_TO_HOME_ST_WAIT_HOME_HLR_RESOLVED)
+ | S(PROXY_TO_HOME_ST_WAIT_UPDATE_LOCATION_RESULT)
+ | S(PROXY_TO_HOME_ST_WAIT_SEND_AUTH_INFO_RESULT)
+ | S(PROXY_TO_HOME_ST_IDLE)
+ | S(PROXY_TO_HOME_ST_CLEAR)
+ ,
+ .onenter = proxy_to_home_wait_home_hlr_resolved_onenter,
+ .action = proxy_to_home_wait_home_hlr_resolved_action,
+ },
+ [PROXY_TO_HOME_ST_WAIT_UPDATE_LOCATION_RESULT] = {
+ .name = "wait_update_location_result",
+ .in_event_mask = 0
+ | S(PROXY_TO_HOME_EV_HOME_HLR_RESOLVED)
+ | S(PROXY_TO_HOME_EV_RX_INSERT_SUBSCRIBER_DATA_REQ)
+ | S(PROXY_TO_HOME_EV_RX_UPDATE_LOCATION_RESULT)
+ | S(PROXY_TO_HOME_EV_RX_SEND_AUTH_INFO_RESULT)
+ | S(PROXY_TO_HOME_EV_CHECK_TUPLES)
+ | S(PROXY_TO_HOME_EV_CONFIRM_LU)
+ ,
+ .out_state_mask = 0
+ | S(PROXY_TO_HOME_ST_WAIT_HOME_HLR_RESOLVED)
+ | S(PROXY_TO_HOME_ST_WAIT_UPDATE_LOCATION_RESULT)
+ | S(PROXY_TO_HOME_ST_WAIT_SEND_AUTH_INFO_RESULT)
+ | S(PROXY_TO_HOME_ST_IDLE)
+ | S(PROXY_TO_HOME_ST_CLEAR)
+ ,
+ .onenter = proxy_to_home_wait_update_location_result_onenter,
+ .action = proxy_to_home_wait_update_location_result_action,
+ },
+ [PROXY_TO_HOME_ST_WAIT_SEND_AUTH_INFO_RESULT] = {
+ .name = "wait_send_auth_info_result",
+ .in_event_mask = 0
+ | S(PROXY_TO_HOME_EV_HOME_HLR_RESOLVED)
+ | S(PROXY_TO_HOME_EV_RX_INSERT_SUBSCRIBER_DATA_REQ)
+ | S(PROXY_TO_HOME_EV_RX_UPDATE_LOCATION_RESULT)
+ | S(PROXY_TO_HOME_EV_RX_SEND_AUTH_INFO_RESULT)
+ | S(PROXY_TO_HOME_EV_CHECK_TUPLES)
+ | S(PROXY_TO_HOME_EV_CONFIRM_LU)
+ ,
+ .out_state_mask = 0
+ | S(PROXY_TO_HOME_ST_WAIT_HOME_HLR_RESOLVED)
+ | S(PROXY_TO_HOME_ST_WAIT_UPDATE_LOCATION_RESULT)
+ | S(PROXY_TO_HOME_ST_WAIT_SEND_AUTH_INFO_RESULT)
+ | S(PROXY_TO_HOME_ST_IDLE)
+ | S(PROXY_TO_HOME_ST_CLEAR)
+ ,
+ .onenter = proxy_to_home_wait_send_auth_info_result_onenter,
+ .action = proxy_to_home_wait_send_auth_info_result_action,
+ },
+ [PROXY_TO_HOME_ST_IDLE] = {
+ .name = "idle",
+ .in_event_mask = 0
+ | S(PROXY_TO_HOME_EV_HOME_HLR_RESOLVED)
+ | S(PROXY_TO_HOME_EV_RX_INSERT_SUBSCRIBER_DATA_REQ)
+ | S(PROXY_TO_HOME_EV_RX_UPDATE_LOCATION_RESULT)
+ | S(PROXY_TO_HOME_EV_RX_SEND_AUTH_INFO_RESULT)
+ | S(PROXY_TO_HOME_EV_CHECK_TUPLES)
+ | S(PROXY_TO_HOME_EV_CONFIRM_LU)
+ ,
+ .out_state_mask = 0
+ | S(PROXY_TO_HOME_ST_WAIT_HOME_HLR_RESOLVED)
+ | S(PROXY_TO_HOME_ST_WAIT_UPDATE_LOCATION_RESULT)
+ | S(PROXY_TO_HOME_ST_WAIT_SEND_AUTH_INFO_RESULT)
+ | S(PROXY_TO_HOME_ST_IDLE)
+ | S(PROXY_TO_HOME_ST_CLEAR)
+ ,
+ .onenter = proxy_to_home_idle_onenter,
+ .action = proxy_to_home_idle_action,
+ },
+ [PROXY_TO_HOME_ST_CLEAR] = {
+ .name = "clear",
+ .in_event_mask = 0
+ | S(PROXY_TO_HOME_EV_HOME_HLR_RESOLVED)
+ | S(PROXY_TO_HOME_EV_RX_INSERT_SUBSCRIBER_DATA_REQ)
+ | S(PROXY_TO_HOME_EV_RX_UPDATE_LOCATION_RESULT)
+ | S(PROXY_TO_HOME_EV_RX_SEND_AUTH_INFO_RESULT)
+ | S(PROXY_TO_HOME_EV_CHECK_TUPLES)
+ | S(PROXY_TO_HOME_EV_CONFIRM_LU)
+ ,
+ .out_state_mask = 0
+ | S(PROXY_TO_HOME_ST_WAIT_HOME_HLR_RESOLVED)
+ | S(PROXY_TO_HOME_ST_WAIT_UPDATE_LOCATION_RESULT)
+ | S(PROXY_TO_HOME_ST_WAIT_SEND_AUTH_INFO_RESULT)
+ | S(PROXY_TO_HOME_ST_IDLE)
+ | S(PROXY_TO_HOME_ST_CLEAR)
+ ,
+ .onenter = proxy_to_home_clear_onenter,
+ .action = proxy_to_home_clear_action,
+ },
+};
+
+static int proxy_to_home_fsm_timer_cb(struct osmo_fsm_inst *fi)
+{
+ //struct proxy_mm *proxy_mm = fi->priv;
+ switch (fi->state) {
+
+ case PROXY_TO_HOME_ST_WAIT_HOME_HLR_RESOLVED:
+ return proxy_to_home_wait_home_hlr_resolved_timeout(fi);
+
+ case PROXY_TO_HOME_ST_WAIT_UPDATE_LOCATION_RESULT:
+ return proxy_to_home_wait_update_location_result_timeout(fi);
+
+ case PROXY_TO_HOME_ST_WAIT_SEND_AUTH_INFO_RESULT:
+ return proxy_to_home_wait_send_auth_info_result_timeout(fi);
+
+ case PROXY_TO_HOME_ST_IDLE:
+ return proxy_to_home_idle_timeout(fi);
+
+ case PROXY_TO_HOME_ST_CLEAR:
+ return proxy_to_home_clear_timeout(fi);
+
+ default:
+ /* Return 1 to terminate FSM instance, 0 to keep running */
+ return 1;
+ }
+}
+
+void proxy_to_home_fsm_cleanup(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)
+{
+ //struct proxy_mm *proxy_mm = fi->priv;
+ // FIXME
+}
+
+static struct osmo_fsm proxy_to_home_fsm = {
+ .name = "proxy_to_home",
+ .states = proxy_to_home_fsm_states,
+ .num_states = ARRAY_SIZE(proxy_to_home_fsm_states),
+ .log_subsys = DLGLOBAL, // FIXME
+ .event_names = proxy_to_home_fsm_event_names,
+ .timer_cb = proxy_to_home_fsm_timer_cb,
+ .cleanup = proxy_to_home_fsm_cleanup,
+};
+
+static __attribute__((constructor)) void proxy_to_home_fsm_register(void)
+{
+ OSMO_ASSERT(osmo_fsm_register(&proxy_to_home_fsm) == 0);
+}