Index: pri_q921.h =================================================================== --- pri_q921.h (revision 376) +++ pri_q921.h (working copy) @@ -172,4 +172,8 @@ extern int q921_transmit_iframe(struct pri *pri, void *buf, int len, int cr); +extern pri_event *q921_dchannel_up(struct pri *pri); + +extern pri_event *q921_dchannel_down(struct pri *pri); + #endif Index: pri_q931.h =================================================================== --- pri_q931.h (revision 376) +++ pri_q931.h (working copy) @@ -108,6 +108,8 @@ #define Q931_PROTOCOL_DISCRIMINATOR 0x08 #define GR303_PROTOCOL_DISCRIMINATOR 0x4f +#define NFAS_MAINTENANCE_PROTOCOL_DISCRIMINATOR 0x3 +#define NFAS_MAINTENANCE_PROTOCOL_DISCRIMINATOR_TOO 0x43 /* Q.931 / National ISDN Message Types */ @@ -151,13 +153,10 @@ #define Q931_SUSPEND_ACKNOWLEDGE 0x2d #define Q931_SUSPEND_REJECT 0x21 -/* Maintenance messages (codeset 0 only) */ -#define NATIONAL_SERVICE 0x0f -#define NATIONAL_SERVICE_ACKNOWLEDGE 0x07 +/* Maintenance messages (codeset 0) */ +#define NFAS_MAINTENANCE_SERVICE 0x0f +#define NFAS_MAINTENANCE_SERVICE_ACKNOWLEDGE 0x07 -/* Special codeset 0 IE */ -#define NATIONAL_CHANGE_STATUS 0x1 - /* Q.931 / National ISDN Information Elements */ #define Q931_LOCKING_SHIFT 0x90 #define Q931_NON_LOCKING_SHIFT 0x98 @@ -218,6 +217,13 @@ #define Q931_IE_USER_USER 0x7E #define Q931_IE_ESCAPE_FOR_EXT 0x7F +/* For maintenance service */ +#define NFAS_IE_CHANGE_STATUS 0x01 +#define NFAS_CHANGE_STATUS_IN_SERVICE 0 +#define NFAS_CHANGE_STATUS_LOOP_BACK 1 +#define NFAS_CHANGE_STATUS_OUT_OF_SERVICE 2 +#define NFAS_CHANGE_STATUS_REQ_CONTINUITY_CHECK 3 +#define NFAS_CHANGE_STATUS_GRACEFUL_SHUTDOWN 4 /* Call state stuff */ #define Q931_CALL_STATE_NULL 0 @@ -243,7 +249,11 @@ /* EuroISDN */ #define Q931_SENDING_COMPLETE 0xa1 +extern int nfas_maintenance_service(struct pri *pri, int span, int channel, int changestatus); +extern int nfas_maintenance_service_ack(struct pri *pri, q931_call *call); + + /* Q.SIG specific */ #define QSIG_IE_TRANSIT_COUNT 0x31 Index: libpri.h =================================================================== --- libpri.h (revision 376) +++ libpri.h (working copy) @@ -76,7 +76,10 @@ #define PRI_EVENT_NOTIFY 16 /* Notification received */ #define PRI_EVENT_PROGRESS 17 /* When we get CALL_PROCEEDING or PROGRESS */ #define PRI_EVENT_KEYPAD_DIGIT 18 /* When we receive during ACTIVE state */ +#define PRI_EVENT_SERVICE 19 /* NFAS Maintenance */ +#define PRI_EVENT_SERVICE_ACK 20 /* NFAS Maintenance */ + /* Simple states */ #define PRI_STATE_DOWN 0 #define PRI_STATE_UP 1 @@ -377,6 +380,18 @@ char digits[64]; } pri_event_keypad_digit; +typedef struct pri_event_service { + int e; + int channel; + int changestatus; +} pri_event_service; + +typedef struct pri_event_service_ack { + int e; + int channel; + int changestatus; +} pri_event_service_ack; + typedef union { int e; pri_event_generic gen; /* Generic view */ @@ -392,6 +407,8 @@ pri_event_setup_ack setup_ack; /* SETUP_ACKNOWLEDGE structure */ pri_event_notify notify; /* Notification */ pri_event_keypad_digit digit; /* Digits that come during a call */ + pri_event_service service; /* NFAS Maintenance */ + pri_event_service_ack service_ack; /* NFAS Maintenance */ } pri_event; struct pri; @@ -502,6 +519,9 @@ extern int pri_reset(struct pri *pri, int channel); +/* Handle NFAS maintenance messages for putting B-Channels and D-Channels in and out of service */ +extern int pri_maintenance_service(struct pri *pri, int span, int channel, int changestatus); + /* Create a new call */ extern q931_call *pri_new_call(struct pri *pri); Index: pri.c =================================================================== --- pri.c (revision 376) +++ pri.c (working copy) @@ -564,6 +564,13 @@ return q931_restart(pri, channel); } +int pri_maintenance_service(struct pri *pri, int span, int channel, int changestatus) +{ + if (!pri) + return -1; + return nfas_maintenance_service(pri, span, channel, changestatus); +} + q931_call *pri_new_call(struct pri *pri) { if (!pri) Index: pri_internal.h =================================================================== --- pri_internal.h (revision 376) +++ pri_internal.h (working copy) @@ -246,6 +246,8 @@ int transferable; unsigned int rlt_call_id; /* RLT call id */ + + int changestatus; /* NFAS Maintenance service related */ }; extern int pri_schedule_event(struct pri *pri, int ms, void (*function)(void *data), void *data); Index: q921.c =================================================================== --- q921.c (revision 376) +++ q921.c (working copy) @@ -202,7 +202,6 @@ static void t203_expire(void *); static void t200_expire(void *); -static pri_event *q921_dchannel_down(struct pri *pri); static void reschedule_t203(struct pri *pri) { @@ -647,7 +646,7 @@ }; } -static pri_event *q921_dchannel_up(struct pri *pri) +pri_event *q921_dchannel_up(struct pri *pri) { /* Reset counters, etc */ q921_reset(pri); @@ -675,7 +674,7 @@ return &pri->ev; } -static pri_event *q921_dchannel_down(struct pri *pri) +pri_event *q921_dchannel_down(struct pri *pri) { /* Reset counters, reset sabme timer etc */ q921_reset(pri); Index: q931.c =================================================================== --- q931.c (revision 376) +++ q931.c (working copy) @@ -84,10 +84,12 @@ { Q931_SUSPEND, "SUSPEND" }, { Q931_SUSPEND_ACKNOWLEDGE, "SUSPEND ACKNOWLEDGE" }, { Q931_SUSPEND_REJECT, "SUSPEND REJECT" }, +}; +struct msgtype nfas_msgs[] = { /* Maintenance */ - { NATIONAL_SERVICE, "SERVICE" }, - { NATIONAL_SERVICE_ACKNOWLEDGE, "SERVICE ACKNOWLEDGE" }, + { NFAS_MAINTENANCE_SERVICE, "SERVICE", { Q931_CHANNEL_IDENT } }, + { NFAS_MAINTENANCE_SERVICE_ACKNOWLEDGE, "SERVICE ACKNOWLEDGE", { Q931_CHANNEL_IDENT } }, }; static struct msgtype causes[] = { @@ -1005,6 +1007,27 @@ return 0; } +static FUNC_DUMP(dump_change_status) +{ + int x; + pri_message(pri, "%c Change Status Information (len=%2d) [", prefix, len); + for (x=0;xlen;x++) + pri_message(pri, " %02x", ie->data[x] & 0x7f); + pri_message(pri, " ]\n"); +} + +static FUNC_RECV(receive_change_status) +{ + call->changestatus = ie->data[0] & 0x0f; + return 0; +} + +static FUNC_SEND(transmit_change_status) +{ + ie->data[0] = 0xc0 | call->changestatus; + return 3; +} + static char *prog2str(int prog) { static struct msgtype progs[] = { @@ -1968,7 +1991,7 @@ static struct ie ies[] = { /* Codeset 0 - Common */ - { 1, NATIONAL_CHANGE_STATUS, "Change Status" }, + { 1, NFAS_IE_CHANGE_STATUS, "Change Status", dump_change_status, receive_change_status, transmit_change_status }, { 0, Q931_LOCKING_SHIFT, "Locking Shift", dump_shift }, { 0, Q931_BEARER_CAPABILITY, "Bearer Capability", dump_bearer_capability, receive_bearer_capability, transmit_bearer_capability }, { 0, Q931_CAUSE, "Cause", dump_cause, receive_cause, transmit_cause }, @@ -2012,7 +2035,6 @@ { 1, Q931_IE_USER_USER, "User-User", dump_user_user, receive_user_user, transmit_user_user }, { 1, Q931_IE_ESCAPE_FOR_EXT, "Escape for Extension" }, { 1, Q931_IE_CALL_STATUS, "Call Status" }, - { 1, Q931_IE_CHANGE_STATUS, "Change Status" }, { 1, Q931_IE_CONNECTED_ADDR, "Connected Number", dump_connected_number }, { 1, Q931_IE_CONNECTED_NUM, "Connected Number", dump_connected_number }, { 1, Q931_IE_ORIGINAL_CALLED_NUMBER, "Original Called Number", dump_redirecting_number, receive_redirecting_number, transmit_redirecting_number }, @@ -2026,7 +2048,7 @@ { 1, Q931_IE_FACILITY | Q931_CODESET(6), "Facility", dump_facility, receive_facility, transmit_facility }, { 1, Q931_DISPLAY | Q931_CODESET(6), "Display (CS6)", dump_display, receive_display, transmit_display }, { 0, Q931_IE_GENERIC_DIGITS, "Generic Digits", dump_generic_digits, receive_generic_digits, transmit_generic_digits }, - /* Codeset 7 */ + /* Codeset 7 - User specific */ }; static char *ie2str(int ie) @@ -2098,6 +2120,15 @@ return "Unknown Message Type"; } +static char *nfas_msg2str(int msg) +{ + unsigned int x; + for (x=0;xcrlen, q931_cr(h) & 0x7FFF, q931_cr(h) & 0x7FFF, (h->crv[0] & 0x80) ? "Terminator" : "Originator"); /* Message header begins at the end of the call reference number */ mh = (q931_mh *)(h->contents + h->crlen); - pri_message(pri, "%c Message type: %s (%d)\n", c, msg2str(mh->msg), mh->msg); + /* Might be an NFAS message */ + if ((h->pd == NFAS_MAINTENANCE_PROTOCOL_DISCRIMINATOR) || (h->pd == NFAS_MAINTENANCE_PROTOCOL_DISCRIMINATOR_TOO)) + pri_message(pri, "%c Message type: %s (%d)\n", c, nfas_msg2str(mh->msg), mh->msg); + else + pri_message(pri, "%c Message type: %s (%d)\n", c, msg2str(mh->msg), mh->msg); /* Drop length of header, including call reference */ len -= (h->crlen + 3); codeset = cur_codeset = 0; @@ -2370,12 +2405,15 @@ return -1; } -static void init_header(struct pri *pri, q931_call *call, unsigned char *buf, q931_h **hb, q931_mh **mhb, int *len) +static void init_header(struct pri *pri, q931_call *call, unsigned char *buf, q931_h **hb, q931_mh **mhb, int *len, int protodisc) { /* Returns header and message header and modifies length in place */ q931_h *h = (q931_h *)buf; q931_mh * mh = (q931_mh *)(h->contents + 2); - h->pd = pri->protodisc; + if (protodisc) + h->pd = protodisc; + else + h->pd = pri->protodisc; h->x0 = 0; /* Reserved 0 */ h->crlen = 2; /* Two bytes of Call Reference. Invert the top bit to make it from our sense */ if (call->cr || call->forceinvert) { @@ -2424,8 +2462,8 @@ memset(buf, 0, sizeof(buf)); len = sizeof(buf); - init_header(pri, c, buf, &h, &mh, &len); - mh->msg = msgtype; + init_header(pri, c, buf, &h, &mh, &len, (msgtype >> 8)); + mh->msg = msgtype & 0x00ff; x=0; codeset = 0; while(ies[x] > -1) { @@ -2447,6 +2485,30 @@ return 0; } +static int maintenance_service_ies[] = { NFAS_IE_CHANGE_STATUS, Q931_CHANNEL_IDENT, -1 }; + +int nfas_maintenance_service_ack(struct pri *pri, q931_call *c) +{ + return send_message(pri, c, (NFAS_MAINTENANCE_PROTOCOL_DISCRIMINATOR << 8) | NFAS_MAINTENANCE_SERVICE_ACKNOWLEDGE, maintenance_service_ies); +} + +int nfas_maintenance_service(struct pri *pri, int span, int channel, int changestatus) +{ + struct q931_call *c; + c = q931_getcall(pri, 0 | 0x8000); + if (!c) + return -1; + if (channel > -1) { + channel &= 0xff; + } + pri_message(pri, "SPANSPAN %d\n", span); + c->ds1no = span; + c->channelno = channel; + c->chanflags &= FLAG_EXCLUSIVE; + c->changestatus = changestatus; + return send_message(pri, c, (NFAS_MAINTENANCE_PROTOCOL_DISCRIMINATOR << 8) | NFAS_MAINTENANCE_SERVICE, maintenance_service_ies); +} + static int status_ies[] = { Q931_CAUSE, Q931_CALL_STATE, -1 }; static int q931_status(struct pri *pri, q931_call *c, int cause) @@ -3031,14 +3093,7 @@ pri->q931_rxcount++; #endif mh = (q931_mh *)(h->contents + h->crlen); - if ((h->pd == 0x3) || (h->pd == 0x43)) { - /* This is the weird maintenance stuff. We majorly - KLUDGE this by changing byte 4 from a 0xf (SERVICE) - to a 0x7 (SERVICE ACKNOWLEDGE) */ - h->raw[h->crlen + 2] -= 0x8; - q931_xmit(pri, h, len, 1); - return 0; - } else if (h->pd != pri->protodisc) { + if ((h->pd != pri->protodisc) && (h->pd != NFAS_MAINTENANCE_PROTOCOL_DISCRIMINATOR) && (h->pd != NFAS_MAINTENANCE_PROTOCOL_DISCRIMINATOR_TOO)) { pri_error(pri, "Warning: unknown/inappropriate protocol discriminator received (%02x/%d)\n", h->pd, h->pd); return 0; } @@ -3048,133 +3103,154 @@ return -1; } /* Preliminary handling */ - switch(mh->msg) { - case Q931_RESTART: - if (pri->debug & PRI_DEBUG_Q931_STATE) - pri_message(pri, "-- Processing Q.931 Restart\n"); - /* Reset information */ - c->channelno = -1; - c->slotmap = -1; - c->chanflags = 0; - c->ds1no = 0; - c->ri = -1; - break; - case Q931_FACILITY: - c->callername[0] = '\0'; - break; - case Q931_SETUP: - if (pri->debug & PRI_DEBUG_Q931_STATE) - pri_message(pri, "-- Processing Q.931 Call Setup\n"); - c->channelno = -1; - c->slotmap = -1; - c->chanflags = 0; - c->ds1no = 0; - c->ri = -1; - c->transcapability = -1; - c->transmoderate = -1; - c->transmultiple = -1; - c->userl1 = -1; - c->userl2 = -1; - c->userl3 = -1; - c->rateadaption = -1; - c->calledplan = -1; - c->callerplan = -1; - c->callerpres = -1; - c->callernum[0] = '\0'; - c->callednum[0] = '\0'; - c->callername[0] = '\0'; - c->callerani[0] = '\0'; - c->callerplanani = -1; - c->redirectingplan = -1; - c->redirectingpres = -1; - c->redirectingreason = -1; - c->origcalledplan = -1; - c->origcalledpres = -1; - c->origredirectingreason = -1; - c->redirectingnum[0] = '\0'; - c->origcallednum[0] = '\0'; - c->redirectingname[0] = '\0'; - c->origcalledname[0] = '\0'; - c->useruserprotocoldisc = -1; - c->useruserinfo[0] = '\0'; - c->complete = 0; - c->nonisdn = 0; - c->aoc_units = -1; - /* Fall through */ - case Q931_CONNECT: - case Q931_ALERTING: - case Q931_PROGRESS: - c->useruserinfo[0] = '\0'; - c->cause = -1; - /* Fall through */ - case Q931_CALL_PROCEEDING: - c->progress = -1; - c->progressmask = 0; - break; - case Q931_CONNECT_ACKNOWLEDGE: - if (c->retranstimer) - pri_schedule_del(pri, c->retranstimer); - c->retranstimer = 0; - break; - case Q931_RELEASE: - case Q931_DISCONNECT: - c->cause = -1; - c->causecode = -1; - c->causeloc = -1; - c->aoc_units = -1; - if (c->retranstimer) - pri_schedule_del(pri, c->retranstimer); - c->retranstimer = 0; - c->useruserinfo[0] = '\0'; - break; - case Q931_RELEASE_COMPLETE: - if (c->retranstimer) - pri_schedule_del(pri, c->retranstimer); - c->retranstimer = 0; - c->useruserinfo[0] = '\0'; - /* Fall through */ - case Q931_STATUS: - c->cause = -1; - c->causecode = -1; - c->causeloc = -1; - c->sugcallstate = -1; - c->aoc_units = -1; - break; - case Q931_RESTART_ACKNOWLEDGE: - c->channelno = -1; - break; - case Q931_INFORMATION: - c->callednum[0] = '\0'; - break; - case Q931_STATUS_ENQUIRY: - break; - case Q931_SETUP_ACKNOWLEDGE: - break; - case Q931_NOTIFY: - break; - case Q931_USER_INFORMATION: - case Q931_SEGMENT: - case Q931_CONGESTION_CONTROL: - case Q931_HOLD: - case Q931_HOLD_ACKNOWLEDGE: - case Q931_HOLD_REJECT: - case Q931_RETRIEVE: - case Q931_RETRIEVE_ACKNOWLEDGE: - case Q931_RETRIEVE_REJECT: - case Q931_RESUME: - case Q931_RESUME_ACKNOWLEDGE: - case Q931_RESUME_REJECT: - case Q931_SUSPEND: - case Q931_SUSPEND_ACKNOWLEDGE: - case Q931_SUSPEND_REJECT: - pri_error(pri, "!! Not yet handling pre-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg); - /* Fall through */ - default: - pri_error(pri, "!! Don't know how to pre-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg); - q931_status(pri,c, PRI_CAUSE_MESSAGE_TYPE_NONEXIST); - if (c->newcall) - q931_destroycall(pri,c->cr); - return -1; + if (h->pd != pri->protodisc) { + /* Service messages are a superset of messages that can + * take B-channels or entire D-channels in and out of service */ + switch(mh->msg) { + case NFAS_MAINTENANCE_SERVICE: + case NFAS_MAINTENANCE_SERVICE_ACKNOWLEDGE: + c->channelno = -1; + c->slotmap = -1; + c->chanflags = 0; + c->ds1no = 0; + c->ri = -1; + c->changestatus = -1; + break; + default: + pri_error(pri, "!! Don't know how to pre-handle maintenance message type %s (%d)\n", nfas_msg2str(mh->msg), mh->msg); + return -1; + break; + } + } else { + /* All other messages*/ + switch(mh->msg) { + case Q931_RESTART: + if (pri->debug & PRI_DEBUG_Q931_STATE) + pri_message(pri, "-- Processing Q.931 Restart\n"); + /* Reset information */ + c->channelno = -1; + c->slotmap = -1; + c->chanflags = 0; + c->ds1no = 0; + c->ri = -1; + break; + case Q931_FACILITY: + c->callername[0] = '\0'; + break; + case Q931_SETUP: + if (pri->debug & PRI_DEBUG_Q931_STATE) + pri_message(pri, "-- Processing Q.931 Call Setup\n"); + c->channelno = -1; + c->slotmap = -1; + c->chanflags = 0; + c->ds1no = 0; + c->ri = -1; + c->transcapability = -1; + c->transmoderate = -1; + c->transmultiple = -1; + c->userl1 = -1; + c->userl2 = -1; + c->userl3 = -1; + c->rateadaption = -1; + c->calledplan = -1; + c->callerplan = -1; + c->callerpres = -1; + c->callernum[0] = '\0'; + c->callednum[0] = '\0'; + c->callername[0] = '\0'; + c->callerani[0] = '\0'; + c->callerplanani = -1; + c->redirectingplan = -1; + c->redirectingpres = -1; + c->redirectingreason = -1; + c->origcalledplan = -1; + c->origcalledpres = -1; + c->origredirectingreason = -1; + c->redirectingnum[0] = '\0'; + c->origcallednum[0] = '\0'; + c->redirectingname[0] = '\0'; + c->origcalledname[0] = '\0'; + c->useruserprotocoldisc = -1; + c->useruserinfo[0] = '\0'; + c->complete = 0; + c->nonisdn = 0; + c->aoc_units = -1; + /* Fall through */ + case Q931_CONNECT: + case Q931_ALERTING: + case Q931_PROGRESS: + c->useruserinfo[0] = '\0'; + c->cause = -1; + /* Fall through */ + case Q931_CALL_PROCEEDING: + c->progress = -1; + c->progressmask = 0; + break; + case Q931_CONNECT_ACKNOWLEDGE: + if (c->retranstimer) + pri_schedule_del(pri, c->retranstimer); + c->retranstimer = 0; + break; + case Q931_RELEASE: + case Q931_DISCONNECT: + c->cause = -1; + c->causecode = -1; + c->causeloc = -1; + c->aoc_units = -1; + if (c->retranstimer) + pri_schedule_del(pri, c->retranstimer); + c->retranstimer = 0; + c->useruserinfo[0] = '\0'; + break; + case Q931_RELEASE_COMPLETE: + if (c->retranstimer) + pri_schedule_del(pri, c->retranstimer); + c->retranstimer = 0; + c->useruserinfo[0] = '\0'; + /* Fall through */ + case Q931_STATUS: + c->cause = -1; + c->causecode = -1; + c->causeloc = -1; + c->sugcallstate = -1; + c->aoc_units = -1; + break; + case Q931_RESTART_ACKNOWLEDGE: + c->channelno = -1; + break; + case Q931_INFORMATION: + c->callednum[0] = '\0'; + break; + case Q931_STATUS_ENQUIRY: + break; + case Q931_SETUP_ACKNOWLEDGE: + break; + case Q931_NOTIFY: + break; + case Q931_USER_INFORMATION: + case Q931_SEGMENT: + case Q931_CONGESTION_CONTROL: + case Q931_HOLD: + case Q931_HOLD_ACKNOWLEDGE: + case Q931_HOLD_REJECT: + case Q931_RETRIEVE: + case Q931_RETRIEVE_ACKNOWLEDGE: + case Q931_RETRIEVE_REJECT: + case Q931_RESUME: + case Q931_RESUME_ACKNOWLEDGE: + case Q931_RESUME_REJECT: + case Q931_SUSPEND: + case Q931_SUSPEND_ACKNOWLEDGE: + case Q931_SUSPEND_REJECT: + pri_error(pri, "!! Not yet handling pre-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg); + /* Fall through */ + default: + pri_error(pri, "!! Don't know how to pre-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg); + q931_status(pri,c, PRI_CAUSE_MESSAGE_TYPE_NONEXIST); + if (c->newcall) + q931_destroycall(pri,c->cr); + return -1; + } } /* Handle IEs */ memset(mandies, 0, sizeof(mandies)); @@ -3264,211 +3340,299 @@ } /* Post handling */ - switch(mh->msg) { - case Q931_RESTART: - if (missingmand) { - q931_status(pri, c, PRI_CAUSE_MANDATORY_IE_MISSING); - q931_destroycall(pri, c->cr); + if (h->pd != pri->protodisc) { + /* Do the maintenance stuff */ + switch(mh->msg) { + case NFAS_MAINTENANCE_SERVICE: + if (c->channelno > 0) { + pri->ev.e = PRI_EVENT_SERVICE; + pri->ev.service.channel = c->channelno | (c->ds1no << 8); + pri->ev.service.changestatus = 0x0f & c->changestatus; + } else { + switch (0x0f & c->changestatus) { + case NFAS_CHANGE_STATUS_IN_SERVICE: + pri->ev.e = PRI_EVENT_DCHAN_UP; + q921_dchannel_up(pri); + break; + case NFAS_CHANGE_STATUS_OUT_OF_SERVICE: + case NFAS_CHANGE_STATUS_LOOP_BACK: + case NFAS_CHANGE_STATUS_REQ_CONTINUITY_CHECK: + case NFAS_CHANGE_STATUS_GRACEFUL_SHUTDOWN: + pri->ev.e = PRI_EVENT_DCHAN_DOWN; + q921_dchannel_down(pri); + break; + default: + pri_error(pri, "!! Don't know how to handle span service change status %d\n", (0x0f & c->changestatus)); + return -1; + break; + } + } + nfas_maintenance_service_ack(pri, c); + return Q931_RES_HAVEEVENT; + case NFAS_MAINTENANCE_SERVICE_ACKNOWLEDGE: + if (c->channelno > 0) { + pri->ev.e = PRI_EVENT_SERVICE_ACK; + pri->ev.service_ack.channel = c->channelno | (c->ds1no << 8); + pri->ev.service_ack.changestatus = 0x0f & c->changestatus; + } else { + switch (0x0f & c->changestatus) { + case NFAS_CHANGE_STATUS_IN_SERVICE: + pri->ev.e = PRI_EVENT_DCHAN_UP; + q921_dchannel_up(pri); + break; + case NFAS_CHANGE_STATUS_OUT_OF_SERVICE: + case NFAS_CHANGE_STATUS_LOOP_BACK: + case NFAS_CHANGE_STATUS_REQ_CONTINUITY_CHECK: + case NFAS_CHANGE_STATUS_GRACEFUL_SHUTDOWN: + pri->ev.e = PRI_EVENT_DCHAN_DOWN; + q921_dchannel_down(pri); + break; + default: + pri_error(pri, "!! Don't know how to handle span service change status %d\n", (0x0f & c->changestatus)); + return -1; + break; + } + } + return Q931_RES_HAVEEVENT; + default: + pri_error(pri, "!! Don't know how to post-handle maintenance message type %s (%d)\n", nfas_msg2str(mh->msg), mh->msg); + return -1; break; } - UPDATE_OURCALLSTATE(pri, c, 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 */ - pri->ev.e = PRI_EVENT_RESTART; - pri->ev.restart.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); - return Q931_RES_HAVEEVENT; - case Q931_SETUP: - if (missingmand) { - q931_release_complete(pri, c, PRI_CAUSE_MANDATORY_IE_MISSING); - break; - } - /* Must be new call */ - if (!c->newcall) { - break; - } - if (c->progressmask & PRI_PROG_CALLER_NOT_ISDN) - c->nonisdn = 1; - c->newcall = 0; - UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_CALL_PRESENT); - 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; - if (c->transmoderate != TRANS_MODE_64_CIRCUIT) { - q931_release_complete(pri, c, PRI_CAUSE_BEARERCAPABILITY_NOTIMPL); - break; - } - pri->ev.e = PRI_EVENT_RING; - pri->ev.ring.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); - pri->ev.ring.callingpres = c->callerpres; - pri->ev.ring.callingplan = c->callerplan; - pri->ev.ring.callingplanani = c->callerplanani; - pri->ev.ring.callingplanrdnis = c->redirectingplan; - pri->ev.ring.callingplanorigcalled = c->origcalledplan; - pri->ev.ring.ani2 = c->ani2; - libpri_copy_string(pri->ev.ring.callingani, c->callerani, sizeof(pri->ev.ring.callingani)); - libpri_copy_string(pri->ev.ring.callingnum, c->callernum, sizeof(pri->ev.ring.callingnum)); - libpri_copy_string(pri->ev.ring.callingname, c->callername, sizeof(pri->ev.ring.callingname)); - pri->ev.ring.calledplan = c->calledplan; - libpri_copy_string(pri->ev.ring.callingsubaddr, c->callingsubaddr, sizeof(pri->ev.ring.callingsubaddr)); - libpri_copy_string(pri->ev.ring.callednum, c->callednum, sizeof(pri->ev.ring.callednum)); - libpri_copy_string(pri->ev.ring.origcalledname, c->origcalledname, sizeof(pri->ev.ring.origcalledname)); - libpri_copy_string(pri->ev.ring.origcallednum, c->origcallednum, sizeof(pri->ev.ring.origcallednum)); - libpri_copy_string(pri->ev.ring.redirectingnum, c->redirectingnum, sizeof(pri->ev.ring.redirectingnum)); - libpri_copy_string(pri->ev.ring.redirectingname, c->redirectingname, sizeof(pri->ev.ring.redirectingname)); - libpri_copy_string(pri->ev.ring.useruserinfo, c->useruserinfo, sizeof(pri->ev.ring.useruserinfo)); - c->useruserinfo[0] = '\0'; - pri->ev.ring.redirectingreason = c->redirectingreason; - pri->ev.ring.origredirectingreason = c->origredirectingreason; - pri->ev.ring.flexible = ! (c->chanflags & FLAG_EXCLUSIVE); - pri->ev.ring.cref = c->cr; - pri->ev.ring.call = c; - pri->ev.ring.layer1 = c->userl1; - pri->ev.ring.complete = c->complete; - pri->ev.ring.ctype = c->transcapability; - pri->ev.ring.redirectingreason = c->redirectingreason; - pri->ev.ring.progress = c->progress; - pri->ev.ring.progressmask = c->progressmask; - return Q931_RES_HAVEEVENT; - case Q931_ALERTING: - if (c->newcall) { - q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE); - break; - } - UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_CALL_DELIVERED); - c->peercallstate = Q931_CALL_STATE_CALL_RECEIVED; - pri->ev.e = PRI_EVENT_RINGING; - pri->ev.ringing.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); - pri->ev.ringing.cref = c->cr; - pri->ev.ringing.call = c; - pri->ev.ringing.progress = c->progress; - pri->ev.ringing.progressmask = c->progressmask; - libpri_copy_string(pri->ev.ringing.useruserinfo, c->useruserinfo, sizeof(pri->ev.ringing.useruserinfo)); - c->useruserinfo[0] = '\0'; - return Q931_RES_HAVEEVENT; - case Q931_CONNECT: - if (c->newcall) { - q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE); - break; - } - if (c->ourcallstate == Q931_CALL_STATE_ACTIVE) { - q931_status(pri, c, PRI_CAUSE_WRONG_MESSAGE); - break; - } - UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_ACTIVE); - c->peercallstate = Q931_CALL_STATE_CONNECT_REQUEST; - pri->ev.e = PRI_EVENT_ANSWER; - pri->ev.answer.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); - pri->ev.answer.cref = c->cr; - pri->ev.answer.call = c; - pri->ev.answer.progress = c->progress; - pri->ev.answer.progressmask = c->progressmask; - libpri_copy_string(pri->ev.answer.useruserinfo, c->useruserinfo, sizeof(pri->ev.answer.useruserinfo)); - c->useruserinfo[0] = '\0'; - q931_connect_acknowledge(pri, c); - if (c->justsignalling) { /* Make sure WE release when we initiatie a signalling only connection */ - q931_release(pri, c, PRI_CAUSE_NORMAL_CLEARING); - break; - } else + } else { + /* Do the non-maintenance stuff */ + switch(mh->msg) { + case Q931_RESTART: + if (missingmand) { + q931_status(pri, c, PRI_CAUSE_MANDATORY_IE_MISSING); + q931_destroycall(pri, c->cr); + break; + } + UPDATE_OURCALLSTATE(pri, c, 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 */ + pri->ev.e = PRI_EVENT_RESTART; + pri->ev.restart.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); return Q931_RES_HAVEEVENT; - case Q931_FACILITY: - if (c->newcall) { - q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE); - break; - } - pri->ev.e = PRI_EVENT_FACNAME; - libpri_copy_string(pri->ev.facname.callingname, c->callername, sizeof(pri->ev.facname.callingname)); - libpri_copy_string(pri->ev.facname.callingnum, c->callernum, sizeof(pri->ev.facname.callingnum)); - pri->ev.facname.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); - pri->ev.facname.cref = c->cr; - pri->ev.facname.call = c; + case Q931_SETUP: + if (missingmand) { + q931_release_complete(pri, c, PRI_CAUSE_MANDATORY_IE_MISSING); + break; + } + /* Must be new call */ + if (!c->newcall) { + break; + } + if (c->progressmask & PRI_PROG_CALLER_NOT_ISDN) + c->nonisdn = 1; + c->newcall = 0; + UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_CALL_PRESENT); + 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; + if (c->transmoderate != TRANS_MODE_64_CIRCUIT) { + q931_release_complete(pri, c, PRI_CAUSE_BEARERCAPABILITY_NOTIMPL); + break; + } + pri->ev.e = PRI_EVENT_RING; + pri->ev.ring.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); + pri->ev.ring.callingpres = c->callerpres; + pri->ev.ring.callingplan = c->callerplan; + pri->ev.ring.callingplanani = c->callerplanani; + pri->ev.ring.callingplanrdnis = c->redirectingplan; + pri->ev.ring.callingplanorigcalled = c->origcalledplan; + pri->ev.ring.ani2 = c->ani2; + libpri_copy_string(pri->ev.ring.callingani, c->callerani, sizeof(pri->ev.ring.callingani)); + libpri_copy_string(pri->ev.ring.callingnum, c->callernum, sizeof(pri->ev.ring.callingnum)); + libpri_copy_string(pri->ev.ring.callingname, c->callername, sizeof(pri->ev.ring.callingname)); + pri->ev.ring.calledplan = c->calledplan; + libpri_copy_string(pri->ev.ring.callingsubaddr, c->callingsubaddr, sizeof(pri->ev.ring.callingsubaddr)); + libpri_copy_string(pri->ev.ring.callednum, c->callednum, sizeof(pri->ev.ring.callednum)); + libpri_copy_string(pri->ev.ring.origcalledname, c->origcalledname, sizeof(pri->ev.ring.origcalledname)); + libpri_copy_string(pri->ev.ring.origcallednum, c->origcallednum, sizeof(pri->ev.ring.origcallednum)); + libpri_copy_string(pri->ev.ring.redirectingnum, c->redirectingnum, sizeof(pri->ev.ring.redirectingnum)); + libpri_copy_string(pri->ev.ring.redirectingname, c->redirectingname, sizeof(pri->ev.ring.redirectingname)); + libpri_copy_string(pri->ev.ring.useruserinfo, c->useruserinfo, sizeof(pri->ev.ring.useruserinfo)); + c->useruserinfo[0] = '\0'; + pri->ev.ring.redirectingreason = c->redirectingreason; + pri->ev.ring.origredirectingreason = c->origredirectingreason; + pri->ev.ring.flexible = ! (c->chanflags & FLAG_EXCLUSIVE); + pri->ev.ring.cref = c->cr; + pri->ev.ring.call = c; + pri->ev.ring.layer1 = c->userl1; + pri->ev.ring.complete = c->complete; + pri->ev.ring.ctype = c->transcapability; + pri->ev.ring.redirectingreason = c->redirectingreason; + pri->ev.ring.progress = c->progress; + pri->ev.ring.progressmask = c->progressmask; + return Q931_RES_HAVEEVENT; + case Q931_ALERTING: + if (c->newcall) { + q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE); + break; + } + UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_CALL_DELIVERED); + c->peercallstate = Q931_CALL_STATE_CALL_RECEIVED; + pri->ev.e = PRI_EVENT_RINGING; + pri->ev.ringing.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); + pri->ev.ringing.cref = c->cr; + pri->ev.ringing.call = c; + pri->ev.ringing.progress = c->progress; + pri->ev.ringing.progressmask = c->progressmask; + libpri_copy_string(pri->ev.ringing.useruserinfo, c->useruserinfo, sizeof(pri->ev.ringing.useruserinfo)); + c->useruserinfo[0] = '\0'; + return Q931_RES_HAVEEVENT; + case Q931_CONNECT: + if (c->newcall) { + q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE); + break; + } + if (c->ourcallstate == Q931_CALL_STATE_ACTIVE) { + q931_status(pri, c, PRI_CAUSE_WRONG_MESSAGE); + break; + } + UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_ACTIVE); + c->peercallstate = Q931_CALL_STATE_CONNECT_REQUEST; + pri->ev.e = PRI_EVENT_ANSWER; + pri->ev.answer.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); + pri->ev.answer.cref = c->cr; + pri->ev.answer.call = c; + pri->ev.answer.progress = c->progress; + pri->ev.answer.progressmask = c->progressmask; + libpri_copy_string(pri->ev.answer.useruserinfo, c->useruserinfo, sizeof(pri->ev.answer.useruserinfo)); + c->useruserinfo[0] = '\0'; + q931_connect_acknowledge(pri, c); + if (c->justsignalling) { /* Make sure WE release when we initiatie a signalling only connection */ + q931_release(pri, c, PRI_CAUSE_NORMAL_CLEARING); + break; + } else + return Q931_RES_HAVEEVENT; + case Q931_FACILITY: + if (c->newcall) { + q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE); + break; + } + pri->ev.e = PRI_EVENT_FACNAME; + libpri_copy_string(pri->ev.facname.callingname, c->callername, sizeof(pri->ev.facname.callingname)); + libpri_copy_string(pri->ev.facname.callingnum, c->callernum, sizeof(pri->ev.facname.callingnum)); + pri->ev.facname.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); + pri->ev.facname.cref = c->cr; + pri->ev.facname.call = c; #if 0 - pri_message(pri, "Sending facility event (%s/%s)\n", pri->ev.facname.callingname, pri->ev.facname.callingnum); + pri_message(pri, "Sending facility event (%s/%s)\n", pri->ev.facname.callingname, pri->ev.facname.callingnum); #endif - return Q931_RES_HAVEEVENT; - case Q931_PROGRESS: - if (missingmand) { - q931_status(pri, c, PRI_CAUSE_MANDATORY_IE_MISSING); - q931_destroycall(pri, c->cr); + return Q931_RES_HAVEEVENT; + case Q931_PROGRESS: + if (missingmand) { + q931_status(pri, c, PRI_CAUSE_MANDATORY_IE_MISSING); + q931_destroycall(pri, c->cr); + break; + } + pri->ev.e = PRI_EVENT_PROGRESS; + pri->ev.proceeding.cause = c->cause; + /* Fall through */ + case Q931_CALL_PROCEEDING: + if (c->newcall) { + q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE); + break; + } + if ((c->ourcallstate != Q931_CALL_STATE_CALL_INITIATED) && + (c->ourcallstate != Q931_CALL_STATE_OVERLAP_SENDING) && + (c->ourcallstate != Q931_CALL_STATE_CALL_DELIVERED) && + (c->ourcallstate != Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING)) { + q931_status(pri,c,PRI_CAUSE_WRONG_MESSAGE); + break; + } + pri->ev.proceeding.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); + if (mh->msg == Q931_CALL_PROCEEDING) { + pri->ev.e = PRI_EVENT_PROCEEDING; + UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING); + c->peercallstate = Q931_CALL_STATE_INCOMING_CALL_PROCEEDING; + } + pri->ev.proceeding.progress = c->progress; + pri->ev.proceeding.progressmask = c->progressmask; + pri->ev.proceeding.cref = c->cr; + pri->ev.proceeding.call = c; + + cur = c->apdus; + while (cur) { + if (!cur->sent && cur->message == Q931_FACILITY) { + q931_facility(pri, c); + break; + } + cur = cur->next; + } + return Q931_RES_HAVEEVENT; + case Q931_CONNECT_ACKNOWLEDGE: + if (c->newcall) { + q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE); + break; + } + if (!(c->ourcallstate == Q931_CALL_STATE_CONNECT_REQUEST) && + !(c->ourcallstate == Q931_CALL_STATE_ACTIVE && + (pri->localtype == PRI_NETWORK || pri->switchtype == PRI_SWITCH_QSIG))) { + q931_status(pri,c,PRI_CAUSE_WRONG_MESSAGE); + break; + } + UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_ACTIVE); + c->peercallstate = Q931_CALL_STATE_ACTIVE; break; - } - pri->ev.e = PRI_EVENT_PROGRESS; - pri->ev.proceeding.cause = c->cause; - /* Fall through */ - case Q931_CALL_PROCEEDING: - if (c->newcall) { - q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE); - break; - } - if ((c->ourcallstate != Q931_CALL_STATE_CALL_INITIATED) && - (c->ourcallstate != Q931_CALL_STATE_OVERLAP_SENDING) && - (c->ourcallstate != Q931_CALL_STATE_CALL_DELIVERED) && - (c->ourcallstate != Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING)) { - q931_status(pri,c,PRI_CAUSE_WRONG_MESSAGE); - break; - } - pri->ev.proceeding.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); - if (mh->msg == Q931_CALL_PROCEEDING) { - pri->ev.e = PRI_EVENT_PROCEEDING; - UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING); - c->peercallstate = Q931_CALL_STATE_INCOMING_CALL_PROCEEDING; - } - pri->ev.proceeding.progress = c->progress; - pri->ev.proceeding.progressmask = c->progressmask; - pri->ev.proceeding.cref = c->cr; - pri->ev.proceeding.call = c; - - cur = c->apdus; - while (cur) { - if (!cur->sent && cur->message == Q931_FACILITY) { - q931_facility(pri, c); + case Q931_STATUS: + if (missingmand) { + q931_status(pri, c, PRI_CAUSE_MANDATORY_IE_MISSING); + q931_destroycall(pri, c->cr); break; } - cur = cur->next; - } - return Q931_RES_HAVEEVENT; - case Q931_CONNECT_ACKNOWLEDGE: - if (c->newcall) { - q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE); + if (c->newcall) { + if (c->cr & 0x7fff) + q931_release_complete(pri,c,PRI_CAUSE_WRONG_CALL_STATE); + break; + } + /* Do nothing */ + /* Also when the STATUS asks for the call of an unexisting reference send RELEASE_COMPL */ + if ((pri->debug & PRI_DEBUG_Q931_ANOMALY) && + (c->cause != PRI_CAUSE_INTERWORKING)) + pri_error(pri, "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 (!c->sugcallstate && (c->ourcallstate != Q931_CALL_STATE_CALL_INITIATED)) { + pri->ev.hangup.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); + pri->ev.hangup.cause = c->cause; + pri->ev.hangup.cref = c->cr; + pri->ev.hangup.call = c; + pri->ev.hangup.aoc_units = c->aoc_units; + libpri_copy_string(pri->ev.hangup.useruserinfo, c->useruserinfo, sizeof(pri->ev.hangup.useruserinfo)); + /* Free resources */ + UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_NULL); + c->peercallstate = Q931_CALL_STATE_NULL; + if (c->alive) { + pri->ev.e = PRI_EVENT_HANGUP; + res = Q931_RES_HAVEEVENT; + c->alive = 0; + } else if (c->sendhangupack) { + res = Q931_RES_HAVEEVENT; + pri->ev.e = PRI_EVENT_HANGUP_ACK; + q931_hangup(pri, c, c->cause); + } else { + q931_hangup(pri, c, c->cause); + res = 0; + } + if (res) + return res; + } break; - } - if (!(c->ourcallstate == Q931_CALL_STATE_CONNECT_REQUEST) && - !(c->ourcallstate == Q931_CALL_STATE_ACTIVE && - (pri->localtype == PRI_NETWORK || pri->switchtype == PRI_SWITCH_QSIG))) { - q931_status(pri,c,PRI_CAUSE_WRONG_MESSAGE); - break; - } - UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_ACTIVE); - c->peercallstate = Q931_CALL_STATE_ACTIVE; - break; - case Q931_STATUS: - if (missingmand) { - q931_status(pri, c, PRI_CAUSE_MANDATORY_IE_MISSING); - q931_destroycall(pri, c->cr); - break; - } - if (c->newcall) { - if (c->cr & 0x7fff) - q931_release_complete(pri,c,PRI_CAUSE_WRONG_CALL_STATE); - break; - } - /* Do nothing */ - /* Also when the STATUS asks for the call of an unexisting reference send RELEASE_COMPL */ - if ((pri->debug & PRI_DEBUG_Q931_ANOMALY) && - (c->cause != PRI_CAUSE_INTERWORKING)) - pri_error(pri, "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 (!c->sugcallstate && (c->ourcallstate != Q931_CALL_STATE_CALL_INITIATED)) { + case Q931_RELEASE_COMPLETE: + UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_NULL); + c->peercallstate = Q931_CALL_STATE_NULL; pri->ev.hangup.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); pri->ev.hangup.cause = c->cause; pri->ev.hangup.cref = c->cr; pri->ev.hangup.call = c; pri->ev.hangup.aoc_units = c->aoc_units; libpri_copy_string(pri->ev.hangup.useruserinfo, c->useruserinfo, sizeof(pri->ev.hangup.useruserinfo)); + c->useruserinfo[0] = '\0'; /* Free resources */ - UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_NULL); - c->peercallstate = Q931_CALL_STATE_NULL; if (c->alive) { pri->ev.e = PRI_EVENT_HANGUP; res = Q931_RES_HAVEEVENT; @@ -3476,180 +3640,154 @@ } else if (c->sendhangupack) { res = Q931_RES_HAVEEVENT; pri->ev.e = PRI_EVENT_HANGUP_ACK; - q931_hangup(pri, c, c->cause); - } else { - q931_hangup(pri, c, c->cause); + pri_hangup(pri, c, c->cause); + } else res = 0; - } if (res) return res; - } - break; - case Q931_RELEASE_COMPLETE: - UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_NULL); - c->peercallstate = Q931_CALL_STATE_NULL; - pri->ev.hangup.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); - pri->ev.hangup.cause = c->cause; - pri->ev.hangup.cref = c->cr; - pri->ev.hangup.call = c; - pri->ev.hangup.aoc_units = c->aoc_units; - libpri_copy_string(pri->ev.hangup.useruserinfo, c->useruserinfo, sizeof(pri->ev.hangup.useruserinfo)); - c->useruserinfo[0] = '\0'; - /* Free resources */ - if (c->alive) { + else + q931_hangup(pri,c,c->cause); + break; + case Q931_RELEASE: + if (missingmand) { + /* Force cause to be mandatory IE missing */ + c->cause = PRI_CAUSE_MANDATORY_IE_MISSING; + } + if (c->ourcallstate == Q931_CALL_STATE_RELEASE_REQUEST) + c->peercallstate = Q931_CALL_STATE_NULL; + else { + c->peercallstate = Q931_CALL_STATE_RELEASE_REQUEST; + } + UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_NULL); pri->ev.e = PRI_EVENT_HANGUP; - 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; - if (res) - return res; - else - q931_hangup(pri,c,c->cause); - break; - case Q931_RELEASE: - if (missingmand) { - /* Force cause to be mandatory IE missing */ - c->cause = PRI_CAUSE_MANDATORY_IE_MISSING; - } - if (c->ourcallstate == Q931_CALL_STATE_RELEASE_REQUEST) + pri->ev.hangup.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); + pri->ev.hangup.cause = c->cause; + pri->ev.hangup.cref = c->cr; + pri->ev.hangup.call = c; + pri->ev.hangup.aoc_units = c->aoc_units; + libpri_copy_string(pri->ev.hangup.useruserinfo, c->useruserinfo, sizeof(pri->ev.hangup.useruserinfo)); + c->useruserinfo[0] = '\0'; + /* Don't send release complete if they send us release + while we sent it, assume a NULL state */ + if (c->newcall) + q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE); + else + return Q931_RES_HAVEEVENT; + break; + case Q931_DISCONNECT: + if (missingmand) { + /* Still let user call release */ + c->cause = PRI_CAUSE_MANDATORY_IE_MISSING; + } + if (c->newcall) { + q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE); + break; + } + UPDATE_OURCALLSTATE(pri, c, 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_REQ; + pri->ev.hangup.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); + pri->ev.hangup.cause = c->cause; + pri->ev.hangup.cref = c->cr; + pri->ev.hangup.call = c; + pri->ev.hangup.aoc_units = c->aoc_units; + libpri_copy_string(pri->ev.hangup.useruserinfo, c->useruserinfo, sizeof(pri->ev.hangup.useruserinfo)); + c->useruserinfo[0] = '\0'; + if (c->alive) + return Q931_RES_HAVEEVENT; + else + q931_hangup(pri,c,c->cause); + break; + case Q931_RESTART_ACKNOWLEDGE: + UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_NULL); c->peercallstate = Q931_CALL_STATE_NULL; - else { - c->peercallstate = Q931_CALL_STATE_RELEASE_REQUEST; - } - UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_NULL); - pri->ev.e = PRI_EVENT_HANGUP; - pri->ev.hangup.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); - pri->ev.hangup.cause = c->cause; - pri->ev.hangup.cref = c->cr; - pri->ev.hangup.call = c; - pri->ev.hangup.aoc_units = c->aoc_units; - libpri_copy_string(pri->ev.hangup.useruserinfo, c->useruserinfo, sizeof(pri->ev.hangup.useruserinfo)); - c->useruserinfo[0] = '\0'; - /* Don't send release complete if they send us release - while we sent it, assume a NULL state */ - if (c->newcall) - q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE); - else + pri->ev.e = PRI_EVENT_RESTART_ACK; + pri->ev.restartack.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); return Q931_RES_HAVEEVENT; - break; - case Q931_DISCONNECT: - if (missingmand) { - /* Still let user call release */ - c->cause = PRI_CAUSE_MANDATORY_IE_MISSING; - } - if (c->newcall) { - q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE); - break; - } - UPDATE_OURCALLSTATE(pri, c, 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_REQ; - pri->ev.hangup.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); - pri->ev.hangup.cause = c->cause; - pri->ev.hangup.cref = c->cr; - pri->ev.hangup.call = c; - pri->ev.hangup.aoc_units = c->aoc_units; - libpri_copy_string(pri->ev.hangup.useruserinfo, c->useruserinfo, sizeof(pri->ev.hangup.useruserinfo)); - c->useruserinfo[0] = '\0'; - if (c->alive) + 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->newcall) { + q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE); + break; + } + if (c->ourcallstate != Q931_CALL_STATE_OVERLAP_RECEIVING) { + pri->ev.e = PRI_EVENT_KEYPAD_DIGIT; + pri->ev.digit.call = c; + pri->ev.digit.channel = c->channelno | (c->ds1no << 8); + libpri_copy_string(pri->ev.digit.digits, c->keypad_digits, sizeof(pri->ev.digit.digits)); + /* Make sure we clear it out before we return */ + c->keypad_digits[0] = '\0'; + return Q931_RES_HAVEEVENT; + } + pri->ev.e = PRI_EVENT_INFO_RECEIVED; + pri->ev.ring.call = c; + pri->ev.ring.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); + libpri_copy_string(pri->ev.ring.callednum, c->callednum, sizeof(pri->ev.ring.callednum)); + libpri_copy_string(pri->ev.ring.callingsubaddr, c->callingsubaddr, sizeof(pri->ev.ring.callingsubaddr)); + pri->ev.ring.complete = c->complete; /* this covers IE 33 (Sending Complete) */ return Q931_RES_HAVEEVENT; - else - q931_hangup(pri,c,c->cause); - break; - case Q931_RESTART_ACKNOWLEDGE: - UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_NULL); - c->peercallstate = Q931_CALL_STATE_NULL; - pri->ev.e = PRI_EVENT_RESTART_ACK; - pri->ev.restartack.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); - 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->newcall) { - q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE); + case Q931_STATUS_ENQUIRY: + if (c->newcall) { + q931_release_complete(pri, c, PRI_CAUSE_INVALID_CALL_REFERENCE); + } else + q931_status(pri,c, 0); break; - } - if (c->ourcallstate != Q931_CALL_STATE_OVERLAP_RECEIVING) { - pri->ev.e = PRI_EVENT_KEYPAD_DIGIT; - pri->ev.digit.call = c; - pri->ev.digit.channel = c->channelno | (c->ds1no << 8); - libpri_copy_string(pri->ev.digit.digits, c->keypad_digits, sizeof(pri->ev.digit.digits)); - /* Make sure we clear it out before we return */ - c->keypad_digits[0] = '\0'; - return Q931_RES_HAVEEVENT; - } - pri->ev.e = PRI_EVENT_INFO_RECEIVED; - pri->ev.ring.call = c; - pri->ev.ring.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); - libpri_copy_string(pri->ev.ring.callednum, c->callednum, sizeof(pri->ev.ring.callednum)); - libpri_copy_string(pri->ev.ring.callingsubaddr, c->callingsubaddr, sizeof(pri->ev.ring.callingsubaddr)); - pri->ev.ring.complete = c->complete; /* this covers IE 33 (Sending Complete) */ - return Q931_RES_HAVEEVENT; - case Q931_STATUS_ENQUIRY: - if (c->newcall) { - q931_release_complete(pri, c, PRI_CAUSE_INVALID_CALL_REFERENCE); - } else - q931_status(pri,c, 0); - break; - case Q931_SETUP_ACKNOWLEDGE: - if (c->newcall) { - q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE); - break; - } - UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_OVERLAP_SENDING); - c->peercallstate = Q931_CALL_STATE_OVERLAP_RECEIVING; - pri->ev.e = PRI_EVENT_SETUP_ACK; - pri->ev.setup_ack.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); - pri->ev.setup_ack.call = c; - - cur = c->apdus; - while (cur) { - if (!cur->sent && cur->message == Q931_FACILITY) { - q931_facility(pri, c); + case Q931_SETUP_ACKNOWLEDGE: + if (c->newcall) { + q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE); break; } - cur = cur->next; + UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_OVERLAP_SENDING); + c->peercallstate = Q931_CALL_STATE_OVERLAP_RECEIVING; + pri->ev.e = PRI_EVENT_SETUP_ACK; + pri->ev.setup_ack.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); + pri->ev.setup_ack.call = c; + + cur = c->apdus; + while (cur) { + if (!cur->sent && cur->message == Q931_FACILITY) { + q931_facility(pri, c); + break; + } + cur = cur->next; + } + + return Q931_RES_HAVEEVENT; + case Q931_NOTIFY: + pri->ev.e = PRI_EVENT_NOTIFY; + pri->ev.notify.channel = c->channelno; + pri->ev.notify.info = c->notify; + return Q931_RES_HAVEEVENT; + case Q931_USER_INFORMATION: + case Q931_SEGMENT: + case Q931_CONGESTION_CONTROL: + case Q931_HOLD: + case Q931_HOLD_ACKNOWLEDGE: + case Q931_HOLD_REJECT: + case Q931_RETRIEVE: + case Q931_RETRIEVE_ACKNOWLEDGE: + case Q931_RETRIEVE_REJECT: + case Q931_RESUME: + case Q931_RESUME_ACKNOWLEDGE: + case Q931_RESUME_REJECT: + case Q931_SUSPEND: + case Q931_SUSPEND_ACKNOWLEDGE: + case Q931_SUSPEND_REJECT: + pri_error(pri, "!! Not yet handling post-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg); + /* Fall through */ + default: + + pri_error(pri, "!! Don't know how to post-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg); + q931_status(pri,c, PRI_CAUSE_MESSAGE_TYPE_NONEXIST); + if (c->newcall) + q931_destroycall(pri,c->cr); + return -1; } - - return Q931_RES_HAVEEVENT; - case Q931_NOTIFY: - pri->ev.e = PRI_EVENT_NOTIFY; - pri->ev.notify.channel = c->channelno; - pri->ev.notify.info = c->notify; - return Q931_RES_HAVEEVENT; - case Q931_USER_INFORMATION: - case Q931_SEGMENT: - case Q931_CONGESTION_CONTROL: - case Q931_HOLD: - case Q931_HOLD_ACKNOWLEDGE: - case Q931_HOLD_REJECT: - case Q931_RETRIEVE: - case Q931_RETRIEVE_ACKNOWLEDGE: - case Q931_RETRIEVE_REJECT: - case Q931_RESUME: - case Q931_RESUME_ACKNOWLEDGE: - case Q931_RESUME_REJECT: - case Q931_SUSPEND: - case Q931_SUSPEND_ACKNOWLEDGE: - case Q931_SUSPEND_REJECT: - pri_error(pri, "!! Not yet handling post-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg); - /* Fall through */ - default: - - pri_error(pri, "!! Don't know how to post-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg); - q931_status(pri,c, PRI_CAUSE_MESSAGE_TYPE_NONEXIST); - if (c->newcall) - q931_destroycall(pri,c->cr); - return -1; } return 0; }