From 8e75e6388c93ea2dc2e9ad1a08989b603ac5cbf2 Mon Sep 17 00:00:00 2001 From: Oliver Smith Date: Wed, 3 Apr 2019 09:52:19 +0200 Subject: sccp_scoc: separate conn_id from local_ref Properly generate a local_ref for each connection, that is unique for each SCU user. Previously, the conn_id was used as local_ref. Related: OS#3871 Change-Id: Ifd55c6b7ed2558ff072042079cf45f5068a971de --- src/sccp_internal.h | 3 +++ src/sccp_scoc.c | 77 ++++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 64 insertions(+), 16 deletions(-) diff --git a/src/sccp_internal.h b/src/sccp_internal.h index ad8a6fd..10ec285 100644 --- a/src/sccp_internal.h +++ b/src/sccp_internal.h @@ -78,6 +78,9 @@ struct osmo_sccp_user { /* Application Server FSM Instance */ struct osmo_fsm_inst *as_fi; + + /* next local reference to allocate */ + uint32_t next_local_ref; }; extern int DSCCP; diff --git a/src/sccp_scoc.c b/src/sccp_scoc.c index 91a1ab7..2f5be28 100644 --- a/src/sccp_scoc.c +++ b/src/sccp_scoc.c @@ -47,6 +47,7 @@ */ #include +#include #include #include @@ -93,6 +94,11 @@ struct sccp_connection { * it whever sending data to the peer. Only relevant over the * wire, not to be used across the SCCP user SAP */ uint32_t remote_ref; + /* SCCP Local Connection Reference. Generated by the local SCCP stack + * (conn_get_unused_local_ref()) to uniquely identify a SCCP connection. + * The local_ref is unique for each (SCCP connection, SCU user) tuple. Only + * relevant over the wire, not to be used accross the SCCP user SAP. */ + uint32_t local_ref; uint32_t importance; uint32_t sccp_class; @@ -456,15 +462,49 @@ static struct sccp_connection *conn_find_by_id(struct osmo_sccp_instance *inst, return NULL; } +static struct sccp_connection *conn_find_by_local_ref(struct osmo_sccp_user *user, uint32_t local_ref) +{ + struct sccp_connection *conn; + + llist_for_each_entry(conn, &user->inst->connections, list) { + if (conn->user == user && conn->local_ref == local_ref) + return conn; + } + return NULL; +} + +static int conn_unused_local_ref(struct osmo_sccp_user *user, uint32_t *local_ref) +{ + uint32_t current; + uint32_t start = user->next_local_ref; + + do { + current = user->next_local_ref++; + if (current == start) { + LOGP(DLSCCP, LOGL_ERROR, "No unused local reference available for user %s\n", user->name); + return -ENOSPC; + } + } while (conn_find_by_local_ref(user, current)); + + *local_ref = current; + return 0; +} + #define INIT_TIMER(x, fn, priv) do { (x)->cb = fn; (x)->data = priv; } while (0) /* allocate + init a SCCP Connection with given ID */ static struct sccp_connection *conn_create_id(struct osmo_sccp_user *user, uint32_t conn_id) { - struct sccp_connection *conn = talloc_zero(user->inst, struct sccp_connection); + uint32_t local_ref; + struct sccp_connection *conn; char name[16]; + if (conn_unused_local_ref(user, &local_ref) < 0) + return NULL; + + conn = talloc_zero(user->inst, struct sccp_connection); conn->conn_id = conn_id; + conn->local_ref = local_ref; conn->inst = user->inst; conn->user = user; @@ -538,7 +578,7 @@ static struct xua_msg *xua_gen_relre(struct sccp_connection *conn, xua->hdr = XUA_HDR(SUA_MSGC_CO, SUA_CO_RELRE); xua_msg_add_u32(xua, SUA_IEI_ROUTE_CTX, conn->inst->route_ctx); xua_msg_add_u32(xua, SUA_IEI_DEST_REF, conn->remote_ref); - xua_msg_add_u32(xua, SUA_IEI_SRC_REF, conn->conn_id); + xua_msg_add_u32(xua, SUA_IEI_SRC_REF, conn->local_ref); xua_msg_add_u32(xua, SUA_IEI_CAUSE, SUA_CAUSE_T_RELEASE | cause); /* optional: importance */ if (prim && msgb_l2(prim->oph.msg)) @@ -581,7 +621,7 @@ static struct xua_msg *xua_gen_msg_co(struct sccp_connection *conn, uint32_t eve xua->hdr = XUA_HDR(SUA_MSGC_CO, SUA_CO_CORE); xua_msg_add_u32(xua, SUA_IEI_ROUTE_CTX, conn->inst->route_ctx); xua_msg_add_u32(xua, SUA_IEI_PROTO_CLASS, conn->sccp_class); - xua_msg_add_u32(xua, SUA_IEI_SRC_REF, conn->conn_id); + xua_msg_add_u32(xua, SUA_IEI_SRC_REF, conn->local_ref); xua_msg_add_sccp_addr(xua, SUA_IEI_DEST_ADDR, &conn->called_addr); xua_msg_add_u32(xua, SUA_IEI_SEQ_CTRL, 0); /* TODO */ /* optional: sequence number (class 3 only) */ @@ -597,7 +637,7 @@ static struct xua_msg *xua_gen_msg_co(struct sccp_connection *conn, uint32_t eve xua_msg_add_u32(xua, SUA_IEI_ROUTE_CTX, conn->inst->route_ctx); xua_msg_add_u32(xua, SUA_IEI_PROTO_CLASS, conn->sccp_class); xua_msg_add_u32(xua, SUA_IEI_DEST_REF, conn->remote_ref); - xua_msg_add_u32(xua, SUA_IEI_SRC_REF, conn->conn_id); + xua_msg_add_u32(xua, SUA_IEI_SRC_REF, conn->local_ref); xua_msg_add_u32(xua, SUA_IEI_SEQ_CTRL, 0); /* TODO */ /* optional: sequence number (class 3 only) */ if (conn->called_addr.presence) @@ -618,7 +658,7 @@ static struct xua_msg *xua_gen_msg_co(struct sccp_connection *conn, uint32_t eve xua->hdr = XUA_HDR(SUA_MSGC_CO, SUA_CO_RELRE); xua_msg_add_u32(xua, SUA_IEI_ROUTE_CTX, conn->inst->route_ctx); xua_msg_add_u32(xua, SUA_IEI_DEST_REF, conn->remote_ref); - xua_msg_add_u32(xua, SUA_IEI_SRC_REF, conn->conn_id); + xua_msg_add_u32(xua, SUA_IEI_SRC_REF, conn->local_ref); xua_msg_add_u32(xua, SUA_IEI_CAUSE, SUA_CAUSE_T_RELEASE | prim->u.disconnect.cause); /* optional: importance */ if (prim && msgb_l2(prim->oph.msg) && msgb_l2len(prim->oph.msg)) @@ -629,7 +669,7 @@ static struct xua_msg *xua_gen_msg_co(struct sccp_connection *conn, uint32_t eve xua->hdr = XUA_HDR(SUA_MSGC_CO, SUA_CO_RELCO); xua_msg_add_u32(xua, SUA_IEI_ROUTE_CTX, conn->inst->route_ctx); xua_msg_add_u32(xua, SUA_IEI_DEST_REF, conn->remote_ref); - xua_msg_add_u32(xua, SUA_IEI_SRC_REF, conn->conn_id); + xua_msg_add_u32(xua, SUA_IEI_SRC_REF, conn->local_ref); /* optional: importance */ break; case SUA_CO_CODT: /* Connection Oriented Data Transfer == SCCP DT1 */ @@ -647,7 +687,7 @@ static struct xua_msg *xua_gen_msg_co(struct sccp_connection *conn, uint32_t eve xua->hdr = XUA_HDR(SUA_MSGC_CO, SUA_CO_COIT); xua_msg_add_u32(xua, SUA_IEI_ROUTE_CTX, conn->inst->route_ctx); xua_msg_add_u32(xua, SUA_IEI_PROTO_CLASS, conn->sccp_class); - xua_msg_add_u32(xua, SUA_IEI_SRC_REF, conn->conn_id); + xua_msg_add_u32(xua, SUA_IEI_SRC_REF, conn->local_ref); xua_msg_add_u32(xua, SUA_IEI_DEST_REF, conn->remote_ref); /* optional: sequence number; credit (both class 3 only) */ break; @@ -1354,6 +1394,16 @@ static struct osmo_sccp_user *sccp_find_user(struct osmo_sccp_instance *inst, return sccp_user_find(inst, called_addr.ssn, called_addr.pc); } +static struct sccp_connection *sccp_find_connection(struct osmo_sccp_instance *inst, struct xua_msg *xua) +{ + uint32_t local_ref = xua_msg_get_u32(xua, SUA_IEI_DEST_REF); + struct osmo_sccp_user *user = sccp_find_user(inst, xua); + + if (user) + return conn_find_by_local_ref(user, local_ref); + return NULL; +} + /*! \brief SCOC: Receive SCRC Routing Failure * \param[in] inst SCCP Instance on which we operate * \param[in] xua SUA message that was failed to route @@ -1361,12 +1411,9 @@ static struct osmo_sccp_user *sccp_find_user(struct osmo_sccp_instance *inst, void sccp_scoc_rx_scrc_rout_fail(struct osmo_sccp_instance *inst, struct xua_msg *xua, uint32_t return_cause) { - uint32_t conn_id; - struct sccp_connection *conn; + struct sccp_connection *conn = sccp_find_connection(inst, xua); /* try to dispatch to connection FSM (if any) */ - conn_id = xua_msg_get_u32(xua, SUA_IEI_DEST_REF); - conn = conn_find_by_id(inst, conn_id); if (conn) { osmo_fsm_inst_dispatch(conn->fi, SCOC_E_RCOC_ROUT_FAIL_IND, xua); @@ -1626,13 +1673,11 @@ void sccp_scoc_rx_from_scrc(struct osmo_sccp_instance *inst, conn = conn_create(scu); conn->incoming = true; } else { - uint32_t conn_id; /* Resolve existing connection */ - conn_id = xua_msg_get_u32(xua, SUA_IEI_DEST_REF); - conn = conn_find_by_id(inst, conn_id); + conn = sccp_find_connection(inst, xua); if (!conn) { LOGP(DLSCCP, LOGL_NOTICE, "Cannot find connection for " - "local reference %u\n", conn_id); + "local reference %u\n", xua_msg_get_u32(xua, SUA_IEI_DEST_REF)); sccp_scoc_rx_unass_local_ref(inst, xua); return; } @@ -1641,7 +1686,7 @@ void sccp_scoc_rx_from_scrc(struct osmo_sccp_instance *inst, OSMO_ASSERT(conn->fi); DEBUGP(DLSCCP, "Received %s for local reference %u\n", - xua_hdr_dump(xua, &xua_dialect_sua), conn->conn_id); + xua_hdr_dump(xua, &xua_dialect_sua), conn->local_ref); if (xua->hdr.msg_type != SUA_CO_CORE && xua->hdr.msg_type != SUA_CO_COAK && -- cgit v1.2.3