Add service maintenance message support
This adds support for two new message types: Service and Service Acknowledge. When a channel receives a service message it will either take the channel in or out of service and then send a service acknowledgment. Although not enforced here (enforced in chan_dahdi), the service messages are only supported with switch types 4ess/5ess. The required Asterisk changes will be coming next. (issue #3450) Reported by: cmaj git-svn-id: https://origsvn.digium.com/svn/libpri/branches/1.4@732 2fbb986a-6c06-0410-b554-c9c1f0a7f128
This commit is contained in:
22
libpri.h
22
libpri.h
@@ -81,6 +81,8 @@
|
||||
#define PRI_EVENT_NOTIFY 16 /* Notification received (NOTIFY) */
|
||||
#define PRI_EVENT_PROGRESS 17 /* When we get PROGRESS */
|
||||
#define PRI_EVENT_KEYPAD_DIGIT 18 /* When we receive during ACTIVE state (INFORMATION) */
|
||||
#define PRI_EVENT_SERVICE 19 /* SERVICE maintenance message */
|
||||
#define PRI_EVENT_SERVICE_ACK 20 /* SERVICE maintenance acknowledgement message */
|
||||
|
||||
/* Simple states */
|
||||
#define PRI_STATE_DOWN 0
|
||||
@@ -430,6 +432,18 @@ typedef struct pri_event_keypad_digit {
|
||||
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 */
|
||||
@@ -445,6 +459,8 @@ typedef union {
|
||||
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; /* service message */
|
||||
pri_event_service_ack service_ack; /* service acknowledgement message */
|
||||
} pri_event;
|
||||
|
||||
struct pri;
|
||||
@@ -556,6 +572,9 @@ int pri_restart(struct pri *pri);
|
||||
|
||||
int pri_reset(struct pri *pri, int channel);
|
||||
|
||||
/* handle b-channel maintenance messages */
|
||||
extern int pri_maintenance_service(struct pri *pri, int span, int channel, int changestatus);
|
||||
|
||||
/* Create a new call */
|
||||
q931_call *pri_new_call(struct pri *pri);
|
||||
|
||||
@@ -601,6 +620,9 @@ int pri_mwi_activate(struct pri *pri, q931_call *c, char *caller, int callerplan
|
||||
/* Send an MWI deactivate request to a remote location */
|
||||
int pri_mwi_deactivate(struct pri *pri, q931_call *c, char *caller, int callerplan, char *callername, int callerpres, char *called, int calledplan);
|
||||
|
||||
/* Set service message support flag */
|
||||
int pri_set_service_message_support(struct pri *pri, int supportflag);
|
||||
|
||||
#define PRI_2BCT
|
||||
/* Attempt to pass the channels back to the NET side if compatable and
|
||||
* suscribed. Sometimes called 2 bchannel transfer (2BCT) */
|
||||
|
||||
17
pri.c
17
pri.c
@@ -110,6 +110,15 @@ int pri_get_timer(struct pri *pri, int timer)
|
||||
return pri->timers[timer];
|
||||
}
|
||||
|
||||
int pri_set_service_message_support(struct pri *pri, int supportflag)
|
||||
{
|
||||
if (!pri) {
|
||||
return -1;
|
||||
}
|
||||
pri->service_message_support = supportflag;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pri_timer2idx(char *timer)
|
||||
{
|
||||
if (!strcasecmp(timer, "N200"))
|
||||
@@ -630,6 +639,14 @@ int pri_reset(struct pri *pri, int channel)
|
||||
return q931_restart(pri, channel);
|
||||
}
|
||||
|
||||
int pri_maintenance_service(struct pri *pri, int span, int channel, int changestatus)
|
||||
{
|
||||
if (!pri) {
|
||||
return -1;
|
||||
}
|
||||
return maintenance_service(pri, span, channel, changestatus);
|
||||
}
|
||||
|
||||
q931_call *pri_new_call(struct pri *pri)
|
||||
{
|
||||
if (!pri)
|
||||
|
||||
@@ -114,6 +114,9 @@ struct pri {
|
||||
/* do we do overlap dialing */
|
||||
int overlapdial;
|
||||
|
||||
/* do we support SERVICE messages */
|
||||
int service_message_support;
|
||||
|
||||
/* do not skip channel 16 */
|
||||
int chan_mapping_logical;
|
||||
|
||||
@@ -264,6 +267,8 @@ struct q931_call {
|
||||
|
||||
/* Bridged call info */
|
||||
q931_call *bridged_call; /* Pointer to other leg of bridged call */
|
||||
|
||||
int changestatus; /* SERVICE message changestatus */
|
||||
};
|
||||
|
||||
extern int pri_schedule_event(struct pri *pri, int ms, void (*function)(void *data), void *data);
|
||||
|
||||
@@ -192,4 +192,8 @@ extern pri_event *q921_receive(struct pri *pri, q921_h *h, int len);
|
||||
|
||||
extern int q921_transmit_iframe(struct pri *pri, void *buf, int len, int cr);
|
||||
|
||||
extern pri_event *q921_dchannel_up(struct pri *pri);
|
||||
|
||||
extern pri_event *q921_dchannel_down(struct pri *pri);
|
||||
|
||||
#endif
|
||||
|
||||
12
pri_q931.h
12
pri_q931.h
@@ -113,6 +113,8 @@ typedef struct q931_ie {
|
||||
|
||||
#define Q931_PROTOCOL_DISCRIMINATOR 0x08
|
||||
#define GR303_PROTOCOL_DISCRIMINATOR 0x4f
|
||||
#define MAINTENANCE_PROTOCOL_DISCRIMINATOR_1 0x03
|
||||
#define MAINTENANCE_PROTOCOL_DISCRIMINATOR_2 0x43
|
||||
|
||||
/* Q.931 / National ISDN Message Types */
|
||||
|
||||
@@ -160,6 +162,12 @@ typedef struct q931_ie {
|
||||
#define NATIONAL_SERVICE 0x0f
|
||||
#define NATIONAL_SERVICE_ACKNOWLEDGE 0x07
|
||||
|
||||
#define SERVICE_CHANGE_STATUS_INSERVICE 0
|
||||
#define SERVICE_CHANGE_STATUS_LOOPBACK 1 /* not supported */
|
||||
#define SERVICE_CHANGE_STATUS_OUTOFSERVICE 2
|
||||
#define SERVICE_CHANGE_STATUS_REQCONTINUITYCHECK 3 /* not supported */
|
||||
#define SERVICE_CHANGE_STATUS_SHUTDOWN 4 /* not supported */
|
||||
|
||||
/* Special codeset 0 IE */
|
||||
#define NATIONAL_CHANGE_STATUS 0x1
|
||||
|
||||
@@ -248,6 +256,10 @@ typedef struct q931_ie {
|
||||
/* EuroISDN */
|
||||
#define Q931_SENDING_COMPLETE 0xa1
|
||||
|
||||
extern int maintenance_service(struct pri *pri, int span, int channel, int changestatus);
|
||||
|
||||
extern int maintenance_service_ack(struct pri *pri, q931_call *call);
|
||||
|
||||
|
||||
/* Q.SIG specific */
|
||||
#define QSIG_IE_TRANSIT_COUNT 0x31
|
||||
|
||||
5
q921.c
5
q921.c
@@ -248,7 +248,6 @@ static int q921_ack_packet(struct pri *pri, int num)
|
||||
|
||||
static void t203_expire(void *);
|
||||
static void t200_expire(void *);
|
||||
static pri_event *q921_dchannel_down(struct pri *pri);
|
||||
|
||||
static void reschedule_t200(struct pri *pri)
|
||||
{
|
||||
@@ -785,7 +784,7 @@ void q921_dump(struct pri *pri, q921_h *h, int len, int showraw, int txrx)
|
||||
}
|
||||
}
|
||||
|
||||
static pri_event *q921_dchannel_up(struct pri *pri)
|
||||
pri_event *q921_dchannel_up(struct pri *pri)
|
||||
{
|
||||
/* Stop any SABME retransmissions */
|
||||
if (pri->sabme_timer) {
|
||||
@@ -814,7 +813,7 @@ static pri_event *q921_dchannel_up(struct pri *pri)
|
||||
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);
|
||||
|
||||
288
q931.c
288
q931.c
@@ -89,11 +89,14 @@ static struct msgtype msgs[] = {
|
||||
{ Q931_SUSPEND, "SUSPEND" },
|
||||
{ Q931_SUSPEND_ACKNOWLEDGE, "SUSPEND ACKNOWLEDGE" },
|
||||
{ Q931_SUSPEND_REJECT, "SUSPEND REJECT" },
|
||||
|
||||
/* Maintenance */
|
||||
{ NATIONAL_SERVICE, "SERVICE" },
|
||||
{ NATIONAL_SERVICE_ACKNOWLEDGE, "SERVICE ACKNOWLEDGE" },
|
||||
};
|
||||
static int post_handle_q931_message(struct pri *pri, struct q931_mh *mh, struct q931_call *c, int missingmand);
|
||||
|
||||
struct msgtype maintenance_msgs[] = {
|
||||
{ NATIONAL_SERVICE, "SERVICE", { Q931_CHANNEL_IDENT } },
|
||||
{ NATIONAL_SERVICE_ACKNOWLEDGE, "SERVICE ACKNOWLEDGE", { Q931_CHANNEL_IDENT } },
|
||||
};
|
||||
static int post_handle_maintenance_message(struct pri *pri, struct q931_mh *mh, struct q931_call *c);
|
||||
|
||||
static struct msgtype causes[] = {
|
||||
{ PRI_CAUSE_UNALLOCATED, "Unallocated (unassigned) number" },
|
||||
@@ -258,6 +261,20 @@ static char *code2str(int code, struct msgtype *codes, int max)
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
static char *pritype(int type)
|
||||
{
|
||||
switch (type) {
|
||||
case PRI_CPE:
|
||||
return "CPE";
|
||||
break;
|
||||
case PRI_NETWORK:
|
||||
return "NET";
|
||||
break;
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
static void call_init(struct q931_call *c)
|
||||
{
|
||||
c->forceinvert = -1;
|
||||
@@ -458,8 +475,8 @@ static FUNC_DUMP(dump_channel_id)
|
||||
if (!(ie->data[pos] & 0x10)) {
|
||||
/* Number specified */
|
||||
pos++;
|
||||
pri_message(pri, "%c Ext: %d Channel: %d ]\n", prefix, (ie->data[pos] & 0x80) >> 7,
|
||||
(ie->data[pos]) & 0x7f);
|
||||
pri_message(pri, "%c Ext: %d Channel: %d Type: %s]\n", prefix, (ie->data[pos] & 0x80) >> 7,
|
||||
(ie->data[pos]) & 0x7f, pritype(pri->localtype));
|
||||
} else {
|
||||
pos++;
|
||||
/* Map specified */
|
||||
@@ -1180,6 +1197,29 @@ static FUNC_SEND(transmit_user_user)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static FUNC_DUMP(dump_change_status)
|
||||
{
|
||||
int x;
|
||||
|
||||
pri_message(pri, "%c Change Status Information (len=%2d) [", prefix, len);
|
||||
for (x=0; x<ie->len; 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[] = {
|
||||
@@ -2143,7 +2183,7 @@ static FUNC_DUMP(dump_transit_count)
|
||||
|
||||
static struct ie ies[] = {
|
||||
/* Codeset 0 - Common */
|
||||
{ 1, NATIONAL_CHANGE_STATUS, "Change Status" },
|
||||
{ 1, NATIONAL_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 },
|
||||
@@ -2187,7 +2227,7 @@ static struct ie ies[] = {
|
||||
{ 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_CHANGE_STATUS, "Change Status", dump_change_status, receive_change_status, transmit_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 },
|
||||
@@ -2273,6 +2313,16 @@ static char *msg2str(int msg)
|
||||
return "Unknown Message Type";
|
||||
}
|
||||
|
||||
static char *maintenance_msg2str(int msg)
|
||||
{
|
||||
unsigned int x;
|
||||
for (x=0; x<sizeof(maintenance_msgs)/sizeof(maintenance_msgs[0]); x++) {
|
||||
if (maintenance_msgs[x].msgnum == msg)
|
||||
return maintenance_msgs[x].name;
|
||||
}
|
||||
return "Unknown Message Type";
|
||||
}
|
||||
|
||||
static inline int q931_cr(q931_h *h)
|
||||
{
|
||||
int cr = 0;
|
||||
@@ -2525,7 +2575,11 @@ void q931_dump(struct pri *pri, q931_h *h, int len, int txrx)
|
||||
pri_message(pri, "%c Call Ref: len=%2d (reference %d/0x%X) (%s)\n", c, h->crlen, 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);
|
||||
if ((h->pd == MAINTENANCE_PROTOCOL_DISCRIMINATOR_1) || (h->pd == MAINTENANCE_PROTOCOL_DISCRIMINATOR_2)) {
|
||||
pri_message(pri, "%c Message Type: %s (%d)\n", c, maintenance_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;
|
||||
@@ -2571,12 +2625,16 @@ static int q931_handle_ie(int codeset, struct pri *pri, q931_call *c, int msg, q
|
||||
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;
|
||||
h->pd = pri->protodisc;
|
||||
if (protodisc) {
|
||||
h->pd = protodisc;
|
||||
} else {
|
||||
h->pd = pri->protodisc;
|
||||
}
|
||||
h->x0 = 0; /* Reserved 0 */
|
||||
if (!pri->bri) {
|
||||
h->crlen = 2; /* Two bytes of Call Reference. Invert the top bit to make it from our sense */
|
||||
@@ -2639,8 +2697,8 @@ static int send_message(struct pri *pri, q931_call *c, int msgtype, int ies[])
|
||||
|
||||
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) {
|
||||
@@ -2662,6 +2720,30 @@ static int send_message(struct pri *pri, q931_call *c, int msgtype, int ies[])
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int maintenance_service_ies[] = { Q931_IE_CHANGE_STATUS, Q931_CHANNEL_IDENT, -1 };
|
||||
|
||||
int maintenance_service_ack(struct pri *pri, q931_call *c)
|
||||
{
|
||||
return send_message(pri, c, (MAINTENANCE_PROTOCOL_DISCRIMINATOR_1 << 8) | NATIONAL_SERVICE_ACKNOWLEDGE, maintenance_service_ies);
|
||||
}
|
||||
|
||||
int maintenance_service(struct pri *pri, int span, int channel, int changestatus)
|
||||
{
|
||||
struct q931_call *c;
|
||||
c = q931_getcall(pri, 0x8000, 0);
|
||||
if (!c) {
|
||||
return -1;
|
||||
}
|
||||
if (channel > -1) {
|
||||
channel &= 0xff;
|
||||
}
|
||||
c->ds1no = span;
|
||||
c->channelno = channel;
|
||||
c->chanflags |= FLAG_EXCLUSIVE;
|
||||
c->changestatus = changestatus;
|
||||
return send_message(pri, c, (MAINTENANCE_PROTOCOL_DISCRIMINATOR_1 << 8) | NATIONAL_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)
|
||||
@@ -3266,45 +3348,36 @@ int q931_hangup(struct pri *pri, q931_call *c, int cause)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int q931_receive(struct pri *pri, q931_h *h, int len)
|
||||
static int prepare_to_handle_maintenance_message(struct pri *pri, q931_mh *mh, q931_call *c)
|
||||
{
|
||||
q931_mh *mh;
|
||||
q931_call *c;
|
||||
q931_ie *ie;
|
||||
unsigned int x;
|
||||
int y;
|
||||
int res;
|
||||
int r;
|
||||
int mandies[MAX_MAND_IES];
|
||||
int missingmand;
|
||||
int codeset, cur_codeset;
|
||||
int last_ie[8];
|
||||
struct apdu_event *cur = NULL;
|
||||
|
||||
memset(last_ie, 0, sizeof(last_ie));
|
||||
if (pri->debug & PRI_DEBUG_Q931_DUMP)
|
||||
q931_dump(pri, h, len, 0);
|
||||
#ifdef LIBPRI_COUNTERS
|
||||
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) {
|
||||
pri_error(pri, "Warning: unknown/inappropriate protocol discriminator received (%02x/%d)\n", h->pd, h->pd);
|
||||
return 0;
|
||||
}
|
||||
c = q931_getcall(pri, q931_cr(h), 0);
|
||||
if (!c) {
|
||||
pri_error(pri, "Unable to locate call %d\n", q931_cr(h));
|
||||
if ((!pri) || (!mh) || (!c)) {
|
||||
return -1;
|
||||
}
|
||||
/* Preliminary handling */
|
||||
/* 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 NATIONAL_SERVICE:
|
||||
case NATIONAL_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", maintenance_msg2str(mh->msg), mh->msg);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int prepare_to_handle_q931_message(struct pri *pri, q931_mh *mh, q931_call *c)
|
||||
{
|
||||
if ((!pri) || (!mh) || (!c)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch(mh->msg) {
|
||||
case Q931_RESTART:
|
||||
if (pri->debug & PRI_DEBUG_Q931_STATE)
|
||||
@@ -3433,6 +3506,57 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
|
||||
q931_destroycall(pri,c->cr);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int q931_receive(struct pri *pri, q931_h *h, int len)
|
||||
{
|
||||
q931_mh *mh;
|
||||
q931_call *c;
|
||||
q931_ie *ie;
|
||||
unsigned int x;
|
||||
int y;
|
||||
int res;
|
||||
int r;
|
||||
int mandies[MAX_MAND_IES];
|
||||
int missingmand;
|
||||
int codeset, cur_codeset;
|
||||
int last_ie[8];
|
||||
|
||||
memset(last_ie, 0, sizeof(last_ie));
|
||||
if (pri->debug & PRI_DEBUG_Q931_DUMP)
|
||||
q931_dump(pri, h, len, 0);
|
||||
#ifdef LIBPRI_COUNTERS
|
||||
pri->q931_rxcount++;
|
||||
#endif
|
||||
mh = (q931_mh *)(h->contents + h->crlen);
|
||||
if ((h->pd != pri->protodisc) && (h->pd != MAINTENANCE_PROTOCOL_DISCRIMINATOR_1) && (h->pd != MAINTENANCE_PROTOCOL_DISCRIMINATOR_2)) {
|
||||
pri_error(pri, "Warning: unknown/inappropriate protocol discriminator received (%02x/%d)\n", h->pd, h->pd);
|
||||
return 0;
|
||||
}
|
||||
if (((h->pd == MAINTENANCE_PROTOCOL_DISCRIMINATOR_1) || (h->pd == MAINTENANCE_PROTOCOL_DISCRIMINATOR_2)) && (!pri->service_message_support)) {
|
||||
/* Real service message support has not been enabled (and is OFF in libpri by default),
|
||||
* so we have to revert to the 'traditional' KLUDGE of changing byte 4 from a 0xf (SERVICE)
|
||||
* to a 0x7 (SERVICE ACKNOWLEDGE) */
|
||||
/* 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;
|
||||
}
|
||||
c = q931_getcall(pri, q931_cr(h), 0);
|
||||
if (!c) {
|
||||
pri_error(pri, "Unable to locate call %d\n", q931_cr(h));
|
||||
return -1;
|
||||
}
|
||||
/* Preliminary handling */
|
||||
if ((h->pd == MAINTENANCE_PROTOCOL_DISCRIMINATOR_1) || (h->pd == MAINTENANCE_PROTOCOL_DISCRIMINATOR_2)) {
|
||||
prepare_to_handle_maintenance_message(pri, mh, c);
|
||||
} else {
|
||||
prepare_to_handle_q931_message(pri, mh, c);
|
||||
}
|
||||
|
||||
/* Handle IEs */
|
||||
memset(mandies, 0, sizeof(mandies));
|
||||
missingmand = 0;
|
||||
@@ -3521,6 +3645,72 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
|
||||
}
|
||||
|
||||
/* Post handling */
|
||||
if ((h->pd == MAINTENANCE_PROTOCOL_DISCRIMINATOR_1) || (h->pd == MAINTENANCE_PROTOCOL_DISCRIMINATOR_2)) {
|
||||
res = post_handle_maintenance_message(pri, mh, c);
|
||||
} else {
|
||||
res = post_handle_q931_message(pri, mh, c, missingmand);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static int post_handle_maintenance_message(struct pri *pri, struct q931_mh *mh, struct q931_call *c)
|
||||
{
|
||||
/* Do some maintenance stuff */
|
||||
switch (mh->msg) {
|
||||
case NATIONAL_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 SERVICE_CHANGE_STATUS_INSERVICE:
|
||||
pri->ev.e = PRI_EVENT_DCHAN_UP;
|
||||
q921_dchannel_up(pri);
|
||||
break;
|
||||
case SERVICE_CHANGE_STATUS_OUTOFSERVICE:
|
||||
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;
|
||||
}
|
||||
}
|
||||
maintenance_service_ack(pri, c);
|
||||
return Q931_RES_HAVEEVENT;
|
||||
case NATIONAL_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 SERVICE_CHANGE_STATUS_INSERVICE:
|
||||
pri->ev.e = PRI_EVENT_DCHAN_UP;
|
||||
q921_dchannel_up(pri);
|
||||
break;
|
||||
case SERVICE_CHANGE_STATUS_OUTOFSERVICE:
|
||||
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;
|
||||
}
|
||||
}
|
||||
return Q931_RES_HAVEEVENT;
|
||||
default:
|
||||
pri_error(pri, "!! Don't know how to post-handle maintenance message type %s (%d)\n", maintenance_msg2str(mh->msg), mh->msg);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int post_handle_q931_message(struct pri *pri, struct q931_mh *mh, struct q931_call *c, int missingmand)
|
||||
{
|
||||
int res;
|
||||
struct apdu_event *cur = NULL;
|
||||
|
||||
switch(mh->msg) {
|
||||
case Q931_RESTART:
|
||||
if (missingmand) {
|
||||
|
||||
Reference in New Issue
Block a user