From 364f237b42d34b14de283d6cb0db2d8c246645d6 Mon Sep 17 00:00:00 2001 From: Keith Date: Sun, 31 Jan 2021 05:24:29 +0100 Subject: [PATCH] MNCC v8: Implement Basic Support for Global Call Reference. * Add GCR to mncc struct and therefore bump mncc version. * Pass the GCR as a SIP Header to SIP UA and retrieve any such header from incoming SIP calls, passing the GCR on to MNCC Related: #OS5164 Depends: osmo-msc I705c860e51637b4537cad65a330ecbaaca96dd5b Change-Id: Id40d7e0fed9356f801b3627c118150055e7232b1 --- src/call.h | 1 + src/mncc.c | 2 ++ src/mncc_protocol.h | 4 ++- src/sip.c | 73 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+), 1 deletion(-) diff --git a/src/call.h b/src/call.h index d1732f9..8360711 100644 --- a/src/call.h +++ b/src/call.h @@ -31,6 +31,7 @@ struct call { const char *source; const char *dest; + struct osmo_gcr_parsed gcr; }; enum { diff --git a/src/mncc.c b/src/mncc.c index 9d75950..fc99400 100644 --- a/src/mncc.c +++ b/src/mncc.c @@ -543,6 +543,7 @@ static void check_setup(struct mncc_connection *conn, const char *buf, int rc) leg->conn = conn; leg->state = MNCC_CC_INITIAL; leg->dir = MNCC_DIR_MO; + leg->base.call->gcr = data->gcr; memcpy(&leg->called, called, sizeof(leg->called)); memcpy(&leg->calling, &data->calling, sizeof(leg->calling)); memcpy(&leg->imsi, data->imsi, sizeof(leg->imsi)); @@ -898,6 +899,7 @@ int mncc_create_remote_leg(struct mncc_connection *conn, struct call *call) mncc.fields |= MNCC_F_CALLING; mncc.calling.plan = GSM48_NPI_ISDN_E164; + mncc.gcr = call->gcr; if (call->source && call->source[0] == '+') { mncc.calling.type = GSM48_TON_INTERNATIONAL; diff --git a/src/mncc_protocol.h b/src/mncc_protocol.h index 5d35191..11969ee 100644 --- a/src/mncc_protocol.h +++ b/src/mncc_protocol.h @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -159,6 +160,7 @@ struct gsm_mncc { unsigned char lchan_type; unsigned char lchan_mode; + struct osmo_gcr_parsed gcr; /* A buffer to contain SDP ('\0' terminated) */ char sdp[1024]; @@ -170,7 +172,7 @@ struct gsm_data_frame { unsigned char data[0]; }; -#define MNCC_SOCK_VERSION 7 +#define MNCC_SOCK_VERSION 8 struct gsm_mncc_hello { uint32_t msg_type; uint32_t version; diff --git a/src/sip.c b/src/sip.c index f0bc4c3..684ef74 100644 --- a/src/sip.c +++ b/src/sip.c @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -106,6 +107,34 @@ static void call_connect(struct sip_call_leg *leg, const sip_t *sip) nua_ack(leg->nua_handle, TAG_END()); } +int _osmo_dec_gcr(struct osmo_gcr_parsed *gcr, const uint8_t *elem, uint8_t len) +{ + uint16_t parsed = 1; /* account for length byte right away */ + + if (len < 13) + return -EBADMSG; + + gcr->net_len = elem[0]; + if (gcr->net_len < 3 || gcr->net_len > 5) + return -EINVAL; + + memcpy(gcr->net, elem + parsed, gcr->net_len); + /* +1 for ignored Node ID length field */ + parsed += (gcr->net_len + 1); + + gcr->node = osmo_load16be(elem + parsed); + parsed += 2; + + if (elem[parsed] != 5) /* see Table B 2.1.9.2 */ + return -ENOENT; + + parsed++; + + memcpy(gcr->cr, elem + parsed, 5); + + return parsed + 5; +} + static void new_call(struct sip_agent *agent, nua_handle_t *nh, const sip_t *sip) { @@ -113,9 +142,20 @@ static void new_call(struct sip_agent *agent, nua_handle_t *nh, struct sip_call_leg *leg; const char *from = NULL, *to = NULL; char ip_addr[INET6_ADDRSTRLEN]; + uint8_t gcr_back[28] = { 0 }; + LOGP(DSIP, LOGL_INFO, "Incoming call(%s) handle(%p)\n", sip->sip_call_id->i_id, nh); + sip_unknown_t *unknown_header = sip->sip_unknown; + while (unknown_header != NULL) { + if (!strcmp("X-Global-Call-Ref", unknown_header->un_name)) { + osmo_hexparse(unknown_header->un_value, gcr_back, sizeof(gcr_back)); + break; + } + unknown_header = unknown_header->un_next; + } + if (!sdp_screen_sdp(sip)) { LOGP(DSIP, LOGL_ERROR, "No supported codec.\n"); nua_respond(nh, SIP_406_NOT_ACCEPTABLE, TAG_END()); @@ -131,6 +171,8 @@ static void new_call(struct sip_agent *agent, nua_handle_t *nh, return; } + _osmo_dec_gcr(&call->gcr, gcr_back, sizeof(gcr_back)); + if (sip->sip_to) to = sip->sip_to->a_url->url_user; if (sip->sip_from) @@ -590,10 +632,38 @@ static void sip_retrieve_call(struct call_leg *_leg) leg->state = SIP_CC_CONNECTED; } +/*! Encode Global Call Reference. */ +uint8_t _osmo_enc_gcr(uint8_t *buf, const struct osmo_gcr_parsed *g) +{ + uint8_t tmp[2]; + + if (!g) + return 0; + + if (g->net_len < 3 || g->net_len > 5) + return 0; + + buf = lv_put(buf, g->net_len, g->net); + osmo_store16be(g->node, &tmp); + buf = lv_put(buf, 2, tmp); + buf = lv_put(buf, 5, g->cr); + + /* Length: LV(Net) + LV(Node) + LV(CRef) - see 3GPP TS ยง3.2.2.115 */ + return (g->net_len + 1) + (2 + 1) + (5 + 1); +} + static int send_invite(struct sip_agent *agent, struct sip_call_leg *leg, const char *calling_num, const char *called_num) { struct call_leg *other = leg->base.call->initial; + char gcr_hex[30]; + uint8_t data[15]; + + gcr_hex[0] = '\0'; + data[0] = '\0'; + uint8_t len = _osmo_enc_gcr(data, &leg->base.call->gcr); + if (len) + osmo_strlcpy(gcr_hex, osmo_hexdump_nospc(data, len*2+1), len*2+1); char *from = talloc_asprintf(leg, "sip:%s@%s:%d", calling_num, @@ -605,6 +675,8 @@ static int send_invite(struct sip_agent *agent, struct sip_call_leg *leg, agent->app->sip.remote_port); char *sdp = sdp_create_file(leg, other, sdp_sendrecv); + char *x_gcr = talloc_asprintf(leg, "X-Global-Call-Ref: %s", gcr_hex); + leg->state = SIP_CC_INITIAL; leg->dir = SIP_DIR_MT; nua_invite(leg->nua_handle, @@ -612,6 +684,7 @@ static int send_invite(struct sip_agent *agent, struct sip_call_leg *leg, SIPTAG_TO_STR(to), NUTAG_MEDIA_ENABLE(0), SIPTAG_CONTENT_TYPE_STR("application/sdp"), + SIPTAG_HEADER_STR(x_gcr), SIPTAG_PAYLOAD_STR(sdp), TAG_END());