summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/osmocom/sigtran/osmo_ss7.h5
-rw-r--r--src/osmo_ss7.c52
-rw-r--r--src/sccp_user.c137
3 files changed, 156 insertions, 38 deletions
diff --git a/include/osmocom/sigtran/osmo_ss7.h b/include/osmocom/sigtran/osmo_ss7.h
index 57a4e06..87ace4a 100644
--- a/include/osmocom/sigtran/osmo_ss7.h
+++ b/include/osmocom/sigtran/osmo_ss7.h
@@ -307,6 +307,8 @@ struct osmo_ss7_as *
osmo_ss7_as_find_by_rctx(struct osmo_ss7_instance *inst, uint32_t rctx);
struct osmo_ss7_as *
osmo_ss7_as_find_by_l_rk_id(struct osmo_ss7_instance *inst, uint32_t l_rk_id);
+struct osmo_ss7_as *osmo_ss7_as_find_by_proto(struct osmo_ss7_instance *inst,
+ enum osmo_ss7_asp_protocol proto);
struct osmo_ss7_as *
osmo_ss7_as_find_or_create(struct osmo_ss7_instance *inst, const char *name,
enum osmo_ss7_asp_protocol proto);
@@ -383,6 +385,9 @@ struct osmo_ss7_asp {
struct osmo_ss7_asp *
osmo_ss7_asp_find_by_name(struct osmo_ss7_instance *inst, const char *name);
+struct osmo_ss7_asp
+*osmo_ss7_asp_find_by_proto(struct osmo_ss7_as *as,
+ enum osmo_ss7_asp_protocol proto);
struct osmo_ss7_asp *
osmo_ss7_asp_find_or_create(struct osmo_ss7_instance *inst, const char *name,
uint16_t remote_port, uint16_t local_port,
diff --git a/src/osmo_ss7.c b/src/osmo_ss7.c
index c13c588..eb5a4ef 100644
--- a/src/osmo_ss7.c
+++ b/src/osmo_ss7.c
@@ -833,6 +833,41 @@ osmo_ss7_as_find_by_l_rk_id(struct osmo_ss7_instance *inst, uint32_t l_rk_id)
return NULL;
}
+/*! \brief Find Application Server (AS) by given protocol.
+ * \param[in] inst SS7 Instance on which we operate
+ * \param[in] proto Protocol identifier that must match
+ * \returns pointer to AS on success; NULL otherwise
+ * If an AS has an ASP also matching the given protocol, that AS is preferred.
+ * If there are multiple matches, return the first matching AS. */
+struct osmo_ss7_as *osmo_ss7_as_find_by_proto(struct osmo_ss7_instance *inst,
+ enum osmo_ss7_asp_protocol proto)
+{
+ struct osmo_ss7_as *as;
+ struct osmo_ss7_as *as_without_asp = NULL;
+
+ OSMO_ASSERT(ss7_initialized);
+
+ /* Loop through the list with AS and try to find one where the proto
+ matches up */
+ llist_for_each_entry(as, &inst->as_list, list) {
+ if (as->cfg.proto == proto) {
+
+ /* Put down the first AS that matches the proto, just in
+ * case we will not find any matching ASP */
+ if (!as_without_asp)
+ as_without_asp = as;
+
+ /* Check if the candicate we have here has any suitable
+ * ASP */
+ if (osmo_ss7_asp_find_by_proto(as, proto))
+ return as;
+ }
+ }
+
+ /* Return with the second best find, if there is any */
+ return as_without_asp;
+}
+
/*! \brief Find or Create Application Server
* \param[in] inst SS7 Instance on which we operate
* \param[in] name Name of Application Server
@@ -1044,6 +1079,23 @@ osmo_ss7_asp_find_by_socket_addr(int fd)
return NULL;
}
+/*! \brief Find an ASP that matches the given protocol.
+ * \param[in] as Application Server in which to look for \ref asp
+ * \returns SS7 ASP in case a matching one is found; NULL otherwise */
+struct osmo_ss7_asp
+*osmo_ss7_asp_find_by_proto(struct osmo_ss7_as *as,
+ enum osmo_ss7_asp_protocol proto)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(as->cfg.asps); i++) {
+ if (as->cfg.asps[i] && as->cfg.asps[i]->cfg.proto == proto)
+ return as->cfg.asps[i];
+ }
+
+ return NULL;
+}
+
struct osmo_ss7_asp *
osmo_ss7_asp_find_or_create(struct osmo_ss7_instance *inst, const char *name,
uint16_t remote_port, uint16_t local_port,
diff --git a/src/sccp_user.c b/src/sccp_user.c
index b21a756..c9443a2 100644
--- a/src/sccp_user.c
+++ b/src/sccp_user.c
@@ -242,54 +242,113 @@ osmo_sccp_simple_client_on_ss7_id(void *ctx, uint32_t ss7_id, const char *name,
int remote_port, const char *remote_ip)
{
struct osmo_ss7_instance *ss7;
+ bool ss7_created = false;
struct osmo_ss7_as *as;
+ bool as_created = false;
struct osmo_ss7_route *rt;
+ bool rt_created = false;
struct osmo_ss7_asp *asp;
- char *as_name, *asp_name;
+ bool asp_created = false;
+ char *as_name, *asp_name = NULL;
+ /* Choose default ports when the caller does not supply valid port
+ * numbers. */
if (!remote_port || remote_port < 0)
remote_port = osmo_ss7_asp_protocol_port(prot);
if (local_port < 0)
local_port = osmo_ss7_asp_protocol_port(prot);
- /* allocate + initialize SS7 instance */
- ss7 = osmo_ss7_instance_find_or_create(ctx, ss7_id);
+ /* Check if there is already an ss7 instance present under
+ * the given id. If not, we will create a new one. */
+ ss7 = osmo_ss7_instance_find(ss7_id);
if (!ss7) {
- LOGP(DLSCCP, LOGL_ERROR, "Failed to find or create SS7 instance\n");
- return NULL;
+ LOGP(DLSCCP, LOGL_NOTICE, "%s: Creating SS7 instance\n",
+ name);
+
+ /* Create a new ss7 instance */
+ ss7 = osmo_ss7_instance_find_or_create(ctx, ss7_id);
+ if (!ss7) {
+ LOGP(DLSCCP, LOGL_ERROR,
+ "Failed to find or create SS7 instance\n");
+ return NULL;
+ }
+
+ /* Setup primary pointcode
+ * NOTE: This means that the user must set the pointcode to a
+ * proper value when a cs7 instance is defined via the VTY. */
+ ss7->cfg.primary_pc = pc;
+ ss7_created = true;
+ }
+ LOGP(DLSCCP, LOGL_NOTICE, "%s: Using SS7 instance %u, pc:%s\n", name,
+ ss7->cfg.id, osmo_ss7_pointcode_print(ss7, ss7->cfg.primary_pc));
+
+ /* There must not be an existing SCCP istance, regarless if the simple
+ * client has created the SS7 instance or if it was already present.
+ * An already existing SCCP instance would be an indication that this
+ * function has been called twice with the same SS7 instance, which
+ * must not be the case! */
+ OSMO_ASSERT(ss7->sccp == NULL);
+
+ /* Check if there is already an application server that matches
+ * the protocol we intend to use. If not, we will create one. */
+ as = osmo_ss7_as_find_by_proto(ss7, prot);
+ if (!as) {
+ LOGP(DLSCCP, LOGL_NOTICE, "%s: Creating AS instance\n",
+ name);
+ as_name = talloc_asprintf(ctx, "as-clnt-%s", name);
+ as = osmo_ss7_as_find_or_create(ss7, as_name, prot);
+ talloc_free(as_name);
+ if (!as)
+ goto out_ss7;
+ as_created = true;
+
+ as->cfg.routing_key.pc = ss7->cfg.primary_pc;
+
+ /* install default route */
+ rt = osmo_ss7_route_create(ss7->rtable_system, 0, 0,
+ as->cfg.name);
+ if (!rt)
+ goto out_as;
+ rt_created = true;
+ }
+ LOGP(DLSCCP, LOGL_NOTICE, "%s: Using AS instance %s\n", name,
+ as->cfg.name);
+
+ /* Check if we do already have an application server process
+ * that is associated with the application server we have choosen
+ * the application server process must also match the protocol
+ * we intend to use. */
+ asp = osmo_ss7_asp_find_by_proto(as, prot);
+ if (!asp) {
+ LOGP(DLSCCP, LOGL_NOTICE, "%s: Creating ASP instance\n",
+ name);
+ asp_name = talloc_asprintf(ctx, "asp-clnt-%s", name);
+ asp =
+ osmo_ss7_asp_find_or_create(ss7, asp_name, remote_port,
+ local_port, prot);
+ talloc_free(asp_name);
+ if (!asp)
+ goto out_rt;
+ asp_created = true;
+
+ asp->cfg.local.host = talloc_strdup(asp, local_ip);
+ asp->cfg.remote.host = talloc_strdup(asp, remote_ip);
+
+ osmo_ss7_as_add_asp(as, asp->cfg.name);
}
- ss7->cfg.primary_pc = pc;
-
- as_name = talloc_asprintf(ctx, "as-clnt-%s", name);
- asp_name = talloc_asprintf(ctx, "asp-clnt-%s", name);
-
- /* application server */
- as = osmo_ss7_as_find_or_create(ss7, as_name, prot);
- if (!as)
- goto out_strings;
-
- as->cfg.routing_key.pc = pc;
- /* install default route */
- rt = osmo_ss7_route_create(ss7->rtable_system, 0, 0, as_name);
- if (!rt)
- goto out_as;
- talloc_free(as_name);
+ /* Ensure that the ASP we use is set to client mode. */
+ asp->cfg.is_server = false;
- /* application server process */
- asp = osmo_ss7_asp_find_or_create(ss7, asp_name, remote_port, local_port,
- prot);
- if (!asp)
- goto out_rt;
- asp->cfg.local.host = talloc_strdup(asp, local_ip);
- asp->cfg.remote.host = talloc_strdup(asp, remote_ip);
- osmo_ss7_as_add_asp(as, asp_name);
+ /* Restart ASP */
if (prot != OSMO_SS7_ASP_PROT_IPA)
osmo_ss7_asp_use_default_lm(asp, LOGL_DEBUG);
- talloc_free(asp_name);
osmo_ss7_asp_restart(asp);
+ LOGP(DLSCCP, LOGL_NOTICE, "%s: Using ASP instance %s\n", name,
+ asp->cfg.name);
- /* Allocate SCCP stack + SCCP user */
+ /* Allocate SCCP instance */
+ LOGP(DLSCCP, LOGL_NOTICE, "%s: Creating SCCP instance\n", name);
ss7->sccp = osmo_sccp_instance_create(ss7, NULL);
if (!ss7->sccp)
goto out_asp;
@@ -297,15 +356,17 @@ osmo_sccp_simple_client_on_ss7_id(void *ctx, uint32_t ss7_id, const char *name,
return ss7->sccp;
out_asp:
- osmo_ss7_asp_destroy(asp);
+ if (asp_created)
+ osmo_ss7_asp_destroy(asp);
out_rt:
- osmo_ss7_route_destroy(rt);
+ if (rt_created)
+ osmo_ss7_route_destroy(rt);
out_as:
- osmo_ss7_as_destroy(as);
-out_strings:
- talloc_free(as_name);
- talloc_free(asp_name);
- osmo_ss7_instance_destroy(ss7);
+ if (as_created)
+ osmo_ss7_as_destroy(as);
+out_ss7:
+ if (ss7_created)
+ osmo_ss7_instance_destroy(ss7);
return NULL;
}