Index: libpri.h =================================================================== RCS file: /usr/cvsroot/libpri/libpri.h,v retrieving revision 1.40 diff -u -w -r1.40 libpri.h --- libpri.h 17 Jan 2005 12:58:05 -0000 1.40 +++ libpri.h 29 Jan 2005 00:19:55 -0000 @@ -73,6 +73,8 @@ #define PRI_EVENT_HANGUP_REQ 15 /* Requesting the higher layer to hangup */ #define PRI_EVENT_NOTIFY 16 /* Notification received */ #define PRI_EVENT_PROGRESS 17 /* When we get CALL_PROCEEDING or PROGRESS */ +#define PRI_EVENT_SERVICE 18 /* ANSI T1.607 Maintenance */ +#define PRI_EVENT_SERVICE_ACK 19 /* ANSI T1.607 Maintenance */ /* Simple states */ #define PRI_STATE_DOWN 0 @@ -346,6 +348,18 @@ int info; } pri_event_notify; +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 */ @@ -360,6 +374,8 @@ pri_event_proceeding proceeding; /* Call proceeding & Progress */ pri_event_setup_ack setup_ack; /* SETUP_ACKNOWLEDGE structure */ pri_event_notify notify; /* Notification */ + pri_event_service service; /* ANSI T1.607 Maintenance */ + pri_event_service_ack service_ack; /* ANSI T1.607 Maintenance */ } pri_event; struct pri; @@ -446,6 +462,9 @@ extern void pri_destroycall(struct pri *pri, q931_call *call); extern int pri_reset(struct pri *pri, int channel); + +/* Handle ANSI T1.607 maintenance messages for putting B-Channels (and eventually D-Channels) in and out of service */ +extern int pri_maintenance_service(struct pri *pri, int channel, int changestatus); /* Create a new call */ extern q931_call *pri_new_call(struct pri *pri); Index: pri.c =================================================================== RCS file: /usr/cvsroot/libpri/pri.c,v retrieving revision 1.31 diff -u -w -r1.31 pri.c --- pri.c 15 Dec 2004 20:15:28 -0000 1.31 +++ pri.c 29 Jan 2005 00:19:55 -0000 @@ -416,6 +416,13 @@ return q931_restart(pri, channel); } +int pri_maintenance_service(struct pri *pri, int channel, int changestatus) +{ + if (!pri) + return -1; + return t1607_maintenance_service(pri, channel, changestatus); +} + q931_call *pri_new_call(struct pri *pri) { if (!pri) Index: pri_internal.h =================================================================== RCS file: /usr/cvsroot/libpri/pri_internal.h,v retrieving revision 1.15 diff -u -w -r1.15 pri_internal.h --- pri_internal.h 17 Jan 2005 12:58:05 -0000 1.15 +++ pri_internal.h 29 Jan 2005 00:19:56 -0000 @@ -200,6 +200,7 @@ int useruserprotocoldisc; char useruserinfo[256]; char callingsubaddr[256]; /* Calling parties sub address */ + int changestatus; /* Maintenance service related */ }; extern int pri_schedule_event(struct pri *pri, int ms, void (*function)(void *data), void *data); Index: pri_q931.h =================================================================== RCS file: /usr/cvsroot/libpri/pri_q931.h,v retrieving revision 1.19 diff -u -w -r1.19 pri_q931.h --- pri_q931.h 5 Nov 2004 02:12:02 -0000 1.19 +++ pri_q931.h 29 Jan 2005 00:19:56 -0000 @@ -108,6 +108,8 @@ #define Q931_PROTOCOL_DISCRIMINATOR 0x08 #define GR303_PROTOCOL_DISCRIMINATOR 0x4f +#define T1607_MAINTENANCE_PROTOCOL_DISCRIMINATOR 0x3 +#define T1607_MAINTENANCE_PROTOCOL_DISCRIMINATOR_TOO 0x43 /* Q.931 / National ISDN Message Types */ @@ -151,12 +153,9 @@ #define Q931_SUSPEND_ACKNOWLEDGE 0x2d #define Q931_SUSPEND_REJECT 0x21 -/* Maintenance messages (codeset 0 only) */ -#define NATIONAL_SERVICE 0x0f -#define NATIONAL_SERVICE_ACKNOWLEDGE 0x07 - -/* Special codeset 0 IE */ -#define NATIONAL_CHANGE_STATUS 0x1 +/* Maintenance messages (codeset 0 and codeset 7) */ +#define T1607_MAINTENANCE_SERVICE 0x0f +#define T1607_MAINTENANCE_SERVICE_ACKNOWLEDGE 0x07 /* Q.931 / National ISDN Information Elements */ #define Q931_LOCKING_SHIFT 0x90 @@ -193,7 +192,6 @@ #define Q931_DISPLAY 0x28 #define Q931_IE_SEGMENTED_MSG 0x00 -#define Q931_IE_CHANGE_STATUS 0x01 #define Q931_IE_ORIGINATING_LINE_INFO (0x01 | Q931_CODESET(6)) #define Q931_IE_CONNECTED_ADDR 0x0C #define Q931_IE_CONNECTED_NUM 0x4C @@ -218,6 +216,13 @@ #define Q931_IE_USER_USER 0x7E #define Q931_IE_ESCAPE_FOR_EXT 0x7F +/* For maintenance service */ +#define T1607_IE_CHANGE_STATUS 0x05 +#define T1607_CHANGE_STATUS_IN_SERVICE 0 +#define T1607_CHANGE_STATUS_LOOP_BACK 1 +#define T1607_CHANGE_STATUS_OUT_OF_SERVICE 2 +#define T1607_CHANGE_STATUS_REQ_CONTINUITY_CHECK 3 +#define T1607_CHANGE_STATUS_GRACEFUL_SHUTDOWN 4 /* Call state stuff */ #define Q931_CALL_STATE_NULL 0 @@ -242,6 +247,10 @@ /* EuroISDN */ #define Q931_SENDING_COMPLETE 0xa1 + +extern int t1607_maintenance_service(struct pri *pri, int channel, int changestatus); + +extern int t1607_maintenance_service_ack(struct pri *pri, q931_call *call); extern int q931_receive(struct pri *pri, q931_h *h, int len); Index: q931.c =================================================================== RCS file: /usr/cvsroot/libpri/q931.c,v retrieving revision 1.112 diff -u -w -r1.112 q931.c --- q931.c 28 Jan 2005 22:11:24 -0000 1.112 +++ q931.c 29 Jan 2005 00:19:59 -0000 @@ -83,10 +83,12 @@ { Q931_SUSPEND, "SUSPEND" }, { Q931_SUSPEND_ACKNOWLEDGE, "SUSPEND ACKNOWLEDGE" }, { Q931_SUSPEND_REJECT, "SUSPEND REJECT" }, +}; +struct msgtype t1607_msgs[] = { /* Maintenance */ - { NATIONAL_SERVICE, "SERVICE" }, - { NATIONAL_SERVICE_ACKNOWLEDGE, "SERVICE ACKNOWLEDGE" }, + { T1607_MAINTENANCE_SERVICE, "SERVICE" }, + { T1607_MAINTENANCE_SERVICE_ACKNOWLEDGE, "SERVICE ACKNOWLEDGE" }, }; struct msgtype causes[] = { @@ -929,6 +931,27 @@ return 0; } +static FUNC_DUMP(dump_change_status) +{ + int x; + pri_message("%c Change Status Information (len=%2d) [", prefix, len); + for (x=0;xlen;x++) + pri_message(" %02x", ie->data[x] & 0x7f); + pri_message(" ]\n"); +} + +static FUNC_RECV(receive_change_status) +{ + call->changestatus = ie->data[0] & 0x7f; + return 0; +} + +static FUNC_SEND(transmit_change_status) +{ + ie->data[0] = 0x80 | call->changestatus; + return 3; +} + static char *prog2str(int prog) { static struct msgtype progs[] = { @@ -1768,7 +1791,7 @@ struct ie ies[] = { /* Codeset 0 - Common */ - { 1, NATIONAL_CHANGE_STATUS, "Change Status" }, + { 1, T1607_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 }, @@ -1812,7 +1835,6 @@ { 1, Q931_IE_USER_USER, "User-User", dump_user_user, receive_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 }, @@ -1824,7 +1846,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) @@ -1896,6 +1918,15 @@ return "Unknown Message Type"; } +static char *t1607_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); + /* Might be an ANSI T1.607 message */ + if ((h->pd == T1607_MAINTENANCE_PROTOCOL_DISCRIMINATOR) || (h->pd == T1607_MAINTENANCE_PROTOCOL_DISCRIMINATOR_TOO)) + pri_message("%c Message type: %s (%d)\n", c, t1607_msg2str(mh->msg), mh->msg); + else pri_message("%c Message type: %s (%d)\n", c, msg2str(mh->msg), mh->msg); /* Drop length of header, including call reference */ len -= (h->crlen + 3); @@ -2165,11 +2200,14 @@ return -1; } -static void init_header(struct pri *pri, q931_call *call, char *buf, q931_h **hb, q931_mh **mhb, int *len) +static void init_header(struct pri *pri, q931_call *call, 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); + 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 */ @@ -2218,8 +2256,8 @@ int codeset; 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) { @@ -2239,6 +2277,29 @@ return 0; } +static int maintenance_service_ies[] = { T1607_IE_CHANGE_STATUS, Q931_CHANNEL_IDENT, -1 }; + +int t1607_maintenance_service_ack(struct pri *pri, q931_call *c) +{ + return send_message(pri, c, (T1607_MAINTENANCE_PROTOCOL_DISCRIMINATOR << 8) | T1607_MAINTENANCE_SERVICE_ACKNOWLEDGE, maintenance_service_ies); +} + +int t1607_maintenance_service(struct pri *pri, int channel, int changestatus) +{ + struct q931_call *c; + c = q931_getcall(pri, 0 | 0x8000); + if (!c) + return -1; + if (channel) { + c->ds1no = (channel & 0xff00) >> 8; + channel &= 0xff; + c->channelno = channel; + } + c->chanflags &= ~FLAG_PREFERRED; + c->changestatus = changestatus; + return send_message(pri, c, (T1607_MAINTENANCE_PROTOCOL_DISCRIMINATOR << 8) | T1607_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) @@ -2774,14 +2835,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 != T1607_MAINTENANCE_PROTOCOL_DISCRIMINATOR) && (h->pd != T1607_MAINTENANCE_PROTOCOL_DISCRIMINATOR_TOO)) { pri_error("Warning: unknown/inappropriate protocol discriminator received (%02x/%d)\n", h->pd, h->pd); return 0; } @@ -2790,6 +2844,7 @@ pri_error("Unable to locate call %d\n", q931_cr(h)); return -1; } + if (h->pd == pri->protodisc) { /* Preliminary handling */ switch(mh->msg) { case Q931_RESTART: @@ -2895,12 +2950,30 @@ pri_error("!! Not yet handling pre-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg); /* Fall through */ default: - pri_error("!! Don't know how to post-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg); + pri_error("!! 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; } + } else { + /* Do the maintenance stuff */ + switch(mh->msg) { + case T1607_MAINTENANCE_SERVICE: + case T1607_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("!! Don't know how to pre-handle maintenance message type %s (%d)\n", t1607_msg2str(mh->msg), mh->msg); + return -1; + break; + } + } memset(mandies, 0, sizeof(mandies)); missingmand = 0; for (x=0;xmsg, ie); /* XXX Applicable to codeset 0 only? XXX */ - if (!cur_codeset && !(ie->ie & 0xf0) && (y < 0)) + if (!cur_codeset && !(ie->ie & 0xf0) && (y < 0)) { mandies[MAX_MAND_IES - 1] = Q931_FULL_IE(cur_codeset, ie->ie); } + } /* Reset current codeset */ cur_codeset = codeset; } @@ -2987,6 +3061,7 @@ } } + if (h->pd == pri->protodisc) { /* Post handling */ switch(mh->msg) { case Q931_RESTART: @@ -3089,9 +3164,6 @@ pri->ev.facname.channel = c->channelno | (c->ds1no << 8); pri->ev.facname.cref = c->cr; pri->ev.facname.call = c; -#if 0 - pri_message("Sending facility event (%s/%s)\n", pri->ev.facname.callingname, pri->ev.facname.callingnum); -#endif return Q931_RES_HAVEEVENT; case Q931_PROGRESS: if (missingmand) { @@ -3316,6 +3388,26 @@ if (c->newcall) q931_destroycall(pri,c->cr); return -1; + } + } else { + /* Do the maintenance stuff */ + switch(mh->msg) { + case T1607_MAINTENANCE_SERVICE: + pri->ev.e = PRI_EVENT_SERVICE; + pri->ev.service.channel = c->channelno | (c->ds1no << 8); + pri->ev.service.changestatus = c->changestatus; + t1607_maintenance_service_ack(pri, c); + return Q931_RES_HAVEEVENT; + case T1607_MAINTENANCE_SERVICE_ACKNOWLEDGE: + pri->ev.e = PRI_EVENT_SERVICE_ACK; + pri->ev.service_ack.channel = c->channelno | (c->ds1no << 8); + pri->ev.service_ack.changestatus = c->changestatus; + return Q931_RES_HAVEEVENT; + default: + pri_error("!! Don't know how to post-handle maintenance message type %s (%d)\n", t1607_msg2str(mh->msg), mh->msg); + return -1; + break; + } } return 0; } Index: testprilib.c =================================================================== RCS file: /usr/cvsroot/libpri/testprilib.c,v retrieving revision 1.3 diff -u -w -r1.3 testprilib.c --- testprilib.c 15 Dec 2004 20:15:28 -0000 1.3 +++ testprilib.c 29 Jan 2005 00:19:59 -0000 @@ -47,9 +47,6 @@ #elif defined(__FreeBSD__) || defined(SOLARIS) #include #endif -#ifndef SOLARIS -#include -#endif #include #include #include "libpri.h"