aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeels Hofmeyr <nhofmeyr@sysmocom.de>2023-04-14 23:33:24 +0200
committerNeels Hofmeyr <nhofmeyr@sysmocom.de>2023-05-10 02:17:04 +0200
commit8bc881f31a5c29734122b3ec1461e42abf6fc7df (patch)
tree5e9ec4fd8efafc896414e65231a5cfe0c046325d
parentd5139548f237bfab984ac0e0ca3406c42cbd895c (diff)
sccp_scoc.c: fix infinite loop on conn ID exhaustion
Looking for an unused SCCP connection ID has no exit condition if all connection IDs are in use. However unlikely it is that there are 16777215 active connections on one SCCP instance, add an exit condition. Do so by implementing the ID lookup in a new separate function, which qualifies for public API (upcoming patch). So far, use an exit condition closest to previous behavior: iterate the entire SCCP conn id number space before exiting in failure. Change-Id: Ib64e0cb1ae0cc8b7bebcb2a352d4068b496b304a
-rw-r--r--src/sccp_scoc.c28
1 files changed, 22 insertions, 6 deletions
diff --git a/src/sccp_scoc.c b/src/sccp_scoc.c
index 1838615..e63ebf8 100644
--- a/src/sccp_scoc.c
+++ b/src/sccp_scoc.c
@@ -539,10 +539,14 @@ static struct sccp_connection *conn_create_id(struct osmo_sccp_user *user, uint3
return conn;
}
-/* Search for next free connection ID and allocate conn */
-static struct sccp_connection *conn_create(struct osmo_sccp_user *user)
+/* Return an unused SCCP connection ID.
+ * Callers should check the returned value: on negative return value, there are no unused IDs available.
+ * \param[in] sccp The SCCP instance to determine a new connection ID for.
+ * \return unused ID on success (range [0x0, 0x00fffffe]) or negative on elapsed max_attempts without an unused id (<0).
+ */
+static int osmo_sccp_instance_next_conn_id(struct osmo_sccp_instance *sccp)
{
- struct osmo_sccp_instance *sccp = user->inst;
+ int max_attempts = 0x00FFFFFE;
/* SUA: RFC3868 sec 3.10.4:
* The source reference number is a 4 octet long integer.
@@ -555,14 +559,26 @@ static struct sccp_connection *conn_create(struct osmo_sccp_user *user)
* Hence, as we currently use the connection ID also as local reference,
* let's simply use 24 bit ids to fit all link types (excluding 0x00ffffff).
*/
- do {
+ while (OSMO_LIKELY((max_attempts--) > 0)) {
/* Optimized modulo operation (% 0x00FFFFFE) using bitwise AND plus CMP: */
sccp->next_id = (sccp->next_id + 1) & 0x00FFFFFF;
if (OSMO_UNLIKELY(sccp->next_id == 0x00FFFFFF))
sccp->next_id = 0;
- } while (conn_find_by_id(sccp, sccp->next_id));
- return conn_create_id(user, sccp->next_id);
+ if (!conn_find_by_id(sccp, sccp->next_id))
+ return sccp->next_id;
+ }
+
+ return -1;
+}
+
+/* Search for next free connection ID and allocate conn */
+static struct sccp_connection *conn_create(struct osmo_sccp_user *user)
+{
+ int conn_id = osmo_sccp_instance_next_conn_id(user->inst);
+ if (conn_id < 0)
+ return NULL;
+ return conn_create_id(user, conn_id);
}
static void conn_opt_data_clear_cache(struct sccp_connection *conn)