@@ -324,7 +324,7 @@
p->subchannel = __pri_new_tei(-1, node, PRI_SWITCH_GR303_EOC_PATH, p, NULL, NULL, NULL, Q921_TEI_GR303_EOC_PATH, 0);
if (!p->subchannel) {
free(p);
- p = NULL;
+ return NULL;
}
break;
case PRI_SWITCH_GR303_TMC:
@@ -334,7 +334,7 @@
p->subchannel = __pri_new_tei(-1, node, PRI_SWITCH_GR303_TMC_SWITCHING, p, NULL, NULL, NULL, Q921_TEI_GR303_TMC_SWITCHING, 0);
if (!p->subchannel) {
free(p);
- p = NULL;
+ return NULL;
}
break;
case PRI_SWITCH_GR303_TMC_SWITCHING:
@@ -365,8 +365,15 @@
void pri_call_set_useruser(q931_call *c, const char *userchars)
{
- if (userchars)
- libpri_copy_string(c->useruserinfo, userchars, sizeof(c->useruserinfo));
+ /*
+ * There is a slight risk here if c is actually stale. However,
+ * if it is stale then it is better to catch it here than to
+ * write with it.
+ */
+ if (!userchars || !pri_is_call_valid(NULL, c)) {
+ return;
+ }
+ libpri_copy_string(c->useruserinfo, userchars, sizeof(c->useruserinfo));
}
void pri_sr_set_useruser(struct pri_sr *sr, const char *userchars)
@@ -434,32 +441,32 @@
char *name;
} events[] = {
/* *INDENT-OFF* */
- { PRI_EVENT_DCHAN_UP, "D-Channel Up" },
- { PRI_EVENT_DCHAN_DOWN, "D-channel Down" },
- { PRI_EVENT_RESTART, "Restart channel" },
- { PRI_EVENT_CONFIG_ERR, "Configuration Error" },
- { PRI_EVENT_RING, "Ring" },
- { PRI_EVENT_HANGUP, "Hangup" },
- { PRI_EVENT_RINGING, "Ringing" },
- { PRI_EVENT_ANSWER, "Answer" },
- { PRI_EVENT_HANGUP_ACK, "Hangup ACK" },
- { PRI_EVENT_RESTART_ACK, "Restart ACK" },
- { PRI_EVENT_FACILITY, "Facility" },
- { PRI_EVENT_INFO_RECEIVED, "Info Received" },
- { PRI_EVENT_PROCEEDING, "Proceeding" },
- { PRI_EVENT_SETUP_ACK, "Setup ACK" },
- { PRI_EVENT_HANGUP_REQ, "Hangup Req" },
- { PRI_EVENT_NOTIFY, "Notify" },
- { PRI_EVENT_PROGRESS, "Progress" },
- { 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" },
+ { PRI_EVENT_DCHAN_UP, "PRI_EVENT_DCHAN_UP" },
+ { PRI_EVENT_DCHAN_DOWN, "PRI_EVENT_DCHAN_DOWN" },
+ { PRI_EVENT_RESTART, "PRI_EVENT_RESTART" },
+ { PRI_EVENT_CONFIG_ERR, "PRI_EVENT_CONFIG_ERR" },
+ { PRI_EVENT_RING, "PRI_EVENT_RING" },
+ { PRI_EVENT_HANGUP, "PRI_EVENT_HANGUP" },
+ { PRI_EVENT_RINGING, "PRI_EVENT_RINGING" },
+ { PRI_EVENT_ANSWER, "PRI_EVENT_ANSWER" },
+ { PRI_EVENT_HANGUP_ACK, "PRI_EVENT_HANGUP_ACK" },
+ { PRI_EVENT_RESTART_ACK, "PRI_EVENT_RESTART_ACK" },
+ { PRI_EVENT_FACILITY, "PRI_EVENT_FACILITY" },
+ { PRI_EVENT_INFO_RECEIVED, "PRI_EVENT_INFO_RECEIVED" },
+ { PRI_EVENT_PROCEEDING, "PRI_EVENT_PROCEEDING" },
+ { PRI_EVENT_SETUP_ACK, "PRI_EVENT_SETUP_ACK" },
+ { PRI_EVENT_HANGUP_REQ, "PRI_EVENT_HANGUP_REQ" },
+ { PRI_EVENT_NOTIFY, "PRI_EVENT_NOTIFY" },
+ { PRI_EVENT_PROGRESS, "PRI_EVENT_PROGRESS" },
+ { PRI_EVENT_KEYPAD_DIGIT, "PRI_EVENT_KEYPAD_DIGIT" },
+ { PRI_EVENT_SERVICE, "PRI_EVENT_SERVICE" },
+ { PRI_EVENT_SERVICE_ACK, "PRI_EVENT_SERVICE_ACK" },
+ { PRI_EVENT_HOLD, "PRI_EVENT_HOLD" },
+ { PRI_EVENT_HOLD_ACK, "PRI_EVENT_HOLD_ACK" },
+ { PRI_EVENT_HOLD_REJ, "PRI_EVENT_HOLD_REJ" },
+ { PRI_EVENT_RETRIEVE, "PRI_EVENT_RETRIEVE" },
+ { PRI_EVENT_RETRIEVE_ACK, "PRI_EVENT_RETRIEVE_ACK" },
+ { PRI_EVENT_RETRIEVE_REJ, "PRI_EVENT_RETRIEVE_REJ" },
/* *INDENT-ON* */
};
@@ -575,74 +582,83 @@
int pri_acknowledge(struct pri *pri, q931_call *call, int channel, int info)
{
- if (!pri || !call)
+ if (!pri || !pri_is_call_valid(pri, call)) {
return -1;
+ }
return q931_alerting(pri, call, channel, info);
}
int pri_proceeding(struct pri *pri, q931_call *call, int channel, int info)
{
- if (!pri || !call)
+ if (!pri || !pri_is_call_valid(pri, call)) {
return -1;
+ }
return q931_call_proceeding(pri, call, channel, info);
}
int pri_progress_with_cause(struct pri *pri, q931_call *call, int channel, int info, int cause)
{
- if (!pri || !call)
+ if (!pri || !pri_is_call_valid(pri, call)) {
return -1;
+ }
return q931_call_progress_with_cause(pri, call, channel, info, cause);
}
int pri_progress(struct pri *pri, q931_call *call, int channel, int info)
{
- if (!pri || !call)
+ if (!pri || !pri_is_call_valid(pri, call)) {
return -1;
+ }
return q931_call_progress(pri, call, channel, info);
}
int pri_information(struct pri *pri, q931_call *call, char digit)
{
- if (!pri || !call)
+ if (!pri || !pri_is_call_valid(pri, call)) {
return -1;
+ }
return q931_information(pri, call, digit);
}
int pri_keypad_facility(struct pri *pri, q931_call *call, const char *digits)
{
- if (!pri || !call || !digits || !digits[0])
+ if (!pri || !pri_is_call_valid(pri, call) || !digits || !digits[0]) {
return -1;
+ }
return q931_keypad_facility(pri, call, digits);
}
int pri_notify(struct pri *pri, q931_call *call, int channel, int info)
{
- if (!pri || !call)
+ if (!pri || !pri_is_call_valid(pri, call)) {
return -1;
+ }
return q931_notify(pri, call, channel, info);
}
void pri_destroycall(struct pri *pri, q931_call *call)
{
- if (pri && call)
+ if (pri && pri_is_call_valid(pri, call)) {
q931_destroycall(pri, call);
- return;
+ }
}
int pri_need_more_info(struct pri *pri, q931_call *call, int channel, int nonisdn)
{
- if (!pri || !call)
+ if (!pri || !pri_is_call_valid(pri, call)) {
return -1;
+ }
return q931_setup_ack(pri, call, channel, nonisdn);
}
int pri_answer(struct pri *pri, q931_call *call, int channel, int nonisdn)
{
- if (!pri || !call)
+ if (!pri || !pri_is_call_valid(pri, call)) {
return -1;
+ }
return q931_connect(pri, call, channel, nonisdn);
}
@@ -738,7 +754,7 @@
unsigned idx;
struct q931_call *subcall;
- if (!ctrl || !call) {
+ if (!ctrl || !pri_is_call_valid(ctrl, call)) {
return -1;
}
@@ -804,7 +820,7 @@
unsigned idx;
struct q931_call *subcall;
- if (!ctrl || !call) {
+ if (!ctrl || !pri_is_call_valid(ctrl, call)) {
return -1;
}
@@ -908,23 +924,31 @@
/* deprecated routines, use pri_hangup */
int pri_release(struct pri *pri, q931_call *call, int cause)
{
- if (!pri || !call)
+ if (!pri || !pri_is_call_valid(pri, call)) {
return -1;
+ }
return q931_release(pri, call, cause);
}
int pri_disconnect(struct pri *pri, q931_call *call, int cause)
{
- if (!pri || !call)
+ if (!pri || !pri_is_call_valid(pri, call)) {
return -1;
+ }
return q931_disconnect(pri, call, cause);
}
#endif
int pri_channel_bridge(q931_call *call1, q931_call *call2)
{
- if (!call1 || !call2)
+ /*
+ * There is a slight risk here if call1 or call2 is actually
+ * stale. However, if they are stale then it is better to catch
+ * it here than to write with these pointers.
+ */
+ if (!pri_is_call_valid(NULL, call1) || !pri_is_call_valid(NULL, call2)) {
return -1;
+ }
/* Make sure we have compatible switchtypes */
if (call1->pri->switchtype != call2->pri->switchtype)
@@ -976,8 +1000,9 @@
int pri_hangup(struct pri *pri, q931_call *call, int cause)
{
- if (!pri || !call)
+ if (!pri || !pri_is_call_valid(pri, call)) {
return -1;
+ }
if (cause == -1)
/* normal clear cause */
cause = PRI_CAUSE_NORMAL_CLEARING;
@@ -1019,26 +1044,6 @@
if (!pri || !e)
return;
pri_message(pri, "Event type: %s (%d)\n", pri_event2str(e->gen.e), e->gen.e);
- switch(e->gen.e) {
- case PRI_EVENT_DCHAN_UP:
- case PRI_EVENT_DCHAN_DOWN:
- break;
- case PRI_EVENT_CONFIG_ERR:
- pri_message(pri, "Error: %s", e->err.err);
- break;
- case PRI_EVENT_RESTART:
- pri_message(pri, "Restart on channel %d\n", e->restart.channel);
- case PRI_EVENT_RING:
- pri_message(pri, "Calling number: %s (%s, %s)\n", e->ring.callingnum, pri_plan2str(e->ring.callingplan), pri_pres2str(e->ring.callingpres));
- pri_message(pri, "Called number: %s (%s)\n", e->ring.callednum, pri_plan2str(e->ring.calledplan));
- pri_message(pri, "Channel: %d (%s) Reference number: %d\n", e->ring.channel, e->ring.flexible ? "Flexible" : "Not Flexible", e->ring.cref);
- break;
- case PRI_EVENT_HANGUP:
- pri_message(pri, "Hangup, reference number: %d, reason: %s\n", e->hangup.cref, pri_cause2str(e->hangup.cause));
- break;
- default:
- pri_message(pri, "Don't know how to dump events of type %d\n", e->gen.e);
- }
}
static void pri_sr_init(struct pri_sr *req)
@@ -1075,8 +1080,10 @@
int calledplan)
{
struct pri_sr req;
- if (!pri || !c)
+
+ if (!pri || !pri_is_call_valid(pri, c)) {
return -1;
+ }
pri_sr_init(&req);
pri_sr_set_connection_call_independent(&req);
@@ -1095,8 +1102,10 @@
int calledplan)
{
struct pri_sr req;
- if (!pri || !c)
+
+ if (!pri || !pri_is_call_valid(pri, c)) {
return -1;
+ }
pri_sr_init(&req);
pri_sr_set_connection_call_independent(&req);
@@ -1113,8 +1122,9 @@
int pri_setup(struct pri *pri, q931_call *c, struct pri_sr *req)
{
- if (!pri || !c)
+ if (!pri || !pri_is_call_valid(pri, c)) {
return -1;
+ }
return q931_setup(pri, c, req);
}
@@ -1124,8 +1134,11 @@
int calledplan, int ulayer1)
{
struct pri_sr req;
- if (!pri || !c)
+
+ if (!pri || !pri_is_call_valid(pri, c)) {
return -1;
+ }
+
pri_sr_init(&req);
pri_sr_set_caller(&req, caller, callername, callerplan, callerpres);
pri_sr_set_called(&req, called, calledplan, 0);
@@ -1348,7 +1361,7 @@
enum PRI_TIMERS_AND_COUNTERS tmr;
tmr = pri_timer[idx].number;
- if (0 <= ctrl->timers[tmr] || tmr == PRI_TIMER_T309) {
+ if (0 <= ctrl->timers[tmr]) {
used = pri_snprintf(buf, used, buf_size, " %s: %d\n",
pri_timer[idx].name, ctrl->timers[tmr]);
}
@@ -1364,18 +1377,27 @@
int pri_get_crv(struct pri *pri, q931_call *call, int *callmode)
{
+ if (!pri || !pri_is_call_valid(pri, call)) {
+ return -1;
+ }
return q931_call_getcrv(pri, call, callmode);
}
int pri_set_crv(struct pri *pri, q931_call *call, int crv, int callmode)
{
+ if (!pri || !pri_is_call_valid(pri, call)) {
+ return -1;
+ }
return q931_call_setcrv(pri, call, crv, callmode);
}
void pri_enslave(struct pri *master, struct pri *slave)
{
- if (master && slave)
+ if (master && slave) {
slave->callpool = &master->localpool;
+ slave->nfas = 1;
+ master->nfas = 1;
+ }
}
struct pri_sr *pri_sr_new(void)
@@ -1514,7 +1536,7 @@
int pri_hold(struct pri *ctrl, q931_call *call)
{
- if (!ctrl || !call) {
+ if (!ctrl || !pri_is_call_valid(ctrl, call)) {
return -1;
}
return q931_send_hold(ctrl, call);
@@ -1522,7 +1544,7 @@
int pri_hold_ack(struct pri *ctrl, q931_call *call)
{
- if (!ctrl || !call) {
+ if (!ctrl || !pri_is_call_valid(ctrl, call)) {
return -1;
}
return q931_send_hold_ack(ctrl, call);
@@ -1530,7 +1552,7 @@
int pri_hold_rej(struct pri *ctrl, q931_call *call, int cause)
{
- if (!ctrl || !call) {
+ if (!ctrl || !pri_is_call_valid(ctrl, call)) {
return -1;
}
return q931_send_hold_rej(ctrl, call, cause);
@@ -1538,7 +1560,7 @@
int pri_retrieve(struct pri *ctrl, q931_call *call, int channel)
{
- if (!ctrl || !call) {
+ if (!ctrl || !pri_is_call_valid(ctrl, call)) {
return -1;
}
return q931_send_retrieve(ctrl, call, channel);
@@ -1546,7 +1568,7 @@
int pri_retrieve_ack(struct pri *ctrl, q931_call *call, int channel)
{
- if (!ctrl || !call) {
+ if (!ctrl || !pri_is_call_valid(ctrl, call)) {
return -1;
}
return q931_send_retrieve_ack(ctrl, call, channel);
@@ -1554,7 +1576,7 @@
int pri_retrieve_rej(struct pri *ctrl, q931_call *call, int cause)
{
- if (!ctrl || !call) {
+ if (!ctrl || !pri_is_call_valid(ctrl, call)) {
return -1;
}
return q931_send_retrieve_rej(ctrl, call, cause);
@@ -1562,8 +1584,9 @@
int pri_callrerouting_facility(struct pri *pri, q931_call *call, const char *dest, const char* original, const char* reason)
{
- if (!pri || !call || !dest)
+ if (!pri || !pri_is_call_valid(pri, call) || !dest) {
return -1;
+ }
return qsig_cf_callrerouting(pri, call, dest, original, reason);
}
@@ -1582,7 +1605,7 @@
struct q931_party_id local_caller;
struct q931_party_redirecting reroute;
- if (!ctrl || !call || !deflection) {
+ if (!ctrl || !pri_is_call_valid(ctrl, call) || !deflection) {
return -1;
}
|
@@ -43,125 +43,269 @@
* Define RANDOM_DROPS To randomly drop packets in order to simulate loss for testing
* retransmission functionality
*/
+//#define RANDOM_DROPS 1
-/*
-#define RANDOM_DROPS
-*/
-
-#define Q921_INIT(pri, hf) do { \
+#define Q921_INIT(ctrl, hf) do { \
memset(&(hf),0,sizeof(hf)); \
- (hf).h.sapi = (pri)->sapi; \
+ (hf).h.sapi = (ctrl)->sapi; \
(hf).h.ea1 = 0; \
(hf).h.ea2 = 1; \
- (hf).h.tei = (pri)->tei; \
+ (hf).h.tei = (ctrl)->tei; \
} while(0)
-static void reschedule_t200(struct pri *pri);
-static void q921_dump_pri(struct pri *pri);
-static void q921_establish_data_link(struct pri *pri);
-static void q921_mdl_error(struct pri *pri, char error);
-static void q921_mdl_remove(struct pri *pri);
+static void reschedule_t200(struct pri *ctrl);
+static void q921_dump_pri(struct pri *ctrl, char direction_tag);
+static void q921_establish_data_link(struct pri *ctrl);
+static void q921_mdl_error(struct pri *ctrl, char error);
+static void q921_mdl_remove(struct pri *ctrl);
+static void q921_restart_ptp_link_if_needed(struct pri *ctrl);
+
+/*!
+ * \internal
+ * \brief Convert Q.921 state to a string.
+ *
+ * \param state Q.921 state to convert.
+ *
+ * \return State name string
+ */
+static const char *q921_state2str(enum q921_state state)
+{
+ switch (state) {
+ case Q921_TEI_UNASSIGNED:
+ return "TEI unassigned";
+ case Q921_ASSIGN_AWAITING_TEI:
+ return "Assign awaiting TEI";
+ case Q921_ESTABLISH_AWAITING_TEI:
+ return "Establish awaiting TEI";
+ case Q921_TEI_ASSIGNED:
+ return "TEI assigned";
+ case Q921_AWAITING_ESTABLISHMENT:
+ return "Awaiting establishment";
+ case Q921_AWAITING_RELEASE:
+ return "Awaiting release";
+ case Q921_MULTI_FRAME_ESTABLISHED:
+ return "Multi-frame established";
+ case Q921_TIMER_RECOVERY:
+ return "Timer recovery";
+ }
-static void q921_setstate(struct pri *pri, int newstate)
+ return "Unknown state";
+}
+
+static void q921_setstate(struct pri *ctrl, int newstate)
{
- if (pri->debug & PRI_DEBUG_Q921_STATE) {
- if ((pri->q921_state != newstate) && (newstate != 7) && (newstate != 8)) {
- pri_message(pri, "Changing from state %d to %d\n", pri->q921_state, newstate);
+ if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
+ /*
+ * Suppress displaying these state transitions:
+ * Q921_MULTI_FRAME_ESTABLISHED <--> Q921_TIMER_RECOVERY
+ *
+ * Q921 keeps flipping back and forth between these two states
+ * when it has nothing better to do.
+ */
+ switch (ctrl->q921_state) {
+ case Q921_MULTI_FRAME_ESTABLISHED:
+ case Q921_TIMER_RECOVERY:
+ switch (newstate) {
+ case Q921_MULTI_FRAME_ESTABLISHED:
+ case Q921_TIMER_RECOVERY:
+ /* Suppress displaying this state transition. */
+ ctrl->q921_state = newstate;
+ return;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ if (ctrl->q921_state != newstate) {
+ pri_message(ctrl, "Changing from state %d(%s) to %d(%s)\n",
+ ctrl->q921_state, q921_state2str(ctrl->q921_state),
+ newstate, q921_state2str(newstate));
}
}
- pri->q921_state = newstate;
+ ctrl->q921_state = newstate;
}
-static void q921_discard_retransmissions(struct pri *pri)
+static void q921_discard_iqueue(struct pri *ctrl)
{
struct q921_frame *f, *p;
- f = pri->txqueue;
- while(f) {
+
+ f = ctrl->txqueue;
+ while (f) {
p = f;
f = f->next;
/* Free frame */
free(p);
}
- pri->txqueue = NULL;
-}
-
-static void q921_discard_iqueue(struct pri *pri)
-{
- q921_discard_retransmissions(pri);
+ ctrl->txqueue = NULL;
}
-static int q921_transmit(struct pri *pri, q921_h *h, int len)
+static int q921_transmit(struct pri *ctrl, q921_h *h, int len)
{
int res;
- pri = PRI_MASTER(pri);
+ ctrl = PRI_MASTER(ctrl);
#ifdef RANDOM_DROPS
if (!(random() % 3)) {
- pri_message(pri, " === Dropping Packet ===\n");
+ pri_message(ctrl, " === Dropping Packet ===\n");
return 0;
}
#endif
#ifdef LIBPRI_COUNTERS
- pri->q921_txcount++;
+ ctrl->q921_txcount++;
#endif
/* Just send it raw */
- if (pri->debug & (PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_RAW))
- q921_dump(pri, h, len, pri->debug & PRI_DEBUG_Q921_RAW, 1);
+ if (ctrl->debug & (PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_RAW))
+ q921_dump(ctrl, h, len, ctrl->debug & PRI_DEBUG_Q921_RAW, 1);
/* Write an extra two bytes for the FCS */
- res = pri->write_func ? pri->write_func(pri, h, len + 2) : 0;
+ res = ctrl->write_func ? ctrl->write_func(ctrl, h, len + 2) : 0;
if (res != (len + 2)) {
- pri_error(pri, "Short write: %d/%d (%s)\n", res, len + 2, strerror(errno));
+ pri_error(ctrl, "Short write: %d/%d (%s)\n", res, len + 2, strerror(errno));
return -1;
}
return 0;
}
-static void q921_send_tei(struct pri *pri, int message, int ri, int ai, int iscommand)
+static void q921_send_tei(struct pri *ctrl, int message, int ri, int ai, int iscommand)
{
q921_u *f;
if (!(f = calloc(1, sizeof(*f) + 5)))
return;
- Q921_INIT(pri, *f);
- f->h.c_r = (pri->localtype == PRI_NETWORK) ? iscommand : !iscommand;
+ Q921_INIT(ctrl, *f);
+ f->h.c_r = (ctrl->localtype == PRI_NETWORK) ? iscommand : !iscommand;
f->ft = Q921_FRAMETYPE_U;
f->data[0] = 0x0f; /* Management entity */
f->data[1] = (ri >> 8) & 0xff;
f->data[2] = ri & 0xff;
f->data[3] = message;
f->data[4] = (ai << 1) | 1;
- if (pri->debug & PRI_DEBUG_Q921_STATE)
- pri_message(pri, "Sending TEI management message %d, TEI=%d\n", message, ai);
- q921_transmit(pri, (q921_h *)f, 8);
+ if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
+ pri_message(ctrl, "Sending TEI management message %d, TEI=%d\n", message, ai);
+ }
+ q921_transmit(ctrl, (q921_h *)f, 8);
free(f);
}
-static void q921_tei_request(void *vpri)
+static void t202_expire(void *vpri)
+{
+ struct pri *ctrl = (struct pri *)vpri;
+
+ /* Start the TEI request timer. */
+ pri_schedule_del(ctrl, ctrl->t202_timer);
+ ctrl->t202_timer =
+ pri_schedule_event(ctrl, ctrl->timers[PRI_TIMER_T202], t202_expire, ctrl);
+
+ ++ctrl->n202_counter;
+ if (!ctrl->t202_timer || ctrl->n202_counter > ctrl->timers[PRI_TIMER_N202]) {
+ if (!ctrl->t202_timer) {
+ pri_error(ctrl, "Could not start T202 timer.");
+ } else {
+ pri_schedule_del(ctrl, ctrl->t202_timer);
+ ctrl->t202_timer = 0;
+ }
+ pri_error(ctrl, "Unable to receive TEI from network in state %d(%s)!\n",
+ ctrl->q921_state, q921_state2str(ctrl->q921_state));
+ switch (ctrl->q921_state) {
+ case Q921_ASSIGN_AWAITING_TEI:
+ break;
+ case Q921_ESTABLISH_AWAITING_TEI:
+ q921_discard_iqueue(ctrl);
+ /* DL-RELEASE indication */
+ q931_dl_event(ctrl, Q931_DL_EVENT_DL_RELEASE_IND);
+ break;
+ default:
+ break;
+ }
+ q921_setstate(ctrl, Q921_TEI_UNASSIGNED);
+ return;
+ }
+
+ /* Send TEI request */
+ ctrl->ri = random() % 65535;
+ q921_send_tei(PRI_MASTER(ctrl), Q921_TEI_IDENTITY_REQUEST, ctrl->ri, Q921_TEI_GROUP, 1);
+}
+
+static void q921_tei_request(struct pri *ctrl)
+{
+ ctrl->n202_counter = 0;
+ t202_expire(ctrl);
+}
+
+static void q921_tei_remove(struct pri *ctrl, int tei)
+{
+ /*
+ * Q.921 Section 5.3.2 says we should send the remove message
+ * twice, in case of message loss.
+ */
+ q921_send_tei(ctrl, Q921_TEI_IDENTITY_REMOVE, 0, tei, 1);
+ q921_send_tei(ctrl, Q921_TEI_IDENTITY_REMOVE, 0, tei, 1);
+}
+
+static void q921_send_dm(struct pri *ctrl, int fbit)
{
- struct pri *pri = (struct pri *)vpri;
- pri->n202_counter++;
- if (pri->n202_counter > pri->timers[PRI_TIMER_N202]) {
- pri_error(pri, "Unable to receive TEI from network!\n");
- pri->n202_counter = 0;
+ q921_h h;
+
+ Q921_INIT(ctrl, h);
+ h.u.m3 = 0; /* M3 = 0 */
+ h.u.m2 = 3; /* M2 = 3 */
+ h.u.p_f = fbit; /* Final set appropriately */
+ h.u.ft = Q921_FRAMETYPE_U;
+ switch(ctrl->localtype) {
+ case PRI_NETWORK:
+ h.h.c_r = 0;
+ break;
+ case PRI_CPE:
+ h.h.c_r = 1;
+ break;
+ default:
+ pri_error(ctrl, "Don't know how to DM on a type %d node\n", ctrl->localtype);
+ return;
+ }
+ if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
+ pri_message(ctrl, "TEI=%d Sending DM\n", ctrl->tei);
+ }
+ q921_transmit(ctrl, &h, 4);
+}
+
+static void q921_send_disc(struct pri *ctrl, int pbit)
+{
+ q921_h h;
+
+ Q921_INIT(ctrl, h);
+ h.u.m3 = 2; /* M3 = 2 */
+ h.u.m2 = 0; /* M2 = 0 */
+ h.u.p_f = pbit; /* Poll set appropriately */
+ h.u.ft = Q921_FRAMETYPE_U;
+ switch(ctrl->localtype) {
+ case PRI_NETWORK:
+ h.h.c_r = 0;
+ break;
+ case PRI_CPE:
+ h.h.c_r = 1;
+ break;
+ default:
+ pri_error(ctrl, "Don't know how to DISC on a type %d node\n", ctrl->localtype);
return;
}
- pri->ri = random() % 65535;
- q921_send_tei(PRI_MASTER(pri), Q921_TEI_IDENTITY_REQUEST, pri->ri, Q921_TEI_GROUP, 1);
- pri_schedule_del(pri, pri->t202_timer);
- pri->t202_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T202], q921_tei_request, pri);
+ if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
+ pri_message(ctrl, "TEI=%d Sending DISC\n", ctrl->tei);
+ }
+ q921_transmit(ctrl, &h, 4);
}
-static void q921_send_ua(struct pri *pri, int pfbit)
+static void q921_send_ua(struct pri *ctrl, int fbit)
{
q921_h h;
- Q921_INIT(pri, h);
+ Q921_INIT(ctrl, h);
h.u.m3 = 3; /* M3 = 3 */
h.u.m2 = 0; /* M2 = 0 */
- h.u.p_f = pfbit; /* Final bit on */
+ h.u.p_f = fbit; /* Final set appropriately */
h.u.ft = Q921_FRAMETYPE_U;
- switch(pri->localtype) {
+ switch(ctrl->localtype) {
case PRI_NETWORK:
h.h.c_r = 0;
break;
@@ -169,24 +313,25 @@
h.h.c_r = 1;
break;
default:
- pri_error(pri, "Don't know how to U/A on a type %d node\n", pri->localtype);
+ pri_error(ctrl, "Don't know how to UA on a type %d node\n", ctrl->localtype);
return;
}
- if (pri->debug & (PRI_DEBUG_Q921_STATE | PRI_DEBUG_Q921_DUMP))
- pri_message(pri, "Sending Unnumbered Acknowledgement\n");
- q921_transmit(pri, &h, 3);
+ if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
+ pri_message(ctrl, "TEI=%d Sending UA\n", ctrl->tei);
+ }
+ q921_transmit(ctrl, &h, 3);
}
-static void q921_send_sabme(struct pri *pri)
+static void q921_send_sabme(struct pri *ctrl)
{
q921_h h;
- Q921_INIT(pri, h);
+ Q921_INIT(ctrl, h);
h.u.m3 = 3; /* M3 = 3 */
h.u.m2 = 3; /* M2 = 3 */
h.u.p_f = 1; /* Poll bit set */
h.u.ft = Q921_FRAMETYPE_U;
- switch(pri->localtype) {
+ switch(ctrl->localtype) {
case PRI_NETWORK:
h.h.c_r = 1;
break;
@@ -194,10 +339,13 @@
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);
+ pri_error(ctrl, "Don't know how to SABME on a type %d node\n", ctrl->localtype);
return;
}
- q921_transmit(pri, &h, 3);
+ if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
+ pri_message(ctrl, "TEI=%d Sending SABME\n", ctrl->tei);
+ }
+ q921_transmit(ctrl, &h, 3);
}
#if 0
@@ -207,26 +355,36 @@
}
#endif
-static int q921_ack_packet(struct pri *pri, int num)
+static int q921_ack_packet(struct pri *ctrl, int num)
{
- struct q921_frame *f, *prev = NULL;
- f = pri->txqueue;
- while (f) {
+ struct q921_frame *f;
+ struct q921_frame *prev;
+
+ for (prev = NULL, f = ctrl->txqueue; f; prev = f, f = f->next) {
+ if (!f->transmitted) {
+ break;
+ }
if (f->h.n_s == num) {
/* Cancel each packet as necessary */
/* That's our packet */
if (prev)
prev->next = f->next;
else
- pri->txqueue = f->next;
- if (pri->debug & PRI_DEBUG_Q921_DUMP)
- pri_message(pri, "-- ACKing packet %d, new txqueue is %d (-1 means empty)\n", f->h.n_s, pri->txqueue ? pri->txqueue->h.n_s : -1);
+ ctrl->txqueue = f->next;
+ if (ctrl->debug & PRI_DEBUG_Q921_DUMP) {
+ pri_message(ctrl,
+ "-- ACKing N(S)=%d, txqueue head is N(S)=%d (-1 is empty, -2 is not transmitted)\n",
+ f->h.n_s,
+ ctrl->txqueue
+ ? ctrl->txqueue->transmitted
+ ? ctrl->txqueue->h.n_s
+ : -2
+ : -1);
+ }
/* Update v_a */
free(f);
return 1;
}
- prev = f;
- f = f->next;
}
return 0;
}
@@ -234,30 +392,30 @@
static void t203_expire(void *);
static void t200_expire(void *);
-static void reschedule_t200(struct pri *pri)
+static void reschedule_t200(struct pri *ctrl)
{
- if (pri->debug & PRI_DEBUG_Q921_DUMP)
- pri_message(pri, "-- Restarting T200 timer\n");
- pri_schedule_del(pri, pri->t200_timer);
- pri->t200_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri);
+ if (ctrl->debug & PRI_DEBUG_Q921_DUMP)
+ pri_message(ctrl, "-- Restarting T200 timer\n");
+ pri_schedule_del(ctrl, ctrl->t200_timer);
+ ctrl->t200_timer = pri_schedule_event(ctrl, ctrl->timers[PRI_TIMER_T200], t200_expire, ctrl);
}
-#define restart_t200(pri) reschedule_t200((pri))
+#define restart_t200(ctrl) reschedule_t200((ctrl))
#if 0
-static void reschedule_t203(struct pri *pri)
+static void reschedule_t203(struct pri *ctrl)
{
- if (pri->debug & PRI_DEBUG_Q921_DUMP)
- pri_message(pri, "-- Restarting T203 timer\n");
- pri_schedule_del(pri, pri->t203_timer);
- pri->t203_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T203], t203_expire, pri);
+ if (ctrl->debug & PRI_DEBUG_Q921_DUMP)
+ pri_message(ctrl, "-- Restarting T203 timer\n");
+ pri_schedule_del(ctrl, ctrl->t203_timer);
+ ctrl->t203_timer = pri_schedule_event(ctrl, ctrl->timers[PRI_TIMER_T203], t203_expire, ctrl);
}
#endif
#if 0
-static int q921_unacked_iframes(struct pri *pri)
+static int q921_unacked_iframes(struct pri *ctrl)
{
- struct q921_frame *f = pri->txqueue;
+ struct q921_frame *f = ctrl->txqueue;
int cnt = 0;
while(f) {
@@ -270,107 +428,149 @@
}
#endif
-static void start_t203(struct pri *pri)
+static void start_t203(struct pri *ctrl)
{
- if (pri->t203_timer) {
- if (pri->debug & PRI_DEBUG_Q921_DUMP)
- pri_message(pri, "T203 requested to start without stopping first\n");
- pri_schedule_del(pri, pri->t203_timer);
+ if (ctrl->t203_timer) {
+ if (ctrl->debug & PRI_DEBUG_Q921_DUMP)
+ pri_message(ctrl, "T203 requested to start without stopping first\n");
+ pri_schedule_del(ctrl, ctrl->t203_timer);
}
- if (pri->debug & PRI_DEBUG_Q921_DUMP)
- pri_message(pri, "-- Starting T203 timer\n");
- pri->t203_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T203], t203_expire, pri);
+ if (ctrl->debug & PRI_DEBUG_Q921_DUMP)
+ pri_message(ctrl, "-- Starting T203 timer\n");
+ ctrl->t203_timer = pri_schedule_event(ctrl, ctrl->timers[PRI_TIMER_T203], t203_expire, ctrl);
}
-static void stop_t203(struct pri *pri)
+static void stop_t203(struct pri *ctrl)
{
- if (pri->t203_timer) {
- if (pri->debug & PRI_DEBUG_Q921_DUMP)
- pri_message(pri, "-- Stopping T203 timer\n");
- pri_schedule_del(pri, pri->t203_timer);
- pri->t203_timer = 0;
+ if (ctrl->t203_timer) {
+ if (ctrl->debug & PRI_DEBUG_Q921_DUMP)
+ pri_message(ctrl, "-- Stopping T203 timer\n");
+ pri_schedule_del(ctrl, ctrl->t203_timer);
+ ctrl->t203_timer = 0;
} else {
- if (pri->debug & PRI_DEBUG_Q921_DUMP)
- pri_message(pri, "-- T203 requested to stop when not started\n");
+ if (ctrl->debug & PRI_DEBUG_Q921_DUMP)
+ pri_message(ctrl, "-- T203 requested to stop when not started\n");
}
}
-static void start_t200(struct pri *pri)
+static void start_t200(struct pri *ctrl)
{
- if (pri->t200_timer) {
- if (pri->debug & PRI_DEBUG_Q921_DUMP)
- pri_message(pri, "T200 requested to start without stopping first\n");
- pri_schedule_del(pri, pri->t200_timer);
+ if (ctrl->t200_timer) {
+ if (ctrl->debug & PRI_DEBUG_Q921_DUMP)
+ pri_message(ctrl, "T200 requested to start without stopping first\n");
+ pri_schedule_del(ctrl, ctrl->t200_timer);
}
- if (pri->debug & PRI_DEBUG_Q921_DUMP)
- pri_message(pri, "-- Starting T200 timer\n");
- pri->t200_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri);
+ if (ctrl->debug & PRI_DEBUG_Q921_DUMP)
+ pri_message(ctrl, "-- Starting T200 timer\n");
+ ctrl->t200_timer = pri_schedule_event(ctrl, ctrl->timers[PRI_TIMER_T200], t200_expire, ctrl);
}
-static void stop_t200(struct pri *pri)
+static void stop_t200(struct pri *ctrl)
{
- if (pri->t200_timer) {
- if (pri->debug & PRI_DEBUG_Q921_DUMP)
- pri_message(pri, "-- Stopping T200 timer\n");
- pri_schedule_del(pri, pri->t200_timer);
- pri->t200_timer = 0;
+ if (ctrl->t200_timer) {
+ if (ctrl->debug & PRI_DEBUG_Q921_DUMP)
+ pri_message(ctrl, "-- Stopping T200 timer\n");
+ pri_schedule_del(ctrl, ctrl->t200_timer);
+ ctrl->t200_timer = 0;
} else {
- if (pri->debug & PRI_DEBUG_Q921_DUMP)
- pri_message(pri, "-- T200 requested to stop when not started\n");
+ if (ctrl->debug & PRI_DEBUG_Q921_DUMP)
+ pri_message(ctrl, "-- T200 requested to stop when not started\n");
}
}
/* This is the equivalent of the I-Frame queued up path in Figure B.7 in MULTI_FRAME_ESTABLISHED */
-static int q921_send_queued_iframes(struct pri *pri)
+static int q921_send_queued_iframes(struct pri *ctrl)
{
struct q921_frame *f;
int frames_txd = 0;
- if (pri->peer_rx_busy || (pri->v_s == Q921_ADD(pri->v_a, pri->timers[PRI_TIMER_K]))) {
- if (pri->debug & PRI_DEBUG_Q921_DUMP)
- pri_message(pri, "Couldn't transmit I frame at this time due to peer busy condition or window shut\n");
+ for (f = ctrl->txqueue; f; f = f->next) {
+ if (!f->transmitted) {
+ /* This frame has not been sent yet. */
+ break;
+ }
+ }
+ if (!f) {
+ /* The Tx queue has no pending frames. */
return 0;
}
- f = pri->txqueue;
- while (f && (pri->v_s != Q921_ADD(pri->v_a, pri->timers[PRI_TIMER_K]))) {
- if (!f->transmitted) {
- /* Send it now... */
- if (pri->debug & PRI_DEBUG_Q921_DUMP)
- pri_message(pri, "-- Finally transmitting %d, since window opened up (%d)\n", f->h.n_s, pri->timers[PRI_TIMER_K]);
- f->transmitted++;
- f->h.n_s = pri->v_s;
- f->h.n_r = pri->v_r;
- f->h.ft = 0;
- f->h.p_f = 0;
- q921_transmit(pri, (q921_h *)(&f->h), f->len);
- Q921_INC(pri->v_s);
- frames_txd++;
- pri->acknowledge_pending = 0;
+ if (ctrl->peer_rx_busy
+ || (ctrl->v_s == Q921_ADD(ctrl->v_a, ctrl->timers[PRI_TIMER_K]))) {
+ /* Don't flood debug trace if not really looking at Q.921 layer. */
+ if (ctrl->debug & (/* PRI_DEBUG_Q921_STATE | */ PRI_DEBUG_Q921_DUMP)) {
+ pri_message(ctrl,
+ "TEI=%d Couldn't transmit I-frame at this time due to peer busy condition or window shut\n",
+ ctrl->tei);
+ }
+ return 0;
+ }
+
+ /* Send all pending frames that fit in the window. */
+ for (; f; f = f->next) {
+ if (ctrl->v_s == Q921_ADD(ctrl->v_a, ctrl->timers[PRI_TIMER_K])) {
+ /* The window is no longer open. */
+ break;
+ }
+
+ /* Send it now... */
+ ++f->transmitted;
+
+ /*
+ * Send the frame out on the assigned TEI.
+ * Done now because the frame may have been queued before we
+ * had an assigned TEI.
+ */
+ f->h.h.tei = ctrl->tei;
+
+ f->h.n_s = ctrl->v_s;
+ f->h.n_r = ctrl->v_r;
+ f->h.ft = 0;
+ f->h.p_f = 0;
+ if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
+ pri_message(ctrl,
+ "TEI=%d Transmitting N(S)=%d, window is open V(A)=%d K=%d\n",
+ ctrl->tei, f->h.n_s, ctrl->v_a, ctrl->timers[PRI_TIMER_K]);
+ }
+ q921_transmit(ctrl, (q921_h *)(&f->h), f->len);
+ Q921_INC(ctrl->v_s);
+ ++frames_txd;
+
+ if (ctrl->debug & PRI_DEBUG_Q931_DUMP) {
+ /*
+ * The transmit operation might dump the Q.921 header, so logging
+ * the Q.931 message body after the transmit puts the sections of
+ * the message in the right order in the log.
+ *
+ * Also the dump is done here so the Q.931 part is decoded only
+ * once instead of for every retransmission.
+ */
+ q931_dump(ctrl, ctrl->tei, (q931_h *) f->h.data, f->len - 4, 1);
}
- f = f->next;
}
if (frames_txd) {
- if (!pri->t200_timer) {
- stop_t203(pri);
- start_t200(pri);
+ ctrl->acknowledge_pending = 0;
+ if (!ctrl->t200_timer) {
+ stop_t203(ctrl);
+ start_t200(ctrl);
}
}
return frames_txd;
}
-static void q921_reject(struct pri *pri, int pf)
+static void q921_reject(struct pri *ctrl, int pf)
{
q921_h h;
- Q921_INIT(pri, h);
+
+ Q921_INIT(ctrl, h);
h.s.x0 = 0; /* Always 0 */
h.s.ss = 2; /* Reject */
h.s.ft = 1; /* Frametype (01) */
- h.s.n_r = pri->v_r; /* Where to start retransmission */
+ h.s.n_r = ctrl->v_r; /* Where to start retransmission */
h.s.p_f = pf;
- switch(pri->localtype) {
+ switch(ctrl->localtype) {
case PRI_NETWORK:
h.h.c_r = 0;
break;
@@ -378,23 +578,26 @@
h.h.c_r = 1;
break;
default:
- pri_error(pri, "Don't know how to U/A on a type %d node\n", pri->localtype);
+ pri_error(ctrl, "Don't know how to REJ on a type %d node\n", ctrl->localtype);
return;
}
- if (pri->debug & PRI_DEBUG_Q921_DUMP)
- pri_message(pri, "Sending Reject (%d)\n", pri->v_r);
- q921_transmit(pri, &h, 4);
+ if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
+ pri_message(ctrl, "TEI=%d Sending REJ N(R)=%d\n", ctrl->tei, ctrl->v_r);
+ }
+ q921_transmit(ctrl, &h, 4);
}
-static void q921_rr(struct pri *pri, int pbit, int cmd) {
+static void q921_rr(struct pri *ctrl, int pbit, int cmd)
+{
q921_h h;
- Q921_INIT(pri, h);
+
+ Q921_INIT(ctrl, h);
h.s.x0 = 0; /* Always 0 */
h.s.ss = 0; /* Receive Ready */
h.s.ft = 1; /* Frametype (01) */
- h.s.n_r = pri->v_r; /* N/R */
+ h.s.n_r = ctrl->v_r; /* N/R */
h.s.p_f = pbit; /* Poll/Final set appropriately */
- switch(pri->localtype) {
+ switch(ctrl->localtype) {
case PRI_NETWORK:
if (cmd)
h.h.c_r = 1;
@@ -408,20 +611,23 @@
h.h.c_r = 1;
break;
default:
- pri_error(pri, "Don't know how to U/A on a type %d node\n", pri->localtype);
+ pri_error(ctrl, "Don't know how to RR on a type %d node\n", ctrl->localtype);
return;
}
- if (pri->debug & PRI_DEBUG_Q921_DUMP)
- pri_message(pri, "Sending Receiver Ready (%d)\n", pri->v_r);
- q921_transmit(pri, &h, 4);
+#if 0 /* Don't flood debug trace with RR if not really looking at Q.921 layer. */
+ if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
+ pri_message(ctrl, "TEI=%d Sending RR N(R)=%d\n", ctrl->tei, ctrl->v_r);
+ }
+#endif
+ q921_transmit(ctrl, &h, 4);
}
-static void transmit_enquiry(struct pri *pri)
+static void transmit_enquiry(struct pri *ctrl)
{
- if (!pri->own_rx_busy) {
- q921_rr(pri, 1, 1);
- pri->acknowledge_pending = 0;
- start_t200(pri);
+ if (!ctrl->own_rx_busy) {
+ q921_rr(ctrl, 1, 1);
+ ctrl->acknowledge_pending = 0;
+ start_t200(ctrl);
} else {
/* XXX: Implement me... */
}
@@ -429,71 +635,84 @@
static void t200_expire(void *vpri)
{
- struct pri *pri = vpri;
+ struct pri *ctrl = vpri;
- if (pri->debug & PRI_DEBUG_Q921_DUMP) {
- pri_message(pri, "%s\n", __FUNCTION__);
- q921_dump_pri(pri);
+ if (ctrl->debug & PRI_DEBUG_Q921_DUMP) {
+ pri_message(ctrl, "%s\n", __FUNCTION__);
+ q921_dump_pri(ctrl, ' ');
}
- pri->t200_timer = 0;
+ ctrl->t200_timer = 0;
- switch (pri->q921_state) {
+ switch (ctrl->q921_state) {
case Q921_MULTI_FRAME_ESTABLISHED:
- pri->RC = 0;
- transmit_enquiry(pri);
- pri->RC++;
- q921_setstate(pri, Q921_TIMER_RECOVERY);
+ ctrl->RC = 0;
+ transmit_enquiry(ctrl);
+ ctrl->RC++;
+ q921_setstate(ctrl, Q921_TIMER_RECOVERY);
break;
case Q921_TIMER_RECOVERY:
/* SDL Flow Figure B.8/Q.921 Page 81 */
- if (pri->RC != pri->timers[PRI_TIMER_N200]) {
+ if (ctrl->RC != ctrl->timers[PRI_TIMER_N200]) {
#if 0
- if (pri->v_s == pri->v_a) {
- transmit_enquiry(pri);
+ if (ctrl->v_s == ctrl->v_a) {
+ transmit_enquiry(ctrl);
}
#else
/* We are chosing to enquiry by default (to reduce risk of T200 timer errors at the other
- * side, instead of retransmission of the last I frame we sent */
- transmit_enquiry(pri);
+ * side, instead of retransmission of the last I-frame we sent */
+ transmit_enquiry(ctrl);
#endif
- pri->RC++;
+ ctrl->RC++;
} else {
- //pri_error(pri, "MDL-ERROR (I): T200 = N200 in timer recovery state\n");
- q921_mdl_error(pri, 'I');
- q921_establish_data_link(pri);
- pri->l3initiated = 0;
- q921_setstate(pri, Q921_AWAITING_ESTABLISHMENT);
+ q921_mdl_error(ctrl, 'I');
+ q921_establish_data_link(ctrl);
+ ctrl->l3initiated = 0;
+ q921_setstate(ctrl, Q921_AWAITING_ESTABLISHMENT);
}
break;
case Q921_AWAITING_ESTABLISHMENT:
- if (pri->RC != pri->timers[PRI_TIMER_N200]) {
- pri->RC++;
- q921_send_sabme(pri);
- start_t200(pri);
- } else {
- q921_discard_iqueue(pri);
- //pri_error(pri, "MDL-ERROR (G) : T200 expired N200 times in state %d\n", pri->q921_state);
- q921_mdl_error(pri, 'G');
- q921_setstate(pri, Q921_TEI_ASSIGNED);
+ if (ctrl->RC != ctrl->timers[PRI_TIMER_N200]) {
+ ctrl->RC++;
+ q921_send_sabme(ctrl);
+ start_t200(ctrl);
+ } else {
+ q921_discard_iqueue(ctrl);
+ q921_mdl_error(ctrl, 'G');
+ q921_setstate(ctrl, Q921_TEI_ASSIGNED);
/* DL-RELEASE indication */
- q931_dl_indication(pri, PRI_EVENT_DCHAN_DOWN);
+ q931_dl_event(ctrl, Q931_DL_EVENT_DL_RELEASE_IND);
+ }
+ break;
+ case Q921_AWAITING_RELEASE:
+ if (ctrl->RC != ctrl->timers[PRI_TIMER_N200]) {
+ ++ctrl->RC;
+ q921_send_disc(ctrl, 1);
+ start_t200(ctrl);
+ } else {
+ q921_mdl_error(ctrl, 'H');
+ /* DL-RELEASE confirm */
+ q931_dl_event(ctrl, Q931_DL_EVENT_DL_RELEASE_CONFIRM);
+ q921_setstate(ctrl, Q921_TEI_ASSIGNED);
}
break;
default:
- pri_error(pri, "Cannot handle T200 expire in state %d\n", pri->q921_state);
+ /* Looks like someone forgot to stop the T200 timer. */
+ pri_error(ctrl, "T200 expired in state %d(%s)\n",
+ ctrl->q921_state, q921_state2str(ctrl->q921_state));
+ break;
}
}
/* This is sending a DL-UNIT-DATA request */
-int q921_transmit_uiframe(struct pri *pri, void *buf, int len)
+int q921_transmit_uiframe(struct pri *ctrl, 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");
+ pri_error(ctrl, "Requested to send UI-frame larger than 512 bytes!\n");
return -1;
}
@@ -501,13 +720,13 @@
h->h.sapi = 0;
h->h.ea1 = 0;
h->h.ea2 = 1;
- h->h.tei = pri->tei;
+ h->h.tei = ctrl->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) {
+ switch(ctrl->localtype) {
case PRI_NETWORK:
h->h.c_r = 1;
break;
@@ -515,33 +734,33 @@
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);
+ pri_error(ctrl, "Don't know how to UI-frame on a type %d node\n", ctrl->localtype);
return -1;
}
memcpy(h->u.data, buf, len);
- q921_transmit(pri, h, len + 3);
+ q921_transmit(ctrl, h, len + 3);
return 0;
}
static struct pri * pri_find_tei(struct pri *vpri, int sapi, int tei)
{
- struct pri *pri;
- for (pri = PRI_MASTER(vpri); pri; pri = pri->subchannel) {
- if (pri->tei == tei && pri->sapi == sapi)
- return pri;
+ struct pri *ctrl;
+ for (ctrl = PRI_MASTER(vpri); ctrl; ctrl = ctrl->subchannel) {
+ if (ctrl->tei == tei && ctrl->sapi == sapi)
+ return ctrl;
}
return NULL;
}
-/* This is the equivalent of a DL-DATA request, as well as the I frame queued up outcome */
+/* This is the equivalent of a DL-DATA request, as well as the I-frame queued up outcome */
int q921_transmit_iframe(struct pri *vpri, int tei, void *buf, int len, int cr)
{
q921_frame *f, *prev=NULL;
- struct pri *pri;
+ struct pri *ctrl;
if (BRI_NT_PTMP(vpri)) {
if (tei == Q921_TEI_GROUP) {
@@ -549,56 +768,67 @@
return 0;
}
- pri = pri_find_tei(vpri, Q921_SAPI_CALL_CTRL, tei);
- if (!pri) {
+ ctrl = pri_find_tei(vpri, Q921_SAPI_CALL_CTRL, tei);
+ if (!ctrl) {
pri_error(vpri, "Huh?! Unable to locate PRI associated with TEI %d. Did we have to ditch it due to error conditions?\n", tei);
return 0;
}
} else if (BRI_TE_PTMP(vpri)) {
/* We don't care what the tei is, since we only support one sub and one TEI */
- pri = PRI_MASTER(vpri)->subchannel;
+ ctrl = PRI_MASTER(vpri)->subchannel;
- if (pri->q921_state == Q921_TEI_UNASSIGNED) {
- q921_tei_request(pri);
- q921_setstate(pri, Q921_ESTABLISH_AWAITING_TEI);
+ switch (ctrl->q921_state) {
+ case Q921_TEI_UNASSIGNED:
+ q921_setstate(ctrl, Q921_ESTABLISH_AWAITING_TEI);
+ q921_tei_request(ctrl);
+ break;
+ case Q921_ASSIGN_AWAITING_TEI:
+ q921_setstate(ctrl, Q921_ESTABLISH_AWAITING_TEI);
+ break;
+ default:
+ break;
}
} else {
/* Should just be PTP modes, which shouldn't have subs */
- pri = vpri;
+ ctrl = vpri;
}
/* Figure B.7/Q.921 Page 70 */
- switch (pri->q921_state) {
+ switch (ctrl->q921_state) {
case Q921_TEI_ASSIGNED:
/* If we aren't in a state compatiable with DL-DATA requests, start getting us there here */
- q921_establish_data_link(pri);
- pri->l3initiated = 1;
- q921_setstate(pri, Q921_AWAITING_ESTABLISHMENT);
+ q921_establish_data_link(ctrl);
+ ctrl->l3initiated = 1;
+ q921_setstate(ctrl, Q921_AWAITING_ESTABLISHMENT);
/* For all rest, we've done the work to get us up prior to this and fall through */
- case Q921_TEI_UNASSIGNED:
case Q921_ESTABLISH_AWAITING_TEI:
- case Q921_ASSIGN_AWAITING_TEI:
case Q921_TIMER_RECOVERY:
case Q921_AWAITING_ESTABLISHMENT:
case Q921_MULTI_FRAME_ESTABLISHED:
- for (f=pri->txqueue; f; f = f->next) prev = f;
+ /* Find queue tail. */
+ for (f = ctrl->txqueue; f; f = f->next) {
+ prev = f;
+ }
+
f = calloc(1, sizeof(q921_frame) + len + 2);
if (f) {
- Q921_INIT(pri, f->h);
- switch(pri->localtype) {
+ Q921_INIT(ctrl, f->h);
+ switch(ctrl->localtype) {
case PRI_NETWORK:
if (cr)
f->h.h.c_r = 1;
else
f->h.h.c_r = 0;
- break;
+ break;
case PRI_CPE:
if (cr)
f->h.h.c_r = 0;
else
f->h.h.c_r = 1;
- break;
+ break;
}
+
+ /* Put new frame on queue tail. */
f->next = NULL;
f->transmitted = 0;
f->len = len + 4;
@@ -606,58 +836,76 @@
if (prev)
prev->next = f;
else
- pri->txqueue = f;
+ ctrl->txqueue = f;
- if (pri->q921_state != Q921_MULTI_FRAME_ESTABLISHED) {
+ if (ctrl->q921_state != Q921_MULTI_FRAME_ESTABLISHED) {
+ if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
+ pri_message(ctrl,
+ "TEI=%d Just queued I-frame since in state %d(%s)\n",
+ ctrl->tei,
+ ctrl->q921_state, q921_state2str(ctrl->q921_state));
+ }
return 0;
}
- if (pri->peer_rx_busy || (pri->v_s == Q921_ADD(pri->v_a, pri->timers[PRI_TIMER_K]))) {
- if (pri->debug & PRI_DEBUG_Q921_DUMP)
- pri_message(pri, "Couldn't transmit I frame at this time due to peer busy condition or window shut\n");
+ if (ctrl->peer_rx_busy || (ctrl->v_s == Q921_ADD(ctrl->v_a, ctrl->timers[PRI_TIMER_K]))) {
+ if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
+ pri_message(ctrl,
+ "TEI=%d Just queued I-frame due to peer busy condition or window shut\n",
+ ctrl->tei);
+ }
return 0;
}
- q921_send_queued_iframes(pri);
+ q921_send_queued_iframes(ctrl);
return 0;
} else {
- pri_error(pri, "!! Out of memory for Q.921 transmit\n");
+ pri_error(ctrl, "!! Out of memory for Q.921 transmit\n");
return -1;
}
+ case Q921_TEI_UNASSIGNED:
+ case Q921_ASSIGN_AWAITING_TEI:
+ case Q921_AWAITING_RELEASE:
default:
- pri_error(pri, "Cannot transmit frames in state %d\n", pri->q921_state);
+ pri_error(ctrl, "Cannot transmit frames in state %d(%s)\n",
+ ctrl->q921_state, q921_state2str(ctrl->q921_state));
+ break;
}
return 0;
}
static void t203_expire(void *vpri)
{
- struct pri *pri = vpri;
- if (pri->debug & PRI_DEBUG_Q921_DUMP)
- pri_message(pri, "%s\n", __FUNCTION__);
- pri->t203_timer = 0;
- switch (pri->q921_state) {
+ struct pri *ctrl = vpri;
+
+ if (ctrl->debug & PRI_DEBUG_Q921_DUMP)
+ pri_message(ctrl, "%s\n", __FUNCTION__);
+
+ ctrl->t203_timer = 0;
+
+ switch (ctrl->q921_state) {
case Q921_MULTI_FRAME_ESTABLISHED:
- transmit_enquiry(pri);
- pri->RC = 0;
- q921_setstate(pri, Q921_TIMER_RECOVERY);
+ transmit_enquiry(ctrl);
+ ctrl->RC = 0;
+ q921_setstate(ctrl, Q921_TIMER_RECOVERY);
break;
default:
- if (pri->debug & PRI_DEBUG_Q921_DUMP)
- pri_message(pri, "T203 counter expired in weird state %d\n", pri->q921_state);
- pri->t203_timer = 0;
+ /* Looks like someone forgot to stop the T203 timer. */
+ pri_error(ctrl, "T203 expired in state %d(%s)\n",
+ ctrl->q921_state, q921_state2str(ctrl->q921_state));
+ break;
}
}
-static void q921_dump_iqueue_info(struct pri *pri, int force)
+static void q921_dump_iqueue_info(struct pri *ctrl)
{
struct q921_frame *f;
int pending = 0, unacked = 0;
unacked = pending = 0;
- for (f = pri->txqueue; f && f->next; f = f->next) {
+ for (f = ctrl->txqueue; f; f = f->next) {
if (f->transmitted) {
unacked++;
} else {
@@ -665,55 +913,52 @@
}
}
- if (force)
- pri_error(pri, "Number of pending packets %d, sent but unacked %d\n", pending, unacked);
-
- return;
+ pri_error(ctrl, "Number of pending packets %d, sent but unacked %d\n", pending, unacked);
}
-static void q921_dump_pri_by_h(struct pri *pri, q921_h *h);
+static void q921_dump_pri_by_h(struct pri *ctrl, char direction_tag, q921_h *h);
-void q921_dump(struct pri *pri, q921_h *h, int len, int showraw, int txrx)
+void q921_dump(struct pri *ctrl, q921_h *h, int len, int showraw, int txrx)
{
int x;
char *type;
char direction_tag;
- q921_dump_pri_by_h(pri, h);
-
direction_tag = txrx ? '>' : '<';
+
+ pri_message(ctrl, "\n");
+ q921_dump_pri_by_h(ctrl, direction_tag, h);
+
if (showraw) {
char *buf = malloc(len * 3 + 1);
int buflen = 0;
if (buf) {
- pri_message(pri, "\n");
for (x=0;x<len;x++)
buflen += sprintf(buf + buflen, "%02x ", h->raw[x]);
- pri_message(pri, "%c [ %s]\n", direction_tag, buf);
+ pri_message(ctrl, "%c [ %s]\n", direction_tag, buf);
free(buf);
}
}
- pri_message(pri, "\n");
switch (h->h.data[0] & Q921_FRAMETYPE_MASK) {
case 0:
case 2:
- pri_message(pri, "%c Informational frame:\n", direction_tag);
+ pri_message(ctrl, "%c Informational frame:\n", direction_tag);
break;
case 1:
- pri_message(pri, "%c Supervisory frame:\n", direction_tag);
+ pri_message(ctrl, "%c Supervisory frame:\n", direction_tag);
break;
case 3:
- pri_message(pri, "%c Unnumbered frame:\n", direction_tag);
+ pri_message(ctrl, "%c Unnumbered frame:\n", direction_tag);
break;
}
- pri_message(pri, "%c SAPI: %02d C/R: %d EA: %d\n",
+ pri_message(ctrl, "%c SAPI: %02d C/R: %d EA: %d\n",
direction_tag,
h->h.sapi,
h->h.c_r,
h->h.ea1);
- pri_message(pri, "%c TEI: %03d EA: %d\n",
+ pri_message(ctrl, "%c TEI: %03d EA: %d\n",
direction_tag,
h->h.tei,
h->h.ea2);
@@ -722,15 +967,15 @@
case 0:
case 2:
/* Informational frame */
- pri_message(pri, "%c N(S): %03d 0: %d\n",
+ pri_message(ctrl, "%c N(S): %03d 0: %d\n",
direction_tag,
h->i.n_s,
h->i.ft);
- pri_message(pri, "%c N(R): %03d P: %d\n",
+ pri_message(ctrl, "%c N(R): %03d P: %d\n",
direction_tag,
h->i.n_r,
h->i.p_f);
- pri_message(pri, "%c %d bytes of data\n",
+ pri_message(ctrl, "%c %d bytes of data\n",
direction_tag,
len - 4);
break;
@@ -748,17 +993,17 @@
type = "REJ (reject)";
break;
}
- pri_message(pri, "%c Zero: %d S: %d 01: %d [ %s ]\n",
+ pri_message(ctrl, "%c Zero: %d S: %d 01: %d [ %s ]\n",
direction_tag,
h->s.x0,
h->s.ss,
h->s.ft,
type);
- pri_message(pri, "%c N(R): %03d P/F: %d\n",
+ pri_message(ctrl, "%c N(R): %03d P/F: %d\n",
direction_tag,
h->s.n_r,
h->s.p_f);
- pri_message(pri, "%c %d bytes of data\n",
+ pri_message(ctrl, "%c %d bytes of data\n",
direction_tag,
len - 4);
break;
@@ -778,7 +1023,7 @@
type = "DISC (disconnect)";
break;
case 3:
- if (h->u.m2 == 3)
+ if (h->u.m2 == 3)
type = "SABME (set asynchronous balanced mode extended)";
else if (h->u.m2 == 0)
type = "UA (unnumbered acknowledgement)";
@@ -793,14 +1038,14 @@
break;
}
}
- pri_message(pri, "%c M3: %d P/F: %d M2: %d 11: %d [ %s ]\n",
+ pri_message(ctrl, "%c M3: %d P/F: %d M2: %d 11: %d [ %s ]\n",
direction_tag,
h->u.m3,
h->u.p_f,
h->u.m2,
h->u.ft,
type);
- pri_message(pri, "%c %d bytes of data\n",
+ pri_message(ctrl, "%c %d bytes of data\n",
direction_tag,
len - 3);
break;
@@ -839,60 +1084,66 @@
type = "Unknown";
break;
}
- pri_message(pri, "%c MDL Message: %s (%d)\n", direction_tag, type, h->u.data[3]);
- pri_message(pri, "%c RI: %d\n", direction_tag, ri);
- pri_message(pri, "%c Ai: %d E:%d\n", direction_tag, (h->u.data[4] >> 1) & 0x7f, h->u.data[4] & 1);
+ pri_message(ctrl, "%c MDL Message: %s (%d)\n", direction_tag, type, h->u.data[3]);
+ pri_message(ctrl, "%c RI: %d\n", direction_tag, ri);
+ pri_message(ctrl, "%c Ai: %d E:%d\n", direction_tag, (h->u.data[4] >> 1) & 0x7f, h->u.data[4] & 1);
}
}
-static void q921_dump_pri(struct pri *pri)
+static void q921_dump_pri(struct pri *ctrl, char direction_tag)
{
- pri_message(pri, "TEI: %d State %d\n", pri->tei, pri->q921_state);
- pri_message(pri, "V(S) %d V(A) %d V(R) %d\n", pri->v_s, pri->v_a, pri->v_r);
- pri_message(pri, "K %d, RC %d, l3initiated %d, reject_except %d ack_pend %d\n", pri->timers[PRI_TIMER_K], pri->RC, pri->l3initiated, pri->reject_exception, pri->acknowledge_pending);
- pri_message(pri, "T200 %d, N200 %d, T203 %d\n", pri->t200_timer, 3, pri->t203_timer);
+ pri_message(ctrl, "%c TEI: %d State %d(%s)\n",
+ direction_tag, ctrl->tei, ctrl->q921_state, q921_state2str(ctrl->q921_state));
+ pri_message(ctrl, "%c V(A)=%d, V(S)=%d, V(R)=%d\n",
+ direction_tag, ctrl->v_a, ctrl->v_s, ctrl->v_r);
+ pri_message(ctrl, "%c K=%d, RC=%d, l3initiated=%d, reject_except=%d, ack_pend=%d\n",
+ direction_tag, ctrl->timers[PRI_TIMER_K], ctrl->RC, ctrl->l3initiated,
+ ctrl->reject_exception, ctrl->acknowledge_pending);
+ pri_message(ctrl, "%c T200_id=%d, N200=%d, T203_id=%d\n",
+ direction_tag, ctrl->t200_timer, ctrl->timers[PRI_TIMER_N200], ctrl->t203_timer);
}
-static void q921_dump_pri_by_h(struct pri *vpri, q921_h *h)
+static void q921_dump_pri_by_h(struct pri *vpri, char direction_tag, q921_h *h)
{
- struct pri *pri = NULL;
+ struct pri *ctrl = NULL;
if (!vpri) {
return;
}
if (BRI_NT_PTMP(vpri)) {
- pri = pri_find_tei(vpri, h->h.sapi, h->h.tei);
+ ctrl = pri_find_tei(vpri, h->h.sapi, h->h.tei);
} else if (BRI_TE_PTMP(vpri)) {
- pri = PRI_MASTER(vpri)->subchannel;
+ ctrl = PRI_MASTER(vpri)->subchannel;
} else
- pri = vpri;
- if (pri) {
- q921_dump_pri(pri);
+ ctrl = vpri;
+ if (ctrl) {
+ q921_dump_pri(ctrl, direction_tag);
} else if (!PTMP_MODE(vpri)) {
pri_error(vpri, "Huh.... no pri found to dump\n");
}
}
-static pri_event *q921_receive_MDL(struct pri *pri, q921_u *h, int len)
+static pri_event *q921_receive_MDL(struct pri *ctrl, q921_u *h, int len)
{
int ri;
- struct pri *sub = pri;
+ struct pri *sub;
pri_event *res = NULL;
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 (!BRI_NT_PTMP(ctrl) && !BRI_TE_PTMP(ctrl)) {
+ return pri_mkerror(ctrl,
+ "Received MDL/TEI managemement message, but configured for mode other than PTMP!\n");
}
- if (pri->debug & PRI_DEBUG_Q921_STATE)
- pri_message(pri, "Received MDL message\n");
+ if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
+ pri_message(ctrl, "Received MDL message\n");
+ }
if (h->data[0] != 0x0f) {
- pri_error(pri, "Received MDL with unsupported management entity %02x\n", h->data[0]);
+ pri_error(ctrl, "Received MDL with unsupported management entity %02x\n", h->data[0]);
return NULL;
}
if (!(h->data[4] & 0x01)) {
- pri_error(pri, "Received MDL with multibyte TEI identifier\n");
+ pri_error(ctrl, "Received MDL with multibyte TEI identifier\n");
return NULL;
}
ri = (h->data[1] << 8) | h->data[2];
@@ -900,249 +1151,311 @@
switch(h->data[3]) {
case Q921_TEI_IDENTITY_REQUEST:
- if (!BRI_NT_PTMP(pri)) {
+ if (!BRI_NT_PTMP(ctrl)) {
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);
+ if (tei != Q921_TEI_GROUP) {
+ pri_error(ctrl, "Received TEI identity request with invalid TEI %d\n", tei);
+ q921_send_tei(ctrl, Q921_TEI_IDENTITY_DENIED, ri, tei, 1);
+ return NULL;
}
+
+ /* Find a TEI that is not allocated. */
tei = 64;
- while (sub->subchannel) {
- if (sub->subchannel->tei == tei)
- ++tei;
- sub = sub->subchannel;
- }
+ do {
+ for (sub = ctrl; sub->subchannel; sub = sub->subchannel) {
+ if (sub->subchannel->tei == tei) {
+ /* This TEI is already assigned, try next one. */
+ ++tei;
+ if (tei < Q921_TEI_GROUP) {
+ break;
+ }
+ /* XXX : TODO later sometime: Implement the TEI check procedure to reclaim some dead TEIs. */
+ pri_error(ctrl, "Reached maximum TEI quota, cannot assign new TEI\n");
+ return NULL;
+ }
+ }
+ } while (sub->subchannel);
- if (tei >= Q921_TEI_GROUP) {
- pri_error(pri, "Reached maximum TEI quota, cannot assign new TEI\n");
- return NULL;
+ if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
+ pri_message(ctrl, "Allocating new TEI %d\n", tei);
}
- sub->subchannel = __pri_new_tei(-1, pri->localtype, pri->switchtype, pri, NULL, NULL, NULL, tei, 1);
-
+ sub->subchannel = __pri_new_tei(-1, ctrl->localtype, ctrl->switchtype, ctrl, NULL, NULL, NULL, tei, 1);
if (!sub->subchannel) {
- pri_error(pri, "Unable to allocate D-channel for new TEI %d\n", tei);
+ pri_error(ctrl, "Unable to allocate D-channel for new TEI %d\n", tei);
return NULL;
}
q921_setstate(sub->subchannel, Q921_TEI_ASSIGNED);
- if (pri->debug & PRI_DEBUG_Q921_STATE) {
- pri_message(pri, "Allocating new TEI %d\n", tei);
- }
- q921_send_tei(pri, Q921_TEI_IDENTITY_ASSIGNED, ri, tei, 1);
+ q921_send_tei(ctrl, Q921_TEI_IDENTITY_ASSIGNED, ri, tei, 1);
break;
case Q921_TEI_IDENTITY_ASSIGNED:
- if (!BRI_TE_PTMP(pri))
+ if (!BRI_TE_PTMP(ctrl))
return NULL;
/* Assuming we're operating on the sub here */
- pri = pri->subchannel;
+ ctrl = ctrl->subchannel;
- switch (pri->q921_state) {
+ switch (ctrl->q921_state) {
case Q921_ASSIGN_AWAITING_TEI:
case Q921_ESTABLISH_AWAITING_TEI:
break;
default:
- pri_message(pri, "Ignoring unrequested TEI assign message\n");
+ pri_message(ctrl, "Ignoring unrequested TEI assign message\n");
return NULL;
}
- if (ri != pri->ri) {
- pri_message(pri, "TEI assignment received for invalid Ri %02x (our is %02x)\n", ri, pri->ri);
+ if (ri != ctrl->ri) {
+ pri_message(ctrl, "TEI assignment received for invalid Ri %02x (our is %02x)\n", ri, ctrl->ri);
return NULL;
}
- pri_schedule_del(pri, pri->t202_timer);
- pri->t202_timer = 0;
- pri->tei = tei;
+ pri_schedule_del(ctrl, ctrl->t202_timer);
+ ctrl->t202_timer = 0;
+
+ ctrl->tei = tei;
+ if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
+ pri_message(ctrl, "Got assigned TEI %d\n", tei);
+ }
- switch (pri->q921_state) {
+ switch (ctrl->q921_state) {
case Q921_ASSIGN_AWAITING_TEI:
- q921_setstate(pri, Q921_TEI_ASSIGNED);
- pri->ev.gen.e = PRI_EVENT_DCHAN_UP;
- res = &pri->ev;
+ q921_setstate(ctrl, Q921_TEI_ASSIGNED);
+ ctrl->ev.gen.e = PRI_EVENT_DCHAN_UP;
+ res = &ctrl->ev;
break;
case Q921_ESTABLISH_AWAITING_TEI:
- q921_establish_data_link(pri);
- pri->l3initiated = 1;
- q921_setstate(pri, Q921_AWAITING_ESTABLISHMENT);
+ q921_establish_data_link(ctrl);
+ ctrl->l3initiated = 1;
+ q921_setstate(ctrl, Q921_AWAITING_ESTABLISHMENT);
+ ctrl->ev.gen.e = PRI_EVENT_DCHAN_UP;
+ res = &ctrl->ev;
break;
default:
- pri_error(pri, "Error 3\n");
- return NULL;
+ break;
}
-
break;
case Q921_TEI_IDENTITY_CHECK_REQUEST:
- if (!BRI_TE_PTMP(pri))
+ if (!BRI_TE_PTMP(ctrl))
return NULL;
- if (pri->subchannel->q921_state < Q921_TEI_ASSIGNED)
+ if (ctrl->subchannel->q921_state < Q921_TEI_ASSIGNED) {
+ /* We do not have a TEI. */
return NULL;
+ }
/* If it's addressed to the group TEI or to our TEI specifically, we respond */
- if ((tei == Q921_TEI_GROUP) || (tei == pri->subchannel->tei))
- q921_send_tei(pri, Q921_TEI_IDENTITY_CHECK_RESPONSE, random() % 65535, pri->subchannel->tei, 1);
-
+ if ((tei == Q921_TEI_GROUP) || (tei == ctrl->subchannel->tei)) {
+ q921_send_tei(ctrl, Q921_TEI_IDENTITY_CHECK_RESPONSE, random() % 65535, ctrl->subchannel->tei, 1);
+ }
break;
case Q921_TEI_IDENTITY_REMOVE:
- if (!BRI_TE_PTMP(pri))
+ if (!BRI_TE_PTMP(ctrl))
return NULL;
- if ((tei == Q921_TEI_GROUP) || (tei == pri->subchannel->tei)) {
- q921_setstate(pri->subchannel, Q921_TEI_UNASSIGNED);
- q921_start(pri->subchannel);
+ if (ctrl->subchannel->q921_state < Q921_TEI_ASSIGNED) {
+ /* We do not have a TEI. */
+ return NULL;
+ }
+
+ /* If it's addressed to the group TEI or to our TEI specifically, we respond */
+ if ((tei == Q921_TEI_GROUP) || (tei == ctrl->subchannel->tei)) {
+ q921_mdl_remove(ctrl->subchannel);
+ q921_start(ctrl->subchannel);
}
+ break;
}
return res; /* Do we need to return something??? */
}
-static int is_command(struct pri *pri, q921_h *h)
+static int is_command(struct pri *ctrl, q921_h *h)
{
int command = 0;
int c_r = h->s.h.c_r;
- if ((pri->localtype == PRI_NETWORK && c_r == 0) ||
- (pri->localtype == PRI_CPE && c_r == 1))
+ if ((ctrl->localtype == PRI_NETWORK && c_r == 0) ||
+ (ctrl->localtype == PRI_CPE && c_r == 1))
command = 1;
return command;
}
-static void q921_clear_exception_conditions(struct pri *pri)
+static void q921_clear_exception_conditions(struct pri *ctrl)
{
- pri->own_rx_busy = 0;
- pri->peer_rx_busy = 0;
- pri->reject_exception = 0;
- pri->acknowledge_pending = 0;
+ ctrl->own_rx_busy = 0;
+ ctrl->peer_rx_busy = 0;
+ ctrl->reject_exception = 0;
+ ctrl->acknowledge_pending = 0;
}
-static pri_event * q921_sabme_rx(struct pri *pri, q921_h *h)
+static pri_event * q921_sabme_rx(struct pri *ctrl, q921_h *h)
{
pri_event *res = NULL;
+ enum Q931_DL_EVENT delay_q931_dl_event;
- switch (pri->q921_state) {
+ switch (ctrl->q921_state) {
case Q921_TIMER_RECOVERY:
/* Timer recovery state handling is same as multiframe established */
case Q921_MULTI_FRAME_ESTABLISHED:
/* Send Unnumbered Acknowledgement */
- q921_send_ua(pri, h->u.p_f);
- q921_clear_exception_conditions(pri);
- //pri_error(pri, "MDL-ERROR (F), SABME in state %d\n", pri->q921_state);
- q921_mdl_error(pri, 'F');
- if (pri->v_s != pri->v_a) {
- q921_discard_iqueue(pri);
+ q921_send_ua(ctrl, h->u.p_f);
+ q921_clear_exception_conditions(ctrl);
+ q921_mdl_error(ctrl, 'F');
+ if (ctrl->v_s != ctrl->v_a) {
+ q921_discard_iqueue(ctrl);
/* DL-ESTABLISH indication */
- q931_dl_indication(pri, PRI_EVENT_DCHAN_UP);
+ delay_q931_dl_event = Q931_DL_EVENT_DL_ESTABLISH_IND;
+ } else {
+ delay_q931_dl_event = Q931_DL_EVENT_NONE;
+ }
+ stop_t200(ctrl);
+ start_t203(ctrl);
+ ctrl->v_s = ctrl->v_a = ctrl->v_r = 0;
+ q921_setstate(ctrl, Q921_MULTI_FRAME_ESTABLISHED);
+ if (delay_q931_dl_event != Q931_DL_EVENT_NONE) {
+ /* Delayed because Q.931 could send STATUS messages. */
+ q931_dl_event(ctrl, delay_q931_dl_event);
}
- stop_t200(pri);
- start_t203(pri);
- pri->v_s = pri->v_a = pri->v_r = 0;
- q921_setstate(pri, Q921_MULTI_FRAME_ESTABLISHED);
break;
case Q921_TEI_ASSIGNED:
- q921_send_ua(pri, h->u.p_f);
- q921_clear_exception_conditions(pri);
- pri->v_s = pri->v_a = pri->v_r = 0;
+ q921_send_ua(ctrl, h->u.p_f);
+ q921_clear_exception_conditions(ctrl);
+ ctrl->v_s = ctrl->v_a = ctrl->v_r = 0;
/* DL-ESTABLISH indication */
- q931_dl_indication(pri, PRI_EVENT_DCHAN_UP);
- if (PTP_MODE(pri)) {
- pri->ev.gen.e = PRI_EVENT_DCHAN_UP;
- res = &pri->ev;
+ delay_q931_dl_event = Q931_DL_EVENT_DL_ESTABLISH_IND;
+ if (PTP_MODE(ctrl)) {
+ ctrl->ev.gen.e = PRI_EVENT_DCHAN_UP;
+ res = &ctrl->ev;
+ }
+ start_t203(ctrl);
+ q921_setstate(ctrl, Q921_MULTI_FRAME_ESTABLISHED);
+ if (delay_q931_dl_event != Q931_DL_EVENT_NONE) {
+ /* Delayed because Q.931 could send STATUS messages. */
+ q931_dl_event(ctrl, delay_q931_dl_event);
}
- start_t203(pri);
- q921_setstate(pri, Q921_MULTI_FRAME_ESTABLISHED);
break;
case Q921_AWAITING_ESTABLISHMENT:
- q921_send_ua(pri, h->u.p_f);
+ q921_send_ua(ctrl, h->u.p_f);
break;
case Q921_AWAITING_RELEASE:
+ q921_send_dm(ctrl, h->u.p_f);
+ break;
default:
- pri_error(pri, "Cannot handle SABME in state %d\n", pri->q921_state);
+ pri_error(ctrl, "Cannot handle SABME in state %d(%s)\n",
+ ctrl->q921_state, q921_state2str(ctrl->q921_state));
+ break;
}
return res;
}
-static pri_event *q921_disc_rx(struct pri *pri, q921_h *h)
+static pri_event *q921_disc_rx(struct pri *ctrl, q921_h *h)
{
pri_event * res = NULL;
- switch (pri->q921_state) {
+ if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
+ pri_message(ctrl, "TEI=%d Got DISC\n", ctrl->tei);
+ }
+
+ switch (ctrl->q921_state) {
+ case Q921_TEI_ASSIGNED:
+ case Q921_AWAITING_ESTABLISHMENT:
+ q921_send_dm(ctrl, h->u.p_f);
+ break;
case Q921_AWAITING_RELEASE:
- q921_send_ua(pri, h->u.p_f);
+ q921_send_ua(ctrl, h->u.p_f);
break;
case Q921_MULTI_FRAME_ESTABLISHED:
case Q921_TIMER_RECOVERY:
- q921_discard_iqueue(pri);
- q921_send_ua(pri, h->u.p_f);
- /* DL-RELEASE Indication */
- q931_dl_indication(pri, PRI_EVENT_DCHAN_DOWN);
-
- stop_t200(pri);
- if (pri->q921_state == Q921_MULTI_FRAME_ESTABLISHED)
- stop_t203(pri);
- q921_setstate(pri, Q921_TEI_ASSIGNED);
+ q921_discard_iqueue(ctrl);
+ q921_send_ua(ctrl, h->u.p_f);
+ /* DL-RELEASE indication */
+ q931_dl_event(ctrl, Q931_DL_EVENT_DL_RELEASE_IND);
+ stop_t200(ctrl);
+ if (ctrl->q921_state == Q921_MULTI_FRAME_ESTABLISHED)
+ stop_t203(ctrl);
+ q921_setstate(ctrl, Q921_TEI_ASSIGNED);
+ q921_restart_ptp_link_if_needed(ctrl);
break;
default:
- pri_error(pri, "Don't know what to do with DISC in state %d\n", pri->q921_state);
+ pri_error(ctrl, "Don't know what to do with DISC in state %d(%s)\n",
+ ctrl->q921_state, q921_state2str(ctrl->q921_state));
break;
-
}
return res;
}
-static void q921_mdl_remove(struct pri *pri)
+static void q921_mdl_remove(struct pri *ctrl)
{
- switch (pri->q921_state) {
+ int mdl_free_me;
+
+ if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
+ pri_message(ctrl, "MDL-REMOVE: Removing TEI %d\n", ctrl->tei);
+ }
+ if (BRI_NT_PTMP(ctrl)) {
+ if (ctrl == PRI_MASTER(ctrl)) {
+ pri_error(ctrl, "Bad bad bad! Cannot MDL-REMOVE master\n");
+ return;
+ }
+ mdl_free_me = 1;
+ } else {
+ mdl_free_me = 0;
+ }
+
+ switch (ctrl->q921_state) {
case Q921_TEI_ASSIGNED:
/* XXX: deviation! Since we don't have a UI queue, we just discard our I-queue */
- q921_discard_iqueue(pri);
- q921_setstate(pri, Q921_TEI_UNASSIGNED);
+ q921_discard_iqueue(ctrl);
+ q921_setstate(ctrl, Q921_TEI_UNASSIGNED);
break;
case Q921_AWAITING_ESTABLISHMENT:
- q921_discard_iqueue(pri);
+ q921_discard_iqueue(ctrl);
/* DL-RELEASE indication */
- q931_dl_indication(pri, PRI_EVENT_DCHAN_DOWN);
-
- stop_t200(pri);
- q921_setstate(pri, Q921_TEI_UNASSIGNED);
+ q931_dl_event(ctrl, Q931_DL_EVENT_DL_RELEASE_IND);
+ stop_t200(ctrl);
+ q921_setstate(ctrl, Q921_TEI_UNASSIGNED);
break;
case Q921_AWAITING_RELEASE:
- q921_discard_iqueue(pri);
+ q921_discard_iqueue(ctrl);
/* DL-RELEASE confirm */
- stop_t200(pri);
+ q931_dl_event(ctrl, Q931_DL_EVENT_DL_RELEASE_CONFIRM);
+ stop_t200(ctrl);
+ q921_setstate(ctrl, Q921_TEI_UNASSIGNED);
break;
case Q921_MULTI_FRAME_ESTABLISHED:
- q921_discard_iqueue(pri);
+ q921_discard_iqueue(ctrl);
/* DL-RELEASE indication */
- q931_dl_indication(pri, PRI_EVENT_DCHAN_DOWN);
- stop_t200(pri);
- stop_t203(pri);
- q921_setstate(pri, Q921_TEI_UNASSIGNED);
+ q931_dl_event(ctrl, Q931_DL_EVENT_DL_RELEASE_IND);
+ stop_t200(ctrl);
+ stop_t203(ctrl);
+ q921_setstate(ctrl, Q921_TEI_UNASSIGNED);
break;
case Q921_TIMER_RECOVERY:
- q921_discard_iqueue(pri);
+ q921_discard_iqueue(ctrl);
/* DL-RELEASE indication */
- q931_dl_indication(pri, PRI_EVENT_DCHAN_DOWN);
- stop_t200(pri);
- q921_setstate(pri, Q921_TEI_UNASSIGNED);
- default:
- pri_error(pri, "Cannot handle MDL remove when PRI is in state %d\n", pri->q921_state);
+ q931_dl_event(ctrl, Q931_DL_EVENT_DL_RELEASE_IND);
+ stop_t200(ctrl);
+ q921_setstate(ctrl, Q921_TEI_UNASSIGNED);
break;
+ default:
+ pri_error(ctrl, "MDL-REMOVE when in state %d(%s)\n",
+ ctrl->q921_state, q921_state2str(ctrl->q921_state));
+ return;
}
- if (BRI_NT_PTMP(pri) && pri->q921_state == Q921_TEI_UNASSIGNED) {
- if (pri == PRI_MASTER(pri)) {
- pri_error(pri, "Bad bad bad! Asked to free master\n");
- return;
- }
- pri->mdl_free_me = 1;
- }
+ q931_dl_event(ctrl, Q931_DL_EVENT_TEI_REMOVAL);
+
+ /*
+ * Negate the TEI value so debug messages will display a
+ * negated TEI when it is actually unassigned.
+ */
+ ctrl->tei = -ctrl->tei;
+
+ ctrl->mdl_free_me = mdl_free_me;
}
-static int q921_mdl_handle_network_error(struct pri *pri, char error)
+static int q921_mdl_handle_network_error(struct pri *ctrl, char error)
{
int handled = 0;
switch (error) {
@@ -1150,7 +1463,7 @@
case 'D':
case 'G':
case 'H':
- q921_mdl_remove(pri);
+ q921_mdl_remove(ctrl);
handled = 1;
break;
case 'A':
@@ -1158,15 +1471,18 @@
case 'E':
case 'F':
case 'I':
+ case 'J':
+ case 'K':
+ break;
default:
- pri_error(pri, "Network MDL can't handle error of type %c\n", error);
+ pri_error(ctrl, "Network MDL can't handle error of type %c\n", error);
break;
}
return handled;
}
-static int q921_mdl_handle_cpe_error(struct pri *pri, char error)
+static int q921_mdl_handle_cpe_error(struct pri *ctrl, char error)
{
int handled = 0;
@@ -1175,7 +1491,7 @@
case 'D':
case 'G':
case 'H':
- q921_mdl_remove(pri);
+ q921_mdl_remove(ctrl);
handled = 1;
break;
case 'A':
@@ -1183,104 +1499,95 @@
case 'E':
case 'F':
case 'I':
+ case 'J':
+ case 'K':
break;
default:
- pri_error(pri, "CPE MDL can't handle error of type %c\n", error);
+ pri_error(ctrl, "CPE MDL can't handle error of type %c\n", error);
break;
}
return handled;
}
-static int q921_mdl_handle_ptp_error(struct pri *pri, char error)
+static int q921_mdl_handle_ptp_error(struct pri *ctrl, char error)
{
int handled = 0;
/* This is where we act a bit like L3 instead of L2, since we've got an L3 that depends on us
* keeping L2 automatically alive and happy for point to point links */
switch (error) {
+ case 'Z':
+ /* This is a special MDL error that actually isn't a spec error, but just so we
+ * have an asynchronous context from the state machine to kick a PTP link back
+ * up after being requested to drop politely (using DISC or DM) */
case 'G':
/* We pick it back up and put it back together for this case */
- q921_discard_iqueue(pri);
- q921_establish_data_link(pri);
- q921_setstate(pri, Q921_AWAITING_ESTABLISHMENT);
- pri->l3initiated = 1;
+ q921_discard_iqueue(ctrl);
+ q921_establish_data_link(ctrl);
+ q921_setstate(ctrl, Q921_AWAITING_ESTABLISHMENT);
+ ctrl->l3initiated = 1;
- pri->schedev = 1;
- pri->ev.gen.e = PRI_EVENT_DCHAN_DOWN;
+ ctrl->schedev = 1;
+ ctrl->ev.gen.e = PRI_EVENT_DCHAN_DOWN;
handled = 1;
break;
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ case 'H':
+ case 'I':
+ case 'J':
+ case 'K':
+ break;
default:
- pri_error(pri, "PTP MDL can't handle error of type %c\n", error);
+ pri_error(ctrl, "PTP MDL can't handle error of type %c\n", error);
+ break;
}
return handled;
}
-static void q921_mdl_handle_error(struct pri *pri, char error, int errored_state)
+static void q921_restart_ptp_link_if_needed(struct pri *ctrl)
{
- int handled = 0;
- if (PTP_MODE(pri)) {
- handled = q921_mdl_handle_ptp_error(pri, error);
+ if (PTP_MODE(ctrl)) {
+ q921_mdl_error(ctrl, 'Z');
+ }
+}
+
+static void q921_mdl_handle_error(struct pri *ctrl, char error, int errored_state)
+{
+ if (PTP_MODE(ctrl)) {
+ q921_mdl_handle_ptp_error(ctrl, error);
} else {
- if (pri->localtype == PRI_NETWORK) {
- handled = q921_mdl_handle_network_error(pri, error);
+ if (ctrl->localtype == PRI_NETWORK) {
+ q921_mdl_handle_network_error(ctrl, error);
} else {
- handled = q921_mdl_handle_cpe_error(pri, error);
+ q921_mdl_handle_cpe_error(ctrl, error);
}
}
-
- if (handled)
- return;
-
- switch (error) {
- case 'C':
- pri_error(pri, "MDL-ERROR (C): UA in state %d\n", errored_state);
- break;
- case 'D':
- pri_error(pri, "MDL-ERROR (D): UA in state %d\n", errored_state);
- break;
- case 'A':
- pri_error(pri, "MDL-ERROR (A): Got supervisory frame with p_f bit set to 1 in state %d\n", errored_state);
- break;
- case 'I':
- pri_error(pri, "MDL-ERROR (I): T200 = N200 in timer recovery state %d\n", errored_state);
- break;
- case 'G':
- pri_error(pri, "MDL-ERROR (G) : T200 expired N200 times in state %d\n", errored_state);
- break;
- case 'F':
- pri_error(pri, "MDL-ERROR (F), SABME in state %d\n", errored_state);
- break;
- case 'H':
- case 'B':
- case 'E':
- case 'J':
- default:
- pri_error(pri, "MDL-ERROR (%c) in state %d\n", error, errored_state);
-
- }
-
- return;
}
static void q921_mdl_handle_error_callback(void *vpri)
{
- struct pri *pri = vpri;
+ struct pri *ctrl = vpri;
- q921_mdl_handle_error(pri, pri->mdl_error, pri->mdl_error_state);
+ q921_mdl_handle_error(ctrl, ctrl->mdl_error, ctrl->mdl_error_state);
- pri->mdl_error = 0;
- pri->mdl_timer = 0;
+ ctrl->mdl_error = 0;
+ ctrl->mdl_timer = 0;
- if (pri->mdl_free_me) {
- struct pri *master = PRI_MASTER(pri);
+ if (ctrl->mdl_free_me) {
+ struct pri *master = PRI_MASTER(ctrl);
struct pri *freep = NULL, *prev, *cur;
prev = master;
cur = master->subchannel;
while (cur) {
- if (cur == pri) {
+ if (cur == ctrl) {
prev->subchannel = cur->subchannel;
freep = cur;
break;
@@ -1290,12 +1597,12 @@
}
if (freep == NULL) {
- pri_error(pri, "Huh!? no match found in list for TEI %d\n", pri->tei);
+ pri_error(ctrl, "Huh!? no match found in list for TEI %d\n", -ctrl->tei);
return;
}
- if (pri->debug & PRI_DEBUG_Q921_STATE) {
- pri_message(pri, "Freeing TEI of %d\n", freep->tei);
+ if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
+ pri_message(ctrl, "Freeing TEI of %d\n", -freep->tei);
}
__pri_free_tei(freep);
@@ -1304,171 +1611,274 @@
return;
}
-static void q921_mdl_error(struct pri *pri, char error)
+static void q921_mdl_error(struct pri *ctrl, char error)
{
- if (pri->mdl_error) {
- pri_error(pri, "Trying to queue an MDL error when one is already scheduled\n");
+ int is_debug_q921_state;
+
+ /* Log the MDL-ERROR event when detected. */
+ is_debug_q921_state = (ctrl->debug & PRI_DEBUG_Q921_STATE);
+ switch (error) {
+ case 'A':
+ pri_message(ctrl,
+ "TEI=%d MDL-ERROR (A): Got supervisory frame with F=1 in state %d(%s)\n",
+ ctrl->tei, ctrl->q921_state, q921_state2str(ctrl->q921_state));
+ break;
+ case 'B':
+ case 'E':
+ pri_message(ctrl, "TEI=%d MDL-ERROR (%c): DM (F=%c) in state %d(%s)\n",
+ ctrl->tei, error, (error == 'B') ? '1' : '0',
+ ctrl->q921_state, q921_state2str(ctrl->q921_state));
+ break;
+ case 'C':
+ case 'D':
+ if (is_debug_q921_state || PTP_MODE(ctrl)) {
+ pri_message(ctrl, "TEI=%d MDL-ERROR (%c): UA (F=%c) in state %d(%s)\n",
+ ctrl->tei, error, (error == 'C') ? '1' : '0',
+ ctrl->q921_state, q921_state2str(ctrl->q921_state));
+ }
+ break;
+ case 'F':
+ /*
+ * The peer is restarting the link.
+ * Some reasons this might happen:
+ * 1) Our link establishment requests collided.
+ * 2) They got reset.
+ * 3) They could not talk to us for some reason because
+ * their T200 timer expired N200 times.
+ * 4) They got an MDL-ERROR (J).
+ */
+ if (is_debug_q921_state) {
+ /*
+ * This message is rather annoying and is normal for
+ * reasons 1-3 above.
+ */
+ pri_message(ctrl, "TEI=%d MDL-ERROR (F): SABME in state %d(%s)\n",
+ ctrl->tei, ctrl->q921_state, q921_state2str(ctrl->q921_state));
+ }
+ break;
+ case 'G':
+ /* We could not get a response from the peer. */
+ if (is_debug_q921_state) {
+ pri_message(ctrl,
+ "TEI=%d MDL-ERROR (G): T200 expired N200 times sending SABME in state %d(%s)\n",
+ ctrl->tei, ctrl->q921_state, q921_state2str(ctrl->q921_state));
+ }
+ break;
+ case 'H':
+ /* We could not get a response from the peer. */
+ if (is_debug_q921_state) {
+ pri_message(ctrl,
+ "TEI=%d MDL-ERROR (H): T200 expired N200 times sending DISC in state %d(%s)\n",
+ ctrl->tei, ctrl->q921_state, q921_state2str(ctrl->q921_state));
+ }
+ break;
+ case 'I':
+ /* We could not get a response from the peer. */
+ if (is_debug_q921_state) {
+ pri_message(ctrl,
+ "TEI=%d MDL-ERROR (I): T200 expired N200 times sending RR/RNR in state %d(%s)\n",
+ ctrl->tei, ctrl->q921_state, q921_state2str(ctrl->q921_state));
+ }
+ break;
+ case 'J':
+ /* N(R) not within ack window. */
+ pri_error(ctrl, "TEI=%d MDL-ERROR (J): N(R) error in state %d(%s)\n",
+ ctrl->tei, ctrl->q921_state, q921_state2str(ctrl->q921_state));
+ break;
+ case 'K':
+ /*
+ * Received a frame reject frame.
+ * The other end does not like what we are doing at all for some reason.
+ */
+ pri_error(ctrl, "TEI=%d MDL-ERROR (K): FRMR in state %d(%s)\n",
+ ctrl->tei, ctrl->q921_state, q921_state2str(ctrl->q921_state));
+ break;
+ case 'Z':
+ if (is_debug_q921_state) {
+ /* Fake MDL-ERROR to kick start PTP L2 link back up. */
+ pri_message(ctrl,
+ "TEI=%d MDL-ERROR (Z): Kick starting L2 link in state %d(%s)\n",
+ ctrl->tei, ctrl->q921_state, q921_state2str(ctrl->q921_state));
+ }
+ break;
+ default:
+ pri_message(ctrl, "TEI=%d MDL-ERROR (%c): in state %d(%s)\n",
+ ctrl->tei, error, ctrl->q921_state, q921_state2str(ctrl->q921_state));
+ break;
+ }
+
+ if (ctrl->mdl_error) {
+ /* This should not happen. */
+ pri_error(ctrl,
+ "Trying to queue MDL-ERROR (%c) when MDL-ERROR (%c) is already scheduled\n",
+ error, ctrl->mdl_error);
return;
}
- pri->mdl_error = error;
- pri->mdl_error_state = pri->q921_state;
- pri->mdl_timer = pri_schedule_event(pri, 0, q921_mdl_handle_error_callback, pri);
+ ctrl->mdl_error = error;
+ ctrl->mdl_error_state = ctrl->q921_state;
+ ctrl->mdl_timer = pri_schedule_event(ctrl, 0, q921_mdl_handle_error_callback, ctrl);
}
-static pri_event *q921_ua_rx(struct pri *pri, q921_h *h)
+static pri_event *q921_ua_rx(struct pri *ctrl, q921_h *h)
{
- pri_event * res = NULL;
+ pri_event *res = NULL;
+ enum Q931_DL_EVENT delay_q931_dl_event;
+
+ if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
+ pri_message(ctrl, "TEI=%d Got UA\n", ctrl->tei);
+ }
- switch (pri->q921_state) {
+ switch (ctrl->q921_state) {
case Q921_TEI_ASSIGNED:
- //pri_error(pri, "MDL-ERROR (C, D): UA received in state %d\n", pri->q921_state);
- if (h->u.p_f)
- q921_mdl_error(pri, 'C');
- else
- q921_mdl_error(pri, 'D');
+ case Q921_MULTI_FRAME_ESTABLISHED:
+ case Q921_TIMER_RECOVERY:
+ if (h->u.p_f) {
+ q921_mdl_error(ctrl, 'C');
+ } else {
+ q921_mdl_error(ctrl, 'D');
+ }
break;
case Q921_AWAITING_ESTABLISHMENT:
if (!h->u.p_f) {
- pri_error(pri, "MDL-ERROR: Received UA with F = 0 while awaiting establishment\n");
+ q921_mdl_error(ctrl, 'D');
break;
}
- if (!pri->l3initiated) {
- if (pri->v_s != pri->v_a) {
- q921_discard_iqueue(pri);
- /* return DL-ESTABLISH-INDICATION */
- q931_dl_indication(pri, PRI_EVENT_DCHAN_UP);
+ delay_q931_dl_event = Q931_DL_EVENT_NONE;
+ if (!ctrl->l3initiated) {
+ if (ctrl->v_s != ctrl->v_a) {
+ q921_discard_iqueue(ctrl);
+ /* DL-ESTABLISH indication */
+ delay_q931_dl_event = Q931_DL_EVENT_DL_ESTABLISH_IND;
}
} else {
- /* Might not want this... */
- pri->l3initiated = 0;
- /* return DL-ESTABLISH-CONFIRM */
+ ctrl->l3initiated = 0;
+ /* DL-ESTABLISH confirm */
+ delay_q931_dl_event = Q931_DL_EVENT_DL_ESTABLISH_CONFIRM;
}
- if (PTP_MODE(pri)) {
- pri->ev.gen.e = PRI_EVENT_DCHAN_UP;
- res = &pri->ev;
+ if (PTP_MODE(ctrl)) {
+ ctrl->ev.gen.e = PRI_EVENT_DCHAN_UP;
+ res = &ctrl->ev;
}
- stop_t200(pri);
- start_t203(pri);
+ stop_t200(ctrl);
+ start_t203(ctrl);
- pri->v_r = pri->v_s = pri->v_a = 0;
+ ctrl->v_r = ctrl->v_s = ctrl->v_a = 0;
- q921_setstate(pri, Q921_MULTI_FRAME_ESTABLISHED);
+ q921_setstate(ctrl, Q921_MULTI_FRAME_ESTABLISHED);
+ if (delay_q931_dl_event != Q931_DL_EVENT_NONE) {
+ /* Delayed because Q.931 could send STATUS messages. */
+ q931_dl_event(ctrl, delay_q931_dl_event);
+ }
break;
case Q921_AWAITING_RELEASE:
if (!h->u.p_f) {
- //pri_error(pri, "MDL-ERROR (D): UA in state %d w with P_F bit 0\n", pri->q921_state);
- q921_mdl_error(pri, 'D');
+ q921_mdl_error(ctrl, 'D');
} else {
- /* return DL-RELEASE-CONFIRM */
- stop_t200(pri);
- q921_setstate(pri, Q921_TEI_ASSIGNED);
+ /* DL-RELEASE confirm */
+ q931_dl_event(ctrl, Q931_DL_EVENT_DL_RELEASE_CONFIRM);
+ stop_t200(ctrl);
+ q921_setstate(ctrl, Q921_TEI_ASSIGNED);
}
break;
- case Q921_MULTI_FRAME_ESTABLISHED:
- case Q921_TIMER_RECOVERY:
- //pri_error(pri, "MDL-ERROR (C, D) UA in state %d\n", pri->q921_state);
- q921_mdl_error(pri, 'C');
- break;
default:
- pri_error(pri, "Don't know what to do with UA in state %d\n", pri->q921_state);
+ pri_error(ctrl, "Don't know what to do with UA in state %d(%s)\n",
+ ctrl->q921_state, q921_state2str(ctrl->q921_state));
break;
-
}
return res;
}
-static void q921_enquiry_response(struct pri *pri)
+static void q921_enquiry_response(struct pri *ctrl)
{
- if (pri->own_rx_busy) {
+ if (ctrl->own_rx_busy) {
/* XXX : TODO later sometime */
- pri_error(pri, "Implement me %s: own_rx_busy\n", __FUNCTION__);
- //q921_rnr(pri);
+ pri_error(ctrl, "Implement me %s: own_rx_busy\n", __FUNCTION__);
+ //q921_rnr(ctrl);
} else {
- q921_rr(pri, 1, 0);
+ q921_rr(ctrl, 1, 0);
}
- pri->acknowledge_pending = 0;
+ ctrl->acknowledge_pending = 0;
}
-static void n_r_error_recovery(struct pri *pri)
+static void n_r_error_recovery(struct pri *ctrl)
{
- q921_mdl_error(pri, 'J');
+ q921_mdl_error(ctrl, 'J');
- q921_establish_data_link(pri);
+ q921_establish_data_link(ctrl);
- pri->l3initiated = 0;
+ ctrl->l3initiated = 0;
}
-static void update_v_a(struct pri *pri, int n_r)
+static void update_v_a(struct pri *ctrl, int n_r)
{
int idealcnt = 0, realcnt = 0;
int x;
/* Cancel each packet as necessary */
- if (pri->debug & PRI_DEBUG_Q921_DUMP)
- pri_message(pri, "-- ACKing all packets from %d to (but not including) %d\n", pri->v_a, n_r);
- for (x = pri->v_a; x != n_r; Q921_INC(x)) {
+ if (ctrl->debug & PRI_DEBUG_Q921_DUMP)
+ pri_message(ctrl, "-- Got ACK for N(S)=%d to (but not including) N(S)=%d\n", ctrl->v_a, n_r);
+ for (x = ctrl->v_a; x != n_r; Q921_INC(x)) {
idealcnt++;
- realcnt += q921_ack_packet(pri, x);
+ realcnt += q921_ack_packet(ctrl, x);
}
if (idealcnt != realcnt) {
- pri_error(pri, "Ideally should have ack'd %d frames, but actually ack'd %d. This is not good.\n", idealcnt, realcnt);
- q921_dump_iqueue_info(pri, 1);
- } else {
- q921_dump_iqueue_info(pri, 0);
+ pri_error(ctrl, "Ideally should have ack'd %d frames, but actually ack'd %d. This is not good.\n", idealcnt, realcnt);
+ q921_dump_iqueue_info(ctrl);
}
- pri->v_a = n_r;
+ ctrl->v_a = n_r;
}
-static int n_r_is_valid(struct pri *pri, int n_r)
+static int n_r_is_valid(struct pri *ctrl, int n_r)
{
int x;
- for (x=pri->v_a; (x != pri->v_s) && (x != n_r); Q921_INC(x));
+ /* Is V(A) <= N(R) <= V(S) */
+ for (x = ctrl->v_a; x != n_r && x != ctrl->v_s; Q921_INC(x)) {
+ }
if (x != n_r) {
- pri_error(pri, "N(R) %d not within ack window! Bad Bad Bad!\n", n_r);
return 0;
} else {
return 1;
}
}
-static int q921_invoke_retransmission(struct pri *pri, int n_r);
+static int q921_invoke_retransmission(struct pri *ctrl, int n_r);
-static pri_event * timer_recovery_rr_rej_rx(struct pri *pri, q921_h *h)
+static pri_event * timer_recovery_rr_rej_rx(struct pri *ctrl, q921_h *h)
{
/* Figure B.7/Q.921 Page 74 */
- pri->peer_rx_busy = 0;
+ ctrl->peer_rx_busy = 0;
- if (is_command(pri, h)) {
+ if (is_command(ctrl, h)) {
if (h->s.p_f) {
/* Enquiry response */
- q921_enquiry_response(pri);
+ q921_enquiry_response(ctrl);
}
- if (n_r_is_valid(pri, h->s.n_r)) {
- update_v_a(pri, h->s.n_r);
+ if (n_r_is_valid(ctrl, h->s.n_r)) {
+ update_v_a(ctrl, h->s.n_r);
} else {
goto n_r_error_out;
}
} else {
if (!h->s.p_f) {
- if (n_r_is_valid(pri, h->s.n_r)) {
- update_v_a(pri, h->s.n_r);
+ if (n_r_is_valid(ctrl, h->s.n_r)) {
+ update_v_a(ctrl, h->s.n_r);
} else {
goto n_r_error_out;
}
} else {
- if (n_r_is_valid(pri, h->s.n_r)) {
- update_v_a(pri, h->s.n_r);
- stop_t200(pri);
- start_t203(pri);
- q921_invoke_retransmission(pri, h->s.n_r);
- q921_setstate(pri, Q921_MULTI_FRAME_ESTABLISHED);
+ if (n_r_is_valid(ctrl, h->s.n_r)) {
+ update_v_a(ctrl, h->s.n_r);
+ stop_t200(ctrl);
+ start_t203(ctrl);
+ q921_invoke_retransmission(ctrl, h->s.n_r);
+ q921_setstate(ctrl, Q921_MULTI_FRAME_ESTABLISHED);
} else {
goto n_r_error_out;
}
@@ -1476,600 +1886,700 @@
}
return NULL;
n_r_error_out:
- n_r_error_recovery(pri);
- q921_setstate(pri, Q921_AWAITING_ESTABLISHMENT);
+ n_r_error_recovery(ctrl);
+ q921_setstate(ctrl, Q921_AWAITING_ESTABLISHMENT);
return NULL;
}
-static pri_event *q921_rr_rx(struct pri *pri, q921_h *h)
+static pri_event *q921_rr_rx(struct pri *ctrl, q921_h *h)
{
pri_event * res = NULL;
- switch (pri->q921_state) {
+
+#if 0 /* Don't flood debug trace with RR if not really looking at Q.921 layer. */
+ if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
+ pri_message(ctrl, "TEI=%d Got RR N(R)=%d\n", ctrl->tei, h->s.n_r);
+ }
+#endif
+
+ switch (ctrl->q921_state) {
case Q921_TIMER_RECOVERY:
- res = timer_recovery_rr_rej_rx(pri, h);
+ res = timer_recovery_rr_rej_rx(ctrl, h);
break;
case Q921_MULTI_FRAME_ESTABLISHED:
/* Figure B.7/Q.921 Page 74 */
- pri->peer_rx_busy = 0;
+ ctrl->peer_rx_busy = 0;
- if (is_command(pri, h)) {
+ if (is_command(ctrl, h)) {
if (h->s.p_f) {
/* Enquiry response */
- q921_enquiry_response(pri);
+ q921_enquiry_response(ctrl);
}
} else {
if (h->s.p_f) {
- //pri_message(pri, "MDL-ERROR (A): Got RR response with p_f bit set to 1 in state %d\n", pri->q921_state);
- q921_mdl_error(pri, 'A');
+ q921_mdl_error(ctrl, 'A');
}
}
- if (!n_r_is_valid(pri, h->s.n_r)) {
- n_r_error_recovery(pri);
- q921_setstate(pri, Q921_AWAITING_ESTABLISHMENT);
+ if (!n_r_is_valid(ctrl, h->s.n_r)) {
+ n_r_error_recovery(ctrl);
+ q921_setstate(ctrl, Q921_AWAITING_ESTABLISHMENT);
} else {
- if (h->s.n_r == pri->v_s) {
- update_v_a(pri, h->s.n_r);
- stop_t200(pri);
- start_t203(pri);
+ if (h->s.n_r == ctrl->v_s) {
+ update_v_a(ctrl, h->s.n_r);
+ stop_t200(ctrl);
+ start_t203(ctrl);
} else {
- if (h->s.n_r != pri->v_a) {
+ if (h->s.n_r != ctrl->v_a) {
/* Need to check the validity of n_r as well.. */
- update_v_a(pri, h->s.n_r);
- restart_t200(pri);
+ update_v_a(ctrl, h->s.n_r);
+ restart_t200(ctrl);
}
}
}
break;
+ case Q921_TEI_ASSIGNED:
+ case Q921_AWAITING_ESTABLISHMENT:
+ case Q921_AWAITING_RELEASE:
+ /*
+ * Ignore this frame.
+ * We likely got reset and the other end has not realized it yet.
+ */
+ break;
default:
- pri_error(pri, "Don't know what to do with RR in state %d\n", pri->q921_state);
+ pri_error(ctrl, "Don't know what to do with RR in state %d(%s)\n",
+ ctrl->q921_state, q921_state2str(ctrl->q921_state));
break;
}
return res;
}
-/* TODO: Look at this code more... */
-static int q921_invoke_retransmission(struct pri *pri, int n_r)
+static int q921_invoke_retransmission(struct pri *ctrl, int n_r)
{
int frames_txd = 0;
int frames_supposed_to_tx = 0;
q921_frame *f;
- unsigned int local_v_s = pri->v_s;
+ unsigned int local_v_s = ctrl->v_s;
-
- for (f = pri->txqueue; f && (f->h.n_s != n_r); f = f->next);
- while (f) {
- if (f->transmitted) {
- if (pri->debug & PRI_DEBUG_Q921_STATE)
- pri_error(pri, "!! Got reject for frame %d, retransmitting frame %d now, updating n_r!\n", n_r, f->h.n_s);
- f->h.n_r = pri->v_r;
- f->h.p_f = 0;
- q921_transmit(pri, (q921_h *)(&f->h), f->len);
- frames_txd++;
+ /* All acked frames should already have been removed from the queue. */
+ for (f = ctrl->txqueue; f && f->transmitted; f = f->next) {
+ if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
+ pri_message(ctrl, "TEI=%d Retransmitting frame N(S)=%d now!\n",
+ ctrl->tei, f->h.n_s);
}
- f = f->next;
+
+ /* Give the other side our current N(R) */
+ f->h.n_r = ctrl->v_r;
+ f->h.p_f = 0;
+ q921_transmit(ctrl, (q921_h *)(&f->h), f->len);
+ frames_txd++;
}
while (local_v_s != n_r) {
Q921_DEC(local_v_s);
frames_supposed_to_tx++;
}
-
if (frames_supposed_to_tx != frames_txd) {
- pri_error(pri, "!!!!!!!!!!!! Should have only transmitted %d frames!\n", frames_supposed_to_tx);
+ pri_error(ctrl, "!!!!!!!!!!!! Should have only transmitted %d frames!\n", frames_supposed_to_tx);
}
return frames_txd;
}
-static pri_event *q921_rej_rx(struct pri *pri, q921_h *h)
+static pri_event *q921_rej_rx(struct pri *ctrl, q921_h *h)
{
pri_event * res = NULL;
- if (pri->debug & PRI_DEBUG_Q921_STATE) {
- pri_message(pri, "!! Got reject for frame %d in state %d\n", h->s.n_r, pri->q921_state);
+ if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
+ pri_message(ctrl, "TEI=%d Got REJ N(R)=%d\n", ctrl->tei, h->s.n_r);
}
- switch (pri->q921_state) {
+ switch (ctrl->q921_state) {
case Q921_TIMER_RECOVERY:
- res = timer_recovery_rr_rej_rx(pri, h);
+ res = timer_recovery_rr_rej_rx(ctrl, h);
break;
case Q921_MULTI_FRAME_ESTABLISHED:
/* Figure B.7/Q.921 Page 74 */
- pri->peer_rx_busy = 0;
+ ctrl->peer_rx_busy = 0;
- if (is_command(pri, h)) {
+ if (is_command(ctrl, h)) {
if (h->s.p_f) {
/* Enquiry response */
- q921_enquiry_response(pri);
+ q921_enquiry_response(ctrl);
}
} else {
if (h->s.p_f) {
- //pri_message(pri, "MDL-ERROR (A): Got REJ response with p_f bit set to 1 in state %d\n", pri->q921_state);
- q921_mdl_error(pri, 'A');
+ q921_mdl_error(ctrl, 'A');
}
}
- if (!n_r_is_valid(pri, h->s.n_r)) {
- n_r_error_recovery(pri);
- q921_setstate(pri, Q921_AWAITING_ESTABLISHMENT);
+ if (!n_r_is_valid(ctrl, h->s.n_r)) {
+ n_r_error_recovery(ctrl);
+ q921_setstate(ctrl, Q921_AWAITING_ESTABLISHMENT);
} else {
- update_v_a(pri, h->s.n_r);
- stop_t200(pri);
- start_t203(pri);
- q921_invoke_retransmission(pri, h->s.n_r);
+ update_v_a(ctrl, h->s.n_r);
+ stop_t200(ctrl);
+ start_t203(ctrl);
+ q921_invoke_retransmission(ctrl, h->s.n_r);
}
- return NULL;
+ break;
+ case Q921_TEI_ASSIGNED:
+ case Q921_AWAITING_ESTABLISHMENT:
+ case Q921_AWAITING_RELEASE:
+ /*
+ * Ignore this frame.
+ * We likely got reset and the other end has not realized it yet.
+ */
+ break;
default:
- pri_error(pri, "Don't know what to do with RR in state %d\n", pri->q921_state);
- return NULL;
+ pri_error(ctrl, "Don't know what to do with REJ in state %d(%s)\n",
+ ctrl->q921_state, q921_state2str(ctrl->q921_state));
+ break;
+ }
+
+ return res;
+}
+
+static pri_event *q921_frmr_rx(struct pri *ctrl, q921_h *h)
+{
+ pri_event *res = NULL;
+
+ if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
+ pri_message(ctrl, "TEI=%d Got FRMR\n", ctrl->tei);
+ }
+
+ switch (ctrl->q921_state) {
+ case Q921_TIMER_RECOVERY:
+ case Q921_MULTI_FRAME_ESTABLISHED:
+ q921_mdl_error(ctrl, 'K');
+ q921_establish_data_link(ctrl);
+ ctrl->l3initiated = 0;
+ q921_setstate(ctrl, Q921_AWAITING_ESTABLISHMENT);
+ break;
+ case Q921_TEI_ASSIGNED:
+ case Q921_AWAITING_ESTABLISHMENT:
+ case Q921_AWAITING_RELEASE:
+ /*
+ * Ignore this frame.
+ * We likely got reset and the other end has not realized it yet.
+ */
+ if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
+ pri_message(ctrl, "TEI=%d Ignoring FRMR.\n", ctrl->tei);
+ }
+ break;
+ default:
+ pri_error(ctrl, "Don't know what to do with FRMR in state %d(%s)\n",
+ ctrl->q921_state, q921_state2str(ctrl->q921_state));
+ break;
}
return res;
}
-static pri_event *q921_iframe_rx(struct pri *pri, q921_h *h, int len)
+static pri_event *q921_iframe_rx(struct pri *ctrl, q921_h *h, int len)
{
pri_event * eres = NULL;
int res = 0;
+ int delay_q931_receive;
- switch (pri->q921_state) {
+ switch (ctrl->q921_state) {
case Q921_TIMER_RECOVERY:
case Q921_MULTI_FRAME_ESTABLISHED:
+ delay_q931_receive = 0;
/* FIXME: Verify that it's a command ... */
- if (pri->own_rx_busy) {
+ if (ctrl->own_rx_busy) {
/* XXX: Note: There's a difference in th P/F between both states */
/* DEVIATION: Handle own rx busy */
- }
-
- if (h->i.n_s == pri->v_r) {
- Q921_INC(pri->v_r);
+ } else if (h->i.n_s == ctrl->v_r) {
+ Q921_INC(ctrl->v_r);
- pri->reject_exception = 0;
+ ctrl->reject_exception = 0;
- //res = q931_receive(PRI_MASTER(pri), pri->tei, (q931_h *)h->i.data, len - 4);
- res = q931_receive(pri, pri->tei, (q931_h *)h->i.data, len - 4);
- if (res != -1 && (res & Q931_RES_HAVEEVENT)) {
- eres = &pri->ev;
+ /*
+ * Dump Q.931 message where Q.921 says to queue it to Q.931 so if
+ * Q.921 is dumping its frames they will be in the correct order.
+ */
+ if (ctrl->debug & PRI_DEBUG_Q931_DUMP) {
+ q931_dump(ctrl, ctrl->tei, (q931_h *) h->i.data, len - 4, 0);
}
+ delay_q931_receive = 1;
if (h->i.p_f) {
- q921_rr(pri, 1, 0);
- pri->acknowledge_pending = 0;
+ q921_rr(ctrl, 1, 0);
+ ctrl->acknowledge_pending = 0;
} else {
- if (!pri->acknowledge_pending) {
- /* XXX: Fix acknowledge_pending */
- pri->acknowledge_pending = 1;
- }
+ ctrl->acknowledge_pending = 1;
}
-
} else {
- if (pri->reject_exception) {
+ if (ctrl->reject_exception) {
if (h->i.p_f) {
- q921_rr(pri, 1, 0);
- pri->acknowledge_pending = 0;
+ q921_rr(ctrl, 1, 0);
+ ctrl->acknowledge_pending = 0;
}
} else {
- pri->reject_exception = 1;
- q921_reject(pri, h->i.p_f);
- pri->acknowledge_pending = 0;
+ ctrl->reject_exception = 1;
+ q921_reject(ctrl, h->i.p_f);
+ ctrl->acknowledge_pending = 0;
}
}
- if (!n_r_is_valid(pri, h->i.n_r)) {
- n_r_error_recovery(pri);
- q921_setstate(pri, Q921_AWAITING_ESTABLISHMENT);
+ if (!n_r_is_valid(ctrl, h->i.n_r)) {
+ n_r_error_recovery(ctrl);
+ q921_setstate(ctrl, Q921_AWAITING_ESTABLISHMENT);
} else {
- if (pri->q921_state == Q921_TIMER_RECOVERY) {
- update_v_a(pri, h->i.n_r);
+ if (ctrl->q921_state == Q921_TIMER_RECOVERY) {
+ update_v_a(ctrl, h->i.n_r);
} else {
- if (pri->peer_rx_busy) {
- update_v_a(pri, h->i.n_r);
+ if (ctrl->peer_rx_busy) {
+ update_v_a(ctrl, h->i.n_r);
} else {
- if (h->i.n_r == pri->v_s) {
- update_v_a(pri, h->i.n_r);
- stop_t200(pri);
- start_t203(pri);
+ if (h->i.n_r == ctrl->v_s) {
+ update_v_a(ctrl, h->i.n_r);
+ stop_t200(ctrl);
+ start_t203(ctrl);
} else {
- if (h->i.n_r != pri->v_a) {
- update_v_a(pri, h->i.n_r);
- stop_t200(pri);
- start_t200(pri);
+ if (h->i.n_r != ctrl->v_a) {
+ update_v_a(ctrl, h->i.n_r);
+ reschedule_t200(ctrl);
}
}
}
}
}
-
+ if (delay_q931_receive) {
+ /* Q.921 has finished processing the frame so we can give it to Q.931 now. */
+ res = q931_receive(ctrl, ctrl->tei, (q931_h *) h->i.data, len - 4);
+ if (res != -1 && (res & Q931_RES_HAVEEVENT)) {
+ eres = &ctrl->ev;
+ }
+ }
+ break;
+ case Q921_TEI_ASSIGNED:
+ case Q921_AWAITING_ESTABLISHMENT:
+ case Q921_AWAITING_RELEASE:
+ /*
+ * Ignore this frame.
+ * We likely got reset and the other end has not realized it yet.
+ */
break;
default:
- pri_error(pri, "Don't know what to do with an I frame in state %d\n", pri->q921_state);
+ pri_error(ctrl, "Don't know what to do with an I-frame in state %d(%s)\n",
+ ctrl->q921_state, q921_state2str(ctrl->q921_state));
break;
}
return eres;
}
-static pri_event *q921_dm_rx(struct pri *pri, q921_h *h)
+static pri_event *q921_dm_rx(struct pri *ctrl, q921_h *h)
{
pri_event * res = NULL;
- switch (pri->q921_state) {
+ if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
+ pri_message(ctrl, "TEI=%d Got DM\n", ctrl->tei);
+ }
+
+ switch (ctrl->q921_state) {
case Q921_TEI_ASSIGNED:
if (h->u.p_f)
break;
/* else */
- q921_establish_data_link(pri);
- pri->l3initiated = 1;
- q921_setstate(pri, Q921_AWAITING_ESTABLISHMENT);
+ q921_establish_data_link(ctrl);
+ ctrl->l3initiated = 1;
+ q921_setstate(ctrl, Q921_AWAITING_ESTABLISHMENT);
break;
case Q921_AWAITING_ESTABLISHMENT:
if (!h->u.p_f)
break;
- q921_discard_iqueue(pri);
+ q921_discard_iqueue(ctrl);
/* DL-RELEASE indication */
- q931_dl_indication(pri, PRI_EVENT_DCHAN_DOWN);
- stop_t200(pri);
- q921_setstate(pri, Q921_TEI_ASSIGNED);
+ q931_dl_event(ctrl, Q931_DL_EVENT_DL_RELEASE_IND);
+ stop_t200(ctrl);
+ q921_setstate(ctrl, Q921_TEI_ASSIGNED);
+ q921_restart_ptp_link_if_needed(ctrl);
break;
case Q921_AWAITING_RELEASE:
if (!h->u.p_f)
break;
/* DL-RELEASE confirm */
- stop_t200(pri);
- q921_setstate(pri, Q921_TEI_ASSIGNED);
+ q931_dl_event(ctrl, Q931_DL_EVENT_DL_RELEASE_CONFIRM);
+ stop_t200(ctrl);
+ q921_setstate(ctrl, Q921_TEI_ASSIGNED);
break;
case Q921_MULTI_FRAME_ESTABLISHED:
if (h->u.p_f) {
- /* MDL-ERROR (B) indication */
- q921_mdl_error(pri, 'B');
+ q921_mdl_error(ctrl, 'B');
break;
}
- q921_mdl_error(pri, 'E');
- q921_establish_data_link(pri);
- pri->l3initiated = 0;
- q921_setstate(pri, Q921_AWAITING_ESTABLISHMENT);
+ q921_mdl_error(ctrl, 'E');
+ q921_establish_data_link(ctrl);
+ ctrl->l3initiated = 0;
+ q921_setstate(ctrl, Q921_AWAITING_ESTABLISHMENT);
break;
case Q921_TIMER_RECOVERY:
if (h->u.p_f) {
- /* MDL-ERROR (B) indication */
- q921_mdl_error(pri, 'B');
+ q921_mdl_error(ctrl, 'B');
} else {
- /* MDL-ERROR (E) indication */
- q921_mdl_error(pri, 'E');
+ q921_mdl_error(ctrl, 'E');
}
- q921_establish_data_link(pri);
- pri->l3initiated = 0;
- q921_setstate(pri, Q921_AWAITING_ESTABLISHMENT);
+ q921_establish_data_link(ctrl);
+ ctrl->l3initiated = 0;
+ q921_setstate(ctrl, Q921_AWAITING_ESTABLISHMENT);
break;
default:
- pri_error(pri, "Don't know what to do with DM frame in state %d\n", pri->q921_state);
+ pri_error(ctrl, "Don't know what to do with DM frame in state %d(%s)\n",
+ ctrl->q921_state, q921_state2str(ctrl->q921_state));
break;
}
return res;
}
-static pri_event *q921_rnr_rx(struct pri *pri, q921_h *h)
+static pri_event *q921_rnr_rx(struct pri *ctrl, q921_h *h)
{
pri_event * res = NULL;
- switch (pri->q921_state) {
+ if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
+ pri_message(ctrl, "TEI=%d Got RNR N(R)=%d\n", ctrl->tei, h->s.n_r);
+ }
+
+ switch (ctrl->q921_state) {
case Q921_MULTI_FRAME_ESTABLISHED:
- pri->peer_rx_busy = 1;
- if (!is_command(pri, h)) {
+ ctrl->peer_rx_busy = 1;
+ if (!is_command(ctrl, h)) {
if (h->s.p_f) {
- /* MDL-ERROR (A) indication */
- q921_mdl_error(pri, 'A');
+ q921_mdl_error(ctrl, 'A');
}
} else {
if (h->s.p_f) {
- q921_enquiry_response(pri);
+ q921_enquiry_response(ctrl);
}
}
- if (!n_r_is_valid(pri, h->s.n_r)) {
- n_r_error_recovery(pri);
- q921_setstate(pri, Q921_AWAITING_ESTABLISHMENT);
+ if (!n_r_is_valid(ctrl, h->s.n_r)) {
+ n_r_error_recovery(ctrl);
+ q921_setstate(ctrl, Q921_AWAITING_ESTABLISHMENT);
} else {
- update_v_a(pri, h->s.n_r);
- stop_t203(pri);
- restart_t200(pri);
+ update_v_a(ctrl, h->s.n_r);
+ stop_t203(ctrl);
+ restart_t200(ctrl);
}
break;
case Q921_TIMER_RECOVERY:
- pri->peer_rx_busy = 1;
- if (is_command(pri, h)) {
+ /* Q.921 Figure B.8 Q921 (Sheet 6 of 9) Page 85 */
+ ctrl->peer_rx_busy = 1;
+ if (is_command(ctrl, h)) {
+ if (h->s.p_f) {
+ q921_enquiry_response(ctrl);
+ }
+ if (n_r_is_valid(ctrl, h->s.n_r)) {
+ update_v_a(ctrl, h->s.n_r);
+ break;
+ } else {
+ n_r_error_recovery(ctrl);
+ q921_setstate(ctrl, Q921_AWAITING_ESTABLISHMENT);
+ break;
+ }
+ } else {
if (h->s.p_f) {
- q921_enquiry_response(pri);
- if (n_r_is_valid(pri, h->s.n_r)) {
- update_v_a(pri, h->s.n_r);
+ if (n_r_is_valid(ctrl, h->s.n_r)) {
+ update_v_a(ctrl, h->s.n_r);
+ restart_t200(ctrl);
+ q921_invoke_retransmission(ctrl, h->s.n_r);
+ q921_setstate(ctrl, Q921_MULTI_FRAME_ESTABLISHED);
break;
} else {
- n_r_error_recovery(pri);
- q921_setstate(pri, Q921_AWAITING_ESTABLISHMENT);
+ n_r_error_recovery(ctrl);
+ q921_setstate(ctrl, Q921_AWAITING_ESTABLISHMENT);
break;
}
- }
- } else {
- if (h->s.p_f) {
- if (n_r_is_valid(pri, h->s.n_r)) {
- update_v_a(pri, h->s.n_r);
- restart_t200(pri);
- q921_invoke_retransmission(pri, h->s.n_r);
- q921_setstate(pri, Q921_MULTI_FRAME_ESTABLISHED);
+ } else {
+ if (n_r_is_valid(ctrl, h->s.n_r)) {
+ update_v_a(ctrl, h->s.n_r);
break;
} else {
- n_r_error_recovery(pri);
- q921_setstate(pri, Q921_AWAITING_ESTABLISHMENT);
+ n_r_error_recovery(ctrl);
+ q921_setstate(ctrl, Q921_AWAITING_ESTABLISHMENT);
break;
}
}
}
break;
+ case Q921_TEI_ASSIGNED:
+ case Q921_AWAITING_ESTABLISHMENT:
+ case Q921_AWAITING_RELEASE:
+ /*
+ * Ignore this frame.
+ * We likely got reset and the other end has not realized it yet.
+ */
+ break;
default:
- pri_error(pri, "Don't know what to do with RNR in state %d\n", pri->q921_state);
+ pri_error(ctrl, "Don't know what to do with RNR in state %d(%s)\n",
+ ctrl->q921_state, q921_state2str(ctrl->q921_state));
break;
}
return res;
}
-static void q921_acknowledge_pending_check(struct pri *pri)
+static void q921_acknowledge_pending_check(struct pri *ctrl)
{
- if (pri->acknowledge_pending) {
- pri->acknowledge_pending = 0;
- q921_rr(pri, 0, 0);
+ if (ctrl->acknowledge_pending) {
+ ctrl->acknowledge_pending = 0;
+ q921_rr(ctrl, 0, 0);
}
}
-static void q921_statemachine_check(struct pri *pri)
+static void q921_statemachine_check(struct pri *ctrl)
{
- switch (pri->q921_state) {
+ switch (ctrl->q921_state) {
case Q921_MULTI_FRAME_ESTABLISHED:
- q921_send_queued_iframes(pri);
- q921_acknowledge_pending_check(pri);
+ q921_send_queued_iframes(ctrl);
+ q921_acknowledge_pending_check(ctrl);
break;
case Q921_TIMER_RECOVERY:
- q921_acknowledge_pending_check(pri);
+ q921_acknowledge_pending_check(ctrl);
break;
default:
break;
}
}
-static pri_event *__q921_receive_qualified(struct pri *pri, q921_h *h, int len)
+static pri_event *__q921_receive_qualified(struct pri *ctrl, q921_h *h, int len)
{
+ int res;
pri_event *ev = NULL;
switch(h->h.data[0] & Q921_FRAMETYPE_MASK) {
case 0:
case 2:
- ev = q921_iframe_rx(pri, h, len);
+ ev = q921_iframe_rx(ctrl, h, len);
break;
case 1:
- switch(h->s.ss) {
- case 0:
- ev = q921_rr_rx(pri, h);
+ switch ((h->s.x0 << 2) | h->s.ss) {
+ case 0x00:
+ ev = q921_rr_rx(ctrl, h);
break;
- case 1:
- ev = q921_rnr_rx(pri, h);
+ case 0x01:
+ ev = q921_rnr_rx(ctrl, h);
break;
- case 2:
- /* Just retransmit */
- if (pri->debug & PRI_DEBUG_Q921_STATE)
- pri_message(pri, "-- Got reject requesting packet %d... Retransmitting.\n", h->s.n_r);
- ev = q921_rej_rx(pri, h);
+ case 0x02:
+ ev = q921_rej_rx(ctrl, h);
break;
default:
- pri_error(pri, "!! XXX Unknown Supervisory frame ss=0x%02x,pf=%02xnr=%02x vs=%02x, va=%02x XXX\n", h->s.ss, h->s.p_f, h->s.n_r,
- pri->v_s, pri->v_a);
+ pri_error(ctrl,
+ "!! XXX Unknown Supervisory frame x0=%d ss=%d, pf=%d, N(R)=%d, V(A)=%d, V(S)=%d XXX\n",
+ h->s.x0, h->s.ss, h->s.p_f, h->s.n_r, ctrl->v_a, ctrl->v_s);
+ break;
}
break;
case 3:
if (len < 3) {
- pri_error(pri, "!! Received short unnumbered frame\n");
+ pri_error(ctrl, "!! Received short unnumbered frame\n");
break;
}
- switch(h->u.m3) {
- case 0:
- if (h->u.m2 == 3) {
- ev = q921_dm_rx(pri, h);
- break;
- } else if (!h->u.m2) {
- if ((pri->sapi == Q921_SAPI_LAYER2_MANAGEMENT) && (pri->tei == Q921_TEI_GROUP)) {
-
- pri_error(pri, "I should never be called\n");
- q921_receive_MDL(pri, (q921_u *)h, len);
-
- } else {
- int res;
-
- res = q931_receive(pri, pri->tei, (q931_h *) h->u.data, len - 3);
- if (res == -1) {
- ev = NULL;
- }
- if (res & Q931_RES_HAVEEVENT)
- ev = &pri->ev;
- }
+ switch ((h->u.m3 << 2) | h->u.m2) {
+ case 0x03:
+ ev = q921_dm_rx(ctrl, h);
+ break;
+ case 0x00:
+ /* UI-frame */
+ if (ctrl->debug & PRI_DEBUG_Q931_DUMP) {
+ q931_dump(ctrl, ctrl->tei, (q931_h *) h->u.data, len - 3, 0);
+ }
+ res = q931_receive(ctrl, ctrl->tei, (q931_h *) h->u.data, len - 3);
+ if (res != -1 && (res & Q931_RES_HAVEEVENT)) {
+ ev = &ctrl->ev;
}
break;
- case 2:
- ev = q921_disc_rx(pri, h);
+ case 0x08:
+ ev = q921_disc_rx(ctrl, h);
break;
- case 3:
- if (h->u.m2 == 3) {
- /* SABME */
- if (pri->debug & (PRI_DEBUG_Q921_STATE | PRI_DEBUG_Q921_DUMP)) {
- pri_message(pri, "-- Got SABME from %s peer.\n", h->h.c_r ? "network" : "cpe");
+ case 0x0F:
+ /* SABME */
+ if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
+ pri_message(ctrl, "TEI=%d Got SABME from %s peer.\n",
+ ctrl->tei, h->h.c_r ? "network" : "cpe");
+ }
+ if (h->h.c_r) {
+ ctrl->remotetype = PRI_NETWORK;
+ if (ctrl->localtype == PRI_NETWORK) {
+ /* We can't both be networks */
+ ev = pri_mkerror(ctrl, "We think we're the network, but they think they're the network, too.");
+ break;
}
- if (h->h.c_r) {
- pri->remotetype = PRI_NETWORK;
- if (pri->localtype == PRI_NETWORK) {
- /* We can't both be networks */
- ev = pri_mkerror(pri, "We think we're the network, but they think they're the network, too.");
- break;
- }
- } else {
- pri->remotetype = PRI_CPE;
- if (pri->localtype == PRI_CPE) {
- /* We can't both be CPE */
- ev = pri_mkerror(pri, "We think we're the CPE, but they think they're the CPE too.\n");
- break;
- }
+ } else {
+ ctrl->remotetype = PRI_CPE;
+ if (ctrl->localtype == PRI_CPE) {
+ /* We can't both be CPE */
+ ev = pri_mkerror(ctrl, "We think we're the CPE, but they think they're the CPE too.\n");
+ break;
}
- ev = q921_sabme_rx(pri, h);
- break;
- } else if (h->u.m2 == 0) {
- ev = q921_ua_rx(pri, h);
- break;
- } else
- pri_error(pri, "!! Weird frame received (m3=3, m2 = %d)\n", h->u.m2);
+ }
+ ev = q921_sabme_rx(ctrl, h);
break;
- case 4:
- pri_error(pri, "!! Frame got rejected!\n");
+ case 0x0C:
+ ev = q921_ua_rx(ctrl, h);
break;
- case 5:
- pri_error(pri, "!! XID frames not supported\n");
+ case 0x11:
+ ev = q921_frmr_rx(ctrl, h);
+ break;
+ case 0x17:
+ pri_error(ctrl, "!! XID frames not supported\n");
break;
default:
- pri_error(pri, "!! Don't know what to do with M3=%d u-frames\n", h->u.m3);
+ pri_error(ctrl, "!! Don't know what to do with u-frame (m3=%d, m2=%d)\n",
+ h->u.m3, h->u.m2);
+ break;
}
break;
-
}
- q921_statemachine_check(pri);
+ q921_statemachine_check(ctrl);
return ev;
}
-static pri_event *q921_handle_unmatched_frame(struct pri *pri, q921_h *h, int len)
+static pri_event *q921_handle_unmatched_frame(struct pri *ctrl, q921_h *h, int len)
{
- pri = PRI_MASTER(pri);
+ ctrl = PRI_MASTER(ctrl);
if (h->h.tei < 64) {
- pri_error(pri, "Do not support manual TEI range. Discarding\n");
+ pri_error(ctrl, "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");
+ pri_error(ctrl, "Message with SAPI other than CALL CTRL is discarded\n");
return NULL;
}
/* If we're NT-PTMP, this means an unrecognized TEI that we'll kill */
- if (BRI_NT_PTMP(pri)) {
- if (pri->debug & PRI_DEBUG_Q921_DUMP) {
- pri_message(pri,
+ if (BRI_NT_PTMP(ctrl)) {
+ if (ctrl->debug & PRI_DEBUG_Q921_STATE) {
+ pri_message(ctrl,
"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");
+ pri_message(ctrl, "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);
+ q921_tei_remove(ctrl, h->h.tei);
}
return NULL;
}
/* This code assumes that the pri structure is the master pri */
-static pri_event *__q921_receive(struct pri *pri, q921_h *h, int len)
+static pri_event *__q921_receive(struct pri *ctrl, q921_h *h, int len)
{
pri_event *ev = NULL;
struct pri *tei;
+
/* Discard FCS */
len -= 2;
- if (pri->debug & (PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_RAW))
- q921_dump(pri, h, len, pri->debug & PRI_DEBUG_Q921_RAW, 0);
+ if (ctrl->debug & (PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_RAW)) {
+ q921_dump(ctrl, h, len, ctrl->debug & PRI_DEBUG_Q921_RAW, 0);
+ }
/* Check some reject conditions -- Start by rejecting improper ea's */
- if (h->h.ea1 || !(h->h.ea2))
+ if (h->h.ea1 || !h->h.ea2) {
return NULL;
+ }
- if ((h->h.sapi == Q921_SAPI_LAYER2_MANAGEMENT)) {
- return q921_receive_MDL(pri, &h->u, len);
+ if (h->h.sapi == Q921_SAPI_LAYER2_MANAGEMENT) {
+ return q921_receive_MDL(ctrl, &h->u, len);
}
- if ((h->h.tei == Q921_TEI_GROUP) && (h->h.sapi != Q921_SAPI_CALL_CTRL)) {
- pri_error(pri, "Do not handle group messages to services other than MDL or CALL CTRL\n");
+ if (h->h.tei == Q921_TEI_GROUP && h->h.sapi != Q921_SAPI_CALL_CTRL) {
+ pri_error(ctrl, "Do not handle group messages to services other than MDL or CALL CTRL\n");
return NULL;
}
- if (BRI_TE_PTMP(pri)) {
- if (((pri->subchannel->q921_state >= Q921_TEI_ASSIGNED) && (h->h.tei == pri->subchannel->tei))
- || (h->h.tei == Q921_TEI_GROUP)) {
- ev = __q921_receive_qualified(pri->subchannel, h, len);
+ if (BRI_TE_PTMP(ctrl)) {
+ if (h->h.sapi == ctrl->subchannel->sapi
+ && ((ctrl->subchannel->q921_state >= Q921_TEI_ASSIGNED
+ && h->h.tei == ctrl->subchannel->tei)
+ || h->h.tei == Q921_TEI_GROUP)) {
+ ev = __q921_receive_qualified(ctrl->subchannel, h, len);
}
/* Only support reception on our single subchannel */
- } else if (BRI_NT_PTMP(pri)) {
- tei = pri_find_tei(pri, h->h.sapi, h->h.tei);
-
- if (tei)
+ } else if (BRI_NT_PTMP(ctrl)) {
+ tei = pri_find_tei(ctrl, h->h.sapi, h->h.tei);
+ if (tei) {
ev = __q921_receive_qualified(tei, h, len);
- else
- ev = q921_handle_unmatched_frame(pri, h, len);
-
- } else if (PTP_MODE(pri) && (h->h.sapi == pri->sapi) && (h->h.tei == pri->tei)) {
- ev = __q921_receive_qualified(pri, h, len);
+ } else {
+ ev = q921_handle_unmatched_frame(ctrl, h, len);
+ }
+ } else if (PTP_MODE(ctrl)
+ && h->h.sapi == ctrl->sapi
+ && (h->h.tei == ctrl->tei || h->h.tei == Q921_TEI_GROUP)) {
+ ev = __q921_receive_qualified(ctrl, h, len);
} else {
ev = NULL;
}
- if (pri->debug & PRI_DEBUG_Q921_DUMP)
- pri_message(pri, "Handling message for SAPI/TEI=%d/%d\n", h->h.sapi, h->h.tei);
+ if (ctrl->debug & PRI_DEBUG_Q921_DUMP) {
+ pri_message(ctrl, "Done handling message for SAPI/TEI=%d/%d\n", h->h.sapi, h->h.tei);
+ }
return ev;
}
-pri_event *q921_receive(struct pri *pri, q921_h *h, int len)
+pri_event *q921_receive(struct pri *ctrl, q921_h *h, int len)
{
pri_event *e;
- e = __q921_receive(pri, h, len);
+ e = __q921_receive(ctrl, h, len);
#ifdef LIBPRI_COUNTERS
- pri->q921_rxcount++;
+ ctrl->q921_rxcount++;
#endif
return e;
}
-static void q921_establish_data_link(struct pri *pri)
+static void q921_establish_data_link(struct pri *ctrl)
{
- q921_clear_exception_conditions(pri);
- pri->RC = 0;
- stop_t203(pri);
- reschedule_t200(pri);
- q921_send_sabme(pri);
+ q921_clear_exception_conditions(ctrl);
+ ctrl->RC = 0;
+ stop_t203(ctrl);
+ reschedule_t200(ctrl);
+ q921_send_sabme(ctrl);
}
static void nt_ptmp_dchannel_up(void *vpri)
{
- struct pri *pri = vpri;
+ struct pri *ctrl = vpri;
- pri->schedev = 1;
- pri->ev.gen.e = PRI_EVENT_DCHAN_UP;
+ ctrl->schedev = 1;
+ ctrl->ev.gen.e = PRI_EVENT_DCHAN_UP;
}
-void q921_start(struct pri *pri)
+void q921_start(struct pri *ctrl)
{
- if (PTMP_MODE(pri)) {
- if (TE_MODE(pri)) {
- q921_setstate(pri, Q921_ASSIGN_AWAITING_TEI);
- q921_tei_request(pri);
+ if (PTMP_MODE(ctrl)) {
+ if (TE_MODE(ctrl)) {
+ q921_setstate(ctrl, Q921_ASSIGN_AWAITING_TEI);
+ q921_tei_request(ctrl);
} else {
- q921_setstate(pri, Q921_TEI_UNASSIGNED);
- pri_schedule_event(pri, 0, nt_ptmp_dchannel_up, pri);
+ q921_setstate(ctrl, Q921_TEI_UNASSIGNED);
+ pri_schedule_event(ctrl, 0, nt_ptmp_dchannel_up, ctrl);
+ ctrl = PRI_MASTER(ctrl);
+ if (!ctrl->subchannel) {
+ /*
+ * We do not have any TEI's so make sure there are no devices
+ * that think they have a TEI. A device may think it has a TEI
+ * if the upper layer program is restarted or the system
+ * reboots.
+ */
+ q921_tei_remove(ctrl, Q921_TEI_GROUP);
+ }
}
} else {
/* PTP mode, no need for TEI management junk */
- q921_establish_data_link(pri);
- pri->l3initiated = 1;
- q921_setstate(pri, Q921_AWAITING_ESTABLISHMENT);
+ q921_establish_data_link(ctrl);
+ ctrl->l3initiated = 1;
+ q921_setstate(ctrl, Q921_AWAITING_ESTABLISHMENT);
}
}
|
@@ -321,6 +321,76 @@
}
/*!
+ * \brief Check if the given call ptr is valid.
+ *
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg.
+ * \param func_name Calling function name for debug tracing. (__PRETTY_FUNCTION__)
+ * \param func_line Calling function line number for debug tracing. (__LINE__)
+ *
+ * \retval TRUE if call ptr is valid.
+ * \retval FALSE if call ptr is invalid.
+ */
+int q931_is_call_valid(struct pri *ctrl, struct q931_call *call, const char *func_name, unsigned long func_line)
+{
+ struct q931_call *cur;
+ struct pri *gripe;
+ struct pri *link;
+ int idx;
+
+ if (!call) {
+ return 0;
+ }
+
+ if (!ctrl) {
+ /* Must use suspect ctrl from call ptr. */
+ if (!call->pri) {
+ pri_message(NULL,
+ "!! %s() line:%lu Called with invalid call ptr (%p) (No ctrl)\n",
+ func_name, func_line, call);
+ return 0;
+ }
+ /* Find the master - He has the call pool */
+ ctrl = PRI_MASTER(call->pri);
+ gripe = NULL;
+ } else {
+ /* Find the master - He has the call pool */
+ ctrl = PRI_MASTER(ctrl);
+ gripe = ctrl;
+ }
+
+ /* Check real call records. */
+ for (cur = *ctrl->callpool; cur; cur = cur->next) {
+ if (call == cur) {
+ /* Found it. */
+ return 1;
+ }
+ if (cur->outboundbroadcast) {
+ /* Check subcalls for call ptr. */
+ for (idx = 0; idx < ARRAY_LEN(cur->subcalls); ++idx) {
+ if (call == cur->subcalls[idx]) {
+ /* Found it. */
+ return 1;
+ }
+ }
+ }
+ }
+
+ /* Check dummy call records. */
+ for (link = ctrl; link; link = link->subchannel) {
+ if (link->dummy_call == call) {
+ /* Found it. */
+ return 1;
+ }
+ }
+
+ /* Well it looks like this is a stale call ptr. */
+ pri_message(gripe, "!! %s() line:%lu Called with invalid call ptr (%p)\n",
+ func_name, func_line, call);
+ return 0;
+}
+
+/*!
* \brief Initialize the given struct q931_party_name
*
* \param name Structure to initialize
@@ -885,7 +955,12 @@
return -1;
}
if (ie->data[pos] & 0x10) {
- /* Expect Slot Map */
+ /*
+ * Expect Slot Map
+ * Note that we are assuming only T1's use slot maps which is wrong
+ * but oh well... We would need to know what type of line we are
+ * connected with (T1 or E1) to interpret the map correctly anyway.
+ */
call->slotmap = 0;
pos++;
for (x=0;x<3;x++) {
@@ -963,22 +1038,26 @@
&& !(call->chanflags & FLAG_WHOLE_INTERFACE)) {
/* The 3.2 and 3.3 octets need to be present */
ie->data[pos] = 0x83;
- if (call->slotmap != -1) {
+ if (0 < call->channelno && call->channelno != 0xff) {
+ /* Channel number specified and preferred over slot map if we have one. */
+ ++pos;
+ if (ctrl->chan_mapping_logical && call->channelno > 16) {
+ ie->data[pos++] = 0x80 | (call->channelno - 1);
+ } else {
+ ie->data[pos++] = 0x80 | call->channelno;
+ }
+ } else if (call->slotmap != -1) {
int octet;
- /* We have to send a channel map */
+ /* We have to send a slot map */
ie->data[pos++] |= 0x10;
for (octet = 3; octet--;) {
ie->data[pos++] = (call->slotmap >> (8 * octet)) & 0xff;
}
} else {
- /* Channel number specified */
- ++pos;
- if (ctrl->chan_mapping_logical && call->channelno > 16) {
- ie->data[pos++] = 0x80 | (call->channelno - 1);
- } else {
- ie->data[pos++] = 0x80 | call->channelno;
- }
+ pri_error(ctrl, "XXX We need either a channelno or slotmap but have neither!\n");
+ /* Discard this malformed ie. */
+ return 0;
}
}
@@ -1994,26 +2073,41 @@
static int receive_calling_party_number(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
{
int i = 0;
+ struct q931_party_number number;
+
+ q931_party_number_init(&number);
+ number.valid = 1;
+ number.presentation = PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED;
- call->remote_id.number.valid = 1;
- call->remote_id.number.presentation =
- PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED;
/* To follow Q.931 (4.5.1), we must search for start of octet 4 by
walking through all bytes until one with ext bit (8) set to 1 */
do {
switch (i) {
case 0:
- call->remote_id.number.plan = ie->data[i] & 0x7f;
+ number.plan = ie->data[i] & 0x7f;
break;
case 1:
/* Keep only the presentation and screening fields */
- call->remote_id.number.presentation =
+ number.presentation =
ie->data[i] & (PRI_PRES_RESTRICTION | PRI_PRES_NUMBER_TYPE);
break;
}
} while (!(ie->data[i++] & 0x80));
- q931_get_number((unsigned char *) call->remote_id.number.str,
- sizeof(call->remote_id.number.str), ie->data + i, ie->len - i);
+ q931_get_number((unsigned char *) number.str, sizeof(number.str), ie->data + i,
+ ie->len - i);
+
+ /* There can be more than one calling party number ie in the SETUP message. */
+ if (number.presentation == (PRI_PRES_ALLOWED | PRI_PRES_NETWORK_NUMBER)
+ || number.presentation == (PRI_PRES_RESTRICTED | PRI_PRES_NETWORK_NUMBER)) {
+ /* The number is network provided so it is an ANI number. */
+ call->ani = number;
+ if (!call->remote_id.number.valid) {
+ /* Copy ANI to CallerID if CallerID is not already set. */
+ call->remote_id.number = number;
+ }
+ } else {
+ call->remote_id.number = number;
+ }
return 0;
}
@@ -3514,6 +3608,7 @@
q931_party_address_init(&call->called);
q931_party_id_init(&call->local_id);
q931_party_id_init(&call->remote_id);
+ q931_party_number_init(&call->ani);
q931_party_redirecting_init(&call->redirecting);
/* PRI is set to whoever called us */
@@ -3900,34 +3995,29 @@
}
/*!
- * \brief Debug dump the given Q.931 packet.
+ * \internal
+ * \brief Dump the Q.931 message header.
*
* \param ctrl D channel controller.
* \param tei TEI the packet is associated with.
* \param h Q.931 packet contents/header.
- * \param len Received length of the Q.931 packet
- * \param txrx TRUE if packet is transmitted/outgoing
+ * \param len Received length of the Q.931 packet.
+ * \param c Message direction prefix character.
*
- * \return Nothing
+ * \retval 0 on success.
+ * \retval -1 on error.
*/
-void q931_dump(struct pri *ctrl, int tei, q931_h *h, int len, int txrx)
+static int q931_dump_header(struct pri *ctrl, int tei, q931_h *h, int len, char c)
{
q931_mh *mh;
- char c;
- int x;
- int r;
- int cur_codeset;
- int codeset;
int cref;
- c = txrx ? '>' : '<';
-
pri_message(ctrl, "%c Protocol Discriminator: %s (%d) len=%d\n", c, disc2str(h->pd), h->pd, len);
if (len < 2 || len < 2 + h->crlen) {
pri_message(ctrl, "%c Message too short for call reference. len=%d\n",
c, len);
- return;
+ return -1;
}
cref = q931_cr(h);
pri_message(ctrl, "%c TEI=%d Call Ref: len=%2d (reference %d/0x%X) (%s)\n",
@@ -3940,7 +4030,7 @@
if (len < 3 + h->crlen) {
pri_message(ctrl, "%c Message too short for supported protocols. len=%d\n",
c, len);
- return;
+ return -1;
}
/* Message header begins at the end of the call reference number */
@@ -3957,7 +4047,64 @@
pri_message(ctrl, "%c Message Type: %s (%d)\n", c, msg2str(mh->msg), mh->msg);
break;
}
+
+ return 0;
+}
+
+/*!
+ * \internal
+ * \brief Q.931 is passing this message to Q.921 debug indication.
+ *
+ * \param ctrl D channel controller.
+ * \param tei TEI the packet is associated with.
+ * \param h Q.931 packet contents/header.
+ * \param len Received length of the Q.931 packet
+ *
+ * \return Nothing
+ */
+static void q931_to_q921_passing_dump(struct pri *ctrl, int tei, q931_h *h, int len)
+{
+ char c;
+
+ c = '>';
+
+ pri_message(ctrl, "\n");
+ pri_message(ctrl, "%c DL-DATA request\n", c);
+ q931_dump_header(ctrl, tei, h, len, c);
+}
+
+/*!
+ * \brief Debug dump the given Q.931 packet.
+ *
+ * \param ctrl D channel controller.
+ * \param tei TEI the packet is associated with.
+ * \param h Q.931 packet contents/header.
+ * \param len Received length of the Q.931 packet
+ * \param txrx TRUE if packet is transmitted/outgoing
+ *
+ * \return Nothing
+ */
+void q931_dump(struct pri *ctrl, int tei, q931_h *h, int len, int txrx)
+{
+ q931_mh *mh;
+ char c;
+ int x;
+ int r;
+ int cur_codeset;
+ int codeset;
+
+ c = txrx ? '>' : '<';
+
+ if (!(ctrl->debug & (PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_RAW))) {
+ /* Put out a blank line if Q.921 is not dumping. */
+ pri_message(ctrl, "\n");
+ }
+ if (q931_dump_header(ctrl, tei, h, len, c)) {
+ return;
+ }
+
/* Drop length of header, including call reference */
+ mh = (q931_mh *)(h->contents + h->crlen);
len -= (h->crlen + 3);
codeset = cur_codeset = 0;
for (x = 0; x < len; x += r) {
@@ -4051,19 +4198,32 @@
static int q931_xmit(struct pri *ctrl, int tei, q931_h *h, int len, int cr, int uiframe)
{
+#ifdef LIBPRI_COUNTERS
+ ctrl->q931_txcount++;
+#endif
if (uiframe) {
q921_transmit_uiframe(ctrl, h, len);
+ if (ctrl->debug & PRI_DEBUG_Q931_DUMP) {
+ /*
+ * The transmit operation might dump the Q.921 header, so logging
+ * the Q.931 message body after the transmit puts the sections of
+ * the message in the right order in the log,
+ */
+ q931_dump(ctrl, tei, h, len, 1);
+ }
} else {
+ /*
+ * Indicate passing the Q.931 message to Q.921 first. Q.921 may
+ * have to request a TEI or bring the connection up before it can
+ * actually send the message. Therefore, the Q.931 message may
+ * actually get sent a few seconds later. Q.921 will dump the
+ * Q.931 message as appropriate at that time.
+ */
+ if (ctrl->debug & PRI_DEBUG_Q931_DUMP) {
+ q931_to_q921_passing_dump(ctrl, tei, h, len);
+ }
q921_transmit_iframe(ctrl, tei, h, len, cr);
}
- /* The transmit operation might dump the q921 header, so logging the q931
- message body after the transmit puts the sections of the message in the
- right order in the log */
- if (ctrl->debug & PRI_DEBUG_Q931_DUMP)
- q931_dump(ctrl, tei, h, len, 1);
-#ifdef LIBPRI_COUNTERS
- ctrl->q931_txcount++;
-#endif
return 0;
}
@@ -4093,6 +4253,7 @@
int x;
int codeset;
int uiframe;
+ int tei;
if (call->outboundbroadcast && call->master_call == call && msgtype != Q931_SETUP) {
pri_error(ctrl,
@@ -4121,6 +4282,7 @@
/* Invert the logic */
len = sizeof(buf) - len;
+ tei = call->pri->tei;
uiframe = 0;
if (BRI_NT_PTMP(ctrl)) {
/* NT PTMP is the only mode that can broadcast Q.931 messages. */
@@ -4137,7 +4299,7 @@
uiframe = 1;
break;
case Q931_FACILITY:
- if (call->pri->tei == Q921_TEI_GROUP) {
+ if (tei == Q921_TEI_GROUP) {
/* Broadcast TEI. */
if (q931_is_dummy_call(call)) {
/*
@@ -4162,8 +4324,14 @@
"Sending message for call %p on call->pri: %p with TEI/SAPI %d/%d\n",
call, call->pri, call->pri->tei, call->pri->sapi);
}
+ } else if (call->pri->subchannel && BRI_TE_PTMP(ctrl)) {
+ /*
+ * Get the best available TEI value for the debug dump display.
+ * We may not actually have a TEI assigned at the moment.
+ */
+ tei = call->pri->subchannel->tei;
}
- q931_xmit(call->pri, call->pri->tei, h, len, 1, uiframe);
+ q931_xmit(call->pri, tei, h, len, 1, uiframe);
call->acked = 1;
return 0;
}
@@ -4497,10 +4665,11 @@
{
struct q931_call *c = data;
struct pri *ctrl = c->pri;
+
if (ctrl->debug & PRI_DEBUG_Q931_STATE)
pri_message(ctrl, "Timed out looking for connect acknowledge\n");
+ c->retranstimer = 0;
q931_disconnect(ctrl, c, PRI_CAUSE_NORMAL_CLEARING);
-
}
/* T308 expiry, first time */
@@ -4508,9 +4677,11 @@
{
struct q931_call *c = data;
struct pri *ctrl = c->pri;
+
if (ctrl->debug & PRI_DEBUG_Q931_STATE)
pri_message(ctrl, "Timed out looking for release complete\n");
c->t308_timedout++;
+ c->retranstimer = 0;
c->alive = 1;
/* The call to q931_release will re-schedule T308 */
@@ -4522,6 +4693,8 @@
{
struct q931_call *c = data;
struct pri *ctrl = c->pri;
+
+ c->retranstimer = 0;
c->alive = 1;
if (ctrl->debug & PRI_DEBUG_Q931_STATE)
pri_message(ctrl, "Final time-out looking for release complete\n");
@@ -4548,8 +4721,10 @@
{
struct q931_call *c = data;
struct pri *ctrl = c->pri;
+
if (ctrl->debug & PRI_DEBUG_Q931_STATE)
pri_message(ctrl, "Timed out looking for release\n");
+ c->retranstimer = 0;
c->alive = 1;
q931_release(ctrl, c, PRI_CAUSE_NORMAL_CLEARING);
}
@@ -4848,6 +5023,9 @@
pri_call_add_standard_apdus(ctrl, c);
+ if (BRI_NT_PTMP(ctrl)) {
+ c->outboundbroadcast = 1;
+ }
if (ctrl->subchannel && !ctrl->bri)
res = send_message(ctrl, c, Q931_SETUP, gr303_setup_ies);
else if (c->cis_call)
@@ -4861,13 +5039,9 @@
UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_CALL_INITIATED);
c->peercallstate = Q931_CALL_STATE_CALL_PRESENT;
c->t303_expirycnt = 0;
- if (BRI_NT_PTMP(ctrl)) {
- c->outboundbroadcast = 1;
- }
start_t303(c);
}
return res;
-
}
static int release_complete_ies[] = { Q931_IE_USER_USER, -1 };
@@ -5363,6 +5537,12 @@
struct q931_call *c = data;
struct pri *ctrl = c->pri;
+ /*
+ * We cannot clear the retranstimer id because we are called by t303_expiry also.
+ * Fortunately, it doesn't matter because pri_internal_clear() will stop it if
+ * it was actually running.
+ */
+ //c->retranstimer = 0;
c->performing_fake_clearing = 1;
if (pri_internal_clear(c) == Q931_RES_HAVEEVENT)
ctrl->schedev = 1;
@@ -5370,6 +5550,7 @@
static void pri_create_fake_clearing(struct q931_call *c, struct pri *master)
{
+ /* Point to the master so the timeout event can come out. */
c->pri = master;
pri_schedule_del(master, c->retranstimer);
@@ -5624,7 +5805,9 @@
c->changestatus = -1;
break;
default:
- pri_error(ctrl, "!! Don't know how to pre-handle maintenance message type '%d'\n", mh->msg);
+ pri_error(ctrl,
+ "!! Don't know how to pre-handle maintenance message type '0x%X'\n",
+ mh->msg);
return -1;
}
return 0;
@@ -5673,6 +5856,7 @@
q931_party_address_init(&c->called);
q931_party_id_init(&c->local_id);
q931_party_id_init(&c->remote_id);
+ q931_party_number_init(&c->ani);
q931_party_redirecting_init(&c->redirecting);
/*
@@ -5772,13 +5956,13 @@
case Q931_SUSPEND:
case Q931_SUSPEND_ACKNOWLEDGE:
case Q931_SUSPEND_REJECT:
- pri_error(ctrl, "!! Not yet handling pre-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg);
+ pri_error(ctrl, "!! Not yet handling pre-handle message type %s (0x%X)\n",
+ msg2str(mh->msg), mh->msg);
/* Fall through */
default:
- pri_error(ctrl, "!! Don't know how to pre-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg);
+ pri_error(ctrl, "!! Don't know how to pre-handle message type %s (0x%X)\n",
+ msg2str(mh->msg), mh->msg);
q931_status(ctrl,c, PRI_CAUSE_MESSAGE_TYPE_NONEXIST);
- if (c->newcall)
- pri_destroycall(ctrl, c);
return -1;
}
return 0;
@@ -5915,8 +6099,6 @@
int allow_posthandle;
memset(last_ie, 0, sizeof(last_ie));
- if (ctrl->debug & PRI_DEBUG_Q931_DUMP)
- q931_dump(ctrl, tei, h, len, 0);
#ifdef LIBPRI_COUNTERS
ctrl->q931_rxcount++;
#endif
@@ -5985,7 +6167,18 @@
/* Unknown protocol discriminator but we will treat it as Q.931 anyway. */
case GR303_PROTOCOL_DISCRIMINATOR:
case Q931_PROTOCOL_DISCRIMINATOR:
- prepare_to_handle_q931_message(ctrl, mh, c);
+ if (prepare_to_handle_q931_message(ctrl, mh, c)) {
+ /* Discard message. We don't know how to handle it. */
+ if (!c->master_call->outboundbroadcast && c->newcall) {
+ /*
+ * Destroy new non-subcalls immediately. Let the normal
+ * disconnect/destruction of subcalls happen when there is a
+ * winner.
+ */
+ pri_destroycall(ctrl, c);
+ }
+ return 0;
+ }
break;
}
q931_clr_subcommands(ctrl);
@@ -6162,7 +6355,8 @@
return Q931_RES_HAVEEVENT;
}
- pri_error(ctrl, "!! Don't know how to post-handle maintenance message type %d\n", mh->msg);
+ pri_error(ctrl, "!! Don't know how to post-handle maintenance message type 0x%X\n",
+ mh->msg);
return -1;
}
@@ -6477,11 +6671,9 @@
/* Calling party information */
ctrl->ev.ring.callingpres = q931_party_id_presentation(&call->remote_id);
ctrl->ev.ring.callingplan = call->remote_id.number.plan;
- if (call->remote_id.number.valid
- && (call->remote_id.number.presentation == PRES_ALLOWED_NETWORK_NUMBER
- || call->remote_id.number.presentation == PRES_PROHIB_NETWORK_NUMBER)) {
- ctrl->ev.ring.callingplanani = call->remote_id.number.plan;
- libpri_copy_string(ctrl->ev.ring.callingani, call->remote_id.number.str,
+ if (call->ani.valid) {
+ ctrl->ev.ring.callingplanani = call->ani.plan;
+ libpri_copy_string(ctrl->ev.ring.callingani, call->ani.str,
sizeof(ctrl->ev.ring.callingani));
} else {
ctrl->ev.ring.callingplanani = -1;
@@ -6815,9 +7007,20 @@
q931_release_complete(ctrl,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
break;
}
- if (c->ourcallstate == Q931_CALL_STATE_ACTIVE) {
- q931_status(ctrl, c, PRI_CAUSE_WRONG_MESSAGE);
+ switch (c->ourcallstate) {
+ case Q931_CALL_STATE_CALL_INITIATED:
+ case Q931_CALL_STATE_OVERLAP_SENDING:
+ case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING:
+ case Q931_CALL_STATE_CALL_DELIVERED:
+ case Q931_CALL_STATE_CALL_PRESENT:
+ case Q931_CALL_STATE_CALL_RECEIVED:
+ case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING:
+ case Q931_CALL_STATE_OVERLAP_RECEIVING:
+ /* Accept CONNECT in these states. */
break;
+ default:
+ q931_status(ctrl, c, PRI_CAUSE_WRONG_CALL_STATE);
+ return 0;
}
UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_ACTIVE);
c->peercallstate = Q931_CALL_STATE_CONNECT_REQUEST;
@@ -6837,7 +7040,6 @@
if (c->cis_auto_disconnect && c->cis_call) {
/* Make sure WE release when we initiate a signalling only connection */
q931_hangup(ctrl, c, PRI_CAUSE_NORMAL_CLEARING);
- break;
} else {
c->incoming_ct_state = INCOMING_CT_STATE_IDLE;
@@ -6850,6 +7052,7 @@
return Q931_RES_HAVEEVENT;
}
+ break;
case Q931_FACILITY:
if (c->newcall) {
q931_release_complete(ctrl,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
@@ -6943,16 +7146,24 @@
if ((ctrl->debug & PRI_DEBUG_Q931_ANOMALY) &&
(c->cause != PRI_CAUSE_INTERWORKING))
pri_error(ctrl, "Received unsolicited status: %s\n", pri_cause2str(c->cause));
- /* Workaround for S-12 ver 7.3 - it responds for invalid/non-implemented IEs at SETUP with null call state */
+ if (
#if 0
- if (!c->sugcallstate && (c->ourcallstate != Q931_CALL_STATE_CALL_INITIATED)) {
+ /*
+ * Workaround for S-12 ver 7.3 - it responds to
+ * invalid/non-implemented IEs in SETUP with NULL call state.
+ */
+ !c->sugcallstate && (c->ourcallstate != Q931_CALL_STATE_CALL_INITIATED)
#else
- /* Remove "workaround" since it breaks certification testing. If we receive a STATUS message of call state
- * NULL and we are not in the call state NULL we must clear resources and return to the call state to pass
- * testing. See section 5.8.11 of Q.931 */
+ /*
+ * Remove "workaround" since it breaks certification testing. If
+ * we receive a STATUS message of call state NULL and we are not
+ * in the call state NULL we must clear resources and return to
+ * the call state to pass testing. See section 5.8.11 of Q.931.
+ */
- if (!c->sugcallstate) {
+ !c->sugcallstate
#endif
+ ) {
ctrl->ev.hangup.subcmds = &ctrl->subcmds;
ctrl->ev.hangup.channel = q931_encode_channel(c);
ctrl->ev.hangup.cause = c->cause;
@@ -7500,13 +7711,21 @@
case Q931_SUSPEND:
case Q931_SUSPEND_ACKNOWLEDGE:
case Q931_SUSPEND_REJECT:
- pri_error(ctrl, "!! Not yet handling post-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg);
+ pri_error(ctrl, "!! Not yet handling post-handle message type %s (0x%X)\n",
+ msg2str(mh->msg), mh->msg);
/* Fall through */
default:
- pri_error(ctrl, "!! Don't know how to post-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg);
+ pri_error(ctrl, "!! Don't know how to post-handle message type %s (0x%X)\n",
+ msg2str(mh->msg), mh->msg);
q931_status(ctrl,c, PRI_CAUSE_MESSAGE_TYPE_NONEXIST);
- if (c->newcall)
+ if (!c->master_call->outboundbroadcast && c->newcall) {
+ /*
+ * Destroy new non-subcalls immediately. Let the normal
+ * disconnect/destruction of subcalls happen when there is a
+ * winner.
+ */
pri_destroycall(ctrl, c);
+ }
return -1;
}
return 0;
@@ -7530,6 +7749,18 @@
UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_NULL);
c->peercallstate = Q931_CALL_STATE_NULL;
+
+ if (c->master_call->outboundbroadcast
+ && c == q931_find_winning_call(c)) {
+ /* Pass the hangup cause to the master_call. */
+ c->master_call->cause = c->cause;
+
+ /* Declare this winning subcall to no longer be the winner and destroy it. */
+ c->master_call->pri_winner = -1;
+ q931_destroycall(ctrl, c);
+ return 0;
+ }
+
q931_clr_subcommands(ctrl);
ctrl->ev.hangup.subcmds = &ctrl->subcmds;
ctrl->ev.hangup.channel = q931_encode_channel(c);
@@ -7566,9 +7797,15 @@
{
struct q931_call *c = data;
struct pri *ctrl = c->pri;
+
+ /* Point to the master so the timeout event can come out. */
+ ctrl = PRI_MASTER(ctrl);
+ c->pri = ctrl;
+
if (ctrl->debug & PRI_DEBUG_Q931_STATE)
- pri_message(ctrl, DBGHEAD "Timed out waiting for data link re-establishment\n", DBGINFO);
+ pri_message(ctrl, "T309 timed out waiting for data link re-establishment\n");
+ c->retranstimer = 0;
c->cause = PRI_CAUSE_DESTINATION_OUT_OF_ORDER;
if (pri_internal_clear(c) == Q931_RES_HAVEEVENT)
ctrl->schedev = 1;
@@ -7579,94 +7816,292 @@
{
struct q931_call *c = data;
struct pri *ctrl = c->pri;
+
+ /* Point to the master so the timeout event can come out. */
+ ctrl = PRI_MASTER(ctrl);
+ c->pri = ctrl;
+
if (ctrl->debug & PRI_DEBUG_Q931_STATE)
- pri_message(ctrl, DBGHEAD "Cancel non active call after data link failure\n", DBGINFO);
+ pri_message(ctrl, "Cancel call after data link failure\n");
+ c->retranstimer = 0;
c->cause = PRI_CAUSE_DESTINATION_OUT_OF_ORDER;
if (pri_internal_clear(c) == Q931_RES_HAVEEVENT)
ctrl->schedev = 1;
}
-/* Receive an indication from Layer 2 */
-void q931_dl_indication(struct pri *ctrl, int event)
+/*!
+ * \internal
+ * \brief Convert the DL event to a string.
+ *
+ * \param event Data-link event to convert to a string.
+ *
+ * \return DL event string
+ */
+static const char *q931_dl_event2str(enum Q931_DL_EVENT event)
+{
+ const char *str;
+
+ str = "Unknown";
+ switch (event) {
+ case Q931_DL_EVENT_NONE:
+ str = "Q931_DL_EVENT_NONE";
+ break;
+ case Q931_DL_EVENT_DL_ESTABLISH_IND:
+ str = "Q931_DL_EVENT_DL_ESTABLISH_IND";
+ break;
+ case Q931_DL_EVENT_DL_ESTABLISH_CONFIRM:
+ str = "Q931_DL_EVENT_DL_ESTABLISH_CONFIRM";
+ break;
+ case Q931_DL_EVENT_DL_RELEASE_IND:
+ str = "Q931_DL_EVENT_DL_RELEASE_IND";
+ break;
+ case Q931_DL_EVENT_DL_RELEASE_CONFIRM:
+ str = "Q931_DL_EVENT_DL_RELEASE_CONFIRM";
+ break;
+ case Q931_DL_EVENT_TEI_REMOVAL:
+ str = "Q931_DL_EVENT_TEI_REMOVAL";
+ break;
+ }
+ return str;
+}
+
+/*!
+ * \brief Receive a DL event from layer 2.
+ *
+ * \param link Q.921 link event occurred on.
+ * \param event Data-link event reporting.
+ *
+ * \return Nothing
+ */
+void q931_dl_event(struct pri *link, enum Q931_DL_EVENT event)
{
struct q931_call *cur;
- struct q931_call *winner;
+ struct q931_call *call;
+ struct pri *ctrl;
+ int idx;
- /* Just return if T309 is not enabled. */
- if (!ctrl || ctrl->timers[PRI_TIMER_T309] < 0)
+ if (!link) {
return;
+ }
+
+ /* Find the master - He has the call pool */
+ ctrl = PRI_MASTER(link);
+
+ if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
+ pri_message(ctrl, "TEI=%d DL event: %s(%d)\n", link->tei,
+ q931_dl_event2str(event), event);
+ }
+
+ if (BRI_TE_PTMP(ctrl)) {
+ /* The link is always the master */
+ link = ctrl;
+ }
switch (event) {
- case PRI_EVENT_DCHAN_DOWN:
- if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
- pri_message(ctrl, DBGHEAD "link is DOWN\n", DBGINFO);
+ case Q931_DL_EVENT_TEI_REMOVAL:
+ if (!BRI_NT_PTMP(ctrl)) {
+ /* Only NT PTMP has anything to worry about when the TEI is removed. */
+ break;
+ }
+
+ /*
+ * For NT PTMP, this deviation from the specifications is needed
+ * because we have no way to re-associate any T309 calls on the
+ * removed TEI.
+ */
+ for (cur = *ctrl->callpool; cur; cur = cur->next) {
+ if (!(cur->cr & ~Q931_CALL_REFERENCE_FLAG)) {
+ /* Don't do anything on the global call reference call record. */
+ continue;
+ }
+ if (cur->outboundbroadcast) {
+ /* Does this master call have a subcall on the link that went down? */
+ call = NULL;
+ for (idx = 0; idx < ARRAY_LEN(cur->subcalls); ++idx) {
+ if (cur->subcalls[idx] && cur->subcalls[idx]->pri == link) {
+ /* This subcall is on the link that went down. */
+ call = cur->subcalls[idx];
+ break;
+ }
+ }
+ if (!call) {
+ /* No subcall is on the link that went down. */
+ continue;
+ }
+ } else if (cur->pri != link) {
+ /* This call is not on the link that went down. */
+ continue;
+ } else {
+ call = cur;
+ }
+
+ /*
+ * NOTE: We are gambling that no T309 timer's have had a chance
+ * to expire. They should not expire since we are either called
+ * immediately after the Q931_DL_EVENT_DL_RELEASE_xxx or after a
+ * timeout of 0.
+ */
+ if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
+ pri_message(ctrl, "Cancel call cref=%d on channel %d in state %d (%s)\n",
+ call->cr, call->channelno, call->ourcallstate,
+ q931_call_state_str(call->ourcallstate));
+ }
+ call->pri = ctrl;/* Point to a safer place until the call is destroyed. */
+ pri_schedule_del(ctrl, call->retranstimer);
+ call->retranstimer = pri_schedule_event(ctrl, 0, pri_dl_down_cancelcall,
+ call);
}
+ break;
+ case Q931_DL_EVENT_DL_RELEASE_IND:
+ case Q931_DL_EVENT_DL_RELEASE_CONFIRM:
for (cur = *ctrl->callpool; cur; cur = cur->next) {
if (!(cur->cr & ~Q931_CALL_REFERENCE_FLAG)) {
/* Don't do anything on the global call reference call record. */
continue;
- } else if (cur->ourcallstate == Q931_CALL_STATE_ACTIVE) {
- /* For a call in Active state, activate T309 only if there is no timer already running. */
- if (!cur->retranstimer) {
+ }
+ if (cur->outboundbroadcast) {
+ /* Does this master call have a subcall on the link that went down? */
+ call = NULL;
+ for (idx = 0; idx < ARRAY_LEN(cur->subcalls); ++idx) {
+ if (cur->subcalls[idx] && cur->subcalls[idx]->pri == link) {
+ /* This subcall is on the link that went down. */
+ call = cur->subcalls[idx];
+ break;
+ }
+ }
+ if (!call) {
+ /* No subcall is on the link that went down. */
+ continue;
+ }
+ } else if (cur->pri != link) {
+ /* This call is not on the link that went down. */
+ continue;
+ } else {
+ call = cur;
+ }
+ switch (call->ourcallstate) {
+ case Q931_CALL_STATE_ACTIVE:
+ /* NOTE: Only a winning subcall can get to the active state. */
+ if (ctrl->nfas) {
+ /*
+ * The upper layer should handle T309 for NFAS since the calls
+ * could be maintained by a backup D channel if the B channel
+ * for the call did not go into alarm.
+ */
+ break;
+ }
+ /*
+ * For a call in Active state, activate T309 only if there is
+ * no timer already running.
+ *
+ * NOTE: cur != call when we have a winning subcall.
+ */
+ if (!cur->retranstimer || !call->retranstimer) {
if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
- pri_message(ctrl,
- DBGHEAD "activate T309 for call %d on channel %d\n", DBGINFO,
- cur->cr, cur->channelno);
+ pri_message(ctrl, "Start T309 for call cref=%d on channel %d\n",
+ call->cr, call->channelno);
}
- cur->retranstimer = pri_schedule_event(ctrl, ctrl->timers[PRI_TIMER_T309], pri_dl_down_timeout, cur);
+ call->retranstimer = pri_schedule_event(ctrl,
+ ctrl->timers[PRI_TIMER_T309], pri_dl_down_timeout, call);
}
- } else if (cur->ourcallstate != Q931_CALL_STATE_NULL) {
- /* For a call that is not in Active state, schedule internal clearing of the call 'ASAP' (delay 0). */
+ break;
+ case Q931_CALL_STATE_NULL:
+ break;
+ default:
+ /*
+ * For a call that is not in Active state, schedule internal
+ * clearing of the call 'ASAP' (delay 0).
+ *
+ * NOTE: We are killing NFAS calls that are not connected yet
+ * because there are likely messages in flight when this link
+ * went down that could leave the call in an unknown/stuck state.
+ */
if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
pri_message(ctrl,
- DBGHEAD "cancel call %d on channel %d in state %d (%s)\n", DBGINFO,
- cur->cr, cur->channelno, cur->ourcallstate,
- q931_call_state_str(cur->ourcallstate));
+ "Cancel call cref=%d on channel %d in state %d (%s)\n",
+ call->cr, call->channelno, call->ourcallstate,
+ q931_call_state_str(call->ourcallstate));
+ }
+ if (cur->outboundbroadcast) {
+ /* Simply destroy non-winning subcalls. */
+ q931_destroycall(ctrl, call);
+ continue;
}
- pri_schedule_del(ctrl, cur->retranstimer);
- cur->retranstimer = pri_schedule_event(ctrl, 0, pri_dl_down_cancelcall, cur);
+ pri_schedule_del(ctrl, call->retranstimer);
+ call->retranstimer = pri_schedule_event(ctrl, 0, pri_dl_down_cancelcall,
+ call);
+ break;
}
}
break;
- case PRI_EVENT_DCHAN_UP:
- if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
- pri_message(ctrl, DBGHEAD "link is UP\n", DBGINFO);
- }
+ case Q931_DL_EVENT_DL_ESTABLISH_IND:
+ case Q931_DL_EVENT_DL_ESTABLISH_CONFIRM:
for (cur = *ctrl->callpool; cur; cur = cur->next) {
if (!(cur->cr & ~Q931_CALL_REFERENCE_FLAG)) {
/* Don't do anything on the global call reference call record. */
continue;
- } else if (cur->ourcallstate == Q931_CALL_STATE_ACTIVE && cur->retranstimer) {
- if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
- pri_message(ctrl,
- DBGHEAD "cancel T309 for call %d on channel %d\n", DBGINFO,
- cur->cr, cur->channelno);
+ }
+ if (cur->outboundbroadcast) {
+ /* Does this master call have a subcall on the link that came up? */
+ call = NULL;
+ for (idx = 0; idx < ARRAY_LEN(cur->subcalls); ++idx) {
+ if (cur->subcalls[idx] && cur->subcalls[idx]->pri == link) {
+ /* This subcall is on the link that came up. */
+ call = cur->subcalls[idx];
+ break;
+ }
+ }
+ if (!call) {
+ /* No subcall is on the link that came up. */
+ continue;
+ }
+ } else if (cur->pri != link) {
+ /* This call is not on the link that came up. */
+ continue;
+ } else {
+ call = cur;
+ }
+ switch (call->ourcallstate) {
+ case Q931_CALL_STATE_ACTIVE:
+ /* NOTE: Only a winning subcall can get to the active state. */
+ if (pri_schedule_check(ctrl, call->retranstimer, pri_dl_down_timeout, call)) {
+ if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
+ pri_message(ctrl, "Stop T309 for call cref=%d on channel %d\n",
+ call->cr, call->channelno);
+ }
+ pri_schedule_del(ctrl, call->retranstimer);
+ call->retranstimer = 0;
}
- pri_schedule_del(ctrl, cur->retranstimer);
- cur->retranstimer = 0;
- winner = q931_find_winning_call(cur);
- if (winner) {
- q931_status(ctrl, winner, PRI_CAUSE_NORMAL_UNSPECIFIED);
+ q931_status(ctrl, call, PRI_CAUSE_NORMAL_UNSPECIFIED);
+ break;
+ case Q931_CALL_STATE_NULL:
+ case Q931_CALL_STATE_DISCONNECT_REQUEST:
+ case Q931_CALL_STATE_DISCONNECT_INDICATION:
+ case Q931_CALL_STATE_RELEASE_REQUEST:
+ break;
+ default:
+ if (event == Q931_DL_EVENT_DL_ESTABLISH_CONFIRM) {
+ /*
+ * Lets not send a STATUS message for this call as we
+ * requested the link to be established as a likely
+ * result of this call.
+ */
+ break;
}
- } else if (cur->ourcallstate != Q931_CALL_STATE_NULL &&
- cur->ourcallstate != Q931_CALL_STATE_DISCONNECT_REQUEST &&
- cur->ourcallstate != Q931_CALL_STATE_DISCONNECT_INDICATION &&
- cur->ourcallstate != Q931_CALL_STATE_RELEASE_REQUEST) {
/*
* The STATUS message sent here is not required by Q.931,
* but it may help anyway.
* This looks like a new call started while the link was down.
*/
- winner = q931_find_winning_call(cur);
- if (winner) {
- q931_status(ctrl, winner, PRI_CAUSE_NORMAL_UNSPECIFIED);
- }
+ q931_status(ctrl, call, PRI_CAUSE_NORMAL_UNSPECIFIED);
+ break;
}
}
break;
default:
pri_message(ctrl, DBGHEAD "unexpected event %d.\n", DBGINFO, event);
+ break;
}
}
|