[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