From f3eb44f54bec0b6ebf78ccd7a182e1dbbd54f5b7 Mon Sep 17 00:00:00 2001 From: Vadim Yanitskiy Date: Wed, 27 Oct 2021 16:28:36 +0300 Subject: [PATCH] sip: use osmo_{enc,dec}_gcr() from libosmocore Change-Id: I46fa46fc79494d337f2f4657215b91c39207eea4 Depends: I06babb959fdc82f4e82d92260131d60c98b0abd2 Fixes: Id40d7e0fed9356f801b3627c118150055e7232b1 Related: OS#5164 --- src/call.h | 4 +++ src/mncc.c | 4 ++- src/sip.c | 89 +++++++++++++++++------------------------------------- 3 files changed, 34 insertions(+), 63 deletions(-) diff --git a/src/call.h b/src/call.h index 8360711..a835f71 100644 --- a/src/call.h +++ b/src/call.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -31,7 +32,10 @@ struct call { const char *source; const char *dest; + + /* Global Call Reference */ struct osmo_gcr_parsed gcr; + bool gcr_present; }; enum { diff --git a/src/mncc.c b/src/mncc.c index fc99400..c8bf4bd 100644 --- a/src/mncc.c +++ b/src/mncc.c @@ -544,6 +544,7 @@ static void check_setup(struct mncc_connection *conn, const char *buf, int rc) leg->state = MNCC_CC_INITIAL; leg->dir = MNCC_DIR_MO; leg->base.call->gcr = data->gcr; + leg->base.call->gcr_present = true; memcpy(&leg->called, called, sizeof(leg->called)); memcpy(&leg->calling, &data->calling, sizeof(leg->calling)); memcpy(&leg->imsi, data->imsi, sizeof(leg->imsi)); @@ -899,7 +900,8 @@ 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->gcr_present) + mncc.gcr = call->gcr; if (call->source && call->source[0] == '+') { mncc.calling.type = GSM48_TON_INTERNATIONAL; diff --git a/src/sip.c b/src/sip.c index 0e88716..9124752 100644 --- a/src/sip.c +++ b/src/sip.c @@ -107,34 +107,6 @@ 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) { @@ -142,15 +114,16 @@ 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 }; - + bool xgcr_hdr_present = false; + uint8_t xgcr_hdr[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)); + osmo_hexparse(unknown_header->un_value, xgcr_hdr, sizeof(xgcr_hdr)); + xgcr_hdr_present = true; break; } unknown_header = unknown_header->un_next; @@ -171,7 +144,16 @@ static void new_call(struct sip_agent *agent, nua_handle_t *nh, return; } - _osmo_dec_gcr(&call->gcr, gcr_back, sizeof(gcr_back)); + /* Decode Decode the Global Call Reference (if present) */ + if (xgcr_hdr_present) { + if (osmo_dec_gcr(&call->gcr, xgcr_hdr, sizeof(xgcr_hdr)) < 0) { + LOGP(DSIP, LOGL_ERROR, "Failed to parse X-Global-Call-Ref.\n"); + nua_respond(nh, SIP_406_NOT_ACCEPTABLE, TAG_END()); + nua_handle_destroy(nh); + return; + } + call->gcr_present = true; + } if (sip->sip_to) to = sip->sip_to->a_url->url_user; @@ -632,38 +614,10 @@ 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, @@ -675,7 +629,18 @@ 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); + /* Encode the Global Call Reference (if present) */ + char *x_gcr = NULL; + + if (leg->base.call->gcr_present) { + struct msgb *msg = msgb_alloc(16, "SIP GCR"); + + if (msg != NULL && osmo_enc_gcr(msg, &leg->base.call->gcr) > 0) + x_gcr = talloc_asprintf(leg, "X-Global-Call-Ref: %s", msgb_hexdump(msg)); + else + LOGP(DSIP, LOGL_ERROR, "Failed to encode GCR for leg(%p)\n", leg); + msgb_free(msg); + } leg->state = SIP_CC_INITIAL; leg->dir = SIP_DIR_MT; @@ -684,7 +649,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), + TAG_IF(x_gcr, SIPTAG_HEADER_STR(x_gcr)), SIPTAG_PAYLOAD_STR(sdp), TAG_END());