support for sending ETSI advice of charge

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


git-svn-id: https://origsvn.digium.com/svn/libpri/branches/1.4@1776 2fbb986a-6c06-0410-b554-c9c1f0a7f128
This commit is contained in:
David Vossel 2010-05-28 22:34:24 +00:00
parent 8c5eeeae79
commit 660609c45b
6 changed files with 1379 additions and 91 deletions

137
libpri.h
View File

@ -543,8 +543,8 @@ struct pri_rerouting_data {
#define PRI_SUBCMD_AOC_S 18 /*!< Advice Of Charge Start information (Rate list) */ #define PRI_SUBCMD_AOC_S 18 /*!< Advice Of Charge Start information (Rate list) */
#define PRI_SUBCMD_AOC_D 19 /*!< Advice Of Charge During information */ #define PRI_SUBCMD_AOC_D 19 /*!< Advice Of Charge During information */
#define PRI_SUBCMD_AOC_E 20 /*!< Advice Of Charge End information */ #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 21 /*!< Advice Of Charge Request information */
//#define PRI_SUBCMD_AOC_CHARGING_REQ_RSP 22 /*!< Advice Of Charge Request Response 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_REQ 23 /*!< Malicious Call ID Request */
#define PRI_SUBCMD_MCID_RSP 24 /*!< Malicious Call ID Request response */ #define PRI_SUBCMD_MCID_RSP 24 /*!< Malicious Call ID Request response */
@ -877,6 +877,64 @@ struct pri_subcmd_aoc_e {
struct pri_aoc_e_charging_association associated; struct pri_aoc_e_charging_association associated;
}; };
enum PRI_AOC_REQ_RSP {
/* Error Results */
PRI_AOC_REQ_RSP_ERROR_NOT_IMPLEMENTED,
PRI_AOC_REQ_RSP_ERROR_NOT_AVAILABLE,
PRI_AOC_REQ_RSP_ERROR_TIMEOUT,
PRI_AOC_REQ_RSP_ERROR_REJECT,
/* generic error result all other errors are lumped into */
PRI_AOC_REQ_RSP_ERROR,
/* AOC Results */
PRI_AOC_REQ_RSP_CHARGING_INFO_FOLLOWS,
PRI_AOC_REQ_RSP_CURRENCY_INFO_LIST,
PRI_AOC_REQ_RSP_SPECIAL_ARR,
};
enum PRI_AOC_REQUEST {
PRI_AOC_REQUEST_S = (1 << 0),
PRI_AOC_REQUEST_D = (1 << 1),
PRI_AOC_REQUEST_E = (1 << 2),
};
struct pri_subcmd_aoc_request_response {
/*!
* \brief aoc_s data from response
*/
struct pri_subcmd_aoc_s aoc_s;
/*!
* \brief if the aoc_s msg is present, this will be set
*/
int valid_aoc_s;
/*!
* \brief What type of aoc was requested.
* \see enum PRI_AOC_REQUEST
*/
int charging_request;
/*!
* \brief response to the charging_request
* \see enum PRI_AOC_REQ_RSP
*/
int charging_response;
};
struct pri_subcmd_aoc_request {
/*!
* \brief What types of aoc are being requested.
* \see enum PRI_AOC_REQUEST
*/
int charging_request;
/*!
* \brief Value given by the initiating request.
*/
int invoke_id;
};
struct pri_subcmd_mcid_req { struct pri_subcmd_mcid_req {
/*! /*!
* \brief Information libpri knows about the malicious caller. * \brief Information libpri knows about the malicious caller.
@ -934,6 +992,8 @@ struct pri_subcommand {
struct pri_subcmd_cc_id cc_call; struct pri_subcmd_cc_id cc_call;
struct pri_subcmd_cc_cancel cc_cancel; struct pri_subcmd_cc_cancel cc_cancel;
struct pri_subcmd_transfer transfer; struct pri_subcmd_transfer transfer;
struct pri_subcmd_aoc_request aoc_request;
struct pri_subcmd_aoc_request_response aoc_request_response;
struct pri_subcmd_aoc_s aoc_s; struct pri_subcmd_aoc_s aoc_s;
struct pri_subcmd_aoc_d aoc_d; struct pri_subcmd_aoc_d aoc_d;
struct pri_subcmd_aoc_e aoc_e; struct pri_subcmd_aoc_e aoc_e;
@ -1587,6 +1647,79 @@ void pri_set_inbanddisconnect(struct pri *pri, unsigned int enable);
(and maybe some timers) */ (and maybe some timers) */
void pri_enslave(struct pri *master, struct pri *slave); void pri_enslave(struct pri *master, struct pri *slave);
/*!
* \brief Request AOC on call setup
*
* \param call setup struct to set charging request info on
* \param charging request to set on setup struct
*
* \retval 0 on success
* \retval -1 on failure
*/
int pri_sr_set_aoc_charging_request(struct pri_sr *sr, int charging_request);
/*!
* \brief Send AOC Request Response to a request for AOC-S
*
* \param ctrl D channel controller.
* \param call Q.931 call leg.
* \param invoke_id for response message
* \param aoc_s message for response
*
* \retval 0 on success
* \retval -1 on failure
*/
int pri_aoc_s_request_response_send(struct pri *ctrl, q931_call *call, int invoke_id, const struct pri_subcmd_aoc_s *aoc_s);
/*!
* \brief Send AOC Request Response to a request for AOC-D or AOC-E
*
* \param ctrl D channel controller.
* \param call Q.931 call leg.
* \param response in form of enum PRI_AOC_REQ_RSP
* \param invoke_id for response message
*
* \retval 0 on success
* \retval -1 on failure
*/
int pri_aoc_de_request_response_send(struct pri *ctrl, q931_call *call, int response, int invoke_id);
/*!
* \brief Send AOC-S message.
*
* \param ctrl D channel controller.
* \param call Q.931 call leg.
* \param aoc_s message to send
*
* \retval 0 on success
* \retval -1 on failure
*/
int pri_aoc_s_send(struct pri *ctrl, q931_call *c, const struct pri_subcmd_aoc_s *aoc_s);
/*!
* \brief Send AOC-D message.
*
* \param ctrl D channel controller.
* \param call Q.931 call leg.
* \param aoc_d message to send
*
* \retval 0 on success
* \retval -1 on failure
*/
int pri_aoc_d_send(struct pri *ctrl, q931_call *c, const struct pri_subcmd_aoc_d *aoc_d);
/*!
* \brief Send AOC-E message.
*
* \param ctrl D channel controller.
* \param call Q.931 call leg.
* \param aoc_e message to send
*
* \retval 0 on success
* \retval -1 on failure
*/
int pri_aoc_e_send(struct pri *ctrl, q931_call *c, const struct pri_subcmd_aoc_e *aoc_e);
#define PRI_GR303_SUPPORT #define PRI_GR303_SUPPORT
#define PRI_ENSLAVE_SUPPORT #define PRI_ENSLAVE_SUPPORT
#define PRI_SETUP_CALL #define PRI_SETUP_CALL

1245
pri_aoc.c

File diff suppressed because it is too large Load Diff

View File

@ -3296,6 +3296,9 @@ int pri_call_add_standard_apdus(struct pri *ctrl, q931_call *call)
switch (ctrl->switchtype) { switch (ctrl->switchtype) {
case PRI_SWITCH_EUROISDN_E1: case PRI_SWITCH_EUROISDN_E1:
case PRI_SWITCH_EUROISDN_T1: case PRI_SWITCH_EUROISDN_T1:
if (call->aoc_charging_request) {
aoc_charging_request_send(ctrl, call, call->aoc_charging_request);
}
if (PTMP_MODE(ctrl)) { if (PTMP_MODE(ctrl)) {
/* PTMP mode */ /* PTMP mode */
break; break;
@ -4336,7 +4339,7 @@ void rose_handle_invoke(struct pri *ctrl, q931_call *call, int msgtype, q931_ie
} }
break; break;
case ROSE_ETSI_ChargingRequest: case ROSE_ETSI_ChargingRequest:
/* Ignore messsage */ aoc_etsi_aoc_request(ctrl, call, invoke);
break; break;
case ROSE_ETSI_AOCSCurrency: case ROSE_ETSI_AOCSCurrency:
aoc_etsi_aoc_s_currency(ctrl, invoke); aoc_etsi_aoc_s_currency(ctrl, invoke);

View File

@ -128,15 +128,21 @@ union apdu_callback_param {
/* So calls to pri_call_apdu_find() will not find an aliased event. */ /* So calls to pri_call_apdu_find() will not find an aliased event. */
#define APDU_INVALID_INVOKE_ID 0x10000 #define APDU_INVALID_INVOKE_ID 0x10000
#define APDU_TIMEOUT_MSGS_ONLY -1
struct apdu_callback_data { struct apdu_callback_data {
/*! APDU invoke id to match with any response messages. (Result/Error/Reject) */ /*! APDU invoke id to match with any response messages. (Result/Error/Reject) */
int invoke_id; int invoke_id;
/*! /*!
* \brief Time to wait for responses to APDU in ms. * \brief Time to wait for responses to APDU in ms.
* \note Set to 0 if send the message only. * \note Set to 0 if send the message only.
* \note Set to less than 0 for PRI_TIMER_T_RESPONSE time. * \note Set to APDU_TIMEOUT_MSGS_ONLY to "timeout" with the message_type list only.
*/ */
int timeout_time; int timeout_time;
/*! Number of Q.931 messages the APDU can "timeout" on. */
unsigned num_messages;
/*! Q.931 message list to "timeout" on. */
int message_type[5];
/*! /*!
* \brief APDU callback function. * \brief APDU callback function.
* *
@ -245,6 +251,8 @@ void pri_cc_qsig_request(struct pri *ctrl, q931_call *call, int msgtype, const s
void pri_cc_qsig_cancel(struct pri *ctrl, q931_call *call, int msgtype, const struct rose_msg_invoke *invoke); void pri_cc_qsig_cancel(struct pri *ctrl, q931_call *call, int msgtype, const struct rose_msg_invoke *invoke);
void pri_cc_qsig_exec_possible(struct pri *ctrl, q931_call *call, int msgtype, const struct rose_msg_invoke *invoke); void pri_cc_qsig_exec_possible(struct pri *ctrl, q931_call *call, int msgtype, const struct rose_msg_invoke *invoke);
int aoc_charging_request_send(struct pri *ctrl, q931_call *c, enum PRI_AOC_REQUEST aoc_request_flag);
void aoc_etsi_aoc_request(struct pri *ctrl, q931_call *call, const struct rose_msg_invoke *invoke);
void aoc_etsi_aoc_s_currency(struct pri *ctrl, const struct rose_msg_invoke *invoke); void aoc_etsi_aoc_s_currency(struct pri *ctrl, const struct rose_msg_invoke *invoke);
void aoc_etsi_aoc_s_special_arrangement(struct pri *ctrl, const struct rose_msg_invoke *invoke); void aoc_etsi_aoc_s_special_arrangement(struct pri *ctrl, const struct rose_msg_invoke *invoke);
void aoc_etsi_aoc_d_currency(struct pri *ctrl, const struct rose_msg_invoke *invoke); void aoc_etsi_aoc_d_currency(struct pri *ctrl, const struct rose_msg_invoke *invoke);

View File

@ -366,6 +366,7 @@ struct pri_sr {
const char *keypad_digits; const char *keypad_digits;
int transferable; int transferable;
int reversecharge; int reversecharge;
int aoc_charging_request;
}; };
/* Internal switch types */ /* Internal switch types */
@ -632,6 +633,9 @@ struct q931_call {
/*! TRUE if outgoing call was already redirected. */ /*! TRUE if outgoing call was already redirected. */
unsigned char initially_redirected; unsigned char initially_redirected;
} cc; } cc;
/* AOC charge requesting on Setup */
int aoc_charging_request;
}; };
enum CC_STATES { enum CC_STATES {

69
q931.c
View File

@ -2437,17 +2437,18 @@ static int transmit_facility(int full_ie, struct pri *ctrl, q931_call *call, int
cur->sent = 1; cur->sent = 1;
if (cur->response.callback && cur->response.timeout_time) { if (cur->response.callback && cur->response.timeout_time) {
int duration; int failed;
if (0 < cur->response.timeout_time) { if (0 < cur->response.timeout_time) {
/* Sender specified timeout duration. */ /* Sender specified a timeout duration. */
duration = cur->response.timeout_time; cur->timer = pri_schedule_event(ctrl, cur->response.timeout_time,
q931_apdu_timeout, cur);
failed = !cur->timer;
} else { } else {
/* Sender wants to use the typical timeout duration. */ /* Sender wants to "timeout" only when specified messages are received. */
duration = ctrl->timers[PRI_TIMER_T_RESPONSE]; failed = !cur->response.num_messages;
} }
cur->timer = pri_schedule_event(ctrl, duration, q931_apdu_timeout, cur); if (failed) {
if (!cur->timer) {
/* Remove APDU from list. */ /* Remove APDU from list. */
*prev = cur->next; *prev = cur->next;
@ -2456,7 +2457,7 @@ static int transmit_facility(int full_ie, struct pri *ctrl, q931_call *call, int
free(cur); free(cur);
} }
} else if (!cur->timer) { } else {
/* Remove APDU from list. */ /* Remove APDU from list. */
*prev = cur->next; *prev = cur->next;
free(cur); free(cur);
@ -2576,6 +2577,52 @@ static void q931_handle_facilities(struct pri *ctrl, q931_call *call, int msgtyp
} }
} }
/*!
* \internal
* \brief Check if any APDU responses "timeout" with the current Q.931 message.
*
* \param ctrl D channel controller.
* \param call Q.931 call leg.
* \param msgtype Q.931 message type received.
*
* \return Nothing
*/
static void q931_apdu_msg_expire(struct pri *ctrl, struct q931_call *call, int msgtype)
{
struct apdu_event **prev;
struct apdu_event **prev_next;
struct apdu_event *cur;
unsigned idx;
for (prev = &call->apdus; *prev; prev = prev_next) {
cur = *prev;
prev_next = &cur->next;
if (cur->sent) {
for (idx = 0; idx < cur->response.num_messages; ++idx) {
if (cur->response.message_type[idx] == msgtype) {
/*
* APDU response message "timeout".
*
* Extract the APDU from the list so it cannot be
* deleted from under us by the callback.
*/
prev_next = prev;
*prev = cur->next;
/* Stop any response timeout. */
pri_schedule_del(ctrl, cur->timer);
cur->timer = 0;
cur->response.callback(APDU_CALLBACK_REASON_TIMEOUT, ctrl, call, cur, NULL);
free(cur);
break;
}
}
}
}
}
static int transmit_progress_indicator(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) static int transmit_progress_indicator(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
{ {
int code, mask; int code, mask;
@ -5093,6 +5140,8 @@ int q931_setup(struct pri *ctrl, q931_call *c, struct pri_sr *req)
c->reversecharge = req->reversecharge; c->reversecharge = req->reversecharge;
c->aoc_charging_request = req->aoc_charging_request;
pri_call_add_standard_apdus(ctrl, c); pri_call_add_standard_apdus(ctrl, c);
/* Save the initial cc-parties. */ /* Save the initial cc-parties. */
@ -6423,6 +6472,7 @@ int q931_receive(struct pri *ctrl, int tei, q931_h *h, int len)
/* Now handle the facility ie's after all the other ie's were processed. */ /* Now handle the facility ie's after all the other ie's were processed. */
q931_handle_facilities(ctrl, c, mh->msg); q931_handle_facilities(ctrl, c, mh->msg);
} }
q931_apdu_msg_expire(ctrl, c, mh->msg);
/* Post handling */ /* Post handling */
switch (h->pd) { switch (h->pd) {
@ -6436,6 +6486,9 @@ int q931_receive(struct pri *ctrl, int tei, q931_h *h, int len)
if (c->master_call->outboundbroadcast) { if (c->master_call->outboundbroadcast) {
nt_ptmp_handle_q931_message(ctrl, mh, c, &allow_event, &allow_posthandle); nt_ptmp_handle_q931_message(ctrl, mh, c, &allow_event, &allow_posthandle);
if (allow_event) {
q931_apdu_msg_expire(ctrl, c->master_call, mh->msg);
}
} }
if (allow_posthandle) { if (allow_posthandle) {