--- libpri-1.4.3.orig/debian/libpri-dev.install +++ libpri-1.4.3/debian/libpri-dev.install @@ -0,0 +1,5 @@ +usr/include/* +usr/lib/lib*.a +usr/lib/lib*.so +usr/lib/pkgconfig/* +/usr/lib/*.la --- libpri-1.4.3.orig/debian/watch +++ libpri-1.4.3/debian/watch @@ -0,0 +1,5 @@ +version=3 +opts=dversionmangle=s/\~dfsg//,downloadurlmangle=s/.*ref=// \ + http://downloads.digium.com/pub/telephony/libpri/releases/ \ + http://www\.digium\.com/elqNow/elqRedir\.htm\?ref=http://downloads\.digium\.com/pub/telephony/libpri/releases/libpri-([0-9.]*)\.tar\.gz \ + debian svn-upgrade --- libpri-1.4.3.orig/debian/libpri1.0.install +++ libpri-1.4.3/debian/libpri1.0.install @@ -0,0 +1 @@ +usr/lib/lib*.so.* --- libpri-1.4.3.orig/debian/compat +++ libpri-1.4.3/debian/compat @@ -0,0 +1 @@ +4 --- libpri-1.4.3.orig/debian/libpri1.0.dirs +++ libpri-1.4.3/debian/libpri1.0.dirs @@ -0,0 +1 @@ +usr/lib --- libpri-1.4.3.orig/debian/docs +++ libpri-1.4.3/debian/docs @@ -0,0 +1,2 @@ +README +TODO --- libpri-1.4.3.orig/debian/rules +++ libpri-1.4.3/debian/rules @@ -0,0 +1,134 @@ +#!/usr/bin/make -f +# -*- makefile -*- +# GNU copyright 1997 to 1999 by Joey Hess. + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +include /usr/share/dpatch/dpatch.make + + +CFLAGS = -Wall -g + +USE_BRISTUFF=1 + +ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) + CFLAGS += -O0 +else + CFLAGS += -O2 +endif +ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS))) + INSTALL_PROGRAM += -s +endif + +PKGNAME:=$(shell sed -nre 's/^Package: (.*[0-9])$$/\1/p' debian/control) +DEBVERSION:=$(shell head -n 1 debian/changelog \ + | sed -e 's/^[^(]*(\([^)]*\)).*/\1/') +UPVERSION:=$(shell echo $(DEBVERSION) | sed -e 's/^.*://' -e 's/-[0-9.]*$$//' -e 's/~dfsg$$//') +UPVERSIONMAJOR:=$(shell echo $(UPVERSION) | sed -re 's/(^[0-9]\.[0-9]).*/\1/') +SHLIBS = $(PKGNAME) (>= $(UPVERSIONMAJOR)) + +FILENAME := libpri_$(UPVERSION).orig.tar.gz +URL := http://ftp2.digium.com/pub/libpri/releases/libpri-$(UPVERSION).tar.gz + +# shared library versions, option 1 +#version=2.0.5 +#major=2 +# option 2, assuming the library is created as src/.libs/libfoo.so.2.0.5 or so +version=`ls lib*.so.* | \ + awk '{if (match($$0,/[0-9]+\.[0-9]+\.[0-9]+$$/)) print substr($$0,RSTART)}'` +major=`ls lib*.so.* | \ + awk '{if (match($$0,/\.so\.[0-9]+$$/)) print substr($$0,RSTART+4)}'` + +configure: configure-stamp +configure-stamp: patch-stamp bristuff-stamp + dh_testdir + # Add here commands to configure the package. + + touch configure-stamp + +BRISTUFF_DIR=bristuffed +bristuff-stamp: patch-stamp +ifeq ($(USE_BRISTUFF),1) + mkdir -p $(BRISTUFF_DIR) + tar cf - . --exclude=./debian/ --exclude=./$(BRISTUFF_DIR)/ \ + | tar xf - -C $(BRISTUFF_DIR) + cd $(BRISTUFF_DIR); patch <$(CURDIR)/debian/patches/bristuff.dpatch -p1 +endif + touch $@ + +build: build-stamp +build-stamp: configure-stamp + dh_testdir + + # Add here commands to compile the package. + CFLAGS="$(CFLAGS)" $(MAKE) +ifeq ($(USE_BRISTUFF),1) + cd $(BRISTUFF_DIR); CFLAGS="$(CFLAGS)" $(MAKE) LIB_SUF=bristuffed +endif + + touch build-stamp + +clean: clean-unpatched unpatch +clean-unpatched: + dh_testdir + dh_testroot + rm -f build-stamp configure-stamp + + # Add here commands to clean up after the build process. + #-$(MAKE) clean + [ ! -f Makefile ] || $(MAKE) clean + rm -rf $(BRISTUFF_DIR) + + dh_clean + +install: build + dh_testdir + dh_testroot + dh_clean -k + dh_installdirs + + # Add here commands to install the package into debian/tmp + $(MAKE) install INSTALL_PREFIX=$(CURDIR)/debian/tmp +ifeq ($(USE_BRISTUFF),1) + cd $(BRISTUFF_DIR); make install INSTALL_PREFIX=$(CURDIR)/debian/tmp \ + LIB_SUF=bristuffed +endif + + +# Build architecture-independent files here. +binary-indep: build install +# We have nothing to do by default. + +# Build architecture-dependent files here. +binary-arch: build install + dh_testdir + dh_testroot + dh_install --sourcedir=debian/tmp + dh_installchangelogs ChangeLog + dh_installdocs + dh_installexamples + dh_installman + dh_strip + dh_compress + dh_fixperms + dh_makeshlibs -V "$(SHLIBS)" + dh_installdeb + dh_shlibdeps + dh_gencontrol + dh_md5sums + dh_builddeb + +print-version: + @@echo "Debian version: $(DEBVERSION)" + @@echo "Upstream version: $(UPVERSION)" + @@echo "Upstream major version: $(UPVERSIONMAJOR)" + +get-orig-source: + @@dh_testdir + @@[ -d ../tarballs/. ]||mkdir -p ../tarballs + @@echo Downloading $(FILENAME) from $(URL) ... + @@wget -nv -T10 -t3 -O ../tarballs/$(FILENAME) $(URL) + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install configure unpatch patch --- libpri-1.4.3.orig/debian/patches/enable-gcc-optimizations.dpatch +++ libpri-1.4.3/debian/patches/enable-gcc-optimizations.dpatch @@ -0,0 +1,20 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## enable-gcc-optimizations.dpatch by Faidon Liambotis +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Don't discard CFLAGS of the environment +## DP: debian/rules passes at least the optimization level + +@DPATCH@ +diff -urNad libpri-1.4.1~/Makefile libpri-1.4.1/Makefile +--- libpri-1.4.1~/Makefile 2006-12-30 21:17:34.000000000 +0200 ++++ libpri-1.4.1/Makefile 2007-08-07 04:15:59.000000000 +0300 +@@ -36,7 +36,7 @@ + DYNAMIC_LIBRARY=libpri.so.1.0 + STATIC_OBJS=copy_string.o pri.o q921.o prisched.o q931.o pri_facility.o + DYNAMIC_OBJS=copy_string.lo pri.lo q921.lo prisched.lo q931.lo pri_facility.lo +-CFLAGS=-Wall -Werror -Wstrict-prototypes -Wmissing-prototypes -g -fPIC $(ALERTING) $(LIBPRI_COUNTERS) ++CFLAGS+=-Wall -Werror -Wstrict-prototypes -Wmissing-prototypes -g -fPIC $(ALERTING) $(LIBPRI_COUNTERS) + INSTALL_PREFIX=$(DESTDIR) + INSTALL_BASE=/usr + SOFLAGS = -Wl,-hlibpri.so.1.0 --- libpri-1.4.3.orig/debian/patches/00list +++ libpri-1.4.3/debian/patches/00list @@ -0,0 +1,2 @@ +enable-gcc-optimizations +libname --- libpri-1.4.3.orig/debian/patches/libname.dpatch +++ libpri-1.4.3/debian/patches/libname.dpatch @@ -0,0 +1,86 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## libname.dpatch by +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: allows using a different name for the library rather than libpri +## DP: if LIB_SUF is set in the environment/makefile params it will install +## DP: the headers under /usr/include/$(LIB_SUF)/libpri.h and call the library +## DP: libpri-$(LIB_SUF).so.1 + +@DPATCH@ +diff -urNad libpri-1.2.3~/Makefile libpri-1.2.3/Makefile +--- libpri-1.2.3~/Makefile 2006-04-30 15:17:47.000000000 +0000 ++++ libpri-1.2.3/Makefile 2006-06-10 13:48:23.000000000 +0000 +@@ -32,14 +32,20 @@ + OSARCH=$(shell uname -s) + PROC?=$(shell uname -m) + ++ifdef LIB_SUF ++LIBNAME=pri-$(LIB_SUF) ++else ++LIBNAME=pri ++endif +-STATIC_LIBRARY=libpri.a +-DYNAMIC_LIBRARY=libpri.so.1.0 ++STATIC_LIBRARY=lib$(LIBNAME).a ++DYNAMIC_LIBRARY=lib$(LIBNAME).so.1.0 + STATIC_OBJS=copy_string.o pri.o q921.o prisched.o q931.o pri_facility.o + DYNAMIC_OBJS=copy_string.lo pri.lo q921.lo prisched.lo q931.lo pri_facility.lo + CFLAGS+=-Wall -Werror -Wstrict-prototypes -Wmissing-prototypes -g -fPIC $(ALERTING) $(LIBPRI_COUNTERS) + INSTALL_PREFIX=$(DESTDIR) + INSTALL_BASE=/usr +-SOFLAGS = -Wl,-hlibpri.so.1.0 ++INCLUDE_DIR=$(INSTALL_PREFIX)$(INSTALL_BASE)/include/$(LIB_SUF) ++SOFLAGS = -Wl,-hlib$(LIBNAME).so.1.0 + LDCONFIG = /sbin/ldconfig + ifneq (,$(findstring X$(OSARCH)X, XLinuxX XGNU/kFreeBSDX)) + LDCONFIG_FLAGS=-n +@@ -55,7 +61,7 @@ + CFLAGS += -DSOLARIS -I../zaptel-solaris + LDCONFIG = + LDCONFIG_FLAGS = \# # Trick to comment out the period in the command below +-SOSLINK = ln -sf libpri.so.1.0 libpri.so.1 ++SOSLINK = ln -sf lib$(LIBNAME).so.1.0 lib$(LIBNAME).so.1 + #INSTALL_PREFIX = /opt/asterisk # Uncomment out to install in standard Solaris location for 3rd party code + endif + +@@ -82,29 +88,28 @@ + + install: $(STATIC_LIBRARY) $(DYNAMIC_LIBRARY) + mkdir -p $(INSTALL_PREFIX)$(INSTALL_BASE)/lib +- mkdir -p $(INSTALL_PREFIX)$(INSTALL_BASE)/include ++ mkdir -p $(INCLUDE_DIR) ++ install -m 644 libpri.h $(INCLUDE_DIR) + ifneq (${OSARCH},SunOS) +- install -m 644 libpri.h $(INSTALL_PREFIX)$(INSTALL_BASE)/include + install -m 755 $(DYNAMIC_LIBRARY) $(INSTALL_PREFIX)$(INSTALL_BASE)/lib + if [ -x /usr/sbin/sestatus ] && ( /usr/sbin/sestatus | grep "SELinux status:" | grep -q "enabled"); then /sbin/restorecon -v $(INSTALL_PREFIX)$(INSTALL_BASE)/lib/$(DYNAMIC_LIBRARY); fi +- ( cd $(INSTALL_PREFIX)$(INSTALL_BASE)/lib ; ln -sf libpri.so.1.0 libpri.so ; ln -sf libpri.so.1.0 libpri.so.1 ) ++ ( cd $(INSTALL_PREFIX)$(INSTALL_BASE)/lib ; ln -sf lib$(LIBNAME).so.1.0 lib$(LIBNAME).so ; ln -sf lib$(LIBNAME).so.1.0 lib$(LIBNAME).so.1 ) + install -m 644 $(STATIC_LIBRARY) $(INSTALL_PREFIX)$(INSTALL_BASE)/lib +- if test $$(id -u) = 0; then $(LDCONFIG) $(LDCONFIG_FLAGS) $(INSTALL_PREFIX)$(INSTALL_BASE)/lib; fi + else + install -f $(INSTALL_PREFIX)$(INSTALL_BASE)/include -m 644 libpri.h + install -f $(INSTALL_PREFIX)$(INSTALL_BASE)/lib -m 755 $(DYNAMIC_LIBRARY) +- ( cd $(INSTALL_PREFIX)$(INSTALL_BASE)/lib ; ln -sf libpri.so.1.0 libpri.so ; $(SOSLINK) ) ++ ( cd $(INSTALL_PREFIX)$(INSTALL_BASE)/lib ; ln -sf lib$(LIBNAME).so.1.0 lib$(LIBNAME).so ; $(SOSLINK) ) + install -f $(INSTALL_PREFIX)$(INSTALL_BASE)/lib -m 644 $(STATIC_LIBRARY) + endif + + uninstall: + @echo "Removing Libpri" +- rm -f $(INSTALL_PREFIX)$(INSTALL_BASE)/lib/libpri.so.1.0 +- rm -f $(INSTALL_PREFIX)$(INSTALL_BASE)/lib/libpri.so.1 +- rm -f $(INSTALL_PREFIX)$(INSTALL_BASE)/lib/libpri.so +- rm -f $(INSTALL_PREFIX)$(INSTALL_BASE)/lib/libpri.a +- rm -f $(INSTALL_PREFIX)$(INSTALL_BASE)/include/libpri.h +- ++ rm -f $(INSTALL_PREFIX)$(INSTALL_BASE)/lib/lib$(LIBNAME).so.1.0 ++ rm -f $(INSTALL_PREFIX)$(INSTALL_BASE)/lib/lib$(LIBNAME).so.1 ++ rm -f $(INSTALL_PREFIX)$(INSTALL_BASE)/lib/lib$(LIBNAME).so ++ rm -f $(INSTALL_PREFIX)$(INSTALL_BASE)/lib/lib$(LIBNAME).a ++ rm -f $(INCLUDE_DIR)/libpri.h ++ + pritest: pritest.o + $(CC) -o pritest pritest.o -L. -lpri -lzap $(CFLAGS) + --- libpri-1.4.3.orig/debian/patches/bristuff.dpatch +++ libpri-1.4.3/debian/patches/bristuff.dpatch @@ -0,0 +1,6087 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## bristuff.dpatch by Tzafrir Cohen +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: The libpri part of bristuff, version bristuff-0.4.0-RC1 +## DP: http://www.junghanns.net/en/download.html +## DP: +## DP: newer versions: replace the contets of the patch file literally. +## DP: Watch out for Makefile changes! + +@DPATCH@ +Index: libpri-1.4.3/libpri.h +=================================================================== +--- libpri-1.4.3.orig/libpri.h ++++ libpri-1.4.3/libpri.h +@@ -5,6 +5,8 @@ + * + * Copyright (C) 2001, Linux Support Services, Inc. + * All Rights Reserved. ++ * Copyright (C) 2003-2006 Junghanns.NET GmbH ++ * Klaus-Peter Junghanns + * + * 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 +@@ -26,8 +28,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 +82,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 +@@ -252,11 +264,17 @@ + #define PRI_NSF_ATT_MULTIQUEST 0xF0 + #define PRI_NSF_CALL_REDIRECTION_SERVICE 0xF7 + ++#ifdef RELAX_TRB ++#define PRI_RELAX_TRB ++#endif ++ ++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 { +@@ -275,18 +293,19 @@ typedef struct pri_event_ringing { + 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 { +@@ -304,32 +323,37 @@ typedef struct pri_event_ring { + 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 */ + char callednum[256]; /* Called number */ +- char redirectingnum[256]; /* Redirecting number */ +- char redirectingname[256]; /* Redirecting name */ +- int redirectingreason; /* Reason for redirect */ ++ char redirectingnum[256]; /* Redirecting number */ ++ char redirectingname[256]; /* Redirecting name */ ++ int redirectingreason; /* Reason for redirect */ + int callingplanrdnis; /* Dialing plan of Redirecting Number */ +- char useruserinfo[260]; /* User->User info */ ++ char useruserinfo[260]; /* User->User info */ + int flexible; /* Are we flexible with our channel selection? */ + int cref; /* Call Reference Number */ + int ctype; /* Call type (see PRI_TRANS_CAP_* */ +- int layer1; /* User layer 1 */ ++ int layer1; /* User layer 1 */ + int complete; /* Have we seen "Complete" i.e. no more number? */ + q931_call *call; /* Opaque call pointer */ +- char callingsubaddr[256]; /* Calling parties subaddress */ ++ int tei; /* belongs to this tei */ ++ char callingsubaddr[256]; /* Calling parties subaddress */ + int progress; + int progressmask; + char origcalledname[256]; + char origcallednum[256]; + int callingplanorigcalled; /* Dialing plan of Originally Called Number */ + int origredirectingreason; ++ char lowlayercompat[16]; ++ char highlayercompat[4]; + } pri_event_ring; + + typedef struct pri_event_hangup { +@@ -337,6 +361,8 @@ typedef struct pri_event_hangup { + 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 */ +@@ -377,12 +403,67 @@ typedef struct pri_event_keypad_digit { + 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 */ +@@ -391,6 +472,11 @@ typedef union { + 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; + +@@ -405,7 +491,9 @@ typedef int (*pri_io_cb)(struct pri *pri + 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); +@@ -429,6 +517,9 @@ extern int pri_get_debug(struct pri *pri + /* 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 */ +@@ -469,6 +560,12 @@ extern int pri_information(struct pri *p + /* Send a keypad facility string of digits */ + extern int pri_keypad_facility(struct pri *pri, q931_call *call, char *digits); + ++/* 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); +@@ -477,6 +574,35 @@ extern int pri_need_more_info(struct pri + 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 */ + + +@@ -485,14 +611,14 @@ extern int pri_answer(struct pri *pri, q + + /* backwards compatibility for those who don't use asterisk with libpri */ + #define pri_release(a,b,c) \ +- pri_hangup(a,b,c) ++ pri_hangup(a,b,c, -1) + + #define pri_disconnect(a,b,c) \ +- pri_hangup(a,b,c) ++ pri_hangup(a,b,c, -1) + + /* Hangup a call */ + #define PRI_HANGUP +-extern int pri_hangup(struct pri *pri, q931_call *call, int cause); ++extern int pri_hangup(struct pri *pri, q931_call *call, int cause, int aocunits); + + #define PRI_DESTROYCALL + extern void pri_destroycall(struct pri *pri, q931_call *call); +@@ -525,7 +651,7 @@ extern struct pri_sr *pri_sr_new(void); + extern void pri_sr_free(struct pri_sr *sr); + + extern int pri_sr_set_channel(struct pri_sr *sr, int channel, int exclusive, int nonisdn); +-extern int pri_sr_set_bearer(struct pri_sr *sr, int transmode, int userl1); ++extern int pri_sr_set_bearer(struct pri_sr *sr, int transmode, int userl1, char *llc); + extern int pri_sr_set_called(struct pri_sr *sr, char *called, int calledplan, int complete); + extern int pri_sr_set_caller(struct pri_sr *sr, char *caller, char *callername, int callerplan, int callerpres); + extern int pri_sr_set_redirecting(struct pri_sr *sr, char *num, int plan, int pres, int reason); +@@ -553,8 +679,8 @@ int pri_channel_bridge(q931_call *call1, + + /* 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 +Index: libpri-1.4.3/Makefile +=================================================================== +--- libpri-1.4.3.orig/Makefile ++++ libpri-1.4.3/Makefile +@@ -27,6 +27,16 @@ + # Uncomment if you want libpri to count number of Q921/Q931 sent/received + #LIBPRI_COUNTERS=-DLIBPRI_COUNTERS + ++# Uncomment if you want libpri to always keep layer 2 up ++#LAYER2ALWAYSUP=-DLAYER2ALWAYSUP ++ ++# Uncomment if you want libpri to hangup a call to an NT (p2mp) port if one ++# device sends a RELEASE COMPLETE with cause 17 ++#FASTBUSYONBUSY=-DFASTBUSYONBUSY ++ ++# workaround for slowly responding COs ++#RELAXEDTIMERS=-DRELAXED_TIMERS ++ + CC=gcc + + OSARCH=$(shell uname -s) +@@ -36,7 +46,7 @@ STATIC_LIBRARY=libpri.a + DYNAMIC_LIBRARY=libpri.so.1.0 + STATIC_OBJS=copy_string.o pri.o q921.o prisched.o q931.o pri_facility.o + DYNAMIC_OBJS=copy_string.lo pri.lo q921.lo prisched.lo q931.lo pri_facility.lo +-CFLAGS+=-Wall -Werror -Wstrict-prototypes -Wmissing-prototypes -g -fPIC $(ALERTING) $(LIBPRI_COUNTERS) ++CFLAGS+=-Wall -Werror -Wstrict-prototypes -Wmissing-prototypes -g -fPIC $(ALERTING) $(LIBPRI_COUNTERS) $(LAYER2ALWAYSUP) $(FASTBUSYONBUSY) -DRELAX_TRB $(RELAXEDTIMERS) + INSTALL_PREFIX=$(DESTDIR) + INSTALL_BASE=/usr + SOFLAGS = -Wl,-hlibpri.so.1.0 +Index: libpri-1.4.3/pri.c +=================================================================== +--- libpri-1.4.3.orig/pri.c ++++ libpri-1.4.3/pri.c +@@ -1,24 +1,14 @@ + /* + * libpri: An implementation of Primary Rate ISDN + * +- * Written by Mark Spencer ++ * Written by Mark Spencer + * +- * Copyright (C) 2001-2005, Digium +- * All Rights Reserved. ++ * This program is confidential ( <- I dont think so! ) + * +- * 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 +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * Copyright (C) 2001, Linux Support Services, Inc. ++ * All Rights Reserved. ++ * Copyright (C) 2003-2006 Junghanns.NET GmbH ++ * Klaus-Peter Junghanns + * + */ + +@@ -48,6 +38,14 @@ char *pri_node2str(int node) + 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 +185,7 @@ static int __pri_write(struct pri *pri, + 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 +205,8 @@ static struct pri *__pri_new(int fd, int + 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 +217,7 @@ static struct pri *__pri_new(int fd, int + 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 +226,7 @@ static struct pri *__pri_new(int fd, int + 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 +242,7 @@ static struct pri *__pri_new(int fd, int + } + /* 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 +262,16 @@ int pri_restart(struct pri *pri) + { + /* 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 +280,7 @@ struct pri *pri_new_cb(int fd, int nodet + 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 +444,15 @@ void pri_facility_enable(struct pri *pri + 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) +@@ -486,6 +496,21 @@ int pri_notify(struct pri *pri, q931_cal + 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) +@@ -507,6 +532,83 @@ int pri_answer(struct pri *pri, q931_cal + 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) ++{ ++ if ((pri->localtype == PRI_CPE) || (pri->localtype == BRI_CPE)) { ++ add_call_rerouting_facility_ie(pri, call, destination); ++ return q931_facility(pri, call); ++ } else if (pri->localtype == BRI_CPE_PTMP) { ++ add_call_deflection_facility_ie(pri, call, destination); ++ return q931_facility(pri, call); ++ } else { ++ return -1; ++ } ++} ++ + #if 0 + /* deprecated routines, use pri_hangup */ + int pri_release(struct pri *pri, q931_call *call, int cause) +@@ -561,14 +663,35 @@ int pri_channel_bridge(q931_call *call1, + } + } + +-int pri_hangup(struct pri *pri, q931_call *call, int cause) ++int pri_hangup(struct pri *pri, q931_call *call, int cause, int aocunits) + { ++ int res=0; + if (!pri || !call) + return -1; + if (cause == -1) + /* normal clear cause */ + cause = 16; +- return q931_hangup(pri, call, cause); ++ if ((cause == 34 || cause == 44 || cause == 82 || cause == 1 || cause == 81 || cause == 17) && (call->ourcallstate == Q931_CALL_STATE_ACTIVE)) { ++ pri_error(pri, "Cause code %d not allowed when disconnecting an active call. Changing to cause 16.\n", cause); ++ cause = 16; ++ } ++ ++ if (aocunits > -1) { ++ call->aoc_units = aocunits; ++ } ++ ++ 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) +@@ -708,15 +831,15 @@ int pri_call(struct pri *pri, q931_call + 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; + } +@@ -728,10 +851,14 @@ void pri_message(struct pri *pri, char * + 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, ...) +@@ -741,10 +868,14 @@ void pri_error(struct pri *pri, char *fm + 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 */ +@@ -785,11 +916,13 @@ char *pri_dump_info_str(struct pri *pri) + } + 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]); +@@ -799,6 +932,7 @@ char *pri_dump_info_str(struct pri *pri) + 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); + } + +@@ -840,10 +974,11 @@ int pri_sr_set_channel(struct pri_sr *sr + return 0; + } + +-int pri_sr_set_bearer(struct pri_sr *sr, int transmode, int userl1) ++int pri_sr_set_bearer(struct pri_sr *sr, int transmode, int userl1, char *llc) + { + sr->transmode = transmode; + sr->userl1 = userl1; ++ sr->llc = llc; + return 0; + } + +@@ -872,3 +1007,14 @@ int pri_sr_set_redirecting(struct pri_sr + sr->redirectingreason = reason; + return 0; + } ++ ++void pri_shutdown(struct pri *pri) ++{ ++#ifndef LAYER2ALWAYSUP ++#ifndef RELAX_TRB ++ if ((pri->localtype == BRI_NETWORK) || (pri->localtype == BRI_CPE) || (pri->localtype == BRI_CPE_PTMP)) { ++ q921_reset(pri, pri->tei, 1); ++ } ++#endif ++#endif ++} +Index: libpri-1.4.3/pridump.c +=================================================================== +--- libpri-1.4.3.orig/pridump.c ++++ libpri-1.4.3/pridump.c +@@ -1,9 +1,9 @@ + /* + * libpri: An implementation of Primary Rate ISDN + * +- * Written by Mark Spencer ++ * Written by Mark Spencer + * +- * Copyright (C) 2001-2005, Digium ++ * Copyright (C) 2001, Linux Support Services, Inc. + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify +Index: libpri-1.4.3/pri_facility.c +=================================================================== +--- libpri-1.4.3.orig/pri_facility.c ++++ libpri-1.4.3/pri_facility.c +@@ -1,26 +1,17 @@ + /* +- * libpri: An implementation of Primary Rate ISDN +- * +- * Written by Matthew Fredrickson +- * +- * Copyright (C) 2004-2005, Digium +- * All Rights Reserved. +- * +- * 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 +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +- * +- */ ++ This file and it's contents are licensed under the terms and conditions ++ of the GNU Public License. See http://www.gnu.org for details. ++ ++ Routines for dealing with facility messages and their respective ++ components (ROSE) ++ ++ by Matthew Fredrickson ++ Copyright (C) 2004-2005 Digium, Inc ++ ++ Copyright (C) 2005-2006 Junghanns.NET GmbH ++ Klaus-Peter Junghanns ++ ++*/ + + #include "compat.h" + #include "libpri.h" +@@ -350,9 +341,9 @@ int asn1_name_decode(void * data, int le + 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) +@@ -447,12 +438,55 @@ static int rose_public_party_number_deco + return -1; + value->ton = ton; + +- return res + 3; ++ return res + 2; + + } while(0); + return -1; + } + ++static int rose_cd_destination_decode(struct pri *pri, q931_call *call, unsigned char *data, int len) ++{ ++ unsigned char *vdata = data; ++ struct rose_component *comp1 = NULL, *comp2 = NULL; ++ int pos1 = 0, pos2, sublen2; ++ ++ if (pri->debug & PRI_DEBUG_AOC) ++ dump_apdu (pri, data, len); ++ ++ do { ++ GET_COMPONENT(comp1, pos1, vdata, len); ++ CHECK_COMPONENT(comp1, ASN1_SEQUENCE, "!! Invalid CD destination argument. Expected Sequence (0x30) but Received 0x%02X\n"); ++ SUB_COMPONENT(comp1, pos1); ++ GET_COMPONENT(comp1, pos1, vdata, len); ++ switch (comp1->type) { ++ case (ASN1_SEQUENCE | ASN1_CONSTRUCTOR): ++ sublen2 = comp1->len; ++ pos2 = pos1; ++ comp2 = comp1; ++ SUB_COMPONENT(comp2, pos2); ++ do { ++ GET_COMPONENT(comp2, pos2, vdata, len); ++ switch (comp2->type) { ++ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0): ++ memcpy(call->redirectingnum, comp2->data, comp2->len); ++ call->redirectingnum[comp2->len] = '\0'; ++ return 0; ++ break; ++ default: ++ pri_message(pri, "!! Don't know how to handle 0x%02X in CD destination argument\n", comp2->type); ++ } ++ NEXT_COMPONENT(comp2, pos2); ++ } while (pos2 < sublen2); ++ break; ++ default: ++ pri_message(pri, "!! Invalid CD destination argument. Expected Sequence (0x30) or Object Identifier (0x81/0x01) but received 0x%02X\n", comp1->type); ++ } ++ NEXT_COMPONENT(comp1, pos1); ++ } while (pos1 < len); ++ ++ return 0; ++} ++ + static int rose_address_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value) + { + int i = 0; +@@ -517,11 +551,10 @@ static int rose_address_decode(struct pr + 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); + +@@ -531,7 +564,6 @@ static int rose_address_decode(struct pr + 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; + +@@ -546,9 +578,7 @@ static int rose_presented_number_unscree + 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"); +@@ -565,9 +595,7 @@ static int rose_presented_number_unscree + 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); + } +@@ -578,7 +606,7 @@ static int rose_presented_number_unscree + 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; +@@ -587,21 +615,9 @@ static int rose_diverting_leg_informatio + 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); +@@ -619,20 +635,18 @@ static int rose_diverting_leg_informatio + + 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; +@@ -641,43 +655,33 @@ static int rose_diverting_leg_informatio + 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; +@@ -690,15 +694,19 @@ static int rose_diverting_leg_informatio + call->origcalledpres = originalcallednr.pres; + libpri_copy_string(call->origcallednum, originalcallednr.partyaddress, sizeof(call->origcallednum)); + } +- libpri_copy_string(call->redirectingname, redirectingname, sizeof(call->redirectingname)); +- libpri_copy_string(call->origcalledname, origcalledname, sizeof(call->origcalledname)); ++ if (strlen(redirectingname) > 0) { ++ libpri_copy_string(call->redirectingname, redirectingname, sizeof(call->redirectingname)); ++ } ++ if (strlen(origcalledname) > 0) { ++ libpri_copy_string(call->origcalledname, origcalledname, sizeof(call->origcalledname)); ++ } + return 0; + } + while (0); + + return -1; + } +- ++ + static int rose_diverting_leg_information2_encode(struct pri *pri, q931_call *call) + { + int i = 0, j, compsp = 0; +@@ -916,6 +924,131 @@ static int add_dms100_transfer_ability_a + 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; ++} ++ ++/* Call rerouting */ ++int add_call_rerouting_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]; ++ unsigned char bcie[5] = { 0x04, 0x03, 0x90, 0x90, 0xA3 }; ++ ++ 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_CALLREROUTING); ++ ++ /* Argument sequence */ ++ ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ /* DIVERSION REASON (CFU) */ ++ ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 1); ++ ++ /* arg.Address */ ++ ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ j = asn1_string_encode(0x80, &buffer[i], sizeof(buffer)-i, 20, destination, strlen(destination)); ++ if(j<0) return -1; ++ i += j; ++ ++ /* close Address */ ++ ASN1_FIXUP(compstk, compsp, buffer, i); ++ ++ /* add rerouting counter tag */ ++ ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, 1); ++ ++ ++ /* IE tag */ ++ j = asn1_string_encode(ASN1_APPLICATION, &buffer[i], sizeof(buffer)-i, 5, bcie, 5); ++ if(j<0) return -1; ++ i += j; ++ ++ /* last rerouting number */ ++ ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), buffer, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ /* presented number unscreened */ ++ ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0), buffer, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ j = asn1_string_encode(0x80, &buffer[i], sizeof(buffer)-i, 20, c->callednum, strlen(c->callednum)); ++ if(j<0) return -1; ++ i += j; ++ ++ /* close Address */ ++ ASN1_FIXUP(compstk, compsp, buffer, i); ++ ++ /* 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) + { +@@ -1150,7 +1283,7 @@ static int aoc_aoce_charging_request_dec + CHECK_COMPONENT(comp, ASN1_ENUMERATED, "!! Invalid AOC Charging Request argument. Expected Enumerated (0x0A) but Received 0x%02X\n"); + ASN1_GET_INTEGER(comp, chargingcase); + if (chargingcase >= 0 && chargingcase <= 2) { +- if (pri->debug & PRI_DEBUG_APDU) ++// if (pri->debug & PRI_DEBUG_APDU) + pri_message(pri, "Channel %d/%d, Call %d - received AOC charging request - charging case: %i\n", + call->ds1no, call->channelno, call->cr, chargingcase); + } else { +@@ -1268,7 +1401,7 @@ static int aoc_aoce_charging_unit_decode + return 0; + } + +-static int aoc_aoce_charging_unit_encode(struct pri *pri, q931_call *c, long chargedunits) ++int aoc_aoce_charging_unit_encode(struct pri *pri, q931_call *c, long chargedunits, int msgtype) + { + /* sample data: [ 91 a1 12 02 02 3a 78 02 01 24 30 09 30 07 a1 05 30 03 02 01 01 ] */ + int i = 0, res = 0, compsp = 0; +@@ -1322,20 +1455,21 @@ static int aoc_aoce_charging_unit_encode + dump_apdu (pri, buffer, i); + + /* code below is untested */ +- res = pri_call_apdu_queue(c, Q931_FACILITY, buffer, i, NULL, NULL); ++ res = pri_call_apdu_queue(c, msgtype, buffer, i, NULL, NULL); + if (res) { + pri_message(pri, "Could not queue APDU in facility message\n"); + return -1; + } + +- /* Remember that if we queue a facility IE for a facility message we +- * have to explicitly send the facility message ourselves */ +- res = q931_facility(c->pri, c); +- if (res) { ++ if (msgtype == Q931_FACILITY) { ++ /* Remember that if we queue a facility IE for a facility message we ++ * have to explicitly send the facility message ourselves */ ++ res = q931_facility(c->pri, c); ++ if (res) { + pri_message(pri, "Could not schedule facility message for call %d\n", c->cr); + return -1; ++ } + } +- + return 0; + } + /* End AOC */ +@@ -1560,13 +1694,15 @@ int rose_invoke_decode(struct pri *pri, + 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); +@@ -1590,7 +1726,11 @@ int rose_invoke_decode(struct pri *pri, + 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); +@@ -1618,6 +1758,7 @@ int rose_invoke_decode(struct pri *pri, + } + return -1; + case ROSE_AOC_AOCD_CHARGING_UNIT: ++// return aoc_aoce_charging_unit_decode(pri, call, (u_int8_t *)comp, comp->len + 2); + if (pri->debug & PRI_DEBUG_APDU) { + pri_message(pri, "ROSE %i: AOC-D Charging Unit - not handled!", operation_tag); + dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); +@@ -1632,7 +1773,7 @@ int rose_invoke_decode(struct pri *pri, + case ROSE_AOC_AOCE_CHARGING_UNIT: + return aoc_aoce_charging_unit_decode(pri, call, (u_int8_t *)comp, comp->len + 2); + if (0) { /* the following function is currently not used - just to make the compiler happy */ +- aoc_aoce_charging_unit_encode(pri, call, call->aoc_units); /* use this function to forward the aoc-e on a bridged channel */ ++ aoc_aoce_charging_unit_encode(pri, call, call->aoc_units, 1); /* use this function to forward the aoc-e on a bridged channel */ + return 0; + } + case ROSE_AOC_IDENTIFICATION_OF_CHARGE: +@@ -1641,6 +1782,22 @@ int rose_invoke_decode(struct pri *pri, + dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); + } + return -1; ++ case ROSE_CALLDEFLECTION: ++ call->facility = operation_tag; ++ return rose_cd_destination_decode(pri, call, (u_int8_t *)comp, comp->len + 2); ++ 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; ++ case ROSE_MALICIOUS_CID: ++// call->facility = operation_tag; ++// if (pri->debug & PRI_DEBUG_APDU) { ++ pri_message(pri, "ROSE %i: received MALICIOUS CID!", operation_tag); ++ // } ++ return 0; + default: + if (pri->debug & PRI_DEBUG_APDU) { + pri_message(pri, "!! Unable to handle ROSE operation %d", operation_tag); +Index: libpri-1.4.3/pri_facility.h +=================================================================== +--- libpri-1.4.3.orig/pri_facility.h ++++ libpri-1.4.3/pri_facility.h +@@ -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,16 @@ + #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_CALLREROUTING 0x0E ++#define ROSE_EXPLICIT_CALL_TRANSFER 0x06 ++#define ROSE_MALICIOUS_CID 0x31 ++ + /* ROSE definitions and data structures */ + #define INVOKE_IDENTIFIER 0x02 + #define INVOKE_LINKED_IDENTIFIER 0x80 +@@ -186,12 +191,6 @@ struct rose_component { + (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)]); \ +@@ -279,4 +278,10 @@ int pri_call_add_standard_apdus(struct p + + int asn1_dump(struct pri *pri, void *comp, int len); + ++extern int add_call_deflection_facility_ie(struct pri *pri, q931_call *c, char *destination); ++ ++extern int add_call_rerouting_facility_ie(struct pri *pri, q931_call *c, char *destination); ++ ++extern int aoc_aoce_charging_unit_encode(struct pri *pri, q931_call *c, long chargedunits, int send_facility_message); ++ + #endif /* _PRI_FACILITY_H */ +Index: libpri-1.4.3/pri_internal.h +=================================================================== +--- libpri-1.4.3.orig/pri_internal.h ++++ libpri-1.4.3/pri_internal.h +@@ -5,6 +5,8 @@ + * + * Copyright (C) 2001, Linux Support Services, Inc. + * All Rights Reserved. ++ * Copyright (C) 2003-2006 Junghanns.NET GmbH ++ * Klaus-Peter Junghanns + * + * 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 +@@ -34,7 +36,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; +@@ -42,8 +47,15 @@ enum q931_state; + 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 { +@@ -55,6 +67,7 @@ struct pri { + 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) */ +@@ -66,25 +79,42 @@ struct pri { + 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]; ++ ++ char q921_tei_check[Q921_MAX_TEIS]; ++ unsigned short q921_tei_check_ri[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]; + +@@ -93,8 +123,8 @@ struct pri { + 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; +@@ -113,6 +143,9 @@ struct pri { + + unsigned char last_invoke; /* Last ROSE invoke ID */ + unsigned char sendfacility; ++ ++ int span; /* our fellow pri lives on this zaptel span */ ++ + }; + + struct pri_sr { +@@ -122,6 +155,7 @@ struct pri_sr { + int nonisdn; + char *caller; + int callerplan; ++ int callerplanani; + char *callername; + int callerpres; + char *called; +@@ -134,6 +168,7 @@ struct pri_sr { + int redirectingreason; + int justsignalling; + const char *useruserinfo; ++ char *llc; + int transferable; + }; + +@@ -172,8 +207,13 @@ struct q931_call { + + int alive; /* Whether or not the call is alive */ + int acked; /* Whether setup has been acked or not */ ++ int con_acked; /* Whether CONNECT has been CONNECT_ACKNOWLEDGEd 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) */ + +@@ -210,6 +250,8 @@ struct q931_call { + char callerani[256]; /* Caller */ + char callernum[256]; + char callername[256]; ++ int callerplanuser; ++ int callerpresuser; + + char keypad_digits[64]; /* Buffer for digits that come in KEYPAD_FACILITY */ + +@@ -230,6 +272,9 @@ struct q931_call { + 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; +@@ -240,17 +285,28 @@ struct q931_call { + 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 */ + + struct apdu_event *apdus; /* APDU queue for call */ + ++ char llc[16]; /* low layer compatibility */ + int transferable; + unsigned int rlt_call_id; /* RLT call id */ + }; + + 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); + + extern void pri_schedule_del(struct pri *pri, int ev); +Index: libpri-1.4.3/pri_q921.h +=================================================================== +--- libpri-1.4.3.orig/pri_q921.h ++++ libpri-1.4.3/pri_q921.h +@@ -5,6 +5,8 @@ + * + * Copyright (C) 2001, Linux Support Services, Inc. + * All Rights Reserved. ++ * Copyright (C) 2003-2006 Junghanns.NET GmbH ++ * Klaus-Peter Junghanns + * + * 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 +@@ -47,6 +49,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 +173,14 @@ typedef enum q921_state { + 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 +Index: libpri-1.4.3/pri_q931.h +=================================================================== +--- libpri-1.4.3.orig/pri_q931.h ++++ libpri-1.4.3/pri_q931.h +@@ -5,6 +5,8 @@ + * + * Copyright (C) 2001, Linux Support Services, Inc. + * All Rights Reserved. ++ * Copyright (C) 2003-2006 Junghanns.NET GmbH ++ * Klaus-Peter Junghanns + * + * 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 +@@ -190,6 +192,10 @@ typedef struct q931_ie { + #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 +224,8 @@ typedef struct q931_ie { + #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 +@@ -247,7 +255,7 @@ typedef struct q931_ie { + /* Q.SIG specific */ + #define QSIG_IE_TRANSIT_COUNT 0x31 + +-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); + +@@ -263,6 +271,10 @@ extern int q931_information(struct pri * + + extern int q931_keypad_facility(struct pri *pri, q931_call *call, char *digits); + ++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); +@@ -271,6 +283,10 @@ extern int q931_disconnect(struct pri *p + + 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); +@@ -286,6 +302,22 @@ extern void q931_dump(struct pri *pri, q + + 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 void q931_dl_indication(struct pri *pri, int event); + + #endif +Index: libpri-1.4.3/prisched.c +=================================================================== +--- libpri-1.4.3.orig/prisched.c ++++ libpri-1.4.3/prisched.c +@@ -1,10 +1,12 @@ + /* + * libpri: An implementation of Primary Rate ISDN + * +- * Written by Mark Spencer ++ * Written by Mark Spencer + * +- * Copyright (C) 2001-2005, Digium ++ * Copyright (C) 2001, Linux Support Services, Inc. + * All Rights Reserved. ++ * Copyright (C) 2003-2006 Junghanns.NET GmbH ++ * Klaus-Peter Junghanns + * + * 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 +@@ -22,10 +24,9 @@ + * + */ + +-#include +- + #include "libpri.h" + #include "pri_internal.h" ++#include + + + static int maxsched = 0; +@@ -36,7 +37,7 @@ int pri_schedule_event(struct pri *pri, + int x; + struct timeval tv; + for (x=1;xpri_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 +54,39 @@ int pri_schedule_event(struct pri *pri, + } + 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;xpri_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 +98,7 @@ struct timeval *pri_schedule_next(struct + if (pri->subchannel) + closest = pri_schedule_next(pri->subchannel); + for (x=1;xpri_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)))) +@@ -76,26 +109,38 @@ struct timeval *pri_schedule_next(struct + + static pri_event *__pri_schedule_run(struct pri *pri, struct timeval *tv) + { +- int x; +- void (*callback)(void *); +- void *data; ++ 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;xpri_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 +161,6 @@ void pri_schedule_del(struct pri *pri,in + 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; + } ++ +Index: libpri-1.4.3/pritest.c +=================================================================== +--- libpri-1.4.3.orig/pritest.c ++++ libpri-1.4.3/pritest.c +@@ -1,9 +1,9 @@ + /* + * libpri: An implementation of Primary Rate ISDN + * +- * Written by Mark Spencer ++ * Written by Mark Spencer + * +- * Copyright (C) 2001-2005, Digium ++ * Copyright (C) 2001, Linux Support Services, Inc. + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify +@@ -47,8 +47,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; +@@ -56,7 +56,7 @@ static int offset = 0; + 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 { +@@ -72,6 +72,14 @@ static int str2node(char *node) + 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; + } + +@@ -281,6 +289,10 @@ static void handle_pri_event(struct pri + } + + 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); + } +Index: libpri-1.4.3/pri_timers.h +=================================================================== +--- libpri-1.4.3.orig/pri_timers.h ++++ libpri-1.4.3/pri_timers.h +@@ -25,19 +25,51 @@ + #ifndef _PRI_TIMERS_H + #define _PRI_TIMERS_H + ++#ifdef RELAXED_TIMERS + /* -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 */ \ ++ 6000, /* T303 */ \ ++ -1, /* T304 */ \ ++ 30000, /* T305 */ \ ++ -1, /* T306 */ \ ++ -1, /* T307 */ \ ++ 6000, /* T308 */ \ ++ -1, /* T309 */ \ ++ -1, /* T310 */ \ ++ 4000, /* T313 */ \ ++ -1, /* T314 */ \ ++ -1, /* T316 */ \ ++ -1, /* T317 */ \ ++ -1, /* T318 */ \ ++ -1, /* T319 */ \ ++ -1, /* T320 */ \ ++ -1, /* T321 */ \ ++ -1 /* T322 */ \ ++ } ++#else ++/* -1 means we dont currently support the timer/counter */ ++#define PRI_TIMERS_DEFAULT { 3, /* N200 */ \ ++ 260, /* N201 */ \ ++ 3, /* N202 */ \ ++ 7, /* K */ \ ++ 1000, /* T200 */ \ ++ 2000, /* T201 */ \ ++ 5000, /* T202 */ \ ++ 10000, /* T203 */ \ ++ -1, /* T300 */ \ ++ -1, /* T301 */ \ ++ -1, /* T302 */ \ ++ 4000, /* T303 */ \ + -1, /* T304 */ \ + 30000, /* T305 */ \ + -1, /* T306 */ \ +@@ -55,6 +87,7 @@ + -1, /* T321 */ \ + -1 /* T322 */ \ + } ++#endif + + /* XXX Only our default timers are setup now XXX */ + #define PRI_TIMERS_UNKNOWN PRI_TIMERS_DEFAULT +Index: libpri-1.4.3/q921.c +=================================================================== +--- libpri-1.4.3.orig/q921.c ++++ libpri-1.4.3/q921.c +@@ -1,10 +1,12 @@ + /* + * libpri: An implementation of Primary Rate ISDN + * +- * Written by Mark Spencer ++ * Written by Mark Spencer + * +- * Copyright (C) 2001-2005, Digium ++ * Copyright (C) 2001, Linux Support Services, Inc. + * All Rights Reserved. ++ * Copyright (C) 2003-2006 Junghanns.NET GmbH ++ * Klaus-Peter Junghanns + * + * 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,24 @@ + (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_send_teiverify(struct pri *pri,int tei); + +-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); ++ 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 +95,15 @@ static int q921_transmit(struct pri *pri + 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 +111,7 @@ static void q921_send_ua(struct pri *pri + 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 +119,19 @@ static void q921_send_ua(struct pri *pri + 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 +141,364 @@ static void q921_send_ua(struct pri *pri + 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_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; ++ q921_send_teiverify(pri, 127); ++#ifdef RELAX_TRB ++ pri->t202_timer[0] = pri_schedule_event(pri, pri->timers[PRI_TIMER_T202] + 3000, q921_send_teireq, pri); ++#endif ++ 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_teichkreq(struct pri *pri,int tei) { ++ q921_u *f; ++ unsigned short ri=0x6464; ++ ri = rand(); ++ ++ if (pri->localtype != BRI_NETWORK_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 = 1; // 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_CHK_REQ; ++ f->data[4] = (tei << 1) | 0x1; ++ if (pri->debug & PRI_DEBUG_Q921_STATE) ++ pri_message(pri, "Sending TEI check request 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) && (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(void *vpri, int now) ++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; ++#ifdef RELAX_TRB ++ pri->sabme_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T200] + 3000, q921_send_sabme_now, pri, tei); ++#endif ++ 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,27 +510,44 @@ static void q921_send_sabme(void *vpri, + 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_DEBUG_Q921_DUMP)) + pri_message(pri, "Sending Set Asynchronous Balanced Mode Extended\n"); + q921_transmit(pri, &h, 3); +- if (pri->debug & PRI_DEBUG_Q921_STATE && pri->q921_state != Q921_AWAITING_ESTABLISH) ++ if (pri->debug & PRI_DEBUG_Q921_STATE && pri->q921_state[teio] != Q921_AWAITING_ESTABLISH) + pri_message(pri, DBGHEAD "q921_state now is Q921_AWAITING_ESTABLISH\n", DBGINFO); +- 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 */ +@@ -167,26 +555,26 @@ static int q921_ack_packet(struct pri *p + if (prev) + prev->next = f->next; + else +- pri->txqueue = f->next; ++ pri->txqueue[teio] = f->next; + if (pri->debug & PRI_DEBUG_Q921_DUMP) +- 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_DUMP) + 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; + } +@@ -200,77 +588,130 @@ static int q921_ack_packet(struct pri *p + 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, int tei) ++{ ++ 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 reschedule_t203(struct pri *pri) ++static void q921_flush_txqueue(struct pri *pri, int tei, int devnull) + { +- if (pri->t203_timer) { +- pri_schedule_del(pri, pri->t203_timer); +- if (pri->debug & PRI_DEBUG_Q921_DUMP) +- 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); ++ 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_DUMP) +- 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]) { ++ /* Something was ACK'd. Stop T200 counter */ ++ pri_schedule_del(pri, pri->t200_timer[teio]); ++ pri->t200_timer[teio] = 0; + if (pri->debug & PRI_DEBUG_Q921_DUMP) + 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->t203_timer) { ++ if (pri->t203_timer[teio]) { ++ pri_schedule_del(pri, pri->t203_timer[teio]); ++ pri->t203_timer[teio] = 0; + if (pri->debug & PRI_DEBUG_Q921_DUMP) + pri_message(pri, "-- Stopping T203 counter since we got an ACK\n"); +- pri_schedule_del(pri, pri->t203_timer); +- pri->t203_timer = 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_DUMP) +- 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->t200_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri, tei); + } else { + if (pri->debug & PRI_DEBUG_Q921_DUMP) + 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: +@@ -279,23 +720,38 @@ static void q921_reject(struct pri *pri, + 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_DUMP) +- 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: +@@ -310,85 +766,190 @@ static void q921_rr(struct pri *pri, int + 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_DUMP) +- 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_DUMP) + pri_message(pri, "-- T200 counter expired, What to do...\n"); + /* Force Poll bit */ +- pri->txqueue->h.p_f = 1; ++ pri->txqueue[teio]->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++; ++ pri->txqueue[teio]->h.n_r = pri->v_r[teio]; ++ pri->v_na[teio] = pri->v_r[teio]; ++ pri->solicitfbit[teio] = 1; ++ 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_DUMP) +- pri_message(pri, "-- Retransmitting %d bytes\n", pri->txqueue->len); +- if (pri->busy) +- q921_rr(pri, 1, 1); ++ pri_message(pri, "-- Retransmitting %d bytes\n", pri->txqueue[teio]->len); ++ if (pri->busy[teio]) ++ q921_rr(pri, 1, 1, tei); + else { +- if (!pri->txqueue->transmitted) ++ 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); + } + if (pri->debug & PRI_DEBUG_Q921_DUMP) +- 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"); +- if (pri->debug & PRI_DEBUG_Q921_STATE && pri->q921_state != Q921_LINK_CONNECTION_RELEASED) ++ if (pri->debug & PRI_DEBUG_Q921_STATE && pri->q921_state[teio] != Q921_LINK_CONNECTION_RELEASED) + pri_message(pri, DBGHEAD "q921_state now is Q921_LINK_CONNECTION_RELEASED\n",DBGINFO); +- 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_DUMP) + 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"); +- if (pri->debug & PRI_DEBUG_Q921_STATE && pri->q921_state != Q921_LINK_CONNECTION_RELEASED) ++ if (pri->debug & PRI_DEBUG_Q921_STATE && pri->q921_state[teio] != Q921_LINK_CONNECTION_RELEASED) + pri_message(pri, DBGHEAD "q921_state now is Q921_LINK_CONNECTION_RELEASED\n", DBGINFO); +- 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); +@@ -406,48 +967,81 @@ int q921_transmit_iframe(struct pri *pri + 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_DUMP) + 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]) { ++ pri_schedule_del(pri, pri->t203_timer[teio]); ++ pri->t203_timer[teio] = 0; + if (pri->debug & PRI_DEBUG_Q921_DUMP) + pri_message(pri, "Stopping T_203 timer\n"); +- pri_schedule_del(pri, pri->t203_timer); +- pri->t203_timer = 0; +- } +- if (!pri->t200_timer) { ++ } ++ if (!pri->t200_timer[teio]) { ++ pri->t200_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri, tei); + if (pri->debug & PRI_DEBUG_Q921_DUMP) + pri_message(pri, "Starting T_200 timer\n"); +- pri->t200_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri); +- } else ++ } else { + if (pri->debug & PRI_DEBUG_Q921_DUMP) +- 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"); + return -1; +@@ -455,49 +1049,78 @@ int q921_transmit_iframe(struct pri *pri + 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) { ++ 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_DUMP) + 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); ++ 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 = pri_schedule_event(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri); ++ pri->t203_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri, tei); + } else { + if (pri->debug & PRI_DEBUG_Q921_DUMP) +- pri_message(pri, "T203 counter expired in weird state %d\n", pri->q921_state); +- pri->t203_timer = 0; ++ pri_message(pri, "T203 counter expired in weird state %d\n", pri->q921_state[teio]); ++ pri->t203_timer[teio] = 0; ++ } ++} ++ ++static void q921_start_tei(struct pri *pri, int tei); ++ ++ ++static void t201_expire(void *vpri, int tei) ++{ ++ struct pri *pri = vpri; ++ int teio=tei - Q921_TEI_BASE; ++ int i = 0; ++ if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; } ++ if (tei == Q921_TEI_GROUP) { ++ for (i=0;iq921_tei_check[i] == 1) { ++ pri->q921_tei_check[i] = 0; ++ q921_start_tei(pri, Q921_TEI_BASE + i); ++ } ++ } ++ } else { ++ if (pri->q921_tei_check[teio] == 1) { ++ pri->q921_tei_check[teio] = 0; ++ q921_start_tei(pri, tei); ++ } + } ++ pri->t201_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; } + /* 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) + return ev; + if (i->p_f) { + /* If the Poll/Final bit is set, immediate send the RR */ +- q921_rr(pri, 1, 0); ++ q921_rr(pri, 1, 0, i->h.tei); + } else if (pri->busy) { +- q921_rr(pri, 0, 0); ++ 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; + } +@@ -506,10 +1129,10 @@ static pri_event *q921_handle_iframe(str + } 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; + } +@@ -647,72 +1270,135 @@ void q921_dump(struct pri *pri, q921_h * + }; + } + +-static pri_event *q921_dchannel_up(struct pri *pri) +-{ +- /* Reset counters, etc */ +- q921_reset(pri); ++static void q921_tei_recovery(struct pri *pri, int tei) { ++ int i = 0; ++ int teio=tei - Q921_TEI_BASE; ++ if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; } ++ for (i=0;iq921_tei_check[i] = 1; ++ } ++ } ++ q921_send_teichkreq(pri, tei); ++ if (!pri->t201_timer[teio]) { ++ pri->t201_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T201], t201_expire, pri, tei); ++ } ++} ++ ++static pri_event *q921_dchannel_up(struct pri *pri, int tei) ++{ ++// q931_dl_indication(pri, PRI_EVENT_DCHAN_UP); ++ // 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; ++ } ++ ++/* neonova test */ ++ if (pri->t203_timer[teio]) { ++ pri_schedule_del(pri, pri->t203_timer[teio]); ++ pri->t203_timer[teio] = 0; ++ } + + /* Reset any rejects */ +- pri->sentrej = 0; ++ pri->sentrej[teio] = 0; + + /* Go into connection established state */ +- if (pri->debug & PRI_DEBUG_Q921_STATE && pri->q921_state != Q921_LINK_CONNECTION_ESTABLISHED) +- pri_message(pri, DBGHEAD "q921_state now is Q921_LINK_CONNECTION_ESTABLISHED\n", DBGINFO); +- 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; + +- /* Notify Layer 3 */ +- q931_dl_indication(pri, PRI_EVENT_DCHAN_UP); ++ 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; +- return &pri->ev; ++ /* 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); +- +- /* Notify Layer 3 */ +- q931_dl_indication(pri, PRI_EVENT_DCHAN_DOWN); ++ if (pri->localtype == BRI_NETWORK_PTMP) { ++ if (pri->t203_timer[teio]) { ++ pri_schedule_del(pri, pri->t203_timer[teio]); ++ pri->t203_timer[teio] = 0; ++ if (pri->debug & PRI_DEBUG_Q921_STATE) { ++ pri_message(pri, "Stopping T_203 timer for TEI %d\n", tei); ++ } ++ } ++ } ++ ++ 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; +- if (pri->debug & PRI_DEBUG_Q921_STATE && pri->q921_state != Q921_LINK_CONNECTION_RELEASED) +- pri_message(pri, DBGHEAD "q921_state now is Q921_LINK_CONNECTION_RELEASED\n", DBGINFO); +- 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) +@@ -720,12 +1406,16 @@ static pri_event *__q921_receive_qualifi + 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 */ +@@ -736,8 +1426,10 @@ static pri_event *__q921_receive_qualifi + 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) { +@@ -747,56 +1439,75 @@ static pri_event *__q921_receive_qualifi + 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) { ++ if (pri->solicitfbit[teio]) { + if (pri->debug & PRI_DEBUG_Q921_DUMP) + pri_message(pri, "-- Got RR response to our frame\n"); + } else { + if (pri->debug & PRI_DEBUG_Q921_DUMP) + 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_DUMP) + 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; ++ 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_DUMP) + 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; ++ q921_ack_rx(pri, h->s.n_r, h->h.tei); ++ /* Reset t200 timer if it was somehow going */ ++ if (pri->t200_timer[teio]) { ++ pri_schedule_del(pri, pri->t200_timer[teio]); ++ pri->t200_timer[teio] = 0; ++ } ++ + /* Resend the proper I-frame */ +- for(f=pri->txqueue;f;f=f->next) { ++ for(f=pri->txqueue[teio];f;f=f->next) { + 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; ++ f->h.n_r = pri->v_r[teio]; + q921_transmit(pri, (q921_h *)(&f->h), f->len); + } + } + if (!sendnow) { +- if (pri->txqueue) { ++ if (pri->txqueue[teio]) { + /* This should never happen */ + 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); +@@ -804,23 +1515,37 @@ static pri_event *__q921_receive_qualifi + } 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->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, h->h.tei); + } +- } ++ } else { ++ if (h->s.p_f) { ++ /* If it has the poll bit set (and an iframe was retransmitted), send an appropriate supervisory response */ ++ /* Reset t200 timer if it was somehow going */ ++ if (pri->t200_timer[teio]) { ++ pri_schedule_del(pri, pri->t200_timer[teio]); ++ pri->t200_timer[teio] = 0; ++ } ++ /* 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: +@@ -837,8 +1562,16 @@ static pri_event *__q921_receive_qualifi + if (pri->debug & (PRI_DEBUG_Q921_STATE | PRI_DEBUG_Q921_DUMP)) + 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 { +@@ -846,21 +1579,153 @@ static pri_event *__q921_receive_qualifi + 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) { ++ } 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: ++ 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;teiq921_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 { ++ pri_error(pri, "no TEI available. starting TEI recovery procedure. dont worry!\n"); ++ q921_tei_recovery(pri, 127); ++ ++ } ++ 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; ++ case Q921_TEI_ID_CHK_RES: ++ if (pri->localtype != BRI_NETWORK_PTMP) ++ break; ++ teio = (h->u.data[4] >> 1) - Q921_TEI_BASE; ++ if ((teio < 0) || (teio >= Q921_MAX_TEIS)) break; ++ if (pri->q921_tei_check[teio] == 1) { ++ pri->q921_tei_check_ri[teio] = (h->u.data[1] << 8) + h->u.data[2]; ++ pri->q921_tei_check[teio] = 0; ++ } else { ++ // d a t ++ pri_error(pri, "double assgined tei for tei %d teio %d\n", h->u.data[4] >> 1, teio); ++ pri->q921_tei_check[teio] = 0; ++ q921_start_tei(pri, h->u.data[4] >> 1); ++ } ++ 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) || (pri->localtype == BRI_CPE)){ ++ 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_DEBUG_Q921_DUMP)) + pri_message(pri, "-- Got Disconnect from peer.\n"); ++#ifndef RELAX_TRB ++ if (pri->q921_state[teio] != Q921_LINK_CONNECTION_ESTABLISHED) { ++ q921_send_dm(pri, 1, h->h.tei); ++ return NULL; ++ } ++#endif + /* 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)) { ++#ifndef LAYER2ALWAYSUP ++ /* release layer 2 */ ++ return NULL; ++#else ++ /* keep layer 2 up */ ++ if (pri->t203_timer[teio]) ++ pri_schedule_del(pri, pri->t203_timer[teio]); ++ pri->t203_timer[teio] = 0; ++ q921_send_sabme(pri, 1, pri->tei); ++#endif ++ } ++ if ((pri->localtype == PRI_NETWORK) || (pri->localtype == PRI_CPE)){ ++ q921_start(pri, 0, 0); ++ } + return ev; + case 3: + if (h->u.m2 == 3) { +@@ -882,17 +1747,29 @@ static pri_event *__q921_receive_qualifi + } + } + /* 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_DEBUG_Q921_DUMP)) { + 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 { ++#ifndef RELAX_TRB ++ q921_reset(pri, h->h.tei, 1); ++#else ++ /* send DM */ ++ q921_send_dm(pri, 1, h->h.tei); ++#endif ++ } ++ } + } else + pri_error(pri, "!! Weird frame received (m3=3, m2 = %d)\n", h->u.m2); + break; +@@ -916,20 +1793,44 @@ static pri_event *__q921_receive(struct + pri_event *ev; + /* Discard FCS */ + len -= 2; +- +- if (!pri->master && pri->debug & (PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_RAW)) +- 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; + +- /* Check for broadcasts - not yet handled */ +- if (h->h.tei == Q921_TEI_GROUP) +- 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 | PRI_DEBUG_Q921_RAW)) ++ q921_dump(pri, h, len, pri->debug & PRI_DEBUG_Q921_RAW, 0); + + /* Check for SAPIs we don't yet handle */ +- if ((h->h.sapi != pri->sapi) || (h->h.tei != pri->tei)) { ++ if (pri->localtype != BRI_NETWORK_PTMP) { ++ /* Check for SAPIs we don't yet handle */ ++ 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) +@@ -937,10 +1838,16 @@ static pri_event *__q921_receive(struct + 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; + } + +@@ -954,14 +1861,58 @@ pri_event *q921_receive(struct pri *pri, + 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_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) { ++#ifdef RELAX_TRB ++ /* let's get a TEI */ ++ q921_send_teireq(pri); ++#endif ++ } 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); + } +Index: libpri-1.4.3/q931.c +=================================================================== +--- libpri-1.4.3.orig/q931.c ++++ libpri-1.4.3/q931.c +@@ -1,10 +1,12 @@ + /* + * libpri: An implementation of Primary Rate ISDN + * +- * Written by Mark Spencer ++ * Written by Mark Spencer + * +- * Copyright (C) 2001-2005, Digium ++ * Copyright (C) 2001, Linux Support Services, Inc. + * All Rights Reserved. ++ * Copyright (C) 2003-2006 Junghanns.NET GmbH ++ * Klaus-Peter Junghanns + * + * 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 + #include ++#include + #include + #include + #include +@@ -208,6 +211,14 @@ static struct msgtype facilities[] = { + #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); + +@@ -256,6 +267,7 @@ static char *code2str(int code, struct m + static void call_init(struct q931_call *c) + { + memset(c, 0, sizeof(*c)); ++ c->con_acked = 0; + c->alive = 0; + c->sendhangupack = 0; + c->forceinvert = -1; +@@ -268,8 +280,16 @@ static void call_init(struct q931_call * + 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; ++ c->llc[0] = '\0'; ++ c->cause = -1; ++ c->causecode = -1; ++ c->causeloc = -1; + } + + static char *binary(int b, int len) { +@@ -287,14 +307,17 @@ static FUNC_RECV(receive_channel_id) + { + 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; +@@ -303,6 +326,7 @@ static FUNC_RECV(receive_channel_id) + default: + pri_error(pri, "!! Unexpected Channel selection %d\n", ie->data[0] & 3); + return -1; ++ } + } + #endif + if (ie->data[0] & 0x08) +@@ -364,10 +388,16 @@ static FUNC_SEND(transmit_channel_id) + } + + /* 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; +@@ -384,6 +414,7 @@ static FUNC_SEND(transmit_channel_id) + } 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) { +@@ -399,11 +430,43 @@ static FUNC_SEND(transmit_channel_id) + 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; + } +@@ -750,9 +813,13 @@ char *pri_pres2str(int pres) + 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) || (len > maxlen - 1)) { ++ if (len < 0) { ++ pri_error(NULL, "q931_get_number received invalid len = %d\n", len); ++ return; ++ } ++ if (len > maxlen - 1) { + num[0] = 0; + return; + } +@@ -762,7 +829,7 @@ static void q931_get_number(unsigned cha + + static FUNC_DUMP(dump_called_party_number) + { +- unsigned char cnum[256]; ++ 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", +@@ -771,7 +838,7 @@ static FUNC_DUMP(dump_called_party_numbe + + static FUNC_DUMP(dump_called_party_subaddr) + { +- unsigned char cnum[256]; ++ 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, +@@ -781,7 +848,7 @@ static FUNC_DUMP(dump_called_party_subad + + static FUNC_DUMP(dump_calling_party_number) + { +- unsigned char cnum[256]; ++ char cnum[256]; + if (ie->data[0] & 0x80) + q931_get_number(cnum, sizeof(cnum), ie->data + 1, len - 3); + else +@@ -795,7 +862,7 @@ static FUNC_DUMP(dump_calling_party_numb + + static FUNC_DUMP(dump_calling_party_subaddr) + { +- unsigned char cnum[256]; ++ char cnum[256]; + q931_get_number(cnum, sizeof(cnum), ie->data + 1, len - 3); + pri_message(pri, "%c Calling Sub-Address (len=%2d) [ Ext: %d Type: %s (%d) O: %d '%s' ]\n", + prefix, len, ie->data[0] >> 7, +@@ -805,7 +872,7 @@ static FUNC_DUMP(dump_calling_party_suba + + 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 */ +@@ -832,7 +899,7 @@ static FUNC_DUMP(dump_redirecting_number + + 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 */ +@@ -874,7 +941,7 @@ static FUNC_RECV(receive_redirecting_num + } + } + 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; + } + +@@ -882,7 +949,7 @@ static FUNC_SEND(transmit_redirecting_nu + { + 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; +@@ -894,7 +961,7 @@ static FUNC_SEND(transmit_redirecting_nu + + static FUNC_DUMP(dump_redirecting_subaddr) + { +- unsigned char cnum[256]; ++ 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, +@@ -905,14 +972,14 @@ static FUNC_DUMP(dump_redirecting_subadd + static FUNC_RECV(receive_calling_party_subaddr) + { + /* copy digits to call->callingsubaddr */ +- q931_get_number((unsigned char *) call->callingsubaddr, sizeof(call->callingsubaddr), ie->data + 1, len - 3); ++ q931_get_number(call->callingsubaddr, sizeof(call->callingsubaddr), ie->data + 1, len - 3); + 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); ++ q931_get_number(call->callednum, sizeof(call->callednum), ie->data + 1, len - 3); + call->calledplan = ie->data[0] & 0x7f; + return 0; + } +@@ -942,7 +1009,7 @@ static FUNC_RECV(receive_calling_party_n + + 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); ++ q931_get_number((char *)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 */ +@@ -951,7 +1018,7 @@ static FUNC_RECV(receive_calling_party_n + } + + } else { +- q931_get_number((u_int8_t *)call->callernum, sizeof(call->callernum), data, length); ++ q931_get_number((char *)call->callernum, sizeof(call->callernum), data, length); + call->callerplan = ie->data[0] & 0x7f; + } + +@@ -962,7 +1029,7 @@ static FUNC_SEND(transmit_calling_party_ + { + ie->data[0] = call->callerplan; + ie->data[1] = 0x80 | call->callerpres; +- if (*call->callernum) ++ if (strlen(call->callernum)) + memcpy(ie->data + 2, call->callernum, strlen(call->callernum)); + return strlen(call->callernum) + 4; + } +@@ -980,11 +1047,89 @@ static FUNC_DUMP(dump_user_user) + 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_RECV(receive_high_layer_compat) ++{ ++ return 0; ++} ++ ++static FUNC_SEND(transmit_high_layer_compat) ++{ ++ if (call->transcapability != PRI_TRANS_CAP_RESTRICTED_DIGITAL && call->transcapability != PRI_TRANS_CAP_DIGITAL && call->transcapability != PRI_TRANS_CAP_DIGITAL_W_TONES) { ++ ie->data[0] = 0x91; ++ ie->data[1] = 0x81; ++ return 4; ++ } ++ return 0; ++} ++ ++static FUNC_DUMP(dump_high_layer_compat) ++{ ++ int x; ++ pri_message(pri, "%c High-layer compatibilty (len=%2d) [ ", prefix, len); ++ for (x=0;xlen;x++) ++ pri_message(pri, "0x%02X ", ie->data[x]); ++ pri_message(pri, " ]\n"); ++} ++ ++ ++static FUNC_RECV(receive_low_layer_compat) ++{ ++ if (len > 0) { ++ if (len > 16) { ++ pri_error(pri, "%d bytes LLC too long\n", len); ++ call->llc[0] = 0; ++ } else { ++ pri_error(pri, "copying %d bytes LLC \n", len); ++ call->llc[0] = len; ++ memcpy(call->llc+1, ie->data, len); ++ } ++ } ++ return 0; ++} ++ ++static FUNC_SEND(transmit_low_layer_compat) ++{ ++ if (call->llc[0] == 0) return 0; ++ memcpy(ie->data, call->llc + 1, call->llc[0]); ++ return call->llc[0] + 2; ++} ++ ++static FUNC_DUMP(dump_low_layer_compat) ++{ ++ int x; ++ pri_message(pri, "%c Low-layer compatibilty (len=%2d) [ ", prefix, len); ++ for (x=0;xlen;x++) ++ pri_message(pri, "0x%02X ", ie->data[x]); ++ pri_message(pri, " ]\n"); ++} ++ + static FUNC_SEND(transmit_user_user) + { + int datalen = strlen(call->useruserinfo); +@@ -1066,7 +1211,7 @@ static FUNC_RECV(receive_display) + data++; + len--; + } +- q931_get_number((unsigned char *) call->callername, sizeof(call->callername), data, len - 2); ++ q931_get_number((char *) call->callername, sizeof(call->callername), data, len - 2); + return 0; + } + +@@ -1130,6 +1275,111 @@ static FUNC_RECV(receive_progress_indica + 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; +@@ -1155,6 +1405,182 @@ static FUNC_SEND(transmit_facility) + 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; +@@ -1362,6 +1788,25 @@ static FUNC_DUMP(dump_call_identity) + pri_message(pri, " ]\n"); + } + ++ ++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_time_date) + { + pri_message(pri, "%c Time Date (len=%2d) [ ", prefix, len); +@@ -1382,7 +1827,7 @@ static FUNC_DUMP(dump_time_date) + + static FUNC_DUMP(dump_keypad_facility) + { +- char tmp[64]; ++ char tmp[64] = ""; + + if (ie->len == 0 || ie->len > sizeof(tmp)) + return; +@@ -1992,8 +2437,8 @@ static struct ie ies[] = { + { 1, Q931_REDIRECTING_SUBADDR, "Redirecting Subaddress", dump_redirecting_subaddr }, + { 0, Q931_TRANSIT_NET_SELECT, "Transit Network Selection" }, + { 1, Q931_RESTART_INDICATOR, "Restart Indicator", dump_restart_indicator, receive_restart_indicator, transmit_restart_indicator }, +- { 0, Q931_LOW_LAYER_COMPAT, "Low-layer Compatibility" }, +- { 0, Q931_HIGH_LAYER_COMPAT, "High-layer Compatibility" }, ++ { 0, Q931_LOW_LAYER_COMPAT, "Low-layer Compatibility" , dump_low_layer_compat, receive_low_layer_compat, transmit_low_layer_compat }, ++ { 1, Q931_HIGH_LAYER_COMPAT, "High-layer Compatibility" , dump_high_layer_compat, receive_high_layer_compat, transmit_high_layer_compat }, + { 1, Q931_PACKET_SIZE, "Packet Size" }, + { 0, Q931_IE_FACILITY, "Facility" , dump_facility, receive_facility, transmit_facility }, + { 1, Q931_IE_REDIRECTION_NUMBER, "Redirection Number" }, +@@ -2002,11 +2447,11 @@ static struct ie ies[] = { + { 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, transmit_keypad_facility }, + { 0, Q931_IE_SIGNAL, "Signal", dump_signal }, + { 1, Q931_IE_SWITCHHOOK, "Switch-hook" }, +@@ -2014,6 +2459,7 @@ static struct ie ies[] = { + { 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_connected_number}, + { 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 }, +@@ -2116,10 +2562,10 @@ static inline int q931_cr(q931_h *h) + 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); +@@ -2162,14 +2608,46 @@ static inline void q931_dumpie(struct pr + pri_error(pri, "!! %c Unknown IE %d (cs%d, len = %d)\n", prefix, Q931_IE_IE(base_ie), Q931_IE_CODESET(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; + } +@@ -2182,6 +2660,7 @@ static q931_call *q931_getcall(struct pr + /* Call reference */ + cur->cr = cr; + cur->pri = pri; ++ cur->tei = tei; + /* Append to end of list */ + if (prev) + prev->next = cur; +@@ -2197,24 +2676,42 @@ q931_call *q931_new_call(struct pri *pri + 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 > 127) ++ 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 +@@ -2223,6 +2720,8 @@ static void q931_destroy(struct pri *pri + 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; +@@ -2233,16 +2732,16 @@ static void q931_destroy(struct pri *pri + 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; + } + +@@ -2354,6 +2853,10 @@ static int q931_handle_ie(int codeset, s + { + 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;xcontents + 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 */ +@@ -2394,13 +2912,23 @@ static void init_header(struct pri *pri, + 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 */ +@@ -2425,7 +2953,11 @@ static int send_message(struct pri *pri, + + 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; +@@ -2443,7 +2975,11 @@ static int send_message(struct pri *pri, + } + /* 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; + } +@@ -2493,12 +3029,34 @@ int q931_keypad_facility(struct pri *pri + return send_message(pri, call, Q931_INFORMATION, keypad_facility_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 restart_ack_ies[] = { Q931_CHANNEL_IDENT, Q931_RESTART_INDICATOR, -1 }; + + static int restart_ack(struct pri *pri, q931_call *c) + { + UPDATE_OURCALLSTATE(pri, c, 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); + } + +@@ -2517,7 +3075,6 @@ int q931_notify(struct pri *pri, q931_ca + if ((info > 0x2) || (info < 0x00)) + return 0; + } +- + if (info >= 0) + c->notify = info & 0x7F; + else +@@ -2560,6 +3117,8 @@ static int call_proceeding_ies[] = { Q93 + + int q931_call_proceeding(struct pri *pri, q931_call *c, int channel, int info) + { ++ // never send two PROCEEDINGs! ++ if (c->proc > 0) return 0; + if (channel) { + c->ds1no = (channel & 0xff00) >> 8; + c->ds1explicit = (channel & 0x10000) >> 16; +@@ -2586,8 +3145,12 @@ static int alerting_ies[] = { Q931_PROGR + 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; + if (!c->proc) + q931_call_proceeding(pri, c, channel, 0); + if (info) { +@@ -2598,14 +3161,130 @@ int q931_alerting(struct pri *pri, q931_ + c->progressmask = 0; + UPDATE_OURCALLSTATE(pri, c, 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_INDICATOR for BRI please */ ++ return send_message(pri, c, Q931_ALERTING, alerting_BRI_ies); ++ } ++ } ++} ++ ++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 connect_ies[] = { Q931_CHANNEL_IDENT, Q931_PROGRESS_INDICATOR, -1 }; ++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)); ++ __q931_destroycall(pri, c); ++ 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) + { ++ int network = pri->localtype == PRI_NETWORK || pri->localtype == BRI_NETWORK || pri->localtype == BRI_NETWORK_PTMP; + if (channel) { + c->ds1no = (channel & 0xff00) >> 8; + c->ds1explicit = (channel & 0x10000) >> 16; +@@ -2623,9 +3302,39 @@ int q931_setup_ack(struct pri *pri, q931 + UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_OVERLAP_RECEIVING); + c->peercallstate = Q931_CALL_STATE_OVERLAP_SENDING; + c->alive = 1; ++ if (network) { ++ c->progloc = LOC_PRIV_NET_LOCAL_USER; ++ c->progcode = CODE_CCITT; ++ c->progressmask = 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.aoc_units = -1; ++ if (c->cause == -1) { ++ pri->ev.hangup.cause = PRI_CAUSE_SWITCH_CONGESTION; ++ } else { ++ pri->ev.hangup.cause = c->cause; ++ } ++ pri->ev.hangup.call = c; ++ q931_hangup(pri, c, c->cause); ++} ++ + static void pri_connect_timeout(void *data) + { + struct q931_call *c = data; +@@ -2680,6 +3389,7 @@ static void pri_disconnect_timeout(void + + int q931_connect(struct pri *pri, q931_call *c, int channel, int nonisdn) + { ++ int network = pri->localtype == PRI_NETWORK || pri->localtype == BRI_NETWORK || pri->localtype == BRI_NETWORK_PTMP; + if (channel) { + c->ds1no = (channel & 0xff00) >> 8; + c->ds1explicit = (channel & 0x10000) >> 16; +@@ -2694,25 +3404,34 @@ int q931_connect(struct pri *pri, q931_c + c->progressmask = PRI_PROG_CALLED_NOT_ISDN; + } else + c->progressmask = 0; +- if(pri->localtype == PRI_NETWORK || pri->switchtype == PRI_SWITCH_QSIG) ++ if(network || pri->switchtype == PRI_SWITCH_QSIG) { + UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_ACTIVE); +- else ++ } else { + UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_CONNECT_REQUEST); ++ } + c->peercallstate = Q931_CALL_STATE_ACTIVE; + c->alive = 1; ++ c->con_acked = 0; + /* Connect request timer */ + if (c->retranstimer) + pri_schedule_del(pri, c->retranstimer); + c->retranstimer = 0; + if ((c->ourcallstate == Q931_CALL_STATE_CONNECT_REQUEST) && (!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 (network) { ++ /* 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_aoce_ies[] = { Q931_CAUSE, Q931_IE_USER_USER, Q931_IE_FACILITY, -1 }; + static int release_ies[] = { Q931_CAUSE, Q931_IE_USER_USER, -1 }; + + int q931_release(struct pri *pri, q931_call *c, int cause) + { ++ int network = pri->localtype == PRI_NETWORK || pri->localtype == BRI_NETWORK || pri->localtype == BRI_NETWORK_PTMP; + UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_RELEASE_REQUEST); + /* c->peercallstate stays the same */ + if (c->alive) { +@@ -2728,7 +3447,14 @@ int q931_release(struct pri *pri, q931_c + } else { + c->retranstimer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T308], pri_release_finaltimeout, c); + } +- return send_message(pri, c, Q931_RELEASE, release_ies); ++ if (network && (c->aoc_units > -1)) { ++ /* include FACILITY IE for AOC-E */ ++ aoc_aoce_charging_unit_encode(pri, c , c->aoc_units, Q931_RELEASE); ++ c->aoc_units = -1; ++ return send_message(pri, c, Q931_RELEASE, release_aoce_ies); ++ } else { ++ return send_message(pri, c, Q931_RELEASE, release_ies); ++ } + } else + return send_message(pri, c, Q931_RELEASE_COMPLETE, release_ies); /* Yes, release_ies, not release_complete_ies */ + } else +@@ -2740,7 +3466,7 @@ static int restart_ies[] = { Q931_CHANNE + 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) +@@ -2757,10 +3483,12 @@ int q931_restart(struct pri *pri, int ch + return send_message(pri, c, Q931_RESTART, restart_ies); + } + ++static int disconnect_aoce_ies[] = { Q931_CAUSE, Q931_IE_USER_USER, Q931_IE_FACILITY, -1 }; + static int disconnect_ies[] = { Q931_CAUSE, Q931_IE_USER_USER, -1 }; + + int q931_disconnect(struct pri *pri, q931_call *c, int cause) + { ++ int network = pri->localtype == PRI_NETWORK || pri->localtype == BRI_NETWORK || pri->localtype == BRI_NETWORK_PTMP; + UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_DISCONNECT_REQUEST); + c->peercallstate = Q931_CALL_STATE_DISCONNECT_INDICATION; + if (c->alive) { +@@ -2772,15 +3500,31 @@ int q931_disconnect(struct pri *pri, q93 + if (c->retranstimer) + pri_schedule_del(pri, c->retranstimer); + c->retranstimer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T305], pri_disconnect_timeout, c); +- return send_message(pri, c, Q931_DISCONNECT, disconnect_ies); ++ if (network && (c->aoc_units > -1)) { ++ /* include FACILITY IE for AOC-E */ ++ aoc_aoce_charging_unit_encode(pri, c , c->aoc_units, Q931_DISCONNECT); ++ c->aoc_units = -1; ++ return send_message(pri, c, Q931_DISCONNECT, disconnect_aoce_ies); ++ } else { ++ return send_message(pri, c, Q931_DISCONNECT, disconnect_ies); ++ } + } else + 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_CALLING_PARTY_NUMBER, Q931_CALLED_PARTY_NUMBER, Q931_REDIRECTING_NUMBER, Q931_IE_USER_USER, Q931_SENDING_COMPLETE, + Q931_IE_ORIGINATING_LINE_INFO, Q931_IE_GENERIC_DIGITS, -1 }; + ++static int setup_cpe_ies[] = { Q931_BEARER_CAPABILITY, Q931_CHANNEL_IDENT, Q931_IE_FACILITY, Q931_PROGRESS_INDICATOR, Q931_NETWORK_SPEC_FAC, 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 }; ++ ++static int setup_bri_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, Q931_HIGH_LAYER_COMPAT, Q931_LOW_LAYER_COMPAT, -1 }; ++ + static int gr303_setup_ies[] = { Q931_BEARER_CAPABILITY, Q931_CHANNEL_IDENT, -1 }; + + static int cis_setup_ies[] = { Q931_BEARER_CAPABILITY, Q931_CHANNEL_IDENT, Q931_IE_FACILITY, Q931_CALLED_PARTY_NUMBER, -1 }; +@@ -2788,7 +3532,13 @@ static int cis_setup_ies[] = { Q931_BEAR + int q931_setup(struct pri *pri, q931_call *c, struct pri_sr *req) + { + int res; +- ++ int network = pri->localtype == PRI_NETWORK || pri->localtype == BRI_NETWORK || pri->localtype == BRI_NETWORK_PTMP; ++ ++ if (pri->localtype == BRI_NETWORK_PTMP) { ++ c->tei = 127; ++ } else { ++ c->tei = 0; ++ } + + c->transcapability = req->transmode; + c->transmoderate = TRANS_MODE_64_CIRCUIT; +@@ -2813,6 +3563,7 @@ int q931_setup(struct pri *pri, q931_cal + c->chanflags = FLAG_EXCLUSIVE; + else if (c->channelno) + c->chanflags = FLAG_PREFERRED; ++ memcpy(c->llc, req->llc, sizeof(c->llc)); + if (req->caller) { + libpri_copy_string(c->callernum, req->caller, sizeof(c->callernum)); + c->callerplan = req->callerplan; +@@ -2868,18 +3619,25 @@ int q931_setup(struct pri *pri, q931_cal + + pri_call_add_standard_apdus(pri, c); + +- if (pri->subchannel) ++ if (pri->subchannel) { + res = send_message(pri, c, Q931_SETUP, gr303_setup_ies); +- else if (c->justsignalling) ++ } else if (c->justsignalling) { + res = send_message(pri, c, Q931_SETUP, cis_setup_ies); +- else ++ } else if (pri->localtype == BRI_NETWORK || pri->localtype == BRI_NETWORK_PTMP) { ++ res = send_message(pri, c, Q931_SETUP, setup_bri_ies); ++ } else if (network) { + res = send_message(pri, c, Q931_SETUP, setup_ies); ++ } else { ++ res = send_message(pri, c, Q931_SETUP, setup_cpe_ies); ++ } + if (!res) { + c->alive = 1; + /* make sure we call PRI_EVENT_HANGUP_ACK once we send/receive RELEASE_COMPLETE */ + c->sendhangupack = 1; + UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_CALL_INITIATED); + c->peercallstate = Q931_CALL_STATE_OVERLAP_SENDING; ++ c->t303timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T303], pri_setup_response_timeout, c); ++ c->t303running = 1; + } + return res; + +@@ -2895,7 +3653,11 @@ static int q931_release_complete(struct + 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 +@@ -2920,6 +3682,125 @@ static int q931_connect_acknowledge(stru + 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! ++#ifdef FASTBUSYONBUSY ++ if ((c->cause == PRI_CAUSE_USER_BUSY) && (c->t303timer)) { ++ c->t303running = 0; ++ pri_schedule_del(pri, c->t303timer); ++ } ++#endif ++ ++ 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.hangup.aoc_units = 0; ++ pri->ev.e = PRI_EVENT_HANGUP; ++ } ++ return res; ++ } ++ ++ ++ + int q931_hangup(struct pri *pri, q931_call *c, int cause) + { + int disconnect = 1; +@@ -2931,7 +3812,7 @@ int q931_hangup(struct pri *pri, q931_ca + /* If mandatory IE was missing, insist upon that cause code */ + if (c->cause == PRI_CAUSE_MANDATORY_IE_MISSING) + cause = c->cause; +- if (cause == 34 || cause == 44 || cause == 82 || cause == 1 || cause == 81) { ++ if (cause == 34 || cause == 44 || cause == 82 || cause == 1 || cause == 81 || cause == 17) { + /* We'll send RELEASE_COMPLETE with these causes */ + disconnect = 0; + release_compl = 1; +@@ -2945,7 +3826,7 @@ int q931_hangup(struct pri *pri, q931_ca + 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; +@@ -2969,6 +3850,11 @@ int q931_hangup(struct pri *pri, q931_ca + /* 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) +@@ -2988,8 +3874,14 @@ int q931_hangup(struct pri *pri, q931_ca + 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; +@@ -3003,19 +3895,17 @@ int q931_hangup(struct pri *pri, q931_ca + 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@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@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; +@@ -3027,6 +3917,7 @@ int q931_receive(struct pri *pri, q931_h + int codeset, cur_codeset; + int last_ie[8]; + struct apdu_event *cur = NULL; ++ int network = pri->localtype == PRI_NETWORK || pri->localtype == BRI_NETWORK || pri->localtype == BRI_NETWORK_PTMP; + + memset(last_ie, 0, sizeof(last_ie)); + if (pri->debug & PRI_DEBUG_Q931_DUMP) +@@ -3040,13 +3931,13 @@ int q931_receive(struct pri *pri, q931_h + 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; +@@ -3069,6 +3960,7 @@ int q931_receive(struct pri *pri, q931_h + 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; +@@ -3104,17 +3996,34 @@ int q931_receive(struct pri *pri, q931_h + c->complete = 0; + c->nonisdn = 0; + c->aoc_units = -1; ++ c->digits[0] = '\0'; ++ c->display[0] = '\0'; ++ c->progress = -1; ++ c->progressmask = 0; + /* Fall through */ +- case Q931_CONNECT: + case Q931_ALERTING: + case Q931_PROGRESS: ++ if (c->t303timer) { ++ c->t303running = 0; ++ pri_schedule_del(pri, c->t303timer); ++ } + c->useruserinfo[0] = '\0'; + c->cause = -1; +- /* Fall through */ +- case Q931_CALL_PROCEEDING: + c->progress = -1; + c->progressmask = 0; + break; ++ case Q931_CALL_PROCEEDING: ++ /* Fall through */ ++ 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; ++ c->progressmask = 0; ++ break; + case Q931_CONNECT_ACKNOWLEDGE: + if (c->retranstimer) + pri_schedule_del(pri, c->retranstimer); +@@ -3130,11 +4039,20 @@ int q931_receive(struct pri *pri, q931_h + 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); + c->retranstimer = 0; ++ if (c->t303timer) { ++ c->t303running = 0; ++ pri_schedule_del(pri, c->t303timer); ++ } + c->useruserinfo[0] = '\0'; + /* Fall through */ + case Q931_STATUS: +@@ -3153,22 +4071,32 @@ int q931_receive(struct pri *pri, q931_h + 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); +@@ -3177,7 +4105,7 @@ int q931_receive(struct pri *pri, q931_h + pri_error(pri, "!! Don't know how to pre-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg); + q931_status(pri,c, PRI_CAUSE_MESSAGE_TYPE_NONEXIST); + if (c->newcall) +- q931_destroycall(pri,c->cr); ++ q931_destroycall(pri,c->cr,c->tei); + return -1; + } + /* Handle IEs */ +@@ -3258,12 +4186,19 @@ int q931_receive(struct pri *pri, q931_h + missingmand = 0; + for (x=0;x 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))) { +- 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++; ++ /* 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++; + } ++ } 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++; ++ } + } + } + +@@ -3272,7 +4207,7 @@ int q931_receive(struct pri *pri, q931_h + 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; + } + UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_RESTART); +@@ -3290,6 +4225,7 @@ int q931_receive(struct pri *pri, q931_h + } + /* 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) +@@ -3307,16 +4243,20 @@ int q931_receive(struct pri *pri, q931_h + 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)); ++ pri->ev.ring.callingplanani = c->callerplanani; + libpri_copy_string(pri->ev.ring.callingnum, c->callernum, sizeof(pri->ev.ring.callingnum)); + libpri_copy_string(pri->ev.ring.callingname, c->callername, sizeof(pri->ev.ring.callingname)); + pri->ev.ring.calledplan = c->calledplan; + libpri_copy_string(pri->ev.ring.callingsubaddr, c->callingsubaddr, sizeof(pri->ev.ring.callingsubaddr)); +- libpri_copy_string(pri->ev.ring.callednum, c->callednum, sizeof(pri->ev.ring.callednum)); ++ if (!strlen(c->callednum) && strlen(c->keypad_digits)) { ++ libpri_copy_string(pri->ev.ring.callednum, c->keypad_digits, sizeof(pri->ev.ring.callednum)); ++ } else { ++ 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)); +@@ -3326,11 +4266,13 @@ int q931_receive(struct pri *pri, q931_h + 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; ++ memcpy(pri->ev.ring.lowlayercompat, c->llc, sizeof(pri->ev.ring.lowlayercompat)); + pri->ev.ring.redirectingreason = c->redirectingreason; + pri->ev.ring.progress = c->progress; + pri->ev.ring.progressmask = c->progressmask; +@@ -3342,6 +4284,9 @@ int q931_receive(struct pri *pri, q931_h + } + UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_CALL_DELIVERED); + c->peercallstate = Q931_CALL_STATE_CALL_RECEIVED; ++ if (pri->localtype == BRI_NETWORK_PTMP) { ++ l2c = q921_getcall(pri, c, tei); ++ } + pri->ev.e = PRI_EVENT_RINGING; + pri->ev.ringing.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); + pri->ev.ringing.cref = c->cr; +@@ -3370,17 +4315,24 @@ int q931_receive(struct pri *pri, q931_h + q931_status(pri, c, PRI_CAUSE_WRONG_MESSAGE); + break; + } ++ /* TEI got the call */ ++ c->tei = tei; + UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_ACTIVE); + c->peercallstate = Q931_CALL_STATE_CONNECT_REQUEST; + pri->ev.e = PRI_EVENT_ANSWER; + pri->ev.answer.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); + pri->ev.answer.cref = c->cr; + pri->ev.answer.call = c; ++ pri->ev.answer.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.answer.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; +@@ -3388,23 +4340,43 @@ int q931_receive(struct pri *pri, q931_h + 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: /* CD */ ++ pri->ev.facility.operation = 0x0D; ++ libpri_copy_string(pri->ev.facility.forwardnum, c->redirectingnum, sizeof(pri->ev.facility.forwardnum)); ++ break; ++ default: ++ pri->ev.facility.operation = c->facility; ++ } ++ } else { ++ 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.callingname)); ++ 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; +@@ -3422,6 +4394,11 @@ int q931_receive(struct pri *pri, q931_h + 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; +@@ -3449,17 +4426,18 @@ int q931_receive(struct pri *pri, q931_h + } + if (!(c->ourcallstate == Q931_CALL_STATE_CONNECT_REQUEST) && + !(c->ourcallstate == Q931_CALL_STATE_ACTIVE && +- (pri->localtype == PRI_NETWORK || pri->switchtype == PRI_SWITCH_QSIG))) { ++ (network || pri->switchtype == PRI_SWITCH_QSIG))) { + q931_status(pri,c,PRI_CAUSE_WRONG_MESSAGE); + break; + } + UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_ACTIVE); + c->peercallstate = Q931_CALL_STATE_ACTIVE; ++ c->con_acked = 1; + break; + 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) { +@@ -3500,30 +4478,46 @@ int q931_receive(struct pri *pri, q931_h + } + break; + case Q931_RELEASE_COMPLETE: +- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_NULL); +- c->peercallstate = Q931_CALL_STATE_NULL; +- pri->ev.hangup.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); +- pri->ev.hangup.cause = c->cause; +- pri->ev.hangup.cref = c->cr; +- pri->ev.hangup.call = c; +- pri->ev.hangup.aoc_units = c->aoc_units; +- libpri_copy_string(pri->ev.hangup.useruserinfo, c->useruserinfo, sizeof(pri->ev.hangup.useruserinfo)); +- c->useruserinfo[0] = '\0'; +- /* Free resources */ +- if (c->alive) { ++ if (pri->localtype != BRI_NETWORK_PTMP) { ++ /* only stop the T303 timer if WE are not a BRI PTMP network */ ++ if (c->t303timer) { ++ c->t303running = 0; ++ pri_schedule_del(pri, c->t303timer); ++ c->t303timer = 0; ++ } ++ } ++ if ((pri->localtype != BRI_NETWORK_PTMP) || (c->tei == tei)) { ++ UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_NULL); ++ c->peercallstate = Q931_CALL_STATE_NULL; ++ pri->ev.hangup.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); ++ pri->ev.hangup.cause = c->cause; ++ pri->ev.hangup.cref = c->cr; ++ pri->ev.hangup.call = c; ++ pri->ev.hangup.aoc_units = c->aoc_units; ++ libpri_copy_string(pri->ev.hangup.useruserinfo, c->useruserinfo, sizeof(pri->ev.hangup.useruserinfo)); ++ c->useruserinfo[0] = '\0'; ++ /* Free resources */ ++ if (c->alive) { + pri->ev.e = PRI_EVENT_HANGUP; + res = Q931_RES_HAVEEVENT; + c->alive = 0; +- } else if (c->sendhangupack) { ++ } else if (c->sendhangupack) { + res = Q931_RES_HAVEEVENT; + pri->ev.e = PRI_EVENT_HANGUP_ACK; +- pri_hangup(pri, c, c->cause); +- } else ++ pri_hangup(pri, c, c->cause, -1); ++ } else + res = 0; +- if (res) ++ if (res) + return res; +- else ++ 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) { +@@ -3538,11 +4532,12 @@ int q931_receive(struct pri *pri, q931_h + UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_NULL); + pri->ev.e = PRI_EVENT_HANGUP; + pri->ev.hangup.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); +- pri->ev.hangup.cause = c->cause; + pri->ev.hangup.cref = c->cr; ++ pri->ev.hangup.tei = c->tei; ++ pri->ev.hangup.cause = c->cause; + pri->ev.hangup.call = c; + pri->ev.hangup.aoc_units = c->aoc_units; +- libpri_copy_string(pri->ev.hangup.useruserinfo, c->useruserinfo, sizeof(pri->ev.hangup.useruserinfo)); ++ libpri_copy_string(pri->ev.hangup.useruserinfo, c->useruserinfo, sizeof(pri->ev.ring.useruserinfo)); + c->useruserinfo[0] = '\0'; + /* Don't send release complete if they send us release + while we sent it, assume a NULL state */ +@@ -3566,12 +4561,17 @@ int q931_receive(struct pri *pri, q931_h + /* Return such an event */ + pri->ev.e = PRI_EVENT_HANGUP_REQ; + pri->ev.hangup.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); +- pri->ev.hangup.cause = c->cause; + pri->ev.hangup.cref = c->cr; ++ pri->ev.hangup.tei = c->tei; ++ pri->ev.hangup.cause = c->cause; + pri->ev.hangup.call = c; + pri->ev.hangup.aoc_units = c->aoc_units; +- libpri_copy_string(pri->ev.hangup.useruserinfo, c->useruserinfo, sizeof(pri->ev.hangup.useruserinfo)); +- c->useruserinfo[0] = '\0'; ++ if (c->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; + else +@@ -3624,7 +4624,6 @@ int q931_receive(struct pri *pri, q931_h + 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) { +@@ -3640,19 +4639,53 @@ int q931_receive(struct pri *pri, q931_h + 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); +@@ -3662,7 +4695,7 @@ int q931_receive(struct pri *pri, q931_h + 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; +Index: libpri-1.4.3/README +=================================================================== +--- libpri-1.4.3.orig/README ++++ libpri-1.4.3/README +@@ -1,6 +1,7 @@ +-libpri: An implementation of Primary Rate ISDN ++libpri: An implementation of Primate Rate ISDN (and BRI ISDN) + +-Written by Mark Spencer ++Written by Mark Spencer ++Modified for BRI support by Klaus-Peter Junghanns + + What is libpri? + =============== +@@ -9,6 +10,7 @@ libpri is a C implementation of the Prim + 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 @@ within the GPL) is licensed either under + 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? --- libpri-1.4.3.orig/debian/patches/stddef.dpatch +++ libpri-1.4.3/debian/patches/stddef.dpatch @@ -0,0 +1,19 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## stddef.dpatch by Faidon Liambotis +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: sys/time.h doesn't include stddef.h and FTBFS because size_t is +## DP: undefined. #453161, upstream r478 + +@DPATCH@ +diff -urNad libpri-1.4.2~/pri_internal.h libpri-1.4.2/pri_internal.h +--- libpri-1.4.2~/pri_internal.h 2006-06-06 22:06:52.000000000 +0000 ++++ libpri-1.4.2/pri_internal.h 2007-11-29 09:50:01.000000000 +0000 +@@ -25,6 +25,7 @@ + #ifndef _PRI_INTERNAL_H + #define _PRI_INTERNAL_H + ++#include + #include + + #define DBGHEAD __FILE__ ":%d %s: " --- libpri-1.4.3.orig/debian/changelog +++ libpri-1.4.3/debian/changelog @@ -0,0 +1,321 @@ +libpri (1.4.3-2~bpo40+1) etch-backports; urgency=low + + * Rebuild for etch-backports. + + -- Victor Seva Fri, 25 Jul 2008 09:13:05 +0200 + +libpri (1.4.3-2) unstable; urgency=low + + [ Faidon Liambotis ] + * Update to bristuff 0.4.0-RC1 + - fixed "call reference exceeds 127 on BRI spans" bug in libpri + which caused a deadlock in chan_zap. + - fixed "t303 not stopped" bug in libpri. + * Add Junghanns.NET GmbH to the copyright holders in debian/copyright. + * Refer to /usr/share/common-licenses/GPL-2 to avoid ambiguity vs. GPLv3. + + [ Victor Seva ] + * debian/rules: fix get-orig-source to actually work + + -- Faidon Liambotis Wed, 21 May 2008 03:33:52 +0300 + +libpri (1.4.3-1) unstable; urgency=low + + [ Mark Purcell ] + * New upstream release + + [ Tzafrir Cohen ] + * Watching downloads.digium.com directly again. + + -- Mark Purcell Tue, 22 Apr 2008 22:49:51 +1000 + +libpri (1.4.2-2) unstable; urgency=low + + [ Faidon Liambotis ] + * Fix debian/watch by using a pkg-voip wrapper to avoid upstream's silly + redirections. (Closes: #449956) + * Bump Standards-Version to 3.7.3, no changed needed. + * Remove Jose Carlos Garcia Sogo and Santiago Garcia Mantinan from + Uploaders. + + [ Tzafrir Cohen ] + * Reset T303 timer on ALERTING and PROGRESS response to setup, from + bristuff 0.4.0-test6-xr2 (Closes: #473550). + + -- Faidon Liambotis Tue, 01 Apr 2008 07:04:33 +0300 + +libpri (1.4.2-1) unstable; urgency=low + + [ Kilian Krause ] + * Add Homepage field as added in dpkg-dev 1.14.6. + + [ Tzafrir Cohen ] + * New upstream release. + * Update bristuff to new upstream release. + * Update makefile patches to new upstream. + * Do build bristuffed version as well with -Werror . + * Fix an uninitialized variable there. + * BRI overlap digits were ignored - regression from 1.2 (Closes: #448118). + + [ Faidon Liambotis ] + * Include since doesn't include it anymore. + Fixes FTBFS (Closes: #453161). + + -- Faidon Liambotis Thu, 29 Nov 2007 10:32:50 +0000 + +libpri (1.4.1-2) unstable; urgency=low + + * Enable -O2 optimizations, following Policy 10.1. (Closes: #359186) + * Conflict with libpri1.2 versions prior to 1.4.0-2 to ease transition for + testing and unstable users. (Closes: #437804) + + -- Faidon Liambotis Wed, 15 Aug 2007 01:11:16 +0300 + +libpri (1.4.1-1) unstable; urgency=low + + * New Upstream Release + + [ Tzafrir Cohen ] + * Re-Adding bristuff. + * Which requires re-applying and fixing libname.dpatch . + + [ Faidon Liambotis ] + * Add myself to Uploaders. + * Add XS-Vcs-Svn and XS-Vcs-Browser to debian/control. + * Switch to dh_install from the deprecated dh_movefiles. + * Use ${binary:Version} instead of ${Source-Version}. + * Loosen up shlibs: we want to create shlibs that are >= 1.4, not the + specific version of libpri 1.4 (e.g. 1.4.1). + * Conflict/Replace libpri1.2 from etch since we're providing the same files. + + [ Mark Purcell ] + * Bump package name to match soname libpri1.0 + + -- Mark Purcell Sat, 04 Aug 2007 09:41:50 +0100 + +libpri (1.4.0-2) unstable; urgency=low + + * unstable release + + -- Mark Purcell Sun, 18 Mar 2007 21:41:16 +0000 + +libpri (1.4.0-1) experimental; urgency=low + + [ Tzafrir Cohen ] + * A new package for branch 1.4. + * Bristuff disabled. + * Standard version updated to 3.7.2. No change required. + + [ Mark Purcell ] + * Update debian/watch for 1.4 series + + -- Mark Purcell Sun, 18 Mar 2007 21:36:25 +0000 + +libpri (1.2.4-1) unstable; urgency=low + + * New upstream release. + * bristuff-0.3.0-PRE-1v + + -- Mark Purcell Tue, 24 Oct 2006 22:21:29 +0100 + +libpri (1.2.3-1) unstable; urgency=low + + * New upstream release. + + [ Tzafrir Cohen ] + * Patches have been applied upstream + * Makefile.dpatch: Remove unused fix from patches + * bristuff 0.3.0-PRE1p + + [ Mark Purcell ] + * Cleanup bristuff.dpatch for Upstream 1.2.3. + + -- Mark Purcell Wed, 14 Jun 2006 12:11:36 +1000 + +libpri (1.2.2-3) unstable; urgency=low + + * Use CURDIR rather than PWD to make sure we can build with sudo. + + -- Kilian Krause Sun, 16 Apr 2006 22:55:59 +0000 + +libpri (1.2.2-2) unstable; urgency=low + + * bristuff 0.3.0-PRE-1k + * some changes to the libname patch (don't change links in the build dir) + * we no longer need to symlink manually (right?) + + -- Tzafrir Cohen Wed, 08 Feb 2006 00:39:46 +0200 + +libpri (1.2.2-1) unstable; urgency=low + + [ Tzafrir Cohen ] + * bristuff 0.3.0-PRE-1f + + [ Kilian Krause ] + * New upstream release. + * New ABI since 1.2.1 without chaning SONAME. Adjusting at least the package + name accordingly nevertheless. (Closes: #341109) + * Add GNU/kFreeBSD patch to run ldconfig (Closes: #338388) + + -- Kilian Krause Sun, 5 Feb 2006 11:42:46 +0100 + +libpri (1.2.1-2) unstable; urgency=low + + * bristuff 0.3.0-PRE-1d + * bristuff is built by default, but as a separate library: + libpri-bristuffed.so.1 , /usr/include/bristuffed/pri.h . Thus the default + libpri is unmodified. + + -- Tzafrir Cohen Sat, 31 Dec 2005 15:28:25 +0200 + +libpri (1.2.1-1) unstable; urgency=low + + * New upstream release + * Disable bristuff for new upstream + + -- Mark Purcell Wed, 7 Dec 2005 21:25:46 +0000 + +libpri (1.2.0-release-2) unstable; urgency=low + + * bristuff 0.3.0-PRE-1 + + -- Tzafrir Cohen Wed, 23 Nov 2005 02:26:50 +0200 + +libpri (1.2.0-release-1) unstable; urgency=low + + * New upstream release + + -- Mark Purcell Thu, 17 Nov 2005 17:44:28 +0000 + +libpri (1.2.0-rc2-1) experimental; urgency=low + + * New upstream release + + -- Mark Purcell Sun, 13 Nov 2005 18:21:12 +0000 + +libpri (1.2.0-rc1-1) unstable; urgency=low + + * New upstream release + * Copyright audit to debian/copyright + + -- Mark Purcell Wed, 9 Nov 2005 20:01:55 +0000 + +libpri (1.2.0-beta2-1) experimental; urgency=low + + * New upstream release + * Update Makefile.patch + + -- Mark Purcell Tue, 1 Nov 2005 21:46:25 +0000 + +libpri (1.2.0-0beta1-1) experimental; urgency=low + + * New upstream release + * Disable bristuff for experimental upload + * lintian cleanup debian/copyright + + -- Mark Purcell Tue, 30 Aug 2005 20:36:41 +0100 + +libpri (1.0.9-4) unstable; urgency=low + + * Import bristuff-0.2.0-RC8l.dpatch + + -- Santiago Ruano Rincon Sat, 30 Jul 2005 11:30:30 -0500 + +libpri (1.0.9-3) unstable; urgency=low + + * Import bristuff_2.0.0-RC8j + + -- Mark Purcell Thu, 14 Jul 2005 12:35:29 +0100 + +libpri (1.0.9-2) unstable; urgency=low + + * With bristuff_2.0.0-RC8h enabled + + -- Mark Purcell Sat, 2 Jul 2005 09:32:21 +0100 + +libpri (1.0.9-1) unstable; urgency=low + + * New upstream release + * Temp disable BRI stuff to enable 1.0.9 upload + + -- Mark Purcell Sat, 2 Jul 2005 09:03:34 +0100 + +libpri (1.0.7-2) UNRELEASED; urgency=low + + * NOT RELEASED YET + + -- Mark Purcell Fri, 25 Mar 2005 10:39:35 +0000 + +libpri (1.0.7-1) unstable; urgency=low + + * New upstream release + * debian/watch to svn-upgrade + + -- Mark Purcell Fri, 25 Mar 2005 10:36:08 +0000 + +libpri (1.0.6-1) unstable; urgency=low + + * New upstream version. (libpri 1.0.6, bristuff RC7k) + * Upgraded Standards-Version to 3.6.1 after converting changelog to UTF8. + + -- Kilian Krause Sat, 5 Mar 2005 13:33:10 +0100 + +libpri (1.0.4-2) unstable; urgency=low + + * Debian VoIP import. + * debian/patches/Makefile.dpatch, debian/patches/q931.dpatch: imported from + old diff. + * debian/patches/bristuff.dpatch: Added bristuff RC7f from junghanns.net + (needs disabled q931.dpatch for now) (Closes: #294184) + + -- Kilian Krause Thu, 24 Feb 2005 01:25:11 +0100 + +libpri (1.0.4-1) unstable; urgency=low + + * New upstream release (Closes: Bug#288447) + * Apply amd64 patch from Andreas Jochens (Closes: Bug#287442) + + -- Mark Purcell Sun, 6 Feb 2005 11:09:04 +0000 + +libpri (1.0.2-1) unstable; urgency=low + + * New upstream release + + -- Mark Purcell Sat, 6 Nov 2004 12:17:41 +1100 + +libpri (1.0.1-1) unstable; urgency=low + + * New upstream release + + -- Mark Purcell Thu, 7 Oct 2004 13:03:22 +1000 + +libpri (1.0.0-1) unstable; urgency=low + + * New upstream release + + -- Mark Purcell Fri, 24 Sep 2004 22:28:02 +1000 + +libpri (0.6.0+1.0RC1-1) unstable; urgency=low + + * New upstream release (Closes: Bug#254501) + + -- Mark Purcell Tue, 20 Jul 2004 19:14:24 +1000 + +libpri (0.6.0-1) unstable; urgency=low + + * New upstream release + + -- Mark Purcell Thu, 22 Apr 2004 23:59:18 +1000 + +libpri (0.5.2-1) unstable; urgency=low + + * New Upstream Release (Closes: Bug#200188) + + -- Mark Purcell Thu, 5 Feb 2004 16:01:49 +1100 + +libpri (0.3.2-1) unstable; urgency=low + + * Initial Release. + + -- Mark Purcell Wed, 2 Jul 2003 20:23:13 +1000 + --- libpri-1.4.3.orig/debian/copyright +++ libpri-1.4.3/debian/copyright @@ -0,0 +1,33 @@ +This package was debianized by Mark Purcell on +Wed, 2 Jul 2003 20:23:13 +1000. + +It was downloaded from htp://ftp.digum.com/pub/libpri + +Copyright Holder: + + * Copyright (C) 2001, Linux Support Services, Inc. + * Copyright (C) 2001-2005, Digium + +Additionally, this package contains changes ("bristuff patch") +in debian/patches/bristuff.dpatch which are + * Copyright (C) 2003-2006 Junghanns.NET GmbH + +License: + + This package is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This package is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this package; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +On Debian systems, the complete text of the GNU General +Public License can be found in `/usr/share/common-licenses/GPL-2'. + --- libpri-1.4.3.orig/debian/control +++ libpri-1.4.3/debian/control @@ -0,0 +1,30 @@ +Source: libpri +Priority: optional +Section: libs +Maintainer: Debian VoIP Team +Uploaders: Kilian Krause , Mark Purcell , Tzafrir Cohen , Faidon Liambotis +Build-Depends: debhelper (>> 4.0.0), dpatch +Standards-Version: 3.7.3 +Homepage: http://www.asterisk.org/ +Vcs-Svn: svn://svn.debian.org/pkg-voip/libpri/trunk/ +Vcs-Browser: http://svn.debian.org/wsvn/pkg-voip/libpri/?op=log + +Package: libpri-dev +Section: libdevel +Architecture: any +Depends: libpri1.0 (= ${binary:Version}) +Description: Primary Rate ISDN specification development files + Development files for the C implementation of the Primary Rate ISDN + specification. + +Package: libpri1.0 +Section: libs +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends} +Conflicts: libpri1.2 (<< 1.4.0-3) +Replaces: libpri1.2 (<< 1.4.0-3) +Description: Primary Rate ISDN specification library + C implementation of the Primary Rate ISDN specification. It was + 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 --- libpri-1.4.3.orig/debian/libpri-dev.dirs +++ libpri-1.4.3/debian/libpri-dev.dirs @@ -0,0 +1,2 @@ +usr/lib +usr/include