ETSI Malicious Call ID support.

Add the ability to report malicious callers.

Relevant specification: EN 300 180

Review:	https://reviewboard.asterisk.org/r/575/


git-svn-id: https://origsvn.digium.com/svn/libpri/branches/1.4@1757 2fbb986a-6c06-0410-b554-c9c1f0a7f128
This commit is contained in:
Richard Mudgett
2010-05-28 20:26:23 +00:00
parent e4b8bed7e9
commit 0b28bf0aab
6 changed files with 264 additions and 0 deletions

View File

@@ -545,6 +545,8 @@ struct pri_rerouting_data {
#define PRI_SUBCMD_AOC_E 20 /*!< Advice Of Charge End information */
//#define PRI_SUBCMD_AOC_CHARGING_REQ 21 /*!< Advice Of Charge Request information */
//#define PRI_SUBCMD_AOC_CHARGING_REQ_RSP 22 /*!< Advice Of Charge Request Response information */
#define PRI_SUBCMD_MCID_REQ 23 /*!< Malicious Call ID Request */
#define PRI_SUBCMD_MCID_RSP 24 /*!< Malicious Call ID Request response */
#if defined(STATUS_REQUEST_PLACE_HOLDER)
struct pri_subcmd_status_request {
@@ -875,6 +877,38 @@ struct pri_subcmd_aoc_e {
struct pri_aoc_e_charging_association associated;
};
struct pri_subcmd_mcid_req {
/*!
* \brief Information libpri knows about the malicious caller.
* \note For the convenience of the upper layer. This information
* may be incomplete if the upper layer redacted some caller
* information because it was restricted.
*/
struct pri_party_id originator;
/*! \brief Information libpri knows about the callee. */
struct pri_party_id answerer;
};
struct pri_subcmd_mcid_rsp {
/*!
* \brief MCID request response status.
* \details
* success(0),
* timeout(1),
* error(2),
* reject(3)
*/
int status;
/*!
* \brief Failure code that can be converted to a string to further
* explain the non-timeout failure.
* \note Valid when status is error or reject.
* \note Use pri_facility_error2str() to convert the error_code.
* \note Use pri_facility_reject2str() to convert the reject_code.
*/
int fail_code;
};
struct pri_subcommand {
/*! PRI_SUBCMD_xxx defined values */
int cmd;
@@ -903,6 +937,8 @@ struct pri_subcommand {
struct pri_subcmd_aoc_s aoc_s;
struct pri_subcmd_aoc_d aoc_d;
struct pri_subcmd_aoc_e aoc_e;
struct pri_subcmd_mcid_req mcid_req;
struct pri_subcmd_mcid_rsp mcid_rsp;
} u;
};
@@ -1734,6 +1770,28 @@ int pri_status_req(struct pri *ctrl, int request_id, const struct pri_sr *req);
void pri_status_req_rsp(struct pri *ctrl, int invoke_id, int status);
#endif /* defined(STATUS_REQUEST_PLACE_HOLDER) */
/*!
* \brief Set the Malicious Call ID feature enable flag.
*
* \param ctrl D channel controller.
* \param enable TRUE to enable MCID feature.
*
* \return Nothing
*/
void pri_mcid_enable(struct pri *ctrl, int enable);
/*!
* \brief Send the MCID request message.
*
* \param ctrl D channel controller.
* \param call Q.931 call leg
*
* \retval 0 on success. You should wait for a PRI_SUBCMD_MCID_RSP
* to continue clearing the call if it was in progress.
* \retval -1 on error.
*/
int pri_mcid_req_send(struct pri *ctrl, q931_call *call);
/*!
* \brief Set the call completion feature enable flag.
*

View File

@@ -3541,6 +3541,151 @@ int pri_transfer_rsp(struct pri *ctrl, q931_call *call, int invoke_id, int is_su
}
}
/*!
* \internal
* \brief MCIDRequest response callback function.
*
* \param reason Reason callback is called.
* \param ctrl D channel controller.
* \param call Q.931 call leg.
* \param apdu APDU queued entry. Do not change!
* \param msg APDU response message data. (NULL if was not the reason called.)
*
* \return TRUE if no more responses are expected.
*/
static int mcid_req_response(enum APDU_CALLBACK_REASON reason, struct pri *ctrl, struct q931_call *call, struct apdu_event *apdu, const struct apdu_msg_data *msg)
{
struct pri_subcommand *subcmd;
int status;
int fail_code;
switch (reason) {
case APDU_CALLBACK_REASON_TIMEOUT:
status = 1;/* timeout */
fail_code = 0;
break;
case APDU_CALLBACK_REASON_MSG_RESULT:
status = 0;/* success */
fail_code = 0;
break;
case APDU_CALLBACK_REASON_MSG_ERROR:
status = 2;/* error */
fail_code = msg->response.error->code;
break;
case APDU_CALLBACK_REASON_MSG_REJECT:
status = 3;/* reject */
fail_code = 0;
fail_code = msg->response.reject->code;
break;
default:
return 1;
}
subcmd = q931_alloc_subcommand(ctrl);
if (subcmd) {
/* Indicate that our MCID request has completed. */
subcmd->cmd = PRI_SUBCMD_MCID_RSP;
subcmd->u.mcid_rsp.status = status;
subcmd->u.mcid_rsp.fail_code = fail_code;
} else {
/* Oh, well. */
}
return 1;
}
/*!
* \internal
* \brief Encode a MCIDRequest message.
*
* \param ctrl D channel controller for diagnostic messages or global options.
* \param pos Starting position to encode the facility ie contents.
* \param end End of facility ie contents encoding data buffer.
* \param call Call leg from which to encode message.
*
* \retval Start of the next ASN.1 component to encode on success.
* \retval NULL on error.
*/
static unsigned char *enc_etsi_mcid_req(struct pri *ctrl, unsigned char *pos,
unsigned char *end, q931_call *call)
{
struct rose_msg_invoke msg;
pos = facility_encode_header(ctrl, pos, end, NULL);
if (!pos) {
return NULL;
}
memset(&msg, 0, sizeof(msg));
msg.invoke_id = get_invokeid(ctrl);
msg.operation = ROSE_ETSI_MCIDRequest;
pos = rose_encode_invoke(ctrl, pos, end, &msg);
return pos;
}
/*!
* \internal
* \brief Encode and queue a MCID request message.
*
* \param ctrl D channel controller for diagnostic messages or global options.
* \param call Call leg from which to encode message.
*
* \retval 0 on success.
* \retval -1 on error.
*/
static int rose_mcid_req_encode(struct pri *ctrl, q931_call *call)
{
unsigned char buffer[256];
unsigned char *end;
struct apdu_callback_data response;
switch (ctrl->switchtype) {
case PRI_SWITCH_EUROISDN_E1:
case PRI_SWITCH_EUROISDN_T1:
end = enc_etsi_mcid_req(ctrl, buffer, buffer + sizeof(buffer), call);
break;
default:
return -1;
}
if (!end) {
return -1;
}
memset(&response, 0, sizeof(response));
response.invoke_id = ctrl->last_invoke;
response.timeout_time = ctrl->timers[PRI_TIMER_T_RESPONSE];
response.callback = mcid_req_response;
return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, &response);
}
int pri_mcid_req_send(struct pri *ctrl, q931_call *call)
{
if (!ctrl || !call) {
return -1;
}
if (call->cc.originated) {
/* We can only send MCID if we answered the call. */
return -1;
}
if (rose_mcid_req_encode(ctrl, call) || q931_facility(ctrl, call)) {
pri_message(ctrl,
"Could not schedule facility message for MCID request message.\n");
return -1;
}
return 0;
}
void pri_mcid_enable(struct pri *ctrl, int enable)
{
if (ctrl) {
ctrl = PRI_MASTER(ctrl);
ctrl->mcid_support = enable ? 1 : 0;
}
}
/*!
* \brief Handle the ROSE reject message.
*
@@ -4375,6 +4520,44 @@ void rose_handle_invoke(struct pri *ctrl, q931_call *call, int msgtype, q931_ie
call->cc.record = cc_record;
pri_cc_event(ctrl, call, cc_record, CC_EVENT_AVAILABLE);
break;
case ROSE_ETSI_MCIDRequest:
if (q931_is_dummy_call(call)) {
/* Don't even dignify this with a response. */
break;
}
if (!PRI_MASTER(ctrl)->mcid_support) {
send_facility_error(ctrl, call, invoke->invoke_id,
ROSE_ERROR_Gen_NotSubscribed);
break;
}
if (!call->cc.originated) {
send_facility_error(ctrl, call, invoke->invoke_id,
ROSE_ERROR_Gen_NotIncomingCall);
break;
}
switch (call->ourcallstate) {
case Q931_CALL_STATE_ACTIVE:
case Q931_CALL_STATE_DISCONNECT_INDICATION:
case Q931_CALL_STATE_DISCONNECT_REQUEST:/* XXX We are really in the wrong state for this mode. */
subcmd = q931_alloc_subcommand(ctrl);
if (!subcmd) {
send_facility_error(ctrl, call, invoke->invoke_id,
ROSE_ERROR_Gen_NotAvailable);
break;
}
subcmd->cmd = PRI_SUBCMD_MCID_REQ;
q931_party_id_copy_to_pri(&subcmd->u.mcid_req.originator, &call->local_id);
q931_party_id_copy_to_pri(&subcmd->u.mcid_req.answerer, &call->remote_id);
send_facility_result_ok(ctrl, call, invoke->invoke_id);
break;
default:
send_facility_error(ctrl, call, invoke->invoke_id,
ROSE_ERROR_Gen_InvalidCallState);
break;
}
break;
case ROSE_QSIG_CallingName:
/* CallingName is put in remote_id.name */
rose_copy_name_to_q931(ctrl, &call->remote_id.name,

View File

@@ -109,6 +109,7 @@ struct pri {
unsigned int transfer_support:1;/* TRUE if the upper layer supports ECT */
unsigned int aoc_support:1;/* TRUE if can send AOC events to the upper layer. */
unsigned int manual_connect_ack:1;/* TRUE if the CONNECT_ACKNOWLEDGE is sent with API call */
unsigned int mcid_support:1;/* TRUE if the upper layer supports MCID */
/* MDL variables */
int mdl_error;

12
rose.c
View File

@@ -531,6 +531,16 @@ static const struct rose_convert_msg rose_etsi_msgs[] = {
rose_enc_etsi_CCNR_T_Request_ARG, rose_enc_etsi_CCNR_T_Request_RES,
rose_dec_etsi_CCNR_T_Request_ARG, rose_dec_etsi_CCNR_T_Request_RES
},
/*
* localValue's from MCID-Operations
* {ccitt identified-organization etsi(0) 130 operations-and-errors(1)}
*/
{
ROSE_ETSI_MCIDRequest, NULL, 3,
NULL, NULL,
NULL, NULL
},
/* *INDENT-ON* */
};
@@ -1391,6 +1401,8 @@ const char *rose_operation2str(enum rose_operation operation)
{ ROSE_ETSI_CCNR_T_Request, "ROSE_ETSI_CCNR_T_Request" },
{ ROSE_ETSI_MCIDRequest, "ROSE_ETSI_MCIDRequest" },
{ ROSE_QSIG_CallingName, "ROSE_QSIG_CallingName" },
{ ROSE_QSIG_CalledName, "ROSE_QSIG_CalledName" },
{ ROSE_QSIG_ConnectedName, "ROSE_QSIG_ConnectedName" },

3
rose.h
View File

@@ -134,6 +134,9 @@ enum rose_operation {
/* ETSI CCNR-private-networks-Operations-and-Errors */
ROSE_ETSI_CCNR_T_Request, /*!< Invoke/Result */
/* ETSI MCID-Operations */
ROSE_ETSI_MCIDRequest, /*!< Invoke/Result */
/* Q.SIG Name-Operations */
ROSE_QSIG_CallingName, /*!< Invoke only */
ROSE_QSIG_CalledName, /*!< Invoke only */

View File

@@ -1389,6 +1389,13 @@ static const struct rose_message rose_etsi_msgs[] = {
.component.result.invoke_id = 53,
.component.result.args.etsi.CCNR_T_Request.retention_supported = 1,
},
/* MCID */
{
.type = ROSE_COMP_TYPE_INVOKE,
.component.invoke.operation = ROSE_ETSI_MCIDRequest,
.component.invoke.invoke_id = 54,
},
/* *INDENT-ON* */
};