From f90f421b165c7880cd88db8795f00073dd768f60 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sat, 13 Mar 2021 17:10:08 +0100 Subject: Add libs --- src/libosmocc/cause.c | 252 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 252 insertions(+) create mode 100644 src/libosmocc/cause.c (limited to 'src/libosmocc/cause.c') diff --git a/src/libosmocc/cause.c b/src/libosmocc/cause.c new file mode 100644 index 0000000..4a3a41e --- /dev/null +++ b/src/libosmocc/cause.c @@ -0,0 +1,252 @@ +/* OSMO-CC Processing: convert causes + * + * (C) 2019 by Andreas Eversberg + * All Rights Reserved + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include "message.h" +#include "cause.h" + +/* stolen from freeswitch */ +/* map sip responses to QSIG cause codes ala RFC4497 section 8.4.4 */ +static uint8_t status2isdn_cause(uint16_t status) +{ + switch (status) { + case 200: + return 16; //SWITCH_CAUSE_NORMAL_CLEARING; + case 401: + case 402: + case 403: + case 407: + case 603: + return 21; //SWITCH_CAUSE_CALL_REJECTED; + case 404: + return 1; //SWITCH_CAUSE_UNALLOCATED_NUMBER; + case 485: + case 604: + return 3; //SWITCH_CAUSE_NO_ROUTE_DESTINATION; + case 408: + case 504: + return 102; //SWITCH_CAUSE_RECOVERY_ON_TIMER_EXPIRE; + case 410: + return 22; //SWITCH_CAUSE_NUMBER_CHANGED; + case 413: + case 414: + case 416: + case 420: + case 421: + case 423: + case 505: + case 513: + return 127; //SWITCH_CAUSE_INTERWORKING; + case 480: + return 180; //SWITCH_CAUSE_NO_USER_RESPONSE; + case 400: + case 481: + case 500: + case 503: + return 41; //SWITCH_CAUSE_NORMAL_TEMPORARY_FAILURE; + case 486: + case 600: + return 17; //SWITCH_CAUSE_USER_BUSY; + case 484: + return 28; //SWITCH_CAUSE_INVALID_NUMBER_FORMAT; + case 488: + case 606: + return 88; //SWITCH_CAUSE_INCOMPATIBLE_DESTINATION; + case 502: + return 38; //SWITCH_CAUSE_NETWORK_OUT_OF_ORDER; + case 405: + return 63; //SWITCH_CAUSE_SERVICE_UNAVAILABLE; + case 406: + case 415: + case 501: + return 79; //SWITCH_CAUSE_SERVICE_NOT_IMPLEMENTED; + case 482: + case 483: + return 25; //SWITCH_CAUSE_EXCHANGE_ROUTING_ERROR; + case 487: + return 31; //??? SWITCH_CAUSE_ORIGINATOR_CANCEL; + default: + return 31; //SWITCH_CAUSE_NORMAL_UNSPECIFIED; + } +} + +static uint16_t isdn2status_cause(uint8_t cause, uint8_t location) +{ + switch (cause) { + case 1: + return 404; + case 2: + return 404; + case 3: + return 404; + case 17: + return 486; + case 18: + return 408; + case 19: + return 480; + case 20: + return 480; + case 21: + if (location == OSMO_CC_LOCATION_USER) + return 603; + return 403; + case 22: + //return 301; + return 410; + case 23: + return 410; + case 26: + return 404; + case 27: + return 502; + case 28: + return 484; + case 29: + return 501; + case 31: + return 480; + case 34: + return 503; + case 38: + return 503; + case 41: + return 503; + case 42: + return 503; + case 47: + return 503; + case 55: + return 403; + case 57: + return 403; + case 58: + return 503; + case 65: + return 488; + case 69: + return 501; + case 70: + return 488; + case 79: + return 501; + case 87: + return 403; + case 88: + return 503; + case 102: + return 504; + case 111: + return 500; + case 127: + return 500; + default: + return 468; + } +} + +static uint8_t socket2isdn_cause(uint8_t sock) +{ + switch (sock) { + case OSMO_CC_SOCKET_CAUSE_FAILED: + return 47; + case OSMO_CC_SOCKET_CAUSE_BROKEN_PIPE: + return 41; + case OSMO_CC_SOCKET_CAUSE_VERSION_MISMATCH: + return 38; + case OSMO_CC_SOCKET_CAUSE_TIMEOUT: + return 41; + default: + return 31; + } +} + +void osmo_cc_convert_cause(struct osmo_cc_ie_cause *cause) +{ + /* complete cause, from socket cause */ + if (cause->socket_cause && cause->isdn_cause == 0 && ntohs(cause->sip_cause_networkorder) == 0) + cause->isdn_cause = socket2isdn_cause(cause->socket_cause); + + /* convert ISDN cause to SIP cause */ + if (cause->isdn_cause && ntohs(cause->sip_cause_networkorder) == 0) { + cause->sip_cause_networkorder = htons(isdn2status_cause(cause->isdn_cause, cause->location)); + } + + /* convert SIP cause to ISDN cause */ + if (ntohs(cause->sip_cause_networkorder) && cause->isdn_cause == 0) { + cause->isdn_cause = status2isdn_cause(ntohs(cause->sip_cause_networkorder)); + } + + /* no cause at all: use Normal Call Clearing */ + if (cause->isdn_cause == 0 && ntohs(cause->sip_cause_networkorder) == 0) { + cause->isdn_cause = OSMO_CC_ISDN_CAUSE_NORM_CALL_CLEAR; + cause->sip_cause_networkorder = htons(486); + } +} + +void osmo_cc_convert_cause_msg(osmo_cc_msg_t *msg) +{ + void *ie; + uint8_t type; + uint16_t length; + void *value; + + /* search for (all) cause IE and convert the values, if needed */ + ie = msg->data; + while ((value = osmo_cc_msg_sep_ie(msg, &ie, &type, &length))) { + if (type == OSMO_CC_IE_CAUSE && length >= sizeof(struct osmo_cc_ie_cause)) { + osmo_cc_convert_cause(value); + } + } +} + +uint8_t osmo_cc_collect_cause(uint8_t old_cause, uint8_t new_cause) +{ + /* first cause */ + if (old_cause == 0) + return new_cause; + + /* first prio: return 17 */ + if (old_cause == OSMO_CC_ISDN_CAUSE_USER_BUSY + || new_cause == OSMO_CC_ISDN_CAUSE_USER_BUSY) + return OSMO_CC_ISDN_CAUSE_USER_BUSY; + + /* second prio: return 21 */ + if (old_cause == OSMO_CC_ISDN_CAUSE_CALL_REJECTED + || new_cause == OSMO_CC_ISDN_CAUSE_CALL_REJECTED) + return OSMO_CC_ISDN_CAUSE_CALL_REJECTED; + + /* third prio: return other than 88 and 18 (what ever was first) */ + if (old_cause != OSMO_CC_ISDN_CAUSE_INCOMPAT_DEST + && old_cause != OSMO_CC_ISDN_CAUSE_USER_NOTRESPOND) + return old_cause; + if (new_cause != OSMO_CC_ISDN_CAUSE_INCOMPAT_DEST + && new_cause != OSMO_CC_ISDN_CAUSE_USER_NOTRESPOND) + return new_cause; + + /* fourth prio: return 88 */ + if (old_cause == OSMO_CC_ISDN_CAUSE_INCOMPAT_DEST + || new_cause == OSMO_CC_ISDN_CAUSE_INCOMPAT_DEST) + return OSMO_CC_ISDN_CAUSE_INCOMPAT_DEST; + + /* fith prio: return 18 */ + return OSMO_CC_ISDN_CAUSE_USER_NOTRESPOND; +} + -- cgit v1.2.3