Implement Cause Mapping

Adds cause field to the call_leg and sip_call_leg structs.

Translates the SIP status to MNCC cause and vice versa and
uses this information in the SIP/MNCC messages at call leg
release time.

Change-Id: Ic1b80dff7e583cd6fff2b662bc6cc4bad3f81cd4
This commit is contained in:
Keith Whyte 2018-08-31 15:44:30 +02:00
parent 503d8fdb64
commit 008915ee41
3 changed files with 25 additions and 2 deletions

View File

@ -43,6 +43,8 @@ struct call_leg {
struct call *call; struct call *call;
bool in_release; bool in_release;
/* Field to hold GSM 04.08 Cause Value. Section 10.5.4.11 Table 10.86 */
int cause;
/** /**
* RTP data * RTP data
@ -130,6 +132,8 @@ struct mncc_call_leg {
int rsp_wanted; int rsp_wanted;
struct mncc_connection *conn; struct mncc_connection *conn;
/* Field to hold GSM 04.08 Cause Value. Section 10.5.4.11 Table 10.86 */
int cause;
}; };
extern struct llist_head g_call_list; extern struct llist_head g_call_list;

View File

@ -105,12 +105,16 @@ static struct mncc_call_leg *mncc_find_leg(uint32_t callref)
static void mncc_fill_header(struct gsm_mncc *mncc, uint32_t msg_type, uint32_t callref) static void mncc_fill_header(struct gsm_mncc *mncc, uint32_t msg_type, uint32_t callref)
{ {
struct mncc_call_leg *mncc_leg;
mncc->msg_type = msg_type; mncc->msg_type = msg_type;
mncc->callref = callref; mncc->callref = callref;
if (MNCC_DISC_REQ == msg_type || MNCC_REL_REQ == msg_type) { if (MNCC_DISC_REQ == msg_type || MNCC_REL_REQ == msg_type) {
mncc_leg = mncc_find_leg(callref);
mncc->fields |= MNCC_F_CAUSE; mncc->fields |= MNCC_F_CAUSE;
mncc->cause.coding = GSM48_CAUSE_CODING_GSM; mncc->cause.coding = GSM48_CAUSE_CODING_GSM;
mncc->cause.location = GSM48_CAUSE_LOC_PUN_S_LU; mncc->cause.location = GSM48_CAUSE_LOC_PUN_S_LU;
mncc->cause.value = mncc_leg->base.cause;
} }
} }
@ -511,6 +515,7 @@ static void check_disc_ind(struct mncc_connection *conn, const char *buf, int rc
other_leg = call_leg_other(&leg->base); other_leg = call_leg_other(&leg->base);
if (other_leg) if (other_leg)
other_leg->cause = data->cause.value;
other_leg->release_call(other_leg); other_leg->release_call(other_leg);
} }
@ -529,6 +534,7 @@ static void check_rel_ind(struct mncc_connection *conn, const char *buf, int rc)
struct call_leg *other_leg; struct call_leg *other_leg;
other_leg = call_leg_other(&leg->base); other_leg = call_leg_other(&leg->base);
if (other_leg) if (other_leg)
other_leg->cause = data->cause.value;
other_leg->release_call(other_leg); other_leg->release_call(other_leg);
} }
LOGP(DMNCC, LOGL_DEBUG, "leg(%u) was released.\n", data->callref); LOGP(DMNCC, LOGL_DEBUG, "leg(%u) was released.\n", data->callref);
@ -573,8 +579,10 @@ static void check_rej_ind(struct mncc_connection *conn, const char *buf, int rc)
if (!leg) if (!leg)
return; return;
leg->cause = data->cause.value;
other_leg = call_leg_other(&leg->base); other_leg = call_leg_other(&leg->base);
if (other_leg) if (other_leg)
other_leg->cause = data->cause.value;
other_leg->release_call(other_leg); other_leg->release_call(other_leg);
LOGP(DMNCC, LOGL_DEBUG, "leg(%u) was rejected.\n", data->callref); LOGP(DMNCC, LOGL_DEBUG, "leg(%u) was rejected.\n", data->callref);
mncc_leg_release(leg); mncc_leg_release(leg);

View File

@ -244,8 +244,10 @@ void nua_callback(nua_event_t event, int status, char const *phrase, nua_t *nua,
nua_handle_destroy(leg->nua_handle); nua_handle_destroy(leg->nua_handle);
call_leg_release(&leg->base); call_leg_release(&leg->base);
if (other) if (other) {
other->cause = status2cause(status);
other->release_call(other); other->release_call(other);
}
} }
} else if (event == nua_r_bye || event == nua_r_cancel) { } else if (event == nua_r_bye || event == nua_r_cancel) {
/* our bye or hang up is answered */ /* our bye or hang up is answered */
@ -309,6 +311,10 @@ static void cause2status(int cause, int *sip_status, const char **sip_phrase, co
static void sip_release_call(struct call_leg *_leg) static void sip_release_call(struct call_leg *_leg)
{ {
struct sip_call_leg *leg; struct sip_call_leg *leg;
char reason[64];
int sip_cause;
const char *sip_phrase;
const char *reason_text;
OSMO_ASSERT(_leg->type == CALL_TYPE_SIP); OSMO_ASSERT(_leg->type == CALL_TYPE_SIP);
leg = (struct sip_call_leg *) _leg; leg = (struct sip_call_leg *) _leg;
@ -319,6 +325,10 @@ static void sip_release_call(struct call_leg *_leg)
* and for a connected one bye. I don't see how sofia-sip is going * and for a connected one bye. I don't see how sofia-sip is going
* to help us here. * to help us here.
*/ */
cause2status(_leg->cause, &sip_cause, &sip_phrase, &reason_text);
snprintf(reason, sizeof reason, "Q.850;cause=%u;text=\"%s\"", _leg->cause, reason_text);
switch (leg->state) { switch (leg->state) {
case SIP_CC_INITIAL: case SIP_CC_INITIAL:
LOGP(DSIP, LOGL_NOTICE, "Canceling leg(%p) in int state\n", leg); LOGP(DSIP, LOGL_NOTICE, "Canceling leg(%p) in int state\n", leg);
@ -330,7 +340,8 @@ static void sip_release_call(struct call_leg *_leg)
if (leg->dir == SIP_DIR_MT) if (leg->dir == SIP_DIR_MT)
nua_cancel(leg->nua_handle, TAG_END()); nua_cancel(leg->nua_handle, TAG_END());
else { else {
nua_respond(leg->nua_handle, SIP_486_BUSY_HERE, nua_respond(leg->nua_handle, sip_cause, sip_phrase,
SIPTAG_REASON_STR(reason),
TAG_END()); TAG_END());
nua_handle_destroy(leg->nua_handle); nua_handle_destroy(leg->nua_handle);
call_leg_release(&leg->base); call_leg_release(&leg->base);