[Pkg-voip-commits] r1022 - libpri/trunk/debian/patches
Tzafrir Cohen
tzafrir-guest at costa.debian.org
Wed Nov 23 02:31:04 UTC 2005
Author: tzafrir-guest
Date: 2005-11-23 02:30:58 +0000 (Wed, 23 Nov 2005)
New Revision: 1022
Added:
libpri/trunk/debian/patches/bristuff.dpatch
Log:
bristuff.dpatch: currently from bristuff-0.3.0-PRE-1 . This version is
slightly modified with minor fixes (already sent upstream)
Added: libpri/trunk/debian/patches/bristuff.dpatch
===================================================================
--- libpri/trunk/debian/patches/bristuff.dpatch 2005-11-21 20:15:38 UTC (rev 1021)
+++ libpri/trunk/debian/patches/bristuff.dpatch 2005-11-23 02:30:58 UTC (rev 1022)
@@ -0,0 +1,5712 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+## bristuff.dpatch by Tzafrir Cohen <tzafrir.cohen at xorcom.com>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: The libpri part of bristuff, version 0.3.0-PRE-1
+
+ at DPATCH@
+diff -urNad libpri-1.2.0-release/libpri.h /tmp/dpep.aQ7o1G/libpri-1.2.0-release/libpri.h
+--- libpri-1.2.0-release/libpri.h 2005-10-21 23:21:22.000000000 +0200
++++ /tmp/dpep.aQ7o1G/libpri-1.2.0-release/libpri.h 2005-11-23 04:05:24.939538825 +0200
+@@ -26,8 +26,12 @@
+ #define _LIBPRI_H
+
+ /* Node types */
+-#define PRI_NETWORK 1
++#define PRI_NETWORK 1 /* PTP modes, default for PRI */
+ #define PRI_CPE 2
++#define BRI_NETWORK_PTMP 3 /* PTMP modes, default for BRI */
++#define BRI_CPE_PTMP 4
++#define BRI_NETWORK 5 /* PTP modes */
++#define BRI_CPE 6
+
+ /* Debugging */
+ #define PRI_DEBUG_Q921_RAW (1 << 0) /* Show raw HDLC frames */
+@@ -76,6 +80,12 @@
+ #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_HOLD_REQ 19 /* R */
++#define PRI_EVENT_RETRIEVE_REQ 20
++#define PRI_EVENT_SUSPEND_REQ 21 /* park */
++#define PRI_EVENT_RESUME_REQ 22 /* unpark */
++#define PRI_EVENT_DISPLAY_RECEIVED 23
++#define PRI_EVENT_FACILITY 24 /* Facility */
+
+ /* Simple states */
+ #define PRI_STATE_DOWN 0
+@@ -250,11 +260,13 @@
+ #define PRI_NSF_ATT_MULTIQUEST 0xF0
+ #define PRI_NSF_CALL_REDIRECTION_SERVICE 0xF7
+
++typedef struct q921_call q921_call;
+ typedef struct q931_call q931_call;
+
+ typedef struct pri_event_generic {
+ /* Events with no additional information fall in this category */
+ int e;
++ int tei;
+ } pri_event_generic;
+
+ typedef struct pri_event_error {
+@@ -273,18 +285,19 @@
+ int cref;
+ int progress;
+ int progressmask;
+- q931_call *call;
+ char useruserinfo[260]; /* User->User info */
++ q931_call *call;
+ } pri_event_ringing;
+
+ typedef struct pri_event_answer {
+ int e;
+ int channel;
++ int tei; /* belongs to this tei */
+ int cref;
+ int progress;
+ int progressmask;
+- q931_call *call;
+ char useruserinfo[260]; /* User->User info */
++ q931_call *call;
+ } pri_event_answer;
+
+ typedef struct pri_event_facname {
+@@ -302,10 +315,12 @@
+ int e;
+ int channel; /* Channel requested */
+ int callingpres; /* Presentation of Calling CallerID */
+- int callingplanani; /* Dialing plan of Calling entity ANI */
++ int callingpresuser; /* Presentation of Calling CallerID */
+ int callingplan; /* Dialing plan of Calling entity */
+- char callingani[256]; /* Calling ANI */
+- char callingnum[256]; /* Calling number */
++ int callingplanuser; /* Dialing plan of Calling entity */
++ int callingplanani; /* Dialing plan of Calling entity ANI */
++ char callingnum[256]; /* Calling number, network provided */
++ char callingani[256]; /* Calling number, user provided */
+ char callingname[256]; /* Calling name (if provided) */
+ int calledplan; /* Dialing plan of Called number */
+ int ani2; /* ANI II */
+@@ -321,6 +336,7 @@
+ int layer1; /* User layer 1 */
+ int complete; /* Have we seen "Complete" i.e. no more number? */
+ q931_call *call; /* Opaque call pointer */
++ int tei; /* belongs to this tei */
+ char callingsubaddr[256]; /* Calling parties subaddress */
+ int progress;
+ int progressmask;
+@@ -335,6 +351,8 @@
+ int channel; /* Channel requested */
+ int cause;
+ int cref;
++ int tei;
++ int inband_progress;
+ q931_call *call; /* Opaque call pointer */
+ long aoc_units; /* Advise of Charge number of charged units */
+ char useruserinfo[260]; /* User->User info */
+@@ -359,6 +377,7 @@
+ typedef struct pri_event_setup_ack {
+ int e;
+ int channel;
++ q931_call *call; /* Opaque call pointer */
+ } pri_event_setup_ack;
+
+ typedef struct pri_event_notify {
+@@ -374,20 +393,80 @@
+ char digits[64];
+ } pri_event_keypad_digit;
+
++typedef struct pri_event_hold_req {
++ int e;
++ int channel;
++ int cref;
++ int tei;
++ q931_call *call;
++} pri_event_hold_req;
++
++/* euroisdn faciltiy fun */
++typedef struct pri_event_facility_req {
++ int e;
++ int channel;
++ int cref;
++ int tei;
++ int operation;
++ char forwardnum[256]; /* Redirection destination */
++ q931_call *call;
++} pri_event_facility_req;
++
++typedef struct pri_event_retrieve_req {
++ int e;
++ int channel;
++ int cref;
++ int tei;
++ q931_call *call;
++} pri_event_retrieve_req;
++
++typedef struct pri_event_suspend_req {
++ int e;
++ int channel;
++ int cref;
++ int tei;
++ q931_call *call;
++ char callid[10];
++} pri_event_suspend_req;
++
++typedef struct pri_event_resume_req {
++ int e;
++ int channel;
++ int cref;
++ int tei;
++ q931_call *call;
++ char callid[10];
++} pri_event_resume_req;
++
++typedef struct pri_event_display {
++ int e;
++ int channel;
++ int cref;
++ q931_call *call;
++ char text[256];
++} pri_event_display;
++
++
+ typedef union {
+ int e;
+ pri_event_generic gen; /* Generic view */
+ pri_event_restart restart; /* Restart view */
+ pri_event_error err; /* Error view */
+ pri_event_facname facname; /* Caller*ID Name on Facility */
++ pri_event_facility_req facility; /* sservices */
+ pri_event_ring ring; /* Ring */
+ pri_event_hangup hangup; /* Hang up */
+ pri_event_ringing ringing; /* Ringing */
+- pri_event_ringing answer; /* Answer */
++ pri_event_answer answer; /* Answer */
+ pri_event_restart_ack restartack; /* Restart Acknowledge */
+ pri_event_proceeding proceeding; /* Call proceeding & Progress */
+ pri_event_setup_ack setup_ack; /* SETUP_ACKNOWLEDGE structure */
+ pri_event_notify notify; /* Notification */
++ pri_event_hold_req hold_req;
++ pri_event_retrieve_req retrieve_req;
++ pri_event_suspend_req suspend_req;
++ pri_event_resume_req resume_req;
++ pri_event_display display;
+ pri_event_keypad_digit digit; /* Digits that come during a call */
+ } pri_event;
+
+@@ -402,7 +481,9 @@
+ channel operating in HDLC mode with FCS computed by the fd's driver. Also it
+ must be NON-BLOCKING! Frames received on the fd should include FCS. Nodetype
+ must be one of PRI_NETWORK or PRI_CPE. switchtype should be PRI_SWITCH_* */
+-extern struct pri *pri_new(int fd, int nodetype, int switchtype);
++extern struct pri *pri_new(int fd, int nodetype, int switchtype, int span);
++
++extern void pri_shutdown(struct pri *pri);
+
+ /* Create D-channel just as above with user defined I/O callbacks and data */
+ extern struct pri *pri_new_cb(int fd, int nodetype, int switchtype, pri_io_cb io_read, pri_io_cb io_write, void *userdata);
+@@ -426,6 +507,9 @@
+ /* Enable transmission support of Facility IEs on the pri */
+ extern void pri_facility_enable(struct pri *pri);
+
++/* Set file descriptor for debugging to a file */
++extern void pri_set_debug_fd(struct pri *pri, int fd);
++
+ /* Run PRI on the given D-channel, taking care of any events that
+ need to be handled. If block is set, it will block until an event
+ occurs which needs to be handled */
+@@ -462,6 +546,12 @@
+ /* Send a digit in overlap mode */
+ extern int pri_information(struct pri *pri, q931_call *call, char digit);
+
++/* Send a INFO msg with display ie */
++extern int pri_information_display(struct pri *pri, q931_call *call, char *display);
++
++/* add a display ie to a call, so it can be sent with the next message */
++extern int pri_add_display(struct pri *pri, q931_call *call, char *display);
++
+ /* Answer the incomplete(call without called number) call on the given channel.
+ Set non-isdn to non-zero if you are not connecting to ISDN equipment */
+ extern int pri_need_more_info(struct pri *pri, q931_call *call, int channel, int nonisdn);
+@@ -470,6 +560,35 @@
+ Set non-isdn to non-zero if you are not connecting to ISDN equipment */
+ extern int pri_answer(struct pri *pri, q931_call *call, int channel, int nonisdn);
+
++extern int pri_deflect(struct pri *pri, q931_call *call, char *destination);
++
++/* Ack a HOLD_REQ */
++extern int pri_hold_acknowledge(struct pri *pri, q931_call *call);
++
++/* Reject a HOLD_REQ */
++extern int pri_hold_reject(struct pri *pri, q931_call *call);
++
++/* Ack a RETRIEVE_REQ */
++extern int pri_retrieve_acknowledge(struct pri *pri, q931_call *call, int channel);
++
++/* Reject a RETRIEVE_REQ */
++extern int pri_retrieve_reject(struct pri *pri, q931_call *call);
++
++/* Ack a SUSPEND_REQ */
++extern int pri_suspend_acknowledge(struct pri *pri, q931_call *call, char *display);
++
++/* Reject a SUSPEND_REQ */
++extern int pri_suspend_reject(struct pri *pri, q931_call *call, char *display);
++
++/* Reject a RESUME_REQ */
++extern int pri_resume_reject(struct pri *pri, q931_call *call, char *display);
++
++/* Ack a RESUME_REQ */
++extern int pri_resume_acknowledge(struct pri *pri, q931_call *call, int channel, char *display);
++
++/* Send a Facility Message */
++extern int pri_facility(struct pri *pri, q931_call *call, int operation, char *arguments);
++
+ /* Set CRV reference for GR-303 calls */
+
+
+@@ -525,7 +644,6 @@
+ #define PRI_USER_USER_TX
+ /* Set the user user field. Warning! don't send binary data accross this field */
+ extern void pri_sr_set_useruser(struct pri_sr *sr, char *userchars);
+-
+ extern void pri_call_set_useruser(q931_call *sr, char *userchars);
+
+ extern int pri_setup(struct pri *pri, q931_call *call, struct pri_sr *req);
+@@ -546,8 +664,8 @@
+
+ /* Override message and error stuff */
+ #define PRI_NEW_SET_API
+-extern void pri_set_message(void (*__pri_error)(struct pri *pri, char *));
+-extern void pri_set_error(void (*__pri_error)(struct pri *pri, char *));
++extern void pri_set_message(void (*__pri_error)(char *, int span));
++extern void pri_set_error(void (*__pri_error)(char *, int span));
+
+ /* Set overlap mode */
+ #define PRI_SET_OVERLAPDIAL
+diff -urNad libpri-1.2.0-release/pri.c /tmp/dpep.aQ7o1G/libpri-1.2.0-release/pri.c
+--- libpri-1.2.0-release/pri.c 2005-10-21 22:20:22.000000000 +0200
++++ /tmp/dpep.aQ7o1G/libpri-1.2.0-release/pri.c 2005-11-23 04:05:24.942538410 +0200
+@@ -48,6 +48,14 @@
+ return "Network";
+ case PRI_CPE:
+ return "CPE";
++ case BRI_NETWORK:
++ return "Network";
++ case BRI_CPE:
++ return "CPE";
++ case BRI_NETWORK_PTMP:
++ return "Network (PtMP)";
++ case BRI_CPE_PTMP:
++ return "CPE (PtMP)";
+ default:
+ return "Invalid value";
+ }
+@@ -187,7 +195,7 @@
+ return res;
+ }
+
+-static struct pri *__pri_new(int fd, int node, int switchtype, struct pri *master, pri_io_cb rd, pri_io_cb wr, void *userdata)
++static struct pri *__pri_new(int fd, int node, int switchtype, struct pri *master, pri_io_cb rd, pri_io_cb wr, void *userdata, int span)
+ {
+ struct pri *p;
+ p = malloc(sizeof(struct pri));
+@@ -207,6 +215,8 @@
+ p->master = master;
+ p->callpool = &p->localpool;
+ pri_default_timers(p, switchtype);
++ p->debugfd = -1;
++ p->span = span;
+ #ifdef LIBPRI_COUNTERS
+ p->q921_rxcount = 0;
+ p->q921_txcount = 0;
+@@ -217,7 +227,7 @@
+ p->protodisc = GR303_PROTOCOL_DISCRIMINATOR;
+ p->sapi = Q921_SAPI_GR303_EOC;
+ p->tei = Q921_TEI_GR303_EOC_OPS;
+- p->subchannel = __pri_new(-1, node, PRI_SWITCH_GR303_EOC_PATH, p, NULL, NULL, NULL);
++ p->subchannel = __pri_new(-1, node, PRI_SWITCH_GR303_EOC_PATH, p, NULL, NULL, NULL, span);
+ if (!p->subchannel) {
+ free(p);
+ p = NULL;
+@@ -226,7 +236,7 @@
+ p->protodisc = GR303_PROTOCOL_DISCRIMINATOR;
+ p->sapi = Q921_SAPI_GR303_TMC_CALLPROC;
+ p->tei = Q921_TEI_GR303_TMC_CALLPROC;
+- p->subchannel = __pri_new(-1, node, PRI_SWITCH_GR303_TMC_SWITCHING, p, NULL, NULL, NULL);
++ p->subchannel = __pri_new(-1, node, PRI_SWITCH_GR303_TMC_SWITCHING, p, NULL, NULL, NULL, span);
+ if (!p->subchannel) {
+ free(p);
+ p = NULL;
+@@ -242,7 +252,7 @@
+ }
+ /* Start Q.921 layer, Wait if we're the network */
+ if (p)
+- q921_start(p, p->localtype == PRI_CPE);
++ q921_start(p, p->localtype == PRI_CPE, 0);
+ }
+ return p;
+ }
+@@ -262,15 +272,16 @@
+ {
+ /* Restart Q.921 layer */
+ if (pri) {
+- q921_reset(pri);
+- q921_start(pri, pri->localtype == PRI_CPE);
++// XXX q921_reset(pri);
++// q921_start(pri, pri->localtype == PRI_CPE);
+ }
+ return 0;
+ }
+
+-struct pri *pri_new(int fd, int nodetype, int switchtype)
++
++struct pri *pri_new(int fd, int nodetype, int switchtype, int span)
+ {
+- return __pri_new(fd, nodetype, switchtype, NULL, __pri_read, __pri_write, NULL);
++ return __pri_new(fd, nodetype, switchtype, NULL, __pri_read, __pri_write, NULL, span);
+ }
+
+ struct pri *pri_new_cb(int fd, int nodetype, int switchtype, pri_io_cb io_read, pri_io_cb io_write, void *userdata)
+@@ -279,7 +290,7 @@
+ io_read = __pri_read;
+ if (!io_write)
+ io_write = __pri_write;
+- return __pri_new(fd, nodetype, switchtype, NULL, io_read, io_write, userdata);
++ return __pri_new(fd, nodetype, switchtype, NULL, io_read, io_write, userdata, -1);
+ }
+
+ void *pri_get_userdata(struct pri *pri)
+@@ -443,6 +454,15 @@
+ return;
+ }
+
++void pri_set_debug_fd(struct pri *pri, int fd)
++{
++ if (!pri)
++ return;
++ pri->debugfd = fd;
++ if (pri->subchannel)
++ pri_set_debug_fd(pri->subchannel, fd);
++}
++
+ int pri_acknowledge(struct pri *pri, q931_call *call, int channel, int info)
+ {
+ if (!pri || !call)
+@@ -478,6 +498,21 @@
+ return q931_notify(pri, call, channel, info);
+ }
+
++int pri_information_display(struct pri *pri, q931_call *call, char *display)
++{
++ if (!pri || !call)
++ return -1;
++ return q931_information_display(pri, call, display);
++}
++
++int pri_add_display(struct pri *pri, q931_call *call, char *display)
++{
++ if (!pri || !call)
++ return -1;
++ return q931_add_display(pri, call, display);
++}
++
++
+ void pri_destroycall(struct pri *pri, q931_call *call)
+ {
+ if (pri && call)
+@@ -499,6 +534,76 @@
+ return q931_connect(pri, call, channel, nonisdn);
+ }
+
++int pri_hold_acknowledge(struct pri *pri, q931_call *call)
++{
++ if (!pri || !call)
++ return -1;
++ return q931_hold_acknowledge(pri, call);
++}
++
++int pri_hold_reject(struct pri *pri, q931_call *call)
++{
++ if (!pri || !call)
++ return -1;
++ return q931_hold_reject(pri, call);
++}
++
++int pri_retrieve_acknowledge(struct pri *pri, q931_call *call, int channel)
++{
++ if (!pri || !call)
++ return -1;
++ return q931_retrieve_acknowledge(pri, call, channel);
++}
++
++int pri_retrieve_reject(struct pri *pri, q931_call *call)
++{
++ if (!pri || !call)
++ return -1;
++ return q931_retrieve_reject(pri, call);
++}
++
++int pri_suspend_acknowledge(struct pri *pri, q931_call *call, char *display)
++{
++ if (!pri || !call)
++ return -1;
++ return q931_suspend_acknowledge(pri, call, display);
++}
++
++int pri_suspend_reject(struct pri *pri, q931_call *call, char *display)
++{
++ if (!pri || !call)
++ return -1;
++ return q931_suspend_reject(pri, call, display);
++}
++
++int pri_resume_reject(struct pri *pri, q931_call *call, char *display)
++{
++ if (!pri || !call)
++ return -1;
++ return q931_resume_reject(pri, call, display);
++}
++
++int pri_resume_acknowledge(struct pri *pri, q931_call *call, int channel, char *display)
++{
++ if (!pri || !call)
++ return -1;
++ return q931_resume_acknowledge(pri, call, channel, display);
++}
++
++int pri_facility(struct pri *pri, q931_call *call, int operation, char *arguments)
++{
++ if (!pri || !call)
++ return -1;
++// return q931_facility(pri, call, operation, arguments);
++ return q931_facility(pri, call);
++}
++
++int pri_deflect(struct pri *pri, q931_call *call, char *destination)
++{
++ add_call_deflection_facility_ie(pri, call, destination);
++ return q931_facility(pri, call);
++}
++
+ #if 0
+ /* deprecated routines, use pri_hangup */
+ int pri_release(struct pri *pri, q931_call *call, int cause)
+@@ -543,12 +648,24 @@
+
+ int pri_hangup(struct pri *pri, q931_call *call, int cause)
+ {
++ int res=0;
+ if (!pri || !call)
+ return -1;
+ if (cause == -1)
+ /* normal clear cause */
+ cause = 16;
+- return q931_hangup(pri, call, cause);
++ if (pri->localtype == BRI_NETWORK_PTMP) {
++ res = q921_hangup(pri, call, 127);
++ if (res) {
++ // q921_setup might give a HANGUP_ACK, if nobody got the call
++ q931_hangup(pri, call, cause);
++ return res;
++ } else {
++ return q931_hangup(pri, call, cause);
++ }
++ } else {
++ return q931_hangup(pri, call, cause);
++ }
+ }
+
+ int pri_reset(struct pri *pri, int channel)
+@@ -688,15 +805,15 @@
+ return q931_setup(pri, c, &req);
+ }
+
+-static void (*__pri_error)(struct pri *pri, char *stuff);
+-static void (*__pri_message)(struct pri *pri, char *stuff);
++static void (*__pri_error)(char *stuff,int span);
++static void (*__pri_message)(char *stuff,int span);
+
+-void pri_set_message(void (*func)(struct pri *pri, char *stuff))
++void pri_set_message(void (*func)(char *stuff,int span))
+ {
+ __pri_message = func;
+ }
+
+-void pri_set_error(void (*func)(struct pri *pri, char *stuff))
++void pri_set_error(void (*func)(char *stuff,int span))
+ {
+ __pri_error = func;
+ }
+@@ -708,10 +825,14 @@
+ va_start(ap, fmt);
+ vsnprintf(tmp, sizeof(tmp), fmt, ap);
+ va_end(ap);
+- if (__pri_message)
+- __pri_message(pri, tmp);
+- else
+- fputs(tmp, stdout);
++ if (__pri_message && pri) {
++ if (pri->debugfd >= 0)
++ write(pri->debugfd, tmp, strlen(tmp));
++ else
++ __pri_message(tmp, pri->span);
++ } else {
++ fputs(tmp, stdout);
++ }
+ }
+
+ void pri_error(struct pri *pri, char *fmt, ...)
+@@ -721,10 +842,14 @@
+ va_start(ap, fmt);
+ vsnprintf(tmp, sizeof(tmp), fmt, ap);
+ va_end(ap);
+- if (__pri_error)
+- __pri_error(pri, tmp);
+- else
+- fputs(tmp, stderr);
++ if (__pri_error && pri) {
++ if (pri->debugfd >= 0)
++ write(pri->debugfd, tmp, strlen(tmp));
++ else
++ __pri_error(tmp, pri->span);
++ } else {
++ fputs(tmp, stderr);
++ }
+ }
+
+ /* Set overlap mode */
+@@ -765,11 +890,13 @@
+ }
+ len += sprintf(buf + len, "Q921 Outstanding: %d\n", q921outstanding);
+ #endif
+- len += sprintf(buf + len, "Window Length: %d/%d\n", pri->windowlen, pri->window);
+- len += sprintf(buf + len, "Sentrej: %d\n", pri->sentrej);
+- len += sprintf(buf + len, "SolicitFbit: %d\n", pri->solicitfbit);
+- len += sprintf(buf + len, "Retrans: %d\n", pri->retrans);
+- len += sprintf(buf + len, "Busy: %d\n", pri->busy);
++ if (pri->localtype != BRI_NETWORK_PTMP) {
++ len += sprintf(buf + len, "Window Length: %d/%d\n", pri->windowlen[0], pri->window[0]);
++ len += sprintf(buf + len, "Sentrej: %d\n", pri->sentrej[0]);
++ len += sprintf(buf + len, "SolicitFbit: %d\n", pri->solicitfbit[0]);
++ len += sprintf(buf + len, "Retrans: %d\n", pri->retrans[0]);
++ len += sprintf(buf + len, "Busy: %d\n", pri->busy[0]);
++ }
+ len += sprintf(buf + len, "Overlap Dial: %d\n", pri->overlapdial);
+ len += sprintf(buf + len, "T200 Timer: %d\n", pri->timers[PRI_TIMER_T200]);
+ len += sprintf(buf + len, "T203 Timer: %d\n", pri->timers[PRI_TIMER_T203]);
+@@ -778,6 +905,7 @@
+ len += sprintf(buf + len, "T313 Timer: %d\n", pri->timers[PRI_TIMER_T313]);
+ len += sprintf(buf + len, "N200 Counter: %d\n", pri->timers[PRI_TIMER_N200]);
+
++
+ return strdup(buf);
+ }
+
+@@ -851,3 +979,10 @@
+ sr->redirectingreason = reason;
+ return 0;
+ }
++
++void pri_shutdown(struct pri *pri)
++{
++ if ((pri->localtype == BRI_NETWORK) || (pri->localtype == BRI_CPE) || (pri->localtype == BRI_CPE_PTMP)) {
++ q921_reset(pri, pri->tei, 1);
++ }
++}
+diff -urNad libpri-1.2.0-release/pri_facility.c /tmp/dpep.aQ7o1G/libpri-1.2.0-release/pri_facility.c
+--- libpri-1.2.0-release/pri_facility.c 2005-10-04 20:35:48.000000000 +0300
++++ /tmp/dpep.aQ7o1G/libpri-1.2.0-release/pri_facility.c 2005-11-23 04:05:24.946537856 +0200
+@@ -208,9 +208,9 @@
+ if (datalen > buflen) {
+ /* Truncate */
+ datalen = buflen;
++ memcpy(namebuf, comp->data, datalen);
+ }
+- memcpy(namebuf, comp->data, datalen);
+- return res + 2;
++ return res;
+ }
+
+ int asn1_string_encode(unsigned char asn1_type, void *data, int len, int max_len, void *src, int src_len)
+@@ -305,7 +305,7 @@
+ return -1;
+ value->ton = ton;
+
+- return res + 3;
++ return res + 2;
+
+ } while(0);
+ return -1;
+@@ -375,11 +375,10 @@
+ pri_message(pri, "!! Unknown Party number component received 0x%X\n", comp->type);
+ return -1;
+ }
+- ASN1_FIXUP_LEN(comp, res);
+ NEXT_COMPONENT(comp, i);
+ if(i < len)
+ pri_message(pri, "!! not all information is handled from Address component\n");
+- return res + 2;
++ return res;
+ }
+ while (0);
+
+@@ -389,7 +388,6 @@
+ static int rose_presented_number_unscreened_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value)
+ {
+ int i = 0;
+- int size = 0;
+ struct rose_component *comp = NULL;
+ unsigned char *vdata = data;
+
+@@ -404,9 +402,7 @@
+ switch(comp->type) {
+ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0): /* [0] presentationAllowedNumber */
+ value->pres = PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
+- size = rose_address_decode(pri, call, comp->data, comp->len, value);
+- ASN1_FIXUP_LEN(comp, size);
+- return size + 2;
++ return rose_address_decode(pri, call, comp->data, comp->len, value) + 2;
+ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1): /* [1] IMPLICIT presentationRestricted */
+ if (comp->len != 0) { /* must be NULL */
+ pri_error(pri, "!! Invalid PresentationRestricted component received (len != 0)\n");
+@@ -423,9 +419,7 @@
+ return 2;
+ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3): /* [3] presentationRestrictedNumber */
+ value->pres = PRES_PROHIB_USER_NUMBER_NOT_SCREENED;
+- size = rose_address_decode(pri, call, comp->data, comp->len, value) + 2;
+- ASN1_FIXUP_LEN(comp, size);
+- return size + 2;
++ return rose_address_decode(pri, call, comp->data, comp->len, value) + 2;
+ default:
+ pri_message(pri, "Invalid PresentedNumberUnscreened component 0x%X\n", comp->type);
+ }
+@@ -436,7 +430,7 @@
+ return -1;
+ }
+
+-static int rose_diverting_leg_information2_decode(struct pri *pri, q931_call *call, struct rose_component *sequence, int len)
++static int rose_diverting_leg_information2_decode(struct pri *pri, q931_call *call, unsigned char *data, int len)
+ {
+ int i = 0;
+ int diversion_counter;
+@@ -445,21 +439,9 @@
+ struct addressingdataelements_presentednumberunscreened divertingnr;
+ struct addressingdataelements_presentednumberunscreened originalcallednr;
+ struct rose_component *comp = NULL;
+- unsigned char *vdata = sequence->data;
++ unsigned char *vdata = data;
+ int res = 0;
+
+- /* Data checks */
+- if (sequence->type != (ASN1_CONSTRUCTOR | ASN1_SEQUENCE)) { /* Constructed Sequence */
+- pri_message(pri, "Invalid DivertingLegInformation2Type argument\n");
+- return -1;
+- }
+-
+- if (sequence->len == ASN1_LEN_INDEF) {
+- len -= 4; /* For the 2 extra characters at the end
+- * and two characters of header */
+- } else
+- len -= 2;
+-
+ do {
+ /* diversionCounter stuff */
+ GET_COMPONENT(comp, i, vdata, len);
+@@ -477,20 +459,18 @@
+
+ if(pri->debug & PRI_DEBUG_APDU)
+ pri_message(pri, " Redirection reason: %d, total diversions: %d\n", diversion_reason, diversion_counter);
+- pri_message(NULL, "Length of message is %d\n", len);
+
+ for(; i < len; NEXT_COMPONENT(comp, i)) {
+ GET_COMPONENT(comp, i, vdata, len);
+- switch(comp->type) {
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0):
++ switch(comp->type & ASN1_TYPE_MASK) {
++ case ASN1_TAG_0:
+ call->origredirectingreason = redirectingreason_for_q931(pri, comp->data[0]);
+ if (pri->debug & PRI_DEBUG_APDU)
+ pri_message(pri, " Received reason for original redirection %d\n", call->origredirectingreason);
+ break;
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1):
++ case ASN1_TAG_1: /* divertingnr: presentednumberunscreened */
+ res = rose_presented_number_unscreened_decode(pri, call, comp->data, comp->len, &divertingnr);
+ /* TODO: Fix indefinite length form hacks */
+- ASN1_FIXUP_LEN(comp, res);
+ comp->len = res;
+ if (res < 0)
+ return -1;
+@@ -499,43 +479,33 @@
+ pri_message(pri, " ton = %d, pres = %d, npi = %d\n", divertingnr.ton, divertingnr.pres, divertingnr.npi);
+ }
+ break;
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_2):
++ case ASN1_TAG_2: /* originalCalledNr: PresentedNumberUnscreened */
+ res = rose_presented_number_unscreened_decode(pri, call, comp->data, comp->len, &originalcallednr);
+ if (res < 0)
+ return -1;
+- ASN1_FIXUP_LEN(comp, res);
+ comp->len = res;
+ if (pri->debug & PRI_DEBUG_APDU) {
+ pri_message(pri, " Received originalcallednr '%s'\n", originalcallednr.partyaddress);
+ pri_message(pri, " ton = %d, pres = %d, npi = %d\n", originalcallednr.ton, originalcallednr.pres, originalcallednr.npi);
+ }
+ break;
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3):
+- res = asn1_name_decode(comp->data, comp->len, redirectingname, sizeof(redirectingname));
+- if (res < 0)
+- return -1;
+- ASN1_FIXUP_LEN(comp, res);
+- comp->len = res;
++ case ASN1_TAG_3:
++ comp->len = asn1_name_decode(comp->data, comp->len, redirectingname, sizeof(redirectingname));
+ if (pri->debug & PRI_DEBUG_APDU)
+ pri_message(pri, " Received RedirectingName '%s'\n", redirectingname);
+ break;
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_4):
+- res = asn1_name_decode(comp->data, comp->len, origcalledname, sizeof(origcalledname));
+- if (res < 0)
+- return -1;
+- ASN1_FIXUP_LEN(comp, res);
+- comp->len = res;
++ case ASN1_TAG_4:
++ comp->len = asn1_name_decode(comp->data, comp->len, origcalledname, sizeof(origcalledname));
+ if (pri->debug & PRI_DEBUG_APDU)
+ pri_message(pri, " Received Originally Called Name '%s'\n", origcalledname);
+ break;
+ default:
+- if (comp->type == 0 && comp->len == 0) {
+- break; /* Found termination characters */
+- }
+ pri_message(pri, "!! Invalid DivertingLegInformation2 component received 0x%X\n", comp->type);
+ return -1;
+ }
+ }
++ if (i < len)
++ return -1; /* Aborted before */
+
+ if (divertingnr.pres >= 0) {
+ call->redirectingplan = divertingnr.npi;
+@@ -694,6 +664,64 @@
+ return 0;
+ }
+
++/* Call deflection */
++int add_call_deflection_facility_ie(struct pri *pri, q931_call *c, char *destination) {
++ int i = 0, j, compsp = 0;
++ struct rose_component *comp, *compstk[10];
++ unsigned char buffer[256];
++
++ buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_ROSE);
++ /* invoke */
++ ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i);
++ ASN1_PUSH(compstk, compsp, comp);
++
++ ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri));
++ ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, ROSE_CALLDEFLECTION);
++
++ /* Argument sequence */
++ ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i);
++ ASN1_PUSH(compstk, compsp, comp);
++
++ /* arg.Address */
++ ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i);
++ ASN1_PUSH(compstk, compsp, comp);
++
++#ifndef CD_UNLIKE_IN_CAPI
++ /* arg.address.PartyNumber */
++
++
++ j = asn1_string_encode((ASN1_CONTEXT_SPECIFIC|ASN1_TAG_0), &buffer[i], sizeof(buffer)-i, 20, destination, strlen(destination));
++ if (j<0) return -1;
++ i += j;
++#else
++ /* using PublicPartyNumber instead */
++ ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE | ASN1_CONTEXT_SPECIFIC| ASN1_TAG_1), buffer, i);
++ ASN1_PUSH(compstk, compsp, comp);
++ /* ToN: unknown */
++ ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 0);
++ j = asn1_string_encode(0x80, &buffer[i], sizeof(buffer)-i, 20, destination, strlen(destination));
++ if(j<0) return -1;
++ i += j;
++ /* close PublicPartyNumber */
++ ASN1_FIXUP(compstk, compsp, buffer, i);
++#endif
++
++ /* close Address */
++ ASN1_FIXUP(compstk, compsp, buffer, i);
++
++ /* add boolean */
++ ASN1_ADD_BYTECOMP(comp, ASN1_BOOLEAN, buffer, i, 0);
++
++ /* Fix length of stacked components */
++ while(compsp > 0) {
++ ASN1_FIXUP(compstk, compsp, buffer, i);
++ }
++ if (pri_call_apdu_queue(c, Q931_FACILITY, buffer, i, NULL, NULL))
++ return -1;
++
++ return 0;
++}
++
+ /* Sending callername information functions */
+ static int add_callername_facility_ies(struct pri *pri, q931_call *c, int cpe)
+ {
+@@ -1132,6 +1160,7 @@
+ int operation_tag;
+ unsigned char *vdata = data;
+ struct rose_component *comp = NULL, *invokeid = NULL, *operationid = NULL;
++// struct addressingdataelements_presentednumberunscreened value;
+
+ do {
+ /* Invoke ID stuff */
+@@ -1148,13 +1177,15 @@
+ NEXT_COMPONENT(comp, i);
+
+ /* No argument - return with error */
+- if (i >= len)
++ if ((i >= len) && (operation_tag != ROSE_EXPLICIT_CALL_TRANSFER))
+ return -1;
+
+- /* Arguement Tag */
+- GET_COMPONENT(comp, i, vdata, len);
+- if (!comp->type)
+- return -1;
++ if (operation_tag != ROSE_EXPLICIT_CALL_TRANSFER) {
++ /* Arguement Tag */
++ GET_COMPONENT(comp, i, vdata, len);
++ if (!comp->type)
++ return -1;
++ }
+
+ if (pri->debug & PRI_DEBUG_APDU)
+ pri_message(pri, " [ Handling operation %d ]\n", operation_tag);
+@@ -1178,7 +1209,11 @@
+ case ROSE_DIVERTING_LEG_INFORMATION2:
+ if (pri->debug & PRI_DEBUG_APDU)
+ pri_message(pri, " Handle DivertingLegInformation2\n");
+- return rose_diverting_leg_information2_decode(pri, call, comp, len-i);
++ if (comp->type != (ASN1_CONSTRUCTOR | ASN1_SEQUENCE)) { /* Constructed Sequence */
++ pri_message(pri, "Invalid DivertingLegInformation2Type argument\n");
++ return -1;
++ }
++ return rose_diverting_leg_information2_decode(pri, call, comp->data, comp->len);
+ case ROSE_AOC_NO_CHARGING_INFO_AVAILABLE:
+ if (pri->debug & PRI_DEBUG_APDU) {
+ pri_message(pri, "ROSE %i: AOC No Charging Info Available - not handled!", operation_tag);
+@@ -1229,6 +1264,32 @@
+ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
+ }
+ return -1;
++ case ROSE_CALLDEFLECTION:
++ // if (pri->debug & PRI_DEBUG_APDU) {
++ pri_message(pri, "ROSE %i: CD - not handled!", operation_tag);
++ dump_apdu (pri, comp->data, comp->len);
++ // }
++/* GET_COMPONENT(comp, i, vdata, len);
++ if (comp->type == ASN1_SEQUENCE | ASN1_CONSTRUCTOR | ASN1_TAG_0) {
++ int j=0;
++ for (j=0;j<comp->len;j++) {
++ pri_error(pri, "comp->data %#x\n",comp->data[j]);
++ }
++
++ pri_error(pri, "c type %#x, c len %#x\n", comp->type, comp->len);
++ if (comp->type == ASN1_SEQUENCE | ASN1_CONSTRUCTOR) {
++ pri_error(pri, "c type %#x, c len %#x\n", comp->type, comp->len);
++ }
++
++ }
++ */
++ return -1;
++ case ROSE_EXPLICIT_CALL_TRANSFER:
++ call->facility = operation_tag;
++ if (pri->debug & PRI_DEBUG_APDU) {
++ pri_message(pri, "ROSE %i: received ECT execute!", operation_tag);
++ }
++ return 0;
+ default:
+ if (pri->debug & PRI_DEBUG_APDU) {
+ pri_message(pri, "!! Unable to handle ROSE operation %d", operation_tag);
+diff -urNad libpri-1.2.0-release/pri_facility.h /tmp/dpep.aQ7o1G/libpri-1.2.0-release/pri_facility.h
+--- libpri-1.2.0-release/pri_facility.h 2005-07-12 23:15:20.000000000 +0300
++++ /tmp/dpep.aQ7o1G/libpri-1.2.0-release/pri_facility.h 2005-11-23 04:05:24.949537440 +0200
+@@ -34,7 +34,7 @@
+ /* Operation ID values */
+ /* Q.952 ROSE operations (Diverting) */
+ #define ROSE_DIVERTING_LEG_INFORMATION1 18
+-#define ROSE_DIVERTING_LEG_INFORMATION2 0x15
++#define ROSE_DIVERTING_LEG_INFORMATION2 15
+ #define ROSE_DIVERTING_LEG_INFORMATION3 19
+ /* Q.956 ROSE operations (Advice Of Charge) */
+ #define ROSE_AOC_NO_CHARGING_INFO_AVAILABLE 26
+@@ -48,11 +48,14 @@
+ #define ROSE_AOC_IDENTIFICATION_OF_CHARGE 37
+ /* Q.SIG operations */
+ #define SS_CNID_CALLINGNAME 0
+-#define SS_DIVERTING_LEG_INFORMATION2 21
++#define SS_DIVERTING_LEG_INFORMATION2 22
+ #define SS_MWI_ACTIVATE 80
+ #define SS_MWI_DEACTIVATE 81
+ #define SS_MWI_INTERROGATE 82
+
++#define ROSE_CALLDEFLECTION 0x0D
++#define ROSE_EXPLICIT_CALL_TRANSFER 0x06
++
+ /* ROSE definitions and data structures */
+ #define INVOKE_IDENTIFIER 0x02
+ #define INVOKE_LINKED_IDENTIFIER 0x80
+@@ -180,12 +183,6 @@
+ (variable) = ((variable) << 8) | (component)->data[comp_idx]; \
+ } while (0)
+
+-#define ASN1_FIXUP_LEN(component, size) \
+- do { \
+- if ((component)->len == ASN1_LEN_INDEF) \
+- size += 2; \
+- } while (0)
+-
+ #define ASN1_ADD_SIMPLE(component, comptype, ptr, idx) \
+ do { \
+ (component) = (struct rose_component *)&((ptr)[(idx)]); \
+@@ -260,4 +257,6 @@
+ /* Adds the "standard" ADPUs to a call */
+ extern int pri_call_add_standard_apdus(struct pri *pri, q931_call *call);
+
++extern int add_call_deflection_facility_ie(struct pri *pri, q931_call *c, char *destination);
++
+ #endif /* _PRI_FACILITY_H */
+diff -urNad libpri-1.2.0-release/pri_internal.h /tmp/dpep.aQ7o1G/libpri-1.2.0-release/pri_internal.h
+--- libpri-1.2.0-release/pri_internal.h 2005-10-21 22:20:22.000000000 +0200
++++ /tmp/dpep.aQ7o1G/libpri-1.2.0-release/pri_internal.h 2005-11-23 04:05:24.952537024 +0200
+@@ -30,7 +30,10 @@
+ struct pri_sched {
+ struct timeval when;
+ void (*callback)(void *data);
++ void (*callback2)(void *data, int);
+ void *data;
++ char hasdata2;
++ int data2;
+ };
+
+ struct q921_frame;
+@@ -38,8 +41,15 @@
+ enum q931_mode;
+
+ /* No more than 128 scheduled events */
++/* XXX is this sufficient for nfs ??? */
+ #define MAX_SCHED 128
+
++/* this can be freely configured to support more devices .... ok, 63 would be max! */
++#define Q921_MAX_TEIS 16
++
++/* dynamically allocated TEIs start here */
++#define Q921_TEI_BASE 64
++
+ #define MAX_TIMERS 32
+
+ struct pri {
+@@ -51,6 +61,7 @@
+ struct pri *master; /* Master channel if appropriate */
+ struct pri_sched pri_sched[MAX_SCHED]; /* Scheduled events */
+ int debug; /* Debug stuff */
++ int debugfd;
+ int state; /* State of D-channel */
+ int switchtype; /* Switch type */
+ int nsf; /* Network-Specific Facility (if any) */
+@@ -62,25 +73,39 @@
+ int protodisc;
+
+ /* Q.921 State */
+- int q921_state;
+- int window; /* Max window size */
+- int windowlen; /* Fullness of window */
+- int v_s; /* Next N(S) for transmission */
+- int v_a; /* Last acknowledged frame */
+- int v_r; /* Next frame expected to be received */
+- int v_na; /* What we've told our peer we've acknowledged */
+- int solicitfbit; /* Have we sent an I or S frame with the F-bit set? */
+- int retrans; /* Retransmissions */
+- int sentrej; /* Are we in reject state */
+-
++ int q921_state[Q921_MAX_TEIS];
++ char dchanup;
++
++ /* TEI registry */
++ char q921_teis[Q921_MAX_TEIS];
++
++ unsigned int ri;
++
++ int busy[Q921_MAX_TEIS]; /* Peer is busy */
++
++ int window[Q921_MAX_TEIS]; /* Max window size */
++ int windowlen[Q921_MAX_TEIS]; /* Fullness of window */
++ int v_s[Q921_MAX_TEIS]; /* Next N(S) for transmission */
++ int v_a[Q921_MAX_TEIS]; /* Last acknowledged frame */
++ int v_r[Q921_MAX_TEIS]; /* Next frame expected to be received */
++ int v_na[Q921_MAX_TEIS]; /* What we've told our peer we've acknowledged */
++ int solicitfbit[Q921_MAX_TEIS]; /* Have we sent an I or S frame with the F-bit set? */
++ int retrans[Q921_MAX_TEIS]; /* Retransmissions */
++ int sabme_retrans[Q921_MAX_TEIS]; /* Retransmissions */
++
++ int sentrej[Q921_MAX_TEIS]; /* Are we in reject state */
++
++ /* Various timers */
++ int sabme_timer[Q921_MAX_TEIS];
++ int t203_timer[Q921_MAX_TEIS];
++ int t202_timer[Q921_MAX_TEIS];
++
++ int t201_timer[Q921_MAX_TEIS];
++ int t200_timer[Q921_MAX_TEIS];
++
++
+ int cref; /* Next call reference value */
+
+- int busy; /* Peer is busy */
+-
+- /* Various timers */
+- int sabme_timer; /* SABME retransmit */
+- int t203_timer; /* Max idle time */
+- int t200_timer; /* T-200 retransmission timer */
+ /* All ISDN Timer values */
+ int timers[MAX_TIMERS];
+
+@@ -89,8 +114,8 @@
+ int schedev;
+ pri_event ev; /* Static event thingy */
+
+- /* Q.921 Re-transmission queue */
+- struct q921_frame *txqueue;
++ /* Q.921 (Re)transmission queue */
++ struct q921_frame *txqueue[Q921_MAX_TEIS];
+
+ /* Q.931 calls */
+ q931_call **callpool;
+@@ -109,6 +134,9 @@
+
+ unsigned char last_invoke; /* Last ROSE invoke ID */
+ unsigned char sendfacility;
++
++ int span; /* our fellow pri lives on this zaptel span */
++
+ };
+
+ struct pri_sr {
+@@ -118,6 +146,7 @@
+ int nonisdn;
+ char *caller;
+ int callerplan;
++ int callerplanani;
+ char *callername;
+ int callerpres;
+ char *called;
+@@ -169,6 +198,10 @@
+ int acked; /* Whether setup has been acked or not */
+ int sendhangupack; /* Whether or not to send a hangup ack */
+ int proc; /* Whether we've sent a call proceeding / alerting */
++ int alert; /* Whether we've sent an alerting */
++
++ int tei;
++ q921_call *phones;
+
+ int ri; /* Restart Indicator (Restart Indicator IE) */
+
+@@ -202,11 +235,14 @@
+ int callerplan;
+ int callerplanani;
+ int callerpres; /* Caller presentation */
+- char callerani[256]; /* Caller */
+- char callernum[256];
++ int callerplanuser;
++ int callerpresuser; /* Caller presentation */
++ char callernum[256]; /* Calling Number (network provided) */
++ char callerani[256]; /* Calling Number, (user provided) */
++
+ char callername[256];
+
+- char digitbuf[64]; /* Buffer for digits that come in KEYPAD_FACILITY */
++ char digitbuf[64]; /* Buffer for digits that come in KEYPAD_FACILITY */
+
+ int ani2; /* ANI II */
+
+@@ -225,16 +261,27 @@
+ char redirectingnum[256]; /* Number of redirecting party */
+ char redirectingname[256]; /* Name of redirecting party */
+
++ int t303timer;
++ int t303running;
++
+ /* Filled in cases of multiple diversions */
+ int origcalledplan;
+ int origcalledpres;
+- int origredirectingreason; /* Original reason for redirect (in cases of multiple redirects) */
++ int origredirectingreason; /* Original reason for redirect (in cases of multiple redirects) */
+ char origcalledname[256]; /* Original name of person being called */
+- char origcallednum[256]; /* Orignal number of person being called */
++ char origcallednum[256]; /* Orignal number of person being called */
+
+ int useruserprotocoldisc;
+ char useruserinfo[256];
+ char callingsubaddr[256]; /* Calling parties sub address */
++
++ char callid[10]; /* call identity for SUSPEND/RESUME */
++ char digits[256]; /* additional digits received via info msgs (cpn or keypad) */
++ char display[256]; /* display ie received in info msgs or for sending */
++
++ /* euroisdn facility fun */
++ int facility; /* FACILTIY received */
++ int aoc;
+
+ long aoc_units; /* Advice of Charge Units */
+
+@@ -242,6 +289,7 @@
+ };
+
+ extern int pri_schedule_event(struct pri *pri, int ms, void (*function)(void *data), void *data);
++extern int pri_schedule_event2(struct pri *pri, int ms, void (*function)(void *data, int data2), void *data, int data2);
+
+ extern pri_event *pri_schedule_run(struct pri *pri);
+
+@@ -250,7 +298,7 @@
+ extern pri_event *pri_mkerror(struct pri *pri, char *errstr);
+
+ extern void pri_message(struct pri *pri, char *fmt, ...);
+-
++
+ extern void pri_error(struct pri *pri, char *fmt, ...);
+
+ void libpri_copy_string(char *dst, const char *src, size_t size);
+diff -urNad libpri-1.2.0-release/pri_q921.h /tmp/dpep.aQ7o1G/libpri-1.2.0-release/pri_q921.h
+--- libpri-1.2.0-release/pri_q921.h 2005-05-23 18:06:33.000000000 +0300
++++ /tmp/dpep.aQ7o1G/libpri-1.2.0-release/pri_q921.h 2005-11-23 04:05:24.955536609 +0200
+@@ -47,6 +47,13 @@
+ #define Q921_FRAMETYPE_S 0x1
+
+ #define Q921_TEI_GROUP 127
++#define Q921_TEI_ID_REQUEST 0x1
++#define Q921_TEI_ID_ASSIGNED 0x2
++#define Q921_TEI_ID_DENIED 0x3
++#define Q921_TEI_ID_CHK_REQ 0x4
++#define Q921_TEI_ID_CHK_RES 0x5
++#define Q921_TEI_ID_REMOVE 0x6
++#define Q921_TEI_ID_VERIFY 0x7
+ #define Q921_TEI_GR303_EOC_PATH 0
+ #define Q921_TEI_GR303_EOC_OPS 4
+ #define Q921_TEI_GR303_TMC_SWITCHING 0
+@@ -164,12 +171,14 @@
+ extern void q921_dump(struct pri *pri, q921_h *h, int len, int showraw, int txrx);
+
+ /* Bring up the D-channel */
+-extern void q921_start(struct pri *pri, int now);
++extern void q921_start(struct pri *pri, int now, int tei);
+
+-extern void q921_reset(struct pri *pri);
++extern void q921_reset(struct pri *pri, int tei, int discard);
+
+ 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 int q921_transmit_uframe(struct pri *pri, void *buf, int len, int cr, int tei);
++
++extern int q921_transmit_iframe(struct pri *pri, void *buf, int len, int cr, int tei);
+
+ #endif
+diff -urNad libpri-1.2.0-release/pri_q931.h /tmp/dpep.aQ7o1G/libpri-1.2.0-release/pri_q931.h
+--- libpri-1.2.0-release/pri_q931.h 2005-05-23 18:06:33.000000000 +0300
++++ /tmp/dpep.aQ7o1G/libpri-1.2.0-release/pri_q931.h 2005-11-23 04:05:24.958536193 +0200
+@@ -190,6 +190,10 @@
+ #define Q931_IE_CODESET(x) ((x) >> 8)
+ #define Q931_IE_IE(x) ((x) & 0xff)
+ #define Q931_FULL_IE(codeset, ie) (((codeset) << 8) | ((ie) & 0xff))
++#define Q931_IE_MAX_LEN 257
++
++// BRI+
++#define Q931_COLP 0x4c
+
+ #define Q931_DISPLAY 0x28
+ #define Q931_IE_SEGMENTED_MSG 0x00
+@@ -218,6 +222,8 @@
+ #define Q931_IE_USER_USER 0x7E
+ #define Q931_IE_ESCAPE_FOR_EXT 0x7F
+
++#define Q931_IE_SPECIAL 0x02
++
+
+ /* Call state stuff */
+ #define Q931_CALL_STATE_NULL 0
+@@ -243,7 +249,7 @@
+ /* EuroISDN */
+ #define Q931_SENDING_COMPLETE 0xa1
+
+-extern int q931_receive(struct pri *pri, q931_h *h, int len);
++extern int q931_receive(struct pri *pri, q931_h *h, int len, int tei);
+
+ extern int q931_alerting(struct pri *pri, q931_call *call, int channel, int info);
+
+@@ -257,6 +263,10 @@
+
+ extern int q931_information(struct pri *pri, q931_call *call, char digit);
+
++extern int q931_information_display(struct pri *pri, q931_call *call, char *display);
++
++extern int q931_add_display(struct pri *pri, q931_call *call, char *display);
++
+ extern int q931_connect(struct pri *pri, q931_call *call, int channel, int nonisdn);
+
+ extern int q931_release(struct pri *pri, q931_call *call, int cause);
+@@ -265,6 +275,10 @@
+
+ extern int q931_hangup(struct pri *pri, q931_call *call, int cause);
+
++extern int q921_hangup(struct pri *pri, q931_call *c, int tei);
++
++extern int q921_handle_hangup(struct pri *pri, q931_call *c, int tei);
++
+ extern int q931_restart(struct pri *pri, int channel);
+
+ extern int q931_facility(struct pri *pri, q931_call *call);
+@@ -279,5 +293,23 @@
+ extern void q931_dump(struct pri *pri, q931_h *h, int len, int txrx);
+
+ extern void __q931_destroycall(struct pri *pri, q931_call *c);
++
++extern int q931_hold_acknowledge(struct pri *pri, q931_call *c);
++
++extern int q931_hold_reject(struct pri *pri, q931_call *c);
++
++extern int q931_retrieve_acknowledge(struct pri *pri, q931_call *c, int channel);
+
++extern int q931_retrieve_reject(struct pri *pri, q931_call *c);
++
++extern int q931_suspend_acknowledge(struct pri *pri, q931_call *c, char *display);
++
++extern int q931_suspend_reject(struct pri *pri, q931_call *c, char *display);
++
++extern int q931_resume_reject(struct pri *pri, q931_call *c, char *display);
++
++extern int q931_resume_acknowledge(struct pri *pri, q931_call *c, int channel, char *display);
++
++//extern int q931_facility(struct pri *pri, q931_call *c, int operation, char *arguments);
++
+ #endif
+diff -urNad libpri-1.2.0-release/prisched.c /tmp/dpep.aQ7o1G/libpri-1.2.0-release/prisched.c
+--- libpri-1.2.0-release/prisched.c 2005-06-22 01:47:39.000000000 +0300
++++ /tmp/dpep.aQ7o1G/libpri-1.2.0-release/prisched.c 2005-11-23 04:05:24.961535777 +0200
+@@ -22,10 +22,9 @@
+ *
+ */
+
+-#include <stdio.h>
+-
+ #include "libpri.h"
+ #include "pri_internal.h"
++#include <stdio.h>
+
+
+ static int maxsched = 0;
+@@ -36,7 +35,7 @@
+ int x;
+ struct timeval tv;
+ for (x=1;x<MAX_SCHED;x++)
+- if (!pri->pri_sched[x].callback)
++ if ((!pri->pri_sched[x].callback2) && (!pri->pri_sched[x].callback))
+ break;
+ if (x == MAX_SCHED) {
+ pri_error(pri, "No more room in scheduler\n");
+@@ -53,7 +52,39 @@
+ }
+ pri->pri_sched[x].when = tv;
+ pri->pri_sched[x].callback = function;
++ pri->pri_sched[x].callback2 = NULL;
+ pri->pri_sched[x].data = data;
++ pri->pri_sched[x].hasdata2 = 0;
++ pri->pri_sched[x].data2 = 0;
++ return x;
++}
++
++int pri_schedule_event2(struct pri *pri, int ms, void (*function)(void *data, int data2), void *data, int data2)
++{
++ int x;
++ struct timeval tv;
++ for (x=1;x<MAX_SCHED;x++)
++ if ((!pri->pri_sched[x].callback2) && (!pri->pri_sched[x].callback))
++ break;
++ if (x == MAX_SCHED) {
++ pri_error(pri, "No more room in scheduler\n");
++ return -1;
++ }
++ if (x > maxsched)
++ maxsched = x;
++ gettimeofday(&tv, NULL);
++ tv.tv_sec += ms / 1000;
++ tv.tv_usec += (ms % 1000) * 1000;
++ if (tv.tv_usec > 1000000) {
++ tv.tv_usec -= 1000000;
++ tv.tv_sec += 1;
++ }
++ pri->pri_sched[x].when = tv;
++ pri->pri_sched[x].callback = NULL;
++ pri->pri_sched[x].callback2 = function;
++ pri->pri_sched[x].data = data;
++ pri->pri_sched[x].hasdata2 = 1;
++ pri->pri_sched[x].data2 = data2;
+ return x;
+ }
+
+@@ -65,7 +96,7 @@
+ if (pri->subchannel)
+ closest = pri_schedule_next(pri->subchannel);
+ for (x=1;x<MAX_SCHED;x++) {
+- if (pri->pri_sched[x].callback &&
++ if ((pri->pri_sched[x].callback || pri->pri_sched[x].callback2) &&
+ (!closest || (closest->tv_sec > pri->pri_sched[x].when.tv_sec) ||
+ ((closest->tv_sec == pri->pri_sched[x].when.tv_sec) &&
+ (closest->tv_usec > pri->pri_sched[x].when.tv_usec))))
+@@ -78,24 +109,36 @@
+ {
+ int x;
+ void (*callback)(void *);
++ void (*callback2)(void *, int);
+ void *data;
++ int data2;
+ pri_event *e;
++
+ if (pri->subchannel) {
+ if ((e = __pri_schedule_run(pri->subchannel, tv))) {
+ return e;
+ }
+ }
+ for (x=1;x<MAX_SCHED;x++) {
+- if (pri->pri_sched[x].callback &&
++ if ((pri->pri_sched[x].callback || pri->pri_sched[x].callback2) &&
+ ((pri->pri_sched[x].when.tv_sec < tv->tv_sec) ||
+ ((pri->pri_sched[x].when.tv_sec == tv->tv_sec) &&
+ (pri->pri_sched[x].when.tv_usec <= tv->tv_usec)))) {
+ pri->schedev = 0;
+ callback = pri->pri_sched[x].callback;
++ callback2 = pri->pri_sched[x].callback2;
+ data = pri->pri_sched[x].data;
++ data2 = pri->pri_sched[x].data2;
+ pri->pri_sched[x].callback = NULL;
++ pri->pri_sched[x].callback2 = NULL;
+ pri->pri_sched[x].data = NULL;
+- callback(data);
++ pri->pri_sched[x].data2 = 0;
++ if (pri->pri_sched[x].hasdata2 == 1) {
++ pri->pri_sched[x].hasdata2 = 0;
++ callback2(data, data2);
++ } else {
++ callback(data);
++ }
+ if (pri->schedev)
+ return &pri->ev;
+ }
+@@ -116,4 +159,6 @@
+ if ((id >= MAX_SCHED) || (id < 0))
+ pri_error(pri, "Asked to delete sched id %d???\n", id);
+ pri->pri_sched[id].callback = NULL;
++ pri->pri_sched[id].callback2 = NULL;
+ }
++
+diff -urNad libpri-1.2.0-release/pritest.c /tmp/dpep.aQ7o1G/libpri-1.2.0-release/pritest.c
+--- libpri-1.2.0-release/pritest.c 2005-06-22 01:47:39.000000000 +0300
++++ /tmp/dpep.aQ7o1G/libpri-1.2.0-release/pritest.c 2005-11-23 04:05:24.964535362 +0200
+@@ -51,8 +51,8 @@
+ #define PRI_DEF_NODETYPE PRI_CPE
+ #define PRI_DEF_SWITCHTYPE PRI_SWITCH_NI2
+
+-#define MAX_CHAN 32
+-#define DCHANNEL_TIMESLOT 16
++#define MAX_CHAN 3
++#define DCHANNEL_TIMESLOT 3
+
+
+ static int offset = 0;
+@@ -60,7 +60,7 @@
+ static void do_channel(ZAP *z)
+ {
+ /* This is the part that runs on a given channel */
+- zap_playf(z, "raw.ulaw", 0);
++ zap_playf(z, "raw.alaw", 0);
+ }
+
+ struct pri_chan {
+@@ -76,6 +76,14 @@
+ return PRI_CPE;
+ if (!strcasecmp(node, "network"))
+ return PRI_NETWORK;
++ if (!strcasecmp(node, "bri_cpe_ptmp"))
++ return BRI_CPE_PTMP;
++ if (!strcasecmp(node, "bri_network_ptmp"))
++ return BRI_NETWORK_PTMP;
++ if (!strcasecmp(node, "bri_cpe"))
++ return BRI_CPE;
++ if (!strcasecmp(node, "bri_network"))
++ return BRI_NETWORK;
+ return -1;
+ }
+
+@@ -285,6 +293,10 @@
+ }
+
+ break;
++ case PRI_EVENT_HANGUP_REQ:
++ printf("-- Hanging up channel %d\n", e->hangup.channel);
++ hangup_channel(e->hangup.channel);
++ break;
+ default:
+ fprintf(stderr, "--!! Unknown PRI event %d\n", e->e);
+ }
+diff -urNad libpri-1.2.0-release/pri_timers.h /tmp/dpep.aQ7o1G/libpri-1.2.0-release/pri_timers.h
+--- libpri-1.2.0-release/pri_timers.h 2005-04-09 02:04:37.000000000 +0300
++++ /tmp/dpep.aQ7o1G/libpri-1.2.0-release/pri_timers.h 2005-11-23 04:05:24.966535085 +0200
+@@ -27,17 +27,17 @@
+
+ /* -1 means we dont currently support the timer/counter */
+ #define PRI_TIMERS_DEFAULT { 3, /* N200 */ \
+- -1, /* N201 */ \
+- -1, /* N202 */ \
++ 260, /* N201 */ \
++ 3, /* N202 */ \
+ 7, /* K */ \
+ 1000, /* T200 */ \
+- -1, /* T201 */ \
+- -1, /* T202 */ \
++ 2000, /* T201 */ \
++ 5000, /* T202 */ \
+ 10000, /* T203 */ \
+ -1, /* T300 */ \
+ -1, /* T301 */ \
+ -1, /* T302 */ \
+- -1, /* T303 */ \
++ 4000, /* T303 */ \
+ -1, /* T304 */ \
+ 30000, /* T305 */ \
+ -1, /* T306 */ \
+diff -urNad libpri-1.2.0-release/q921.c /tmp/dpep.aQ7o1G/libpri-1.2.0-release/q921.c
+--- libpri-1.2.0-release/q921.c 2005-06-22 01:47:39.000000000 +0300
++++ /tmp/dpep.aQ7o1G/libpri-1.2.0-release/q921.c 2005-11-23 04:05:24.972534253 +0200
+@@ -5,6 +5,8 @@
+ *
+ * Copyright (C) 2001-2005, Digium
+ * All Rights Reserved.
++ * Copyright (C) 2003,2004,2005 Junghanns.NET GmbH
++ * Klaus-Peter Junghanns <kpj at junghanns.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+@@ -50,19 +52,23 @@
+ (hf).h.tei = (pri)->tei; \
+ } while(0)
+
+-static void reschedule_t203(struct pri *pri);
++static void reschedule_t203(struct pri *pri, int tei);
++static void q921_flush_txqueue(struct pri *pri, int tei, int devnull);
+
+-static void q921_discard_retransmissions(struct pri *pri)
++static void q921_discard_retransmissions(struct pri *pri, int tei)
+ {
+ struct q921_frame *f, *p;
+- f = pri->txqueue;
++ int teio = tei - Q921_TEI_BASE;
++ if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; }
++
++ f = pri->txqueue[teio];
+ while(f) {
+ p = f;
+ f = f->next;
+ /* Free frame */
+ free(p);
+ }
+- pri->txqueue = NULL;
++ pri->txqueue[teio] = NULL;
+ }
+
+ static int q921_transmit(struct pri *pri, q921_h *h, int len)
+@@ -88,11 +94,15 @@
+ pri_error(pri, "Short write: %d/%d (%s)\n", res, len + 2, strerror(errno));
+ return -1;
+ }
+- reschedule_t203(pri);
++ if (pri->localtype == BRI_CPE_PTMP) {
++ reschedule_t203(pri, pri->tei);
++ } else if (h->h.tei != Q921_TEI_GROUP) {
++ reschedule_t203(pri, h->h.tei);
++ }
+ return 0;
+ }
+
+-static void q921_send_ua(struct pri *pri, int pfbit)
++static void q921_send_ua(struct pri *pri, int pfbit, int tei)
+ {
+ q921_h h;
+ Q921_INIT(pri, h);
+@@ -100,6 +110,7 @@
+ h.u.m2 = 0; /* M2 = 0 */
+ h.u.p_f = pfbit; /* Final bit on */
+ h.u.ft = Q921_FRAMETYPE_U;
++ h.h.tei = tei;
+ switch(pri->localtype) {
+ case PRI_NETWORK:
+ h.h.c_r = 0;
+@@ -107,6 +118,19 @@
+ case PRI_CPE:
+ h.h.c_r = 1;
+ break;
++ case BRI_NETWORK_PTMP:
++ h.h.c_r = 0;
++ break;
++ case BRI_CPE_PTMP:
++ h.h.tei = pri->tei;
++ h.h.c_r = 1;
++ break;
++ case BRI_NETWORK:
++ h.h.c_r = 0;
++ break;
++ case BRI_CPE:
++ h.h.c_r = 1;
++ break;
+ default:
+ pri_error(pri, "Don't know how to U/A on a type %d node\n", pri->localtype);
+ return;
+@@ -116,18 +140,326 @@
+ q921_transmit(pri, &h, 3);
+ }
+
+-static void q921_send_sabme_now(void *vpri);
++/*
++static void q921_send_disconnect(struct pri *pri, int pfbit, int tei) {
++ q921_h h;
++ Q921_INIT(pri, h);
++ h.u.m3 = 2;
++ h.u.m2 = 0;
++ h.u.p_f = pfbit;
++ h.u.ft = Q921_FRAMETYPE_U;
++ h.h.tei = tei;
++ switch(pri->localtype) {
++ case PRI_NETWORK:
++ h.h.c_r = 0;
++ break;
++ case PRI_CPE:
++ h.h.c_r = 1;
++ break;
++ case BRI_NETWORK_PTMP:
++ h.h.c_r = 0;
++ break;
++ case BRI_CPE_PTMP:
++ h.h.tei = pri->tei;
++ h.h.c_r = 1;
++ break;
++ case BRI_NETWORK:
++ h.h.c_r = 0;
++ break;
++ case BRI_CPE:
++ h.h.c_r = 1;
++ break;
++ default:
++ pri_error(pri, "Don't know how to disconnect on a type %d node\n", pri->localtype);
++ return;
++ }
++ if (pri->debug & PRI_DEBUG_Q921_STATE)
++ pri_message(pri, "Sending Disconnect\n");
++ q921_transmit(pri, &h, 3);
++ }
++*/
+
+-static void q921_send_sabme(void *vpri, int now)
++static void q921_send_dm(struct pri *pri, int pfbit, int tei)
++{
++ q921_h h;
++ Q921_INIT(pri, h);
++ h.u.m3 = 0; /* M3 = 0 */
++ h.u.m2 = 3; /* M2 = 3 */
++ h.u.p_f = pfbit; /* Final bit on */
++ h.u.ft = Q921_FRAMETYPE_U;
++ h.h.tei = tei;
++ switch(pri->localtype) {
++ case PRI_NETWORK:
++ h.h.c_r = 0;
++ break;
++ case PRI_CPE:
++ h.h.c_r = 1;
++ break;
++ case BRI_NETWORK_PTMP:
++ h.h.c_r = 0;
++ break;
++ case BRI_CPE_PTMP:
++ h.h.tei = pri->tei;
++ h.h.c_r = 1;
++ break;
++ case BRI_NETWORK:
++ h.h.c_r = 0;
++ break;
++ case BRI_CPE:
++ h.h.c_r = 1;
++ break;
++ default:
++ pri_error(pri, "Don't know how to DM on a type %d node\n", pri->localtype);
++ return;
++ }
++ if (pri->debug & PRI_DEBUG_Q921_STATE)
++ pri_message(pri, "Sending DM\n");
++ q921_transmit(pri, &h, 3);
++}
++
++static void q921_send_teireq(void *vpri) {
++ struct pri *pri = vpri;
++ unsigned short ri=0x6464;
++ q921_u *f;
++ ri = rand();
++
++ if (pri->localtype != BRI_CPE_PTMP) {
++ pri_error(pri, "TEI req for non-ptmp???\n");
++ return;
++ }
++ if (pri->t202_timer[0]) {
++ pri_schedule_del(pri, pri->t202_timer[0]);
++ pri->t202_timer[0] = 0;
++ }
++ if (pri->sabme_retrans[0]++ > (pri->timers[PRI_TIMER_N202])) {
++ /* delete txqueue */
++ q921_flush_txqueue(pri, 0, 1);
++ /* N202 retransmissions, activation of layer 2 failed, tell upper layer, start again */
++ pri->schedev = 1;
++ pri->ev.gen.e = PRI_EVENT_DCHAN_DOWN;
++ pri->ev.gen.tei = 0;
++ pri->sabme_retrans[0] = 0;
++ /* dont try again, they are gone */
++ return;
++ }
++
++ pri->t202_timer[0] = pri_schedule_event(pri, pri->timers[PRI_TIMER_T202], q921_send_teireq, pri);
++
++ pri->ri = ri;
++ f = malloc(sizeof(q921_u) + 5 + 2);
++ memset(f,0x0,sizeof(q921_u) + 5 + 2);
++ if (f) {
++ f->h.sapi = Q921_SAPI_LAYER2_MANAGEMENT;
++ f->h.tei = Q921_TEI_GROUP;
++ f->h.c_r = 0;
++ f->h.ea1 = 0;
++ f->h.ea2 = 1;
++ f->m2 = 0;
++ f->m3 = 0;
++ f->ft = Q921_FRAMETYPE_U;
++ f->data[0] = 0xf;
++ f->data[1] = ri >> 8;
++ f->data[2] = ri & 0xff;
++ f->data[3] = Q921_TEI_ID_REQUEST;
++ f->data[4] = 0xff;
++ if (pri->debug & PRI_DEBUG_Q921_STATE)
++ pri_message(pri, "Sending TEI Request ri=%d\n",ri);
++ q921_transmit(pri,(q921_h *)&(f->h),8);
++ }
++}
++
++static void q921_send_teiassign(struct pri *pri,int ri,int tei) {
++ q921_u *f;
++
++ if (pri->localtype != BRI_NETWORK_PTMP) {
++ pri_error(pri, "TEI assign for non-ptmp???\n");
++ return;
++ }
++
++ f = malloc(sizeof(q921_u) + 5 + 2);
++ memset(f,0x0,sizeof(q921_u) + 5 + 2);
++ if (f) {
++ f->h.sapi = Q921_SAPI_LAYER2_MANAGEMENT;
++ f->h.tei = Q921_TEI_GROUP;
++ f->h.c_r = 1;
++ f->h.ea1 = 0;
++ f->h.ea2 = 1;
++ f->m2 = 0;
++ f->m3 = 0;
++ f->ft = Q921_FRAMETYPE_U;
++ f->data[0] = 0xf;
++ f->data[1] = ri >> 8;
++ f->data[2] = ri & 0xff;
++ f->data[3] = Q921_TEI_ID_ASSIGNED;
++ f->data[4] = (tei << 1) | 0x1;
++ if (pri->debug & PRI_DEBUG_Q921_STATE)
++ pri_message(pri, "Sending TEI assign ri=%d tei=%d\n",ri,tei);
++ q921_transmit(pri,(q921_h *)&(f->h),8);
++ free(f);
++ } else {
++ pri_error(pri, "q921_send_teiassign: failed to malloc f!\n");
++ }
++}
++
++static void q921_send_teichkresp(struct pri *pri,int tei) {
++ q921_u *f;
++ unsigned short ri=0x6464;
++ ri = rand();
++
++ if (pri->localtype != BRI_CPE_PTMP) {
++ pri_error(pri, "TEI check response for non-ptmp???\n");
++ return;
++ }
++
++ f = malloc(sizeof(q921_u) + 5 + 2);
++ memset(f,0x0,sizeof(q921_u) + 5 + 2);
++ if (f) {
++ f->h.sapi = Q921_SAPI_LAYER2_MANAGEMENT;
++ f->h.tei = Q921_TEI_GROUP;
++ f->h.c_r = 0; // command u->n
++ f->h.ea1 = 0;
++ f->h.ea2 = 1;
++ f->m2 = 0;
++ f->m3 = 0;
++ f->ft = Q921_FRAMETYPE_U;
++ f->data[0] = 0xf;
++ f->data[1] = ri >> 8;
++ f->data[2] = ri & 0xff;
++ f->data[3] = Q921_TEI_ID_CHK_RES;
++ f->data[4] = (tei << 1) | 0x1;
++ if (pri->debug & PRI_DEBUG_Q921_STATE)
++ pri_message(pri, "Sending TEI check resp ri=%d tei=%d\n",ri,tei);
++ q921_transmit(pri,(q921_h *)&(f->h),8);
++ free(f);
++ }
++}
++
++static void q921_send_teiverify(struct pri *pri,int tei) {
++ q921_u *f;
++
++ if (pri->localtype != BRI_CPE_PTMP) {
++ pri_error(pri, "TEI verify for non-ptmp???\n");
++ return;
++ }
++
++ f = malloc(sizeof(q921_u) + 5 + 2);
++ memset(f,0x0,sizeof(q921_u) + 5 + 2);
++ if (f) {
++ f->h.sapi = Q921_SAPI_LAYER2_MANAGEMENT;
++ f->h.tei = Q921_TEI_GROUP;
++ f->h.c_r = 0; // command u->n
++ f->h.ea1 = 0;
++ f->h.ea2 = 1;
++ f->m2 = 0;
++ f->m3 = 0;
++ f->ft = Q921_FRAMETYPE_U;
++ f->data[0] = 0xf;
++ f->data[1] = 0;
++ f->data[2] = 0;
++ f->data[3] = Q921_TEI_ID_VERIFY;
++ f->data[4] = (tei << 1) | 0x1;
++ if (pri->debug & PRI_DEBUG_Q921_STATE)
++ pri_message(pri, "Sending TEI verify tei=%d\n", tei);
++ q921_transmit(pri,(q921_h *)&(f->h),8);
++ free(f);
++ }
++}
++
++ static void q921_send_teiremove(struct pri *pri, int tei) {
++ q921_u *f;
++ unsigned short ri=0x6464;
++ ri = rand();
++
++ if (pri->localtype != BRI_NETWORK_PTMP) {
++ pri_error(pri, "TEI remove for non-ptmp???\n");
++ return;
++ }
++
++ f = malloc(sizeof(q921_u) + 5 + 2);
++ memset(f,0x0,sizeof(q921_u) + 5 + 2);
++ if (f) {
++ f->h.sapi = Q921_SAPI_LAYER2_MANAGEMENT;
++ f->h.tei = Q921_TEI_GROUP;
++ f->h.c_r = 1;
++ f->h.ea1 = 0;
++ f->h.ea2 = 1;
++ f->m2 = 0;
++ f->m3 = 0;
++ f->ft = Q921_FRAMETYPE_U;
++ f->data[0] = 0xf;
++ f->data[1] = ri >> 8;
++ f->data[2] = ri & 0xff;
++ f->data[3] = Q921_TEI_ID_REMOVE;
++ f->data[4] = (tei << 1) | 0x1;
++ if (pri->debug & PRI_DEBUG_Q921_STATE)
++ pri_message(pri, "Sending TEI remove tei=%d\n",tei);
++ q921_transmit(pri,(q921_h *)&(f->h),8);
++ free(f);
++ }
++ }
++
++ static void q921_send_teidenied(struct pri *pri, int ri, int tei) {
++ q921_u *f;
++
++ if (pri->localtype != BRI_NETWORK_PTMP) {
++ pri_error(pri, "TEI ID denied for non-ptmp???\n");
++ return;
++ }
++
++ f = malloc(sizeof(q921_u) + 5 + 2);
++ memset(f,0x0,sizeof(q921_u) + 5 + 2);
++ if (f) {
++ f->h.sapi = Q921_SAPI_LAYER2_MANAGEMENT;
++ f->h.tei = Q921_TEI_GROUP;
++ f->h.c_r = 1;
++ f->h.ea1 = 0;
++ f->h.ea2 = 1;
++ f->m2 = 0;
++ f->m3 = 0;
++ f->ft = Q921_FRAMETYPE_U;
++ f->data[0] = 0xf;
++ f->data[1] = ri >> 8;
++ f->data[2] = ri & 0xff;
++ f->data[3] = Q921_TEI_ID_DENIED;
++ f->data[4] = (tei << 1) | 0x1;
++ if (pri->debug & PRI_DEBUG_Q921_STATE)
++ pri_message(pri, "Sending TEI ID denied tei=%d\n",tei);
++ q921_transmit(pri,(q921_h *)&(f->h),8);
++ free(f);
++ }
++ }
++
++
++static void q921_send_sabme_now(void *vpri, int tei);
++
++static void q921_send_sabme(void *vpri, int now, int tei)
+ {
+ struct pri *pri = vpri;
+ q921_h h;
+- pri_schedule_del(pri, pri->sabme_timer);
+- pri->sabme_timer = 0;
+- pri->sabme_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T200], q921_send_sabme_now, pri);
++ int teio=tei - Q921_TEI_BASE;
++ if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; }
++
++ if (pri->sabme_timer[teio]) {
++ pri_schedule_del(pri, pri->sabme_timer[teio]);
++ pri->sabme_timer[teio] = 0;
++ }
++ pri->sabme_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T200], q921_send_sabme_now, pri, tei);
+ if (!now)
+ return;
++ if (pri->sabme_retrans[teio]++ > (pri->timers[PRI_TIMER_N202])) {
++ /* delete txqueue */
++ q921_flush_txqueue(pri, tei, 1);
++ /* N202 retransmissions, activation of layer 2 failed, tell upper layer, start again */
++ pri->schedev = 1;
++ pri->ev.gen.e = PRI_EVENT_DCHAN_DOWN;
++ pri->ev.gen.tei = tei;
++ pri->sabme_retrans[teio] = 0;
++ /* dont try again, they are gone */
++ return;
++ }
+ Q921_INIT(pri, h);
++ // XXX
++ h.h.tei = tei;
+ h.u.m3 = 3; /* M3 = 3 */
+ h.u.m2 = 3; /* M2 = 3 */
+ h.u.p_f = 1; /* Poll bit set */
+@@ -139,25 +471,42 @@
+ case PRI_CPE:
+ h.h.c_r = 0;
+ break;
++ case BRI_NETWORK_PTMP:
++ h.h.c_r = 1;
++ break;
++ case BRI_CPE_PTMP:
++ h.h.c_r = 0;
++ h.h.tei = pri->tei;
++ break;
++ case BRI_NETWORK:
++ h.h.c_r = 1;
++ break;
++ case BRI_CPE:
++ h.h.c_r = 0;
++ break;
+ default:
+- pri_error(pri, "Don't know how to U/A on a type %d node\n", pri->localtype);
++ pri_error(pri, "Don't know how to send SABME on a type %d node\n", pri->localtype);
+ return;
+ }
+ if (pri->debug & PRI_DEBUG_Q921_STATE)
+ pri_message(pri, "Sending Set Asynchronous Balanced Mode Extended\n");
+ q921_transmit(pri, &h, 3);
+- pri->q921_state = Q921_AWAITING_ESTABLISH;
++ pri->q921_state[teio] = Q921_AWAITING_ESTABLISH;
+ }
+
+-static void q921_send_sabme_now(void *vpri)
++static void q921_send_sabme_now(void *vpri, int tei)
+ {
+- q921_send_sabme(vpri, 1);
++ q921_send_sabme(vpri, 1, tei);
+ }
+
+-static int q921_ack_packet(struct pri *pri, int num)
++
++
++static int q921_ack_packet(struct pri *pri, int num, int tei)
+ {
+ struct q921_frame *f, *prev = NULL;
+- f = pri->txqueue;
++ int teio=tei - Q921_TEI_BASE;
++ if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; }
++ f = pri->txqueue[teio];
+ while(f) {
+ if (f->h.n_s == num) {
+ /* Cancel each packet as necessary */
+@@ -165,26 +514,26 @@
+ if (prev)
+ prev->next = f->next;
+ else
+- pri->txqueue = f->next;
++ pri->txqueue[teio] = f->next;
+ if (pri->debug & PRI_DEBUG_Q921_STATE)
+- pri_message(pri, "-- ACKing packet %d, new txqueue is %d (-1 means empty)\n", f->h.n_s, pri->txqueue ? pri->txqueue->h.n_s : -1);
++ pri_message(pri, "-- ACKing packet %d, new txqueue is %d (-1 means empty)\n", f->h.n_s, pri->txqueue[teio] ? pri->txqueue[teio]->h.n_s : -1);
+ /* Update v_a */
+- pri->v_a = num;
++ pri->v_a[teio] = num;
+ free(f);
+ /* Reset retransmission counter if we actually acked something */
+- pri->retrans = 0;
++ pri->retrans[teio] = 0;
+ /* Decrement window size */
+- pri->windowlen--;
++ pri->windowlen[teio]--;
+ /* Search for something to send */
+- f = pri->txqueue;
++ f = pri->txqueue[teio];
+ while(f) {
+ if (!f->transmitted) {
+ /* Send it now... */
+ if (pri->debug & PRI_DEBUG_Q921_STATE)
+ pri_message(pri, "-- Finally transmitting %d, since window opened up\n", f->h.n_s);
+ f->transmitted++;
+- pri->windowlen++;
+- f->h.n_r = pri->v_r;
++ pri->windowlen[teio]++;
++ f->h.n_r = pri->v_r[teio];
+ q921_transmit(pri, (q921_h *)(&f->h), f->len);
+ break;
+ }
+@@ -198,77 +547,136 @@
+ return 0;
+ }
+
+-static void t203_expire(void *);
+-static void t200_expire(void *);
+-static pri_event *q921_dchannel_down(struct pri *pri);
++static void t203_expire(void *, int tei);
++static void t200_expire(void *, int tei);
++static pri_event *q921_dchannel_down(struct pri *pri, int tei);
+
+-static void reschedule_t203(struct pri *pri)
++static void reschedule_t203(struct pri *pri, int tei)
+ {
+- if (pri->t203_timer) {
+- pri_schedule_del(pri, pri->t203_timer);
+- if (pri->debug & PRI_DEBUG_Q921_STATE)
+- pri_message(pri, "-- Restarting T203 counter\n");
+- /* Nothing to transmit, start the T203 counter instead */
+- pri->t203_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T203], t203_expire, pri);
++ int teio=tei - Q921_TEI_BASE;
++ if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; }
++ if (pri->t203_timer[teio]) {
++ pri_schedule_del(pri, pri->t203_timer[teio]);
++ pri->t203_timer[teio] = 0;
++ if (pri->q921_state[teio] != Q921_LINK_CONNECTION_RELEASED) {
++ if (pri->debug & PRI_DEBUG_Q921_STATE)
++ pri_message(pri, "-- Restarting T203 counter\n");
++ /* Nothing to transmit, start the T203 counter instead */
++ pri->t203_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T203], t203_expire, pri, tei);
++ }
++ }
++}
++
++static void q921_flush_txqueue(struct pri *pri, int tei, int devnull)
++{
++ struct q921_frame *f, *tmp = NULL;
++ int teio=tei - Q921_TEI_BASE;
++ if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; }
++ f = pri->txqueue[teio];
++
++ /* nothing to send */
++ if (!f) return;
++
++ /* transmit all i-frames that were queued up while we were waiting for layer 2 to rise */
++ while(f) {
++ if (devnull) {
++ tmp = f;
++ f = f->next;
++ free(tmp);
++ tmp = NULL;
++ } else {
++ if (pri->localtype == BRI_CPE_PTMP) {
++ /* update TEI, it might have changed */
++ f->h.h.tei = pri->tei;
++ }
++ q921_transmit(pri, (q921_h *)&f->h, f->len);
++ f->transmitted++;
++ f = f->next;
++ }
++ }
++
++ if (devnull) {
++ pri->txqueue[teio] = NULL;
++ pri->v_s[teio] = 0;
++ } else {
++ if (pri->t200_timer[teio]) {
++ pri_schedule_del(pri, pri->t200_timer[teio]);
++ pri->t200_timer[teio] = 0;
++ }
++ if (pri->t203_timer[teio]) {
++ pri_schedule_del(pri, pri->t203_timer[teio]);
++ pri->t203_timer[teio] = 0;
++ }
++ pri->t200_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri, tei);
+ }
+ }
+
+-static pri_event *q921_ack_rx(struct pri *pri, int ack)
++static pri_event *q921_ack_rx(struct pri *pri, int ack, int tei)
+ {
+ int x;
+ int cnt=0;
+ pri_event *ev;
++ int teio=tei - Q921_TEI_BASE;
++ if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; }
+ /* Make sure the ACK was within our window */
+- for (x=pri->v_a; (x != pri->v_s) && (x != ack); Q921_INC(x));
++ for (x=pri->v_a[teio]; (x != pri->v_s[teio]) && (x != ack); Q921_INC(x));
+ if (x != ack) {
+ /* ACK was outside of our window --- ignore */
+- pri_error(pri, "ACK received for '%d' outside of window of '%d' to '%d', restarting\n", ack, pri->v_a, pri->v_s);
+- ev = q921_dchannel_down(pri);
+- q921_start(pri, 1);
++ pri_error(pri, "ACK received for '%d' outside of window of '%d' to '%d', restarting\n", ack, pri->v_a[teio], pri->v_s[teio]);
++ ev = q921_dchannel_down(pri, tei);
++ q921_start(pri, 1, tei);
+ pri->schedev = 1;
+ return ev;
+ }
+ /* Cancel each packet as necessary */
+ if (pri->debug & PRI_DEBUG_Q921_STATE)
+- pri_message(pri, "-- ACKing all packets from %d to (but not including) %d\n", pri->v_a, ack);
+- for (x=pri->v_a; x != ack; Q921_INC(x))
+- cnt += q921_ack_packet(pri, x);
+- if (!pri->txqueue) {
++ pri_message(pri, "-- ACKing all packets from %d to (but not including) %d\n", pri->v_a[teio], ack);
++ for (x=pri->v_a[teio]; x != ack; Q921_INC(x))
++ cnt += q921_ack_packet(pri, x, tei);
++ if (!pri->txqueue[teio]) {
+ if (pri->debug & PRI_DEBUG_Q921_STATE)
+ pri_message(pri, "-- Since there was nothing left, stopping T200 counter\n");
+ /* Something was ACK'd. Stop T200 counter */
+- pri_schedule_del(pri, pri->t200_timer);
+- pri->t200_timer = 0;
++ if (pri->t200_timer[teio]) {
++ pri_schedule_del(pri, pri->t200_timer[teio]);
++ pri->t200_timer[teio] = 0;
++ }
+ }
+- if (pri->t203_timer) {
++ if (pri->t203_timer[teio]) {
+ if (pri->debug & PRI_DEBUG_Q921_STATE)
+ pri_message(pri, "-- Stopping T203 counter since we got an ACK\n");
+- pri_schedule_del(pri, pri->t203_timer);
+- pri->t203_timer = 0;
++ pri_schedule_del(pri, pri->t203_timer[teio]);
++ pri->t203_timer[teio] = 0;
+ }
+- if (pri->txqueue) {
++ if (pri->txqueue[teio]) {
+ /* Something left to transmit, Start the T200 counter again if we stopped it */
+ if (pri->debug & PRI_DEBUG_Q921_STATE)
+- pri_message(pri, "-- Something left to transmit (%d), restarting T200 counter\n", pri->txqueue->h.n_s);
+- if (!pri->t200_timer)
+- pri->t200_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri);
++ pri_message(pri, "-- Something left to transmit (%d), restarting T200 counter\n", pri->txqueue[teio]->h.n_s);
++ if (pri->t200_timer[teio]) {
++ pri_schedule_del(pri, pri->t200_timer[teio]);
++ pri->t200_timer[teio] = 0;
++ }
++ pri->t200_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri, tei);
++
+ } else {
+ if (pri->debug & PRI_DEBUG_Q921_STATE)
+ pri_message(pri, "-- Nothing left, starting T203 counter\n");
+ /* Nothing to transmit, start the T203 counter instead */
+- pri->t203_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T203], t203_expire, pri);
++ pri->t203_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T203], t203_expire, pri, tei);
+ }
+ return NULL;
+ }
+
+-static void q921_reject(struct pri *pri, int pf)
++static void q921_reject(struct pri *pri, int pf, int tei)
+ {
+ q921_h h;
++ int teio=tei - Q921_TEI_BASE;
++ if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; }
+ Q921_INIT(pri, h);
+ h.s.x0 = 0; /* Always 0 */
+ h.s.ss = 2; /* Reject */
+ h.s.ft = 1; /* Frametype (01) */
+- h.s.n_r = pri->v_r; /* Where to start retransmission */
++ h.s.n_r = pri->v_r[teio]; /* Where to start retransmission */
+ h.s.p_f = pf;
+ switch(pri->localtype) {
+ case PRI_NETWORK:
+@@ -277,23 +685,38 @@
+ case PRI_CPE:
+ h.h.c_r = 1;
+ break;
++ case BRI_NETWORK_PTMP:
++ h.h.c_r = 0;
++ break;
++ case BRI_CPE_PTMP:
++ h.h.c_r = 1;
++ h.h.tei = tei;
++ break;
++ case BRI_NETWORK:
++ h.h.c_r = 0;
++ break;
++ case BRI_CPE:
++ h.h.c_r = 1;
++ break;
+ default:
+- pri_error(pri, "Don't know how to U/A on a type %d node\n", pri->localtype);
++ pri_error(pri, "Don't know how to REJECT on a type %d node\n", pri->localtype);
+ return;
+ }
+ if (pri->debug & PRI_DEBUG_Q921_STATE)
+- pri_message(pri, "Sending Reject (%d)\n", pri->v_r);
+- pri->sentrej = 1;
++ pri_message(pri, "Sending Reject (%d)\n", pri->v_r[teio]);
++ pri->sentrej[teio] = 1;
+ q921_transmit(pri, &h, 4);
+ }
+
+-static void q921_rr(struct pri *pri, int pbit, int cmd) {
++static void q921_rr(struct pri *pri, int pbit, int cmd, int tei) {
+ q921_h h;
++ int teio=tei - Q921_TEI_BASE;
++ if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; }
+ Q921_INIT(pri, h);
+ h.s.x0 = 0; /* Always 0 */
+ h.s.ss = 0; /* Receive Ready */
+ h.s.ft = 1; /* Frametype (01) */
+- h.s.n_r = pri->v_r; /* N/R */
++ h.s.n_r = pri->v_r[teio]; /* N/R */
+ h.s.p_f = pbit; /* Poll/Final set appropriately */
+ switch(pri->localtype) {
+ case PRI_NETWORK:
+@@ -308,81 +731,192 @@
+ else
+ h.h.c_r = 1;
+ break;
++ case BRI_NETWORK_PTMP:
++ h.h.tei = tei;
++ if (cmd)
++ h.h.c_r = 1;
++ else
++ h.h.c_r = 0;
++ break;
++ case BRI_CPE_PTMP:
++ h.h.tei = tei;
++ if (cmd)
++ h.h.c_r = 0;
++ else
++ h.h.c_r = 1;
++ break;
++ case BRI_NETWORK:
++ if (cmd)
++ h.h.c_r = 1;
++ else
++ h.h.c_r = 0;
++ break;
++ case BRI_CPE:
++ if (cmd)
++ h.h.c_r = 0;
++ else
++ h.h.c_r = 1;
++ break;
+ default:
+- pri_error(pri, "Don't know how to U/A on a type %d node\n", pri->localtype);
++ pri_error(pri, "Don't know how to RR on a type %d node\n", pri->localtype);
+ return;
+ }
+- pri->v_na = pri->v_r; /* Make a note that we've already acked this */
++ pri->v_na[teio] = pri->v_r[teio]; /* Make a note that we've already acked this */
+ if (pri->debug & PRI_DEBUG_Q921_STATE)
+- pri_message(pri, "Sending Receiver Ready (%d)\n", pri->v_r);
++ pri_message(pri, "Sending Receiver Ready (%d)\n", pri->v_r[teio]);
+ q921_transmit(pri, &h, 4);
+ }
+
+-static void t200_expire(void *vpri)
++static void t200_expire(void *vpri, int tei)
+ {
+ struct pri *pri = vpri;
+- if (pri->txqueue) {
++ int teio=tei - Q921_TEI_BASE;
++ if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; }
++ if (pri->txqueue[teio]) {
+ /* Retransmit first packet in the queue, setting the poll bit */
+ if (pri->debug & PRI_DEBUG_Q921_STATE)
+ pri_message(pri, "-- T200 counter expired, What to do...\n");
+- /* Force Poll bit */
+- pri->txqueue->h.p_f = 1;
+- /* Update nr */
+- pri->txqueue->h.n_r = pri->v_r;
+- pri->v_na = pri->v_r;
+- pri->solicitfbit = 1;
+- pri->retrans++;
++ if (pri->txqueue[teio]->transmitted) {
++ /* Force Poll bit, if this is a retransmission */
++ pri->txqueue[teio]->h.p_f = 1;
++ pri->solicitfbit[teio] = 1;
++ /* Update nr */
++ pri->txqueue[teio]->h.n_r = pri->v_r[teio];
++ pri->v_na[teio] = pri->v_r[teio];
++ pri->retrans[teio]++;
++ }
+ /* Up to three retransmissions */
+- if (pri->retrans < pri->timers[PRI_TIMER_N200]) {
++ if ((pri->retrans[teio] + 1) <= pri->timers[PRI_TIMER_N200]) {
+ /* Reschedule t200_timer */
+ if (pri->debug & PRI_DEBUG_Q921_STATE)
+- pri_message(pri, "-- Retransmitting %d bytes\n", pri->txqueue->len);
+- if (pri->busy)
+- q921_rr(pri, 1, 0);
+- else {
+- if (!pri->txqueue->transmitted)
++ pri_message(pri, "-- Retransmitting %d bytes\n", pri->txqueue[teio]->len);
++ if (pri->busy[teio]) {
++ // pri_message(pri, "-- q921_rr(pri, 1, 1) \n", tei);
++ q921_rr(pri, 1, 1, tei);
++ } else {
++ if (!pri->txqueue[teio]->transmitted)
+ pri_error(pri, "!! Not good - head of queue has not been transmitted yet\n");
+- q921_transmit(pri, (q921_h *)&pri->txqueue->h, pri->txqueue->len);
++ q921_transmit(pri, (q921_h *)&pri->txqueue[teio]->h, pri->txqueue[teio]->len);
++ //layer 3
++ pri->txqueue[teio]->transmitted++;
+ }
+ if (pri->debug & PRI_DEBUG_Q921_STATE)
+- pri_message(pri, "-- Rescheduling retransmission (%d)\n", pri->retrans);
+- pri->t200_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri);
++ pri_message(pri, "-- Rescheduling retransmission (%d)\n", pri->retrans[teio]);
++ pri->t200_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri, tei);
+ } else {
+ if (pri->debug & PRI_DEBUG_Q921_STATE)
+ pri_message(pri, "-- Timeout occured, restarting PRI\n");
+- pri->q921_state = Q921_LINK_CONNECTION_RELEASED;
+- pri->t200_timer = 0;
+- q921_dchannel_down(pri);
+- q921_start(pri, 1);
++ pri->q921_state[teio] = Q921_LINK_CONNECTION_RELEASED;
++ pri->t200_timer[teio] = 0;
++ q921_dchannel_down(pri, tei);
++ q921_start(pri, 1, tei);
+ pri->schedev = 1;
+ }
+- } else if (pri->solicitfbit) {
++ } else if (pri->solicitfbit[teio]) {
+ if (pri->debug & PRI_DEBUG_Q921_STATE)
+ pri_message(pri, "-- Retrying poll with f-bit\n");
+- pri->retrans++;
+- if (pri->retrans < pri->timers[PRI_TIMER_N200]) {
+- pri->solicitfbit = 1;
+- q921_rr(pri, 1, 1);
+- pri->t200_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri);
++ pri->retrans[teio]++;
++ if (pri->retrans[teio] < pri->timers[PRI_TIMER_N200]) {
++ pri->solicitfbit[teio] = 1;
++ q921_rr(pri, 1, 1, tei);
++ pri->t200_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri, tei);
+ } else {
+ if (pri->debug & PRI_DEBUG_Q921_STATE)
+ pri_message(pri, "-- Timeout occured, restarting PRI\n");
+- pri->q921_state = Q921_LINK_CONNECTION_RELEASED;
+- pri->t200_timer = 0;
+- q921_dchannel_down(pri);
+- q921_start(pri, 1);
++ pri->q921_state[teio] = Q921_LINK_CONNECTION_RELEASED;
++ pri->t200_timer[teio] = 0;
++ q921_dchannel_down(pri, tei);
++ q921_start(pri, 1, tei);
+ pri->schedev = 1;
+ }
+ } else {
+ pri_error(pri, "T200 counter expired, nothing to send...\n");
+- pri->t200_timer = 0;
++ pri->t200_timer[teio] = 0;
++ if (pri->busy[teio]) {
++ if ((pri->retrans[teio] + 1) <= pri->timers[PRI_TIMER_N200]) {
++ /* poll RR */
++ pri->t200_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri, tei);
++ pri->retrans[teio]++;
++ q921_rr(pri, 1, 1, tei);
++ } else {
++ q921_reset(pri, tei, 1);
++ q921_start(pri, 1, tei);
++ }
++ }
+ }
+ }
+
+-int q921_transmit_iframe(struct pri *pri, void *buf, int len, int cr)
++int q921_transmit_uframe(struct pri *pri, void *buf, int len, int cr, int tei)
++{
++ q921_u *uf;
++ uf = malloc(sizeof(q921_u) + len + 2);
++ memset(uf,0,sizeof(q921_u) + len + 2);
++
++ uf->h.sapi = 0;
++ uf->h.ea1 = 0;
++ uf->h.ea2 = 1;
++ uf->h.tei = tei;
++ uf->m3 = 0;
++ uf->m2 = 0;
++ uf->ft = Q921_FRAMETYPE_U;
++ switch(pri->localtype) {
++ case PRI_NETWORK:
++ uf->h.c_r = 1;
++ break;
++ case PRI_CPE:
++ uf->h.c_r = 0;
++ break;
++ case BRI_NETWORK_PTMP:
++ uf->h.c_r = 1;
++ break;
++ case BRI_CPE_PTMP:
++ uf->h.c_r = 0;
++ break;
++ case BRI_NETWORK:
++ uf->h.c_r = 1;
++ break;
++ case BRI_CPE:
++ uf->h.c_r = 0;
++ break;
++ default:
++ pri_error(pri, "Don't know how to send U frames on a type %d node\n", pri->localtype);
++ return -1;
++ }
++ memcpy(uf->data,buf,len);
++ q921_transmit(pri, (q921_h*)&(uf->h), 3+len);
++ free(uf);
++ return 0;
++}
++
++
++int q921_transmit_iframe(struct pri *pri, void *buf, int len, int cr, int tei)
+ {
+ q921_frame *f, *prev=NULL;
+- for (f=pri->txqueue; f; f = f->next) prev = f;
++ int teio=tei - Q921_TEI_BASE;
++ if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; }
++ if ((pri->q921_state[teio] == Q921_LINK_CONNECTION_RELEASED) && (!pri->sabme_timer[teio])) {
++ if (pri->localtype == BRI_CPE_PTMP) {
++ if (pri->tei > 0) {
++ /* p2p datalink is down */
++ pri->sabme_retrans[teio] = 0;
++ q921_send_sabme_now(pri, pri->tei);
++ if (pri->debug & PRI_DEBUG_Q921_STATE)
++ pri_message(pri, "Reactivating layer 2\n");
++ } else {
++ /* no tei */
++ if (pri->debug & PRI_DEBUG_Q921_STATE)
++ pri_message(pri, "reactivating layer 2, sending tei req\n");
++ q921_send_teireq(pri);
++ }
++ } else if ((pri->localtype == BRI_CPE) || (pri->localtype == BRI_NETWORK)) {
++ /* p2p datalink is down */
++ pri->sabme_retrans[teio] = 0;
++ q921_send_sabme_now(pri, pri->tei);
++ if (pri->debug & PRI_DEBUG_Q921_STATE)
++ pri_message(pri, "Reactivating layer 2\n");
++ }
++ }
++ for (f=pri->txqueue[teio]; f; f = f->next) prev = f;
+ f = malloc(sizeof(q921_frame) + len + 2);
+ if (f) {
+ memset(f,0,sizeof(q921_frame) + len + 2);
+@@ -400,47 +934,80 @@
+ else
+ f->h.h.c_r = 1;
+ break;
++ case BRI_NETWORK_PTMP:
++ f->h.h.tei = tei;
++ if (cr)
++ f->h.h.c_r = 1;
++ else
++ f->h.h.c_r = 0;
++ break;
++ case BRI_CPE_PTMP:
++ f->h.h.tei = pri->tei;
++ if (cr)
++ f->h.h.c_r = 0;
++ else
++ f->h.h.c_r = 1;
++ break;
++ case BRI_NETWORK:
++ if (cr)
++ f->h.h.c_r = 1;
++ else
++ f->h.h.c_r = 0;
++ break;
++ case BRI_CPE:
++ if (cr)
++ f->h.h.c_r = 0;
++ else
++ f->h.h.c_r = 1;
++ break;
+ }
+ f->next = NULL;
+ f->transmitted = 0;
+ f->len = len + 4;
+ memcpy(f->h.data, buf, len);
+- f->h.n_s = pri->v_s;
+- f->h.n_r = pri->v_r;
+- pri->v_s++;
+- pri->v_na = pri->v_r;
++ f->h.n_s = pri->v_s[teio];
++ f->h.n_r = pri->v_r[teio];
++ pri->v_s[teio]++;
++ pri->v_na[teio] = pri->v_r[teio];
+ f->h.p_f = 0;
+ f->h.ft = 0;
+ if (prev)
+ prev->next = f;
+ else
+- pri->txqueue = f;
+- /* Immediately transmit unless we're in a recovery state, or the window
+- size is too big */
+- if (!pri->retrans && !pri->busy) {
+- if (pri->windowlen < pri->window) {
+- pri->windowlen++;
++ pri->txqueue[teio] = f;
++
++ if ((pri->q921_state[teio] != Q921_LINK_CONNECTION_ESTABLISHED) && ((pri->localtype == BRI_CPE_PTMP) || (pri->localtype == BRI_CPE) || (pri->localtype == BRI_NETWORK))){
++ /* no p2p datalink, yet. queue up the iframes... */
++ if (pri->debug & PRI_DEBUG_Q921_STATE)
++ pri_message(pri, "Layer 3 transmit waiting for layer 2\n");
++ } else {
++ /* Immediately transmit unless we're in a recovery state, or the window
++ size is too big */
++ if (!pri->retrans[teio] && !pri->busy[teio]) {
++ if (pri->windowlen[teio] < pri->window[teio]) {
++ pri->windowlen[teio]++;
+ q921_transmit(pri, (q921_h *)(&f->h), f->len);
+ f->transmitted++;
+ } else {
+ if (pri->debug & PRI_DEBUG_Q921_STATE)
+ pri_message(pri, "Delaying transmission of %d, window is %d/%d long\n",
+- f->h.n_s, pri->windowlen, pri->window);
++ f->h.n_s, pri->windowlen[teio], pri->window[teio]);
+ }
+- }
+- if (pri->t203_timer) {
++ }
++ if (pri->t203_timer[teio]) {
+ if (pri->debug & PRI_DEBUG_Q921_STATE)
+ pri_message(pri, "Stopping T_203 timer\n");
+- pri_schedule_del(pri, pri->t203_timer);
+- pri->t203_timer = 0;
+- }
+- if (!pri->t200_timer) {
++ pri_schedule_del(pri, pri->t203_timer[teio]);
++ pri->t203_timer[teio] = 0;
++ }
++ if (!pri->t200_timer[teio]) {
+ if (pri->debug & PRI_DEBUG_Q921_STATE)
+ pri_message(pri, "Starting T_200 timer\n");
+- pri->t200_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri);
+- } else
++ pri->t200_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri, tei);
++ } else
+ if (pri->debug & PRI_DEBUG_Q921_STATE)
+- pri_message(pri, "T_200 timer already going (%d)\n", pri->t200_timer);
++ pri_message(pri, "T_200 timer already going (%d)\n", pri->t200_timer[teio]);
++ }
+
+ } else {
+ pri_error(pri, "!! Out of memory for Q.921 transmit\n");
+@@ -449,49 +1016,61 @@
+ return 0;
+ }
+
+-static void t203_expire(void *vpri)
++static void t203_expire(void *vpri, int tei)
+ {
+- struct pri *pri = vpri;
+- if (pri->q921_state == Q921_LINK_CONNECTION_ESTABLISHED) {
+- if (pri->debug & PRI_DEBUG_Q921_STATE)
++ struct pri *pri = vpri;
++ int teio=tei - Q921_TEI_BASE;
++ if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; }
++
++ if (pri->q921_state[teio] == Q921_LINK_CONNECTION_ESTABLISHED) {
++ if (pri->debug & PRI_DEBUG_Q921_STATE)
+ pri_message(pri, "T203 counter expired, sending RR and scheduling T203 again\n");
+- /* Solicit an F-bit in the other's RR */
+- pri->solicitfbit = 1;
+- pri->retrans = 0;
+- q921_rr(pri, 1, 1);
+- /* Start timer T200 to resend our RR if we don't get it */
+- pri->t203_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri);
+- } else {
+- if (pri->debug & PRI_DEBUG_Q921_STATE)
+- pri_message(pri, "T203 counter expired in weird state %d\n", pri->q921_state);
+- pri->t203_timer = 0;
+- }
++ /* Solicit an F-bit in the other's RR */
++ pri->solicitfbit[teio] = 1;
++ pri->retrans[teio] = 0;
++ q921_rr(pri, 1, 1, tei);
++ /* Start timer T200 to resend our RR if we don't get it */
++ pri->t203_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri, tei);
++ } else {
++ if (pri->debug & PRI_DEBUG_Q921_STATE)
++ pri_message(pri, "T203 counter expired in weird state %d\n", pri->q921_state[teio]);
++ pri->t203_timer[teio] = 0;
++ }
+ }
+
+ static pri_event *q921_handle_iframe(struct pri *pri, q921_i *i, int len)
+ {
+ int res;
+ pri_event *ev;
++ int teio= i->h.tei - Q921_TEI_BASE;
++ if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; }
++// pri_error(pri, "q921_handle_iframe: i->n_s %d pri->v_r[%d] %d \n", i->n_s, teio, pri->v_r[teio]);
+ /* Make sure this is a valid packet */
+- if (i->n_s == pri->v_r) {
++ if (i->n_s == pri->v_r[teio]) {
+ /* Increment next expected I-frame */
+- Q921_INC(pri->v_r);
++ Q921_INC(pri->v_r[teio]);
+ /* Handle their ACK */
+- pri->sentrej = 0;
+- ev = q921_ack_rx(pri, i->n_r);
++ pri->sentrej[teio] = 0;
++ ev = q921_ack_rx(pri, i->n_r, i->h.tei);
++ if (ev) {
++ pri_error(pri, "q921_handle_iframe: ev = %d \n", ev->e);
++ }
+ if (ev)
+ return ev;
+ if (i->p_f) {
+ /* If the Poll/Final bit is set, immediate send the RR */
+- q921_rr(pri, 1, 0);
+- } else if (pri->busy) {
+- q921_rr(pri, 0, 0);
++ q921_rr(pri, 1, 0, i->h.tei);
++ } else if (pri->busy[teio]) {
++ q921_rr(pri, 0, 0, i->h.tei);
++ } else if (pri->t200_timer[teio] && pri->retrans[teio]) {
++ pri_error(pri, "q921_handle_iframe: sending RR \n");
++ q921_rr(pri, 0, 0, i->h.tei);
+ }
+ /* Receive Q.931 data */
+- res = q931_receive(pri, (q931_h *)i->data, len - 4);
++ res = q931_receive(pri, (q931_h *)i->data, len - 4, i->h.tei);
+ /* Send an RR if one wasn't sent already */
+- if (pri->v_na != pri->v_r)
+- q921_rr(pri, 0, 0);
++ if (pri->v_na[teio] != pri->v_r[teio])
++ q921_rr(pri, 0, 0, i->h.tei);
+ if (res == -1) {
+ return NULL;
+ }
+@@ -500,10 +1079,10 @@
+ } else {
+ /* If we haven't already sent a reject, send it now, otherwise
+ we are obliged to RR */
+- if (!pri->sentrej)
+- q921_reject(pri, i->p_f);
++ if (!pri->sentrej[teio])
++ q921_reject(pri, i->p_f, i->h.tei);
+ else if (i->p_f)
+- q921_rr(pri, 1, 0);
++ q921_rr(pri, 1, 0, i->h.tei);
+ }
+ return NULL;
+ }
+@@ -641,62 +1220,113 @@
+ };
+ }
+
+-static pri_event *q921_dchannel_up(struct pri *pri)
++static pri_event *q921_dchannel_up(struct pri *pri, int tei)
+ {
+- /* Reset counters, etc */
+- q921_reset(pri);
++ // we treat this as MFE
++ int teio=tei - Q921_TEI_BASE;
++ if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; }
++
++ if (((pri->localtype == BRI_CPE_PTMP) || (pri->localtype == BRI_CPE) || (pri->localtype == BRI_NETWORK)) && (pri->txqueue[teio])) {
++ /* Reset counters, etc */
++ q921_reset(pri, tei, 0);
++ } else {
++ /* Reset counters, discard frames, etc */
++ q921_reset(pri, tei, 1);
++ }
+
+ /* Stop any SABME retransmissions */
+- pri_schedule_del(pri, pri->sabme_timer);
+- pri->sabme_timer = 0;
++ if (pri->sabme_timer[teio]) {
++ pri_schedule_del(pri, pri->sabme_timer[teio]);
++ pri->sabme_timer[teio] = 0;
++ }
++
++ if (pri->t202_timer[teio]) {
++ pri_schedule_del(pri, pri->t202_timer[teio]);
++ pri->t202_timer[teio] = 0;
++ }
+
+ /* Reset any rejects */
+- pri->sentrej = 0;
++ pri->sentrej[teio] = 0;
+
+ /* Go into connection established state */
+- pri->q921_state = Q921_LINK_CONNECTION_ESTABLISHED;
+-
+- /* Start the T203 timer */
+- pri->t203_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T203], t203_expire, pri);
++ pri->q921_state[teio] = Q921_LINK_CONNECTION_ESTABLISHED;
+
+- /* Report event that D-Channel is now up */
+- pri->ev.gen.e = PRI_EVENT_DCHAN_UP;
+- return &pri->ev;
++ if (((pri->localtype == BRI_CPE_PTMP) || (pri->localtype == BRI_CPE) || (pri->localtype == BRI_NETWORK)) && (pri->txqueue[teio])) {
++ /* transmit queued iframes ans start T200 (handled by flush_txqueue) */
++ q921_flush_txqueue(pri, tei, 0);
++ /* dont upset upper layers if we reactivate layer 2 */
++ return NULL;
++ } else {
++ /* Start the T203 timer */
++ pri->t203_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T203], t203_expire, pri, tei);
++
++ /* Report event that D-Channel is now up */
++ pri->ev.gen.e = PRI_EVENT_DCHAN_UP;
++ pri->ev.gen.tei = tei;
++ return &pri->ev;
++ }
+ }
+
+-static pri_event *q921_dchannel_down(struct pri *pri)
++static pri_event *q921_dchannel_down(struct pri *pri, int tei)
+ {
++ int teio=tei - Q921_TEI_BASE;
++ if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; }
++
++ pri->q921_state[teio] = Q921_LINK_CONNECTION_RELEASED;
++
+ /* Reset counters, reset sabme timer etc */
+- q921_reset(pri);
++ if (pri->localtype == BRI_NETWORK_PTMP) {
++ if (pri->t203_timer[teio]) {
++ if (pri->debug & PRI_DEBUG_Q921_STATE) {
++ pri_message(pri, "Stopping T_203 timer for TEI %d\n", tei);
++ }
++ pri_schedule_del(pri, pri->t203_timer[teio]);
++ pri->t203_timer[teio] = 0;
++ }
++ }
++
++ q921_reset(pri, tei, 1);
+
+- /* Report event that D-Channel is now up */
++ /* Report event that D-Channel is now down */
+ pri->ev.gen.e = PRI_EVENT_DCHAN_DOWN;
++ pri->ev.gen.tei = tei;
+ return &pri->ev;
+ }
+
+-void q921_reset(struct pri *pri)
++void q921_reset(struct pri *pri, int tei, int discard)
+ {
++ int teio=tei - Q921_TEI_BASE;
++ if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; }
+ /* Having gotten a SABME we MUST reset our entire state */
+- pri->v_s = 0;
+- pri->v_a = 0;
+- pri->v_r = 0;
+- pri->v_na = 0;
+- pri->window = pri->timers[PRI_TIMER_K];
+- pri->windowlen = 0;
+- pri_schedule_del(pri, pri->sabme_timer);
+- pri_schedule_del(pri, pri->t203_timer);
+- pri_schedule_del(pri, pri->t200_timer);
+- pri->sabme_timer = 0;
+- pri->t203_timer = 0;
+- pri->t200_timer = 0;
+- pri->busy = 0;
+- pri->solicitfbit = 0;
+- pri->q921_state = Q921_LINK_CONNECTION_RELEASED;
+- pri->retrans = 0;
+- pri->sentrej = 0;
++ if (discard) {
++ pri->v_s[teio] = 0;
++ }
++ pri->v_a[teio] = 0;
++ pri->v_r[teio] = 0;
++ pri->v_na[teio] = 0;
++ pri->window[teio] = pri->timers[PRI_TIMER_K];
++ pri->windowlen[teio] = 0;
++ pri_schedule_del(pri, pri->sabme_timer[teio]);
++ pri_schedule_del(pri, pri->t203_timer[teio]);
++ pri_schedule_del(pri, pri->t200_timer[teio]);
++ pri->sabme_timer[teio] = 0;
++ pri->t203_timer[teio] = 0;
++ pri->t200_timer[teio] = 0;
++ pri_schedule_del(pri, pri->t202_timer[teio]);
++ pri->t202_timer[teio] = 0;
++ pri_schedule_del(pri, pri->t201_timer[teio]);
++ pri->t201_timer[teio] = 0;
++ pri->busy[teio] = 0;
++ pri->solicitfbit[teio] = 0;
++ pri->q921_state[teio] = Q921_LINK_CONNECTION_RELEASED;
++ pri->retrans[teio] = 0;
++ pri->sabme_retrans[teio] = 0;
++ pri->sentrej[teio] = 0;
+
+- /* Discard anything waiting to go out */
+- q921_discard_retransmissions(pri);
++ if (discard) {
++ /* Discard anything waiting to go out */
++ q921_discard_retransmissions(pri, tei);
++ }
+ }
+
+ static pri_event *__q921_receive_qualified(struct pri *pri, q921_h *h, int len)
+@@ -704,12 +1334,16 @@
+ q921_frame *f;
+ pri_event *ev;
+ int sendnow;
++ int tei;
++ int res=-1;
++ int teio=h->h.tei - Q921_TEI_BASE;
++ if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; }
+
+ switch(h->h.data[0] & Q921_FRAMETYPE_MASK) {
+ case 0:
+ case 2:
+- if (pri->q921_state != Q921_LINK_CONNECTION_ESTABLISHED) {
+- pri_error(pri, "!! Got I-frame while link state %d\n", pri->q921_state);
++ if (pri->q921_state[teio] != Q921_LINK_CONNECTION_ESTABLISHED) {
++ pri_error(pri, "!! Got I-frame while link state %d\n", pri->q921_state[teio]);
+ return NULL;
+ }
+ /* Informational frame */
+@@ -720,8 +1354,10 @@
+ return q921_handle_iframe(pri, &h->i, len);
+ break;
+ case 1:
+- if (pri->q921_state != Q921_LINK_CONNECTION_ESTABLISHED) {
++ if (pri->q921_state[teio] != Q921_LINK_CONNECTION_ESTABLISHED) {
+ pri_error(pri, "!! Got S-frame while link down\n");
++ q921_send_dm(pri, 1, h->h.tei);
++ q921_reset(pri, h->h.tei, 1);
+ return NULL;
+ }
+ if (len < 4) {
+@@ -731,80 +1367,122 @@
+ switch(h->s.ss) {
+ case 0:
+ /* Receiver Ready */
+- pri->busy = 0;
++ pri->busy[teio] = 0;
+ /* Acknowledge frames as necessary */
+- ev = q921_ack_rx(pri, h->s.n_r);
++ ev = q921_ack_rx(pri, h->s.n_r, h->h.tei);
+ if (ev)
+ return ev;
+ if (h->s.p_f) {
+ /* If it's a p/f one then send back a RR in return with the p/f bit set */
+- if (pri->solicitfbit) {
++// pri_error(pri, "-- h->s.pf %d pri->solicitfbit[teio] %d\n", h->s.p_f, pri->solicitfbit[teio]);
++ if (pri->solicitfbit[teio]) {
+ if (pri->debug & PRI_DEBUG_Q921_STATE)
+ pri_message(pri, "-- Got RR response to our frame\n");
+ } else {
+- if (pri->debug & PRI_DEBUG_Q921_STATE)
++ if (pri->txqueue[teio]) {
++ q921_flush_txqueue(pri, pri->tei, 0);
++ } else {
++ if (pri->debug & PRI_DEBUG_Q921_STATE)
+ pri_message(pri, "-- Unsolicited RR with P/F bit, responding\n");
+- q921_rr(pri, 1, 0);
++ q921_rr(pri, 1, 0, h->h.tei);
++ }
+ }
+- pri->solicitfbit = 0;
++ pri->solicitfbit[teio] = 0;
+ }
+ break;
+ case 1:
+ /* Receiver not ready */
+ if (pri->debug & PRI_DEBUG_Q921_STATE)
+ pri_message(pri, "-- Got receiver not ready\n");
+- if(h->s.p_f) {
+- /* Send RR if poll bit set */
+- q921_rr(pri, h->s.p_f, 0);
++ if ((pri->localtype != PRI_NETWORK) && (pri->localtype != BRI_NETWORK) && (pri->localtype != BRI_NETWORK_PTMP)) {
++ if (h->s.p_f && h->s.h.c_r) {
++// if (!pri->t200_timer[teio]) {
++ /* Send RR if poll bit set */
++ q921_rr(pri, h->s.p_f, 0, h->h.tei);
++// }
++ }
++ } else {
++ if (h->s.p_f && (!h->s.h.c_r)) {
++// if (!pri->t200_timer[teio]) {
++ /* Send RR if poll bit set */
++ q921_rr(pri, h->s.p_f, 0, h->h.tei);
++// }
++ }
+ }
+- pri->busy = 1;
+- break;
++ pri->busy[teio] = 1;
++ if (pri->t200_timer[teio]) {
++ pri_schedule_del(pri, pri->t200_timer[teio]);
++ pri->t200_timer[teio] = 0;
++ }
++ pri->t200_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri, h->h.tei);
++ break;
+ case 2:
+ /* Just retransmit */
+ if (pri->debug & PRI_DEBUG_Q921_STATE)
+ pri_message(pri, "-- Got reject requesting packet %d... Retransmitting.\n", h->s.n_r);
+- if (h->s.p_f) {
+- /* If it has the poll bit set, send an appropriate supervisory response */
+- q921_rr(pri, 1, 0);
+- }
+ sendnow = 0;
++// XXX
++ q921_ack_rx(pri, h->s.n_r, h->h.tei);
+ /* Resend the proper I-frame */
+- for(f=pri->txqueue;f;f=f->next) {
++ for(f=pri->txqueue[teio];f;f=f->next) {
++// pri_error(pri, "!! frame n_s %d transmitted %d (searching for %d)!\n", f->h.n_s, f->transmitted, h->s.n_r);
+ if ((sendnow || (f->h.n_s == h->s.n_r)) && f->transmitted) {
+ /* Matches the request, or follows in our window, and has
+ already been transmitted. */
+- sendnow = 1;
+- pri_error(pri, "!! Got reject for frame %d, retransmitting frame %d now, updating n_r!\n", h->s.n_r, f->h.n_s);
+- f->h.n_r = pri->v_r;
++
++ /* multiframe established */
++ f->transmitted = 0;
++ f->h.n_r = pri->v_r[teio];
++
++ if (pri->busy[teio]) {
++ pri->busy[teio] = 0;
++ sendnow = 0;
++ } else {
++ f->h.p_f = 0;
++ sendnow = 1;
++ pri_error(pri, "!! Got reject for frame %d, retransmitting frame %d now, updating n_r!\n", h->s.n_r, f->h.n_s);
+ q921_transmit(pri, (q921_h *)(&f->h), f->len);
++ }
+ }
+ }
+ if (!sendnow) {
+- if (pri->txqueue) {
+- /* This should never happen */
+- if (!h->s.p_f || h->s.n_r) {
++ if (pri->txqueue[teio]) {
++ if (h->s.p_f) {
++ q921_rr(pri, 1, 0, h->h.tei);
++ } else if (!h->s.p_f || h->s.n_r) {
+ pri_error(pri, "!! Got reject for frame %d, but we only have others!\n", h->s.n_r);
+ }
+ } else {
+ /* Hrm, we have nothing to send, but have been REJ'd. Reset v_a, v_s, etc */
+- pri_error(pri, "!! Got reject for frame %d, but we have nothing -- resetting!\n", h->s.n_r);
+- pri->v_a = h->s.n_r;
+- pri->v_s = h->s.n_r;
++/* pri_error(pri, "!! Got reject for frame %d, but we have nothing -- resetting!\n", h->s.n_r);
++ pri->v_a[teio] = h->s.n_r;
++ pri->v_s[teio] = h->s.n_r; */
+ /* Reset t200 timer if it was somehow going */
+- if (pri->t200_timer) {
+- pri_schedule_del(pri, pri->t200_timer);
+- pri->t200_timer = 0;
++ if (pri->t200_timer[teio]) {
++ pri_schedule_del(pri, pri->t200_timer[teio]);
++ pri->t200_timer[teio] = 0;
+ }
+ /* Reset and restart t203 timer */
+- if (pri->t203_timer)
+- pri_schedule_del(pri, pri->t203_timer);
+- pri->t203_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T203], t203_expire, pri);
++ if (pri->t203_timer[teio])
++ pri_schedule_del(pri, pri->t203_timer[teio]);
++ pri->t203_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T203], t203_expire, pri, tei);
++ pri->solicitfbit[teio] = 0;
+ }
+- }
++ } else {
++ if (h->s.p_f) {
++ /* If it has the poll bit set (and an iframe was retransmitted), send an appropriate supervisory response */
++// q921_rr(pri, 1, 0, h->h.tei);
++ /* Reset and restart t203 timer */
++ pri->solicitfbit[teio] = 0;
++ if (pri->t203_timer[teio])
++ pri_schedule_del(pri, pri->t203_timer[teio]);
++ pri->t203_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T203], t203_expire, pri, h->h.tei);
++ }
++ }
+ break;
+ default:
+ pri_error(pri, "!! XXX Unknown Supervisory frame ss=0x%02x,pf=%02xnr=%02x vs=%02x, va=%02x XXX\n", h->s.ss, h->s.p_f, h->s.n_r,
+- pri->v_s, pri->v_a);
++ pri->v_s[teio], pri->v_a[teio]);
+ }
+ break;
+ case 3:
+@@ -821,8 +1499,16 @@
+ if (pri->debug & PRI_DEBUG_Q921_STATE)
+ pri_message(pri, "-- Got DM Mode from peer.\n");
+ /* Disconnected mode, try again after T200 */
+- ev = q921_dchannel_down(pri);
+- q921_start(pri, 0);
++ ev = q921_dchannel_down(pri, h->h.tei);
++ if ((pri->localtype == BRI_CPE_PTMP) || (pri->localtype == BRI_CPE) || (pri->localtype == BRI_NETWORK)) {
++ /* release layer 2 */
++ // pri_error(pri, "got DM, restarting layer 2.\n");
++ // return NULL;
++ q921_start(pri, 0, h->h.tei);
++ }
++ if ((pri->localtype == PRI_NETWORK) || (pri->localtype == PRI_CPE)){
++ q921_start(pri, 0, h->h.tei);
++ }
+ return ev;
+
+ } else {
+@@ -830,21 +1516,139 @@
+ pri_message(pri, "-- Ignoring unsolicited DM with p/f set to 0\n");
+ #if 0
+ /* Requesting that we start */
+- q921_start(pri, 0);
++ q921_start(pri, 0, h->h.tei);
+ #endif
+ }
+ break;
+- } else if (!h->u.m2) {
+- pri_message(pri, "XXX Unnumbered Information not implemented XXX\n");
++ } else if (h->u.m2 == 0) {
++ if (h->u.ft == 3) {
++ switch (h->u.data[0]) { /* Management Entity Identifier */
++ case 0x0f:
++ /* TEI Procedure */
++ switch (h->u.data[3]) {
++ case Q921_TEI_ID_VERIFY:
++ if (pri->localtype != BRI_NETWORK_PTMP)
++ break;
++ if (pri->debug & PRI_DEBUG_Q921_STATE)
++ pri_message(pri, "got TEI verify for TEI = %d\n",h->u.data[4] >> 1);
++ break;
++ case Q921_TEI_ID_ASSIGNED:
++ if (pri->localtype != BRI_CPE_PTMP)
++ break;
++ if (pri->tei == (h->u.data[4] >> 1)) {
++ // TEI already assgined, CHECK_TEI or REMOVE_TEI
++ pri_error(pri, "Double assgined TEI!\n");
++ }
++ if (pri->ri == ((unsigned short) (h->u.data[1] << 8) + h->u.data[2])) {
++ if (pri->t202_timer[0]) {
++ pri_schedule_del(pri, pri->t202_timer[0]);
++ pri->t202_timer[0] = 0;
++ }
++ pri->tei = h->u.data[4] >> 1;
++ pri->ri = 0;
++ if (pri->debug & PRI_DEBUG_Q921_STATE)
++ pri_message(pri, "received TEI assign TEI = %d ri=%d\n",pri->tei,(unsigned short) (h->u.data[1] << 8) + h->u.data[2]);
++ pri->sabme_retrans[teio] = 0;
++ q921_send_sabme_now(pri, pri->tei);
++ }
++ break;
++ case Q921_TEI_ID_REMOVE:
++ pri_error(pri, "TEI remove TEI = %d\n",(h->u.data[4] >> 1));
++ if (pri->localtype != BRI_CPE_PTMP)
++ break;
++ if (((h->u.data[4] >> 1) == Q921_TEI_GROUP) || (pri->tei == (h->u.data[4] >> 1))){
++ if (pri->debug & PRI_DEBUG_Q921_STATE)
++ pri_message(pri, "received TEI remove TEI = %d\n",pri->tei);
++ pri->tei = 0;
++ pri->ri = 0;
++ // get a new TEI
++ q921_reset(pri, 0, 1);
++ q921_send_teireq(pri);
++ }
++ break;
++ case Q921_TEI_ID_REQUEST:
++ if (pri->localtype != BRI_NETWORK_PTMP)
++ break;
++
++ tei = h->u.data[4] >> 1;
++ if (tei != Q921_TEI_GROUP) {
++ pri_message(pri, "got TEI request for unavailable TEI..\n");
++ q921_send_teidenied(pri,((unsigned int)(h->u.data[1] << 8) + h->u.data[2]),h->u.data[4] >> 1);
++ break;
++ }
++
++ for (tei=0;tei<Q921_MAX_TEIS;tei++) {
++ if (pri->q921_teis[tei] == 0) {
++ pri->q921_teis[tei] = 1;
++ break;
++ }
++ }
++ if (tei < Q921_MAX_TEIS) {
++ q921_send_teiassign(pri,((unsigned int)(h->u.data[1] << 8) + h->u.data[2]),tei + Q921_TEI_BASE);
++ } else {
++ // if you plug too many TEs into my bus it's your fault!!!
++
++ pri_error(pri, "Whooopsie...general protection fault in module TEI manager.\n");
++
++ // XXX IMPLEMENT TEI RECOVERY!!!
++ for (tei=0;tei<Q921_MAX_TEIS;tei++) {
++ // XXX ri should be 0?
++ // q921_reset(pri, tei + Q921_TEI_BASE);
++ // q921_send_teiremove(pri,((unsigned int)(h->u.data[1] << 8) + h->u.data[2]),tei + Q921_TEI_BASE);
++ // pri->q921_teis[tei] = 0;
++ // XXX dont forget schedulers, etc...
++ }
++ q921_send_teidenied(pri,((unsigned int)(h->u.data[1] << 8) + h->u.data[2]),h->u.data[4] >> 1);
++ }
++ break;
++ case Q921_TEI_ID_CHK_REQ:
++ if (pri->localtype != BRI_CPE_PTMP)
++ break;
++ if ((((h->u.data[4] >> 1) == Q921_TEI_GROUP) || ((h->u.data[4] >> 1) == 0) || ((h->u.data[4] >> 1) == pri->tei)) && (pri->tei > 0)) {
++ pri_message(pri, "received TEI check request for TEI = %d\n",h->u.data[4] >> 1);
++ q921_send_teichkresp(pri, pri->tei);
++ }
++ break;
++ default:
++ pri_message(pri, "Ri = %d TEI msg = %x TEI = %x\n", (h->u.data[1] << 8) + h->u.data[2], h->u.data[3], h->u.data[4] >> 1);
++ }
++ break;
++ case Q931_PROTOCOL_DISCRIMINATOR:
++ if (pri->localtype == BRI_CPE_PTMP) {
++ res = q931_receive(pri, (q931_h *)h->u.data, len-3, h->h.tei);
++ /* Send an RR if one wasn't sent already */
++ if (pri->v_na[teio] != pri->v_r[teio])
++ q921_rr(pri, 0, 0, pri->tei);
++ if (res == -1) {
++ return NULL;
++ }
++ if (res & Q931_RES_HAVEEVENT)
++ return &pri->ev;
++ }
++ break;
++ }
++ } else {
++ pri_message(pri, "XXX Unnumbered Information not implemented XXX\n");
++ }
+ }
+ break;
+ case 2:
+ if (pri->debug & PRI_DEBUG_Q921_STATE)
+ pri_message(pri, "-- Got Disconnect from peer.\n");
++ if (pri->q921_state[teio] != Q921_LINK_CONNECTION_ESTABLISHED) {
++ q921_send_dm(pri, 1, h->h.tei);
++ return NULL;
++ }
+ /* Acknowledge */
+- q921_send_ua(pri, h->u.p_f);
+- ev = q921_dchannel_down(pri);
+- q921_start(pri, 0);
++ q921_send_ua(pri, h->u.p_f, h->h.tei);
++ ev = q921_dchannel_down(pri, h->h.tei);
++ if ((pri->localtype == BRI_CPE_PTMP) || (pri->localtype == BRI_CPE) || (pri->localtype == BRI_NETWORK)) {
++ /* release layer 2 */
++ return NULL;
++ }
++ if ((pri->localtype == PRI_NETWORK) || (pri->localtype == PRI_CPE)){
++ q921_start(pri, 0, 0);
++ }
+ return ev;
+ case 3:
+ if (h->u.m2 == 3) {
+@@ -866,17 +1670,26 @@
+ }
+ }
+ /* Send Unnumbered Acknowledgement */
+- q921_send_ua(pri, h->u.p_f);
+- return q921_dchannel_up(pri);
++ q921_send_ua(pri, h->u.p_f, h->h.tei);
++ return q921_dchannel_up(pri, h->h.tei);
+ } else if (h->u.m2 == 0) {
+ /* It's a UA */
+- if (pri->q921_state == Q921_AWAITING_ESTABLISH) {
++ if (pri->q921_state[teio] == Q921_AWAITING_ESTABLISH) {
+ if (pri->debug & PRI_DEBUG_Q921_STATE) {
+ pri_message(pri, "-- Got UA from %s peer Link up.\n", h->h.c_r ? "cpe" : "network");
+ }
+- return q921_dchannel_up(pri);
+- } else
+- pri_error(pri, "!! Got a UA, but i'm in state %d\n", pri->q921_state);
++ return q921_dchannel_up(pri, h->h.tei);
++ } else {
++ pri_error(pri, "!! Got a UA, but i'm in state %d\n", pri->q921_state[teio]);
++ if ((pri->localtype == BRI_CPE_PTMP) || (pri->localtype == BRI_CPE)) {
++ q921_reset(pri, h->h.tei, 1);
++ q921_send_teiverify(pri, h->h.tei);
++ } else {
++ /* send DM */
++ // q921_send_dm(pri, 1, h->h.tei);
++ q921_reset(pri, h->h.tei, 1);
++ }
++ }
+ } else
+ pri_error(pri, "!! Weird frame received (m3=3, m2 = %d)\n", h->u.m2);
+ break;
+@@ -901,19 +1714,42 @@
+ /* Discard FCS */
+ len -= 2;
+
+- if (!pri->master && pri->debug & PRI_DEBUG_Q921_DUMP)
+- q921_dump(pri, h, len, pri->debug & PRI_DEBUG_Q921_RAW, 0);
+-
+ /* Check some reject conditions -- Start by rejecting improper ea's */
+ if (h->h.ea1 || !(h->h.ea2))
+ return NULL;
++ if ((pri->localtype == PRI_CPE) || (pri->localtype == PRI_NETWORK)) {
++ /* Check for broadcasts - not yet handled (for PRI) */
++ if (h->h.tei == Q921_TEI_GROUP) {
++ return NULL;
++ }
++ } else if ((pri->localtype == BRI_CPE) || (pri->localtype == BRI_CPE_PTMP)) {
++ if ((h->h.tei != pri->tei) && (h->h.tei != Q921_TEI_GROUP)) {
++ return NULL;
++ }
++ } else if (pri->localtype == BRI_NETWORK_PTMP) {
++ /* discard anything from a strange TEI (strange == not assigned by us or the broadcast tei) */
++ if (((h->h.tei < Q921_TEI_BASE) || (h->h.tei > Q921_TEI_BASE + Q921_MAX_TEIS)) && (h->h.tei != Q921_TEI_GROUP)) {
++ if (pri->debug & PRI_DEBUG_Q921_DUMP)
++ pri_message(pri, "Received a Q.921 message from strange/unassigned TEI %d.\n");
++ return NULL;
++ } else {
++ if ((pri->q921_teis[h->h.tei - Q921_TEI_BASE] != 1) && (h->h.tei != Q921_TEI_GROUP)) {
++ if (pri->debug & PRI_DEBUG_Q921_DUMP)
++ pri_message(pri, "Received a Q.921 message from unassigned TEI %d.. Sending DM and assigning.\n", h->h.tei);
++ // send DM
++ q921_send_dm(pri, 1, h->h.tei);
++ pri->q921_teis[h->h.tei - Q921_TEI_BASE] = 1;
++ }
++ }
++ }
++
++ if (!pri->master && pri->debug & PRI_DEBUG_Q921_DUMP)
++ q921_dump(pri, h, len, pri->debug & PRI_DEBUG_Q921_RAW, 0);
+
+- /* Check for broadcasts - not yet handled */
+- if (h->h.tei == Q921_TEI_GROUP)
+- return NULL;
+
++ if (pri->localtype != BRI_NETWORK_PTMP) {
+ /* Check for SAPIs we don't yet handle */
+- if ((h->h.sapi != pri->sapi) || (h->h.tei != pri->tei)) {
++ if (((h->h.sapi != pri->sapi) && (h->h.sapi != Q921_SAPI_LAYER2_MANAGEMENT)) || ((h->h.tei != pri->tei) && (h->h.tei != Q921_TEI_GROUP) )) {
+ #ifdef PROCESS_SUBCHANNELS
+ /* If it's not us, try any subchannels we have */
+ if (pri->subchannel)
+@@ -921,10 +1757,16 @@
+ else
+ #endif
+ return NULL;
+-
++ }
+ }
+ ev = __q921_receive_qualified(pri, h, len);
+- reschedule_t203(pri);
++
++// Q921_GROUP_TEI
++ if (pri->localtype == BRI_CPE_PTMP) {
++ reschedule_t203(pri, pri->tei);
++ } else {
++ reschedule_t203(pri, h->h.tei);
++ }
+ return ev;
+ }
+
+@@ -938,14 +1780,54 @@
+ return e;
+ }
+
+-void q921_start(struct pri *pri, int now)
++static void q921_start_tei(struct pri *pri, int tei)
+ {
+- if (pri->q921_state != Q921_LINK_CONNECTION_RELEASED) {
+- pri_error(pri, "!! q921_start: Not in 'Link Connection Released' state\n");
+- return;
++ int teio=tei - Q921_TEI_BASE;
++ if (pri->localtype != BRI_NETWORK_PTMP) { return; }
++ if (((teio < 0) || (teio > Q921_MAX_TEIS))) { teio=0; }
++ pri->q921_teis[teio] = 0;
++ q921_send_teiremove(pri, tei);
++ q921_reset(pri,tei,1);
++}
++
++void q921_start(struct pri *pri, int now, int tei)
++{
++ int i=0;
++/* if (pri->q921_state != Q921_LINK_CONNECTION_RELEASED) {
++ pri_error(pri, "!! q921_start: Not in 'Link Connection Released' state\n");
++ return;
++ } */
++ /* Reset our interface */
++ if (pri->localtype != BRI_NETWORK_PTMP) {
++ q921_reset(pri,0,1);
++ }
++ /* Do the SABME XXX Maybe we should implement T_WAIT? XXX */
++ if ((pri->localtype == PRI_NETWORK) || (pri->localtype == PRI_CPE) || (pri->localtype == BRI_NETWORK) || (pri->localtype == BRI_CPE)) {
++ pri->sabme_retrans[0] = 0;
++ q921_send_sabme(pri, now, 0);
++ }
++
++ if (pri->localtype == BRI_NETWORK_PTMP) {
++ if (tei == 0) {
++ // initial start or complete restart
++ q921_send_teiremove(pri, 127);
++ pri->dchanup = 0;
++ for (i=0;i<Q921_MAX_TEIS;i++) {
++ q921_start_tei(pri,Q921_TEI_BASE+i);
++ }
++ } else if ((tei >= Q921_TEI_BASE) && (tei < Q921_TEI_BASE + Q921_MAX_TEIS)){
++ // restart of a single p2p datalink
++ q921_start_tei(pri,tei);
++ }
++ }
++ if (pri->localtype == BRI_CPE_PTMP){
++ if (tei == 0) {
++ /* let's get a TEI */
++ // q921_send_teireq(pri);
++ } else {
++ /* save the planet by recycling */
++ pri->sabme_retrans[0] = 0;
++ q921_send_sabme(pri, now, tei);
++ }
+ }
+- /* Reset our interface */
+- q921_reset(pri);
+- /* Do the SABME XXX Maybe we should implement T_WAIT? XXX */
+- q921_send_sabme(pri, now);
+ }
+diff -urNad libpri-1.2.0-release/q931.c /tmp/dpep.aQ7o1G/libpri-1.2.0-release/q931.c
+--- libpri-1.2.0-release/q931.c 2005-10-25 18:59:59.000000000 +0200
++++ /tmp/dpep.aQ7o1G/libpri-1.2.0-release/q931.c 2005-11-23 04:05:24.984532591 +0200
+@@ -5,6 +5,8 @@
+ *
+ * Copyright (C) 2001-2005, Digium
+ * All Rights Reserved.
++ * Copyright (C) 2003,2004,2005 Junghanns.NET GmbH
++ * Klaus-Peter Junghanns <kpj at junghanns.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+@@ -31,6 +33,7 @@
+
+ #include <unistd.h>
+ #include <stdlib.h>
++#include <time.h>
+ #include <string.h>
+ #include <stdio.h>
+ #include <limits.h>
+@@ -205,6 +208,14 @@
+ #define LOC_INTERNATIONAL_NETWORK 0x7
+ #define LOC_NETWORK_BEYOND_INTERWORKING 0xa
+
++struct q921_call {
++ int tei;
++ int proc;
++ int channel;
++ q921_call *next;
++};
++
++
+ static char *ie2str(int ie);
+ static char *msg2str(int msg);
+
+@@ -253,6 +264,10 @@
+ c->next = NULL;
+ c->sentchannel = 0;
+ c->newcall = 1;
++ c->t303timer = 0;
++ c->t303running = 0;
++ c->aoc = 0;
++ c->phones = NULL;
+ c->ourcallstate = Q931_CALL_STATE_NULL;
+ c->peercallstate = Q931_CALL_STATE_NULL;
+ }
+@@ -272,14 +287,17 @@
+ {
+ int x;
+ int pos=0;
+-#ifdef NO_BRI_SUPPORT
+- if (!ie->data[0] & 0x20) {
+- pri_error(pri, "!! Not PRI type!?\n");
+- return -1;
++ if ((pri->localtype != PRI_CPE) && (pri->localtype != PRI_NETWORK)) {
++ // pri_error(pri, "!! BRI type %d!?\n",ie->data[0] & 0x03);
++ call->channelno = ie->data[0] & 0x03;
++ if (call->channelno == 3) {
++ call->channelno = -1; // any channel
++ }
++ return 0;
+ }
+-#endif
+ #ifndef NOAUTO_CHANNEL_SELECTION_SUPPORT
+- switch (ie->data[0] & 3) {
++ if ((pri->localtype == PRI_NETWORK) || (pri->localtype == PRI_CPE)) {
++ switch (ie->data[0] & 3) {
+ case 0:
+ call->justsignalling = 1;
+ break;
+@@ -288,6 +306,7 @@
+ default:
+ pri_error(pri, "!! Unexpected Channel selection %d\n", ie->data[0] & 3);
+ return -1;
++ }
+ }
+ #endif
+ if (ie->data[0] & 0x08)
+@@ -349,10 +368,16 @@
+ }
+
+ /* Start with standard stuff */
+- if (pri->switchtype == PRI_SWITCH_GR303_TMC)
++ if (pri->switchtype == PRI_SWITCH_GR303_TMC) {
+ ie->data[pos] = 0x69;
+- else
++ } else {
++ if ((pri->localtype == PRI_NETWORK) || (pri->localtype == PRI_CPE)) {
+ ie->data[pos] = 0xa1;
++ } else {
++ // BRI
++ ie->data[pos] = 0x80;
++ }
++ }
+ /* Add exclusive flag if necessary */
+ if (call->chanflags & FLAG_EXCLUSIVE)
+ ie->data[pos] |= 0x08;
+@@ -369,6 +394,7 @@
+ } else
+ pos++;
+ if ((call->channelno > -1) || (call->slotmap != -1)) {
++ if ((pri->localtype == PRI_NETWORK) || (pri->localtype == PRI_CPE)) {
+ /* We'll have the octet 8.2 and 8.3's present */
+ ie->data[pos++] = 0x83;
+ if (call->channelno > -1) {
+@@ -384,11 +410,43 @@
+ ie->data[pos++] = (call->slotmap & 0xff);
+ return pos + 2;
+ }
+- }
++ } else {
++ // BRI
++ // pri_error(pri, "channelno %d, ds1no %d data %d\n",call->channelno,call->ds1no,ie->data[pos-1]);
++ if (pri->localtype == BRI_CPE_PTMP) {
++ if (msgtype == Q931_SETUP) {
++ // network, you decide!
++ if (call->channelno > -1) {
++ // ie->data[pos-1] = 0x83;
++ ie->data[pos-1] = 0x80 | call->channelno;
++ }
++ } else {
++ if (call->channelno > -1) {
++ ie->data[pos-1] |= call->channelno;
++ }
++ }
++ } else {
++ if (call->channelno > -1) {
++ ie->data[pos-1] |= call->channelno;
++ }
++ }
++ return pos + 2;
++ }
++ } else {
++ if (pri->localtype == BRI_CPE) {
++ ie->data[pos++] = 0x80 | 3;
++ return pos + 2;
++ }
++ }
++
+ if (call->ds1no > 0) {
+ /* We're done */
+ return pos + 2;
+ }
++ if (msgtype == Q931_RESTART_ACKNOWLEDGE) {
++ /* restart complete interface! */
++ return 0;
++ }
+ pri_error(pri, "!! No channel map, no channel, and no ds1? What am I supposed to identify?\n");
+ return -1;
+ }
+@@ -734,8 +792,12 @@
+ return code2str(pres, press, sizeof(press) / sizeof(press[0]));
+ }
+
+-static void q931_get_number(unsigned char *num, int maxlen, unsigned char *src, int len)
++static void q931_get_number(char *num, int maxlen, unsigned char *src, int len)
+ {
++ if (len < 0) {
++ pri_error(NULL, "q931_get_number received invalid len = %d\n", len);
++ return;
++ }
+ if (len > maxlen - 1) {
+ num[0] = 0;
+ return;
+@@ -746,50 +808,75 @@
+
+ static FUNC_DUMP(dump_called_party_number)
+ {
+- unsigned char cnum[256];
+-
+- q931_get_number(cnum, sizeof(cnum), ie->data + 1, len - 3);
+- pri_message(pri, "%c Called Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d) '%s' ]\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, cnum);
++ char cnum[256];
++ if (len >= 3) {
++ q931_get_number(cnum, sizeof(cnum), ie->data + 1, len - 3);
++ pri_message(pri, "%c Called Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d) '%s' ]\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, cnum);
++ } else {
++ pri_error(pri, "Called Number (len=%2d) too short.\n", len);
++ }
+ }
+
+ static FUNC_DUMP(dump_called_party_subaddr)
+ {
+- unsigned char cnum[256];
+- q931_get_number(cnum, sizeof(cnum), ie->data + 1, len - 3);
+- pri_message(pri, "%c Called Sub-Address (len=%2d) [ Ext: %d Type: %s (%d) O: %d '%s' ]\n",
+- prefix, len, ie->data[0] >> 7,
+- subaddrtype2str((ie->data[0] & 0x70) >> 4), (ie->data[0] & 0x70) >> 4,
+- (ie->data[0] & 0x08) >> 3, cnum);
++ char cnum[256];
++ if (len >= 3) {
++ q931_get_number(cnum, sizeof(cnum), ie->data + 1, len - 3);
++ pri_message(pri, "%c Called Sub-Address (len=%2d) [ Ext: %d Type: %s (%d) O: %d '%s' ]\n",
++ prefix, len, ie->data[0] >> 7,
++ subaddrtype2str((ie->data[0] & 0x70) >> 4), (ie->data[0] & 0x70) >> 4,
++ (ie->data[0] & 0x08) >> 3, cnum);
++ } else {
++ pri_error(pri, "Called Party Subaddress (len=%2d) too short.\n", len);
++ }
+ }
+
+ static FUNC_DUMP(dump_calling_party_number)
+ {
+- unsigned char cnum[256];
+- if (ie->data[0] & 0x80)
+- q931_get_number(cnum, sizeof(cnum), ie->data + 1, len - 3);
+- else
+- q931_get_number(cnum, sizeof(cnum), ie->data + 2, len - 4);
+- pri_message(pri, "%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);
+- if (ie->data[0] & 0x80)
+- pri_message(pri, "%c Presentation: %s (%d) '%s' ]\n", prefix, pri_pres2str(0), 0, cnum);
+- else
+- pri_message(pri, "%c Presentation: %s (%d) '%s' ]\n", prefix, pri_pres2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f, cnum);
++ char cnum[256];
++ if ((ie->data[0] & 0x80) && (len >= 3)) {
++ q931_get_number(cnum, sizeof(cnum), ie->data + 1, len - 3);
++ pri_message(pri, "%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(pri, "%c Presentation: %s (%d) '%s' ]\n", prefix, pri_pres2str(0), 0, cnum);
++ } else if (len >= 4) {
++ q931_get_number(cnum, sizeof(cnum), ie->data + 2, len - 4);
++ pri_message(pri, "%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(pri, "%c Presentation: %s (%d) '%s' ]\n", prefix, pri_pres2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f, cnum);
++ } else {
++ pri_error(pri, "Calling Party Number (len=%2d) too short.\n", len);
++ }
+ }
+
+ static FUNC_DUMP(dump_calling_party_subaddr)
+ {
+- unsigned char cnum[256];
+- q931_get_number(cnum, sizeof(cnum), ie->data + 2, len - 4);
+- pri_message(pri, "%c Calling Sub-Address (len=%2d) [ Ext: %d Type: %s (%d) O: %d '%s' ]\n",
+- prefix, len, ie->data[0] >> 7,
+- subaddrtype2str((ie->data[0] & 0x70) >> 4), (ie->data[0] & 0x70) >> 4,
+- (ie->data[0] & 0x08) >> 3, cnum);
++ char cnum[256];
++ if (len >= 4) {
++ q931_get_number(cnum, sizeof(cnum), ie->data + 2, len - 4);
++ pri_message(pri, "%c Calling Sub-Address (len=%2d) [ Ext: %d Type: %s (%d) O: %d '%s' ]\n",
++ prefix, len, ie->data[0] >> 7,
++ subaddrtype2str((ie->data[0] & 0x70) >> 4), (ie->data[0] & 0x70) >> 4,
++ (ie->data[0] & 0x08) >> 3, cnum);
++ } else {
++ pri_error(pri, "Calling Party Subaddress (len=%2d) too short.\n", len);
++ }
++}
++
++static FUNC_DUMP(dump_colp)
++{
++ char cnum[256];
++ if (len >= 4) {
++ q931_get_number(cnum, sizeof(cnum), ie->data + 2, len - 4);
++ pri_message(pri, "%c COLP (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(pri, "%c Presentation: %s (%d) '%s' ]\n", prefix, pri_pres2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f, cnum);
++ } else {
++ pri_error(pri, "COLP (len=%2d) too short.\n", len);
++ }
+ }
+
+ static FUNC_DUMP(dump_redirecting_number)
+ {
+- unsigned char cnum[256];
++ char cnum[256];
+ int i = 0;
+ /* To follow Q.931 (4.5.1), we must search for start of octet 4 by
+ walking through all bytes until one with ext bit (8) set to 1 */
+@@ -810,13 +897,17 @@
+ }
+ }
+ while(!(ie->data[i++]& 0x80));
+- q931_get_number(cnum, sizeof(cnum), ie->data + i, ie->len - i);
+- pri_message(pri, " '%s' ]\n", cnum);
++ if ((ie->len - i) >= 0) {
++ q931_get_number(cnum, sizeof(cnum), ie->data + i, ie->len - i);
++ pri_message(pri, " '%s' ]\n", cnum);
++ } else {
++ pri_error(pri, "Redirecting Number (len=%2d) too short.\n", len);
++ }
+ }
+
+ static FUNC_DUMP(dump_connected_number)
+ {
+- unsigned char cnum[256];
++ char cnum[256];
+ int i = 0;
+ /* To follow Q.931 (4.5.1), we must search for start of octet 4 by
+ walking through all bytes until one with ext bit (8) set to 1 */
+@@ -833,8 +924,12 @@
+ }
+ }
+ while(!(ie->data[i++]& 0x80));
+- q931_get_number(cnum, sizeof(cnum), ie->data + i, ie->len - i);
+- pri_message(pri, " '%s' ]\n", cnum);
++ if ((ie->len - i) >= 0) {
++ q931_get_number(cnum, sizeof(cnum), ie->data + i, ie->len - i);
++ pri_message(pri, " '%s' ]\n", cnum);
++ } else {
++ pri_error(pri, "Connected Number (len=%2d) too short.\n", len);
++ }
+ }
+
+
+@@ -858,7 +953,7 @@
+ }
+ }
+ while(!(ie->data[i++] & 0x80));
+- q931_get_number((unsigned char *) call->redirectingnum, sizeof(call->redirectingnum), ie->data + i, ie->len - i);
++ q931_get_number(call->redirectingnum, sizeof(call->redirectingnum), ie->data + i, ie->len - i);
+ return 0;
+ }
+
+@@ -866,7 +961,7 @@
+ {
+ if (order > 1)
+ return 0;
+- if (call->redirectingnum && *call->redirectingnum) {
++ if (call->redirectingnum && strlen(call->redirectingnum)) {
+ ie->data[0] = call->redirectingplan;
+ ie->data[1] = call->redirectingpres;
+ ie->data[2] = (call->redirectingreason & 0x0f) | 0x80;
+@@ -878,67 +973,90 @@
+
+ static FUNC_DUMP(dump_redirecting_subaddr)
+ {
+- unsigned char cnum[256];
+- q931_get_number(cnum, sizeof(cnum), ie->data + 2, len - 4);
+- pri_message(pri, "%c Redirecting Sub-Address (len=%2d) [ Ext: %d Type: %s (%d) O: %d '%s' ]\n",
+- prefix, len, ie->data[0] >> 7,
+- subaddrtype2str((ie->data[0] & 0x70) >> 4), (ie->data[0] & 0x70) >> 4,
+- (ie->data[0] & 0x08) >> 3, cnum);
++ char cnum[256];
++ if (len >= 4) {
++ q931_get_number(cnum, sizeof(cnum), ie->data + 2, len - 4);
++ pri_message(pri, "%c Redirecting Sub-Address (len=%2d) [ Ext: %d Type: %s (%d) O: %d '%s' ]\n",
++ prefix, len, ie->data[0] >> 7,
++ subaddrtype2str((ie->data[0] & 0x70) >> 4), (ie->data[0] & 0x70) >> 4,
++ (ie->data[0] & 0x08) >> 3, cnum);
++ } else {
++ pri_error(pri, "Redirecting Subaddress (len=%2d) too short.\n", len);
++ }
+ }
+
+ static FUNC_RECV(receive_calling_party_subaddr)
+ {
+ /* copy digits to call->callingsubaddr */
+- q931_get_number((unsigned char *) call->callingsubaddr, sizeof(call->callingsubaddr), ie->data + 2, len - 4);
++ if (len >= 4) {
++ q931_get_number(call->callingsubaddr, sizeof(call->callingsubaddr), ie->data + 2, len - 4);
++ } else {
++ pri_error(call->pri, "Calling Party Subaddress (len=%2d) too short.\n", len);
++ }
+ return 0;
+ }
+
+ static FUNC_RECV(receive_called_party_number)
+ {
+- /* copy digits to call->callednum */
+- q931_get_number((unsigned char *) call->callednum, sizeof(call->callednum), ie->data + 1, len - 3);
+- call->calledplan = ie->data[0] & 0x7f;
++ /* copy digits to call->callednum or call->digits */
++ if (len >= 3) {
++ if (msgtype == Q931_INFORMATION) {
++ q931_get_number(call->digits, sizeof(call->digits), ie->data + 1, len - 3);
++ } else {
++ q931_get_number(call->callednum, sizeof(call->callednum), ie->data + 1, len - 3);
++ }
++ call->calledplan = ie->data[0] & 0x7f;
++ } else {
++ pri_error(call->pri, "Called Party Number (len=%2d) too short.\n", len);
++ }
+ return 0;
+ }
+
+ static FUNC_SEND(transmit_called_party_number)
+ {
+ ie->data[0] = 0x80 | call->calledplan;
+- if (*call->callednum)
++ if (strlen(call->callednum))
+ memcpy(ie->data + 1, call->callednum, strlen(call->callednum));
+ return strlen(call->callednum) + 3;
+ }
+
+ static FUNC_RECV(receive_calling_party_number)
+ {
+- u_int8_t *data;
+- size_t length;
+-
+- if (ie->data[0] & 0x80) {
+- data = ie->data + 1;
+- length = len - 3;
+- call->callerpres = 0; /* PI presentation allowed SI user-provided, not screened */
+- } else {
+- data = ie->data + 2;
+- length = len - 4;
+- call->callerpres = ie->data[1] & 0x7f;
+- }
+-
+- if (call->callerpres == PRES_ALLOWED_NETWORK_NUMBER ||
+- call->callerpres == PRES_PROHIB_NETWORK_NUMBER) {
+- q931_get_number((u_int8_t *)call->callerani, sizeof(call->callerani), data, length);
+- call->callerplanani = ie->data[0] & 0x7f;
+-
+- if (!*call->callernum) { /*Copy ANI to CallerID if CallerID is not already set */
+- libpri_copy_string(call->callernum, call->callerani, sizeof(call->callernum));
+- call->callerplan = call->callerplanani;
+- }
+-
+- } else {
+- q931_get_number((u_int8_t *)call->callernum, sizeof(call->callernum), data, length);
+- call->callerplan = ie->data[0] & 0x7f;
+- }
++/// callerani!!
++ if (strlen(call->callernum)) {
++ call->callerplanuser = ie->data[0] & 0x7f;
++ } else {
++ call->callerplan = ie->data[0] & 0x7f;
++ }
+
++ if (ie->data[0] & 0x80) {
++ if (len >= 3) {
++ if (strlen(call->callernum)) {
++ // got A NUM already (this is not 100% correct, but the network should do it this way to protect bad implementations
++ q931_get_number(call->callerani, sizeof(call->callerani), ie->data + 1, len - 3);
++ call->callerpresuser = 0; /* PI presentation allowed
++ SI user-provided, not screened */
++ } else {
++ q931_get_number(call->callernum, sizeof(call->callernum), ie->data + 1, len - 3);
++ call->callerpres = 0; /* PI presentation allowed
++ SI user-provided, not screened */
++ }
++ } else {
++ pri_error(call->pri, "Calling Party Number (len=%2d) too short.\n", len);
++ }
++ } else {
++ if (len >= 4) {
++ if (strlen(call->callernum)) {
++ q931_get_number(call->callerani, sizeof(call->callerani), ie->data + 2, len - 4);
++ call->callerpresuser = ie->data[1] & 0x7f;
++ } else {
++ q931_get_number(call->callernum, sizeof(call->callernum), ie->data + 2, len - 4);
++ call->callerpres = ie->data[1] & 0x7f;
++ }
++ } else {
++ pri_error(call->pri, "Calling Party Number (len=%2d) too short.\n", len);
++ }
++ }
+ return 0;
+ }
+
+@@ -964,11 +1082,33 @@
+ static FUNC_RECV(receive_user_user)
+ {
+ call->useruserprotocoldisc = ie->data[0] & 0xff;
+- if (call->useruserprotocoldisc == 4) /* IA5 */
+- q931_get_number((unsigned char *) call->useruserinfo, sizeof(call->useruserinfo), ie->data + 1, len - 3);
++ if (call->useruserprotocoldisc == 4) { /* IA5 */
++ if (len >= 3) {
++ q931_get_number(call->useruserinfo, sizeof(call->useruserinfo), ie->data + 1, len - 3);
++ } else {
++ pri_error(call->pri, "User-User Information (len=%2d) too short.\n", len);
++ }
++ }
+ return 0;
+ }
+
++static FUNC_RECV(receive_call_identity)
++{
++ if (len >= 2) {
++ q931_get_number(call->callid, sizeof(call->callid), ie->data, len - 2);
++ } else {
++ pri_error(call->pri, "Call Identity (len=%2d) too short.\n", len);
++ }
++ return 0;
++}
++
++static FUNC_SEND(transmit_call_identity)
++{
++ if (strlen(call->callid))
++ memcpy(ie->data , call->callid, strlen(call->callid));
++ return strlen(call->callednum) + 3;
++}
++
+ static FUNC_SEND(transmit_user_user)
+ {
+ int datalen = strlen(call->useruserinfo);
+@@ -1050,22 +1190,41 @@
+ data++;
+ len--;
+ }
+- q931_get_number((unsigned char *) call->callername, sizeof(call->callername), data, len - 2);
++ if (msgtype == Q931_SETUP) {
++ /* we treat display IEs in the SETUP msg as callername */
++ if (len >= 2) {
++ q931_get_number(call->callername, sizeof(call->callername), data, len - 2);
++ } else {
++ pri_error(call->pri, "Display (len=%2d) too short.\n", len);
++ }
++ } else {
++ /* in other msgs we will pass it as text to chan_zap */
++ if (len >= 2) {
++ q931_get_number(call->display, sizeof(call->display), data, len - 2);
++ } else {
++ pri_error(call->pri, "Display (len=%2d) too short.\n", len);
++ }
++ }
+ return 0;
+ }
+
+ static FUNC_SEND(transmit_display)
+ {
+ int i;
+- if ((pri->switchtype != PRI_SWITCH_NI1) && (pri->switchtype != PRI_SWITCH_QSIG)
+- && *call->callername) {
++ int cpe = pri->localtype == BRI_CPE || pri->localtype == BRI_CPE_PTMP || pri->localtype == PRI_CPE;
++ if ((pri->switchtype != PRI_SWITCH_NI1) && (pri->switchtype != PRI_SWITCH_QSIG) && strlen(call->callername) && !cpe) {
+ i = 0;
+ if(pri->switchtype != PRI_SWITCH_EUROISDN_E1) {
+ ie->data[0] = 0xb1;
+ ++i;
+ }
+- memcpy(ie->data + i, call->callername, strlen(call->callername));
+- return 2 + i + strlen(call->callername);
++ if (msgtype == Q931_SETUP_ACKNOWLEDGE) {
++ memcpy(ie->data + i, call->display, strlen(call->display));
++ return 2 + i + strlen(call->display);
++ } else {
++ memcpy(ie->data + i, call->callername, strlen(call->callername));
++ return 2 + i + strlen(call->callername);
++ }
+ }
+ return 0;
+ }
+@@ -1112,6 +1271,111 @@
+ return 0;
+ }
+
++ #if 0
++ static FUNC_RECV(receive_facility_kpj)
++ {
++ unsigned char cpt_tag, cp_len, invoke_id_tag, invoke_id_len, operation_value_len, operation_value_tag;
++ unsigned char arg_len = 0;
++ unsigned char pos = 0;
++ short invoke_id = 0, operation_value = 0;
++ if ((ie->data[pos++] & 0x1F) == 0x11) {
++ /* service discriminator == supplementary services */
++ cpt_tag = ie->data[pos++] & 0x1F;
++ cp_len = ie->data[pos++];
++ switch (cpt_tag) {
++ case 1: /* invoke */
++ invoke_id_tag = ie->data[pos++];
++ if (invoke_id_tag != 0x02) {
++ // pri_error(call->pri, "invoke id tag != 0x02\n");
++ break;
++ }
++ invoke_id_len = ie->data[pos++]; // 4
++ while (invoke_id_len > 0) {
++ invoke_id = (invoke_id << 8) | (ie->data[pos++] & 0xFF);
++ invoke_id_len--;
++ }
++ operation_value_tag = ie->data[pos++];
++ if (operation_value_tag != 0x02) {
++ // pri_error(call->pri, "operation value tag != 0x02\n");
++ break;
++ }
++ operation_value_len = ie->data[pos++];
++ while (operation_value_len > 0) {
++ operation_value = (operation_value << 8) | (ie->data[pos++] & 0xFF);
++ operation_value_len--;
++ }
++ arg_len = ie->len - pos;
++ switch (operation_value) {
++ case 0x06: /* ECT execute */
++ call->facility = operation_value;
++ break;
++ case 0x0D: /* call deflection */
++ call->facility = operation_value;
++ /* dirty hack! */
++ arg_len -= 6;
++ if (arg_len > 0) {
++ pos += 6;
++ q931_get_number(call->redirectingnum, sizeof(call->redirectingnum), ie->data + pos, arg_len);
++ }
++ /* now retrieve the number */
++ break;
++ case 0x22: /* AOC-D */
++ break;
++ case 0x24: /* AOC-E */
++ break;
++ }
++ break;
++ case 2: /* return result */
++ break;
++ case 3: /* return error */
++ break;
++ case 4: /* reject */
++ break;
++ }
++ } else {
++ /* OLD DIRTY ULAW HACK */
++ if (ie->len < 14) {
++ pri_error(call->pri, "!! Facility message shorter than 14 bytes\n");
++ return 0;
++ }
++ if (ie->data[13] + 14 == ie->len) {
++ q931_get_number(call->callername, sizeof(call->callername) - 1, ie->data + 14, ie->len - 14);
++ }
++ call->facility = 0x0;
++ }
++ return 0;
++ }
++
++ static FUNC_SEND(transmit_facility_kpj)
++ {
++ int i = 0;
++ return i;
++ if (call->aoc && (pri->switchtype == PRI_SWITCH_EUROISDN_E1) && ((pri->localtype == BRI_NETWORK) || (pri->localtype == BRI_NETWORK_PTMP) || (pri->localtype == PRI_NETWORK))) {
++ ie->data[0] = 0x90; /* PP remote operations */
++ ie->data[i++] = 0x00; /* component tag */
++ ie->data[i++] = 0x02; /* invoke id tag */
++ ie->data[i++] = 0x02; /* invoke id len */
++ ie->data[i++] = 0x34; /* invoke id */
++ ie->data[i++] = 0x56; /* invoke id */
++ ie->data[i++] = 0x02; /* operation value tag */
++ ie->data[i++] = 0x01; /* operation value len */
++ switch (msgtype) {
++ case Q931_SETUP:
++ ie->data[i++] = 0x26; /* operation value AOC-S */
++ break;
++ case Q931_DISCONNECT:
++ ie->data[i++] = 0x24; /* operation value AOC-E */
++ break;
++ default:
++ ie->data[i++] = 0x22; /* operation value AOC-D */
++ break;
++ }
++ // ARGUMENTS!
++ }
++ // return 2 + i;
++ }
++#endif
++
+ static FUNC_SEND(transmit_facility)
+ {
+ struct apdu_event *tmp;
+@@ -1138,6 +1402,182 @@
+ return i + 2;
+ }
+
++#if 0
++static FUNC_SEND(transmit_facility)
++{
++ int i = 0, j, first_i, compsp = 0;
++ struct rose_component *comp, *compstk[10];
++ unsigned char namelen = strlen(call->callername);
++
++ if ((pri->switchtype == PRI_SWITCH_NI2) && (namelen > 15))
++ namelen = 15; /* According to GR-1367, for NI2 switches it can't be > 15 characters */
++ if ((namelen > 0) && ((pri->switchtype == PRI_SWITCH_QSIG) ||
++ ((pri->switchtype == PRI_SWITCH_NI2) && (pri->localtype == PRI_NETWORK)))) {
++ do {
++ first_i = i;
++ ie->data[i] = 0x80 | Q932_PROTOCOL_EXTENSIONS;
++ i++;
++ /* Interpretation component */
++ ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, ie->data, i, 0x00 /* Discard unrecognized invokes */);
++
++ /* Invoke ID */
++ ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, ie->data, i);
++ ASN1_PUSH(compstk, compsp, comp);
++
++ /* Invoke component contents */
++ /* Invoke ID */
++ ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, ie->data, i, ++pri->last_invoke);
++
++ /* Operation Tag */
++ ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, ie->data, i, SS_CNID_CALLINGNAME);
++
++ /* Arugement Tag */
++ j = asn1_string_encode(ROSE_NAME_PRESENTATION_ALLOWED_SIMPLE, &ie->data[i], len - i, 15, call->callername, namelen);
++ if (j < 0) {
++ i = first_i;
++ break;
++ }
++ i += j;
++
++ /* Fix length of stacked components */
++ while(compsp > 0) {
++ ASN1_FIXUP(compstk, compsp, ie->data, i);
++ }
++ } while (0);
++ }
++ if (/*(pri->switchtype == PRI_SWITCH_EUROISDN_E1) &&*/ call->redirectingnum && strlen(call->redirectingnum)) {
++ if (!(first_i = i)) {
++ /* Add protocol information header */
++ ie->data[i++] = 0x80 | Q932_PROTOCOL_ROSE;
++ }
++
++ /* ROSE invoke component */
++ ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, ie->data, i);
++ ASN1_PUSH(compstk, compsp, comp);
++
++ /* ROSE invokeId component */
++ ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, ie->data, i, ++pri->last_invoke);
++
++ /* ROSE operationId component */
++ ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, ie->data, i, ROSE_DIVERTING_LEG_INFORMATION2);
++
++ /* ROSE ARGUMENT component */
++ ASN1_ADD_SIMPLE(comp, 0x30, ie->data, i);
++ ASN1_PUSH(compstk, compsp, comp);
++
++ /* ROSE DivertingLegInformation2.diversionCounter component */
++ /* Always is 1 because other isn't available in the current design */
++ ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, ie->data, i, 1);
++
++ /* ROSE DivertingLegInformation2.diversionReason component */
++ ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, ie->data, i, redirectingreason_from_q931(pri, call->redirectingreason));
++
++ /* ROSE DivertingLegInformation2.divertingNr component */
++ ASN1_ADD_SIMPLE(comp, 0xA1, ie->data, i);
++ ASN1_PUSH(compstk, compsp, comp);
++
++ /* Redirecting information always not screened */
++ switch(call->redirectingpres) {
++ case PRES_ALLOWED_USER_NUMBER_NOT_SCREENED:
++ case PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN:
++ if (call->redirectingnum && strlen(call->redirectingnum)) {
++ ASN1_ADD_SIMPLE(comp, 0xA0, ie->data, i);
++ ASN1_PUSH(compstk, compsp, comp);
++
++ /* NPI of redirected number is not supported in the current design */
++ ASN1_ADD_SIMPLE(comp, 0xA1, ie->data, i);
++ ASN1_PUSH(compstk, compsp, comp);
++
++ ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, ie->data, i, typeofnumber_from_q931(pri, call->redirectingplan >> 4));
++
++ j = asn1_string_encode(ASN1_NUMERICSTRING, &ie->data[i], len - i, 20, call->redirectingnum, strlen(call->redirectingnum));
++ if (j < 0) {
++ i = first_i;
++ goto finish2;
++ }
++ i += j;
++ ASN1_FIXUP(compstk, compsp, ie->data, i);
++ ASN1_FIXUP(compstk, compsp, ie->data, i);
++ break;
++ }
++ /* fall through */
++ case PRES_PROHIB_USER_NUMBER_PASSED_SCREEN:
++ case PRES_PROHIB_USER_NUMBER_NOT_SCREENED:
++ ASN1_ADD_SIMPLE(comp, 0x81, ie->data, i);
++ break;
++ /* Don't know how to handle this */
++ case PRES_ALLOWED_NETWORK_NUMBER:
++ case PRES_PROHIB_NETWORK_NUMBER:
++ case PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN:
++ case PRES_PROHIB_USER_NUMBER_FAILED_SCREEN:
++ ASN1_ADD_SIMPLE(comp, 0x81, ie->data, i);
++ break;
++ default:
++ pri_message(pri, "!! Undefined presentation value for redirecting number: %d\n", call->redirectingpres);
++ case PRES_NUMBER_NOT_AVAILABLE:
++ ASN1_ADD_SIMPLE(comp, 0x82, ie->data, i);
++ break;
++ }
++ ASN1_FIXUP(compstk, compsp, ie->data, i);
++
++ /* ROSE DivertingLegInformation2.originalCalledNr component */
++ /* This information isn't supported by current design - duplicate divertingNr */
++ ASN1_ADD_SIMPLE(comp, 0xA2, ie->data, i);
++ ASN1_PUSH(compstk, compsp, comp);
++
++ /* Redirecting information always not screened */
++ switch(call->redirectingpres) {
++ case PRES_ALLOWED_USER_NUMBER_NOT_SCREENED:
++ case PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN:
++ if (call->redirectingnum && strlen(call->redirectingnum)) {
++ ASN1_ADD_SIMPLE(comp, 0xA0, ie->data, i);
++ ASN1_PUSH(compstk, compsp, comp);
++
++ ASN1_ADD_SIMPLE(comp, 0xA1, ie->data, i);
++ ASN1_PUSH(compstk, compsp, comp);
++
++ ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, ie->data, i, typeofnumber_from_q931(pri, call->redirectingplan >> 4));
++
++ j = asn1_string_encode(ASN1_NUMERICSTRING, &ie->data[i], len - i, 20, call->redirectingnum, strlen(call->redirectingnum));
++ if (j < 0) {
++ i = first_i;
++ goto finish2;
++ }
++ i += j;
++ ASN1_FIXUP(compstk, compsp, ie->data, i);
++ ASN1_FIXUP(compstk, compsp, ie->data, i);
++ break;
++ }
++ /* fall through */
++ case PRES_PROHIB_USER_NUMBER_PASSED_SCREEN:
++ case PRES_PROHIB_USER_NUMBER_NOT_SCREENED:
++ ASN1_ADD_SIMPLE(comp, 0x81, ie->data, i);
++ break;
++ /* Don't know how to handle this */
++ case PRES_ALLOWED_NETWORK_NUMBER:
++ case PRES_PROHIB_NETWORK_NUMBER:
++ case PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN:
++ case PRES_PROHIB_USER_NUMBER_FAILED_SCREEN:
++ ASN1_ADD_SIMPLE(comp, 0x81, ie->data, i);
++ break;
++ default:
++ pri_message(pri, "!! Undefined presentation value for redirecting number: %d\n", call->redirectingpres);
++ case PRES_NUMBER_NOT_AVAILABLE:
++ ASN1_ADD_SIMPLE(comp, 0x82, ie->data, i);
++ break;
++ }
++ ASN1_FIXUP(compstk, compsp, ie->data, i);
++
++ /* Fix length of stacked components */
++ while(compsp > 0) {
++ ASN1_FIXUP(compstk, compsp, ie->data, i);
++ }
++ }
++finish2:
++ return (i ? i+2 : 0);
++}
++#endif
++
+ static FUNC_RECV(receive_facility)
+ {
+ int i = 0;
+@@ -1366,7 +1806,7 @@
+
+ static FUNC_DUMP(dump_keypad_facility)
+ {
+- char tmp[64];
++ char tmp[64] = "";
+
+ if (ie->len == 0 || ie->len > sizeof(tmp))
+ return;
+@@ -1377,7 +1817,7 @@
+
+ static FUNC_RECV(receive_keypad_facility)
+ {
+- int mylen;
++ int mylen = 0;
+
+ if (ie->len == 0)
+ return -1;
+@@ -1392,11 +1832,31 @@
+ return 0;
+ }
+
++static FUNC_RECV(receive_time_date)
++{
++ return 0;
++}
++
++static FUNC_SEND(transmit_time_date) {
++ time_t now;
++ struct tm *timedate;
++ time(&now);
++ timedate = localtime(&now);
++ ie->data[0] = timedate->tm_year - 100; // 1900+
++ ie->data[1] = timedate->tm_mon + 1;
++ ie->data[2] = timedate->tm_mday;
++ ie->data[3] = timedate->tm_hour;
++ ie->data[4] = timedate->tm_min;
++ return 7;
++}
++
++
++
+ static FUNC_DUMP(dump_display)
+ {
+ int x, y;
+ char *buf = malloc(len + 1);
+- char tmp[80];
++ char tmp[80]="";
+ if (buf) {
+ x=y=0;
+ if ((x < ie->len) && (ie->data[x] & 0x80)) {
+@@ -1411,7 +1871,7 @@
+ }
+ }
+
+-static void dump_ie_data(unsigned char *c, int len)
++static void dump_ie_data(struct pri *pri, unsigned char *c, int len)
+ {
+ char tmp[1024] = "";
+ int x=0;
+@@ -1421,7 +1881,7 @@
+ ((*c >= 'a') && (*c <= 'z')) ||
+ ((*c >= '0') && (*c <= '9'))) {
+ if (!lastascii) {
+- if (*tmp) {
++ if (strlen(tmp)) {
+ tmp[x++] = ',';
+ tmp[x++] = ' ';
+ }
+@@ -1433,7 +1893,7 @@
+ if (lastascii) {
+ tmp[x++] = '\'';
+ }
+- if (*tmp) {
++ if (strlen(tmp)) {
+ tmp[x++] = ',';
+ tmp[x++] = ' ';
+ }
+@@ -1446,14 +1906,14 @@
+ }
+ if (lastascii)
+ tmp[x++] = '\'';
+- pri_message(NULL, tmp);
++ pri_message(pri, tmp);
+ }
+
+ static FUNC_DUMP(dump_facility)
+ {
+ pri_message(pri, "%c Facility (len=%2d, codeset=%d) [ ", prefix, len, Q931_IE_CODESET(full_ie));
+- dump_ie_data(ie->data, ie->len);
+- pri_message(NULL, " ]\n");
++ dump_ie_data(pri, ie->data, ie->len);
++ pri_message(pri, " ]\n");
+ }
+
+ static FUNC_DUMP(dump_network_spec_fac)
+@@ -1463,7 +1923,7 @@
+ pri_message(pri, code2str(ie->data[1], facilities, sizeof(facilities) / sizeof(facilities[0])));
+ }
+ else
+- dump_ie_data(ie->data, ie->len);
++ dump_ie_data(pri, ie->data, ie->len);
+ pri_message(pri, " ]\n");
+ }
+
+@@ -1940,11 +2400,11 @@
+ { 1, Q931_IE_INFO_REQUEST, "Feature Request" },
+ { 1, Q931_IE_FEATURE_IND, "Feature Indication" },
+ { 1, Q931_IE_SEGMENTED_MSG, "Segmented Message" },
+- { 1, Q931_IE_CALL_IDENTITY, "Call Identity", dump_call_identity },
++ { 1, Q931_IE_CALL_IDENTITY, "Call Identity", dump_call_identity, receive_call_identity, transmit_call_identity },
+ { 1, Q931_IE_ENDPOINT_ID, "Endpoint Identification" },
+ { 1, Q931_IE_NOTIFY_IND, "Notification Indicator", dump_notify, receive_notify, transmit_notify },
+ { 1, Q931_DISPLAY, "Display", dump_display, receive_display, transmit_display },
+- { 1, Q931_IE_TIME_DATE, "Date/Time", dump_time_date },
++ { 1, Q931_IE_TIME_DATE, "Date/Time", dump_time_date, receive_time_date, transmit_time_date },
+ { 1, Q931_IE_KEYPAD_FACILITY, "Keypad Facility", dump_keypad_facility, receive_keypad_facility },
+ { 0, Q931_IE_SIGNAL, "Signal", dump_signal },
+ { 1, Q931_IE_SWITCHHOOK, "Switch-hook" },
+@@ -1952,6 +2412,7 @@
+ { 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_COLP, "Connect Line ID Presentation", dump_colp},
+ { 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 },
+@@ -2052,10 +2513,10 @@
+ break;
+ case 1:
+ cr = h->crv[0];
+- if (cr & 0x80) {
++ /* if (cr & 0x80) {
+ cr &= ~0x80;
+ cr |= 0x8000;
+- }
++ } */
+ break;
+ default:
+ pri_error(NULL, "Call Reference Length not supported: %d\n", h->crlen);
+@@ -2069,14 +2530,14 @@
+ int full_ie = Q931_FULL_IE(codeset, ie->ie);
+ int base_ie;
+
+- pri_message(NULL, "%c [", prefix);
+- pri_message(NULL, "%02x", ie->ie);
++ pri_message(pri, "%c [", prefix);
++ pri_message(pri, "%02x", ie->ie);
+ if (!(ie->ie & 0x80)) {
+- pri_message(NULL, " %02x", ielen(ie)-2);
++ pri_message(pri, " %02x", ielen(ie)-2);
+ for (x = 0; x + 2 < ielen(ie); ++x)
+- pri_message(NULL, " %02x", ie->data[x]);
++ pri_message(pri, " %02x", ie->data[x]);
+ }
+- pri_message(NULL, "]\n");
++ pri_message(pri, "]\n");
+
+ /* Special treatment for shifts */
+ if((full_ie & 0xf0) == Q931_LOCKING_SHIFT)
+@@ -2096,14 +2557,46 @@
+ pri_error(pri, "!! %c Unknown IE %d (len = %d)\n", prefix, base_ie, ielen(ie));
+ }
+
+-static q931_call *q931_getcall(struct pri *pri, int cr)
++static q921_call *q921_getcall(struct pri *pri, struct q931_call *c, int tei)
++{
++ q921_call *cur;
++ cur = c->phones;
++ while(cur) {
++ if (cur->tei == tei) {
++ return cur;
++ }
++ cur = cur->next;
++ }
++ /* No call exists, make a new one */
++ if (pri->debug & PRI_DEBUG_Q921_STATE)
++ pri_message(pri, "-- Making new q921 call for cref %d tei %d\n", c->cr, tei);
++ cur = malloc(sizeof(struct q921_call));
++ memset(cur, 0, sizeof(cur));
++ cur->tei = tei;
++ cur->proc = 0;
++ cur->channel = -1;
++ cur->next = c->phones;
++ c->phones = cur;
++ return cur;
++}
++
++static q931_call *q931_getcall(struct pri *pri, int cr, int tei)
+ {
+ q931_call *cur, *prev;
+ cur = *pri->callpool;
+ prev = NULL;
+ while(cur) {
+- if (cur->cr == cr)
+- return cur;
++ if ((pri->localtype == BRI_NETWORK_PTMP) && (tei >= 0)) {
++ // hmm...ok, we might be the 1st responding to the setup
++ // or it is really our call
++ if ((cur->cr == cr) && ((cur->tei == tei) || (cur->tei == 127)))
++ return cur;
++ // or we might not be the 1st responding, then we need to clone
++ // the call struct to hangup properly
++ } else {
++ if (cur->cr == cr)
++ return cur;
++ }
+ prev = cur;
+ cur = cur->next;
+ }
+@@ -2116,6 +2609,7 @@
+ /* Call reference */
+ cur->cr = cr;
+ cur->pri = pri;
++ cur->tei = tei;
+ /* Append to end of list */
+ if (prev)
+ prev->next = cur;
+@@ -2131,24 +2625,42 @@
+ do {
+ cur = *pri->callpool;
+ pri->cref++;
+- if (pri->cref > 32767)
+- pri->cref = 1;
++ if ((pri->localtype == PRI_NETWORK) || (pri->localtype == PRI_CPE)) {
++ if (pri->cref > 32767)
++ pri->cref = 1;
++ } else {
++ // BRI
++ if (pri->cref > 255)
++ pri->cref = 1;
++ }
+ while(cur) {
+- if (cur->cr == (0x8000 | pri->cref))
+- break;
++ if ((pri->localtype == PRI_NETWORK) || (pri->localtype == PRI_CPE)) {
++ if (cur->cr == (0x8000 | pri->cref))
++ break;
++ } else {
++ // BRIs have only 1 bye cref
++ if (cur->cr == (0x80 | pri->cref))
++ break;
++ }
+ cur = cur->next;
+ }
+ } while(cur);
+- return q931_getcall(pri, pri->cref | 0x8000);
++ if ((pri->localtype == PRI_NETWORK) || (pri->localtype == PRI_CPE)) {
++ return q931_getcall(pri, pri->cref | 0x8000, 0);
++ } else {
++ // BRI
++ return q931_getcall(pri, pri->cref | 0x80, 0);
++ }
+ }
+
+-static void q931_destroy(struct pri *pri, int cr, q931_call *c)
++static void q931_destroy(struct pri *pri, int cr, q931_call *c, int tei)
+ {
+ q931_call *cur, *prev;
+ prev = NULL;
+ cur = *pri->callpool;
+ while(cur) {
+- if ((c && (cur == c)) || (!c && (cur->cr == cr))) {
++// if ((c && (cur == c)) || (!c && (cur->cr == cr))) {
++ if ((c && (cur == c)) || (!c && ((cur->cr == cr) && ((pri->localtype != BRI_NETWORK_PTMP) || (cur->tei == tei))))) {
+ if (prev)
+ prev->next = cur->next;
+ else
+@@ -2157,6 +2669,8 @@
+ pri_message(pri, "NEW_HANGUP DEBUG: Destroying the call, ourstate %s, peerstate %s\n",callstate2str(cur->ourcallstate),callstate2str(cur->peercallstate));
+ if (cur->retranstimer)
+ pri_schedule_del(pri, cur->retranstimer);
++ if (cur->t303timer)
++ pri_schedule_del(pri, cur->t303timer);
+ pri_call_apdu_queue_cleanup(cur);
+ free(cur);
+ return;
+@@ -2167,16 +2681,16 @@
+ pri_error(pri, "Can't destroy call %d!\n", cr);
+ }
+
+-static void q931_destroycall(struct pri *pri, int cr)
++static void q931_destroycall(struct pri *pri, int cr, int tei)
+ {
+- return q931_destroy(pri, cr, NULL);
++ return q931_destroy(pri, cr, NULL, tei);
+ }
+
+
+ void __q931_destroycall(struct pri *pri, q931_call *c)
+ {
+ if (pri && c)
+- q931_destroy(pri,0, c);
++ q931_destroy(pri,0, c, c->tei);
+ return;
+ }
+
+@@ -2288,6 +2802,10 @@
+ {
+ unsigned int x;
+ int full_ie = Q931_FULL_IE(codeset, ie->ie);
++ if (ielen(ie) > Q931_IE_MAX_LEN) {
++ pri_error(pri, "!! Invalid IE length %d (len = %d)\n", full_ie, ielen(ie));
++ return -1;
++ }
+ if (pri->debug & PRI_DEBUG_Q931_STATE)
+ pri_message(pri, "-- Processing IE %d (cs%d, %s)\n", ie->ie, codeset, ie2str(full_ie));
+ for (x=0;x<sizeof(ies) / sizeof(ies[0]);x++) {
+@@ -2305,21 +2823,36 @@
+ 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 briflag)
+ {
+ /* Returns header and message header and modifies length in place */
+ q931_h *h = (q931_h *)buf;
+- q931_mh * mh = (q931_mh *)(h->contents + 2);
++ q931_mh *mh;
+ 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) {
++
++ if (briflag == 1) {
++ mh = (q931_mh *)(h->contents + 1);
++ h->crlen = 1; /* One bytes of Call Reference. Invert the top bit to make it from our sense */
++ if (call->cr || call->forceinvert) {
++ h->crv[0] = (call->cr ^ 0x80);
++ } else {
++ /* Unless of course this has no call reference */
++ h->crv[0] = 0;
++ }
++ *len -= 4;
++ } else {
++ mh = (q931_mh *)(h->contents + 2);
++ h->crlen = 2; /* Two bytes of Call Reference. Invert the top bit to make it from our sense */
++ if (call->cr || call->forceinvert) {
+ h->crv[0] = ((call->cr ^ 0x8000) & 0xff00) >> 8;
+ h->crv[1] = (call->cr & 0xff);
+- } else {
++ } else {
+ /* Unless of course this has no call reference */
+ h->crv[0] = 0;
+ h->crv[1] = 0;
++ }
++ *len -= 5;
+ }
+ if (pri->subchannel) {
+ /* On GR-303, top bit is always 0 */
+@@ -2328,13 +2861,23 @@
+ mh->f = 0;
+ *hb = h;
+ *mhb = mh;
+- *len -= 5;
+-
+ }
+
+-static int q931_xmit(struct pri *pri, q931_h *h, int len, int cr)
++static int q931_xmit(struct pri *pri, q931_h *h, int len, int cr, int tei)
+ {
+- q921_transmit_iframe(pri, h, len, cr);
++ q931_mh *mh;
++ if (pri->localtype == BRI_NETWORK_PTMP) {
++ mh = (q931_mh *)(h->contents + 1);
++ if (mh->msg == Q931_SETUP) {
++ q921_transmit_uframe(pri, h, len, cr, tei);
++ } else {
++ q921_transmit_iframe(pri, h, len, cr, tei);
++ }
++ } else if (pri->localtype == BRI_CPE_PTMP) {
++ q921_transmit_iframe(pri, h, len, cr, pri->tei);
++ } else {
++ q921_transmit_iframe(pri, h, len, cr, tei);
++ }
+ /* The transmit operation might dump the q921 header, so logging the q931
+ message body after the transmit puts the sections of the message in the
+ right order in the log */
+@@ -2360,7 +2903,11 @@
+
+ memset(buf, 0, sizeof(buf));
+ len = sizeof(buf);
+- init_header(pri, c, buf, &h, &mh, &len);
++ if ((pri->localtype == PRI_NETWORK) || (pri->localtype == PRI_CPE)) {
++ init_header(pri, c, buf, &h, &mh, &len, 0);
++ } else {
++ init_header(pri, c, buf, &h, &mh, &len, 1);
++ }
+ mh->msg = msgtype;
+ x=0;
+ codeset = 0;
+@@ -2395,11 +2942,34 @@
+ }
+ /* Invert the logic */
+ len = sizeof(buf) - len;
+- q931_xmit(pri, h, len, 1);
++ if (pri->localtype == BRI_CPE_PTMP) {
++ q931_xmit(pri, h, len, 1, pri->tei);
++ } else {
++ q931_xmit(pri, h, len, 1, c->tei);
++ }
+ c->acked = 1;
+ return 0;
+ }
+
++static int facility_ies[] = { Q931_IE_FACILITY, -1 };
++
++#if 0
++int q931_facility_kpj(struct pri *pri, q931_call *c, int operation, char *arguments)
++{
++ switch (operation) {
++ case 0x26: c->aoc = 1;
++ break;
++ case 0x24: c->aoc = 1;
++ break;
++ case 0x22: c->aoc = 1;
++ break;
++ default:
++ return -1;
++ }
++ return send_message(pri, c, Q931_FACILITY, facility_ies);
++}
++#endif
++
+ static int status_ies[] = { Q931_CAUSE, Q931_CALL_STATE, -1 };
+
+ static int q931_status(struct pri *pri, q931_call *c, int cause)
+@@ -2437,17 +3007,45 @@
+ return send_message(pri, c, Q931_INFORMATION, information_ies);
+ }
+
++static int information_display_ies[] = { Q931_DISPLAY, -1 };
++
++int q931_information_display(struct pri *pri, q931_call *c, char *display)
++{
++ int res=0;
++ char temp[256];
++ if (!display) return -1;
++ strncpy(temp, c->callername, sizeof(temp));
++ strncpy(c->callername, display, sizeof(c->callername));
++ res = send_message(pri, c, Q931_INFORMATION, information_display_ies);
++ strncpy(c->callername, temp, sizeof(c->callername));
++ return res;
++}
++
++int q931_add_display(struct pri *pri, q931_call *c, char *display)
++{
++ strncpy(c->display, display, sizeof(c->display));
++ return 0;
++}
++
++/* static int information_special_ies[] = { Q931_IE_SPECIAL, -1 };
++static int q931_information_special(struct pri *pri, q931_call *c)
++{
++ return send_message(pri, c, Q931_FACILITY, information_special_ies);
++}
++*/
++
++
+ 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_NULL;
+ c->peercallstate = Q931_CALL_STATE_NULL;
++ c->chanflags &= ~FLAG_PREFERRED;
++ c->chanflags |= FLAG_EXCLUSIVE;
+ return send_message(pri, c, Q931_RESTART_ACKNOWLEDGE, restart_ack_ies);
+ }
+
+-static int facility_ies[] = { Q931_IE_FACILITY, -1 };
+-
+ int q931_facility(struct pri*pri, q931_call *c)
+ {
+ return send_message(pri, c, Q931_FACILITY, facility_ies);
+@@ -2461,7 +3059,6 @@
+ if ((info > 0x2) || (info < 0x00))
+ return 0;
+ }
+-
+ if (info >= 0)
+ c->notify = info & 0x7F;
+ else
+@@ -2530,8 +3127,14 @@
+ static int alerting_ies[] = { -1 };
+ #endif
+
++// static int alerting_BRI_ies[] = { -1 };
++
+ int q931_alerting(struct pri *pri, q931_call *c, int channel, int info)
+ {
++ // never send two ALERTINGs!
++ if (c->alert > 0) return 0;
++ // XXX novo vox hack
++// if ((!c->proc) && (pri->localtype != BRI_CPE_PTMP))
+ if (!c->proc)
+ q931_call_proceeding(pri, c, channel, 0);
+ if (info) {
+@@ -2542,11 +3145,126 @@
+ c->progressmask = 0;
+ c->ourcallstate = Q931_CALL_STATE_CALL_RECEIVED;
+ c->peercallstate = Q931_CALL_STATE_CALL_DELIVERED;
++ c->alert = 1;
+ c->alive = 1;
+ return send_message(pri, c, Q931_ALERTING, alerting_ies);
++/* if ((pri->localtype == PRI_NETWORK) || (pri->localtype == PRI_CPE)) {
++ return send_message(pri, c, Q931_ALERTING, alerting_ies);
++ } else {
++ if ((pri->localtype == BRI_NETWORK) || (pri->localtype == BRI_NETWORK_PTMP)) {
++ return send_message(pri, c, Q931_ALERTING, alerting_ies);
++ } else {
++ // no PROGRESS_IND for BRI please
++ return send_message(pri, c, Q931_ALERTING, alerting_BRI_ies);
++ }
++ } */
+ }
+
+-static int connect_ies[] = { Q931_CHANNEL_IDENT, Q931_PROGRESS_INDICATOR, -1 };
++static int hold_acknowledge_ies[] = { -1 };
++
++int q931_hold_acknowledge(struct pri *pri, q931_call *c)
++{
++ return send_message(pri, c, Q931_HOLD_ACKNOWLEDGE, hold_acknowledge_ies);
++}
++
++static int hold_reject_ies[] = { Q931_CAUSE, -1 };
++
++int q931_hold_reject(struct pri *pri, q931_call *c)
++{
++ c->cause = 12;
++ c->causecode = CODE_CCITT;
++ c->causeloc = LOC_PRIV_NET_LOCAL_USER;
++ return send_message(pri, c, Q931_HOLD_REJECT, hold_reject_ies);
++}
++
++static int retrieve_acknowledge_ies[] = { Q931_CHANNEL_IDENT, -1 };
++
++int q931_retrieve_acknowledge(struct pri *pri, q931_call *c, int channel)
++{
++ if (channel)
++ c->channelno = channel;
++ c->chanflags &= ~FLAG_PREFERRED;
++ c->chanflags |= FLAG_EXCLUSIVE;
++ return send_message(pri, c, Q931_RETRIEVE_ACKNOWLEDGE, retrieve_acknowledge_ies);
++}
++
++static int retrieve_reject_ies[] = { -1 };
++
++int q931_retrieve_reject(struct pri *pri, q931_call *c)
++{
++ return send_message(pri, c, Q931_RETRIEVE_REJECT, retrieve_reject_ies);
++}
++
++static int suspend_acknowledge_ies[] = { Q931_DISPLAY, -1 };
++
++int q931_suspend_acknowledge(struct pri *pri, q931_call *c, char *display)
++{
++ char tempcallername[256];
++ int res;
++ c->ourcallstate = Q931_CALL_STATE_NULL;
++ c->peercallstate = Q931_CALL_STATE_NULL;
++ strncpy(tempcallername,c->callername,sizeof(tempcallername));
++ strncpy(c->callername,display,sizeof(c->callername));
++ res = send_message(pri, c, Q931_SUSPEND_ACKNOWLEDGE, suspend_acknowledge_ies);
++ strncpy(c->callername,tempcallername,sizeof(c->callername));
++ return res;
++}
++
++static int suspend_reject_ies[] = { Q931_DISPLAY, Q931_CAUSE, -1 };
++
++int q931_suspend_reject(struct pri *pri, q931_call *c, char *display)
++{
++ char tempcallername[256];
++ int res;
++ strncpy(tempcallername,c->callername,sizeof(tempcallername));
++ strncpy(c->callername,display,sizeof(c->callername));
++ c->cause = 12;
++ c->causecode = CODE_CCITT;
++ c->causeloc = LOC_PRIV_NET_LOCAL_USER;
++ res = send_message(pri, c, Q931_SUSPEND_REJECT, suspend_reject_ies);
++ strncpy(c->callername,tempcallername,sizeof(c->callername));
++ return res;
++}
++
++static int resume_reject_ies[] = { Q931_CAUSE, Q931_DISPLAY, -1 };
++
++int q931_resume_reject(struct pri *pri, q931_call *c, char *display)
++{
++ char tempcallername[256];
++ int res;
++ c->cause = 12;
++ c->causecode = CODE_CCITT;
++ c->causeloc = LOC_PRIV_NET_LOCAL_USER;
++ strncpy(tempcallername,c->callername,sizeof(tempcallername));
++ strncpy(c->callername,display,sizeof(c->callername));
++ res = send_message(pri, c, Q931_RESUME_REJECT, resume_reject_ies);
++ strncpy(c->callername,tempcallername,sizeof(c->callername));
++ return res;
++}
++
++static int resume_acknowledge_ies[] = { Q931_CHANNEL_IDENT, Q931_DISPLAY, -1 };
++
++int q931_resume_acknowledge(struct pri *pri, q931_call *c, int channel, char *display)
++{
++ char tempcallername[256];
++ int res;
++ if (channel)
++ c->channelno = channel;
++ c->chanflags &= ~FLAG_PREFERRED;
++ c->chanflags |= FLAG_EXCLUSIVE;
++ c->alive = 1;
++ c->ourcallstate = Q931_CALL_STATE_ACTIVE;
++ c->peercallstate = Q931_CALL_STATE_ACTIVE;
++ strncpy(tempcallername,c->callername,sizeof(tempcallername));
++ strncpy(c->callername,display,sizeof(c->callername));
++ res = send_message(pri, c, Q931_RESUME_ACKNOWLEDGE, resume_acknowledge_ies);
++ strncpy(c->callername,tempcallername,sizeof(c->callername));
++ return res;
++}
++
++
++static int connect_ies[] = { Q931_CHANNEL_IDENT, Q931_PROGRESS_INDICATOR, Q931_DISPLAY, -1 };
++static int connect_NET_ies[] = { Q931_CHANNEL_IDENT, Q931_PROGRESS_INDICATOR, Q931_IE_TIME_DATE, -1 };
+
+ int q931_setup_ack(struct pri *pri, q931_call *c, int channel, int nonisdn)
+ {
+@@ -2567,9 +3285,35 @@
+ c->ourcallstate = Q931_CALL_STATE_OVERLAP_RECEIVING;
+ c->peercallstate = Q931_CALL_STATE_OVERLAP_SENDING;
+ c->alive = 1;
++ if (pri->localtype == BRI_NETWORK_PTMP) {
++ c->progloc = LOC_PRIV_NET_LOCAL_USER;
++ c->progcode = CODE_CCITT;
++ c->progress = Q931_PROG_INBAND_AVAILABLE;
++ }
+ return send_message(pri, c, Q931_SETUP_ACKNOWLEDGE, connect_ies);
+ }
+
++static void pri_setup_response_timeout(void *data)
++{
++ struct q931_call *c = data;
++ struct pri *pri = NULL;
++ if (!c) return;
++ pri = c->pri;
++ if (!pri) return;
++ c->alive = 1;
++ c->cause = PRI_CAUSE_NO_USER_RESPONSE;
++ if (pri->debug & PRI_DEBUG_Q931_STATE)
++ pri_message(pri, "No response to SETUP message\n");
++ pri->schedev = 1;
++ 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.cause = PRI_CAUSE_SWITCH_CONGESTION;
++ pri->ev.hangup.call = c;
++ q931_hangup(pri, c, c->cause);
++}
++
+ static void pri_connect_timeout(void *data)
+ {
+ struct q931_call *c = data;
+@@ -2645,7 +3389,12 @@
+ c->retranstimer = 0;
+ if ((pri->localtype == PRI_CPE) && (!pri->subchannel))
+ c->retranstimer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T313], pri_connect_timeout, c);
+- return send_message(pri, c, Q931_CONNECT, connect_ies);
++ if ((pri->localtype != PRI_CPE) && (pri->localtype != BRI_CPE) && (pri->localtype != BRI_CPE_PTMP)) {
++ // networks may send datetime
++ return send_message(pri, c, Q931_CONNECT, connect_NET_ies);
++ } else {
++ return send_message(pri, c, Q931_CONNECT, connect_ies);
++ }
+ }
+
+ static int release_ies[] = { Q931_CAUSE, Q931_IE_USER_USER, -1 };
+@@ -2679,7 +3428,7 @@
+ int q931_restart(struct pri *pri, int channel)
+ {
+ struct q931_call *c;
+- c = q931_getcall(pri, 0 | 0x8000);
++ c = q931_getcall(pri, 0 | 0x8000, 0);
+ if (!c)
+ return -1;
+ if (!channel)
+@@ -2716,6 +3465,9 @@
+ return 0;
+ }
+
++//static int setup_ies[] = { Q931_BEARER_CAPABILITY, Q931_CHANNEL_IDENT, Q931_DISPLAY, Q931_PROGRESS_INDICATOR,
++// Q931_IE_SIGNAL, Q931_CALLING_PARTY_NUMBER, Q931_CALLED_PARTY_NUMBER, Q931_SENDING_COMPLETE, -1 };
++
+ static int setup_ies[] = { Q931_BEARER_CAPABILITY, Q931_CHANNEL_IDENT, Q931_IE_FACILITY, Q931_PROGRESS_INDICATOR, Q931_NETWORK_SPEC_FAC, Q931_DISPLAY, Q931_IE_USER_USER,
+ Q931_CALLING_PARTY_NUMBER, Q931_CALLED_PARTY_NUMBER, Q931_REDIRECTING_NUMBER, Q931_SENDING_COMPLETE, Q931_IE_ORIGINATING_LINE_INFO, Q931_IE_GENERIC_DIGITS, -1 };
+
+@@ -2726,7 +3478,12 @@
+ int q931_setup(struct pri *pri, q931_call *c, struct pri_sr *req)
+ {
+ int res;
+-
++
++ if (pri->localtype == BRI_NETWORK_PTMP) {
++ c->tei = 127;
++ } else {
++ c->tei = 0;
++ }
+
+ c->transcapability = req->transmode;
+ c->transmoderate = TRANS_MODE_64_CIRCUIT;
+@@ -2752,12 +3509,12 @@
+ else if (c->channelno)
+ c->chanflags = FLAG_PREFERRED;
+ if (req->caller) {
+- libpri_copy_string(c->callernum, req->caller, sizeof(c->callernum));
++ strncpy(c->callernum, req->caller, sizeof(c->callernum) - 1);
+ c->callerplan = req->callerplan;
+ if (req->callername)
+- libpri_copy_string(c->callername, req->callername, sizeof(c->callername));
++ strncpy(c->callername, req->callername, sizeof(c->callername) - 1);
+ else
+- c->callername[0] = '\0';
++ strcpy(c->callername, "");
+ if ((pri->switchtype == PRI_SWITCH_DMS100) ||
+ (pri->switchtype == PRI_SWITCH_ATT4ESS)) {
+ /* Doesn't like certain presentation types */
+@@ -2766,13 +3523,13 @@
+ }
+ c->callerpres = req->callerpres;
+ } else {
+- c->callernum[0] = '\0';
+- c->callername[0] = '\0';
++ strcpy(c->callernum, "");
++ strcpy(c->callername, "");
+ c->callerplan = PRI_UNKNOWN;
+ c->callerpres = PRES_NUMBER_NOT_AVAILABLE;
+ }
+ if (req->redirectingnum) {
+- libpri_copy_string(c->redirectingnum, req->redirectingnum, sizeof(c->redirectingnum));
++ strncpy(c->redirectingnum, req->redirectingnum, sizeof(c->redirectingnum) - 1);
+ c->redirectingplan = req->redirectingplan;
+ if ((pri->switchtype == PRI_SWITCH_DMS100) ||
+ (pri->switchtype == PRI_SWITCH_ATT4ESS)) {
+@@ -2783,13 +3540,13 @@
+ c->redirectingpres = req->redirectingpres;
+ c->redirectingreason = req->redirectingreason;
+ } else {
+- c->redirectingnum[0] = '\0';
++ strcpy(c->redirectingnum, "");
+ c->redirectingplan = PRI_UNKNOWN;
+ c->redirectingpres = PRES_NUMBER_NOT_AVAILABLE;
+ c->redirectingreason = PRI_REDIR_UNKNOWN;
+ }
+ if (req->called) {
+- libpri_copy_string(c->callednum, req->called, sizeof(c->callednum));
++ strncpy(c->callednum, req->called, sizeof(c->callednum) - 1);
+ c->calledplan = req->calledplan;
+ } else
+ return -1;
+@@ -2810,12 +3567,17 @@
+ res = send_message(pri, c, Q931_SETUP, cis_setup_ies);
+ else
+ 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;
++// if ((pri->localtype == BRI_NETWORK) || (pri->localtype == BRI_NETWORK_PTMP) || (pri->localtype == PRI_NETWORK)) {
++ c->t303timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T303], pri_setup_response_timeout, c);
++ c->t303running = 1;
++// }
+ }
+ return res;
+
+@@ -2831,7 +3593,11 @@
+ if (cause > -1) {
+ c->cause = cause;
+ c->causecode = CODE_CCITT;
+- c->causeloc = LOC_PRIV_NET_LOCAL_USER;
++ if ((pri->localtype == PRI_NETWORK) || (pri->localtype == BRI_NETWORK) || (pri->localtype == BRI_NETWORK_PTMP)) {
++ c->causeloc = LOC_PRIV_NET_LOCAL_USER;
++ } else {
++ c->causeloc = LOC_USER;
++ }
+ /* release_ies has CAUSE in it */
+ res = send_message(pri, c, Q931_RELEASE_COMPLETE, release_ies);
+ } else
+@@ -2856,6 +3622,117 @@
+ return 0;
+ }
+
++/* here we cleanly hangup the phones that responded to our call but didnt get the call */
++int q921_hangup(struct pri *pri, q931_call *c, int tei)
++{
++ q921_call *cur,*prev;
++ int tc;
++ int ttei;
++ int res=0;
++
++ if (!pri || !c)
++ return -1;
++
++ if (pri->localtype != BRI_NETWORK_PTMP){
++ return 0;
++ }
++// pri_error(pri, "q921_hangup(%d, %d)\n", c->cr, tei);
++
++ if (tei == 127) {
++ tei = c->tei;
++ }
++// pri_error(pri, "tei %d\n", tei);
++
++ cur = c->phones;
++
++ tc = c->cause;
++ ttei = c->tei;
++ while (cur) {
++ if (cur->tei != tei) {
++ c->cause = PRI_CAUSE_NORMAL_CLEARING;
++ c->tei = cur->tei;
++ if (pri->debug & PRI_DEBUG_Q921_STATE)
++ pri_message(pri, "sending RELEASE for TEI %d\n", cur->tei);
++ send_message(pri, c, Q931_RELEASE, release_ies);
++ }
++ prev = cur;
++ cur = cur->next;
++ if (prev) {
++ free(prev);
++ prev = NULL;
++ }
++ }
++ c->phones = NULL;
++ c->tei = ttei;
++ c->cause = tc;
++
++ if (c->tei == 127) {
++ q931_destroycall(pri, c->cr, c->tei);
++ // make sure * frees the channel
++/* pri_error(pri, "returning PRI_EVENT_HANGUP_ACK\n");
++ res = Q931_RES_HAVEEVENT;
++ pri->ev.hangup.channel = c->channelno;
++ pri->ev.e = PRI_EVENT_HANGUP_ACK; */
++ }
++ return res;
++}
++
++/* here we handle release_completes from the phones
++ because some (elmeg) phones do not send a disconnect
++ message when the phone is busy */
++int q921_handle_hangup(struct pri *pri, q931_call *c, int tei)
++{
++ q921_call *cur,*match,*prev=NULL;
++ int left=0;
++ int res=0;
++
++ if (!pri || !c)
++ return -1;
++
++ if (pri->localtype != BRI_NETWORK_PTMP){
++ return 0;
++ }
++
++ cur = c->phones;
++
++ while (cur) {
++ if (cur->tei == tei) {
++ match = cur;
++ if (prev) {
++ prev->next = cur->next;
++ cur = prev;
++ } else {
++ c->phones = cur->next;
++ }
++ free(match);
++ }
++ prev = cur;
++ if (cur) cur = cur->next;
++ }
++
++ cur = c->phones;
++
++ while (cur) {
++ left++;
++ cur = cur->next;
++ }
++
++ // if all phones have signalled busy AND the timer is not running anymore!
++ if ((left==0) && (c->cause == PRI_CAUSE_USER_BUSY) && (c->t303running == 0)) {
++ // pri_error(pri, "q921_handle_hangup(%d, %d, %d)\n", c->cr, tei, c->tei);
++ // make sure * frees the channel
++ res = Q931_RES_HAVEEVENT;
++ pri->ev.hangup.cause = PRI_CAUSE_USER_BUSY;
++ pri->ev.hangup.channel = c->channelno | (c->ds1no << 8);
++ pri->ev.hangup.cref = c->cr;
++ pri->ev.hangup.call = c;
++ pri->ev.e = PRI_EVENT_HANGUP;
++ }
++ return res;
++ }
++
++
++
+ int q931_hangup(struct pri *pri, q931_call *c, int cause)
+ {
+ int disconnect = 1;
+@@ -2881,7 +3758,7 @@
+ 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);
++ q931_destroycall(pri, c->cr, c->tei);
+ else if (c->peercallstate == Q931_CALL_STATE_RELEASE_REQUEST)
+ q931_release_complete(pri,c,cause);
+ break;
+@@ -2907,6 +3784,11 @@
+ /* 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 (pri->localtype == BRI_NETWORK_PTMP) {
++ if (c->tei == 127) {
++ break;
++ }
++ }
+ if (disconnect)
+ q931_disconnect(pri,c,cause);
+ else if (release_compl)
+@@ -2922,8 +3804,14 @@
+ break;
+ case Q931_CALL_STATE_DISCONNECT_INDICATION:
+ /* received DISCONNECT */
++ if (pri->localtype == BRI_NETWORK_PTMP) {
++ if (c->tei == 127) {
++ break;
++ }
++ }
+ if (c->peercallstate == Q931_CALL_STATE_DISCONNECT_REQUEST) {
+ c->alive = 1;
++// pri_error(pri, "sending release to %d\n", c->tei);
+ q931_release(pri,c,cause);
+ }
+ break;
+@@ -2937,19 +3825,17 @@
+ pri_error(pri, "q931_hangup shouldn't be called in this state, ourstate %s, peerstate %s\n",callstate2str(c->ourcallstate),callstate2str(c->peercallstate));
+ break;
+ default:
+- pri_error(pri, "We're not yet handling hanging up when our state is %d, contact support at digium.com, ourstate %s, peerstate %s\n",
+- c->ourcallstate,
+- callstate2str(c->ourcallstate),
+- callstate2str(c->peercallstate));
++ pri_error(pri, "We're not yet handling hanging up when our state is %d, contact support at 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)
++int q931_receive(struct pri *pri, q931_h *h, int len, int tei)
+ {
+ q931_mh *mh;
++ q921_call *l2c;
+ q931_call *c;
+ q931_ie *ie;
+ unsigned int x;
+@@ -2974,13 +3860,13 @@
+ 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);
++ q931_xmit(pri, h, len, 1, tei);
+ 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));
++ c = q931_getcall(pri, q931_cr(h), tei);
+ if (!c) {
+ pri_error(pri, "Unable to locate call %d\n", q931_cr(h));
+ return -1;
+@@ -2998,11 +3884,12 @@
+ c->ri = -1;
+ break;
+ case Q931_FACILITY:
+- c->callername[0] = '\0';
++ strcpy(c->callername, "");
+ break;
+ case Q931_SETUP:
+ if (pri->debug & PRI_DEBUG_Q931_STATE)
+ pri_message(pri, "-- Processing Q.931 Call Setup\n");
++ c->tei = tei;
+ c->channelno = -1;
+ c->slotmap = -1;
+ c->chanflags = 0;
+@@ -3018,33 +3905,49 @@
+ c->calledplan = -1;
+ c->callerplan = -1;
+ c->callerpres = -1;
+- c->callernum[0] = '\0';
+- c->callednum[0] = '\0';
+- c->callername[0] = '\0';
++ strcpy(c->callernum, "");
++ strcpy(c->callednum, "");
++ strcpy(c->callername, "");
+ 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->redirectingplan = -1;
++ c->redirectingpres = -1;
++ c->redirectingreason = -1;
++ c->origcalledplan = -1;
++ c->origcalledpres = -1;
++ c->origredirectingreason = -1;
++ strcpy(c->redirectingnum, "");
++ strcpy(c->origcallednum, "");
++ strcpy(c->redirectingname, "");
++ strcpy(c->origcalledname, "");
++ c->useruserprotocoldisc = -1;
++ strcpy(c->useruserinfo, "");
+ c->complete = 0;
+ c->nonisdn = 0;
+ c->aoc_units = -1;
+- /* Fall through */
++ strcpy(c->digits, "");
++ strcpy(c->display, "");
++ c->progress = -1;
++ c->progressmask = 0;
++ break;
+ case Q931_CONNECT:
++ if (c->t303timer) {
++ c->t303running = 0;
++ pri_schedule_del(pri, c->t303timer);
++ }
++ c->useruserinfo[0] = '\0';
++ c->t303timer = 0;
++ c->progress = -1;
++ break;
+ case Q931_ALERTING:
+ case Q931_PROGRESS:
+ c->useruserinfo[0] = '\0';
+- c->cause = -1;
+ case Q931_CALL_PROCEEDING:
++ if (c->t303timer) {
++ c->t303running = 0;
++ pri_schedule_del(pri, c->t303timer);
++ }
++ c->t303timer = 0;
+ c->progress = -1;
+ c->progressmask = 0;
+ break;
+@@ -3059,14 +3962,19 @@
+ c->causecode = -1;
+ c->causeloc = -1;
+ c->aoc_units = -1;
++ c->useruserinfo[0] = '\0';
+ if (c->retranstimer)
+ pri_schedule_del(pri, c->retranstimer);
+ c->retranstimer = 0;
+- c->useruserinfo[0] = '\0';
++ if (c->t303timer) {
++ c->t303running = 0;
++ pri_schedule_del(pri, c->t303timer);
++ }
++ c->t303timer = 0;
+ break;
+ case Q931_RELEASE_COMPLETE:
+ if (c->retranstimer)
+- pri_schedule_del(pri, c->retranstimer);
++ pri_schedule_del(pri, c->retranstimer);
+ c->retranstimer = 0;
+ c->useruserinfo[0] = '\0';
+ case Q931_STATUS:
+@@ -3084,22 +3992,32 @@
+ case Q931_STATUS_ENQUIRY:
+ break;
+ case Q931_SETUP_ACKNOWLEDGE:
++ if (c->t303timer) {
++ c->t303running = 0;
++ pri_schedule_del(pri, c->t303timer);
++ }
++ c->t303timer = 0;
+ break;
+ case Q931_NOTIFY:
+ break;
++ case Q931_HOLD:
++ break;
++ case Q931_RETRIEVE:
++ break;
++ case Q931_RESUME:
++ c->tei = tei;
++ break;
++ case Q931_SUSPEND:
++ 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);
+@@ -3108,7 +4026,7 @@
+ 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);
++ q931_destroycall(pri,c->cr,c->tei);
+ return -1;
+ }
+ memset(mandies, 0, sizeof(mandies));
+@@ -3188,12 +4106,17 @@
+ missingmand = 0;
+ for (x=0;x<MAX_MAND_IES;x++) {
+ if (mandies[x]) {
+- /* check if there is no channel identification when we're configured as network -> that's not an error */
+- if (((pri->localtype != PRI_NETWORK) || (mh->msg != Q931_SETUP) || (mandies[x] != Q931_CHANNEL_IDENT)) &&
+- ((mh->msg != Q931_PROGRESS) || (mandies[x] != Q931_PROGRESS_INDICATOR))) {
++ int network = pri->localtype == PRI_NETWORK || pri->localtype == BRI_NETWORK || pri->localtype == BRI_NETWORK_PTMP;
++ /* check if there is no channel identification when we're configured as network -> that's not an error */
++ if (network) {
++ if (((mh->msg == Q931_SETUP) && (mandies[x] == Q931_CHANNEL_IDENT)) ||
++ ((mh->msg == Q931_PROGRESS) && (mandies[x] == Q931_PROGRESS_INDICATOR))) {
++ /* according to ets 300 102-1 a progress indicator is mandatory, but so what? ;-) */
++ } else {
+ pri_error(pri, "XXX Missing handling for mandatory IE %d (cs%d, %s) XXX\n", Q931_IE_IE(mandies[x]), Q931_IE_CODESET(mandies[x]), ie2str(mandies[x]));
+ missingmand++;
+ }
++ }
+ }
+ }
+
+@@ -3202,7 +4125,7 @@
+ case Q931_RESTART:
+ if (missingmand) {
+ q931_status(pri, c, PRI_CAUSE_MANDATORY_IE_MISSING);
+- q931_destroycall(pri, c->cr);
++ q931_destroycall(pri, c->cr, c->tei);
+ break;
+ }
+ c->ourcallstate = Q931_CALL_STATE_RESTART;
+@@ -3220,6 +4143,7 @@
+ }
+ /* Must be new call */
+ if (!c->newcall) {
++ pri_error(pri, "received SETUP message for call that is not a new call (retransmission). \n");
+ break;
+ }
+ if (c->progressmask & PRI_PROG_CALLER_NOT_ISDN)
+@@ -3237,27 +4161,31 @@
+ 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.callingplanani = c->callerplanani;
++ strncpy(pri->ev.ring.callingnum, c->callernum, sizeof(pri->ev.ring.callingnum) - 1);
++ strncpy(pri->ev.ring.callingname, c->callername, sizeof(pri->ev.ring.callingname) - 1);
+ 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));
++ strncpy(pri->ev.ring.callingsubaddr, c->callingsubaddr, sizeof(pri->ev.ring.callingsubaddr) - 1);
++ if (!strlen(c->callednum) && strlen(c->digitbuf)) {
++ strncpy(pri->ev.ring.callednum, c->digitbuf, sizeof(pri->ev.ring.callednum) - 1);
++ } else {
++ strncpy(pri->ev.ring.callednum, c->callednum, sizeof(pri->ev.ring.callednum) - 1);
++ }
++ strncpy(pri->ev.ring.origcalledname, c->origcalledname, sizeof(pri->ev.ring.origcalledname) - 1);
++ strncpy(pri->ev.ring.origcallednum, c->origcallednum, sizeof(pri->ev.ring.origcallednum) - 1);
++ strncpy(pri->ev.ring.redirectingnum, c->redirectingnum, sizeof(pri->ev.ring.redirectingnum) - 1);
++ strncpy(pri->ev.ring.redirectingname, c->redirectingname, sizeof(pri->ev.ring.redirectingname) - 1);
++ strncpy(pri->ev.ring.useruserinfo, c->useruserinfo, sizeof(pri->ev.ring.useruserinfo) - 1);
+ 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.tei = c->tei;
+ pri->ev.ring.call = c;
++ pri->ev.ring.cref = c->cr;
+ pri->ev.ring.layer1 = c->userl1;
+ pri->ev.ring.complete = c->complete;
+ pri->ev.ring.ctype = c->transcapability;
+@@ -3270,6 +4198,9 @@
+ q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
+ break;
+ }
++ if (pri->localtype == BRI_NETWORK_PTMP) {
++ l2c = q921_getcall(pri, c, tei);
++ }
+ c->ourcallstate = Q931_CALL_STATE_CALL_DELIVERED;
+ c->peercallstate = Q931_CALL_STATE_CALL_RECEIVED;
+ pri->ev.e = PRI_EVENT_RINGING;
+@@ -3290,17 +4221,24 @@
+ q931_status(pri, c, PRI_CAUSE_WRONG_MESSAGE);
+ break;
+ }
++ /* TEI got the call */
++ c->tei = tei;
+ 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 | (c->ds1no << 8) | (c->ds1explicit << 16);
+ pri->ev.answer.cref = c->cr;
+ pri->ev.answer.call = c;
++ pri->ev.answer.tei = c->tei;
+ pri->ev.answer.progress = c->progress;
+ pri->ev.answer.progressmask = c->progressmask;
+ libpri_copy_string(pri->ev.answer.useruserinfo, c->useruserinfo, sizeof(pri->ev.ring.useruserinfo));
+ c->useruserinfo[0] = '\0';
+ q931_connect_acknowledge(pri, c);
++ if (pri->localtype == BRI_NETWORK_PTMP) {
++ /* Release all other TEIs */
++ q921_hangup(pri, c, tei);
++ }
+ if (c->justsignalling) { /* Make sure WE release when we initiatie a signalling only connection */
+ q931_release(pri, c, PRI_CAUSE_NORMAL_CLEARING);
+ break;
+@@ -3308,23 +4246,43 @@
+ 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);
+-#endif
++ if ((pri->localtype == PRI_CPE) || (pri->localtype == PRI_NETWORK)) {
++ q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
++ } else {
++ // BRI uses the dummy cref for sservices like ccnr
++ }
++ break;
++ }
++ if (c->facility > 0) {
++ pri->ev.e = PRI_EVENT_FACILITY;
++ pri->ev.facility.channel = c->channelno | (c->ds1no << 8);
++ pri->ev.facility.cref = c->cr;
++ pri->ev.facility.tei = c->tei;
++ pri->ev.facility.call = c;
++ switch (c->facility) {
++ case 0x06: /* ECT execute */
++ pri->ev.facility.operation = 0x06;
++ break;
++ case 0x0D:
++ pri->ev.facility.operation = 0x0D;
++ strncpy(pri->ev.facility.forwardnum, c->redirectingnum, sizeof(pri->ev.facility.forwardnum) - 1);
++ break;
++ default:
++ pri->ev.facility.operation = c->facility;
++ }
++ } else {
++ pri->ev.e = PRI_EVENT_FACNAME;
++ strncpy(pri->ev.facname.callingname, c->callername, sizeof(pri->ev.facname.callingname) - 1);
++ strncpy(pri->ev.facname.callingnum, c->callernum, sizeof(pri->ev.facname.callingname) - 1);
++ pri->ev.facname.channel = c->channelno | (c->ds1no << 8);
++ pri->ev.facname.cref = c->cr;
++ pri->ev.facname.call = c;
++ }
+ return Q931_RES_HAVEEVENT;
+ case Q931_PROGRESS:
+ if (missingmand) {
+ q931_status(pri, c, PRI_CAUSE_MANDATORY_IE_MISSING);
+- q931_destroycall(pri, c->cr);
++ q931_destroycall(pri, c->cr, c->tei);
+ break;
+ }
+ pri->ev.e = PRI_EVENT_PROGRESS;
+@@ -3342,6 +4300,11 @@
+ q931_status(pri,c,PRI_CAUSE_WRONG_MESSAGE);
+ break;
+ }
++ if (pri->localtype == BRI_NETWORK_PTMP) {
++ l2c = q921_getcall(pri, c, tei);
++ l2c->proc = 1;
++ l2c->channel = c->channelno;
++ }
+ pri->ev.proceeding.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
+ if (mh->msg == Q931_CALL_PROCEEDING) {
+ pri->ev.e = PRI_EVENT_PROCEEDING;
+@@ -3368,7 +4331,7 @@
+ case Q931_STATUS:
+ if (missingmand) {
+ q931_status(pri, c, PRI_CAUSE_MANDATORY_IE_MISSING);
+- q931_destroycall(pri, c->cr);
++ q931_destroycall(pri, c->cr, c->tei);
+ break;
+ }
+ if (c->newcall) {
+@@ -3405,31 +4368,67 @@
+ if (res)
+ return res;
+ }
+- break;
++ if (c->ourcallstate != c->sugcallstate) {
++ pri_error(pri, "updating callstate, ourcallstate %d to %d\n", c->ourcallstate, c->sugcallstate);
++ c->ourcallstate = c->sugcallstate;
++ if (c->sugcallstate != Q931_CALL_STATE_ACTIVE) {
++ /* pass hangup to upper layer! */
++ 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;
+ case Q931_RELEASE_COMPLETE:
+- c->ourcallstate = 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.cref = c->cr;
+- pri->ev.hangup.cause = c->cause;
+- pri->ev.hangup.call = c;
+- libpri_copy_string(pri->ev.hangup.useruserinfo, c->useruserinfo, sizeof(pri->ev.ring.useruserinfo));
+- c->useruserinfo[0] = '\0';
+- /* Free resources */
+- 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;
+- pri_hangup(pri, c, c->cause);
+- } else
+- res = 0;
+- if (res)
+- return res;
+- else
+- q931_hangup(pri,c,c->cause);
++ if (c->cause != PRI_CAUSE_INCOMPATIBLE_DESTINATION) {
++ if (c->t303timer) {
++ c->t303running = 0;
++ pri_schedule_del(pri, c->t303timer);
++ }
++ c->t303timer = 0;
++ }
++ if ((pri->localtype != BRI_NETWORK_PTMP) || (c->tei == tei)) {
++ c->ourcallstate = 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.cref = c->cr;
++ pri->ev.hangup.cause = c->cause;
++ pri->ev.hangup.call = c;
++ libpri_copy_string(pri->ev.hangup.useruserinfo, c->useruserinfo, sizeof(pri->ev.ring.useruserinfo));
++ c->useruserinfo[0] = '\0';
++ /* Free resources */
++ 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;
++ pri_hangup(pri, c, c->cause);
++ } else
++ res = 0;
++ if (res)
++ return res;
++ else
++ q931_hangup(pri,c,c->cause);
++ } else {
++ // BRI_NET_PTMP
++ // ignoring relase_complete
++ res = q921_handle_hangup(pri,c,tei);
++ if (res)
++ return res;
++ }
+ break;
+ case Q931_RELEASE:
+ if (missingmand) {
+@@ -3445,6 +4444,7 @@
+ pri->ev.e = PRI_EVENT_HANGUP;
+ pri->ev.hangup.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
+ pri->ev.hangup.cref = c->cr;
++ pri->ev.hangup.tei = c->tei;
+ pri->ev.hangup.cause = c->cause;
+ pri->ev.hangup.call = c;
+ pri->ev.hangup.aoc_units = c->aoc_units;
+@@ -3473,8 +4473,14 @@
+ pri->ev.e = PRI_EVENT_HANGUP_REQ;
+ pri->ev.hangup.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
+ pri->ev.hangup.cref = c->cr;
++ pri->ev.hangup.tei = c->tei;
+ pri->ev.hangup.cause = c->cause;
+ pri->ev.hangup.call = c;
++ if (c->progressmask & PRI_PROG_INBAND_AVAILABLE) {
++ pri->ev.hangup.inband_progress = 1;
++ } else {
++ pri->ev.hangup.inband_progress = 0;
++ }
+ pri->ev.hangup.aoc_units = c->aoc_units;
+ if (c->alive)
+ return Q931_RES_HAVEEVENT;
+@@ -3500,14 +4506,14 @@
+ 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->digitbuf, sizeof(pri->ev.digit.digits));
++ strncpy(pri->ev.digit.digits, c->digitbuf, sizeof(pri->ev.digit.digits));
+ 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));
++ strncpy(pri->ev.ring.callednum, c->digits, sizeof(pri->ev.ring.callednum) - 1);
++ strncpy(pri->ev.ring.callingsubaddr, c->callingsubaddr, sizeof(pri->ev.ring.callingsubaddr) - 1);
+ pri->ev.ring.complete = c->complete; /* this covers IE 33 (Sending Complete) */
+ return Q931_RES_HAVEEVENT;
+ case Q931_STATUS_ENQUIRY:
+@@ -3525,7 +4531,7 @@
+ 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) {
+@@ -3541,19 +4547,53 @@
+ pri->ev.notify.channel = c->channelno;
+ pri->ev.notify.info = c->notify;
+ return Q931_RES_HAVEEVENT;
++ case Q931_HOLD:
++ pri->ev.e = PRI_EVENT_HOLD_REQ;
++ pri->ev.hold_req.call = c;
++ pri->ev.hold_req.cref = c->cr;
++ pri->ev.hold_req.tei = c->tei;
++ pri->ev.hold_req.channel = c->channelno;
++ return Q931_RES_HAVEEVENT;
++ break;
++ case Q931_RETRIEVE:
++ pri->ev.e = PRI_EVENT_RETRIEVE_REQ;
++ pri->ev.retrieve_req.call = c;
++ pri->ev.retrieve_req.cref = c->cr;
++ pri->ev.retrieve_req.tei = c->tei;
++ pri->ev.retrieve_req.channel = c->channelno;
++ return Q931_RES_HAVEEVENT;
++ break;
++ case Q931_SUSPEND:
++ pri->ev.e = PRI_EVENT_SUSPEND_REQ;
++ pri->ev.suspend_req.call = c;
++ pri->ev.suspend_req.cref = c->cr;
++ pri->ev.suspend_req.tei = c->tei;
++ pri->ev.suspend_req.channel = c->channelno;
++ strncpy(pri->ev.suspend_req.callid, c->callid, sizeof(pri->ev.suspend_req.callid) - 1);
++ return Q931_RES_HAVEEVENT;
++ break;
++ case Q931_RESUME:
++ if (pri->localtype == BRI_NETWORK_PTMP) {
++ l2c = q921_getcall(pri, c, tei);
++ }
++ c->newcall = 0;
++ pri->ev.e = PRI_EVENT_RESUME_REQ;
++ pri->ev.resume_req.call = c;
++ pri->ev.resume_req.cref = c->cr;
++ pri->ev.resume_req.tei = c->tei;
++ pri->ev.resume_req.channel = c->channelno;
++ strncpy(pri->ev.resume_req.callid, c->callid, sizeof(pri->ev.resume_req.callid) - 1);
++ return Q931_RES_HAVEEVENT;
++ 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 post-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg);
+@@ -3563,7 +4603,7 @@
+ 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);
++ q931_destroycall(pri,c->cr,c->tei);
+ return -1;
+ }
+ return 0;
+diff -urNad libpri-1.2.0-release/README /tmp/dpep.aQ7o1G/libpri-1.2.0-release/README
+--- libpri-1.2.0-release/README 2005-02-20 00:04:11.000000000 +0200
++++ /tmp/dpep.aQ7o1G/libpri-1.2.0-release/README 2005-11-23 04:05:24.987532175 +0200
+@@ -1,6 +1,7 @@
+-libpri: An implementation of Primate Rate ISDN
+-
++libpri: An implementation of Primate Rate ISDN (and BRI ISDN)
++
+ Written by Mark Spencer <markster at digium.com>
++Modified for BRI support by Klaus-Peter Junghanns <kpj at junghanns.net>
+
+ What is libpri?
+ ===============
+@@ -9,6 +10,7 @@
+ based on the Bellcore specification SR-NWT-002343 for National ISDN. As of
+ May 12, 2001, it has been tested work with NI-2, Nortel DMS-100, and
+ Lucent 5E Custom protocols on switches from Nortel and Lucent.
++The BRI and euroISDN modifications are based on ETS 300 102-1.
+
+ What is the license for libpri?
+ ===============================
+@@ -22,9 +24,8 @@
+ or the GPL of libpri.
+
+ If you wish to use libpri in an application for which the GPL is not
+-appropriate (e.g. a proprietary embedded system), licenses for libpri
+-under more flexible terms can be readily obtained through Digium, Inc.
+-at reasonable cost.
++appropriate (e.g. a proprietary embedded system), then you have to use
++a non-standard compliant version without BRI support.
+
+
+ How do I report bugs or contribute?
+diff -urNad libpri-1.2.0-release/TODO /tmp/dpep.aQ7o1G/libpri-1.2.0-release/TODO
+--- libpri-1.2.0-release/TODO 2001-05-12 19:53:13.000000000 +0300
++++ /tmp/dpep.aQ7o1G/libpri-1.2.0-release/TODO 2005-11-23 04:05:24.990531760 +0200
+@@ -2,9 +2,7 @@
+ -- D-Channel Backup
+ -- Test against 4e
+
+-Q.921:
+--- Support unnumbered information frames
+-
+ Q.931:
+--- Locking Shift IE
+--- Implement the 11 missing Q.931 timers
++-- Locking Shift IE (you did that already, didnt you??)
++-- Implement the 10 missing Q.931 timers
++-- more facilities
+\ ץבוקה ףוסב השדח-הרוש ות רסח
Property changes on: libpri/trunk/debian/patches/bristuff.dpatch
___________________________________________________________________
Name: svn:executable
+ *
More information about the Pkg-voip-commits
mailing list