|
|
|
|
@@ -218,7 +218,7 @@ struct q931_call {
|
|
|
|
|
int causeloc; /* Cause Location */
|
|
|
|
|
int cause; /* Cause of clearing */
|
|
|
|
|
|
|
|
|
|
int callstate; /* Call state of peer as reported */
|
|
|
|
|
int peercallstate; /* Call state of peer as reported */
|
|
|
|
|
int ourcallstate; /* Our call state */
|
|
|
|
|
|
|
|
|
|
int callerplan;
|
|
|
|
|
@@ -229,6 +229,7 @@ struct q931_call {
|
|
|
|
|
int calledplan;
|
|
|
|
|
int nonisdn;
|
|
|
|
|
char callednum[256]; /* Called Number */
|
|
|
|
|
int complete; /* no more digits coming */
|
|
|
|
|
|
|
|
|
|
int redirectingplan;
|
|
|
|
|
int redirectingpres;
|
|
|
|
|
@@ -273,6 +274,7 @@ static void call_init(struct q931_call *c)
|
|
|
|
|
c->next = NULL;
|
|
|
|
|
c->sentchannel = 0;
|
|
|
|
|
c->ourcallstate = Q931_CALL_STATE_NULL;
|
|
|
|
|
c->peercallstate = Q931_CALL_STATE_NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *binary(int b, int len) {
|
|
|
|
|
@@ -700,7 +702,7 @@ char *pri_pres2str(int pres)
|
|
|
|
|
{ PRES_PROHIB_USER_NUMBER_NOT_SCREENED, "Presentation prohibited, user number not screened" },
|
|
|
|
|
{ PRES_PROHIB_USER_NUMBER_PASSED_SCREEN, "Presentation prohibited, user number passed network screening" },
|
|
|
|
|
{ PRES_PROHIB_USER_NUMBER_FAILED_SCREEN, "Presentation prohibited, user number failed network screening" },
|
|
|
|
|
{ PRES_PROHIB_NETWORK_NUMBER, "Presentation prohibbited of network provided number" },
|
|
|
|
|
{ PRES_PROHIB_NETWORK_NUMBER, "Presentation prohibited of network provided number" },
|
|
|
|
|
};
|
|
|
|
|
return code2str(pres, press, sizeof(press) / sizeof(press[0]));
|
|
|
|
|
}
|
|
|
|
|
@@ -740,7 +742,7 @@ static void dump_calling_party_number(q931_ie *ie, int len, char prefix)
|
|
|
|
|
|
|
|
|
|
q931_get_number(cnum, sizeof(cnum), ie->data + 2, len - 4);
|
|
|
|
|
pri_message("%c Calling Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d)\n", prefix, len, ie->data[0] >> 7, ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07, npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f);
|
|
|
|
|
pri_message("%c Presentation: %s (%d) '%s' ]\n", prefix, pri_pres2str(ie->data[1]), ie->data[1] & 0x7f, cnum);
|
|
|
|
|
pri_message("%c Presentation: %s (%d) '%s' ]\n", prefix, pri_pres2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f, cnum);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void dump_calling_party_subaddr(q931_ie *ie, int len, char prefix)
|
|
|
|
|
@@ -758,7 +760,7 @@ static void dump_redirecting_number(q931_ie *ie, int len, char prefix)
|
|
|
|
|
char cnum[256];
|
|
|
|
|
q931_get_number(cnum, sizeof(cnum), ie->data + 3, len - 5);
|
|
|
|
|
pri_message("%c Redirecting Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d)\n", prefix, len, ie->data[0] >> 7, ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07, npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f);
|
|
|
|
|
pri_message("%c Presentation: %s (%d) Reason: %s (%d) '%s' ]\n", prefix, pri_pres2str(ie->data[1]), ie->data[1] & 0x7f, redirection_reason2str(ie->data[2]), ie->data[2], cnum);
|
|
|
|
|
pri_message("%c Presentation: %s (%d) Reason: %s (%d) '%s' ]\n", prefix, pri_pres2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f, redirection_reason2str(ie->data[2]), ie->data[2], cnum);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -785,13 +787,8 @@ static void dump_redirecting_subaddr(q931_ie *ie, int len, char prefix)
|
|
|
|
|
|
|
|
|
|
static int receive_called_party_number(struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len)
|
|
|
|
|
{
|
|
|
|
|
#ifdef SKIP_OVERLAP_SUPPORT
|
|
|
|
|
/* copy digits to call->callednum */
|
|
|
|
|
q931_get_number(call->callednum, sizeof(call->callednum), ie->data + 1, len - 3);
|
|
|
|
|
#else
|
|
|
|
|
/* append new digits to call->callednum */
|
|
|
|
|
q931_get_number(call->callednum + strlen(call->callednum), sizeof(call->callednum) - strlen(call->callednum), ie->data + 1, len - 3);
|
|
|
|
|
#endif
|
|
|
|
|
call->calledplan = ie->data[0] & 0x7f;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
@@ -911,9 +908,12 @@ static int receive_display(struct pri *pri, q931_call *call, int msgtype, q931_i
|
|
|
|
|
|
|
|
|
|
static int transmit_display(struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len)
|
|
|
|
|
{
|
|
|
|
|
ie->data[0] = 0xb1;
|
|
|
|
|
memcpy(ie->data + 1, call->callername, strlen(call->callername));
|
|
|
|
|
return 3 + strlen(call->callername);
|
|
|
|
|
if (pri->switchtype != PRI_SWITCH_NI1) {
|
|
|
|
|
ie->data[0] = 0xb1;
|
|
|
|
|
memcpy(ie->data + 1, call->callername, strlen(call->callername));
|
|
|
|
|
return 3 + strlen(call->callername);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int receive_progress_indicator(struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len)
|
|
|
|
|
@@ -1136,13 +1136,14 @@ static void dump_sending_complete(q931_ie *ie, int len, char prefix)
|
|
|
|
|
|
|
|
|
|
static int receive_sending_complete(struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len)
|
|
|
|
|
{
|
|
|
|
|
/* Do nothing */
|
|
|
|
|
/* We've got a "Complete" message: Exect no further digits. */
|
|
|
|
|
call->complete = 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int transmit_sending_complete(struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len)
|
|
|
|
|
{
|
|
|
|
|
if ((pri->switchtype == PRI_SWITCH_EUROISDN_E1) || (pri->switchtype == PRI_SWITCH_EUROISDN_T1)) {
|
|
|
|
|
if (!pri->overlapdial && ((pri->switchtype == PRI_SWITCH_EUROISDN_E1) || (pri->switchtype == PRI_SWITCH_EUROISDN_T1))) {
|
|
|
|
|
/* Include this single-byte IE */
|
|
|
|
|
ie->f = 1;
|
|
|
|
|
return 1;
|
|
|
|
|
@@ -1205,7 +1206,7 @@ struct ie ies[] = {
|
|
|
|
|
|
|
|
|
|
static char *ie2str(int ie)
|
|
|
|
|
{
|
|
|
|
|
int x;
|
|
|
|
|
unsigned int x;
|
|
|
|
|
for (x=0;x<sizeof(ies) / sizeof(ies[0]); x++)
|
|
|
|
|
if (ies[x].ie == ie)
|
|
|
|
|
return ies[x].name;
|
|
|
|
|
@@ -1222,7 +1223,7 @@ static inline int ielen(q931_ie *ie)
|
|
|
|
|
|
|
|
|
|
static char *msg2str(int msg)
|
|
|
|
|
{
|
|
|
|
|
int x;
|
|
|
|
|
unsigned int x;
|
|
|
|
|
for (x=0;x<sizeof(msgs) / sizeof(msgs[0]); x++)
|
|
|
|
|
if (msgs[x].msgnum == msg)
|
|
|
|
|
return msgs[x].name;
|
|
|
|
|
@@ -1246,7 +1247,7 @@ static inline int q931_cr(q931_h *h)
|
|
|
|
|
|
|
|
|
|
static inline void q931_dumpie(q931_ie *ie, char prefix)
|
|
|
|
|
{
|
|
|
|
|
int x;
|
|
|
|
|
unsigned int x;
|
|
|
|
|
for (x=0;x<sizeof(ies) / sizeof(ies[0]); x++)
|
|
|
|
|
if (ies[x].ie == ie->ie) {
|
|
|
|
|
if (ies[x].dump)
|
|
|
|
|
@@ -1315,6 +1316,8 @@ static void q931_destroycall(struct pri *pri, int cr)
|
|
|
|
|
prev->next = cur->next;
|
|
|
|
|
else
|
|
|
|
|
pri->calls = cur->next;
|
|
|
|
|
if (pri->debug & PRI_DEBUG_Q931_STATE)
|
|
|
|
|
pri_message("NEW_HANGUP DEBUG: Destroying the call, ourstate %s, peerstate %s\n",callstate2str(cur->ourcallstate),callstate2str(cur->peercallstate));
|
|
|
|
|
free(cur);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
@@ -1324,9 +1327,14 @@ static void q931_destroycall(struct pri *pri, int cr)
|
|
|
|
|
pri_error("Can't destroy call %d!\n", cr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void __q931_destroycall(struct pri *pri, q931_call *c) {
|
|
|
|
|
if (pri && c)
|
|
|
|
|
q931_destroycall(pri,c->cr);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
static int add_ie(struct pri *pri, q931_call *call, int msgtype, int ie, q931_ie *iet, int maxlen)
|
|
|
|
|
{
|
|
|
|
|
int x;
|
|
|
|
|
unsigned int x;
|
|
|
|
|
int res;
|
|
|
|
|
for (x=0;x<sizeof(ies) / sizeof(ies[0]);x++) {
|
|
|
|
|
if (ies[x].ie == ie) {
|
|
|
|
|
@@ -1385,7 +1393,7 @@ void q931_dump(q931_h *h, int len, int txrx)
|
|
|
|
|
|
|
|
|
|
static int q931_handle_ie(struct pri *pri, q931_call *c, int msg, q931_ie *ie)
|
|
|
|
|
{
|
|
|
|
|
int x;
|
|
|
|
|
unsigned int x;
|
|
|
|
|
if (pri->debug & PRI_DEBUG_Q931_STATE)
|
|
|
|
|
pri_message("-- Processing IE %d (%s)\n", ie->ie, ie2str(ie->ie));
|
|
|
|
|
for (x=0;x<sizeof(ies) / sizeof(ies[0]);x++) {
|
|
|
|
|
@@ -1487,6 +1495,7 @@ static int q931_status(struct pri *pri, q931_call *c)
|
|
|
|
|
if (!cur) {
|
|
|
|
|
/* something went wrong, respond with "no such call" */
|
|
|
|
|
c->ourcallstate = Q931_CALL_STATE_NULL;
|
|
|
|
|
c->peercallstate = Q931_CALL_STATE_NULL;
|
|
|
|
|
cur=c;
|
|
|
|
|
}
|
|
|
|
|
return send_message(pri, cur, Q931_STATUS, status_ies);
|
|
|
|
|
@@ -1505,7 +1514,8 @@ static int restart_ack_ies[] = { Q931_CHANNEL_IDENT, Q931_RESTART_INDICATOR, -1
|
|
|
|
|
|
|
|
|
|
static int restart_ack(struct pri *pri, q931_call *c)
|
|
|
|
|
{
|
|
|
|
|
c->ourcallstate = Q931_CALL_STATE_CONNECT_REQUEST;
|
|
|
|
|
c->ourcallstate = Q931_CALL_STATE_NULL;
|
|
|
|
|
c->peercallstate = Q931_CALL_STATE_NULL;
|
|
|
|
|
return send_message(pri, c, Q931_RESTART_ACKNOWLEDGE, restart_ack_ies);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1514,11 +1524,16 @@ static int call_proceeding_ies[] = { Q931_CHANNEL_IDENT, -1 };
|
|
|
|
|
int q931_call_proceeding(struct pri *pri, q931_call *c)
|
|
|
|
|
{
|
|
|
|
|
c->ourcallstate = Q931_CALL_STATE_INCOMING_CALL_PROCEEDING;
|
|
|
|
|
c->peercallstate = Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING;
|
|
|
|
|
c->proc = 1;
|
|
|
|
|
c->alive = 1;
|
|
|
|
|
return send_message(pri, c, Q931_CALL_PROCEEDING, call_proceeding_ies);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifndef ALERTING_NO_PROGRESS
|
|
|
|
|
static int alerting_ies[] = { Q931_CHANNEL_IDENT, Q931_PROGRESS_INDICATOR, -1 };
|
|
|
|
|
#else
|
|
|
|
|
static int alerting_ies[] = { Q931_CHANNEL_IDENT, -1 };
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
int q931_alerting(struct pri *pri, q931_call *c, int channel, int info)
|
|
|
|
|
{
|
|
|
|
|
@@ -1535,6 +1550,8 @@ int q931_alerting(struct pri *pri, q931_call *c, int channel, int info)
|
|
|
|
|
if (!c->proc)
|
|
|
|
|
q931_call_proceeding(pri, c);
|
|
|
|
|
c->ourcallstate = Q931_CALL_STATE_CALL_RECEIVED;
|
|
|
|
|
c->peercallstate = Q931_CALL_STATE_CALL_DELIVERED;
|
|
|
|
|
c->alive = 1;
|
|
|
|
|
return send_message(pri, c, Q931_ALERTING, alerting_ies);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1553,6 +1570,8 @@ int q931_setup_ack(struct pri *pri, q931_call *c, int channel, int nonisdn)
|
|
|
|
|
} else
|
|
|
|
|
c->progress = -1;
|
|
|
|
|
c->ourcallstate = Q931_CALL_STATE_OVERLAP_RECEIVING;
|
|
|
|
|
c->peercallstate = Q931_CALL_STATE_OVERLAP_SENDING;
|
|
|
|
|
c->alive = 1;
|
|
|
|
|
return send_message(pri, c, Q931_SETUP_ACKNOWLEDGE, connect_ies);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1569,6 +1588,8 @@ int q931_connect(struct pri *pri, q931_call *c, int channel, int nonisdn)
|
|
|
|
|
} else
|
|
|
|
|
c->progress = -1;
|
|
|
|
|
c->ourcallstate = Q931_CALL_STATE_CONNECT_REQUEST;
|
|
|
|
|
c->peercallstate = Q931_CALL_STATE_ACTIVE;
|
|
|
|
|
c->alive = 1;
|
|
|
|
|
return send_message(pri, c, Q931_CONNECT, connect_ies);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1577,6 +1598,7 @@ static int release_ies[] = { Q931_CAUSE, -1 };
|
|
|
|
|
int q931_release(struct pri *pri, q931_call *c, int cause)
|
|
|
|
|
{
|
|
|
|
|
c->ourcallstate = Q931_CALL_STATE_RELEASE_REQUEST;
|
|
|
|
|
/* c->peercallstate stays the same */
|
|
|
|
|
if (c->alive) {
|
|
|
|
|
c->alive = 0;
|
|
|
|
|
c->cause = cause;
|
|
|
|
|
@@ -1605,6 +1627,7 @@ int q931_restart(struct pri *pri, int channel)
|
|
|
|
|
c->chanflags &= ~FLAG_PREFERRED;
|
|
|
|
|
c->chanflags |= FLAG_EXCLUSIVE;
|
|
|
|
|
c->ourcallstate = Q931_CALL_STATE_RESTART;
|
|
|
|
|
c->peercallstate = Q931_CALL_STATE_RESTART_REQUEST;
|
|
|
|
|
return send_message(pri, c, Q931_RESTART, restart_ies);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1613,6 +1636,7 @@ static int disconnect_ies[] = { Q931_CAUSE, -1 };
|
|
|
|
|
int q931_disconnect(struct pri *pri, q931_call *c, int cause)
|
|
|
|
|
{
|
|
|
|
|
c->ourcallstate = Q931_CALL_STATE_DISCONNECT_REQUEST;
|
|
|
|
|
c->peercallstate = Q931_CALL_STATE_DISCONNECT_INDICATION;
|
|
|
|
|
if (c->alive) {
|
|
|
|
|
c->alive = 0;
|
|
|
|
|
c->cause = cause;
|
|
|
|
|
@@ -1680,11 +1704,13 @@ int q931_setup(struct pri *pri, q931_call *c, int transmode, int channel, int ex
|
|
|
|
|
c->progress = Q931_PROG_CALLER_NOT_ISDN;
|
|
|
|
|
else
|
|
|
|
|
c->progress = -1;
|
|
|
|
|
|
|
|
|
|
c->ourcallstate = Q931_CALL_STATE_CALL_INITIATED;
|
|
|
|
|
res = send_message(pri, c, Q931_SETUP, setup_ies);
|
|
|
|
|
if (!res) {
|
|
|
|
|
c->alive = 1;
|
|
|
|
|
/* make sure we call PRI_EVENT_HANGUP_ACK once we send/receive RELEASE_COMPLETE */
|
|
|
|
|
c->sendhangupack = 1;
|
|
|
|
|
c->ourcallstate = Q931_CALL_STATE_CALL_INITIATED;
|
|
|
|
|
c->peercallstate = Q931_CALL_STATE_OVERLAP_SENDING;
|
|
|
|
|
}
|
|
|
|
|
return res;
|
|
|
|
|
|
|
|
|
|
@@ -1692,10 +1718,23 @@ int q931_setup(struct pri *pri, q931_call *c, int transmode, int channel, int ex
|
|
|
|
|
|
|
|
|
|
static int release_complete_ies[] = { -1 };
|
|
|
|
|
|
|
|
|
|
static int q931_release_complete(struct pri *pri, q931_call *c)
|
|
|
|
|
static int q931_release_complete(struct pri *pri, q931_call *c, int cause)
|
|
|
|
|
{
|
|
|
|
|
int res = 0;
|
|
|
|
|
c->ourcallstate = Q931_CALL_STATE_NULL;
|
|
|
|
|
return send_message(pri, c, Q931_RELEASE_COMPLETE, release_complete_ies);
|
|
|
|
|
c->peercallstate = Q931_CALL_STATE_NULL;
|
|
|
|
|
if (cause > -1) {
|
|
|
|
|
c->cause = cause;
|
|
|
|
|
c->causecode = CODE_CCITT;
|
|
|
|
|
c->causeloc = LOC_PRIV_NET_LOCAL_USER;
|
|
|
|
|
/* release_ies has CAUSE in it */
|
|
|
|
|
res = send_message(pri, c, Q931_RELEASE_COMPLETE, release_ies);
|
|
|
|
|
} else
|
|
|
|
|
res = send_message(pri, c, Q931_RELEASE_COMPLETE, release_complete_ies);
|
|
|
|
|
c->alive = 0;
|
|
|
|
|
/* release the structure */
|
|
|
|
|
res += q931_hangup(pri,c,cause);
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int connect_acknowledge_ies[] = { -1 };
|
|
|
|
|
@@ -1705,6 +1744,86 @@ static int q931_connect_acknowledge(struct pri *pri, q931_call *c)
|
|
|
|
|
return send_message(pri, c, Q931_CONNECT_ACKNOWLEDGE, connect_acknowledge_ies);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int q931_hangup(struct pri *pri, q931_call *c, int cause)
|
|
|
|
|
{
|
|
|
|
|
int disconnect = 1;
|
|
|
|
|
int release_compl = 0;
|
|
|
|
|
if (pri->debug & PRI_DEBUG_Q931_STATE)
|
|
|
|
|
pri_message("NEW_HANGUP DEBUG: Calling q931_hangup, ourstate %s, peerstate %s\n",callstate2str(c->ourcallstate),callstate2str(c->peercallstate));
|
|
|
|
|
if (!pri || !c)
|
|
|
|
|
return -1;
|
|
|
|
|
if (cause == 34 || cause == 44 || cause == 82 || cause == 1) {
|
|
|
|
|
/* We'll send RELEASE_COMPLETE with these causes */
|
|
|
|
|
disconnect = 0;
|
|
|
|
|
release_compl = 1;
|
|
|
|
|
}
|
|
|
|
|
if (cause == 6 || cause == 7 || cause == 26) {
|
|
|
|
|
/* We'll send RELEASE with these causes */
|
|
|
|
|
disconnect = 0;
|
|
|
|
|
}
|
|
|
|
|
/* All other causes we send with DISCONNECT */
|
|
|
|
|
switch(c->ourcallstate) {
|
|
|
|
|
case Q931_CALL_STATE_NULL:
|
|
|
|
|
if (c->peercallstate == Q931_CALL_STATE_NULL)
|
|
|
|
|
/* free the resources if we receive or send REL_COMPL */
|
|
|
|
|
q931_destroycall(pri, c->cr);
|
|
|
|
|
else if (c->peercallstate == Q931_CALL_STATE_RELEASE_REQUEST)
|
|
|
|
|
q931_release_complete(pri,c,cause);
|
|
|
|
|
break;
|
|
|
|
|
case Q931_CALL_STATE_CALL_INITIATED:
|
|
|
|
|
/* we sent SETUP */
|
|
|
|
|
case Q931_CALL_STATE_OVERLAP_SENDING:
|
|
|
|
|
/* received SETUP_ACKNOWLEDGE */
|
|
|
|
|
case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING:
|
|
|
|
|
/* received CALL_PROCEEDING */
|
|
|
|
|
case Q931_CALL_STATE_CALL_DELIVERED:
|
|
|
|
|
/* received ALERTING */
|
|
|
|
|
case Q931_CALL_STATE_CALL_PRESENT:
|
|
|
|
|
/* received SETUP */
|
|
|
|
|
case Q931_CALL_STATE_CALL_RECEIVED:
|
|
|
|
|
/* sent ALERTING */
|
|
|
|
|
case Q931_CALL_STATE_CONNECT_REQUEST:
|
|
|
|
|
/* sent CONNECT */
|
|
|
|
|
case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING:
|
|
|
|
|
/* we sent CALL_PROCEEDING */
|
|
|
|
|
case Q931_CALL_STATE_ACTIVE:
|
|
|
|
|
/* received CONNECT */
|
|
|
|
|
case Q931_CALL_STATE_OVERLAP_RECEIVING:
|
|
|
|
|
/* received SETUP_ACKNOWLEDGE */
|
|
|
|
|
/* send DISCONNECT in general */
|
|
|
|
|
if (c->peercallstate != Q931_CALL_STATE_NULL && c->peercallstate != Q931_CALL_STATE_DISCONNECT_REQUEST && c->peercallstate != Q931_CALL_STATE_DISCONNECT_INDICATION && c->peercallstate != Q931_CALL_STATE_RELEASE_REQUEST && c->peercallstate != Q931_CALL_STATE_RESTART_REQUEST && c->peercallstate != Q931_CALL_STATE_RESTART) {
|
|
|
|
|
if (disconnect)
|
|
|
|
|
q931_disconnect(pri,c,cause);
|
|
|
|
|
else if (release_compl)
|
|
|
|
|
q931_release_complete(pri,c,cause);
|
|
|
|
|
else
|
|
|
|
|
q931_release(pri,c,cause);
|
|
|
|
|
} else
|
|
|
|
|
pri_error("Wierd, doing nothing but this shouldn't happen, ourstate %s, peerstate %s\n",callstate2str(c->ourcallstate),callstate2str(c->peercallstate));
|
|
|
|
|
break;
|
|
|
|
|
case Q931_CALL_STATE_DISCONNECT_REQUEST:
|
|
|
|
|
/* sent DISCONNECT */
|
|
|
|
|
break;
|
|
|
|
|
case Q931_CALL_STATE_DISCONNECT_INDICATION:
|
|
|
|
|
/* received DISCONNECT */
|
|
|
|
|
if (c->peercallstate == Q931_CALL_STATE_DISCONNECT_REQUEST)
|
|
|
|
|
q931_release(pri,c,cause);
|
|
|
|
|
case Q931_CALL_STATE_RELEASE_REQUEST:
|
|
|
|
|
/* sent RELEASE */
|
|
|
|
|
/* don't do anything, waiting for RELEASE_COMPLETE */
|
|
|
|
|
break;
|
|
|
|
|
case Q931_CALL_STATE_RESTART:
|
|
|
|
|
case Q931_CALL_STATE_RESTART_REQUEST:
|
|
|
|
|
/* sent RESTART */
|
|
|
|
|
pri_error("q931_hangup shouldn't be called in this state, ourstate %s, peerstate %s\n",callstate2str(c->ourcallstate),callstate2str(c->peercallstate));
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
pri_error("We're not yet handling hanging up when our state is %d, contact support@digium.com, ourstate %s, peerstate %s\n",callstate2str(c->ourcallstate),callstate2str(c->peercallstate));
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
/* we did handle hangup properly at this point */
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int q931_receive(struct pri *pri, q931_h *h, int len)
|
|
|
|
|
{
|
|
|
|
|
@@ -1772,34 +1891,28 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
|
|
|
|
|
strcpy(c->redirectingnum, "");
|
|
|
|
|
c->useruserprotocoldisc = -1;
|
|
|
|
|
strcpy(c->useruserinfo, "");
|
|
|
|
|
c->ourcallstate = Q931_CALL_STATE_CALL_INITIATED;
|
|
|
|
|
c->complete = 0;
|
|
|
|
|
break;
|
|
|
|
|
case Q931_CONNECT:
|
|
|
|
|
c->ourcallstate = Q931_CALL_STATE_ACTIVE;
|
|
|
|
|
case Q931_ALERTING:
|
|
|
|
|
case Q931_PROGRESS:
|
|
|
|
|
c->progress = -1;
|
|
|
|
|
break;
|
|
|
|
|
case Q931_CALL_PROCEEDING:
|
|
|
|
|
case Q931_CONNECT_ACKNOWLEDGE:
|
|
|
|
|
c->ourcallstate = Q931_CALL_STATE_ACTIVE;
|
|
|
|
|
/* Do nothing */
|
|
|
|
|
break;
|
|
|
|
|
case Q931_RELEASE:
|
|
|
|
|
c->ourcallstate = Q931_CALL_STATE_NULL;
|
|
|
|
|
case Q931_DISCONNECT:
|
|
|
|
|
c->cause = -1;
|
|
|
|
|
c->causecode = -1;
|
|
|
|
|
c->causeloc = -1;
|
|
|
|
|
c->ourcallstate = Q931_CALL_STATE_NULL;
|
|
|
|
|
break;
|
|
|
|
|
case Q931_RELEASE_COMPLETE:
|
|
|
|
|
c->ourcallstate = Q931_CALL_STATE_NULL;
|
|
|
|
|
case Q931_STATUS:
|
|
|
|
|
c->cause = -1;
|
|
|
|
|
c->causecode = -1;
|
|
|
|
|
c->causeloc = -1;
|
|
|
|
|
c->callstate = -1;
|
|
|
|
|
break;
|
|
|
|
|
case Q931_RESTART_ACKNOWLEDGE:
|
|
|
|
|
c->channelno = -1;
|
|
|
|
|
@@ -1850,7 +1963,8 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
|
|
|
|
|
/* Post handling */
|
|
|
|
|
switch(mh->msg) {
|
|
|
|
|
case Q931_RESTART:
|
|
|
|
|
c->ourcallstate = Q931_CALL_STATE_RESTART_REQUEST;
|
|
|
|
|
c->ourcallstate = Q931_CALL_STATE_RESTART;
|
|
|
|
|
c->peercallstate = Q931_CALL_STATE_RESTART_REQUEST;
|
|
|
|
|
/* Send back the Restart Acknowledge */
|
|
|
|
|
restart_ack(pri, c);
|
|
|
|
|
/* Notify user of restart event */
|
|
|
|
|
@@ -1859,7 +1973,9 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
|
|
|
|
|
return Q931_RES_HAVEEVENT;
|
|
|
|
|
case Q931_SETUP:
|
|
|
|
|
c->ourcallstate = Q931_CALL_STATE_CALL_PRESENT;
|
|
|
|
|
c->alive = 1;
|
|
|
|
|
c->peercallstate = Q931_CALL_STATE_CALL_INITIATED;
|
|
|
|
|
/* it's not yet a call since higher level can respond with RELEASE or RELEASE_COMPLETE */
|
|
|
|
|
c->alive = 0;
|
|
|
|
|
pri->ev.e = PRI_EVENT_RING;
|
|
|
|
|
pri->ev.ring.channel = c->channelno;
|
|
|
|
|
pri->ev.ring.callingpres = c->callerpres;
|
|
|
|
|
@@ -1874,6 +1990,7 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
|
|
|
|
|
pri->ev.ring.cref = c->cr;
|
|
|
|
|
pri->ev.ring.call = c;
|
|
|
|
|
pri->ev.ring.layer1 = c->userl1;
|
|
|
|
|
pri->ev.ring.complete = c->complete;
|
|
|
|
|
if (c->transmoderate != TRANS_MODE_64_CIRCUIT) {
|
|
|
|
|
q931_release(pri, c, PRI_CAUSE_BEARERCAPABILITY_NOTIMPL);
|
|
|
|
|
break;
|
|
|
|
|
@@ -1881,6 +1998,7 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
|
|
|
|
|
return Q931_RES_HAVEEVENT;
|
|
|
|
|
case Q931_ALERTING:
|
|
|
|
|
c->ourcallstate = Q931_CALL_STATE_CALL_DELIVERED;
|
|
|
|
|
c->peercallstate = Q931_CALL_STATE_CALL_RECEIVED;
|
|
|
|
|
pri->ev.e = PRI_EVENT_RINGING;
|
|
|
|
|
pri->ev.ringing.channel = c->channelno;
|
|
|
|
|
pri->ev.ringing.cref = c->cr;
|
|
|
|
|
@@ -1888,6 +2006,7 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
|
|
|
|
|
return Q931_RES_HAVEEVENT;
|
|
|
|
|
case Q931_CONNECT:
|
|
|
|
|
c->ourcallstate = Q931_CALL_STATE_ACTIVE;
|
|
|
|
|
c->peercallstate = Q931_CALL_STATE_CONNECT_REQUEST;
|
|
|
|
|
pri->ev.e = PRI_EVENT_ANSWER;
|
|
|
|
|
pri->ev.answer.channel = c->channelno;
|
|
|
|
|
pri->ev.answer.cref = c->cr;
|
|
|
|
|
@@ -1906,73 +2025,84 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
|
|
|
|
|
#endif
|
|
|
|
|
return Q931_RES_HAVEEVENT;
|
|
|
|
|
case Q931_PROGRESS:
|
|
|
|
|
case Q931_CALL_PROCEEDING:
|
|
|
|
|
pri->ev.e = PRI_EVENT_PROCEEDING;
|
|
|
|
|
pri->ev.proceeding.channel = c->channelno;
|
|
|
|
|
c->ourcallstate = Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING;
|
|
|
|
|
c->peercallstate = Q931_CALL_STATE_INCOMING_CALL_PROCEEDING;
|
|
|
|
|
return Q931_RES_HAVEEVENT;
|
|
|
|
|
case Q931_CONNECT_ACKNOWLEDGE:
|
|
|
|
|
c->ourcallstate = Q931_CALL_STATE_ACTIVE;
|
|
|
|
|
c->peercallstate = Q931_CALL_STATE_ACTIVE;
|
|
|
|
|
break;
|
|
|
|
|
case Q931_STATUS:
|
|
|
|
|
/* Do nothing */
|
|
|
|
|
/* FIXME if the callstate != ourcallstate send RELEASE */
|
|
|
|
|
if ((pri->debug & PRI_DEBUG_Q931_ANOMALY) &&
|
|
|
|
|
(c->cause != PRI_CAUSE_INTERWORKING))
|
|
|
|
|
pri_error("Received unsolicited status: %s\n", pri_cause2str(c->cause));
|
|
|
|
|
break;
|
|
|
|
|
case Q931_CALL_PROCEEDING:
|
|
|
|
|
c->ourcallstate = Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING;
|
|
|
|
|
break;
|
|
|
|
|
case Q931_RELEASE_COMPLETE:
|
|
|
|
|
c->ourcallstate = Q931_CALL_STATE_NULL;
|
|
|
|
|
c->peercallstate = Q931_CALL_STATE_NULL;
|
|
|
|
|
pri->ev.hangup.channel = c->channelno;
|
|
|
|
|
pri->ev.hangup.cref = c->cr;
|
|
|
|
|
pri->ev.hangup.cause = c->cause;
|
|
|
|
|
pri->ev.hangup.call = c;
|
|
|
|
|
/* Free resources */
|
|
|
|
|
if (c->alive) {
|
|
|
|
|
pri->ev.e = PRI_EVENT_HANGUP;
|
|
|
|
|
pri->ev.hangup.channel = c->channelno;
|
|
|
|
|
pri->ev.hangup.cref = c->cr;
|
|
|
|
|
pri->ev.hangup.cause = c->cause;
|
|
|
|
|
pri->ev.hangup.call = c;
|
|
|
|
|
res = Q931_RES_HAVEEVENT;
|
|
|
|
|
c->alive = 0;
|
|
|
|
|
} else if (c->sendhangupack) {
|
|
|
|
|
res = Q931_RES_HAVEEVENT;
|
|
|
|
|
pri->ev.e = PRI_EVENT_HANGUP_ACK;
|
|
|
|
|
pri_hangup(pri, c, c->cause);
|
|
|
|
|
} else
|
|
|
|
|
res = 0;
|
|
|
|
|
q931_destroycall(pri, c->cr);
|
|
|
|
|
if (res)
|
|
|
|
|
return res;
|
|
|
|
|
else
|
|
|
|
|
q931_hangup(pri,c,c->cause);
|
|
|
|
|
break;
|
|
|
|
|
case Q931_RELEASE:
|
|
|
|
|
c->ourcallstate = Q931_CALL_STATE_NULL;
|
|
|
|
|
c->peercallstate = Q931_CALL_STATE_RELEASE_REQUEST;
|
|
|
|
|
pri->ev.e = PRI_EVENT_HANGUP;
|
|
|
|
|
pri->ev.hangup.channel = c->channelno;
|
|
|
|
|
pri->ev.hangup.cref = c->cr;
|
|
|
|
|
pri->ev.hangup.cause = c->cause;
|
|
|
|
|
pri->ev.hangup.call = c;
|
|
|
|
|
if (c->alive)
|
|
|
|
|
res = Q931_RES_HAVEEVENT;
|
|
|
|
|
else if (c->sendhangupack) {
|
|
|
|
|
res = Q931_RES_HAVEEVENT;
|
|
|
|
|
pri->ev.e = PRI_EVENT_HANGUP_ACK;
|
|
|
|
|
} else
|
|
|
|
|
res = 0;
|
|
|
|
|
q931_release_complete(pri, c);
|
|
|
|
|
/* Free resources */
|
|
|
|
|
q931_destroycall(pri, c->cr);
|
|
|
|
|
if (res)
|
|
|
|
|
return res;
|
|
|
|
|
break;
|
|
|
|
|
return Q931_RES_HAVEEVENT;
|
|
|
|
|
case Q931_DISCONNECT:
|
|
|
|
|
c->ourcallstate = Q931_CALL_STATE_DISCONNECT_INDICATION;
|
|
|
|
|
c->peercallstate = Q931_CALL_STATE_DISCONNECT_REQUEST;
|
|
|
|
|
c->sendhangupack = 1;
|
|
|
|
|
/* Return such an event */
|
|
|
|
|
pri->ev.e = PRI_EVENT_HANGUP;
|
|
|
|
|
pri->ev.e = PRI_EVENT_HANGUP_REQ;
|
|
|
|
|
pri->ev.hangup.channel = c->channelno;
|
|
|
|
|
pri->ev.hangup.cref = c->cr;
|
|
|
|
|
pri->ev.hangup.cause = c->cause;
|
|
|
|
|
pri->ev.hangup.call = c;
|
|
|
|
|
#if 0 /* Require the user app to call release */
|
|
|
|
|
/* Send a release with no cause */
|
|
|
|
|
q931_release(pri, c, -1);
|
|
|
|
|
return Q931_RES_HAVEEVENT;
|
|
|
|
|
#endif
|
|
|
|
|
if (c->alive)
|
|
|
|
|
return Q931_RES_HAVEEVENT;
|
|
|
|
|
else
|
|
|
|
|
q931_hangup(pri,c,c->cause);
|
|
|
|
|
break;
|
|
|
|
|
case Q931_RESTART_ACKNOWLEDGE:
|
|
|
|
|
c->ourcallstate = Q931_CALL_STATE_NULL;
|
|
|
|
|
c->peercallstate = Q931_CALL_STATE_NULL;
|
|
|
|
|
pri->ev.e = PRI_EVENT_RESTART_ACK;
|
|
|
|
|
pri->ev.restartack.channel = c->channelno;
|
|
|
|
|
return Q931_RES_HAVEEVENT;
|
|
|
|
|
case Q931_INFORMATION:
|
|
|
|
|
/* XXX We're handling only INFORMATION messages that contain
|
|
|
|
|
overlap dialing received digit
|
|
|
|
|
+ the "Complete" msg which is basically an EOF on further digits
|
|
|
|
|
XXX */
|
|
|
|
|
if (c->ourcallstate!=Q931_CALL_STATE_OVERLAP_RECEIVING)
|
|
|
|
|
break;
|
|
|
|
|
@@ -1980,13 +2110,17 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
|
|
|
|
|
pri->ev.ring.call = c;
|
|
|
|
|
pri->ev.ring.channel = c->channelno;
|
|
|
|
|
strncpy(pri->ev.ring.callednum, c->callednum, sizeof(pri->ev.ring.callednum) - 1);
|
|
|
|
|
pri->ev.ring.complete = c->complete; /* this covers IE 33 (Sending Complete) */
|
|
|
|
|
return Q931_RES_HAVEEVENT;
|
|
|
|
|
case Q931_STATUS_ENQUIRY:
|
|
|
|
|
q931_status(pri,c);
|
|
|
|
|
break;
|
|
|
|
|
case Q931_SETUP_ACKNOWLEDGE:
|
|
|
|
|
c->ourcallstate = Q931_CALL_STATE_OVERLAP_SENDING;
|
|
|
|
|
break;
|
|
|
|
|
c->peercallstate = Q931_CALL_STATE_OVERLAP_RECEIVING;
|
|
|
|
|
pri->ev.e = PRI_EVENT_SETUP_ACK;
|
|
|
|
|
pri->ev.setup_ack.channel = c->channelno;
|
|
|
|
|
return Q931_RES_HAVEEVENT;
|
|
|
|
|
case Q931_USER_INFORMATION:
|
|
|
|
|
case Q931_SEGMENT:
|
|
|
|
|
case Q931_CONGESTION_CONTROL:
|
|
|
|
|
|