libosmo-mgcp: Connection Identifiers are allocated by MGW, not CA
The MGCP connection identifier is allocated by the MGW while processing
the CRCX, see RFC3435 2.1.3.2:. Including/Accepting a connection
identifier in CRCX is "forbidden" as per RFC3435 Section 3.2.2.
So the MGW side must *reject* a CRCX message with 'I' parameter, and
allocate a connection identifier which is subsequently returned in the
response.
Closes: OS#2648
Change-Id: Iab6a6038e7610c62f34e642cd49c93d11151252c
diff --git a/src/libosmo-mgcp/Makefile.am b/src/libosmo-mgcp/Makefile.am
index fce0e1b..a785d62 100644
--- a/src/libosmo-mgcp/Makefile.am
+++ b/src/libosmo-mgcp/Makefile.am
@@ -7,6 +7,7 @@
AM_CFLAGS = \
-Wall \
$(LIBOSMOCORE_CFLAGS) \
+ $(LIBOSMOGSM_CFLAGS) \
$(LIBOSMOVTY_CFLAGS) \
$(LIBOSMONETIF_CFLAGS) \
$(COVERAGE_CFLAGS) \
@@ -14,6 +15,7 @@
AM_LDFLAGS = \
$(LIBOSMOCORE_LIBS) \
+ $(LIBOSMOGSM_LIBS) \
$(LIBOSMOVTY_LIBS) \
$(LIBOSMONETIF_LIBS) \
$(COVERAGE_LDFLAGS) \
diff --git a/src/libosmo-mgcp/mgcp_conn.c b/src/libosmo-mgcp/mgcp_conn.c
index 31713cb..e33596d 100644
--- a/src/libosmo-mgcp/mgcp_conn.c
+++ b/src/libosmo-mgcp/mgcp_conn.c
@@ -25,6 +25,46 @@
#include <osmocom/mgcp/mgcp_internal.h>
#include <osmocom/mgcp/mgcp_common.h>
#include <osmocom/mgcp/mgcp_ep.h>
+#include <osmocom/gsm/gsm_utils.h>
+#include <ctype.h>
+
+/* Allocate a new connection identifier. According to RFC3435, they must
+ * be unique only within the scope of the endpoint. */
+static int mgcp_alloc_id(struct mgcp_endpoint *endp, char *id)
+{
+ int i;
+ int k;
+ int rc;
+ uint8_t id_bin[16];
+ char *id_hex;
+
+ /* Generate a connection id that is unique for the current endpoint.
+ * Technically a counter would be sufficient, but in order to
+ * be able to find a specific connection in large logfiles and to
+ * prevent unintentional connections we assign the connection
+ * identifiers randomly from a reasonable large number space */
+ for (i = 0; i < 32; i++) {
+ rc = osmo_get_rand_id(id_bin, sizeof(id_bin));
+ if (rc < 0)
+ return rc;
+
+ id_hex = osmo_hexdump_nospc(id_bin, sizeof(id_bin));
+ for (k = 0; k < strlen(id_hex); k++)
+ id_hex[k] = toupper(id_hex[k]);
+
+ /* ensure that the generated conn_id is unique
+ * for this endpoint */
+ if (!mgcp_conn_get_rtp(endp, id_hex)) {
+ osmo_strlcpy(id, id_hex, MGCP_CONN_ID_LENGTH);
+ return 0;
+ }
+ }
+
+ LOGP(DLMGCP, LOGL_ERROR, "endpoint:%x, unable to generate a unique connectionIdentifier\n",
+ ENDPOINT_NUMBER(endp));
+
+ return -1;
+}
/* Reset codec state and free memory */
static void mgcp_rtp_codec_reset(struct mgcp_rtp_codec *codec)
@@ -78,30 +118,19 @@
* \param[in] type connection type (e.g. MGCP_CONN_TYPE_RTP)
* \returns pointer to allocated connection, NULL on error */
struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp,
- const char *id, enum mgcp_conn_type type,
- char *name)
+ enum mgcp_conn_type type, char *name)
{
struct mgcp_conn *conn;
+ int rc;
+
OSMO_ASSERT(endp);
OSMO_ASSERT(endp->conns.next != NULL && endp->conns.prev != NULL);
OSMO_ASSERT(strlen(name) < sizeof(conn->name));
- /* Id is a mandatory parameter */
- if (!id)
- return NULL;
-
- /* Prevent over long id strings */
- if (strlen(id) >= MGCP_CONN_ID_LENGTH)
- return NULL;
-
/* Do not allow more then two connections */
if (llist_count(&endp->conns) >= endp->type->max_conns)
return NULL;
- /* Prevent duplicate connection IDs */
- if (mgcp_conn_get(endp, id))
- return NULL;
-
/* Create new connection and add it to the list */
conn = talloc_zero(ctx, struct mgcp_conn);
if (!conn)
@@ -112,7 +141,11 @@
conn->mode_orig = MGCP_CONN_NONE;
conn->u.rtp.conn = conn;
strcpy(conn->name, name);
- osmo_strlcpy(conn->id, id, sizeof(conn->id));
+ rc = mgcp_alloc_id(endp, conn->id);
+ if (rc < 0) {
+ talloc_free(conn);
+ return NULL;
+ }
switch (type) {
case MGCP_CONN_TYPE_RTP:
diff --git a/src/libosmo-mgcp/mgcp_protocol.c b/src/libosmo-mgcp/mgcp_protocol.c
index 672a8d4..feca8da 100644
--- a/src/libosmo-mgcp/mgcp_protocol.c
+++ b/src/libosmo-mgcp/mgcp_protocol.c
@@ -447,7 +447,7 @@
char *line;
int have_sdp = 0, osmux_cid = -1;
struct mgcp_conn_rtp *conn = NULL;
- const char *conn_id = NULL;
+ struct mgcp_conn *_conn = NULL;
char conn_name[512];
LOGP(DLMGCP, LOGL_NOTICE, "CRCX: creating new connection ...\n");
@@ -468,7 +468,10 @@
callid = (const char *)line + 3;
break;
case 'I':
- conn_id = (const char *)line + 3;
+ /* It is illegal to send a connection identifier
+ * together with a CRCX, the MGW will assign the
+ * connection identifier by itself on CRCX */
+ return create_err_response(NULL, 523, "CRCX", p->trans);
break;
case 'M':
mode = (const char *)line + 3;
@@ -510,13 +513,6 @@
return create_err_response(endp, 400, "CRCX", p->trans);
}
- if (!conn_id) {
- LOGP(DLMGCP, LOGL_ERROR,
- "CRCX: endpoint:%x insufficient parameters, missing connection id\n",
- ENDPOINT_NUMBER(endp));
- return create_err_response(endp, 400, "CRCX", p->trans);
- }
-
/* Check if we are able to accept the creation of another connection */
if (llist_count(&endp->conns) >= endp->type->max_conns) {
LOGP(DLMGCP, LOGL_ERROR,
@@ -560,32 +556,17 @@
set_local_cx_options(endp->tcfg->endpoints, &endp->local_options,
local_options);
- /* Only accept another connection when the connection ID is different. */
- if (mgcp_conn_get_rtp(endp, conn_id)) {
- LOGP(DLMGCP, LOGL_ERROR,
- "CRCX: endpoint:%x there is already a connection with id %u present!\n",
- conn_id, ENDPOINT_NUMBER(endp));
- if (tcfg->force_realloc) {
- /* Ignore the existing connection by just freeing it */
- mgcp_conn_free(endp, conn_id);
- } else {
- /* There is already a connection with that ID present,
- * leave everything as it is and return with an error. */
- return create_err_response(endp, 400, "CRCX", p->trans);
- }
- }
-
- snprintf(conn_name, sizeof(conn_name), "%s-%s", callid, conn_id);
- mgcp_conn_alloc(NULL, endp, conn_id, MGCP_CONN_TYPE_RTP,
- conn_name);
- conn = mgcp_conn_get_rtp(endp, conn_id);
- if (!conn) {
+ snprintf(conn_name, sizeof(conn_name), "%s", callid);
+ _conn = mgcp_conn_alloc(NULL, endp, MGCP_CONN_TYPE_RTP, conn_name);
+ if (!_conn) {
LOGP(DLMGCP, LOGL_ERROR,
"CRCX: endpoint:%x unable to allocate RTP connection\n",
ENDPOINT_NUMBER(endp));
goto error2;
}
+ conn = mgcp_conn_get_rtp(endp, _conn->id);
+ OSMO_ASSERT(conn);
if (mgcp_parse_conn_mode(mode, endp, conn->conn) != 0) {
error_code = 517;