Add BRI PTMP NT mode, HOLD/RETRIEVE, Call rerouting/deflection, and keypad facility support.
* Added support for BRI PTMP NT mode. (Overlap dialing NT -> TE not supported.) * Added handling of received HOLD/RETRIEVE messages and the optional ability to transfer a held call on disconnect similar to an analog phone. * Added CallRerouting/CallDeflection support for Q.SIG, ETSI PTP, ETSI PTMP. Will reroute/deflect an outgoing call when receive the message. Can use the DAHDISendCallreroutingFacility to send the message for the supported switches. * Added ability to send/receive keypad digits in the SETUP message. Send keypad digits in SETUP message: Dial(DAHDI/g1[/K<keypad_digits>][/extension]) Access any received keypad digits in SETUP message by: ${CHANNEL(keypad_digits)} (closes issue #15048) Tested by: rmudgett, mattf git-svn-id: https://origsvn.digium.com/svn/libpri/branches/1.4@1242 2fbb986a-6c06-0410-b554-c9c1f0a7f128
This commit is contained in:
parent
a78ee730c9
commit
a2dcb6adba
277
libpri.h
277
libpri.h
@ -91,6 +91,12 @@
|
|||||||
#define PRI_EVENT_KEYPAD_DIGIT 18 /* When we receive during ACTIVE state (INFORMATION) */
|
#define PRI_EVENT_KEYPAD_DIGIT 18 /* When we receive during ACTIVE state (INFORMATION) */
|
||||||
#define PRI_EVENT_SERVICE 19 /* SERVICE maintenance message */
|
#define PRI_EVENT_SERVICE 19 /* SERVICE maintenance message */
|
||||||
#define PRI_EVENT_SERVICE_ACK 20 /* SERVICE maintenance acknowledgement message */
|
#define PRI_EVENT_SERVICE_ACK 20 /* SERVICE maintenance acknowledgement message */
|
||||||
|
#define PRI_EVENT_HOLD 21 /* HOLD request received */
|
||||||
|
#define PRI_EVENT_HOLD_ACK 22 /* HOLD_ACKNOWLEDGE received */
|
||||||
|
#define PRI_EVENT_HOLD_REJ 23 /* HOLD_REJECT received */
|
||||||
|
#define PRI_EVENT_RETRIEVE 24 /* RETRIEVE request received */
|
||||||
|
#define PRI_EVENT_RETRIEVE_ACK 25 /* RETRIEVE_ACKNOWLEDGE received */
|
||||||
|
#define PRI_EVENT_RETRIEVE_REJ 26 /* RETRIEVE_REJECT received */
|
||||||
|
|
||||||
/* Simple states */
|
/* Simple states */
|
||||||
#define PRI_STATE_DOWN 0
|
#define PRI_STATE_DOWN 0
|
||||||
@ -200,6 +206,7 @@
|
|||||||
#define PRI_CAUSE_NO_ANSWER 19
|
#define PRI_CAUSE_NO_ANSWER 19
|
||||||
#define PRI_CAUSE_CALL_REJECTED 21
|
#define PRI_CAUSE_CALL_REJECTED 21
|
||||||
#define PRI_CAUSE_NUMBER_CHANGED 22
|
#define PRI_CAUSE_NUMBER_CHANGED 22
|
||||||
|
#define PRI_CAUSE_NONSELECTED_USER_CLEARING 26
|
||||||
#define PRI_CAUSE_DESTINATION_OUT_OF_ORDER 27
|
#define PRI_CAUSE_DESTINATION_OUT_OF_ORDER 27
|
||||||
#define PRI_CAUSE_INVALID_NUMBER_FORMAT 28
|
#define PRI_CAUSE_INVALID_NUMBER_FORMAT 28
|
||||||
#define PRI_CAUSE_FACILITY_REJECTED 29 /* !Q.SIG */
|
#define PRI_CAUSE_FACILITY_REJECTED 29 /* !Q.SIG */
|
||||||
@ -212,6 +219,7 @@
|
|||||||
#define PRI_CAUSE_ACCESS_INFO_DISCARDED 43 /* !Q.SIG */
|
#define PRI_CAUSE_ACCESS_INFO_DISCARDED 43 /* !Q.SIG */
|
||||||
#define PRI_CAUSE_REQUESTED_CHAN_UNAVAIL 44
|
#define PRI_CAUSE_REQUESTED_CHAN_UNAVAIL 44
|
||||||
#define PRI_CAUSE_PRE_EMPTED 45 /* !Q.SIG */
|
#define PRI_CAUSE_PRE_EMPTED 45 /* !Q.SIG */
|
||||||
|
#define PRI_CAUSE_RESOURCE_UNAVAIL_UNSPECIFIED 47
|
||||||
#define PRI_CAUSE_FACILITY_NOT_SUBSCRIBED 50 /* !Q.SIG */
|
#define PRI_CAUSE_FACILITY_NOT_SUBSCRIBED 50 /* !Q.SIG */
|
||||||
#define PRI_CAUSE_OUTGOING_CALL_BARRED 52 /* !Q.SIG */
|
#define PRI_CAUSE_OUTGOING_CALL_BARRED 52 /* !Q.SIG */
|
||||||
#define PRI_CAUSE_INCOMING_CALL_BARRED 54 /* !Q.SIG */
|
#define PRI_CAUSE_INCOMING_CALL_BARRED 54 /* !Q.SIG */
|
||||||
@ -468,9 +476,37 @@ struct pri_party_redirecting {
|
|||||||
int reason;
|
int reason;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Information for rerouting/deflecting the call.
|
||||||
|
*/
|
||||||
|
struct pri_rerouting_data {
|
||||||
|
/*!
|
||||||
|
* \brief Updated caller-id information.
|
||||||
|
* \note The information may have been altered by procedure in the private network.
|
||||||
|
*/
|
||||||
|
struct pri_party_id caller;
|
||||||
|
/*!
|
||||||
|
* \note
|
||||||
|
* deflection.to is the new called number and must always be present.
|
||||||
|
*/
|
||||||
|
struct pri_party_redirecting deflection;
|
||||||
|
/*!
|
||||||
|
* \brief Diverting user subscription option to specify if caller is notified.
|
||||||
|
* \details
|
||||||
|
* noNotification(0),
|
||||||
|
* notificationWithoutDivertedToNr(1),
|
||||||
|
* notificationWithDivertedToNr(2),
|
||||||
|
* notApplicable(3) (Status only.)
|
||||||
|
*/
|
||||||
|
int subscription_option;
|
||||||
|
/*! Invocation ID to use when sending a reply to the call rerouting/deflection request. */
|
||||||
|
int invoke_id;
|
||||||
|
};
|
||||||
|
|
||||||
/* Subcommands derived from supplementary services. */
|
/* Subcommands derived from supplementary services. */
|
||||||
#define PRI_SUBCMD_REDIRECTING 1
|
#define PRI_SUBCMD_REDIRECTING 1
|
||||||
#define PRI_SUBCMD_CONNECTED_LINE 2
|
#define PRI_SUBCMD_CONNECTED_LINE 2
|
||||||
|
#define PRI_SUBCMD_REROUTING 3
|
||||||
|
|
||||||
|
|
||||||
struct pri_subcommand {
|
struct pri_subcommand {
|
||||||
@ -481,6 +517,7 @@ struct pri_subcommand {
|
|||||||
char reserve_space[512];
|
char reserve_space[512];
|
||||||
struct pri_party_connected_line connected_line;
|
struct pri_party_connected_line connected_line;
|
||||||
struct pri_party_redirecting redirecting;
|
struct pri_party_redirecting redirecting;
|
||||||
|
struct pri_rerouting_data rerouting;
|
||||||
} u;
|
} u;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -497,13 +534,14 @@ struct pri_subcommands {
|
|||||||
* Event channel parameter encoding:
|
* Event channel parameter encoding:
|
||||||
* 3322 2222 2222 1111 1111 1100 0000 0000
|
* 3322 2222 2222 1111 1111 1100 0000 0000
|
||||||
* 1098 7654 3210 9876 5432 1098 7654 3210
|
* 1098 7654 3210 9876 5432 1098 7654 3210
|
||||||
* xxxx xxxx xxxx xxDC BBBBBBBBB AAAAAAAAA
|
* xxxx xxxx xxxx xEDC BBBBBBBBB AAAAAAAAA
|
||||||
*
|
*
|
||||||
* Bit field
|
* Bit field
|
||||||
* A - B channel
|
* A - B channel
|
||||||
* B - Span (DS1) (0 - 127)
|
* B - Span (DS1) (0 - 127)
|
||||||
* C - DS1 Explicit bit
|
* C - DS1 Explicit bit
|
||||||
* D - D channel (cis_call) bit (status only)
|
* D - D channel (cis_call) bit (status only)
|
||||||
|
* E - Call is held bit (status only)
|
||||||
*
|
*
|
||||||
* B channel values:
|
* B channel values:
|
||||||
* 0 - No channel (ISDN uses for call waiting feature)
|
* 0 - No channel (ISDN uses for call waiting feature)
|
||||||
@ -567,10 +605,16 @@ struct pri_event_facility {
|
|||||||
char callingnum[256]; /*!< Deprecated, preserved for struct pri_event_facname compatibility */
|
char callingnum[256]; /*!< Deprecated, preserved for struct pri_event_facname compatibility */
|
||||||
int channel;
|
int channel;
|
||||||
int cref;
|
int cref;
|
||||||
|
/*!
|
||||||
|
* \brief Master call or normal call.
|
||||||
|
* \note Call pointer known about by upper layer.
|
||||||
|
* \note NULL if dummy call reference.
|
||||||
|
*/
|
||||||
q931_call *call;
|
q931_call *call;
|
||||||
int callingpres; /*!< Presentation of Calling CallerID (Deprecated, preserved for struct pri_event_facname compatibility) */
|
int callingpres; /*!< Presentation of Calling CallerID (Deprecated, preserved for struct pri_event_facname compatibility) */
|
||||||
int callingplan; /*!< Dialing plan of Calling entity (Deprecated, preserved for struct pri_event_facname compatibility) */
|
int callingplan; /*!< Dialing plan of Calling entity (Deprecated, preserved for struct pri_event_facname compatibility) */
|
||||||
struct pri_subcommands *subcmds;
|
struct pri_subcommands *subcmds;
|
||||||
|
q931_call *subcall; /*!< Subcall to send any reply toward. */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define PRI_CALLINGPLANANI
|
#define PRI_CALLINGPLANANI
|
||||||
@ -609,6 +653,7 @@ typedef struct pri_event_ring {
|
|||||||
struct pri_subcommands *subcmds;
|
struct pri_subcommands *subcmds;
|
||||||
struct pri_party_id calling; /* Calling Party's info, initially subaddress' */
|
struct pri_party_id calling; /* Calling Party's info, initially subaddress' */
|
||||||
struct pri_party_subaddress called_subaddress; /* Called party's subaddress */
|
struct pri_party_subaddress called_subaddress; /* Called party's subaddress */
|
||||||
|
char keypad_digits[64]; /* Keypad digits in the SETUP message. */
|
||||||
} pri_event_ring;
|
} pri_event_ring;
|
||||||
|
|
||||||
typedef struct pri_event_hangup {
|
typedef struct pri_event_hangup {
|
||||||
@ -616,10 +661,22 @@ typedef struct pri_event_hangup {
|
|||||||
int channel; /* Channel requested */
|
int channel; /* Channel requested */
|
||||||
int cause;
|
int cause;
|
||||||
int cref;
|
int cref;
|
||||||
q931_call *call; /* Opaque call pointer */
|
q931_call *call; /* Opaque call pointer of call hanging up. */
|
||||||
long aoc_units; /* Advise of Charge number of charged units */
|
long aoc_units; /* Advise of Charge number of charged units */
|
||||||
char useruserinfo[260]; /* User->User info */
|
char useruserinfo[260]; /* User->User info */
|
||||||
struct pri_subcommands *subcmds;
|
struct pri_subcommands *subcmds;
|
||||||
|
/*!
|
||||||
|
* \brief Opaque held call pointer for possible transfer to active call.
|
||||||
|
* \note The call_held and call_active pointers must not be NULL if
|
||||||
|
* transfer held call on disconnect is available.
|
||||||
|
*/
|
||||||
|
q931_call *call_held;
|
||||||
|
/*!
|
||||||
|
* \brief Opaque active call pointer for possible transfer with held call.
|
||||||
|
* \note The call_held and call_active pointers must not be NULL if
|
||||||
|
* transfer held call on disconnect is available.
|
||||||
|
*/
|
||||||
|
q931_call *call_active;
|
||||||
} pri_event_hangup;
|
} pri_event_hangup;
|
||||||
|
|
||||||
typedef struct pri_event_restart_ack {
|
typedef struct pri_event_restart_ack {
|
||||||
@ -651,6 +708,7 @@ typedef struct pri_event_notify {
|
|||||||
int channel;
|
int channel;
|
||||||
int info;
|
int info;
|
||||||
struct pri_subcommands *subcmds;
|
struct pri_subcommands *subcmds;
|
||||||
|
q931_call *call;
|
||||||
} pri_event_notify;
|
} pri_event_notify;
|
||||||
|
|
||||||
typedef struct pri_event_keypad_digit {
|
typedef struct pri_event_keypad_digit {
|
||||||
@ -673,6 +731,51 @@ typedef struct pri_event_service_ack {
|
|||||||
int changestatus;
|
int changestatus;
|
||||||
} pri_event_service_ack;
|
} pri_event_service_ack;
|
||||||
|
|
||||||
|
struct pri_event_hold {
|
||||||
|
int e;
|
||||||
|
int channel;
|
||||||
|
q931_call *call;
|
||||||
|
struct pri_subcommands *subcmds;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pri_event_hold_ack {
|
||||||
|
int e;
|
||||||
|
int channel;
|
||||||
|
q931_call *call;
|
||||||
|
struct pri_subcommands *subcmds;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pri_event_hold_rej {
|
||||||
|
int e;
|
||||||
|
int channel;
|
||||||
|
q931_call *call;
|
||||||
|
int cause;
|
||||||
|
struct pri_subcommands *subcmds;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pri_event_retrieve {
|
||||||
|
int e;
|
||||||
|
int channel;
|
||||||
|
q931_call *call;
|
||||||
|
int flexible; /* Are we flexible with our channel selection? */
|
||||||
|
struct pri_subcommands *subcmds;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pri_event_retrieve_ack {
|
||||||
|
int e;
|
||||||
|
int channel;
|
||||||
|
q931_call *call;
|
||||||
|
struct pri_subcommands *subcmds;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pri_event_retrieve_rej {
|
||||||
|
int e;
|
||||||
|
int channel;
|
||||||
|
q931_call *call;
|
||||||
|
int cause;
|
||||||
|
struct pri_subcommands *subcmds;
|
||||||
|
};
|
||||||
|
|
||||||
typedef union {
|
typedef union {
|
||||||
int e;
|
int e;
|
||||||
pri_event_generic gen; /* Generic view */
|
pri_event_generic gen; /* Generic view */
|
||||||
@ -691,6 +794,12 @@ typedef union {
|
|||||||
pri_event_service service; /* service message */
|
pri_event_service service; /* service message */
|
||||||
pri_event_service_ack service_ack; /* service acknowledgement message */
|
pri_event_service_ack service_ack; /* service acknowledgement message */
|
||||||
struct pri_event_facility facility;
|
struct pri_event_facility facility;
|
||||||
|
struct pri_event_hold hold;
|
||||||
|
struct pri_event_hold_ack hold_ack;
|
||||||
|
struct pri_event_hold_rej hold_rej;
|
||||||
|
struct pri_event_retrieve retrieve;
|
||||||
|
struct pri_event_retrieve_ack retrieve_ack;
|
||||||
|
struct pri_event_retrieve_rej retrieve_rej;
|
||||||
} pri_event;
|
} pri_event;
|
||||||
|
|
||||||
struct pri;
|
struct pri;
|
||||||
@ -888,6 +997,16 @@ void pri_sr_set_redirecting_parties(struct pri_sr *sr, const struct pri_party_re
|
|||||||
/*! \note Use pri_sr_set_redirecting_parties() instead to pass more precise redirecting information. */
|
/*! \note Use pri_sr_set_redirecting_parties() instead to pass more precise redirecting information. */
|
||||||
int pri_sr_set_redirecting(struct pri_sr *sr, char *num, int plan, int pres, int reason);
|
int pri_sr_set_redirecting(struct pri_sr *sr, char *num, int plan, int pres, int reason);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Set the keypad digits in the call SETUP record.
|
||||||
|
*
|
||||||
|
* \param sr New call SETUP record.
|
||||||
|
* \param keypad_digits Keypad digits to send.
|
||||||
|
*
|
||||||
|
* \return Nothing
|
||||||
|
*/
|
||||||
|
void pri_sr_set_keypad_digits(struct pri_sr *sr, const char *keypad_digits);
|
||||||
|
|
||||||
#define PRI_USER_USER_TX
|
#define PRI_USER_USER_TX
|
||||||
/* Set the user user field. Warning! don't send binary data accross this field */
|
/* Set the user user field. Warning! don't send binary data accross this field */
|
||||||
void pri_sr_set_useruser(struct pri_sr *sr, const char *userchars);
|
void pri_sr_set_useruser(struct pri_sr *sr, const char *userchars);
|
||||||
@ -973,6 +1092,157 @@ int pri_notify(struct pri *pri, q931_call *c, int channel, int info);
|
|||||||
|
|
||||||
int pri_callrerouting_facility(struct pri *pri, q931_call *call, const char *dest, const char* original, const char* reason);
|
int pri_callrerouting_facility(struct pri *pri, q931_call *call, const char *dest, const char* original, const char* reason);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Set the call deflection/rerouting feature enable flag.
|
||||||
|
*
|
||||||
|
* \param ctrl D channel controller.
|
||||||
|
* \param enable TRUE to enable call deflection/rerouting feature.
|
||||||
|
*
|
||||||
|
* \return Nothing
|
||||||
|
*/
|
||||||
|
void pri_reroute_enable(struct pri *ctrl, int enable);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Send the CallRerouting/CallDeflection message.
|
||||||
|
*
|
||||||
|
* \param ctrl D channel controller.
|
||||||
|
* \param call Q.931 call leg.
|
||||||
|
* \param caller Call rerouting/deflecting updated caller data. (NULL if data not updated.)
|
||||||
|
* \param deflection Call rerouting/deflecting redirection data.
|
||||||
|
* \param subscription_option Diverting user subscription option to specify if caller is notified.
|
||||||
|
*
|
||||||
|
* \note
|
||||||
|
* deflection->to is the new called number and must always be present.
|
||||||
|
* \note
|
||||||
|
* subscription option:
|
||||||
|
* noNotification(0),
|
||||||
|
* notificationWithoutDivertedToNr(1),
|
||||||
|
* notificationWithDivertedToNr(2)
|
||||||
|
*
|
||||||
|
* \retval 0 on success.
|
||||||
|
* \retval -1 on error.
|
||||||
|
*/
|
||||||
|
int pri_reroute_call(struct pri *ctrl, q931_call *call, const struct pri_party_id *caller, const struct pri_party_redirecting *deflection, int subscription_option);
|
||||||
|
|
||||||
|
enum PRI_REROUTING_RSP_CODE {
|
||||||
|
/*!
|
||||||
|
* Rerouting invocation accepted and the network provider option
|
||||||
|
* "served user call retention on invocation of diversion"
|
||||||
|
* is "clear call on invocation".
|
||||||
|
*/
|
||||||
|
PRI_REROUTING_RSP_OK_CLEAR,
|
||||||
|
/*!
|
||||||
|
* Rerouting invocation accepted and the network provider option
|
||||||
|
* "served user call retention on invocation of diversion"
|
||||||
|
* is "retain call until alerting begins at the deflected-to user".
|
||||||
|
*/
|
||||||
|
PRI_REROUTING_RSP_OK_RETAIN,
|
||||||
|
PRI_REROUTING_RSP_NOT_SUBSCRIBED,
|
||||||
|
PRI_REROUTING_RSP_NOT_AVAILABLE,
|
||||||
|
/*! Supplementary service interaction not allowed. */
|
||||||
|
PRI_REROUTING_RSP_NOT_ALLOWED,
|
||||||
|
PRI_REROUTING_RSP_INVALID_NUMBER,
|
||||||
|
/*! Deflection to prohibited number (e.g., operator, police, emergency). */
|
||||||
|
PRI_REROUTING_RSP_SPECIAL_SERVICE_NUMBER,
|
||||||
|
/*! Deflection to served user number. */
|
||||||
|
PRI_REROUTING_RSP_DIVERSION_TO_SELF,
|
||||||
|
PRI_REROUTING_RSP_MAX_DIVERSIONS_EXCEEDED,
|
||||||
|
PRI_REROUTING_RSP_RESOURCE_UNAVAILABLE,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Send the CallRerouteing/CallDeflection response message.
|
||||||
|
*
|
||||||
|
* \param ctrl D channel controller.
|
||||||
|
* \param call Q.931 call leg.
|
||||||
|
* \param invoke_id Value given by the initiating request.
|
||||||
|
* \param code The result to send.
|
||||||
|
*
|
||||||
|
* \retval 0 on success.
|
||||||
|
* \retval -1 on error.
|
||||||
|
*/
|
||||||
|
int pri_rerouting_rsp(struct pri *ctrl, q931_call *call, int invoke_id, enum PRI_REROUTING_RSP_CODE code);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Set the call hold feature enable flag.
|
||||||
|
*
|
||||||
|
* \param ctrl D channel controller.
|
||||||
|
* \param enable TRUE to enable call hold feature.
|
||||||
|
*
|
||||||
|
* \return Nothing
|
||||||
|
*/
|
||||||
|
void pri_hold_enable(struct pri *ctrl, int enable);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Send the HOLD message.
|
||||||
|
*
|
||||||
|
* \param ctrl D channel controller.
|
||||||
|
* \param call Q.931 call leg
|
||||||
|
*
|
||||||
|
* \retval 0 on success.
|
||||||
|
* \retval -1 on error.
|
||||||
|
*/
|
||||||
|
int pri_hold(struct pri *ctrl, q931_call *call);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Send the HOLD ACKNOWLEDGE message.
|
||||||
|
*
|
||||||
|
* \param ctrl D channel controller.
|
||||||
|
* \param call Q.931 call leg
|
||||||
|
*
|
||||||
|
* \retval 0 on success.
|
||||||
|
* \retval -1 on error.
|
||||||
|
*/
|
||||||
|
int pri_hold_ack(struct pri *ctrl, q931_call *call);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Send the HOLD REJECT message.
|
||||||
|
*
|
||||||
|
* \param ctrl D channel controller.
|
||||||
|
* \param call Q.931 call leg
|
||||||
|
* \param cause Q.931 cause code for rejecting the hold request.
|
||||||
|
*
|
||||||
|
* \retval 0 on success.
|
||||||
|
* \retval -1 on error.
|
||||||
|
*/
|
||||||
|
int pri_hold_rej(struct pri *ctrl, q931_call *call, int cause);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Send the RETRIEVE message.
|
||||||
|
*
|
||||||
|
* \param ctrl D channel controller.
|
||||||
|
* \param call Q.931 call leg
|
||||||
|
* \param channel Encoded channel id to use. If zero do not send channel id.
|
||||||
|
*
|
||||||
|
* \retval 0 on success.
|
||||||
|
* \retval -1 on error.
|
||||||
|
*/
|
||||||
|
int pri_retrieve(struct pri *ctrl, q931_call *call, int channel);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Send the RETRIEVE ACKNOWLEDGE message.
|
||||||
|
*
|
||||||
|
* \param ctrl D channel controller.
|
||||||
|
* \param call Q.931 call leg
|
||||||
|
* \param channel Encoded channel id to use.
|
||||||
|
*
|
||||||
|
* \retval 0 on success.
|
||||||
|
* \retval -1 on error.
|
||||||
|
*/
|
||||||
|
int pri_retrieve_ack(struct pri *ctrl, q931_call *call, int channel);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Send the RETRIEVE REJECT message.
|
||||||
|
*
|
||||||
|
* \param ctrl D channel controller.
|
||||||
|
* \param call Q.931 call leg
|
||||||
|
* \param cause Q.931 cause code for rejecting the retrieve request.
|
||||||
|
*
|
||||||
|
* \retval 0 on success.
|
||||||
|
* \retval -1 on error.
|
||||||
|
*/
|
||||||
|
int pri_retrieve_rej(struct pri *ctrl, q931_call *call, int cause);
|
||||||
|
|
||||||
/* Get/Set PRI Timers */
|
/* Get/Set PRI Timers */
|
||||||
#define PRI_GETSET_TIMERS
|
#define PRI_GETSET_TIMERS
|
||||||
int pri_set_timer(struct pri *pri, int timer, int value);
|
int pri_set_timer(struct pri *pri, int timer, int value);
|
||||||
@ -1015,6 +1285,9 @@ enum PRI_TIMERS_AND_COUNTERS {
|
|||||||
PRI_TIMER_TM20, /*!< Maximum time awaiting XID response */
|
PRI_TIMER_TM20, /*!< Maximum time awaiting XID response */
|
||||||
PRI_TIMER_NM20, /*!< Number of XID retransmits */
|
PRI_TIMER_NM20, /*!< Number of XID retransmits */
|
||||||
|
|
||||||
|
PRI_TIMER_T_HOLD, /*!< Maximum time to wait for HOLD request response. */
|
||||||
|
PRI_TIMER_T_RETRIEVE, /*!< Maximum time to wait for RETRIEVE request response. */
|
||||||
|
|
||||||
/* Must be last in the enum list */
|
/* Must be last in the enum list */
|
||||||
_PRI_MAX_TIMERS,
|
_PRI_MAX_TIMERS,
|
||||||
PRI_MAX_TIMERS = (_PRI_MAX_TIMERS < 32) ? 32 : _PRI_MAX_TIMERS
|
PRI_MAX_TIMERS = (_PRI_MAX_TIMERS < 32) ? 32 : _PRI_MAX_TIMERS
|
||||||
|
178
pri.c
178
pri.c
@ -86,6 +86,8 @@ static const struct pri_timer_table pri_timer[] = {
|
|||||||
{ "T320", PRI_TIMER_T320, PRI_ALL_SWITCHES },
|
{ "T320", PRI_TIMER_T320, PRI_ALL_SWITCHES },
|
||||||
{ "T321", PRI_TIMER_T321, PRI_ALL_SWITCHES },
|
{ "T321", PRI_TIMER_T321, PRI_ALL_SWITCHES },
|
||||||
{ "T322", PRI_TIMER_T322, PRI_ALL_SWITCHES },
|
{ "T322", PRI_TIMER_T322, PRI_ALL_SWITCHES },
|
||||||
|
{ "T-HOLD", PRI_TIMER_T_HOLD, PRI_ALL_SWITCHES },
|
||||||
|
{ "T-RETRIEVE", PRI_TIMER_T_RETRIEVE, PRI_ALL_SWITCHES },
|
||||||
/* *INDENT-ON* */
|
/* *INDENT-ON* */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -150,6 +152,10 @@ static void pri_default_timers(struct pri *ctrl, int switchtype)
|
|||||||
ctrl->timers[PRI_TIMER_T313] = 4 * 1000; /* Wait for CONNECT acknowledge, CPE side only */
|
ctrl->timers[PRI_TIMER_T313] = 4 * 1000; /* Wait for CONNECT acknowledge, CPE side only */
|
||||||
ctrl->timers[PRI_TIMER_TM20] = 2500; /* Max time awaiting XID response - Q.921 Appendix IV */
|
ctrl->timers[PRI_TIMER_TM20] = 2500; /* Max time awaiting XID response - Q.921 Appendix IV */
|
||||||
ctrl->timers[PRI_TIMER_NM20] = 3; /* Number of XID retransmits - Q.921 Appendix IV */
|
ctrl->timers[PRI_TIMER_NM20] = 3; /* Number of XID retransmits - Q.921 Appendix IV */
|
||||||
|
ctrl->timers[PRI_TIMER_T303] = 4 * 1000; /* Length between SETUP retransmissions and timeout */
|
||||||
|
|
||||||
|
ctrl->timers[PRI_TIMER_T_HOLD] = 4 * 1000; /* Wait for HOLD request response. */
|
||||||
|
ctrl->timers[PRI_TIMER_T_RETRIEVE] = 4 * 1000;/* Wait for RETRIEVE request response. */
|
||||||
|
|
||||||
/* Set any switch specific override default values */
|
/* Set any switch specific override default values */
|
||||||
switch (switchtype) {
|
switch (switchtype) {
|
||||||
@ -381,6 +387,12 @@ char *pri_event2str(int id)
|
|||||||
{ PRI_EVENT_KEYPAD_DIGIT, "Keypad Digit" },
|
{ PRI_EVENT_KEYPAD_DIGIT, "Keypad Digit" },
|
||||||
{ PRI_EVENT_SERVICE, "Service" },
|
{ PRI_EVENT_SERVICE, "Service" },
|
||||||
{ PRI_EVENT_SERVICE_ACK, "Service ACK" },
|
{ PRI_EVENT_SERVICE_ACK, "Service ACK" },
|
||||||
|
{ PRI_EVENT_HOLD, "Hold" },
|
||||||
|
{ PRI_EVENT_HOLD_ACK, "Hold Ack" },
|
||||||
|
{ PRI_EVENT_HOLD_REJ, "Hold Rej" },
|
||||||
|
{ PRI_EVENT_RETRIEVE, "Retrieve" },
|
||||||
|
{ PRI_EVENT_RETRIEVE_ACK, "Retrieve ACK" },
|
||||||
|
{ PRI_EVENT_RETRIEVE_REJ, "Retrieve Rej" },
|
||||||
/* *INDENT-ON* */
|
/* *INDENT-ON* */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -539,15 +551,6 @@ int pri_keypad_facility(struct pri *pri, q931_call *call, const char *digits)
|
|||||||
return q931_keypad_facility(pri, call, digits);
|
return q931_keypad_facility(pri, call, digits);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int pri_callrerouting_facility(struct pri *pri, q931_call *call, const char *dest, const char* original, const char* reason)
|
|
||||||
{
|
|
||||||
if (!pri || !call)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return qsig_cf_callrerouting(pri, call, dest, original, reason);
|
|
||||||
}
|
|
||||||
|
|
||||||
int pri_notify(struct pri *pri, q931_call *call, int channel, int info)
|
int pri_notify(struct pri *pri, q931_call *call, int channel, int info)
|
||||||
{
|
{
|
||||||
if (!pri || !call)
|
if (!pri || !call)
|
||||||
@ -558,7 +561,7 @@ int pri_notify(struct pri *pri, q931_call *call, int channel, int info)
|
|||||||
void pri_destroycall(struct pri *pri, q931_call *call)
|
void pri_destroycall(struct pri *pri, q931_call *call)
|
||||||
{
|
{
|
||||||
if (pri && call)
|
if (pri && call)
|
||||||
__q931_destroycall(pri, call);
|
q931_destroycall(pri, call);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -669,6 +672,8 @@ static void pri_copy_party_id_to_q931(struct q931_party_id *q931_id, const struc
|
|||||||
int pri_connected_line_update(struct pri *ctrl, q931_call *call, const struct pri_party_connected_line *connected)
|
int pri_connected_line_update(struct pri *ctrl, q931_call *call, const struct pri_party_connected_line *connected)
|
||||||
{
|
{
|
||||||
struct q931_party_id party_id;
|
struct q931_party_id party_id;
|
||||||
|
unsigned idx;
|
||||||
|
struct q931_call *subcall;
|
||||||
|
|
||||||
if (!ctrl || !call) {
|
if (!ctrl || !call) {
|
||||||
return -1;
|
return -1;
|
||||||
@ -682,6 +687,16 @@ int pri_connected_line_update(struct pri *ctrl, q931_call *call, const struct pr
|
|||||||
}
|
}
|
||||||
call->local_id = party_id;
|
call->local_id = party_id;
|
||||||
|
|
||||||
|
/* Update all subcalls with new local_id. */
|
||||||
|
if (call->outboundbroadcast && call->master_call == call) {
|
||||||
|
for (idx = 0; idx < Q931_MAX_TEI; ++idx) {
|
||||||
|
subcall = call->subcalls[idx];
|
||||||
|
if (subcall) {
|
||||||
|
subcall->local_id = party_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch (call->ourcallstate) {
|
switch (call->ourcallstate) {
|
||||||
case Q931_CALL_STATE_CALL_INITIATED:
|
case Q931_CALL_STATE_CALL_INITIATED:
|
||||||
case Q931_CALL_STATE_OVERLAP_SENDING:
|
case Q931_CALL_STATE_OVERLAP_SENDING:
|
||||||
@ -723,6 +738,9 @@ int pri_connected_line_update(struct pri *ctrl, q931_call *call, const struct pr
|
|||||||
|
|
||||||
int pri_redirecting_update(struct pri *ctrl, q931_call *call, const struct pri_party_redirecting *redirecting)
|
int pri_redirecting_update(struct pri *ctrl, q931_call *call, const struct pri_party_redirecting *redirecting)
|
||||||
{
|
{
|
||||||
|
unsigned idx;
|
||||||
|
struct q931_call *subcall;
|
||||||
|
|
||||||
if (!ctrl || !call) {
|
if (!ctrl || !call) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -732,6 +750,21 @@ int pri_redirecting_update(struct pri *ctrl, q931_call *call, const struct pri_p
|
|||||||
q931_party_id_fixup(ctrl, &call->redirecting.to);
|
q931_party_id_fixup(ctrl, &call->redirecting.to);
|
||||||
call->redirecting.reason = redirecting->reason;
|
call->redirecting.reason = redirecting->reason;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Update all subcalls with new redirecting.to information and reason.
|
||||||
|
* I do not think we will ever have any subcalls when this data is relevant,
|
||||||
|
* but update it just in case.
|
||||||
|
*/
|
||||||
|
if (call->outboundbroadcast && call->master_call == call) {
|
||||||
|
for (idx = 0; idx < Q931_MAX_TEI; ++idx) {
|
||||||
|
subcall = call->subcalls[idx];
|
||||||
|
if (subcall) {
|
||||||
|
subcall->redirecting.to = call->redirecting.to;
|
||||||
|
subcall->redirecting.reason = redirecting->reason;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch (call->ourcallstate) {
|
switch (call->ourcallstate) {
|
||||||
case Q931_CALL_STATE_NULL:
|
case Q931_CALL_STATE_NULL:
|
||||||
/* Save the remaining redirecting information before we place a call. */
|
/* Save the remaining redirecting information before we place a call. */
|
||||||
@ -1046,7 +1079,7 @@ void pri_message(struct pri *pri, char *fmt, ...)
|
|||||||
vsnprintf(tmp, sizeof(tmp), fmt, ap);
|
vsnprintf(tmp, sizeof(tmp), fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
if (__pri_message)
|
if (__pri_message)
|
||||||
__pri_message(pri, tmp);
|
__pri_message(PRI_MASTER(pri), tmp);
|
||||||
else
|
else
|
||||||
fputs(tmp, stdout);
|
fputs(tmp, stdout);
|
||||||
}
|
}
|
||||||
@ -1059,7 +1092,7 @@ void pri_error(struct pri *pri, char *fmt, ...)
|
|||||||
vsnprintf(tmp, sizeof(tmp), fmt, ap);
|
vsnprintf(tmp, sizeof(tmp), fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
if (__pri_error)
|
if (__pri_error)
|
||||||
__pri_error(pri, tmp);
|
__pri_error(PRI_MASTER(pri), tmp);
|
||||||
else
|
else
|
||||||
fputs(tmp, stderr);
|
fputs(tmp, stderr);
|
||||||
}
|
}
|
||||||
@ -1320,3 +1353,124 @@ void pri_sr_set_reversecharge(struct pri_sr *sr, int requested)
|
|||||||
{
|
{
|
||||||
sr->reversecharge = requested;
|
sr->reversecharge = requested;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pri_sr_set_keypad_digits(struct pri_sr *sr, const char *keypad_digits)
|
||||||
|
{
|
||||||
|
sr->keypad_digits = keypad_digits;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pri_hold_enable(struct pri *ctrl, int enable)
|
||||||
|
{
|
||||||
|
ctrl = PRI_MASTER(ctrl);
|
||||||
|
if (ctrl) {
|
||||||
|
ctrl->hold_support = enable ? 1 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int pri_hold(struct pri *ctrl, q931_call *call)
|
||||||
|
{
|
||||||
|
if (!ctrl || !call) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return q931_send_hold(ctrl, call);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pri_hold_ack(struct pri *ctrl, q931_call *call)
|
||||||
|
{
|
||||||
|
if (!ctrl || !call) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return q931_send_hold_ack(ctrl, call);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pri_hold_rej(struct pri *ctrl, q931_call *call, int cause)
|
||||||
|
{
|
||||||
|
if (!ctrl || !call) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return q931_send_hold_rej(ctrl, call, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pri_retrieve(struct pri *ctrl, q931_call *call, int channel)
|
||||||
|
{
|
||||||
|
if (!ctrl || !call) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return q931_send_retrieve(ctrl, call, channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pri_retrieve_ack(struct pri *ctrl, q931_call *call, int channel)
|
||||||
|
{
|
||||||
|
if (!ctrl || !call) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return q931_send_retrieve_ack(ctrl, call, channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pri_retrieve_rej(struct pri *ctrl, q931_call *call, int cause)
|
||||||
|
{
|
||||||
|
if (!ctrl || !call) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return q931_send_retrieve_rej(ctrl, call, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pri_callrerouting_facility(struct pri *pri, q931_call *call, const char *dest, const char* original, const char* reason)
|
||||||
|
{
|
||||||
|
if (!pri || !call || !dest)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return qsig_cf_callrerouting(pri, call, dest, original, reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pri_reroute_enable(struct pri *ctrl, int enable)
|
||||||
|
{
|
||||||
|
ctrl = PRI_MASTER(ctrl);
|
||||||
|
if (ctrl) {
|
||||||
|
ctrl->deflection_support = enable ? 1 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int pri_reroute_call(struct pri *ctrl, q931_call *call, const struct pri_party_id *caller, const struct pri_party_redirecting *deflection, int subscription_option)
|
||||||
|
{
|
||||||
|
const struct q931_party_id *caller_id;
|
||||||
|
struct q931_party_id local_caller;
|
||||||
|
struct q931_party_redirecting reroute;
|
||||||
|
|
||||||
|
if (!ctrl || !call || !deflection) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (caller) {
|
||||||
|
/* Convert the caller update information. */
|
||||||
|
pri_copy_party_id_to_q931(&local_caller, caller);
|
||||||
|
q931_party_id_fixup(ctrl, &local_caller);
|
||||||
|
caller_id = &local_caller;
|
||||||
|
} else {
|
||||||
|
caller_id = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert the deflection information. */
|
||||||
|
q931_party_redirecting_init(&reroute);
|
||||||
|
pri_copy_party_id_to_q931(&reroute.from, &deflection->from);
|
||||||
|
q931_party_id_fixup(ctrl, &reroute.from);
|
||||||
|
pri_copy_party_id_to_q931(&reroute.to, &deflection->to);
|
||||||
|
q931_party_id_fixup(ctrl, &reroute.to);
|
||||||
|
pri_copy_party_id_to_q931(&reroute.orig_called, &deflection->orig_called);
|
||||||
|
q931_party_id_fixup(ctrl, &reroute.orig_called);
|
||||||
|
reroute.reason = deflection->reason;
|
||||||
|
reroute.orig_reason = deflection->orig_reason;
|
||||||
|
if (deflection->count <= 0) {
|
||||||
|
/*
|
||||||
|
* We are deflecting with an unknown count
|
||||||
|
* so assume the count is one.
|
||||||
|
*/
|
||||||
|
reroute.count = 1;
|
||||||
|
} else if (deflection->count < PRI_MAX_REDIRECTS) {
|
||||||
|
reroute.count = deflection->count;
|
||||||
|
} else {
|
||||||
|
reroute.count = PRI_MAX_REDIRECTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return send_reroute_request(ctrl, call, caller_id, &reroute, subscription_option);
|
||||||
|
}
|
||||||
|
954
pri_facility.c
954
pri_facility.c
File diff suppressed because it is too large
Load Diff
@ -74,6 +74,7 @@ int eect_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2);
|
|||||||
int rlt_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2);
|
int rlt_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2);
|
||||||
|
|
||||||
int qsig_cf_callrerouting(struct pri *pri, q931_call *c, const char* dest, const char* original, const char* reason);
|
int qsig_cf_callrerouting(struct pri *pri, q931_call *c, const char* dest, const char* original, const char* reason);
|
||||||
|
int send_reroute_request(struct pri *ctrl, q931_call *call, const struct q931_party_id *caller, const struct q931_party_redirecting *deflection, int subscription_option);
|
||||||
|
|
||||||
/* starts a QSIG Path Replacement */
|
/* starts a QSIG Path Replacement */
|
||||||
int anfpr_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2);
|
int anfpr_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2);
|
||||||
@ -106,9 +107,9 @@ struct rose_msg_result;
|
|||||||
struct rose_msg_error;
|
struct rose_msg_error;
|
||||||
struct rose_msg_reject;
|
struct rose_msg_reject;
|
||||||
|
|
||||||
void rose_handle_invoke(struct pri *ctrl, q931_call *call, q931_ie *ie, const struct fac_extension_header *header, const struct rose_msg_invoke *invoke);
|
void rose_handle_invoke(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, const struct fac_extension_header *header, const struct rose_msg_invoke *invoke);
|
||||||
void rose_handle_result(struct pri *ctrl, q931_call *call, q931_ie *ie, const struct fac_extension_header *header, const struct rose_msg_result *result);
|
void rose_handle_result(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, const struct fac_extension_header *header, const struct rose_msg_result *result);
|
||||||
void rose_handle_error(struct pri *ctrl, q931_call *call, q931_ie *ie, const struct fac_extension_header *header, const struct rose_msg_error *error);
|
void rose_handle_error(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, const struct fac_extension_header *header, const struct rose_msg_error *error);
|
||||||
void rose_handle_reject(struct pri *ctrl, q931_call *call, q931_ie *ie, const struct fac_extension_header *header, const struct rose_msg_reject *reject);
|
void rose_handle_reject(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, const struct fac_extension_header *header, const struct rose_msg_reject *reject);
|
||||||
|
|
||||||
#endif /* _PRI_FACILITY_H */
|
#endif /* _PRI_FACILITY_H */
|
||||||
|
@ -70,7 +70,9 @@ struct pri {
|
|||||||
int protodisc;
|
int protodisc;
|
||||||
unsigned int bri:1;
|
unsigned int bri:1;
|
||||||
unsigned int acceptinbanddisconnect:1; /* Should we allow inband progress after DISCONNECT? */
|
unsigned int acceptinbanddisconnect:1; /* Should we allow inband progress after DISCONNECT? */
|
||||||
|
unsigned int hold_support:1;/* TRUE if upper layer supports call hold. */
|
||||||
|
unsigned int deflection_support:1;/* TRUE if upper layer supports call deflection/rerouting. */
|
||||||
|
|
||||||
/* Q.921 State */
|
/* Q.921 State */
|
||||||
int q921_state;
|
int q921_state;
|
||||||
int window; /* Max window size */
|
int window; /* Max window size */
|
||||||
@ -287,6 +289,7 @@ struct pri_sr {
|
|||||||
int cis_call;
|
int cis_call;
|
||||||
int cis_auto_disconnect;
|
int cis_auto_disconnect;
|
||||||
const char *useruserinfo;
|
const char *useruserinfo;
|
||||||
|
const char *keypad_digits;
|
||||||
int transferable;
|
int transferable;
|
||||||
int reversecharge;
|
int reversecharge;
|
||||||
};
|
};
|
||||||
@ -295,6 +298,8 @@ struct pri_sr {
|
|||||||
#define PRI_SWITCH_GR303_EOC_PATH 19
|
#define PRI_SWITCH_GR303_EOC_PATH 19
|
||||||
#define PRI_SWITCH_GR303_TMC_SWITCHING 20
|
#define PRI_SWITCH_GR303_TMC_SWITCHING 20
|
||||||
|
|
||||||
|
#define Q931_MAX_TEI 8
|
||||||
|
|
||||||
struct apdu_event {
|
struct apdu_event {
|
||||||
int message; /* What message to send the ADPU in */
|
int message; /* What message to send the ADPU in */
|
||||||
void (*callback)(void *data); /* Callback function for when response is received */
|
void (*callback)(void *data); /* Callback function for when response is received */
|
||||||
@ -327,6 +332,22 @@ enum INCOMING_CT_STATE {
|
|||||||
INCOMING_CT_STATE_POST_CONNECTED_LINE
|
INCOMING_CT_STATE_POST_CONNECTED_LINE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*! Call hold supplementary states. */
|
||||||
|
enum Q931_HOLD_STATE {
|
||||||
|
/*! \brief No call hold activity. */
|
||||||
|
Q931_HOLD_STATE_IDLE,
|
||||||
|
/*! \brief Request made to hold call. */
|
||||||
|
Q931_HOLD_STATE_HOLD_REQ,
|
||||||
|
/*! \brief Request received to hold call. */
|
||||||
|
Q931_HOLD_STATE_HOLD_IND,
|
||||||
|
/*! \brief Call is held. */
|
||||||
|
Q931_HOLD_STATE_CALL_HELD,
|
||||||
|
/*! \brief Request made to retrieve call. */
|
||||||
|
Q931_HOLD_STATE_RETRIEVE_REQ,
|
||||||
|
/*! \brief Request received to retrieve call. */
|
||||||
|
Q931_HOLD_STATE_RETRIEVE_IND,
|
||||||
|
};
|
||||||
|
|
||||||
/* q931_call datastructure */
|
/* q931_call datastructure */
|
||||||
struct q931_call {
|
struct q931_call {
|
||||||
struct pri *pri; /* PRI */
|
struct pri *pri; /* PRI */
|
||||||
@ -442,6 +463,12 @@ struct q931_call {
|
|||||||
|
|
||||||
/*! \brief Incoming call transfer state. */
|
/*! \brief Incoming call transfer state. */
|
||||||
enum INCOMING_CT_STATE incoming_ct_state;
|
enum INCOMING_CT_STATE incoming_ct_state;
|
||||||
|
/*! Call hold supplementary state. */
|
||||||
|
enum Q931_HOLD_STATE hold_state;
|
||||||
|
/*! Call hold event timer */
|
||||||
|
int hold_timer;
|
||||||
|
|
||||||
|
int deflection_in_progress; /*!< CallDeflection for NT PTMP in progress. */
|
||||||
|
|
||||||
int useruserprotocoldisc;
|
int useruserprotocoldisc;
|
||||||
char useruserinfo[256];
|
char useruserinfo[256];
|
||||||
@ -462,6 +489,22 @@ struct q931_call {
|
|||||||
-1 - No reverse charging
|
-1 - No reverse charging
|
||||||
1 - Reverse charging
|
1 - Reverse charging
|
||||||
0,2-7 - Reserved for future use */
|
0,2-7 - Reserved for future use */
|
||||||
|
int t303_timer;
|
||||||
|
int t303_expirycnt;
|
||||||
|
|
||||||
|
int hangupinitiated;
|
||||||
|
/*! \brief TRUE if we broadcast this call's SETUP message. */
|
||||||
|
int outboundbroadcast;
|
||||||
|
int performing_fake_clearing;
|
||||||
|
/*!
|
||||||
|
* \brief Master call controlling this call.
|
||||||
|
* \note Always valid. Master and normal calls point to self.
|
||||||
|
*/
|
||||||
|
struct q931_call *master_call;
|
||||||
|
|
||||||
|
/* These valid in master call only */
|
||||||
|
struct q931_call *subcalls[Q931_MAX_TEI];
|
||||||
|
int pri_winner;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern int pri_schedule_event(struct pri *pri, int ms, void (*function)(void *data), void *data);
|
extern int pri_schedule_event(struct pri *pri, int ms, void (*function)(void *data), void *data);
|
||||||
@ -484,6 +527,11 @@ void __pri_free_tei(struct pri *p);
|
|||||||
void q931_party_name_init(struct q931_party_name *name);
|
void q931_party_name_init(struct q931_party_name *name);
|
||||||
void q931_party_number_init(struct q931_party_number *number);
|
void q931_party_number_init(struct q931_party_number *number);
|
||||||
void q931_party_subaddress_init(struct q931_party_subaddress *subaddr);
|
void q931_party_subaddress_init(struct q931_party_subaddress *subaddr);
|
||||||
|
#define q931_party_address_to_id(q931_id, q931_address) \
|
||||||
|
do { \
|
||||||
|
(q931_id)->number = (q931_address)->number; \
|
||||||
|
/*(q931_id)->subaddress = (q931_address)->subaddress;*/ \
|
||||||
|
} while (0)
|
||||||
void q931_party_address_init(struct q931_party_address *address);
|
void q931_party_address_init(struct q931_party_address *address);
|
||||||
void q931_party_id_init(struct q931_party_id *id);
|
void q931_party_id_init(struct q931_party_id *id);
|
||||||
void q931_party_redirecting_init(struct q931_party_redirecting *redirecting);
|
void q931_party_redirecting_init(struct q931_party_redirecting *redirecting);
|
||||||
@ -505,8 +553,40 @@ int q931_party_id_presentation(const struct q931_party_id *id);
|
|||||||
const char *q931_call_state_str(enum Q931_CALL_STATE callstate);
|
const char *q931_call_state_str(enum Q931_CALL_STATE callstate);
|
||||||
|
|
||||||
int q931_is_ptmp(const struct pri *ctrl);
|
int q931_is_ptmp(const struct pri *ctrl);
|
||||||
|
int q931_master_pass_event(struct pri *ctrl, struct q931_call *subcall, int msg_type);
|
||||||
struct pri_subcommand *q931_alloc_subcommand(struct pri *ctrl);
|
struct pri_subcommand *q931_alloc_subcommand(struct pri *ctrl);
|
||||||
|
|
||||||
int q931_notify_redirection(struct pri *ctrl, q931_call *call, int notify, const struct q931_party_number *number);
|
int q931_notify_redirection(struct pri *ctrl, q931_call *call, int notify, const struct q931_party_number *number);
|
||||||
|
|
||||||
|
static inline struct pri * PRI_MASTER(struct pri *mypri)
|
||||||
|
{
|
||||||
|
struct pri *pri = mypri;
|
||||||
|
|
||||||
|
if (!pri)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
while (pri->master)
|
||||||
|
pri = pri->master;
|
||||||
|
|
||||||
|
return pri;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int BRI_NT_PTMP(struct pri *mypri)
|
||||||
|
{
|
||||||
|
struct pri *pri;
|
||||||
|
|
||||||
|
pri = PRI_MASTER(mypri);
|
||||||
|
|
||||||
|
return pri->bri && (((pri)->localtype == PRI_NETWORK) && ((pri)->tei == Q921_TEI_GROUP));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int BRI_TE_PTMP(struct pri *mypri)
|
||||||
|
{
|
||||||
|
struct pri *pri;
|
||||||
|
|
||||||
|
pri = PRI_MASTER(mypri);
|
||||||
|
|
||||||
|
return pri->bri && (((pri)->localtype == PRI_CPE) && ((pri)->tei == Q921_TEI_GROUP));
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -192,6 +192,8 @@ extern pri_event *q921_receive(struct pri *pri, q921_h *h, int len);
|
|||||||
|
|
||||||
extern int q921_transmit_iframe(struct pri *pri, void *buf, int len, int cr);
|
extern int q921_transmit_iframe(struct pri *pri, void *buf, int len, int cr);
|
||||||
|
|
||||||
|
extern int q921_transmit_uiframe(struct pri *pri, void *buf, int len);
|
||||||
|
|
||||||
extern pri_event *q921_dchannel_up(struct pri *pri);
|
extern pri_event *q921_dchannel_up(struct pri *pri);
|
||||||
|
|
||||||
extern pri_event *q921_dchannel_down(struct pri *pri);
|
extern pri_event *q921_dchannel_down(struct pri *pri);
|
||||||
|
26
pri_q931.h
26
pri_q931.h
@ -424,6 +424,22 @@ enum Q931_CALL_STATE {
|
|||||||
Q931_CALL_STATE_NOT_SET = 0xFF,
|
Q931_CALL_STATE_NOT_SET = 0xFF,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*! Q.931 call establishment state ranking for competing calls in PTMP NT mode. */
|
||||||
|
enum Q931_RANKED_CALL_STATE {
|
||||||
|
/*! Call is present but has no response yet. */
|
||||||
|
Q931_RANKED_CALL_STATE_PRESENT,
|
||||||
|
/*! Call is collecting digits. */
|
||||||
|
Q931_RANKED_CALL_STATE_OVERLAP,
|
||||||
|
/*! Call routing is happening. */
|
||||||
|
Q931_RANKED_CALL_STATE_PROCEEDING,
|
||||||
|
/*! Called party is being alerted of the call. */
|
||||||
|
Q931_RANKED_CALL_STATE_ALERTING,
|
||||||
|
/*! Call is connected. A winner has been declared. */
|
||||||
|
Q931_RANKED_CALL_STATE_CONNECT,
|
||||||
|
/*! Call is in some non-call establishment state (likely disconnecting). */
|
||||||
|
Q931_RANKED_CALL_STATE_OTHER,
|
||||||
|
};
|
||||||
|
|
||||||
/* EuroISDN */
|
/* EuroISDN */
|
||||||
#define Q931_SENDING_COMPLETE 0xa1
|
#define Q931_SENDING_COMPLETE 0xa1
|
||||||
|
|
||||||
@ -474,8 +490,16 @@ extern q931_call *q931_new_call(struct pri *pri);
|
|||||||
extern int q931_setup(struct pri *pri, q931_call *c, struct pri_sr *req);
|
extern int q931_setup(struct pri *pri, q931_call *c, struct pri_sr *req);
|
||||||
extern void q931_dump(struct pri *pri, q931_h *h, int len, int txrx);
|
extern void q931_dump(struct pri *pri, q931_h *h, int len, int txrx);
|
||||||
|
|
||||||
extern void __q931_destroycall(struct pri *pri, q931_call *c);
|
void q931_destroycall(struct pri *pri, q931_call *c);
|
||||||
|
|
||||||
extern void q931_dl_indication(struct pri *pri, int event);
|
extern void q931_dl_indication(struct pri *pri, int event);
|
||||||
|
|
||||||
|
int q931_send_hold(struct pri *ctrl, struct q931_call *call);
|
||||||
|
int q931_send_hold_ack(struct pri *ctrl, struct q931_call *call);
|
||||||
|
int q931_send_hold_rej(struct pri *ctrl, struct q931_call *call, int cause);
|
||||||
|
|
||||||
|
int q931_send_retrieve(struct pri *ctrl, struct q931_call *call, int channel);
|
||||||
|
int q931_send_retrieve_ack(struct pri *ctrl, struct q931_call *call, int channel);
|
||||||
|
int q931_send_retrieve_rej(struct pri *ctrl, struct q931_call *call, int cause);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
128
q921.c
128
q921.c
@ -27,6 +27,7 @@
|
|||||||
* terms granted here.
|
* terms granted here.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -477,6 +478,45 @@ static void t200_expire(void *vpri)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int q921_transmit_uiframe(struct pri *pri, void *buf, int len)
|
||||||
|
{
|
||||||
|
uint8_t ubuf[512];
|
||||||
|
q921_h *h = (void *)&ubuf[0];
|
||||||
|
|
||||||
|
if (len >= 512) {
|
||||||
|
pri_error(pri, "Requested to send UI frame larger than 512 bytes!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(ubuf, 0, sizeof(ubuf));
|
||||||
|
h->h.sapi = 0;
|
||||||
|
h->h.ea1 = 0;
|
||||||
|
h->h.ea2 = 1;
|
||||||
|
h->h.tei = pri->tei;
|
||||||
|
h->u.m3 = 0;
|
||||||
|
h->u.m2 = 0;
|
||||||
|
h->u.p_f = 0; /* Poll bit set */
|
||||||
|
h->u.ft = Q921_FRAMETYPE_U;
|
||||||
|
|
||||||
|
switch(pri->localtype) {
|
||||||
|
case PRI_NETWORK:
|
||||||
|
h->h.c_r = 1;
|
||||||
|
break;
|
||||||
|
case PRI_CPE:
|
||||||
|
h->h.c_r = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
pri_error(pri, "Don't know how to U/A on a type %d node\n", pri->localtype);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(h->u.data, buf, len);
|
||||||
|
|
||||||
|
q921_transmit(pri, h, len + 3);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int q921_transmit_iframe(struct pri *pri, void *buf, int len, int cr)
|
int q921_transmit_iframe(struct pri *pri, void *buf, int len, int cr)
|
||||||
{
|
{
|
||||||
q921_frame *f, *prev=NULL;
|
q921_frame *f, *prev=NULL;
|
||||||
@ -515,6 +555,10 @@ int q921_transmit_iframe(struct pri *pri, void *buf, int len, int cr)
|
|||||||
pri->txqueue = f;
|
pri->txqueue = f;
|
||||||
/* Immediately transmit unless we're in a recovery state, or the window
|
/* Immediately transmit unless we're in a recovery state, or the window
|
||||||
size is too big */
|
size is too big */
|
||||||
|
if (pri->debug & PRI_DEBUG_Q921_DUMP) {
|
||||||
|
pri_message(pri, "TEI/SAPI: %d/%d state %d retran %d busy %d\n",
|
||||||
|
pri->tei, pri->sapi, pri->q921_state, pri->retrans, pri->busy);
|
||||||
|
}
|
||||||
if ((pri->q921_state == Q921_LINK_CONNECTION_ESTABLISHED) && (!pri->retrans && !pri->busy)) {
|
if ((pri->q921_state == Q921_LINK_CONNECTION_ESTABLISHED) && (!pri->retrans && !pri->busy)) {
|
||||||
if (pri->windowlen < pri->window) {
|
if (pri->windowlen < pri->window) {
|
||||||
q921_send_queued_iframes(pri);
|
q921_send_queued_iframes(pri);
|
||||||
@ -558,11 +602,15 @@ static void t203_expire(void *vpri)
|
|||||||
/* Start timer T200 to resend our RR if we don't get it */
|
/* Start timer T200 to resend our RR if we don't get it */
|
||||||
pri->t203_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri);
|
pri->t203_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri);
|
||||||
} else {
|
} else {
|
||||||
if (pri->debug & PRI_DEBUG_Q921_DUMP)
|
if (pri->debug & PRI_DEBUG_Q921_DUMP) {
|
||||||
pri_message(pri, "T203 counter expired in weird state %d\n", pri->q921_state);
|
pri_message(pri,
|
||||||
|
"T203 counter expired in weird state %d on pri with SAPI/TEI of %d/%d\n",
|
||||||
|
pri->q921_state, pri->sapi, pri->tei);
|
||||||
|
}
|
||||||
pri->t203_timer = 0;
|
pri->t203_timer = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static pri_event *q921_handle_iframe(struct pri *pri, q921_i *i, int len)
|
static pri_event *q921_handle_iframe(struct pri *pri, q921_i *i, int len)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
@ -879,8 +927,14 @@ static void q921_tei_release_and_reacquire(struct pri *master)
|
|||||||
static pri_event *q921_receive_MDL(struct pri *pri, q921_u *h, int len)
|
static pri_event *q921_receive_MDL(struct pri *pri, q921_u *h, int len)
|
||||||
{
|
{
|
||||||
int ri;
|
int ri;
|
||||||
struct pri *sub;
|
struct pri *sub = pri;
|
||||||
int tei;
|
int tei;
|
||||||
|
|
||||||
|
if (!BRI_NT_PTMP(pri) && !BRI_TE_PTMP(pri)) {
|
||||||
|
pri_error(pri, "Received MDL/TEI managemement message, but configured for mode other than PTMP!\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (pri->debug & PRI_DEBUG_Q921_STATE)
|
if (pri->debug & PRI_DEBUG_Q921_STATE)
|
||||||
pri_message(pri, "Received MDL message\n");
|
pri_message(pri, "Received MDL message\n");
|
||||||
if (h->data[0] != 0x0f) {
|
if (h->data[0] != 0x0f) {
|
||||||
@ -895,17 +949,19 @@ static pri_event *q921_receive_MDL(struct pri *pri, q921_u *h, int len)
|
|||||||
tei = (h->data[4] >> 1);
|
tei = (h->data[4] >> 1);
|
||||||
switch(h->data[3]) {
|
switch(h->data[3]) {
|
||||||
case Q921_TEI_IDENTITY_REQUEST:
|
case Q921_TEI_IDENTITY_REQUEST:
|
||||||
|
if (!BRI_NT_PTMP(pri)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (tei != 127) {
|
if (tei != 127) {
|
||||||
pri_error(pri, "Received TEI identity request with invalid TEI %d\n", tei);
|
pri_error(pri, "Received TEI identity request with invalid TEI %d\n", tei);
|
||||||
q921_send_tei(pri, Q921_TEI_IDENTITY_DENIED, ri, tei, 1);
|
q921_send_tei(pri, Q921_TEI_IDENTITY_DENIED, ri, tei, 1);
|
||||||
}
|
}
|
||||||
/* Go to master */
|
|
||||||
for (sub = pri; sub->master; sub = sub->master);
|
|
||||||
tei = 64;
|
tei = 64;
|
||||||
/*! \todo XXX Error: The following loop never terminates! */
|
while (sub->subchannel) {
|
||||||
while(sub->subchannel) {
|
if (sub->subchannel->tei == tei)
|
||||||
if(sub->subchannel->tei == tei)
|
|
||||||
++tei;
|
++tei;
|
||||||
|
sub = sub->subchannel;
|
||||||
}
|
}
|
||||||
sub->subchannel = __pri_new_tei(-1, pri->localtype, pri->switchtype, pri, NULL, NULL, NULL, tei, 1);
|
sub->subchannel = __pri_new_tei(-1, pri->localtype, pri->switchtype, pri, NULL, NULL, NULL, tei, 1);
|
||||||
if (!sub->subchannel) {
|
if (!sub->subchannel) {
|
||||||
@ -915,6 +971,9 @@ static pri_event *q921_receive_MDL(struct pri *pri, q921_u *h, int len)
|
|||||||
q921_send_tei(pri, Q921_TEI_IDENTITY_ASSIGNED, ri, tei, 1);
|
q921_send_tei(pri, Q921_TEI_IDENTITY_ASSIGNED, ri, tei, 1);
|
||||||
break;
|
break;
|
||||||
case Q921_TEI_IDENTITY_ASSIGNED:
|
case Q921_TEI_IDENTITY_ASSIGNED:
|
||||||
|
if (!BRI_TE_PTMP(pri))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
if (ri != pri->ri) {
|
if (ri != pri->ri) {
|
||||||
pri_message(pri, "TEI assignment received for invalid Ri %02x (our is %02x)\n", ri, pri->ri);
|
pri_message(pri, "TEI assignment received for invalid Ri %02x (our is %02x)\n", ri, pri->ri);
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -936,6 +995,8 @@ static pri_event *q921_receive_MDL(struct pri *pri, q921_u *h, int len)
|
|||||||
pri->q921_state = Q921_TEI_ASSIGNED;
|
pri->q921_state = Q921_TEI_ASSIGNED;
|
||||||
break;
|
break;
|
||||||
case Q921_TEI_IDENTITY_CHECK_REQUEST:
|
case Q921_TEI_IDENTITY_CHECK_REQUEST:
|
||||||
|
if (!BRI_TE_PTMP(pri))
|
||||||
|
return NULL;
|
||||||
/* We're assuming one TEI per PRI in TE PTMP mode */
|
/* We're assuming one TEI per PRI in TE PTMP mode */
|
||||||
|
|
||||||
/* If no subchannel (TEI) ignore */
|
/* If no subchannel (TEI) ignore */
|
||||||
@ -948,6 +1009,8 @@ static pri_event *q921_receive_MDL(struct pri *pri, q921_u *h, int len)
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
case Q921_TEI_IDENTITY_REMOVE:
|
case Q921_TEI_IDENTITY_REMOVE:
|
||||||
|
if (!BRI_TE_PTMP(pri))
|
||||||
|
return NULL;
|
||||||
/* XXX: Assuming multiframe mode has been disconnected already */
|
/* XXX: Assuming multiframe mode has been disconnected already */
|
||||||
if (!pri->subchannel)
|
if (!pri->subchannel)
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -989,6 +1052,10 @@ static pri_event *__q921_receive_qualified(struct pri *pri, q921_h *h, int len)
|
|||||||
pri_error(pri, "!! Received short I-frame (expected 4, got %d)\n", len);
|
pri_error(pri, "!! Received short I-frame (expected 4, got %d)\n", len);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* T203 is rescheduled only on reception of I frames or S frames */
|
||||||
|
reschedule_t203(pri);
|
||||||
|
|
||||||
return q921_handle_iframe(pri, &h->i, len);
|
return q921_handle_iframe(pri, &h->i, len);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
@ -1000,6 +1067,10 @@ static pri_event *__q921_receive_qualified(struct pri *pri, q921_h *h, int len)
|
|||||||
pri_error(pri, "!! Received short S-frame (expected 4, got %d)\n", len);
|
pri_error(pri, "!! Received short S-frame (expected 4, got %d)\n", len);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* T203 is rescheduled only on reception of I frames or S frames */
|
||||||
|
reschedule_t203(pri);
|
||||||
|
|
||||||
switch(h->s.ss) {
|
switch(h->s.ss) {
|
||||||
case 0:
|
case 0:
|
||||||
/* Receiver Ready */
|
/* Receiver Ready */
|
||||||
@ -1149,7 +1220,6 @@ static pri_event *__q921_receive_qualified(struct pri *pri, q921_h *h, int len)
|
|||||||
/* Acknowledge */
|
/* Acknowledge */
|
||||||
q921_send_ua(pri, h->u.p_f);
|
q921_send_ua(pri, h->u.p_f);
|
||||||
ev = q921_dchannel_down(pri);
|
ev = q921_dchannel_down(pri);
|
||||||
q921_restart(pri, 0);
|
|
||||||
return ev;
|
return ev;
|
||||||
case 3:
|
case 3:
|
||||||
if (h->u.m2 == 3) {
|
if (h->u.m2 == 3) {
|
||||||
@ -1209,6 +1279,34 @@ static pri_event *__q921_receive_qualified(struct pri *pri, q921_h *h, int len)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static pri_event *q921_handle_unmatched_frame(struct pri *pri, q921_h *h, int len)
|
||||||
|
{
|
||||||
|
pri = PRI_MASTER(pri);
|
||||||
|
|
||||||
|
if (h->h.tei < 64) {
|
||||||
|
pri_error(pri, "Do not support manual TEI range. Discarding\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (h->h.sapi != Q921_SAPI_CALL_CTRL) {
|
||||||
|
pri_error(pri, "Message with SAPI other than CALL CTRL is discarded\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pri->debug & PRI_DEBUG_Q921_DUMP) {
|
||||||
|
pri_message(pri,
|
||||||
|
"Could not find candidate subchannel for received frame with SAPI/TEI of %d/%d.\n",
|
||||||
|
h->h.sapi, h->h.tei);
|
||||||
|
pri_message(pri, "Sending TEI release, in order to re-establish TEI state\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Q.921 says we should send the remove message twice, in case of link corruption */
|
||||||
|
q921_send_tei(pri, Q921_TEI_IDENTITY_REMOVE, 0, h->h.tei, 1);
|
||||||
|
q921_send_tei(pri, Q921_TEI_IDENTITY_REMOVE, 0, h->h.tei, 1);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static pri_event *__q921_receive(struct pri *pri, q921_h *h, int len)
|
static pri_event *__q921_receive(struct pri *pri, q921_h *h, int len)
|
||||||
{
|
{
|
||||||
pri_event *ev;
|
pri_event *ev;
|
||||||
@ -1222,26 +1320,22 @@ static pri_event *__q921_receive(struct pri *pri, q921_h *h, int len)
|
|||||||
if (h->h.ea1 || !(h->h.ea2))
|
if (h->h.ea1 || !(h->h.ea2))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
#if 0 /* Will be rejected by subchannel analyzis */
|
|
||||||
/* Check for broadcasts - not yet handled */
|
|
||||||
if (h->h.tei == Q921_TEI_GROUP)
|
|
||||||
return NULL;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!((h->h.sapi == pri->sapi) && ((h->h.tei == pri->tei) || (h->h.tei == Q921_TEI_GROUP)))) {
|
if (!((h->h.sapi == pri->sapi) && ((h->h.tei == pri->tei) || (h->h.tei == Q921_TEI_GROUP)))) {
|
||||||
/* Check for SAPIs we don't yet handle */
|
/* Check for SAPIs we don't yet handle */
|
||||||
/* If it's not us, try any subchannels we have */
|
/* If it's not us, try any subchannels we have */
|
||||||
if (pri->subchannel)
|
if (pri->subchannel)
|
||||||
return q921_receive(pri->subchannel, h, len + 2);
|
return q921_receive(pri->subchannel, h, len + 2);
|
||||||
else {
|
else {
|
||||||
return NULL;
|
/* This means we couldn't find a candidate subchannel for it...
|
||||||
|
* Time for some corrective action */
|
||||||
|
|
||||||
|
return q921_handle_unmatched_frame(pri, h, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if (pri->debug & PRI_DEBUG_Q921_DUMP)
|
if (pri->debug & PRI_DEBUG_Q921_DUMP)
|
||||||
pri_message(pri, "Handling message for SAPI/TEI=%d/%d\n", h->h.sapi, h->h.tei);
|
pri_message(pri, "Handling message for SAPI/TEI=%d/%d\n", h->h.sapi, h->h.tei);
|
||||||
ev = __q921_receive_qualified(pri, h, len);
|
ev = __q921_receive_qualified(pri, h, len);
|
||||||
reschedule_t203(pri);
|
|
||||||
return ev;
|
return ev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user