[asterisk-commits] rmudgett: branch rmudgett/misdn_facility r154780 - in /team/rmudgett/misdn_fa...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Wed Nov 5 11:42:23 CST 2008
Author: rmudgett
Date: Wed Nov 5 11:42:22 2008
New Revision: 154780
URL: http://svn.digium.com/view/asterisk?view=rev&rev=154780
Log:
Merged revision 153295 from
https://origsvn.digium.com/svn/asterisk/be/branches/C.2-datus
..........
r153295 | rmudgett | 2008-10-31 20:13:02 -0500 (Fri, 31 Oct 2008) | 1 line
Initial mISDN CCBS/CCNR implementation. Needs testing
Modified:
team/rmudgett/misdn_facility/channels/chan_misdn.c
team/rmudgett/misdn_facility/channels/misdn/isdn_lib.c
team/rmudgett/misdn_facility/channels/misdn/isdn_lib.h
team/rmudgett/misdn_facility/channels/misdn/isdn_msg_parser.c
Modified: team/rmudgett/misdn_facility/channels/chan_misdn.c
URL: http://svn.digium.com/view/asterisk/team/rmudgett/misdn_facility/channels/chan_misdn.c?view=diff&rev=154780&r1=154779&r2=154780
==============================================================================
--- team/rmudgett/misdn_facility/channels/chan_misdn.c (original)
+++ team/rmudgett/misdn_facility/channels/chan_misdn.c Wed Nov 5 11:42:22 2008
@@ -28,6 +28,9 @@
*
* \ingroup channel_drivers
*/
+
+/* Define to enable cli commands to generate canned CCBS messages. */
+// #define CCBS_TEST_MESSAGES 1
/*** MODULEINFO
<depend>isdnnet</depend>
@@ -48,6 +51,7 @@
#include <sys/file.h>
#include <semaphore.h>
#include <ctype.h>
+#include <time.h>
#include "asterisk/channel.h"
#include "asterisk/config.h"
@@ -111,6 +115,137 @@
static char *complete_show_config(struct ast_cli_args *a);
/* BEGIN: chan_misdn.h */
+
+#if defined(AST_MISDN_ENHANCEMENTS)
+#define MISDN_PEER_LINKS_MAX 64
+#define MISDN_PEER_AGE_MAX 20 /* seconds */
+
+/*
+ * This timeout duration is to clean up any call completion records that
+ * are forgotten about by the switch.
+ */
+#define MISDN_CC_RECORD_AGE_MAX (6UL * 60 * 60) /* seconds */
+
+#define MISDN_CC_REQUEST_WAIT_MAX 5 /* seconds */
+
+struct misdn_peer_link {
+ /*! \brief Asterisk channel that is a potential peer (NULL if not allocated) */
+ struct ast_channel *peer;
+
+ /*! \brief Time the record was allocated. */
+ time_t time_created;
+};
+
+/*! \brief Peer link guardian */
+ast_mutex_t misdn_peer_link_lock;
+/*! \brief mISDN peer link database */
+static struct misdn_peer_link misdn_peers[MISDN_PEER_LINKS_MAX];
+
+struct misdn_cc_notify {
+ /*! \brief Dialplan: Notify extension priority */
+ int priority;
+
+ /*! \brief Dialplan: Notify extension context */
+ char context[AST_MAX_CONTEXT];
+
+ /*! \brief Dialplan: Notify caller-extension number (User-A) */
+ char exten[AST_MAX_EXTENSION];
+};
+
+/*! \brief mISDN call completion record */
+struct misdn_cc_record {
+ /*! \brief Next record in linked list */
+ struct misdn_cc_record *next;
+
+ /*! \brief Time the record was created. */
+ time_t time_created;
+
+ /*! \brief MISDN_CC_RECORD_ID value */
+ int record_id;
+
+ /*!
+ * \brief Logical Layer 1 port associated with this
+ * call completion record
+ */
+ int port;
+
+ /*! \brief CallLinkageID (valid when port determined) */
+ int linkage_id;
+
+ /*! \breif CCBSReference (valid when activated) */
+ int reference_id;
+
+ /*! \brief TRUE if call completion activated (reference_id is valid) */
+ int activated;
+
+ /*! \brief Outstanding message ID (valid while outstanding_message) */
+ int invoke_id;
+
+ /*! \brief TRUE if waiting for a response from a message (invoke_id is valid) */
+ int outstanding_message;
+
+ /*! \brief TRUE if activation has been requested */
+ int activation_requested;
+
+ /*! \brief globalRecall(0), specificRecall(1) */
+ int recall_mode;
+
+ /*! \brief TRUE if User-A is free (Used to answer CCBSStatusRequest) */
+ int party_a_free;
+
+ /*! \brief Error code received from last outstanding message. */
+ enum FacErrorCode error_code;
+
+ /*! \brief Reject code received from last outstanding message. */
+ enum FacRejectCode reject_code;
+
+ /* Information obtained from CCBSRemoteUserFree or CCBSBFree messages */
+ //struct FacAddress Address_Of_B;
+ //struct Q931_Bc_Hlc_Llc Q931ie_Of_B;
+
+ /*!
+ * \brief Saved struct misdn_bchannel call information when
+ * attempted to call User-B
+ */
+ struct {
+ /*! \brief User-A caller id information */
+ struct misdn_party_id caller;
+
+ /*! \brief User-B number information */
+ struct misdn_party_dialing dialed;
+
+ /*! \brief SETUP message bearer capability field code value */
+ int capability;
+
+ /*! \brief TRUE if call made in digital HDLC mode */
+ int hdlc;
+ } redial;
+
+ /*! \brief Dialplan location to indicate User-B free and User-A is free */
+ struct misdn_cc_notify remote_user_free;
+
+ /*! \brief Dialplan location to indicate User-B free and User-A is busy */
+ struct misdn_cc_notify b_free;
+};
+
+/*! \brief Call completion record guardian */
+ast_mutex_t misdn_cc_record_lock;
+/*! \brief mISDN call completion record database */
+static struct misdn_cc_record *misdn_cc_records;
+/*! \brief Next call completion record ID to use */
+static __u16 misdn_cc_record_id;
+/*! \brief Next invoke ID to use */
+static __s16 misdn_invoke_id;
+
+static const char misdn_no_response_from_network[] = "No response from network";
+static const char misdn_cc_record_not_found[] = "Call completion record not found";
+
+/* mISDN channel variable names */
+#define MISDN_CC_PEER_ID "MISDN_CC_PEER_ID"
+#define MISDN_CC_RECORD_ID "MISDN_CC_RECORD_ID"
+#define MISDN_CC_STATUS "MISDN_CC_STATUS"
+#define MISDN_ERROR_MSG "MISDN_ERROR_MSG"
+#endif /* defined(AST_MISDN_ENHANCEMENTS) */
ast_mutex_t release_lock;
@@ -312,6 +447,14 @@
*/
struct misdn_bchannel *bc;
+#if defined(AST_MISDN_ENHANCEMENTS)
+ /*! \brief Asterisk channel that initiated this call (may be NULL) */
+ struct ast_channel *peer;
+
+ /*! \brief Associated call completion record ID (-1 if not associated) */
+ int record_id;
+#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+
/*!
* \brief HOLDED channel information
*/
@@ -525,6 +668,10 @@
static int stop_bc_tones(struct chan_list *cl);
static void release_chan(struct misdn_bchannel *bc);
+#if defined(AST_MISDN_ENHANCEMENTS)
+static const char misdn_command_name[] = "misdn_command";
+static int misdn_command_exec(struct ast_channel *chan, void *data);
+#endif /* defined(AST_MISDN_ENHANCEMENTS) */
static int misdn_check_l2l1(struct ast_channel *chan, void *data);
static int misdn_set_opt_exec(struct ast_channel *chan, void *data);
static int misdn_facility_exec(struct ast_channel *chan, void *data);
@@ -570,6 +717,571 @@
return NULL;
}
+
+
+
+
+/* ******************************************************************* */
+#if defined(AST_MISDN_ENHANCEMENTS)
+/*!
+ * \internal
+ * \brief Get the requested peer link.
+ *
+ * \param peer_id Peer link id to obtain
+ *
+ * \retval peer_channel on success.
+ * \retval NULL on error.
+ */
+static struct ast_channel *misdn_peer_link_get(unsigned peer_id)
+{
+ struct ast_channel *peer;
+
+ if (peer_id < ARRAY_LEN(misdn_peers)) {
+ ast_mutex_lock(&misdn_peer_link_lock);
+ peer = misdn_peers[peer_id].peer;
+ ast_mutex_unlock(&misdn_peer_link_lock);
+ } else {
+ peer = NULL;
+ }
+
+ return peer;
+} /* end misdn_peer_link_get() */
+#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+
+
+
+
+/* ******************************************************************* */
+#if defined(AST_MISDN_ENHANCEMENTS)
+/*!
+ * \internal
+ * \brief Allocate a new peer link association id.
+ *
+ * \param chan Asterisk channel that is a potential peer.
+ *
+ * \retval peer_link_id on success.
+ * \retval -1 on error.
+ */
+static int misdn_peer_link_new(struct ast_channel *chan)
+{
+ int index;
+ int peer_id;
+ time_t now;
+
+ ast_mutex_lock(&misdn_peer_link_lock);
+
+ /* Remove all old entries */
+ now = time(NULL);
+ for (index = 0; index < ARRAY_LEN(misdn_peers); ++index) {
+ if (misdn_peers[index].peer
+ && MISDN_PEER_AGE_MAX < now - misdn_peers[index].time_created) {
+ misdn_peers[index].peer = NULL;
+ }
+ } /* end for */
+
+ /* Allocate a peer_id */
+ peer_id = -1;
+ for (index = 0; index < ARRAY_LEN(misdn_peers); ++index) {
+ if (!misdn_peers[index].peer) {
+ misdn_peers[index].peer = chan;
+ misdn_peers[index].time_created = time(NULL);
+ peer_id = index;
+ break;
+ }
+ } /* end for */
+ ast_mutex_unlock(&misdn_peer_link_lock);
+
+ return peer_id;
+} /* end misdn_peer_link_new() */
+#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+
+
+
+
+/* ******************************************************************* */
+#if defined(AST_MISDN_ENHANCEMENTS)
+/*!
+ * \internal
+ * \brief Find the call completion record given the record id.
+ *
+ * \param record_id
+ *
+ * \retval pointer to found call completion record
+ * \retval NULL if not found
+ *
+ * \note Assumes the misdn_cc_record_lock is already obtained.
+ */
+static struct misdn_cc_record *misdn_cc_find_by_id(int record_id)
+{
+ struct misdn_cc_record *current;
+
+ for (current = misdn_cc_records; current; current = current->next) {
+ if (current->record_id == record_id) {
+ /* Found the record */
+ break;
+ }
+ } /* end for */
+
+ return current;
+} /* end misdn_cc_find_by_id() */
+#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+
+
+
+
+/* ******************************************************************* */
+#if defined(AST_MISDN_ENHANCEMENTS)
+/*!
+ * \internal
+ * \brief Find the call completion record given the port and call linkage id.
+ *
+ * \param port Logical port number
+ * \param linkage_id Call linkage ID number from switch.
+ *
+ * \retval pointer to found call completion record
+ * \retval NULL if not found
+ *
+ * \note Assumes the misdn_cc_record_lock is already obtained.
+ */
+static struct misdn_cc_record *misdn_cc_find_by_linkage(int port, int linkage_id)
+{
+ struct misdn_cc_record *current;
+
+ for (current = misdn_cc_records; current; current = current->next) {
+ if (current->port == port && current->linkage_id == linkage_id) {
+ /* Found the record */
+ break;
+ }
+ } /* end for */
+
+ return current;
+} /* end misdn_cc_find_by_linkage() */
+#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+
+
+
+
+/* ******************************************************************* */
+#if defined(AST_MISDN_ENHANCEMENTS)
+/*!
+ * \internal
+ * \brief Find the call completion record given the port and outstanding invocation id.
+ *
+ * \param port Logical port number
+ * \param invoke_id Outstanding message invocation ID number.
+ *
+ * \retval pointer to found call completion record
+ * \retval NULL if not found
+ *
+ * \note Assumes the misdn_cc_record_lock is already obtained.
+ */
+static struct misdn_cc_record *misdn_cc_find_by_invoke(int port, int invoke_id)
+{
+ struct misdn_cc_record *current;
+
+ for (current = misdn_cc_records; current; current = current->next) {
+ if (current->outstanding_message
+ && current->invoke_id == invoke_id
+ && current->port == port) {
+ /* Found the record */
+ break;
+ }
+ } /* end for */
+
+ return current;
+} /* end misdn_cc_find_by_invoke() */
+#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+
+
+
+
+/* ******************************************************************* */
+#if defined(AST_MISDN_ENHANCEMENTS)
+/*!
+ * \internal
+ * \brief Find the call completion record given the port and CCBS reference id.
+ *
+ * \param port Logical port number
+ * \param reference_id CCBS reference ID number from switch.
+ *
+ * \retval pointer to found call completion record
+ * \retval NULL if not found
+ *
+ * \note Assumes the misdn_cc_record_lock is already obtained.
+ */
+static struct misdn_cc_record *misdn_cc_find_by_reference(int port, int reference_id)
+{
+ struct misdn_cc_record *current;
+
+ for (current = misdn_cc_records; current; current = current->next) {
+ if (current->activated
+ && current->port == port
+ && current->reference_id == reference_id) {
+ /* Found the record */
+ break;
+ }
+ } /* end for */
+
+ return current;
+} /* end misdn_cc_find_by_reference() */
+#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+
+
+
+
+/* ******************************************************************* */
+#if defined(AST_MISDN_ENHANCEMENTS)
+/*!
+ * \internal
+ * \brief Delete the given call completion record
+ *
+ * \param doomed Call completion record to destroy
+ *
+ * \return Nothing
+ *
+ * \note Assumes the misdn_cc_record_lock is already obtained.
+ */
+static void misdn_cc_delete(struct misdn_cc_record *doomed)
+{
+ struct misdn_cc_record *current;
+ struct misdn_cc_record **prev;
+
+ prev = &misdn_cc_records;
+ for (current = misdn_cc_records; current; current = current->next) {
+ if (current == doomed) {
+ *prev = doomed->next;
+ ast_free(doomed);
+ return;
+ }
+ prev = ¤t->next;
+ } /* end for */
+
+ /* The doomed node is not in the call completion database */
+} /* end misdn_cc_delete() */
+#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+
+
+
+
+/* ******************************************************************* */
+#if defined(AST_MISDN_ENHANCEMENTS)
+/*!
+ * \internal
+ * \brief Delete all old call completion records
+ *
+ * \return Nothing
+ *
+ * \note Assumes the misdn_cc_record_lock is already obtained.
+ */
+static void misdn_cc_remove_old(void)
+{
+ struct misdn_cc_record *current;
+ struct misdn_cc_record **prev;
+ time_t now;
+
+ now = time(NULL);
+ prev = &misdn_cc_records;
+ for (current = misdn_cc_records; current;) {
+ if (MISDN_CC_RECORD_AGE_MAX < now - current->time_created) {
+ /* Remove the old call completion record */
+ *prev = current->next;
+ ast_free(current);
+ current = *prev;
+ } else {
+ prev = ¤t->next;
+ current = current->next;
+ }
+ } /* end for */
+} /* end misdn_cc_remove_old() */
+#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+
+
+
+
+/* ******************************************************************* */
+#if defined(AST_MISDN_ENHANCEMENTS)
+/*!
+ * \internal
+ * \brief Create a new call completion record
+ *
+ * \retval pointer to new call completion record
+ * \retval NULL if failed
+ *
+ * \note Assumes the misdn_cc_record_lock is already obtained.
+ */
+static struct misdn_cc_record *misdn_cc_new(void)
+{
+ struct misdn_cc_record *cc_record;
+ int record_id;
+ int first_id;
+
+ misdn_cc_remove_old();
+
+ cc_record = ast_calloc(1, sizeof(*cc_record));
+ if (cc_record) {
+ record_id = ++misdn_cc_record_id;
+ first_id = record_id;
+ while (misdn_cc_find_by_id(record_id)) {
+ record_id = ++misdn_cc_record_id;
+ if (record_id == first_id) {
+ /*
+ * We have a resource leak.
+ * We should never need to allocate 64k records.
+ */
+ chan_misdn_log(0, 0, " --> ERROR Too many call completion records!\n");
+ ast_free(cc_record);
+ return NULL;
+ }
+ } /* end while */
+
+ /* Initialize the new record */
+ cc_record->record_id = record_id;
+ cc_record->port = -1;/* Invalid port so it will never be found this way */
+ cc_record->party_a_free = 1;/* Default User-A as free */
+ cc_record->error_code = FacError_None;
+ cc_record->reject_code = FacReject_None;
+ cc_record->time_created = time(NULL);
+
+ /* Insert the new record into the database */
+ cc_record->next = misdn_cc_records;
+ misdn_cc_records = cc_record;
+ }
+ return cc_record;
+} /* end misdn_cc_new() */
+#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+
+
+
+
+/* ******************************************************************* */
+#if defined(AST_MISDN_ENHANCEMENTS)
+/*!
+ * \internal
+ * \brief Destroy the call completion record database
+ *
+ * \return Nothing
+ */
+static void misdn_cc_destroy(void)
+{
+ ast_mutex_destroy(&misdn_cc_record_lock);
+ while (misdn_cc_records) {
+ misdn_cc_delete(misdn_cc_records);
+ } /* end while */
+} /* end misdn_cc_destroy() */
+#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+
+
+
+
+/* ******************************************************************* */
+#if defined(AST_MISDN_ENHANCEMENTS)
+/*!
+ * \internal
+ * \brief Initialize the call completion record database
+ *
+ * \return Nothing
+ */
+static void misdn_cc_init(void)
+{
+ misdn_cc_records = NULL;
+ misdn_cc_record_id = 0;
+ ast_mutex_init(&misdn_cc_record_lock);
+} /* end misdn_cc_init() */
+#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+
+
+
+
+/* ******************************************************************* */
+#if defined(AST_MISDN_ENHANCEMENTS)
+/*!
+ * \internal
+ * \brief Check the status of an outstanding invocation request.
+ *
+ * \param data Points to an integer containing the call completion record id.
+ *
+ * \retval 0 if got a response.
+ * \retval -1 if no response yet.
+ */
+static int misdn_cc_response_check(void *data)
+{
+ int not_responded;
+ struct misdn_cc_record *cc_record;
+
+ ast_mutex_lock(&misdn_cc_record_lock);
+ cc_record = misdn_cc_find_by_id(*(int *) data);
+ if (cc_record) {
+ if (cc_record->outstanding_message) {
+ not_responded = -1;
+ } else {
+ not_responded = 0;
+ }
+ } else {
+ /* No record so there is no response to check. */
+ not_responded = 0;
+ }
+ ast_mutex_unlock(&misdn_cc_record_lock);
+
+ return not_responded;
+} /* end misdn_cc_response_check() */
+#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+
+
+
+
+/* ******************************************************************* */
+#if defined(AST_MISDN_ENHANCEMENTS)
+/*!
+ * \internal
+ * \brief Wait for a response from the switch for an outstanding
+ * invocation request.
+ *
+ * \param chan Asterisk channel to operate upon.
+ * \param wait_seconds Number of seconds to wait
+ * \param record_id Call completion record ID.
+ *
+ * \return Nothing
+ */
+static void misdn_cc_response_wait(struct ast_channel *chan, int wait_seconds, int record_id)
+{
+ unsigned count;
+
+ for (count = 2 * MISDN_CC_REQUEST_WAIT_MAX; count--;) {
+ /* Sleep in 500 ms increments */
+ if (ast_safe_sleep_conditional(chan, 500, misdn_cc_response_check, &record_id) != 0) {
+ /* We got hung up or our response came in. */
+ break;
+ }
+ } /* end for */
+} /* end misdn_cc_response_wait() */
+#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+
+
+
+
+/* ******************************************************************* */
+#if defined(AST_MISDN_ENHANCEMENTS)
+/*!
+ * \internal
+ * \brief Convert the mISDN reject code to a string
+ *
+ * \param code mISDN reject code.
+ *
+ * \return The mISDN reject code as a string
+ */
+static const char *misdn_to_str_reject_code(enum FacRejectCode code)
+{
+ static const struct {
+ enum FacRejectCode code;
+ char *name;
+ } arr[] = {
+/* *INDENT-OFF* */
+ { FacReject_None, "No reject occurred" },
+ { FacReject_Unknown, "Unknown reject code" },
+
+ { FacReject_Gen_UnrecognizedComponent, "General: Unrecognized Component" },
+ { FacReject_Gen_MistypedComponent, "General: Mistyped Component" },
+ { FacReject_Gen_BadlyStructuredComponent, "General: Badly Structured Component" },
+
+ { FacReject_Inv_DuplicateInvocation, "Invoke: Duplicate Invocation" },
+ { FacReject_Inv_UnrecognizedOperation, "Invoke: Unrecognized Operation" },
+ { FacReject_Inv_MistypedArgument, "Invoke: Mistyped Argument" },
+ { FacReject_Inv_ResourceLimitation, "Invoke: Resource Limitation" },
+ { FacReject_Inv_InitiatorReleasing, "Invoke: Initiator Releasing" },
+ { FacReject_Inv_UnrecognizedLinkedID, "Invoke: Unrecognized Linked ID" },
+ { FacReject_Inv_LinkedResponseUnexpected, "Invoke: Linked Response Unexpected" },
+ { FacReject_Inv_UnexpectedChildOperation, "Invoke: Unexpected Child Operation" },
+
+ { FacReject_Res_UnrecognizedInvocation, "Result: Unrecognized Invocation" },
+ { FacReject_Res_ResultResponseUnexpected, "Result: Result Response Unexpected" },
+ { FacReject_Res_MistypedResult, "Result: Mistyped Result" },
+
+ { FacReject_Err_UnrecognizedInvocation, "Error: Unrecognized Invocation" },
+ { FacReject_Err_ErrorResponseUnexpected, "Error: Error Response Unexpected" },
+ { FacReject_Err_UnrecognizedError, "Error: Unrecognized Error" },
+ { FacReject_Err_UnexpectedError, "Error: Unexpected Error" },
+ { FacReject_Err_MistypedParameter, "Error: Mistyped Parameter" },
+/* *INDENT-ON* */
+ };
+
+ unsigned index;
+
+ for (index = 0; index < ARRAY_LEN(arr); ++index) {
+ if (arr[index].code == code) {
+ return arr[index].name;
+ }
+ } /* end for */
+
+ return "unknown";
+} /* end misdn_to_str_reject_code() */
+#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+
+
+
+
+/* ******************************************************************* */
+#if defined(AST_MISDN_ENHANCEMENTS)
+/*!
+ * \internal
+ * \brief Convert the mISDN error code to a string
+ *
+ * \param code mISDN error code.
+ *
+ * \return The mISDN error code as a string
+ */
+static const char *misdn_to_str_error_code(enum FacErrorCode code)
+{
+ static const struct {
+ enum FacErrorCode code;
+ char *name;
+ } arr[] = {
+/* *INDENT-OFF* */
+ { FacError_None, "No error occurred" },
+ { FacError_Unknown, "Unknown OID error code" },
+
+ { FacError_Gen_NotSubscribed, "General: Not Subscribed" },
+ { FacError_Gen_NotAvailable, "General: Not Available" },
+ { FacError_Gen_NotImplemented, "General: Not Implemented" },
+ { FacError_Gen_InvalidServedUserNr, "General: Invalid Served User Number" },
+ { FacError_Gen_InvalidCallState, "General: Invalid Call State" },
+ { FacError_Gen_BasicServiceNotProvided, "General: Basic Service Not Provided" },
+ { FacError_Gen_NotIncomingCall, "General: Not Incoming Call" },
+ { FacError_Gen_SupplementaryServiceInteractionNotAllowed,"General: Supplementary Service Interaction Not Allowed" },
+ { FacError_Gen_ResourceUnavailable, "General: Resource Unavailable" },
+
+ { FacError_Div_InvalidDivertedToNr, "Diversion: Invalid Diverted To Number" },
+ { FacError_Div_SpecialServiceNr, "Diversion: Special Service Number" },
+ { FacError_Div_DiversionToServedUserNr, "Diversion: Diversion To Served User Number" },
+ { FacError_Div_IncomingCallAccepted, "Diversion: Incoming Call Accepted" },
+ { FacError_Div_NumberOfDiversionsExceeded, "Diversion: Number Of Diversions Exceeded" },
+ { FacError_Div_NotActivated, "Diversion: Not Activated" },
+ { FacError_Div_RequestAlreadyAccepted, "Diversion: Request Already Accepted" },
+
+ { FacError_AOC_NoChargingInfoAvailable, "AOC: No Charging Info Available" },
+
+ { FacError_CCBS_InvalidCallLinkageID, "CCBS: Invalid Call Linkage ID" },
+ { FacError_CCBS_InvalidCCBSReference, "CCBS: Invalid CCBS Reference" },
+ { FacError_CCBS_LongTermDenial, "CCBS: Long Term Denial" },
+ { FacError_CCBS_ShortTermDenial, "CCBS: Short Term Denial" },
+ { FacError_CCBS_IsAlreadyActivated, "CCBS: Is Already Activated" },
+ { FacError_CCBS_AlreadyAccepted, "CCBS: Already Accepted" },
+ { FacError_CCBS_OutgoingCCBSQueueFull, "CCBS: Outgoing CCBS Queue Full" },
+ { FacError_CCBS_CallFailureReasonNotBusy, "CCBS: Call Failure Reason Not Busy" },
+ { FacError_CCBS_NotReadyForCall, "CCBS: Not Ready For Call" },
+/* *INDENT-ON* */
+ };
+
+ unsigned index;
+
+ for (index = 0; index < ARRAY_LEN(arr); ++index) {
+ if (arr[index].code == code) {
+ return arr[index].name;
+ }
+ } /* end for */
+
+ return "unknown";
+} /* end misdn_to_str_error_code() */
+#endif /* defined(AST_MISDN_ENHANCEMENTS) */
@@ -1190,20 +1902,132 @@
}
-static void print_facility(struct FacParm *fac, struct misdn_bchannel *bc)
-{
+
+#if defined(AST_MISDN_ENHANCEMENTS)
+static const char Level_Spacing[] = " ";/* Work for up to 10 levels */
+#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+
+/* ******************************************************************* */
+#if defined(AST_MISDN_ENHANCEMENTS)
+static void print_facility_partynumber(unsigned Level, const struct FacPartyNumber *Party, const struct misdn_bchannel *bc)
+{
+ if (Party->LengthOfNumber) {
+ const char *Spacing;
+
+ Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
+ chan_misdn_log(1, bc->port, " -->%s PartyNumber: Type:%d\n",
+ Spacing, Party->Type);
+ switch (Party->Type) {
+ case 0: /* Unknown PartyNumber */
+ chan_misdn_log(1, bc->port, " -->%s Unknown %s\n",
+ Spacing, Party->Number);
+ break;
+ case 1: /* Public PartyNumber */
+ chan_misdn_log(1, bc->port, " -->%s Public TON:%d %s\n",
+ Spacing, Party->TypeOfNumber, Party->Number);
+ break;
+ case 2: /* NSAP encoded PartyNumber */
+ chan_misdn_log(1, bc->port, " -->%s NSAP %s\n",
+ Spacing, Party->Number);
+ break;
+ case 3: /* Data PartyNumber (Not used) */
+ chan_misdn_log(1, bc->port, " -->%s Data %s\n",
+ Spacing, Party->Number);
+ break;
+ case 4: /* Telex PartyNumber (Not used) */
+ chan_misdn_log(1, bc->port, " -->%s Telex %s\n",
+ Spacing, Party->Number);
+ break;
+ case 5: /* Private PartyNumber */
+ chan_misdn_log(1, bc->port, " -->%s Private TON:%d %s\n",
+ Spacing, Party->TypeOfNumber, Party->Number);
+ break;
+ case 8: /* National Standard PartyNumber (Not used) */
+ chan_misdn_log(1, bc->port, " -->%s National %s\n",
+ Spacing, Party->Number);
+ break;
+ default:
+ break;
+ } /* end switch */
+ }
+} /* end print_facility_partynumber() */
+#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+
+
+
+
+/* ******************************************************************* */
+#if defined(AST_MISDN_ENHANCEMENTS)
+static void print_facility_subaddress(unsigned Level, const struct FacPartySubaddress *Subaddress, const struct misdn_bchannel *bc)
+{
+ if (Subaddress->Length) {
+ const char *Spacing;
+
+ Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
+ chan_misdn_log(1, bc->port, " -->%s Subaddress: Type:%d\n",
+ Spacing, Subaddress->Type);
+ switch (Subaddress->Type) {
+ case 0: /* UserSpecified */
+ if (Subaddress->u.UserSpecified.OddCountPresent) {
+ chan_misdn_log(1, bc->port, " -->%s User BCD OddCount:%d NumOctets:%d\n",
+ Spacing, Subaddress->u.UserSpecified.OddCount, Subaddress->Length);
+ } else {
+ chan_misdn_log(1, bc->port, " -->%s User %s\n",
+ Spacing, Subaddress->u.UserSpecified.Information);
+ }
+ break;
+ case 1: /* NSAP */
+ chan_misdn_log(1, bc->port, " -->%s NSAP %s\n",
+ Spacing, Subaddress->u.Nsap);
+ break;
+ default:
+ break;
+ } /* end switch */
+ }
+} /* end print_facility_subaddress() */
+#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+
+
+
+
+/* ******************************************************************* */
+#if defined(AST_MISDN_ENHANCEMENTS)
+static void print_facility_address(unsigned Level, const struct FacAddress *Address, const struct misdn_bchannel *bc)
+{
+ print_facility_partynumber(Level, &Address->Party, bc);
+ print_facility_subaddress(Level, &Address->Subaddress, bc);
+} /* end print_facility_address() */
+#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+
+
+
+
+/* ******************************************************************* */
+#if defined(AST_MISDN_ENHANCEMENTS)
+static void print_facility_callinformation(unsigned Level, const struct FacCallInformation *CallInfo, const struct misdn_bchannel *bc)
+{
+ const char *Spacing;
+
+ Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
+ chan_misdn_log(1, bc->port, " -->%s CCBSReference:%d\n",
+ Spacing, CallInfo->CCBSReference);
+ chan_misdn_log(1, bc->port, " -->%s AddressOfB\n", Spacing);
+ print_facility_address(Level + 1, &CallInfo->AddressOfB, bc);
+ if (CallInfo->SubaddressOfA.Length) {
+ chan_misdn_log(1, bc->port, " -->%s SubaddressOfA\n", Spacing);
+ print_facility_subaddress(Level + 1, &CallInfo->SubaddressOfA, bc);
+ }
+} /* end print_facility_callinformation() */
+#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+
+
+static void print_facility(const struct FacParm *fac, const const struct misdn_bchannel *bc)
+{
+#if defined(AST_MISDN_ENHANCEMENTS)
+ unsigned Index;
+#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+
switch (fac->Function) {
-#ifdef HAVE_MISDN_FAC_RESULT
- case Fac_RESULT:
- chan_misdn_log(0, bc->port," --> Received RESULT Operation\n");
- break;
-#endif
-#ifdef HAVE_MISDN_FAC_ERROR
- case Fac_ERROR:
- chan_misdn_log(0, bc->port," --> Received Error Operation\n");
- chan_misdn_log(0, bc->port," --> Value:%d Error:%s\n",fac->u.ERROR.errorValue, fac->u.ERROR.error);
- break;
-#endif
case Fac_CD:
chan_misdn_log(1,bc->port," --> calldeflect to: %s, presentable: %s\n", fac->u.CDeflection.DeflectedToNumber,
fac->u.CDeflection.PresentationAllowed ? "yes" : "no");
@@ -1234,11 +2058,207 @@
chan_misdn_log(1,bc->port," --> AOCD charging unit: recordedUnits:%d typeOfChargingInfo:%s\n",
fac->u.AOCDchu.recordedUnits, (fac->u.AOCDchu.typeOfChargingInfo == 0) ? "subTotal" : "total");
break;
+#if defined(AST_MISDN_ENHANCEMENTS)
+ case Fac_ERROR:
+ chan_misdn_log(1, bc->port, " --> ERROR: InvokeID:%d, Code:0x%02x\n",
+ fac->u.ERROR.invokeId, fac->u.ERROR.errorValue);
+ break;
+ case Fac_RESULT:
+ chan_misdn_log(1, bc->port, " --> RESULT: InvokeID:%d\n",
+ fac->u.RESULT.InvokeID);
+ break;
+ case Fac_REJECT:
+ if (fac->u.REJECT.InvokeIDPresent) {
+ chan_misdn_log(1, bc->port, " --> REJECT: InvokeID:%d, Code:0x%02x\n",
+ fac->u.REJECT.InvokeID, fac->u.REJECT.Code);
+ } else {
+ chan_misdn_log(1, bc->port, " --> REJECT: Code:0x%02x\n",
+ fac->u.REJECT.Code);
+ }
+ break;
+ case Fac_StatusRequest:
+ chan_misdn_log(1, bc->port, " --> StatusRequest: InvokeID:%d\n",
+ fac->u.StatusRequest.InvokeID);
+ switch (fac->u.StatusRequest.ComponentType) {
+ case FacComponent_Invoke:
+ chan_misdn_log(1, bc->port, " --> Invoke: Compatibility:%d\n",
+ fac->u.StatusRequest.Component.Invoke.CompatibilityMode);
+ break;
+ case FacComponent_Result:
+ chan_misdn_log(1, bc->port, " --> Result: Status:%d\n",
+ fac->u.StatusRequest.Component.Result.Status);
+ break;
+ default:
+ break;
+ } /* end switch */
+ break;
+ case Fac_CallInfoRetain:
+ chan_misdn_log(1, bc->port, " --> CallInfoRetain: InvokeID:%d, LinkageID:%d\n",
+ fac->u.CallInfoRetain.InvokeID, fac->u.CallInfoRetain.CallLinkageID);
+ break;
+ case Fac_CCBSDeactivate:
+ chan_misdn_log(1, bc->port, " --> CCBSDeactivate: InvokeID:%d\n",
+ fac->u.CCBSDeactivate.InvokeID);
+ switch (fac->u.CCBSDeactivate.ComponentType) {
+ case FacComponent_Invoke:
+ chan_misdn_log(1, bc->port, " --> Invoke: CCBSReference:%d\n",
+ fac->u.CCBSDeactivate.Component.Invoke.CCBSReference);
+ break;
+ case FacComponent_Result:
+ chan_misdn_log(1, bc->port, " --> Result\n");
+ break;
+ default:
+ break;
+ } /* end switch */
+ break;
+ case Fac_CCBSErase:
+ chan_misdn_log(1, bc->port, " --> CCBSErase: InvokeID:%d, CCBSReference:%d RecallMode:%d, Reason:%d\n",
+ fac->u.CCBSErase.InvokeID, fac->u.CCBSErase.CCBSReference,
+ fac->u.CCBSErase.RecallMode, fac->u.CCBSErase.Reason);
+ chan_misdn_log(1, bc->port, " --> AddressOfB\n");
+ print_facility_address(2, &fac->u.CCBSErase.AddressOfB, bc);
+ break;
+ case Fac_CCBSRemoteUserFree:
+ chan_misdn_log(1, bc->port, " --> CCBSRemoteUserFree: InvokeID:%d, CCBSReference:%d RecallMode:%d\n",
+ fac->u.CCBSRemoteUserFree.InvokeID, fac->u.CCBSRemoteUserFree.CCBSReference,
+ fac->u.CCBSRemoteUserFree.RecallMode);
+ chan_misdn_log(1, bc->port, " --> AddressOfB\n");
+ print_facility_address(2, &fac->u.CCBSRemoteUserFree.AddressOfB, bc);
+ break;
+ case Fac_CCBSCall:
+ chan_misdn_log(1, bc->port, " --> CCBSCall: InvokeID:%d, CCBSReference:%d\n",
+ fac->u.CCBSCall.InvokeID, fac->u.CCBSCall.CCBSReference);
+ break;
+ case Fac_CCBSStatusRequest:
+ chan_misdn_log(1, bc->port, " --> CCBSStatusRequest: InvokeID:%d\n",
+ fac->u.CCBSStatusRequest.InvokeID);
+ switch (fac->u.CCBSStatusRequest.ComponentType) {
+ case FacComponent_Invoke:
+ chan_misdn_log(1, bc->port, " --> Invoke: CCBSReference:%d RecallMode:%d\n",
+ fac->u.CCBSStatusRequest.Component.Invoke.CCBSReference,
+ fac->u.CCBSStatusRequest.Component.Invoke.RecallMode);
+ break;
+ case FacComponent_Result:
+ chan_misdn_log(1, bc->port, " --> Result: Free:%d\n",
+ fac->u.CCBSStatusRequest.Component.Result.Free);
+ break;
+ default:
+ break;
+ } /* end switch */
+ break;
+ case Fac_CCBSBFree:
+ chan_misdn_log(1, bc->port, " --> CCBSBFree: InvokeID:%d, CCBSReference:%d RecallMode:%d\n",
+ fac->u.CCBSBFree.InvokeID, fac->u.CCBSBFree.CCBSReference,
+ fac->u.CCBSBFree.RecallMode);
+ chan_misdn_log(1, bc->port, " --> AddressOfB\n");
+ print_facility_address(2, &fac->u.CCBSBFree.AddressOfB, bc);
+ break;
+ case Fac_EraseCallLinkageID:
+ chan_misdn_log(1, bc->port, " --> EraseCallLinkageID: InvokeID:%d, LinkageID:%d\n",
+ fac->u.EraseCallLinkageID.InvokeID, fac->u.EraseCallLinkageID.CallLinkageID);
+ break;
+ case Fac_CCBSStopAlerting:
+ chan_misdn_log(1, bc->port, " --> CCBSStopAlerting: InvokeID:%d, CCBSReference:%d\n",
+ fac->u.CCBSStopAlerting.InvokeID, fac->u.CCBSStopAlerting.CCBSReference);
+ break;
+ case Fac_CCBSRequest:
+ chan_misdn_log(1, bc->port, " --> CCBSRequest: InvokeID:%d\n",
+ fac->u.CCBSRequest.InvokeID);
+ switch (fac->u.CCBSRequest.ComponentType) {
+ case FacComponent_Invoke:
+ chan_misdn_log(1, bc->port, " --> Invoke: LinkageID:%d\n",
+ fac->u.CCBSRequest.Component.Invoke.CallLinkageID);
+ break;
+ case FacComponent_Result:
+ chan_misdn_log(1, bc->port, " --> Result: CCBSReference:%d RecallMode:%d\n",
+ fac->u.CCBSRequest.Component.Result.CCBSReference,
+ fac->u.CCBSRequest.Component.Result.RecallMode);
+ break;
+ default:
+ break;
+ } /* end switch */
+ break;
+ case Fac_CCBSInterrogate:
+ chan_misdn_log(1, bc->port, " --> CCBSInterrogate: InvokeID:%d\n",
+ fac->u.CCBSInterrogate.InvokeID);
+ switch (fac->u.CCBSInterrogate.ComponentType) {
+ case FacComponent_Invoke:
+ chan_misdn_log(1, bc->port, " --> Invoke\n");
+ if (fac->u.CCBSInterrogate.Component.Invoke.CCBSReferencePresent) {
+ chan_misdn_log(1, bc->port, " --> CCBSReference:%d\n",
+ fac->u.CCBSInterrogate.Component.Invoke.CCBSReference);
+ }
+ if (fac->u.CCBSInterrogate.Component.Invoke.AParty.LengthOfNumber) {
+ chan_misdn_log(1, bc->port, " --> AParty\n");
+ print_facility_partynumber(3, &fac->u.CCBSInterrogate.Component.Invoke.AParty, bc);
+ }
+ break;
+ case FacComponent_Result:
+ chan_misdn_log(1, bc->port, " --> Result: RecallMode:%d\n",
+ fac->u.CCBSInterrogate.Component.Result.RecallMode);
+ if (fac->u.CCBSInterrogate.Component.Result.NumRecords) {
+ for (Index = 0; Index < fac->u.CCBSInterrogate.Component.Result.NumRecords; ++Index) {
+ chan_misdn_log(1, bc->port, " --> CallDetails[%d]:\n", Index);
+ print_facility_callinformation(3, &fac->u.CCBSInterrogate.Component.Result.CallDetails[Index], bc);
+ } /* end for */
+ }
+ break;
+ default:
+ break;
+ } /* end switch */
+ break;
+ case Fac_CCNRRequest:
+ chan_misdn_log(1, bc->port, " --> CCNRRequest: InvokeID:%d\n",
+ fac->u.CCNRRequest.InvokeID);
+ switch (fac->u.CCNRRequest.ComponentType) {
+ case FacComponent_Invoke:
+ chan_misdn_log(1, bc->port, " --> Invoke: LinkageID:%d\n",
+ fac->u.CCNRRequest.Component.Invoke.CallLinkageID);
+ break;
+ case FacComponent_Result:
+ chan_misdn_log(1, bc->port, " --> Result: CCBSReference:%d RecallMode:%d\n",
+ fac->u.CCNRRequest.Component.Result.CCBSReference,
+ fac->u.CCNRRequest.Component.Result.RecallMode);
+ break;
+ default:
+ break;
+ } /* end switch */
+ break;
+ case Fac_CCNRInterrogate:
+ chan_misdn_log(1, bc->port, " --> CCNRInterrogate: InvokeID:%d\n",
+ fac->u.CCNRInterrogate.InvokeID);
+ switch (fac->u.CCNRInterrogate.ComponentType) {
+ case FacComponent_Invoke:
+ chan_misdn_log(1, bc->port, " --> Invoke\n");
+ if (fac->u.CCNRInterrogate.Component.Invoke.CCBSReferencePresent) {
+ chan_misdn_log(1, bc->port, " --> CCBSReference:%d\n",
+ fac->u.CCNRInterrogate.Component.Invoke.CCBSReference);
+ }
+ if (fac->u.CCNRInterrogate.Component.Invoke.AParty.LengthOfNumber) {
+ chan_misdn_log(1, bc->port, " --> AParty\n");
+ print_facility_partynumber(3, &fac->u.CCNRInterrogate.Component.Invoke.AParty, bc);
+ }
+ break;
+ case FacComponent_Result:
+ chan_misdn_log(1, bc->port, " --> Result: RecallMode:%d\n",
+ fac->u.CCNRInterrogate.Component.Result.RecallMode);
+ if (fac->u.CCNRInterrogate.Component.Result.NumRecords) {
+ for (Index = 0; Index < fac->u.CCNRInterrogate.Component.Result.NumRecords; ++Index) {
+ chan_misdn_log(1, bc->port, " --> CallDetails[%d]:\n", Index);
+ print_facility_callinformation(3, &fac->u.CCNRInterrogate.Component.Result.CallDetails[Index], bc);
+ } /* end for */
+ }
+ break;
+ default:
+ break;
+ } /* end switch */
+ break;
+#endif /* defined(AST_MISDN_ENHANCEMENTS) */
case Fac_None:
default:
chan_misdn_log(1,bc->port," --> unknown facility\n");
break;
- }
+ } /* end switch */
}
static void print_bearer(struct misdn_bchannel *bc)
@@ -2197,6 +3217,300 @@
return CLI_SUCCESS;
}
+#if defined(AST_MISDN_ENHANCEMENTS) && defined(CCBS_TEST_MESSAGES)
+static const struct FacParm Fac_Msgs[] = {
+ [0].Function = Fac_ERROR,
+ [0].u.ERROR.invokeId = 8,
+ [0].u.ERROR.errorValue = FacError_CCBS_AlreadyAccepted,
+
+ [1].Function = Fac_RESULT,
+ [1].u.RESULT.InvokeID = 9,
+
+ [2].Function = Fac_REJECT,
+ [2].u.REJECT.Code = FacReject_Gen_BadlyStructuredComponent,
+
+ [3].Function = Fac_REJECT,
+ [3].u.REJECT.InvokeIDPresent = 1,
+ [3].u.REJECT.InvokeID = 10,
+ [3].u.REJECT.Code = FacReject_Inv_InitiatorReleasing,
+
+ [4].Function = Fac_REJECT,
+ [4].u.REJECT.InvokeIDPresent = 1,
+ [4].u.REJECT.InvokeID = 11,
+ [4].u.REJECT.Code = FacReject_Res_MistypedResult,
+
+ [5].Function = Fac_REJECT,
+ [5].u.REJECT.InvokeIDPresent = 1,
+ [5].u.REJECT.InvokeID = 12,
+ [5].u.REJECT.Code = FacReject_Err_ErrorResponseUnexpected,
+
+ [6].Function = Fac_StatusRequest,
+ [6].u.StatusRequest.InvokeID = 13,
+ [6].u.StatusRequest.ComponentType = FacComponent_Invoke,
+ [6].u.StatusRequest.Component.Invoke.Q931ie.Bc.Length = 2,
+ [6].u.StatusRequest.Component.Invoke.Q931ie.Bc.Contents = "AB",
+ [6].u.StatusRequest.Component.Invoke.Q931ie.Llc.Length = 3,
+ [6].u.StatusRequest.Component.Invoke.Q931ie.Llc.Contents = "CDE",
+ [6].u.StatusRequest.Component.Invoke.Q931ie.Hlc.Length = 4,
+ [6].u.StatusRequest.Component.Invoke.Q931ie.Hlc.Contents = "FGHI",
+ [6].u.StatusRequest.Component.Invoke.CompatibilityMode = 1,
+
+ [7].Function = Fac_StatusRequest,
+ [7].u.StatusRequest.InvokeID = 14,
+ [7].u.StatusRequest.ComponentType = FacComponent_Result,
+ [7].u.StatusRequest.Component.Result.Status = 2,
+
+ [8].Function = Fac_CallInfoRetain,
+ [8].u.CallInfoRetain.InvokeID = 15,
+ [8].u.CallInfoRetain.CallLinkageID = 115,
+
+ [9].Function = Fac_EraseCallLinkageID,
+ [9].u.EraseCallLinkageID.InvokeID = 16,
+ [9].u.EraseCallLinkageID.CallLinkageID = 105,
+
+ [10].Function = Fac_CCBSDeactivate,
+ [10].u.CCBSDeactivate.InvokeID = 17,
+ [10].u.CCBSDeactivate.ComponentType = FacComponent_Invoke,
+ [10].u.CCBSDeactivate.Component.Invoke.CCBSReference = 2,
+
+ [11].Function = Fac_CCBSDeactivate,
+ [11].u.CCBSDeactivate.InvokeID = 18,
+ [11].u.CCBSDeactivate.ComponentType = FacComponent_Result,
+
+ [12].Function = Fac_CCBSErase,
+ [12].u.CCBSErase.InvokeID = 19,
+ [12].u.CCBSErase.Q931ie.Bc.Length = 2,
+ [12].u.CCBSErase.Q931ie.Bc.Contents = "JK",
+ [12].u.CCBSErase.AddressOfB.Party.Type = 0,
+ [12].u.CCBSErase.AddressOfB.Party.LengthOfNumber = 5,
+ [12].u.CCBSErase.AddressOfB.Party.Number = "33403",
+ [12].u.CCBSErase.AddressOfB.Subaddress.Type = 0,
+ [12].u.CCBSErase.AddressOfB.Subaddress.Length = 4,
+ [12].u.CCBSErase.AddressOfB.Subaddress.u.UserSpecified.Information = "3748",
+ [12].u.CCBSErase.RecallMode = 1,
+ [12].u.CCBSErase.CCBSReference = 102,
+ [12].u.CCBSErase.Reason = 3,
+
+ [13].Function = Fac_CCBSErase,
+ [13].u.CCBSErase.InvokeID = 20,
[... 2339 lines stripped ...]
More information about the asterisk-commits
mailing list