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_SERVICE 19 /* SERVICE maintenance 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 */
|
||||
#define PRI_STATE_DOWN 0
|
||||
@ -200,6 +206,7 @@
|
||||
#define PRI_CAUSE_NO_ANSWER 19
|
||||
#define PRI_CAUSE_CALL_REJECTED 21
|
||||
#define PRI_CAUSE_NUMBER_CHANGED 22
|
||||
#define PRI_CAUSE_NONSELECTED_USER_CLEARING 26
|
||||
#define PRI_CAUSE_DESTINATION_OUT_OF_ORDER 27
|
||||
#define PRI_CAUSE_INVALID_NUMBER_FORMAT 28
|
||||
#define PRI_CAUSE_FACILITY_REJECTED 29 /* !Q.SIG */
|
||||
@ -212,6 +219,7 @@
|
||||
#define PRI_CAUSE_ACCESS_INFO_DISCARDED 43 /* !Q.SIG */
|
||||
#define PRI_CAUSE_REQUESTED_CHAN_UNAVAIL 44
|
||||
#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_OUTGOING_CALL_BARRED 52 /* !Q.SIG */
|
||||
#define PRI_CAUSE_INCOMING_CALL_BARRED 54 /* !Q.SIG */
|
||||
@ -468,9 +476,37 @@ struct pri_party_redirecting {
|
||||
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. */
|
||||
#define PRI_SUBCMD_REDIRECTING 1
|
||||
#define PRI_SUBCMD_CONNECTED_LINE 2
|
||||
#define PRI_SUBCMD_REROUTING 3
|
||||
|
||||
|
||||
struct pri_subcommand {
|
||||
@ -481,6 +517,7 @@ struct pri_subcommand {
|
||||
char reserve_space[512];
|
||||
struct pri_party_connected_line connected_line;
|
||||
struct pri_party_redirecting redirecting;
|
||||
struct pri_rerouting_data rerouting;
|
||||
} u;
|
||||
};
|
||||
|
||||
@ -497,13 +534,14 @@ struct pri_subcommands {
|
||||
* Event channel parameter encoding:
|
||||
* 3322 2222 2222 1111 1111 1100 0000 0000
|
||||
* 1098 7654 3210 9876 5432 1098 7654 3210
|
||||
* xxxx xxxx xxxx xxDC BBBBBBBBB AAAAAAAAA
|
||||
* xxxx xxxx xxxx xEDC BBBBBBBBB AAAAAAAAA
|
||||
*
|
||||
* Bit field
|
||||
* A - B channel
|
||||
* B - Span (DS1) (0 - 127)
|
||||
* C - DS1 Explicit bit
|
||||
* D - D channel (cis_call) bit (status only)
|
||||
* E - Call is held bit (status only)
|
||||
*
|
||||
* B channel values:
|
||||
* 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 */
|
||||
int channel;
|
||||
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;
|
||||
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) */
|
||||
struct pri_subcommands *subcmds;
|
||||
q931_call *subcall; /*!< Subcall to send any reply toward. */
|
||||
};
|
||||
|
||||
#define PRI_CALLINGPLANANI
|
||||
@ -609,6 +653,7 @@ typedef struct pri_event_ring {
|
||||
struct pri_subcommands *subcmds;
|
||||
struct pri_party_id calling; /* Calling Party's info, initially subaddress' */
|
||||
struct pri_party_subaddress called_subaddress; /* Called party's subaddress */
|
||||
char keypad_digits[64]; /* Keypad digits in the SETUP message. */
|
||||
} pri_event_ring;
|
||||
|
||||
typedef struct pri_event_hangup {
|
||||
@ -616,10 +661,22 @@ typedef struct pri_event_hangup {
|
||||
int channel; /* Channel requested */
|
||||
int cause;
|
||||
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 */
|
||||
char useruserinfo[260]; /* User->User info */
|
||||
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;
|
||||
|
||||
typedef struct pri_event_restart_ack {
|
||||
@ -651,6 +708,7 @@ typedef struct pri_event_notify {
|
||||
int channel;
|
||||
int info;
|
||||
struct pri_subcommands *subcmds;
|
||||
q931_call *call;
|
||||
} pri_event_notify;
|
||||
|
||||
typedef struct pri_event_keypad_digit {
|
||||
@ -673,6 +731,51 @@ typedef struct pri_event_service_ack {
|
||||
int changestatus;
|
||||
} 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 {
|
||||
int e;
|
||||
pri_event_generic gen; /* Generic view */
|
||||
@ -691,6 +794,12 @@ typedef union {
|
||||
pri_event_service service; /* service message */
|
||||
pri_event_service_ack service_ack; /* service acknowledgement message */
|
||||
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;
|
||||
|
||||
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. */
|
||||
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
|
||||
/* 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);
|
||||
@ -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);
|
||||
|
||||
/*!
|
||||
* \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 */
|
||||
#define PRI_GETSET_TIMERS
|
||||
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_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 */
|
||||
_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 },
|
||||
{ "T321", PRI_TIMER_T321, 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* */
|
||||
};
|
||||
|
||||
@ -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_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_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 */
|
||||
switch (switchtype) {
|
||||
@ -381,6 +387,12 @@ char *pri_event2str(int id)
|
||||
{ PRI_EVENT_KEYPAD_DIGIT, "Keypad Digit" },
|
||||
{ PRI_EVENT_SERVICE, "Service" },
|
||||
{ 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* */
|
||||
};
|
||||
|
||||
@ -539,15 +551,6 @@ int pri_keypad_facility(struct pri *pri, q931_call *call, const char *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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (pri && call)
|
||||
__q931_destroycall(pri, call);
|
||||
q931_destroycall(pri, call);
|
||||
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)
|
||||
{
|
||||
struct q931_party_id party_id;
|
||||
unsigned idx;
|
||||
struct q931_call *subcall;
|
||||
|
||||
if (!ctrl || !call) {
|
||||
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;
|
||||
|
||||
/* 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) {
|
||||
case Q931_CALL_STATE_CALL_INITIATED:
|
||||
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)
|
||||
{
|
||||
unsigned idx;
|
||||
struct q931_call *subcall;
|
||||
|
||||
if (!ctrl || !call) {
|
||||
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);
|
||||
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) {
|
||||
case Q931_CALL_STATE_NULL:
|
||||
/* 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);
|
||||
va_end(ap);
|
||||
if (__pri_message)
|
||||
__pri_message(pri, tmp);
|
||||
__pri_message(PRI_MASTER(pri), tmp);
|
||||
else
|
||||
fputs(tmp, stdout);
|
||||
}
|
||||
@ -1059,7 +1092,7 @@ void pri_error(struct pri *pri, char *fmt, ...)
|
||||
vsnprintf(tmp, sizeof(tmp), fmt, ap);
|
||||
va_end(ap);
|
||||
if (__pri_error)
|
||||
__pri_error(pri, tmp);
|
||||
__pri_error(PRI_MASTER(pri), tmp);
|
||||
else
|
||||
fputs(tmp, stderr);
|
||||
}
|
||||
@ -1320,3 +1353,124 @@ void pri_sr_set_reversecharge(struct pri_sr *sr, int 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 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 */
|
||||
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_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_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_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_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_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, 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, 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, int msgtype, q931_ie *ie, const struct fac_extension_header *header, const struct rose_msg_reject *reject);
|
||||
|
||||
#endif /* _PRI_FACILITY_H */
|
||||
|
@ -70,7 +70,9 @@ struct pri {
|
||||
int protodisc;
|
||||
unsigned int bri:1;
|
||||
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 */
|
||||
int q921_state;
|
||||
int window; /* Max window size */
|
||||
@ -287,6 +289,7 @@ struct pri_sr {
|
||||
int cis_call;
|
||||
int cis_auto_disconnect;
|
||||
const char *useruserinfo;
|
||||
const char *keypad_digits;
|
||||
int transferable;
|
||||
int reversecharge;
|
||||
};
|
||||
@ -295,6 +298,8 @@ struct pri_sr {
|
||||
#define PRI_SWITCH_GR303_EOC_PATH 19
|
||||
#define PRI_SWITCH_GR303_TMC_SWITCHING 20
|
||||
|
||||
#define Q931_MAX_TEI 8
|
||||
|
||||
struct apdu_event {
|
||||
int message; /* What message to send the ADPU in */
|
||||
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
|
||||
};
|
||||
|
||||
/*! 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 */
|
||||
struct q931_call {
|
||||
struct pri *pri; /* PRI */
|
||||
@ -442,6 +463,12 @@ struct q931_call {
|
||||
|
||||
/*! \brief Incoming call transfer 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;
|
||||
char useruserinfo[256];
|
||||
@ -462,6 +489,22 @@ struct q931_call {
|
||||
-1 - No reverse charging
|
||||
1 - Reverse charging
|
||||
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);
|
||||
@ -484,6 +527,11 @@ void __pri_free_tei(struct pri *p);
|
||||
void q931_party_name_init(struct q931_party_name *name);
|
||||
void q931_party_number_init(struct q931_party_number *number);
|
||||
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_id_init(struct q931_party_id *id);
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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
|
||||
|
@ -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_uiframe(struct pri *pri, void *buf, int len);
|
||||
|
||||
extern pri_event *q921_dchannel_up(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,
|
||||
};
|
||||
|
||||
/*! 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 */
|
||||
#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 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);
|
||||
|
||||
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
|
||||
|
128
q921.c
128
q921.c
@ -27,6 +27,7 @@
|
||||
* terms granted here.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.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)
|
||||
{
|
||||
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;
|
||||
/* Immediately transmit unless we're in a recovery state, or the window
|
||||
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->windowlen < pri->window) {
|
||||
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 */
|
||||
pri->t203_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri);
|
||||
} else {
|
||||
if (pri->debug & PRI_DEBUG_Q921_DUMP)
|
||||
pri_message(pri, "T203 counter expired in weird state %d\n", pri->q921_state);
|
||||
if (pri->debug & PRI_DEBUG_Q921_DUMP) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
static pri_event *q921_handle_iframe(struct pri *pri, q921_i *i, int len)
|
||||
{
|
||||
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)
|
||||
{
|
||||
int ri;
|
||||
struct pri *sub;
|
||||
struct pri *sub = pri;
|
||||
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)
|
||||
pri_message(pri, "Received MDL message\n");
|
||||
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);
|
||||
switch(h->data[3]) {
|
||||
case Q921_TEI_IDENTITY_REQUEST:
|
||||
if (!BRI_NT_PTMP(pri)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (tei != 127) {
|
||||
pri_error(pri, "Received TEI identity request with invalid TEI %d\n", tei);
|
||||
q921_send_tei(pri, Q921_TEI_IDENTITY_DENIED, ri, tei, 1);
|
||||
}
|
||||
/* Go to master */
|
||||
for (sub = pri; sub->master; sub = sub->master);
|
||||
tei = 64;
|
||||
/*! \todo XXX Error: The following loop never terminates! */
|
||||
while(sub->subchannel) {
|
||||
if(sub->subchannel->tei == tei)
|
||||
while (sub->subchannel) {
|
||||
if (sub->subchannel->tei == tei)
|
||||
++tei;
|
||||
sub = sub->subchannel;
|
||||
}
|
||||
sub->subchannel = __pri_new_tei(-1, pri->localtype, pri->switchtype, pri, NULL, NULL, NULL, tei, 1);
|
||||
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);
|
||||
break;
|
||||
case Q921_TEI_IDENTITY_ASSIGNED:
|
||||
if (!BRI_TE_PTMP(pri))
|
||||
return NULL;
|
||||
|
||||
if (ri != pri->ri) {
|
||||
pri_message(pri, "TEI assignment received for invalid Ri %02x (our is %02x)\n", ri, pri->ri);
|
||||
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;
|
||||
break;
|
||||
case Q921_TEI_IDENTITY_CHECK_REQUEST:
|
||||
if (!BRI_TE_PTMP(pri))
|
||||
return NULL;
|
||||
/* We're assuming one TEI per PRI in TE PTMP mode */
|
||||
|
||||
/* If no subchannel (TEI) ignore */
|
||||
@ -948,6 +1009,8 @@ static pri_event *q921_receive_MDL(struct pri *pri, q921_u *h, int len)
|
||||
|
||||
break;
|
||||
case Q921_TEI_IDENTITY_REMOVE:
|
||||
if (!BRI_TE_PTMP(pri))
|
||||
return NULL;
|
||||
/* XXX: Assuming multiframe mode has been disconnected already */
|
||||
if (!pri->subchannel)
|
||||
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);
|
||||
break;
|
||||
}
|
||||
|
||||
/* T203 is rescheduled only on reception of I frames or S frames */
|
||||
reschedule_t203(pri);
|
||||
|
||||
return q921_handle_iframe(pri, &h->i, len);
|
||||
break;
|
||||
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);
|
||||
break;
|
||||
}
|
||||
|
||||
/* T203 is rescheduled only on reception of I frames or S frames */
|
||||
reschedule_t203(pri);
|
||||
|
||||
switch(h->s.ss) {
|
||||
case 0:
|
||||
/* Receiver Ready */
|
||||
@ -1149,7 +1220,6 @@ static pri_event *__q921_receive_qualified(struct pri *pri, q921_h *h, int len)
|
||||
/* Acknowledge */
|
||||
q921_send_ua(pri, h->u.p_f);
|
||||
ev = q921_dchannel_down(pri);
|
||||
q921_restart(pri, 0);
|
||||
return ev;
|
||||
case 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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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))
|
||||
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)))) {
|
||||
/* Check for SAPIs we don't yet handle */
|
||||
/* If it's not us, try any subchannels we have */
|
||||
if (pri->subchannel)
|
||||
return q921_receive(pri->subchannel, h, len + 2);
|
||||
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)
|
||||
pri_message(pri, "Handling message for SAPI/TEI=%d/%d\n", h->h.sapi, h->h.tei);
|
||||
ev = __q921_receive_qualified(pri, h, len);
|
||||
reschedule_t203(pri);
|
||||
return ev;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user