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:
58
libpri.h
58
libpri.h
@@ -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.
|
||||
*
|
||||
|
||||
183
pri_facility.c
183
pri_facility.c
@@ -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,
|
||||
|
||||
@@ -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
12
rose.c
@@ -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
3
rose.h
@@ -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 */
|
||||
|
||||
@@ -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* */
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user