2020-08-01 07:36:09 +00:00
|
|
|
/* OSMO-CC Processing: convert causes
|
|
|
|
*
|
|
|
|
* (C) 2019 by Andreas Eversberg <jolly@eversberg.eu>
|
|
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
#include "message.h"
|
|
|
|
#include "cause.h"
|
|
|
|
|
2022-07-10 20:02:16 +00:00
|
|
|
/* stolen from freeswitch, did some corrections */
|
2020-08-01 07:36:09 +00:00
|
|
|
/* 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:
|
|
|
|
case 485:
|
|
|
|
case 604:
|
2022-07-10 20:02:16 +00:00
|
|
|
return 1; //SWITCH_CAUSE_UNALLOCATED_NUMBER;
|
2020-08-01 07:36:09 +00:00
|
|
|
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:
|
2022-07-10 20:02:16 +00:00
|
|
|
return 18; //SWITCH_CAUSE_NO_USER_RESPONSE;
|
2020-08-01 07:36:09 +00:00
|
|
|
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:
|
2022-07-10 20:02:16 +00:00
|
|
|
return 65; //SWITCH_CAUSE_BERER_CAPABILITY_NOT_IMPLEMENTED;
|
2020-08-01 07:36:09 +00:00
|
|
|
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:
|
2022-07-10 20:02:16 +00:00
|
|
|
return 31; //??? SWITCH_CAUSE_ORIGINATOR_CANCEL; (not specified)
|
2020-08-01 07:36:09 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|