--- libpri-1.2.3.orig/debian/patches/bristuff.dpatch +++ libpri-1.2.3/debian/patches/bristuff.dpatch @@ -0,0 +1,6373 @@ +#! /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 0.3.0-PRE-1p +## DP: +## DP: newer versions: replace the contets of the patch file literally. +## DP: The remove Makefile and the strange changes this libpri.patch makes to +## DP: copyright statements. + +@DPATCH@ +diff -urNad libpri-1.2.3~/README libpri-1.2.3/README +--- libpri-1.2.3~/README 2006-02-16 04:59:38.000000000 +1100 ++++ libpri-1.2.3/README 2006-06-14 12:09:23.000000000 +1000 +@@ -1,6 +1,7 @@ + libpri: An implementation of Primary Rate ISDN + + Written by Mark Spencer ++Modified for BRI support by Klaus-Peter Junghanns + + What is libpri? + =============== +@@ -9,6 +10,7 @@ + based on the Bellcore specification SR-NWT-002343 for National ISDN. As of + May 12, 2001, it has been tested work with NI-2, Nortel DMS-100, and + Lucent 5E Custom protocols on switches from Nortel and Lucent. ++The BRI and euroISDN modifications are based on ETS 300 102-1. + + What is the license for libpri? + =============================== +@@ -22,9 +24,8 @@ + or the GPL of libpri. + + If you wish to use libpri in an application for which the GPL is not +-appropriate (e.g. a proprietary embedded system), licenses for libpri +-under more flexible terms can be readily obtained through Digium, Inc. +-at reasonable cost. ++appropriate (e.g. a proprietary embedded system), then you have to use ++a non-standard compliant version without BRI support. + + + How do I report bugs or contribute? +diff -urNad libpri-1.2.3~/TODO libpri-1.2.3/TODO +--- libpri-1.2.3~/TODO 2005-11-30 05:39:18.000000000 +1100 ++++ libpri-1.2.3/TODO 2006-06-14 12:09:23.000000000 +1000 +@@ -2,9 +2,7 @@ + -- D-Channel Backup + -- Test against 4e + +-Q.921: +--- Support unnumbered information frames +- + Q.931: +--- Locking Shift IE +--- Implement the 11 missing Q.931 timers ++-- Locking Shift IE (you did that already, didnt you??) ++-- Implement the 10 missing Q.931 timers ++-- more facilities +diff -urNad libpri-1.2.3~/libpri.h libpri-1.2.3/libpri.h +--- libpri-1.2.3~/libpri.h 2006-04-28 02:08:39.000000000 +1000 ++++ libpri-1.2.3/libpri.h 2006-06-14 12:09:23.000000000 +1000 +@@ -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 +@@ -250,11 +262,13 @@ + #define PRI_NSF_ATT_MULTIQUEST 0xF0 + #define PRI_NSF_CALL_REDIRECTION_SERVICE 0xF7 + ++typedef struct q921_call q921_call; + typedef struct q931_call q931_call; + + typedef struct pri_event_generic { + /* Events with no additional information fall in this category */ + int e; ++ int tei; + } pri_event_generic; + + typedef struct pri_event_error { +@@ -273,18 +287,19 @@ + int cref; + int progress; + int progressmask; +- q931_call *call; + char useruserinfo[260]; /* User->User info */ ++ q931_call *call; + } pri_event_ringing; + + typedef struct pri_event_answer { + int e; + int channel; ++ int tei; /* belongs to this tei */ + int cref; + int progress; + int progressmask; +- q931_call *call; + char useruserinfo[260]; /* User->User info */ ++ q931_call *call; + } pri_event_answer; + + typedef struct pri_event_facname { +@@ -302,32 +317,37 @@ + 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 { +@@ -335,6 +355,8 @@ + int channel; /* Channel requested */ + int cause; + int cref; ++ int tei; ++ int inband_progress; + q931_call *call; /* Opaque call pointer */ + long aoc_units; /* Advise of Charge number of charged units */ + char useruserinfo[260]; /* User->User info */ +@@ -375,20 +397,80 @@ + char digits[64]; + } pri_event_keypad_digit; + ++typedef struct pri_event_hold_req { ++ int e; ++ int channel; ++ int cref; ++ int tei; ++ q931_call *call; ++} pri_event_hold_req; ++ ++/* euroisdn faciltiy fun */ ++typedef struct pri_event_facility_req { ++ int e; ++ int channel; ++ int cref; ++ int tei; ++ int operation; ++ char forwardnum[256]; /* Redirection destination */ ++ q931_call *call; ++} pri_event_facility_req; ++ ++typedef struct pri_event_retrieve_req { ++ int e; ++ int channel; ++ int cref; ++ int tei; ++ q931_call *call; ++} pri_event_retrieve_req; ++ ++typedef struct pri_event_suspend_req { ++ int e; ++ int channel; ++ int cref; ++ int tei; ++ q931_call *call; ++ char callid[10]; ++} pri_event_suspend_req; ++ ++typedef struct pri_event_resume_req { ++ int e; ++ int channel; ++ int cref; ++ int tei; ++ q931_call *call; ++ char callid[10]; ++} pri_event_resume_req; ++ ++typedef struct pri_event_display { ++ int e; ++ int channel; ++ int cref; ++ q931_call *call; ++ char text[256]; ++} pri_event_display; ++ ++ + typedef union { + int e; + pri_event_generic gen; /* Generic view */ + pri_event_restart restart; /* Restart view */ + pri_event_error err; /* Error view */ + pri_event_facname facname; /* Caller*ID Name on Facility */ ++ pri_event_facility_req facility; /* sservices */ + pri_event_ring ring; /* Ring */ + pri_event_hangup hangup; /* Hang up */ + pri_event_ringing ringing; /* Ringing */ +- pri_event_ringing answer; /* Answer */ ++ pri_event_answer answer; /* Answer */ + pri_event_restart_ack restartack; /* Restart Acknowledge */ + pri_event_proceeding proceeding; /* Call proceeding & Progress */ + pri_event_setup_ack setup_ack; /* SETUP_ACKNOWLEDGE structure */ + pri_event_notify notify; /* Notification */ ++ pri_event_hold_req hold_req; ++ pri_event_retrieve_req retrieve_req; ++ pri_event_suspend_req suspend_req; ++ pri_event_resume_req resume_req; ++ pri_event_display display; + pri_event_keypad_digit digit; /* Digits that come during a call */ + } pri_event; + +@@ -403,7 +485,9 @@ + channel operating in HDLC mode with FCS computed by the fd's driver. Also it + must be NON-BLOCKING! Frames received on the fd should include FCS. Nodetype + must be one of PRI_NETWORK or PRI_CPE. switchtype should be PRI_SWITCH_* */ +-extern struct pri *pri_new(int fd, int nodetype, int switchtype); ++extern struct pri *pri_new(int fd, int nodetype, int switchtype, int span); ++ ++extern void pri_shutdown(struct pri *pri); + + /* Create D-channel just as above with user defined I/O callbacks and data */ + extern struct pri *pri_new_cb(int fd, int nodetype, int switchtype, pri_io_cb io_read, pri_io_cb io_write, void *userdata); +@@ -427,6 +511,9 @@ + /* Enable transmission support of Facility IEs on the pri */ + extern void pri_facility_enable(struct pri *pri); + ++/* Set file descriptor for debugging to a file */ ++extern void pri_set_debug_fd(struct pri *pri, int fd); ++ + /* Run PRI on the given D-channel, taking care of any events that + need to be handled. If block is set, it will block until an event + occurs which needs to be handled */ +@@ -463,6 +550,12 @@ + /* Send a digit in overlap mode */ + extern int pri_information(struct pri *pri, q931_call *call, char digit); + ++/* Send a INFO msg with display ie */ ++extern int pri_information_display(struct pri *pri, q931_call *call, char *display); ++ ++/* add a display ie to a call, so it can be sent with the next message */ ++extern int pri_add_display(struct pri *pri, q931_call *call, char *display); ++ + /* Answer the incomplete(call without called number) call on the given channel. + Set non-isdn to non-zero if you are not connecting to ISDN equipment */ + extern int pri_need_more_info(struct pri *pri, q931_call *call, int channel, int nonisdn); +@@ -471,6 +564,35 @@ + Set non-isdn to non-zero if you are not connecting to ISDN equipment */ + extern int pri_answer(struct pri *pri, q931_call *call, int channel, int nonisdn); + ++extern int pri_deflect(struct pri *pri, q931_call *call, char *destination); ++ ++/* Ack a HOLD_REQ */ ++extern int pri_hold_acknowledge(struct pri *pri, q931_call *call); ++ ++/* Reject a HOLD_REQ */ ++extern int pri_hold_reject(struct pri *pri, q931_call *call); ++ ++/* Ack a RETRIEVE_REQ */ ++extern int pri_retrieve_acknowledge(struct pri *pri, q931_call *call, int channel); ++ ++/* Reject a RETRIEVE_REQ */ ++extern int pri_retrieve_reject(struct pri *pri, q931_call *call); ++ ++/* Ack a SUSPEND_REQ */ ++extern int pri_suspend_acknowledge(struct pri *pri, q931_call *call, char *display); ++ ++/* Reject a SUSPEND_REQ */ ++extern int pri_suspend_reject(struct pri *pri, q931_call *call, char *display); ++ ++/* Reject a RESUME_REQ */ ++extern int pri_resume_reject(struct pri *pri, q931_call *call, char *display); ++ ++/* Ack a RESUME_REQ */ ++extern int pri_resume_acknowledge(struct pri *pri, q931_call *call, int channel, char *display); ++ ++/* Send a Facility Message */ ++extern int pri_facility(struct pri *pri, q931_call *call, int operation, char *arguments); ++ + /* Set CRV reference for GR-303 calls */ + + +@@ -479,14 +601,14 @@ + + /* 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); +@@ -519,14 +641,13 @@ + 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); + #define PRI_USER_USER_TX + /* Set the user user field. Warning! don't send binary data accross this field */ + extern void pri_sr_set_useruser(struct pri_sr *sr, char *userchars); +- + extern void pri_call_set_useruser(q931_call *sr, char *userchars); + + extern int pri_setup(struct pri *pri, q931_call *call, struct pri_sr *req); +@@ -547,8 +668,8 @@ + + /* Override message and error stuff */ + #define PRI_NEW_SET_API +-extern void pri_set_message(void (*__pri_error)(struct pri *pri, char *)); +-extern void pri_set_error(void (*__pri_error)(struct pri *pri, char *)); ++extern void pri_set_message(void (*__pri_error)(char *, int span)); ++extern void pri_set_error(void (*__pri_error)(char *, int span)); + + /* Set overlap mode */ + #define PRI_SET_OVERLAPDIAL +diff -urNad libpri-1.2.3~/pri.c libpri-1.2.3/pri.c +--- libpri-1.2.3~/pri.c 2005-11-30 05:39:18.000000000 +1100 ++++ libpri-1.2.3/pri.c 2006-06-14 12:09:23.000000000 +1000 +@@ -3,22 +3,12 @@ + * + * 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 @@ + 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 @@ + 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 @@ + 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 @@ + 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 @@ + 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 @@ + } + /* 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 @@ + { + /* 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 @@ + 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 @@ + return; + } + ++void pri_set_debug_fd(struct pri *pri, int fd) ++{ ++ if (!pri) ++ return; ++ pri->debugfd = fd; ++ if (pri->subchannel) ++ pri_set_debug_fd(pri->subchannel, fd); ++} ++ + int pri_acknowledge(struct pri *pri, q931_call *call, int channel, int info) + { + if (!pri || !call) +@@ -478,6 +488,21 @@ + return q931_notify(pri, call, channel, info); + } + ++int pri_information_display(struct pri *pri, q931_call *call, char *display) ++{ ++ if (!pri || !call) ++ return -1; ++ return q931_information_display(pri, call, display); ++} ++ ++int pri_add_display(struct pri *pri, q931_call *call, char *display) ++{ ++ if (!pri || !call) ++ return -1; ++ return q931_add_display(pri, call, display); ++} ++ ++ + void pri_destroycall(struct pri *pri, q931_call *call) + { + if (pri && call) +@@ -499,6 +524,76 @@ + return q931_connect(pri, call, channel, nonisdn); + } + ++int pri_hold_acknowledge(struct pri *pri, q931_call *call) ++{ ++ if (!pri || !call) ++ return -1; ++ return q931_hold_acknowledge(pri, call); ++} ++ ++int pri_hold_reject(struct pri *pri, q931_call *call) ++{ ++ if (!pri || !call) ++ return -1; ++ return q931_hold_reject(pri, call); ++} ++ ++int pri_retrieve_acknowledge(struct pri *pri, q931_call *call, int channel) ++{ ++ if (!pri || !call) ++ return -1; ++ return q931_retrieve_acknowledge(pri, call, channel); ++} ++ ++int pri_retrieve_reject(struct pri *pri, q931_call *call) ++{ ++ if (!pri || !call) ++ return -1; ++ return q931_retrieve_reject(pri, call); ++} ++ ++int pri_suspend_acknowledge(struct pri *pri, q931_call *call, char *display) ++{ ++ if (!pri || !call) ++ return -1; ++ return q931_suspend_acknowledge(pri, call, display); ++} ++ ++int pri_suspend_reject(struct pri *pri, q931_call *call, char *display) ++{ ++ if (!pri || !call) ++ return -1; ++ return q931_suspend_reject(pri, call, display); ++} ++ ++int pri_resume_reject(struct pri *pri, q931_call *call, char *display) ++{ ++ if (!pri || !call) ++ return -1; ++ return q931_resume_reject(pri, call, display); ++} ++ ++int pri_resume_acknowledge(struct pri *pri, q931_call *call, int channel, char *display) ++{ ++ if (!pri || !call) ++ return -1; ++ return q931_resume_acknowledge(pri, call, channel, display); ++} ++ ++int pri_facility(struct pri *pri, q931_call *call, int operation, char *arguments) ++{ ++ if (!pri || !call) ++ return -1; ++// return q931_facility(pri, call, operation, arguments); ++ return q931_facility(pri, call); ++} ++ ++int pri_deflect(struct pri *pri, q931_call *call, char *destination) ++{ ++ add_call_deflection_facility_ie(pri, call, destination); ++ return q931_facility(pri, call); ++} ++ + #if 0 + /* deprecated routines, use pri_hangup */ + int pri_release(struct pri *pri, q931_call *call, int cause) +@@ -541,14 +636,35 @@ + return 0; + } + +-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) +@@ -688,15 +804,15 @@ + return q931_setup(pri, c, &req); + } + +-static void (*__pri_error)(struct pri *pri, char *stuff); +-static void (*__pri_message)(struct pri *pri, char *stuff); ++static void (*__pri_error)(char *stuff,int span); ++static void (*__pri_message)(char *stuff,int span); + +-void pri_set_message(void (*func)(struct pri *pri, char *stuff)) ++void pri_set_message(void (*func)(char *stuff,int span)) + { + __pri_message = func; + } + +-void pri_set_error(void (*func)(struct pri *pri, char *stuff)) ++void pri_set_error(void (*func)(char *stuff,int span)) + { + __pri_error = func; + } +@@ -708,10 +824,14 @@ + va_start(ap, fmt); + vsnprintf(tmp, sizeof(tmp), fmt, ap); + va_end(ap); +- if (__pri_message) +- __pri_message(pri, tmp); +- else +- fputs(tmp, stdout); ++ if (__pri_message && pri) { ++ if (pri->debugfd >= 0) ++ write(pri->debugfd, tmp, strlen(tmp)); ++ else ++ __pri_message(tmp, pri->span); ++ } else { ++ fputs(tmp, stdout); ++ } + } + + void pri_error(struct pri *pri, char *fmt, ...) +@@ -721,10 +841,14 @@ + va_start(ap, fmt); + vsnprintf(tmp, sizeof(tmp), fmt, ap); + va_end(ap); +- if (__pri_error) +- __pri_error(pri, tmp); +- else +- fputs(tmp, stderr); ++ if (__pri_error && pri) { ++ if (pri->debugfd >= 0) ++ write(pri->debugfd, tmp, strlen(tmp)); ++ else ++ __pri_error(tmp, pri->span); ++ } else { ++ fputs(tmp, stderr); ++ } + } + + /* Set overlap mode */ +@@ -765,11 +889,13 @@ + } + len += sprintf(buf + len, "Q921 Outstanding: %d\n", q921outstanding); + #endif +- len += sprintf(buf + len, "Window Length: %d/%d\n", pri->windowlen, pri->window); +- len += sprintf(buf + len, "Sentrej: %d\n", pri->sentrej); +- len += sprintf(buf + len, "SolicitFbit: %d\n", pri->solicitfbit); +- len += sprintf(buf + len, "Retrans: %d\n", pri->retrans); +- len += sprintf(buf + len, "Busy: %d\n", pri->busy); ++ if (pri->localtype != BRI_NETWORK_PTMP) { ++ len += sprintf(buf + len, "Window Length: %d/%d\n", pri->windowlen[0], pri->window[0]); ++ len += sprintf(buf + len, "Sentrej: %d\n", pri->sentrej[0]); ++ len += sprintf(buf + len, "SolicitFbit: %d\n", pri->solicitfbit[0]); ++ len += sprintf(buf + len, "Retrans: %d\n", pri->retrans[0]); ++ len += sprintf(buf + len, "Busy: %d\n", pri->busy[0]); ++ } + len += sprintf(buf + len, "Overlap Dial: %d\n", pri->overlapdial); + len += sprintf(buf + len, "T200 Timer: %d\n", pri->timers[PRI_TIMER_T200]); + len += sprintf(buf + len, "T203 Timer: %d\n", pri->timers[PRI_TIMER_T203]); +@@ -778,6 +904,7 @@ + len += sprintf(buf + len, "T313 Timer: %d\n", pri->timers[PRI_TIMER_T313]); + len += sprintf(buf + len, "N200 Counter: %d\n", pri->timers[PRI_TIMER_N200]); + ++ + return strdup(buf); + } + +@@ -819,10 +946,11 @@ + 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; + } + +@@ -851,3 +979,10 @@ + sr->redirectingreason = reason; + return 0; + } ++ ++void pri_shutdown(struct pri *pri) ++{ ++ if ((pri->localtype == BRI_NETWORK) || (pri->localtype == BRI_CPE) || (pri->localtype == BRI_CPE_PTMP)) { ++ q921_reset(pri, pri->tei, 1); ++ } ++} +diff -urNad libpri-1.2.3~/pri_facility.c libpri-1.2.3/pri_facility.c +--- libpri-1.2.3~/pri_facility.c 2006-02-14 10:06:02.000000000 +1100 ++++ libpri-1.2.3/pri_facility.c 2006-06-14 12:09:23.000000000 +1000 +@@ -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" +@@ -208,9 +199,9 @@ + if (datalen > buflen) { + /* Truncate */ + datalen = buflen; ++ memcpy(namebuf, comp->data, datalen); + } +- memcpy(namebuf, comp->data, datalen); +- return res + 2; ++ return res; + } + + int asn1_string_encode(unsigned char asn1_type, void *data, int len, int max_len, void *src, int src_len) +@@ -305,12 +296,55 @@ + 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; +@@ -375,11 +409,10 @@ + pri_message(pri, "!! Unknown Party number component received 0x%X\n", comp->type); + return -1; + } +- ASN1_FIXUP_LEN(comp, res); + NEXT_COMPONENT(comp, i); + if(i < len) + pri_message(pri, "!! not all information is handled from Address component\n"); +- return res + 2; ++ return res; + } + while (0); + +@@ -389,7 +422,6 @@ + static int rose_presented_number_unscreened_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value) + { + int i = 0; +- int size = 0; + struct rose_component *comp = NULL; + unsigned char *vdata = data; + +@@ -404,9 +436,7 @@ + switch(comp->type) { + case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0): /* [0] presentationAllowedNumber */ + value->pres = PRES_ALLOWED_USER_NUMBER_NOT_SCREENED; +- size = rose_address_decode(pri, call, comp->data, comp->len, value); +- ASN1_FIXUP_LEN(comp, size); +- return size + 2; ++ return rose_address_decode(pri, call, comp->data, comp->len, value) + 2; + case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1): /* [1] IMPLICIT presentationRestricted */ + if (comp->len != 0) { /* must be NULL */ + pri_error(pri, "!! Invalid PresentationRestricted component received (len != 0)\n"); +@@ -423,9 +453,7 @@ + return 2; + case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3): /* [3] presentationRestrictedNumber */ + value->pres = PRES_PROHIB_USER_NUMBER_NOT_SCREENED; +- size = rose_address_decode(pri, call, comp->data, comp->len, value) + 2; +- ASN1_FIXUP_LEN(comp, size); +- return size + 2; ++ return rose_address_decode(pri, call, comp->data, comp->len, value) + 2; + default: + pri_message(pri, "Invalid PresentedNumberUnscreened component 0x%X\n", comp->type); + } +@@ -436,7 +464,7 @@ + return -1; + } + +-static int rose_diverting_leg_information2_decode(struct pri *pri, q931_call *call, struct rose_component *sequence, int len) ++static int rose_diverting_leg_information2_decode(struct pri *pri, q931_call *call, unsigned char *data, int len) + { + int i = 0; + int diversion_counter; +@@ -445,21 +473,9 @@ + struct addressingdataelements_presentednumberunscreened divertingnr; + struct addressingdataelements_presentednumberunscreened originalcallednr; + struct rose_component *comp = NULL; +- unsigned char *vdata = sequence->data; ++ unsigned char *vdata = data; + int res = 0; + +- /* Data checks */ +- if (sequence->type != (ASN1_CONSTRUCTOR | ASN1_SEQUENCE)) { /* Constructed Sequence */ +- pri_message(pri, "Invalid DivertingLegInformation2Type argument\n"); +- return -1; +- } +- +- if (sequence->len == ASN1_LEN_INDEF) { +- len -= 4; /* For the 2 extra characters at the end +- * and two characters of header */ +- } else +- len -= 2; +- + do { + /* diversionCounter stuff */ + GET_COMPONENT(comp, i, vdata, len); +@@ -477,20 +493,18 @@ + + if(pri->debug & PRI_DEBUG_APDU) + pri_message(pri, " Redirection reason: %d, total diversions: %d\n", diversion_reason, diversion_counter); +- pri_message(NULL, "Length of message is %d\n", len); + + for(; i < len; NEXT_COMPONENT(comp, i)) { + GET_COMPONENT(comp, i, vdata, len); +- switch(comp->type) { +- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0): ++ switch(comp->type & ASN1_TYPE_MASK) { ++ case ASN1_TAG_0: + call->origredirectingreason = redirectingreason_for_q931(pri, comp->data[0]); + if (pri->debug & PRI_DEBUG_APDU) + pri_message(pri, " Received reason for original redirection %d\n", call->origredirectingreason); + break; +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1): ++ case ASN1_TAG_1: /* divertingnr: presentednumberunscreened */ + res = rose_presented_number_unscreened_decode(pri, call, comp->data, comp->len, &divertingnr); + /* TODO: Fix indefinite length form hacks */ +- ASN1_FIXUP_LEN(comp, res); + comp->len = res; + if (res < 0) + return -1; +@@ -499,43 +513,33 @@ + pri_message(pri, " ton = %d, pres = %d, npi = %d\n", divertingnr.ton, divertingnr.pres, divertingnr.npi); + } + break; +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_2): ++ case ASN1_TAG_2: /* originalCalledNr: PresentedNumberUnscreened */ + res = rose_presented_number_unscreened_decode(pri, call, comp->data, comp->len, &originalcallednr); + if (res < 0) + return -1; +- ASN1_FIXUP_LEN(comp, res); + comp->len = res; + if (pri->debug & PRI_DEBUG_APDU) { + pri_message(pri, " Received originalcallednr '%s'\n", originalcallednr.partyaddress); + pri_message(pri, " ton = %d, pres = %d, npi = %d\n", originalcallednr.ton, originalcallednr.pres, originalcallednr.npi); + } + break; +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3): +- res = asn1_name_decode(comp->data, comp->len, redirectingname, sizeof(redirectingname)); +- if (res < 0) +- return -1; +- ASN1_FIXUP_LEN(comp, res); +- comp->len = res; ++ case ASN1_TAG_3: ++ comp->len = asn1_name_decode(comp->data, comp->len, redirectingname, sizeof(redirectingname)); + if (pri->debug & PRI_DEBUG_APDU) + pri_message(pri, " Received RedirectingName '%s'\n", redirectingname); + break; +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_4): +- res = asn1_name_decode(comp->data, comp->len, origcalledname, sizeof(origcalledname)); +- if (res < 0) +- return -1; +- ASN1_FIXUP_LEN(comp, res); +- comp->len = res; ++ case ASN1_TAG_4: ++ comp->len = asn1_name_decode(comp->data, comp->len, origcalledname, sizeof(origcalledname)); + if (pri->debug & PRI_DEBUG_APDU) + pri_message(pri, " Received Originally Called Name '%s'\n", origcalledname); + break; + default: +- if (comp->type == 0 && comp->len == 0) { +- break; /* Found termination characters */ +- } + pri_message(pri, "!! Invalid DivertingLegInformation2 component received 0x%X\n", comp->type); + return -1; + } + } ++ if (i < len) ++ return -1; /* Aborted before */ + + if (divertingnr.pres >= 0) { + call->redirectingplan = divertingnr.npi; +@@ -548,15 +552,19 @@ + 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; +@@ -694,6 +702,64 @@ + return 0; + } + ++/* Call deflection */ ++int add_call_deflection_facility_ie(struct pri *pri, q931_call *c, char *destination) { ++ int i = 0, j, compsp = 0; ++ struct rose_component *comp, *compstk[10]; ++ unsigned char buffer[256]; ++ ++ buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_ROSE); ++ /* invoke */ ++ ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri)); ++ ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, ROSE_CALLDEFLECTION); ++ ++ /* Argument sequence */ ++ ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ /* arg.Address */ ++ ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ ++#ifndef CD_UNLIKE_IN_CAPI ++ /* arg.address.PartyNumber */ ++ ++ ++ j = asn1_string_encode((ASN1_CONTEXT_SPECIFIC|ASN1_TAG_0), &buffer[i], sizeof(buffer)-i, 20, destination, strlen(destination)); ++ if (j<0) return -1; ++ i += j; ++#else ++ /* using PublicPartyNumber instead */ ++ ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE | ASN1_CONTEXT_SPECIFIC| ASN1_TAG_1), buffer, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ /* ToN: unknown */ ++ ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 0); ++ j = asn1_string_encode(0x80, &buffer[i], sizeof(buffer)-i, 20, destination, strlen(destination)); ++ if(j<0) return -1; ++ i += j; ++ /* close PublicPartyNumber */ ++ ASN1_FIXUP(compstk, compsp, buffer, i); ++#endif ++ ++ /* close Address */ ++ ASN1_FIXUP(compstk, compsp, buffer, i); ++ ++ /* add boolean */ ++ ASN1_ADD_BYTECOMP(comp, ASN1_BOOLEAN, buffer, i, 0); ++ ++ /* Fix length of stacked components */ ++ while(compsp > 0) { ++ ASN1_FIXUP(compstk, compsp, buffer, i); ++ } ++ if (pri_call_apdu_queue(c, Q931_FACILITY, buffer, i, NULL, NULL)) ++ return -1; ++ ++ return 0; ++} ++ + /* Sending callername information functions */ + static int add_callername_facility_ies(struct pri *pri, q931_call *c, int cpe) + { +@@ -936,7 +1002,7 @@ + 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 { +@@ -1054,7 +1120,7 @@ + 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; +@@ -1108,18 +1174,20 @@ + 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 ADPU 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; +@@ -1152,13 +1220,15 @@ + NEXT_COMPONENT(comp, i); + + /* No argument - return with error */ +- if (i >= len) ++ if ((i >= len) && (operation_tag != ROSE_EXPLICIT_CALL_TRANSFER)) + return -1; + +- /* Arguement Tag */ +- GET_COMPONENT(comp, i, vdata, len); +- if (!comp->type) +- return -1; ++ if (operation_tag != ROSE_EXPLICIT_CALL_TRANSFER) { ++ /* Arguement Tag */ ++ GET_COMPONENT(comp, i, vdata, len); ++ if (!comp->type) ++ return -1; ++ } + + if (pri->debug & PRI_DEBUG_APDU) + pri_message(pri, " [ Handling operation %d ]\n", operation_tag); +@@ -1182,7 +1252,11 @@ + case ROSE_DIVERTING_LEG_INFORMATION2: + if (pri->debug & PRI_DEBUG_APDU) + pri_message(pri, " Handle DivertingLegInformation2\n"); +- return rose_diverting_leg_information2_decode(pri, call, comp, len-i); ++ if (comp->type != (ASN1_CONSTRUCTOR | ASN1_SEQUENCE)) { /* Constructed Sequence */ ++ pri_message(pri, "Invalid DivertingLegInformation2Type argument\n"); ++ return -1; ++ } ++ return rose_diverting_leg_information2_decode(pri, call, comp->data, comp->len); + case ROSE_AOC_NO_CHARGING_INFO_AVAILABLE: + if (pri->debug & PRI_DEBUG_APDU) { + pri_message(pri, "ROSE %i: AOC No Charging Info Available - not handled!", operation_tag); +@@ -1210,6 +1284,7 @@ + } + 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); +@@ -1224,7 +1299,7 @@ + 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: +@@ -1233,6 +1308,22 @@ + 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); +diff -urNad libpri-1.2.3~/pri_facility.h libpri-1.2.3/pri_facility.h +--- libpri-1.2.3~/pri_facility.h 2005-11-30 05:39:18.000000000 +1100 ++++ libpri-1.2.3/pri_facility.h 2006-06-14 12:09:23.000000000 +1000 +@@ -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,15 @@ + #define ROSE_AOC_IDENTIFICATION_OF_CHARGE 37 + /* Q.SIG operations */ + #define SS_CNID_CALLINGNAME 0 +-#define SS_DIVERTING_LEG_INFORMATION2 21 ++#define SS_DIVERTING_LEG_INFORMATION2 22 + #define SS_MWI_ACTIVATE 80 + #define SS_MWI_DEACTIVATE 81 + #define SS_MWI_INTERROGATE 82 + ++#define ROSE_CALLDEFLECTION 0x0D ++#define ROSE_EXPLICIT_CALL_TRANSFER 0x06 ++#define ROSE_MALICIOUS_CID 0x31 ++ + /* ROSE definitions and data structures */ + #define INVOKE_IDENTIFIER 0x02 + #define INVOKE_LINKED_IDENTIFIER 0x80 +@@ -180,12 +184,6 @@ + (variable) = ((variable) << 8) | (component)->data[comp_idx]; \ + } while (0) + +-#define ASN1_FIXUP_LEN(component, size) \ +- do { \ +- if ((component)->len == ASN1_LEN_INDEF) \ +- size += 2; \ +- } while (0) +- + #define ASN1_ADD_SIMPLE(component, comptype, ptr, idx) \ + do { \ + (component) = (struct rose_component *)&((ptr)[(idx)]); \ +@@ -260,4 +258,8 @@ + /* Adds the "standard" ADPUs to a call */ + extern int pri_call_add_standard_apdus(struct pri *pri, q931_call *call); + ++extern int add_call_deflection_facility_ie(struct pri *pri, q931_call *c, char *destination); ++ ++extern int aoc_aoce_charging_unit_encode(struct pri *pri, q931_call *c, long chargedunits, int send_facility_message); ++ + #endif /* _PRI_FACILITY_H */ +diff -urNad libpri-1.2.3~/pri_internal.h libpri-1.2.3/pri_internal.h +--- libpri-1.2.3~/pri_internal.h 2005-11-30 05:39:18.000000000 +1100 ++++ libpri-1.2.3/pri_internal.h 2006-06-14 12:09:23.000000000 +1000 +@@ -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 +@@ -30,7 +32,10 @@ + struct pri_sched { + struct timeval when; + void (*callback)(void *data); ++ void (*callback2)(void *data, int); + void *data; ++ char hasdata2; ++ int data2; + }; + + struct q921_frame; +@@ -38,8 +43,15 @@ + enum q931_mode; + + /* No more than 128 scheduled events */ ++/* XXX is this sufficient for nfs ??? */ + #define MAX_SCHED 128 + ++/* this can be freely configured to support more devices .... ok, 63 would be max! */ ++#define Q921_MAX_TEIS 16 ++ ++/* dynamically allocated TEIs start here */ ++#define Q921_TEI_BASE 64 ++ + #define MAX_TIMERS 32 + + struct pri { +@@ -51,6 +63,7 @@ + struct pri *master; /* Master channel if appropriate */ + struct pri_sched pri_sched[MAX_SCHED]; /* Scheduled events */ + int debug; /* Debug stuff */ ++ int debugfd; + int state; /* State of D-channel */ + int switchtype; /* Switch type */ + int nsf; /* Network-Specific Facility (if any) */ +@@ -62,25 +75,42 @@ + 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]; + +@@ -89,8 +119,8 @@ + int schedev; + pri_event ev; /* Static event thingy */ + +- /* Q.921 Re-transmission queue */ +- struct q921_frame *txqueue; ++ /* Q.921 (Re)transmission queue */ ++ struct q921_frame *txqueue[Q921_MAX_TEIS]; + + /* Q.931 calls */ + q931_call **callpool; +@@ -109,6 +139,9 @@ + + unsigned char last_invoke; /* Last ROSE invoke ID */ + unsigned char sendfacility; ++ ++ int span; /* our fellow pri lives on this zaptel span */ ++ + }; + + struct pri_sr { +@@ -118,6 +151,7 @@ + int nonisdn; + char *caller; + int callerplan; ++ int callerplanani; + char *callername; + int callerpres; + char *called; +@@ -130,6 +164,7 @@ + int redirectingreason; + int justsignalling; + char *useruserinfo; ++ char *llc; + }; + + /* Internal switch types */ +@@ -167,8 +202,13 @@ + + 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) */ + +@@ -202,15 +242,18 @@ + int callerplan; + int callerplanani; + int callerpres; /* Caller presentation */ +- char callerani[256]; /* Caller */ +- char callernum[256]; ++ int callerplanuser; ++ int callerpresuser; /* Caller presentation */ ++ char callernum[256]; /* Calling Number (network provided) */ ++ char callerani[256]; /* Calling Number, (user provided) */ ++ + char callername[256]; + +- char digitbuf[64]; /* Buffer for digits that come in KEYPAD_FACILITY */ ++ char digitbuf[64]; /* Buffer for digits that come in KEYPAD_FACILITY */ + + int ani2; /* ANI II */ + +- int calledplan; ++ int calledplan; + int nonisdn; + char callednum[256]; /* Called Number */ + int complete; /* no more digits coming */ +@@ -225,23 +268,36 @@ + char redirectingnum[256]; /* Number of redirecting party */ + char redirectingname[256]; /* Name of redirecting party */ + ++ int t303timer; ++ int t303running; ++ + /* Filled in cases of multiple diversions */ + int origcalledplan; + int origcalledpres; +- int origredirectingreason; /* Original reason for redirect (in cases of multiple redirects) */ ++ int origredirectingreason; /* Original reason for redirect (in cases of multiple redirects) */ + char origcalledname[256]; /* Original name of person being called */ +- char origcallednum[256]; /* Orignal number of person being called */ ++ char origcallednum[256]; /* Orignal number of person being called */ + +- int useruserprotocoldisc; ++ 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 */ + ++ char llc[16]; /* low layer compatibility */ + struct apdu_event *apdus; /* APDU queue for call */ + }; + + extern int pri_schedule_event(struct pri *pri, int ms, void (*function)(void *data), void *data); ++extern int pri_schedule_event2(struct pri *pri, int ms, void (*function)(void *data, int data2), void *data, int data2); + + extern pri_event *pri_schedule_run(struct pri *pri); + +@@ -250,7 +306,7 @@ + extern pri_event *pri_mkerror(struct pri *pri, char *errstr); + + extern void pri_message(struct pri *pri, char *fmt, ...); +- ++ + extern void pri_error(struct pri *pri, char *fmt, ...); + + void libpri_copy_string(char *dst, const char *src, size_t size); +diff -urNad libpri-1.2.3~/pri_q921.h libpri-1.2.3/pri_q921.h +--- libpri-1.2.3~/pri_q921.h 2005-11-30 05:39:18.000000000 +1100 ++++ libpri-1.2.3/pri_q921.h 2006-06-14 12:09:23.000000000 +1000 +@@ -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 @@ + extern void q921_dump(struct pri *pri, q921_h *h, int len, int showraw, int txrx); + + /* Bring up the D-channel */ +-extern void q921_start(struct pri *pri, int now); ++extern void q921_start(struct pri *pri, int now, int tei); + +-extern void q921_reset(struct pri *pri); ++extern void q921_reset(struct pri *pri, int tei, int discard); + + extern pri_event *q921_receive(struct pri *pri, q921_h *h, int len); + +-extern int q921_transmit_iframe(struct pri *pri, void *buf, int len, int cr); ++extern int q921_transmit_uframe(struct pri *pri, void *buf, int len, int cr, int tei); ++ ++extern int q921_transmit_iframe(struct pri *pri, void *buf, int len, int cr, int tei); + + #endif +diff -urNad libpri-1.2.3~/pri_q931.h libpri-1.2.3/pri_q931.h +--- libpri-1.2.3~/pri_q931.h 2005-11-30 05:39:18.000000000 +1100 ++++ libpri-1.2.3/pri_q931.h 2006-06-14 12:09:23.000000000 +1000 +@@ -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 @@ + #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 @@ + #define Q931_IE_USER_USER 0x7E + #define Q931_IE_ESCAPE_FOR_EXT 0x7F + ++#define Q931_IE_SPECIAL 0x02 ++ + + /* Call state stuff */ + #define Q931_CALL_STATE_NULL 0 +@@ -243,7 +251,7 @@ + /* EuroISDN */ + #define Q931_SENDING_COMPLETE 0xa1 + +-extern int q931_receive(struct pri *pri, q931_h *h, int len); ++extern int q931_receive(struct pri *pri, q931_h *h, int len, int tei); + + extern int q931_alerting(struct pri *pri, q931_call *call, int channel, int info); + +@@ -257,6 +265,10 @@ + + extern int q931_information(struct pri *pri, q931_call *call, char digit); + ++extern int q931_information_display(struct pri *pri, q931_call *call, char *display); ++ ++extern int q931_add_display(struct pri *pri, q931_call *call, char *display); ++ + extern int q931_connect(struct pri *pri, q931_call *call, int channel, int nonisdn); + + extern int q931_release(struct pri *pri, q931_call *call, int cause); +@@ -265,6 +277,10 @@ + + extern int q931_hangup(struct pri *pri, q931_call *call, int cause); + ++extern int q921_hangup(struct pri *pri, q931_call *c, int tei); ++ ++extern int q921_handle_hangup(struct pri *pri, q931_call *c, int tei); ++ + extern int q931_restart(struct pri *pri, int channel); + + extern int q931_facility(struct pri *pri, q931_call *call); +@@ -279,5 +295,23 @@ + extern void q931_dump(struct pri *pri, q931_h *h, int len, int txrx); + + extern void __q931_destroycall(struct pri *pri, q931_call *c); ++ ++extern int q931_hold_acknowledge(struct pri *pri, q931_call *c); ++ ++extern int q931_hold_reject(struct pri *pri, q931_call *c); ++ ++extern int q931_retrieve_acknowledge(struct pri *pri, q931_call *c, int channel); + ++extern int q931_retrieve_reject(struct pri *pri, q931_call *c); ++ ++extern int q931_suspend_acknowledge(struct pri *pri, q931_call *c, char *display); ++ ++extern int q931_suspend_reject(struct pri *pri, q931_call *c, char *display); ++ ++extern int q931_resume_reject(struct pri *pri, q931_call *c, char *display); ++ ++extern int q931_resume_acknowledge(struct pri *pri, q931_call *c, int channel, char *display); ++ ++//extern int q931_facility(struct pri *pri, q931_call *c, int operation, char *arguments); ++ + #endif +diff -urNad libpri-1.2.3~/pri_timers.h libpri-1.2.3/pri_timers.h +--- libpri-1.2.3~/pri_timers.h 2005-11-30 05:39:18.000000000 +1100 ++++ libpri-1.2.3/pri_timers.h 2006-06-14 12:09:23.000000000 +1000 +@@ -27,17 +27,17 @@ + + /* -1 means we dont currently support the timer/counter */ + #define PRI_TIMERS_DEFAULT { 3, /* N200 */ \ +- -1, /* N201 */ \ +- -1, /* N202 */ \ ++ 260, /* N201 */ \ ++ 3, /* N202 */ \ + 7, /* K */ \ + 1000, /* T200 */ \ +- -1, /* T201 */ \ +- -1, /* T202 */ \ ++ 2000, /* T201 */ \ ++ 5000, /* T202 */ \ + 10000, /* T203 */ \ + -1, /* T300 */ \ + -1, /* T301 */ \ + -1, /* T302 */ \ +- -1, /* T303 */ \ ++ 4000, /* T303 */ \ + -1, /* T304 */ \ + 30000, /* T305 */ \ + -1, /* T306 */ \ +diff -urNad libpri-1.2.3~/pridump.c libpri-1.2.3/pridump.c +--- libpri-1.2.3~/pridump.c 2005-11-30 05:39:18.000000000 +1100 ++++ libpri-1.2.3/pridump.c 2006-06-14 12:09:23.000000000 +1000 +@@ -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 +diff -urNad libpri-1.2.3~/prisched.c libpri-1.2.3/prisched.c +--- libpri-1.2.3~/prisched.c 2005-11-30 05:39:18.000000000 +1100 ++++ libpri-1.2.3/prisched.c 2006-06-14 12:09:23.000000000 +1000 +@@ -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 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 @@ + } + 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 @@ + 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 @@ + + 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 @@ + if ((id >= MAX_SCHED) || (id < 0)) + pri_error(pri, "Asked to delete sched id %d???\n", id); + pri->pri_sched[id].callback = NULL; ++ pri->pri_sched[id].callback2 = NULL; + } ++ +diff -urNad libpri-1.2.3~/pritest.c libpri-1.2.3/pritest.c +--- libpri-1.2.3~/pritest.c 2005-11-30 05:39:18.000000000 +1100 ++++ libpri-1.2.3/pritest.c 2006-06-14 12:09:23.000000000 +1000 +@@ -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 +@@ -51,8 +51,8 @@ + #define PRI_DEF_NODETYPE PRI_CPE + #define PRI_DEF_SWITCHTYPE PRI_SWITCH_NI2 + +-#define MAX_CHAN 32 +-#define DCHANNEL_TIMESLOT 16 ++#define MAX_CHAN 3 ++#define DCHANNEL_TIMESLOT 3 + + + static int offset = 0; +@@ -60,7 +60,7 @@ + static void do_channel(ZAP *z) + { + /* This is the part that runs on a given channel */ +- zap_playf(z, "raw.ulaw", 0); ++ zap_playf(z, "raw.alaw", 0); + } + + struct pri_chan { +@@ -76,6 +76,14 @@ + return PRI_CPE; + if (!strcasecmp(node, "network")) + return PRI_NETWORK; ++ if (!strcasecmp(node, "bri_cpe_ptmp")) ++ return BRI_CPE_PTMP; ++ if (!strcasecmp(node, "bri_network_ptmp")) ++ return BRI_NETWORK_PTMP; ++ if (!strcasecmp(node, "bri_cpe")) ++ return BRI_CPE; ++ if (!strcasecmp(node, "bri_network")) ++ return BRI_NETWORK; + return -1; + } + +@@ -285,6 +293,10 @@ + } + + break; ++ case PRI_EVENT_HANGUP_REQ: ++ printf("-- Hanging up channel %d\n", e->hangup.channel); ++ hangup_channel(e->hangup.channel); ++ break; + default: + fprintf(stderr, "--!! Unknown PRI event %d\n", e->e); + } +diff -urNad libpri-1.2.3~/q921.c libpri-1.2.3/q921.c +--- libpri-1.2.3~/q921.c 2005-12-07 08:35:50.000000000 +1100 ++++ libpri-1.2.3/q921.c 2006-06-14 12:09:23.000000000 +1000 +@@ -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 +@@ -21,7 +23,7 @@ + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +- ++ + #include + #include + #include +@@ -50,19 +52,23 @@ + (hf).h.tei = (pri)->tei; \ + } while(0) + +-static void reschedule_t203(struct pri *pri); ++static void reschedule_t203(struct pri *pri, int tei); ++static void q921_flush_txqueue(struct pri *pri, int tei, int devnull); + +-static void q921_discard_retransmissions(struct pri *pri) ++static void q921_discard_retransmissions(struct pri *pri, int tei) + { + struct q921_frame *f, *p; +- f = pri->txqueue; ++ int teio = tei - Q921_TEI_BASE; ++ if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; } ++ ++ f = pri->txqueue[teio]; + while(f) { +- p = f; +- f = f->next; +- /* Free frame */ +- free(p); ++ p = f; ++ f = f->next; ++ /* Free frame */ ++ free(p); + } +- pri->txqueue = NULL; ++ pri->txqueue[teio] = NULL; + } + + static int q921_transmit(struct pri *pri, q921_h *h, int len) +@@ -88,11 +94,15 @@ + pri_error(pri, "Short write: %d/%d (%s)\n", res, len + 2, strerror(errno)); + return -1; + } +- reschedule_t203(pri); ++ if (pri->localtype == BRI_CPE_PTMP) { ++ reschedule_t203(pri, pri->tei); ++ } else if (h->h.tei != Q921_TEI_GROUP) { ++ reschedule_t203(pri, h->h.tei); ++ } + return 0; + } + +-static void q921_send_ua(struct pri *pri, int pfbit) ++static void q921_send_ua(struct pri *pri, int pfbit, int tei) + { + q921_h h; + Q921_INIT(pri, h); +@@ -100,6 +110,7 @@ + h.u.m2 = 0; /* M2 = 0 */ + h.u.p_f = pfbit; /* Final bit on */ + h.u.ft = Q921_FRAMETYPE_U; ++ h.h.tei = tei; + switch(pri->localtype) { + case PRI_NETWORK: + h.h.c_r = 0; +@@ -107,6 +118,19 @@ + case PRI_CPE: + h.h.c_r = 1; + break; ++ case BRI_NETWORK_PTMP: ++ h.h.c_r = 0; ++ break; ++ case BRI_CPE_PTMP: ++ h.h.tei = pri->tei; ++ h.h.c_r = 1; ++ break; ++ case BRI_NETWORK: ++ h.h.c_r = 0; ++ break; ++ case BRI_CPE: ++ h.h.c_r = 1; ++ break; + default: + pri_error(pri, "Don't know how to U/A on a type %d node\n", pri->localtype); + return; +@@ -116,18 +140,359 @@ + q921_transmit(pri, &h, 3); + } + +-static void q921_send_sabme_now(void *vpri); ++/* ++static void q921_send_disconnect(struct pri *pri, int pfbit, int tei) { ++ q921_h h; ++ Q921_INIT(pri, h); ++ h.u.m3 = 2; ++ h.u.m2 = 0; ++ h.u.p_f = pfbit; ++ h.u.ft = Q921_FRAMETYPE_U; ++ h.h.tei = tei; ++ switch(pri->localtype) { ++ case PRI_NETWORK: ++ h.h.c_r = 0; ++ break; ++ case PRI_CPE: ++ h.h.c_r = 1; ++ break; ++ case BRI_NETWORK_PTMP: ++ h.h.c_r = 0; ++ break; ++ case BRI_CPE_PTMP: ++ h.h.tei = pri->tei; ++ h.h.c_r = 1; ++ break; ++ case BRI_NETWORK: ++ h.h.c_r = 0; ++ break; ++ case BRI_CPE: ++ h.h.c_r = 1; ++ break; ++ default: ++ pri_error(pri, "Don't know how to disconnect on a type %d node\n", pri->localtype); ++ return; ++ } ++ if (pri->debug & PRI_DEBUG_Q921_STATE) ++ pri_message(pri, "Sending Disconnect\n"); ++ q921_transmit(pri, &h, 3); ++ } ++*/ + +-static void q921_send_sabme(void *vpri, int now) ++static void q921_send_dm(struct pri *pri, int pfbit, int tei) ++{ ++ q921_h h; ++ Q921_INIT(pri, h); ++ h.u.m3 = 0; /* M3 = 0 */ ++ h.u.m2 = 3; /* M2 = 3 */ ++ h.u.p_f = pfbit; /* Final bit on */ ++ h.u.ft = Q921_FRAMETYPE_U; ++ h.h.tei = tei; ++ switch(pri->localtype) { ++ case PRI_NETWORK: ++ h.h.c_r = 0; ++ break; ++ case PRI_CPE: ++ h.h.c_r = 1; ++ break; ++ case BRI_NETWORK_PTMP: ++ h.h.c_r = 0; ++ break; ++ case BRI_CPE_PTMP: ++ h.h.tei = pri->tei; ++ h.h.c_r = 1; ++ break; ++ case BRI_NETWORK: ++ h.h.c_r = 0; ++ break; ++ case BRI_CPE: ++ h.h.c_r = 1; ++ break; ++ default: ++ pri_error(pri, "Don't know how to DM on a type %d node\n", pri->localtype); ++ return; ++ } ++ if (pri->debug & PRI_DEBUG_Q921_STATE) ++ pri_message(pri, "Sending DM\n"); ++ q921_transmit(pri, &h, 3); ++} ++ ++static void q921_send_teireq(void *vpri) { ++ struct pri *pri = vpri; ++ unsigned short ri=0x6464; ++ q921_u *f; ++ ri = rand(); ++ ++ if (pri->localtype != BRI_CPE_PTMP) { ++ pri_error(pri, "TEI req for non-ptmp???\n"); ++ return; ++ } ++ if (pri->t202_timer[0]) { ++ pri_schedule_del(pri, pri->t202_timer[0]); ++ pri->t202_timer[0] = 0; ++ } ++ if (pri->sabme_retrans[0]++ > (pri->timers[PRI_TIMER_N202])) { ++ /* delete txqueue */ ++ q921_flush_txqueue(pri, 0, 1); ++ /* N202 retransmissions, activation of layer 2 failed, tell upper layer, start again */ ++ pri->schedev = 1; ++ pri->ev.gen.e = PRI_EVENT_DCHAN_DOWN; ++ pri->ev.gen.tei = 0; ++ pri->sabme_retrans[0] = 0; ++ /* dont try again, they are gone */ ++ return; ++ } ++ ++ pri->t202_timer[0] = pri_schedule_event(pri, pri->timers[PRI_TIMER_T202], q921_send_teireq, pri); ++ ++ pri->ri = ri; ++ f = malloc(sizeof(q921_u) + 5 + 2); ++ memset(f,0x0,sizeof(q921_u) + 5 + 2); ++ if (f) { ++ f->h.sapi = Q921_SAPI_LAYER2_MANAGEMENT; ++ f->h.tei = Q921_TEI_GROUP; ++ f->h.c_r = 0; ++ f->h.ea1 = 0; ++ f->h.ea2 = 1; ++ f->m2 = 0; ++ f->m3 = 0; ++ f->ft = Q921_FRAMETYPE_U; ++ f->data[0] = 0xf; ++ f->data[1] = ri >> 8; ++ f->data[2] = ri & 0xff; ++ f->data[3] = Q921_TEI_ID_REQUEST; ++ f->data[4] = 0xff; ++ if (pri->debug & PRI_DEBUG_Q921_STATE) ++ pri_message(pri, "Sending TEI Request ri=%d\n",ri); ++ q921_transmit(pri,(q921_h *)&(f->h),8); ++ } ++} ++ ++static void q921_send_teiassign(struct pri *pri,int ri,int tei) { ++ q921_u *f; ++ ++ if (pri->localtype != BRI_NETWORK_PTMP) { ++ pri_error(pri, "TEI assign for non-ptmp???\n"); ++ return; ++ } ++ ++ f = malloc(sizeof(q921_u) + 5 + 2); ++ memset(f,0x0,sizeof(q921_u) + 5 + 2); ++ if (f) { ++ f->h.sapi = Q921_SAPI_LAYER2_MANAGEMENT; ++ f->h.tei = Q921_TEI_GROUP; ++ f->h.c_r = 1; ++ f->h.ea1 = 0; ++ f->h.ea2 = 1; ++ f->m2 = 0; ++ f->m3 = 0; ++ f->ft = Q921_FRAMETYPE_U; ++ f->data[0] = 0xf; ++ f->data[1] = ri >> 8; ++ f->data[2] = ri & 0xff; ++ f->data[3] = Q921_TEI_ID_ASSIGNED; ++ f->data[4] = (tei << 1) | 0x1; ++ if (pri->debug & PRI_DEBUG_Q921_STATE) ++ pri_message(pri, "Sending TEI assign ri=%d tei=%d\n",ri,tei); ++ q921_transmit(pri,(q921_h *)&(f->h),8); ++ free(f); ++ } else { ++ pri_error(pri, "q921_send_teiassign: failed to malloc f!\n"); ++ } ++} ++ ++static void q921_send_teichkresp(struct pri *pri,int tei) { ++ q921_u *f; ++ unsigned short ri=0x6464; ++ ri = rand(); ++ ++ if (pri->localtype != BRI_CPE_PTMP) { ++ pri_error(pri, "TEI check response for non-ptmp???\n"); ++ return; ++ } ++ ++ f = malloc(sizeof(q921_u) + 5 + 2); ++ memset(f,0x0,sizeof(q921_u) + 5 + 2); ++ if (f) { ++ f->h.sapi = Q921_SAPI_LAYER2_MANAGEMENT; ++ f->h.tei = Q921_TEI_GROUP; ++ f->h.c_r = 0; // command u->n ++ f->h.ea1 = 0; ++ f->h.ea2 = 1; ++ f->m2 = 0; ++ f->m3 = 0; ++ f->ft = Q921_FRAMETYPE_U; ++ f->data[0] = 0xf; ++ f->data[1] = ri >> 8; ++ f->data[2] = ri & 0xff; ++ f->data[3] = Q921_TEI_ID_CHK_RES; ++ f->data[4] = (tei << 1) | 0x1; ++ if (pri->debug & PRI_DEBUG_Q921_STATE) ++ pri_message(pri, "Sending TEI check resp ri=%d tei=%d\n",ri,tei); ++ q921_transmit(pri,(q921_h *)&(f->h),8); ++ free(f); ++ } ++} ++ ++static void q921_send_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_now(void *vpri, int tei); ++ ++static void q921_send_sabme(void *vpri, int now, int tei) + { + struct pri *pri = vpri; + q921_h h; +- pri_schedule_del(pri, pri->sabme_timer); +- pri->sabme_timer = 0; +- pri->sabme_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T200], q921_send_sabme_now, pri); ++ int teio=tei - Q921_TEI_BASE; ++ if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; } ++ ++ if (pri->sabme_timer[teio]) { ++ pri_schedule_del(pri, pri->sabme_timer[teio]); ++ pri->sabme_timer[teio] = 0; ++ } ++ pri->sabme_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T200], q921_send_sabme_now, pri, tei); + if (!now) + return; ++ if (pri->sabme_retrans[teio]++ > (pri->timers[PRI_TIMER_N202])) { ++ /* delete txqueue */ ++ q921_flush_txqueue(pri, tei, 1); ++ /* N202 retransmissions, activation of layer 2 failed, tell upper layer, start again */ ++ pri->schedev = 1; ++ pri->ev.gen.e = PRI_EVENT_DCHAN_DOWN; ++ pri->ev.gen.tei = tei; ++ pri->sabme_retrans[teio] = 0; ++ /* dont try again, they are gone */ ++ return; ++ } + Q921_INIT(pri, h); ++ // XXX ++ h.h.tei = tei; + h.u.m3 = 3; /* M3 = 3 */ + h.u.m2 = 3; /* M2 = 3 */ + h.u.p_f = 1; /* Poll bit set */ +@@ -139,25 +504,42 @@ + case PRI_CPE: + h.h.c_r = 0; + break; ++ case BRI_NETWORK_PTMP: ++ h.h.c_r = 1; ++ break; ++ case BRI_CPE_PTMP: ++ h.h.c_r = 0; ++ h.h.tei = pri->tei; ++ break; ++ case BRI_NETWORK: ++ h.h.c_r = 1; ++ break; ++ case BRI_CPE: ++ h.h.c_r = 0; ++ break; + default: +- pri_error(pri, "Don't know how to U/A on a type %d node\n", pri->localtype); ++ pri_error(pri, "Don't know how to send SABME on a type %d node\n", pri->localtype); + return; + } + if (pri->debug & PRI_DEBUG_Q921_STATE) + pri_message(pri, "Sending Set Asynchronous Balanced Mode Extended\n"); + q921_transmit(pri, &h, 3); +- pri->q921_state = Q921_AWAITING_ESTABLISH; ++ pri->q921_state[teio] = Q921_AWAITING_ESTABLISH; + } + +-static void q921_send_sabme_now(void *vpri) ++static void q921_send_sabme_now(void *vpri, int tei) + { +- q921_send_sabme(vpri, 1); ++ q921_send_sabme(vpri, 1, tei); + } + +-static int q921_ack_packet(struct pri *pri, int num) ++ ++ ++static int q921_ack_packet(struct pri *pri, int num, int tei) + { + struct q921_frame *f, *prev = NULL; +- f = pri->txqueue; ++ int teio=tei - Q921_TEI_BASE; ++ if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; } ++ f = pri->txqueue[teio]; + while(f) { + if (f->h.n_s == num) { + /* Cancel each packet as necessary */ +@@ -165,26 +547,26 @@ + if (prev) + prev->next = f->next; + else +- pri->txqueue = f->next; ++ pri->txqueue[teio] = f->next; + if (pri->debug & PRI_DEBUG_Q921_STATE) +- pri_message(pri, "-- ACKing packet %d, new txqueue is %d (-1 means empty)\n", f->h.n_s, pri->txqueue ? pri->txqueue->h.n_s : -1); ++ pri_message(pri, "-- ACKing packet %d, new txqueue is %d (-1 means empty)\n", f->h.n_s, pri->txqueue[teio] ? pri->txqueue[teio]->h.n_s : -1); + /* Update v_a */ +- pri->v_a = num; ++ pri->v_a[teio] = num; + free(f); + /* Reset retransmission counter if we actually acked something */ +- pri->retrans = 0; ++ pri->retrans[teio] = 0; + /* Decrement window size */ +- pri->windowlen--; ++ pri->windowlen[teio]--; + /* Search for something to send */ +- f = pri->txqueue; ++ f = pri->txqueue[teio]; + while(f) { + if (!f->transmitted) { + /* Send it now... */ + if (pri->debug & PRI_DEBUG_Q921_STATE) + pri_message(pri, "-- Finally transmitting %d, since window opened up\n", f->h.n_s); + f->transmitted++; +- pri->windowlen++; +- f->h.n_r = pri->v_r; ++ pri->windowlen[teio]++; ++ f->h.n_r = pri->v_r[teio]; + q921_transmit(pri, (q921_h *)(&f->h), f->len); + break; + } +@@ -198,77 +580,136 @@ + return 0; + } + +-static void t203_expire(void *); +-static void t200_expire(void *); +-static pri_event *q921_dchannel_down(struct pri *pri); ++static void t203_expire(void *, int tei); ++static void t200_expire(void *, int tei); ++static pri_event *q921_dchannel_down(struct pri *pri, int tei); + +-static void reschedule_t203(struct pri *pri) ++static void reschedule_t203(struct pri *pri, int tei) + { +- if (pri->t203_timer) { +- pri_schedule_del(pri, pri->t203_timer); +- if (pri->debug & PRI_DEBUG_Q921_STATE) +- pri_message(pri, "-- Restarting T203 counter\n"); +- /* Nothing to transmit, start the T203 counter instead */ +- pri->t203_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T203], t203_expire, pri); ++ int teio=tei - Q921_TEI_BASE; ++ if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; } ++ if (pri->t203_timer[teio]) { ++ pri_schedule_del(pri, pri->t203_timer[teio]); ++ pri->t203_timer[teio] = 0; ++ if (pri->q921_state[teio] != Q921_LINK_CONNECTION_RELEASED) { ++ if (pri->debug & PRI_DEBUG_Q921_STATE) ++ pri_message(pri, "-- Restarting T203 counter\n"); ++ /* Nothing to transmit, start the T203 counter instead */ ++ pri->t203_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T203], t203_expire, pri, tei); ++ } ++ } ++} ++ ++static void q921_flush_txqueue(struct pri *pri, int tei, int devnull) ++{ ++ struct q921_frame *f, *tmp = NULL; ++ int teio=tei - Q921_TEI_BASE; ++ if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; } ++ f = pri->txqueue[teio]; ++ ++ /* nothing to send */ ++ if (!f) return; ++ ++ /* transmit all i-frames that were queued up while we were waiting for layer 2 to rise */ ++ while(f) { ++ if (devnull) { ++ tmp = f; ++ f = f->next; ++ free(tmp); ++ tmp = NULL; ++ } else { ++ if (pri->localtype == BRI_CPE_PTMP) { ++ /* update TEI, it might have changed */ ++ f->h.h.tei = pri->tei; ++ } ++ q921_transmit(pri, (q921_h *)&f->h, f->len); ++ f->transmitted++; ++ f = f->next; ++ } ++ } ++ ++ if (devnull) { ++ pri->txqueue[teio] = NULL; ++ pri->v_s[teio] = 0; ++ } else { ++ if (pri->t200_timer[teio]) { ++ pri_schedule_del(pri, pri->t200_timer[teio]); ++ pri->t200_timer[teio] = 0; ++ } ++ if (pri->t203_timer[teio]) { ++ pri_schedule_del(pri, pri->t203_timer[teio]); ++ pri->t203_timer[teio] = 0; ++ } ++ pri->t200_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri, tei); + } + } + +-static pri_event *q921_ack_rx(struct pri *pri, int ack) ++static pri_event *q921_ack_rx(struct pri *pri, int ack, int tei) + { + int x; + int cnt=0; + pri_event *ev; ++ int teio=tei - Q921_TEI_BASE; ++ if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; } + /* Make sure the ACK was within our window */ +- for (x=pri->v_a; (x != pri->v_s) && (x != ack); Q921_INC(x)); ++ for (x=pri->v_a[teio]; (x != pri->v_s[teio]) && (x != ack); Q921_INC(x)); + if (x != ack) { + /* ACK was outside of our window --- ignore */ +- pri_error(pri, "ACK received for '%d' outside of window of '%d' to '%d', restarting\n", ack, pri->v_a, pri->v_s); +- ev = q921_dchannel_down(pri); +- q921_start(pri, 1); ++ pri_error(pri, "ACK received for '%d' outside of window of '%d' to '%d', restarting\n", ack, pri->v_a[teio], pri->v_s[teio]); ++ ev = q921_dchannel_down(pri, tei); ++ q921_start(pri, 1, tei); + pri->schedev = 1; + return ev; + } + /* Cancel each packet as necessary */ + if (pri->debug & PRI_DEBUG_Q921_STATE) +- pri_message(pri, "-- ACKing all packets from %d to (but not including) %d\n", pri->v_a, ack); +- for (x=pri->v_a; x != ack; Q921_INC(x)) +- cnt += q921_ack_packet(pri, x); +- if (!pri->txqueue) { ++ pri_message(pri, "-- ACKing all packets from %d to (but not including) %d\n", pri->v_a[teio], ack); ++ for (x=pri->v_a[teio]; x != ack; Q921_INC(x)) ++ cnt += q921_ack_packet(pri, x, tei); ++ if (!pri->txqueue[teio]) { ++ /* Something was ACK'd. Stop T200 counter */ ++ if (pri->t200_timer[teio]) { ++ pri_schedule_del(pri, pri->t200_timer[teio]); ++ pri->t200_timer[teio] = 0; ++ } + if (pri->debug & PRI_DEBUG_Q921_STATE) + pri_message(pri, "-- Since there was nothing left, stopping T200 counter\n"); +- /* Something was ACK'd. Stop T200 counter */ +- pri_schedule_del(pri, pri->t200_timer); +- pri->t200_timer = 0; + } +- if (pri->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_STATE) + 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->t200_timer[teio]) { ++ pri_schedule_del(pri, pri->t200_timer[teio]); ++ pri->t200_timer[teio] = 0; ++ } + if (pri->debug & PRI_DEBUG_Q921_STATE) +- pri_message(pri, "-- Something left to transmit (%d), restarting T200 counter\n", pri->txqueue->h.n_s); +- if (!pri->t200_timer) +- pri->t200_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri); ++ pri_message(pri, "-- Something left to transmit (%d), restarting T200 counter\n", pri->txqueue[teio]->h.n_s); ++ pri->t200_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri, tei); ++ + } else { + if (pri->debug & PRI_DEBUG_Q921_STATE) + pri_message(pri, "-- Nothing left, starting T203 counter\n"); + /* Nothing to transmit, start the T203 counter instead */ +- pri->t203_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T203], t203_expire, pri); ++ pri->t203_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T203], t203_expire, pri, tei); + } + return NULL; + } + +-static void q921_reject(struct pri *pri, int pf) ++static void q921_reject(struct pri *pri, int pf, int tei) + { + q921_h h; ++ int teio=tei - Q921_TEI_BASE; ++ if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; } + Q921_INIT(pri, h); + h.s.x0 = 0; /* Always 0 */ + h.s.ss = 2; /* Reject */ + h.s.ft = 1; /* Frametype (01) */ +- h.s.n_r = pri->v_r; /* Where to start retransmission */ ++ h.s.n_r = pri->v_r[teio]; /* Where to start retransmission */ + h.s.p_f = pf; + switch(pri->localtype) { + case PRI_NETWORK: +@@ -277,23 +718,38 @@ + case PRI_CPE: + h.h.c_r = 1; + break; ++ case BRI_NETWORK_PTMP: ++ h.h.c_r = 0; ++ break; ++ case BRI_CPE_PTMP: ++ h.h.c_r = 1; ++ h.h.tei = tei; ++ break; ++ case BRI_NETWORK: ++ h.h.c_r = 0; ++ break; ++ case BRI_CPE: ++ h.h.c_r = 1; ++ break; + default: +- pri_error(pri, "Don't know how to U/A on a type %d node\n", pri->localtype); ++ pri_error(pri, "Don't know how to REJECT on a type %d node\n", pri->localtype); + return; + } + if (pri->debug & PRI_DEBUG_Q921_STATE) +- pri_message(pri, "Sending Reject (%d)\n", pri->v_r); +- pri->sentrej = 1; ++ pri_message(pri, "Sending Reject (%d)\n", pri->v_r[teio]); ++ pri->sentrej[teio] = 1; + q921_transmit(pri, &h, 4); + } + +-static void q921_rr(struct pri *pri, int pbit, int cmd) { ++static void q921_rr(struct pri *pri, int pbit, int cmd, int tei) { + q921_h h; ++ int teio=tei - Q921_TEI_BASE; ++ if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; } + Q921_INIT(pri, h); + h.s.x0 = 0; /* Always 0 */ + h.s.ss = 0; /* Receive Ready */ + h.s.ft = 1; /* Frametype (01) */ +- h.s.n_r = pri->v_r; /* N/R */ ++ h.s.n_r = pri->v_r[teio]; /* N/R */ + h.s.p_f = pbit; /* Poll/Final set appropriately */ + switch(pri->localtype) { + case PRI_NETWORK: +@@ -308,81 +764,192 @@ + else + h.h.c_r = 1; + break; ++ case BRI_NETWORK_PTMP: ++ h.h.tei = tei; ++ if (cmd) ++ h.h.c_r = 1; ++ else ++ h.h.c_r = 0; ++ break; ++ case BRI_CPE_PTMP: ++ h.h.tei = tei; ++ if (cmd) ++ h.h.c_r = 0; ++ else ++ h.h.c_r = 1; ++ break; ++ case BRI_NETWORK: ++ if (cmd) ++ h.h.c_r = 1; ++ else ++ h.h.c_r = 0; ++ break; ++ case BRI_CPE: ++ if (cmd) ++ h.h.c_r = 0; ++ else ++ h.h.c_r = 1; ++ break; + default: +- pri_error(pri, "Don't know how to U/A on a type %d node\n", pri->localtype); ++ pri_error(pri, "Don't know how to RR on a type %d node\n", pri->localtype); + return; + } +- pri->v_na = pri->v_r; /* Make a note that we've already acked this */ ++ pri->v_na[teio] = pri->v_r[teio]; /* Make a note that we've already acked this */ + if (pri->debug & PRI_DEBUG_Q921_STATE) +- pri_message(pri, "Sending Receiver Ready (%d)\n", pri->v_r); ++ pri_message(pri, "Sending Receiver Ready (%d)\n", pri->v_r[teio]); + q921_transmit(pri, &h, 4); + } + +-static void t200_expire(void *vpri) ++static void t200_expire(void *vpri, int tei) + { + struct pri *pri = vpri; +- if (pri->txqueue) { ++ int teio=tei - Q921_TEI_BASE; ++ if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; } ++ if (pri->txqueue[teio]) { + /* Retransmit first packet in the queue, setting the poll bit */ + if (pri->debug & PRI_DEBUG_Q921_STATE) + pri_message(pri, "-- T200 counter expired, What to do...\n"); +- /* Force Poll bit */ +- pri->txqueue->h.p_f = 1; +- /* Update nr */ +- pri->txqueue->h.n_r = pri->v_r; +- pri->v_na = pri->v_r; +- pri->solicitfbit = 1; +- pri->retrans++; ++ if (pri->txqueue[teio]->transmitted) { ++ /* Force Poll bit, if this is a retransmission */ ++ pri->txqueue[teio]->h.p_f = 1; ++ pri->solicitfbit[teio] = 1; ++ /* Update nr */ ++ pri->txqueue[teio]->h.n_r = pri->v_r[teio]; ++ pri->v_na[teio] = pri->v_r[teio]; ++ pri->retrans[teio]++; ++ } + /* Up to three retransmissions */ +- if (pri->retrans < pri->timers[PRI_TIMER_N200]) { ++ if ((pri->retrans[teio] + 1) <= pri->timers[PRI_TIMER_N200]) { + /* Reschedule t200_timer */ + if (pri->debug & PRI_DEBUG_Q921_STATE) +- pri_message(pri, "-- Retransmitting %d bytes\n", pri->txqueue->len); +- if (pri->busy) +- q921_rr(pri, 1, 1); +- else { +- if (!pri->txqueue->transmitted) ++ pri_message(pri, "-- Retransmitting %d bytes\n", pri->txqueue[teio]->len); ++ if (pri->busy[teio]) { ++ // pri_message(pri, "-- q921_rr(pri, 1, 1) \n", tei); ++ q921_rr(pri, 1, 1, tei); ++ } else { ++ if (!pri->txqueue[teio]->transmitted) + pri_error(pri, "!! Not good - head of queue has not been transmitted yet\n"); +- q921_transmit(pri, (q921_h *)&pri->txqueue->h, pri->txqueue->len); ++ q921_transmit(pri, (q921_h *)&pri->txqueue[teio]->h, pri->txqueue[teio]->len); ++ //layer 3 ++ pri->txqueue[teio]->transmitted++; + } + if (pri->debug & PRI_DEBUG_Q921_STATE) +- pri_message(pri, "-- Rescheduling retransmission (%d)\n", pri->retrans); +- pri->t200_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri); ++ pri_message(pri, "-- Rescheduling retransmission (%d)\n", pri->retrans[teio]); ++ pri->t200_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri, tei); + } else { + if (pri->debug & PRI_DEBUG_Q921_STATE) + pri_message(pri, "-- Timeout occured, restarting PRI\n"); +- pri->q921_state = Q921_LINK_CONNECTION_RELEASED; +- pri->t200_timer = 0; +- q921_dchannel_down(pri); +- q921_start(pri, 1); ++ pri->q921_state[teio] = Q921_LINK_CONNECTION_RELEASED; ++ pri->t200_timer[teio] = 0; ++ q921_dchannel_down(pri, tei); ++ q921_start(pri, 1, tei); + pri->schedev = 1; + } +- } else if (pri->solicitfbit) { ++ } else if (pri->solicitfbit[teio]) { + if (pri->debug & PRI_DEBUG_Q921_STATE) + pri_message(pri, "-- Retrying poll with f-bit\n"); +- pri->retrans++; +- if (pri->retrans < pri->timers[PRI_TIMER_N200]) { +- pri->solicitfbit = 1; +- q921_rr(pri, 1, 1); +- pri->t200_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri); ++ pri->retrans[teio]++; ++ if (pri->retrans[teio] < pri->timers[PRI_TIMER_N200]) { ++ pri->solicitfbit[teio] = 1; ++ q921_rr(pri, 1, 1, tei); ++ pri->t200_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri, tei); + } else { + if (pri->debug & PRI_DEBUG_Q921_STATE) + pri_message(pri, "-- Timeout occured, restarting PRI\n"); +- pri->q921_state = Q921_LINK_CONNECTION_RELEASED; +- pri->t200_timer = 0; +- q921_dchannel_down(pri); +- q921_start(pri, 1); ++ pri->q921_state[teio] = Q921_LINK_CONNECTION_RELEASED; ++ pri->t200_timer[teio] = 0; ++ q921_dchannel_down(pri, tei); ++ q921_start(pri, 1, tei); + pri->schedev = 1; + } + } else { + pri_error(pri, "T200 counter expired, nothing to send...\n"); +- pri->t200_timer = 0; ++ pri->t200_timer[teio] = 0; ++ if (pri->busy[teio]) { ++ if ((pri->retrans[teio] + 1) <= pri->timers[PRI_TIMER_N200]) { ++ /* poll RR */ ++ pri->t200_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri, tei); ++ pri->retrans[teio]++; ++ q921_rr(pri, 1, 1, tei); ++ } else { ++ q921_reset(pri, tei, 1); ++ q921_start(pri, 1, tei); ++ } ++ } + } + } + +-int q921_transmit_iframe(struct pri *pri, void *buf, int len, int cr) ++int q921_transmit_uframe(struct pri *pri, void *buf, int len, int cr, int tei) ++{ ++ q921_u *uf; ++ uf = malloc(sizeof(q921_u) + len + 2); ++ memset(uf,0,sizeof(q921_u) + len + 2); ++ ++ uf->h.sapi = 0; ++ uf->h.ea1 = 0; ++ uf->h.ea2 = 1; ++ uf->h.tei = tei; ++ uf->m3 = 0; ++ uf->m2 = 0; ++ uf->ft = Q921_FRAMETYPE_U; ++ switch(pri->localtype) { ++ case PRI_NETWORK: ++ uf->h.c_r = 1; ++ break; ++ case PRI_CPE: ++ uf->h.c_r = 0; ++ break; ++ case BRI_NETWORK_PTMP: ++ uf->h.c_r = 1; ++ break; ++ case BRI_CPE_PTMP: ++ uf->h.c_r = 0; ++ break; ++ case BRI_NETWORK: ++ uf->h.c_r = 1; ++ break; ++ case BRI_CPE: ++ uf->h.c_r = 0; ++ break; ++ default: ++ pri_error(pri, "Don't know how to send U frames on a type %d node\n", pri->localtype); ++ return -1; ++ } ++ memcpy(uf->data,buf,len); ++ q921_transmit(pri, (q921_h*)&(uf->h), 3+len); ++ free(uf); ++ return 0; ++} ++ ++ ++int q921_transmit_iframe(struct pri *pri, void *buf, int len, int cr, int tei) + { + q921_frame *f, *prev=NULL; +- for (f=pri->txqueue; f; f = f->next) prev = f; ++ int teio=tei - Q921_TEI_BASE; ++ if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; } ++ if ((pri->q921_state[teio] == Q921_LINK_CONNECTION_RELEASED) && (!pri->sabme_timer[teio])) { ++ if (pri->localtype == BRI_CPE_PTMP) { ++ if (pri->tei > 0) { ++ /* p2p datalink is down */ ++ pri->sabme_retrans[teio] = 0; ++ q921_send_sabme_now(pri, pri->tei); ++ if (pri->debug & PRI_DEBUG_Q921_STATE) ++ pri_message(pri, "Reactivating layer 2\n"); ++ } else { ++ /* no tei */ ++ if (pri->debug & PRI_DEBUG_Q921_STATE) ++ pri_message(pri, "reactivating layer 2, sending tei req\n"); ++ q921_send_teireq(pri); ++ } ++ } else if ((pri->localtype == BRI_CPE) || (pri->localtype == BRI_NETWORK)) { ++ /* p2p datalink is down */ ++ pri->sabme_retrans[teio] = 0; ++ q921_send_sabme_now(pri, pri->tei); ++ if (pri->debug & PRI_DEBUG_Q921_STATE) ++ pri_message(pri, "Reactivating layer 2\n"); ++ } ++ } ++ for (f=pri->txqueue[teio]; f; f = f->next) prev = f; + f = malloc(sizeof(q921_frame) + len + 2); + if (f) { + memset(f,0,sizeof(q921_frame) + len + 2); +@@ -400,47 +967,80 @@ + else + f->h.h.c_r = 1; + break; ++ case BRI_NETWORK_PTMP: ++ f->h.h.tei = tei; ++ if (cr) ++ f->h.h.c_r = 1; ++ else ++ f->h.h.c_r = 0; ++ break; ++ case BRI_CPE_PTMP: ++ f->h.h.tei = pri->tei; ++ if (cr) ++ f->h.h.c_r = 0; ++ else ++ f->h.h.c_r = 1; ++ break; ++ case BRI_NETWORK: ++ if (cr) ++ f->h.h.c_r = 1; ++ else ++ f->h.h.c_r = 0; ++ break; ++ case BRI_CPE: ++ if (cr) ++ f->h.h.c_r = 0; ++ else ++ f->h.h.c_r = 1; ++ break; + } + f->next = NULL; + f->transmitted = 0; + f->len = len + 4; + memcpy(f->h.data, buf, len); +- f->h.n_s = pri->v_s; +- f->h.n_r = pri->v_r; +- pri->v_s++; +- pri->v_na = pri->v_r; ++ f->h.n_s = pri->v_s[teio]; ++ f->h.n_r = pri->v_r[teio]; ++ pri->v_s[teio]++; ++ pri->v_na[teio] = pri->v_r[teio]; + f->h.p_f = 0; + f->h.ft = 0; + if (prev) + prev->next = f; + else +- pri->txqueue = f; +- /* Immediately transmit unless we're in a recovery state, or the window +- size is too big */ +- if (!pri->retrans && !pri->busy) { +- if (pri->windowlen < pri->window) { +- pri->windowlen++; ++ pri->txqueue[teio] = f; ++ ++ if ((pri->q921_state[teio] != Q921_LINK_CONNECTION_ESTABLISHED) && ((pri->localtype == BRI_CPE_PTMP) || (pri->localtype == BRI_CPE) || (pri->localtype == BRI_NETWORK))){ ++ /* no p2p datalink, yet. queue up the iframes... */ ++ if (pri->debug & PRI_DEBUG_Q921_STATE) ++ pri_message(pri, "Layer 3 transmit waiting for layer 2\n"); ++ } else { ++ /* Immediately transmit unless we're in a recovery state, or the window ++ size is too big */ ++ if (!pri->retrans[teio] && !pri->busy[teio]) { ++ if (pri->windowlen[teio] < pri->window[teio]) { ++ pri->windowlen[teio]++; + q921_transmit(pri, (q921_h *)(&f->h), f->len); + f->transmitted++; + } else { + if (pri->debug & PRI_DEBUG_Q921_STATE) + pri_message(pri, "Delaying transmission of %d, window is %d/%d long\n", +- f->h.n_s, pri->windowlen, pri->window); ++ f->h.n_s, pri->windowlen[teio], pri->window[teio]); + } +- } +- if (pri->t203_timer) { ++ } ++ if (pri->t203_timer[teio]) { ++ 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\n"); +- pri_schedule_del(pri, pri->t203_timer); +- pri->t203_timer = 0; +- } +- if (!pri->t200_timer) { ++ } ++ if (!pri->t200_timer[teio]) { + if (pri->debug & PRI_DEBUG_Q921_STATE) + pri_message(pri, "Starting T_200 timer\n"); +- pri->t200_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri); +- } else ++ pri->t200_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri, tei); ++ } else + if (pri->debug & PRI_DEBUG_Q921_STATE) +- pri_message(pri, "T_200 timer already going (%d)\n", pri->t200_timer); ++ pri_message(pri, "T_200 timer already going (%d)\n", pri->t200_timer[teio]); ++ } + + } else { + pri_error(pri, "!! Out of memory for Q.921 transmit\n"); +@@ -449,49 +1049,86 @@ + return 0; + } + +-static void t203_expire(void *vpri) ++static void t203_expire(void *vpri, int tei) + { +- struct pri *pri = vpri; +- if (pri->q921_state == Q921_LINK_CONNECTION_ESTABLISHED) { +- if (pri->debug & PRI_DEBUG_Q921_STATE) ++ struct pri *pri = vpri; ++ int teio=tei - Q921_TEI_BASE; ++ if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; } ++ ++ if (pri->q921_state[teio] == Q921_LINK_CONNECTION_ESTABLISHED) { ++ if (pri->debug & PRI_DEBUG_Q921_STATE) + pri_message(pri, "T203 counter expired, sending RR and scheduling T203 again\n"); +- /* Solicit an F-bit in the other's RR */ +- pri->solicitfbit = 1; +- pri->retrans = 0; +- q921_rr(pri, 1, 1); +- /* Start timer T200 to resend our RR if we don't get it */ +- pri->t203_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri); ++ /* Solicit an F-bit in the other's RR */ ++ pri->solicitfbit[teio] = 1; ++ pri->retrans[teio] = 0; ++ q921_rr(pri, 1, 1, tei); ++ /* Start timer T200 to resend our RR if we don't get it */ ++ pri->t203_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri, tei); ++ } else { ++ if (pri->debug & PRI_DEBUG_Q921_STATE) ++ pri_message(pri, "T203 counter expired in weird state %d\n", pri->q921_state[teio]); ++ pri->t203_timer[teio] = 0; ++ } ++} ++ ++static 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->debug & PRI_DEBUG_Q921_STATE) +- pri_message(pri, "T203 counter expired in weird state %d\n", pri->q921_state); +- pri->t203_timer = 0; ++ 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; } ++// pri_error(pri, "q921_handle_iframe: i->n_s %d pri->v_r[%d] %d \n", i->n_s, teio, pri->v_r[teio]); + /* Make sure this is a valid packet */ +- if (i->n_s == pri->v_r) { ++ if (i->n_s == pri->v_r[teio]) { + /* Increment next expected I-frame */ +- Q921_INC(pri->v_r); ++ Q921_INC(pri->v_r[teio]); + /* Handle their ACK */ +- pri->sentrej = 0; +- ev = q921_ack_rx(pri, i->n_r); ++ pri->sentrej[teio] = 0; ++ ev = q921_ack_rx(pri, i->n_r, i->h.tei); ++ if (ev) { ++ pri_error(pri, "q921_handle_iframe: ev = %d \n", ev->e); ++ } + if (ev) + return ev; + if (i->p_f) { + /* If the Poll/Final bit is set, immediate send the RR */ +- q921_rr(pri, 1, 0); +- } else if (pri->busy) { +- q921_rr(pri, 0, 0); ++ q921_rr(pri, 1, 0, i->h.tei); ++ } else if (pri->busy[teio]) { ++ q921_rr(pri, 0, 0, i->h.tei); ++ } else if (pri->t200_timer[teio] && pri->retrans[teio]) { ++ pri_error(pri, "q921_handle_iframe: sending RR \n"); ++ q921_rr(pri, 0, 0, i->h.tei); + } + /* Receive Q.931 data */ +- res = q931_receive(pri, (q931_h *)i->data, len - 4); ++ res = q931_receive(pri, (q931_h *)i->data, len - 4, i->h.tei); + /* Send an RR if one wasn't sent already */ +- if (pri->v_na != pri->v_r) +- q921_rr(pri, 0, 0); ++ if (pri->v_na[teio] != pri->v_r[teio]) ++ q921_rr(pri, 0, 0, i->h.tei); + if (res == -1) { + return NULL; + } +@@ -500,10 +1137,10 @@ + } else { + /* If we haven't already sent a reject, send it now, otherwise + we are obliged to RR */ +- if (!pri->sentrej) +- q921_reject(pri, i->p_f); ++ if (!pri->sentrej[teio]) ++ q921_reject(pri, i->p_f, i->h.tei); + else if (i->p_f) +- q921_rr(pri, 1, 0); ++ q921_rr(pri, 1, 0, i->h.tei); + } + return NULL; + } +@@ -641,75 +1278,152 @@ + }; + } + +-static pri_event *q921_dchannel_up(struct pri *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 void q921_invoke_tei_recovery(void *vpri, int tei) { ++ struct pri *pri = vpri; ++ q921_tei_recovery(pri, tei); ++} ++*/ ++ ++static pri_event *q921_dchannel_up(struct pri *pri, int tei) + { +- /* Reset counters, etc */ +- q921_reset(pri); ++ // we treat this as MFE ++ int teio=tei - Q921_TEI_BASE; ++ if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; } ++ ++ if (((pri->localtype == BRI_CPE_PTMP) || (pri->localtype == BRI_CPE) || (pri->localtype == BRI_NETWORK)) && (pri->txqueue[teio])) { ++ /* Reset counters, etc */ ++ q921_reset(pri, tei, 0); ++ } else { ++ /* Reset counters, discard frames, etc */ ++ q921_reset(pri, tei, 1); ++ } + + /* Stop any SABME retransmissions */ +- pri_schedule_del(pri, pri->sabme_timer); +- pri->sabme_timer = 0; ++ if (pri->sabme_timer[teio]) { ++ pri_schedule_del(pri, pri->sabme_timer[teio]); ++ pri->sabme_timer[teio] = 0; ++ } ++ ++ if (pri->t202_timer[teio]) { ++ pri_schedule_del(pri, pri->t202_timer[teio]); ++ pri->t202_timer[teio] = 0; ++ } + + /* Reset any rejects */ +- pri->sentrej = 0; ++ pri->sentrej[teio] = 0; + + /* Go into connection established state */ +- pri->q921_state = Q921_LINK_CONNECTION_ESTABLISHED; +- +- /* Start the T203 timer */ +- pri->t203_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T203], t203_expire, pri); ++ pri->q921_state[teio] = Q921_LINK_CONNECTION_ESTABLISHED; + +- /* Report event that D-Channel is now up */ +- pri->ev.gen.e = PRI_EVENT_DCHAN_UP; +- return &pri->ev; ++ if (((pri->localtype == BRI_CPE_PTMP) || (pri->localtype == BRI_CPE) || (pri->localtype == BRI_NETWORK)) && (pri->txqueue[teio])) { ++ /* transmit queued iframes ans start T200 (handled by flush_txqueue) */ ++ q921_flush_txqueue(pri, tei, 0); ++ /* dont upset upper layers if we reactivate layer 2 */ ++ return NULL; ++ } else { ++ /* Start the T203 timer */ ++ pri->t203_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T203], t203_expire, pri, tei); ++ ++ /* Report event that D-Channel is now up */ ++ pri->ev.gen.e = PRI_EVENT_DCHAN_UP; ++ pri->ev.gen.tei = tei; ++ return &pri->ev; ++ } + } + +-static pri_event *q921_dchannel_down(struct pri *pri) ++static pri_event *q921_dchannel_down(struct pri *pri, int tei) + { ++ int teio=tei - Q921_TEI_BASE; ++ if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; } ++ ++ pri->q921_state[teio] = Q921_LINK_CONNECTION_RELEASED; ++ + /* Reset counters, reset sabme timer etc */ +- q921_reset(pri); ++ if (pri->localtype == BRI_NETWORK_PTMP) { ++ if (pri->t203_timer[teio]) { ++ 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; +- 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) + { + q921_frame *f; + pri_event *ev; + int sendnow; ++ int tei; ++ int res=-1; ++ int teio=h->h.tei - Q921_TEI_BASE; ++ if (((teio < 0) || (teio > Q921_MAX_TEIS)) || (pri->localtype != BRI_NETWORK_PTMP)) { teio=0; } + + switch(h->h.data[0] & Q921_FRAMETYPE_MASK) { + case 0: + case 2: +- if (pri->q921_state != Q921_LINK_CONNECTION_ESTABLISHED) { +- pri_error(pri, "!! Got I-frame while link state %d\n", pri->q921_state); ++ if (pri->q921_state[teio] != Q921_LINK_CONNECTION_ESTABLISHED) { ++ pri_error(pri, "!! Got I-frame while link state %d\n", pri->q921_state[teio]); + return NULL; + } + /* Informational frame */ +@@ -720,8 +1434,10 @@ + return q921_handle_iframe(pri, &h->i, len); + break; + case 1: +- if (pri->q921_state != Q921_LINK_CONNECTION_ESTABLISHED) { ++ if (pri->q921_state[teio] != Q921_LINK_CONNECTION_ESTABLISHED) { + pri_error(pri, "!! Got S-frame while link down\n"); ++ q921_send_dm(pri, 1, h->h.tei); ++ q921_reset(pri, h->h.tei, 1); + return NULL; + } + if (len < 4) { +@@ -731,80 +1447,128 @@ + 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 it's a p/f one then send back a RR in return with the p/f bit set */ ++// pri_error(pri, "-- h->s.pf %d pri->solicitfbit[teio] %d\n", h->s.p_f, pri->solicitfbit[teio]); ++ if (pri->solicitfbit[teio]) { + if (pri->debug & PRI_DEBUG_Q921_STATE) + pri_message(pri, "-- Got RR response to our frame\n"); + } else { +- if (pri->debug & PRI_DEBUG_Q921_STATE) ++ if (pri->txqueue[teio]) { ++ q921_flush_txqueue(pri, pri->tei, 0); ++ } else { ++ if (pri->debug & PRI_DEBUG_Q921_STATE) + pri_message(pri, "-- Unsolicited RR with P/F bit, responding\n"); +- q921_rr(pri, 1, 0); ++ q921_rr(pri, 1, 0, h->h.tei); ++ } + } +- pri->solicitfbit = 0; ++ pri->solicitfbit[teio] = 0; + } + break; + case 1: + /* Receiver not ready */ + if (pri->debug & PRI_DEBUG_Q921_STATE) + pri_message(pri, "-- Got receiver not ready\n"); +- if(h->s.p_f) { +- /* Send RR if poll bit set */ +- q921_rr(pri, h->s.p_f, 0); ++ if ((pri->localtype != PRI_NETWORK) && (pri->localtype != BRI_NETWORK) && (pri->localtype != BRI_NETWORK_PTMP)) { ++ if (h->s.p_f && h->s.h.c_r) { ++// if (!pri->t200_timer[teio]) { ++ /* Send RR if poll bit set */ ++ q921_rr(pri, h->s.p_f, 0, h->h.tei); ++// } ++ } ++ } else { ++ if (h->s.p_f && (!h->s.h.c_r)) { ++// if (!pri->t200_timer[teio]) { ++ /* Send RR if poll bit set */ ++ q921_rr(pri, h->s.p_f, 0, h->h.tei); ++// } ++ } + } +- pri->busy = 1; +- break; ++ pri->busy[teio] = 1; ++ if (pri->t200_timer[teio]) { ++ pri_schedule_del(pri, pri->t200_timer[teio]); ++ pri->t200_timer[teio] = 0; ++ } ++ pri->t200_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri, h->h.tei); ++ break; + case 2: + /* Just retransmit */ + if (pri->debug & PRI_DEBUG_Q921_STATE) + pri_message(pri, "-- Got reject requesting packet %d... Retransmitting.\n", h->s.n_r); +- if (h->s.p_f) { +- /* If it has the poll bit set, send an appropriate supervisory response */ +- q921_rr(pri, 1, 0); +- } + sendnow = 0; ++// XXX ++ q921_ack_rx(pri, h->s.n_r, h->h.tei); ++ /* 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) { ++// pri_error(pri, "!! frame n_s %d transmitted %d (searching for %d)!\n", f->h.n_s, f->transmitted, h->s.n_r); + if ((sendnow || (f->h.n_s == h->s.n_r)) && f->transmitted) { + /* Matches the request, or follows in our window, and has + already been transmitted. */ +- sendnow = 1; +- pri_error(pri, "!! Got reject for frame %d, retransmitting frame %d now, updating n_r!\n", h->s.n_r, f->h.n_s); +- f->h.n_r = pri->v_r; +- q921_transmit(pri, (q921_h *)(&f->h), f->len); ++ ++ /* multiframe established */ ++ f->transmitted = 0; ++ f->h.n_r = pri->v_r[teio]; ++ ++ if (pri->busy[teio]) { ++ pri->busy[teio] = 0; ++ sendnow = 0; ++ } else { ++ f->h.p_f = 0; ++ sendnow = 1; ++ pri_error(pri, "!! Got reject for frame %d, retransmitting frame %d now, updating n_r!\n", h->s.n_r, f->h.n_s); ++ q921_transmit(pri, (q921_h *)(&f->h), f->len); ++ f->transmitted++; ++ } + } + } + if (!sendnow) { +- if (pri->txqueue) { +- /* This should never happen */ +- if (!h->s.p_f || h->s.n_r) { ++ if (pri->txqueue[teio]) { ++ if (h->s.p_f) { ++ q921_rr(pri, 1, 0, h->h.tei); ++ } else if (!h->s.p_f || h->s.n_r) { + pri_error(pri, "!! Got reject for frame %d, but we only have others!\n", h->s.n_r); + } + } else { + /* Hrm, we have nothing to send, but have been REJ'd. Reset v_a, v_s, etc */ +- pri_error(pri, "!! Got reject for frame %d, but we have nothing -- resetting!\n", h->s.n_r); +- pri->v_a = h->s.n_r; +- pri->v_s = h->s.n_r; +- /* Reset t200 timer if it was somehow going */ +- if (pri->t200_timer) { +- pri_schedule_del(pri, pri->t200_timer); +- pri->t200_timer = 0; +- } ++/* pri_error(pri, "!! Got reject for frame %d, but we have nothing -- resetting!\n", h->s.n_r); ++ pri->v_a[teio] = h->s.n_r; ++ pri->v_s[teio] = h->s.n_r; */ + /* Reset and restart t203 timer */ +- if (pri->t203_timer) +- pri_schedule_del(pri, pri->t203_timer); +- pri->t203_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T203], t203_expire, pri); ++ if (pri->t203_timer[teio]) ++ pri_schedule_del(pri, pri->t203_timer[teio]); ++ pri->t203_timer[teio] = pri_schedule_event2(pri, pri->timers[PRI_TIMER_T203], t203_expire, pri, tei); ++ pri->solicitfbit[teio] = 0; + } +- } ++ } else { ++ if (h->s.p_f) { ++ /* If it has the poll bit set (and an iframe was retransmitted), send an appropriate supervisory response */ ++// q921_rr(pri, 1, 0, h->h.tei); ++ /* Reset 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: +@@ -821,8 +1585,16 @@ + if (pri->debug & PRI_DEBUG_Q921_STATE) + pri_message(pri, "-- Got DM Mode from peer.\n"); + /* Disconnected mode, try again after T200 */ +- ev = q921_dchannel_down(pri); +- q921_start(pri, 0); ++ ev = q921_dchannel_down(pri, h->h.tei); ++ if ((pri->localtype == BRI_CPE_PTMP) || (pri->localtype == BRI_CPE) || (pri->localtype == BRI_NETWORK)) { ++ /* release layer 2 */ ++ // pri_error(pri, "got DM, restarting layer 2.\n"); ++ // return NULL; ++ q921_start(pri, 0, h->h.tei); ++ } ++ if ((pri->localtype == PRI_NETWORK) || (pri->localtype == PRI_CPE)){ ++ q921_start(pri, 0, h->h.tei); ++ } + return ev; + + } else { +@@ -830,21 +1602,144 @@ + pri_message(pri, "-- Ignoring unsolicited DM with p/f set to 0\n"); + #if 0 + /* Requesting that we start */ +- q921_start(pri, 0); ++ q921_start(pri, 0, h->h.tei); + #endif + } + break; +- } else if (!h->u.m2) { +- pri_message(pri, "XXX Unnumbered Information not implemented XXX\n"); ++ } else if (h->u.m2 == 0) { ++ if (h->u.ft == 3) { ++ switch (h->u.data[0]) { /* Management Entity Identifier */ ++ case 0x0f: ++ /* TEI Procedure */ ++ switch (h->u.data[3]) { ++ case Q921_TEI_ID_VERIFY: ++ if (pri->localtype != BRI_NETWORK_PTMP) ++ break; ++ if (pri->debug & PRI_DEBUG_Q921_STATE) ++ pri_message(pri, "got TEI verify for TEI = %d\n",h->u.data[4] >> 1); ++ break; ++ case Q921_TEI_ID_ASSIGNED: ++ if (pri->localtype != BRI_CPE_PTMP) ++ break; ++ if (pri->tei == (h->u.data[4] >> 1)) { ++ // TEI already assgined, CHECK_TEI or REMOVE_TEI ++ pri_error(pri, "Double assgined TEI!\n"); ++ } ++ if (pri->ri == ((unsigned short) (h->u.data[1] << 8) + h->u.data[2])) { ++ if (pri->t202_timer[0]) { ++ pri_schedule_del(pri, pri->t202_timer[0]); ++ pri->t202_timer[0] = 0; ++ } ++ pri->tei = h->u.data[4] >> 1; ++ pri->ri = 0; ++ if (pri->debug & PRI_DEBUG_Q921_STATE) ++ pri_message(pri, "received TEI assign TEI = %d ri=%d\n",pri->tei,(unsigned short) (h->u.data[1] << 8) + h->u.data[2]); ++ pri->sabme_retrans[teio] = 0; ++ q921_send_sabme_now(pri, pri->tei); ++ } ++ break; ++ case Q921_TEI_ID_REMOVE: ++ pri_error(pri, "TEI remove TEI = %d\n",(h->u.data[4] >> 1)); ++ if (pri->localtype != BRI_CPE_PTMP) ++ break; ++ if (((h->u.data[4] >> 1) == Q921_TEI_GROUP) || (pri->tei == (h->u.data[4] >> 1))){ ++ if (pri->debug & PRI_DEBUG_Q921_STATE) ++ pri_message(pri, "received TEI remove TEI = %d\n",pri->tei); ++ pri->tei = 0; ++ pri->ri = 0; ++ // get a new TEI ++ q921_reset(pri, 0, 1); ++ q921_send_teireq(pri); ++ } ++ break; ++ case Q921_TEI_ID_REQUEST: ++ if (pri->localtype != BRI_NETWORK_PTMP) ++ break; ++ ++ tei = h->u.data[4] >> 1; ++ if (tei != Q921_TEI_GROUP) { ++ pri_message(pri, "got TEI request for unavailable TEI..\n"); ++ q921_send_teidenied(pri,((unsigned int)(h->u.data[1] << 8) + h->u.data[2]),h->u.data[4] >> 1); ++ break; ++ } ++ ++ for (tei=0;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) { ++ res = q931_receive(pri, (q931_h *)h->u.data, len-3, h->h.tei); ++ /* Send an RR if one wasn't sent already */ ++ if (pri->v_na[teio] != pri->v_r[teio]) ++ q921_rr(pri, 0, 0, pri->tei); ++ if (res == -1) { ++ return NULL; ++ } ++ if (res & Q931_RES_HAVEEVENT) ++ return &pri->ev; ++ } ++ break; ++ } ++ } else { ++ pri_message(pri, "XXX Unnumbered Information not implemented XXX\n"); ++ } + } + break; + case 2: + if (pri->debug & PRI_DEBUG_Q921_STATE) + pri_message(pri, "-- Got Disconnect from peer.\n"); ++ if (pri->q921_state[teio] != Q921_LINK_CONNECTION_ESTABLISHED) { ++ q921_send_dm(pri, 1, h->h.tei); ++ return NULL; ++ } + /* Acknowledge */ +- q921_send_ua(pri, h->u.p_f); +- ev = q921_dchannel_down(pri); +- q921_start(pri, 0); ++ q921_send_ua(pri, h->u.p_f, h->h.tei); ++ ev = q921_dchannel_down(pri, h->h.tei); ++ if ((pri->localtype == BRI_CPE_PTMP) || (pri->localtype == BRI_CPE) || (pri->localtype == BRI_NETWORK)) { ++ /* release layer 2 */ ++ return NULL; ++ } ++ if ((pri->localtype == PRI_NETWORK) || (pri->localtype == PRI_CPE)){ ++ q921_start(pri, 0, 0); ++ } + return ev; + case 3: + if (h->u.m2 == 3) { +@@ -866,17 +1761,28 @@ + } + } + /* Send Unnumbered Acknowledgement */ +- q921_send_ua(pri, h->u.p_f); +- return q921_dchannel_up(pri); ++ q921_send_ua(pri, h->u.p_f, h->h.tei); ++ return q921_dchannel_up(pri, h->h.tei); + } else if (h->u.m2 == 0) { + /* It's a UA */ +- if (pri->q921_state == Q921_AWAITING_ESTABLISH) { ++ if (pri->q921_state[teio] == Q921_AWAITING_ESTABLISH) { + if (pri->debug & PRI_DEBUG_Q921_STATE) { + pri_message(pri, "-- Got UA from %s peer Link up.\n", h->h.c_r ? "cpe" : "network"); + } +- return q921_dchannel_up(pri); +- } else +- pri_error(pri, "!! Got a UA, but i'm in state %d\n", pri->q921_state); ++ return q921_dchannel_up(pri, h->h.tei); ++ } else { ++ pri_error(pri, "!! Got a UA, but i'm in state %d\n", pri->q921_state[teio]); ++ if ((pri->localtype == BRI_CPE_PTMP) || (pri->localtype == BRI_CPE)) { ++ q921_reset(pri, h->h.tei, 1); ++ q921_send_teiverify(pri, h->h.tei); ++ } else { ++ /* send DM */ ++ // q921_send_dm(pri, 1, h->h.tei); ++#ifndef RELAX_TRB ++ q921_reset(pri, h->h.tei, 1); ++#endif ++ } ++ } + } else + pri_error(pri, "!! Weird frame received (m3=3, m2 = %d)\n", h->u.m2); + break; +@@ -901,19 +1807,42 @@ + /* Discard FCS */ + len -= 2; + +- if (!pri->master && pri->debug & PRI_DEBUG_Q921_DUMP) +- q921_dump(pri, h, len, pri->debug & PRI_DEBUG_Q921_RAW, 0); +- + /* Check some reject conditions -- Start by rejecting improper ea's */ + if (h->h.ea1 || !(h->h.ea2)) + return NULL; ++ if ((pri->localtype == PRI_CPE) || (pri->localtype == PRI_NETWORK)) { ++ /* Check for broadcasts - not yet handled (for PRI) */ ++ if (h->h.tei == Q921_TEI_GROUP) { ++ return NULL; ++ } ++ } else if ((pri->localtype == BRI_CPE) || (pri->localtype == BRI_CPE_PTMP)) { ++ if ((h->h.tei != pri->tei) && (h->h.tei != Q921_TEI_GROUP)) { ++ return NULL; ++ } ++ } else if (pri->localtype == BRI_NETWORK_PTMP) { ++ /* discard anything from a strange TEI (strange == not assigned by us or the broadcast tei) */ ++ if (((h->h.tei < Q921_TEI_BASE) || (h->h.tei > Q921_TEI_BASE + Q921_MAX_TEIS)) && (h->h.tei != Q921_TEI_GROUP)) { ++ if (pri->debug & PRI_DEBUG_Q921_DUMP) ++ pri_message(pri, "Received a Q.921 message from strange/unassigned TEI %d.\n"); ++ return NULL; ++ } else { ++ if ((pri->q921_teis[h->h.tei - Q921_TEI_BASE] != 1) && (h->h.tei != Q921_TEI_GROUP)) { ++ if (pri->debug & PRI_DEBUG_Q921_DUMP) ++ pri_message(pri, "Received a Q.921 message from unassigned TEI %d.. Sending DM and assigning.\n", h->h.tei); ++ // send DM ++ q921_send_dm(pri, 1, h->h.tei); ++ pri->q921_teis[h->h.tei - Q921_TEI_BASE] = 1; ++ } ++ } ++ } ++ ++ if (!pri->master && pri->debug & PRI_DEBUG_Q921_DUMP) ++ q921_dump(pri, h, len, pri->debug & PRI_DEBUG_Q921_RAW, 0); + +- /* Check for broadcasts - not yet handled */ +- if (h->h.tei == Q921_TEI_GROUP) +- return NULL; + ++ if (pri->localtype != BRI_NETWORK_PTMP) { + /* Check for SAPIs we don't yet handle */ +- if ((h->h.sapi != pri->sapi) || (h->h.tei != pri->tei)) { ++ if (((h->h.sapi != pri->sapi) && (h->h.sapi != Q921_SAPI_LAYER2_MANAGEMENT)) || ((h->h.tei != pri->tei) && (h->h.tei != Q921_TEI_GROUP) )) { + #ifdef PROCESS_SUBCHANNELS + /* If it's not us, try any subchannels we have */ + if (pri->subchannel) +@@ -921,10 +1850,16 @@ + else + #endif + return NULL; +- ++ } + } + ev = __q921_receive_qualified(pri, h, len); +- reschedule_t203(pri); ++ ++// Q921_GROUP_TEI ++ if (pri->localtype == BRI_CPE_PTMP) { ++ reschedule_t203(pri, pri->tei); ++ } else { ++ reschedule_t203(pri, h->h.tei); ++ } + return ev; + } + +@@ -938,14 +1873,58 @@ + 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); + } +diff -urNad libpri-1.2.3~/q931.c libpri-1.2.3/q931.c +--- libpri-1.2.3~/q931.c 2006-04-28 02:08:39.000000000 +1000 ++++ libpri-1.2.3/q931.c 2006-06-14 12:10:18.000000000 +1000 +@@ -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 +@@ -21,7 +23,7 @@ + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +- ++ + #include "compat.h" + #include "libpri.h" + #include "pri_internal.h" +@@ -31,6 +33,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -205,6 +208,14 @@ + #define LOC_INTERNATIONAL_NETWORK 0x7 + #define LOC_NETWORK_BEYOND_INTERWORKING 0xa + ++struct q921_call { ++ int tei; ++ int proc; ++ int channel; ++ q921_call *next; ++}; ++ ++ + static char *ie2str(int ie); + static char *msg2str(int msg); + +@@ -241,6 +252,7 @@ + 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; +@@ -253,8 +265,16 @@ + 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) { +@@ -272,14 +292,17 @@ + { + int x; + int pos=0; +-#ifdef NO_BRI_SUPPORT +- if (!ie->data[0] & 0x20) { +- pri_error(pri, "!! Not PRI type!?\n"); +- return -1; ++ if ((pri->localtype != PRI_CPE) && (pri->localtype != PRI_NETWORK)) { ++ // pri_error(pri, "!! BRI type %d!?\n",ie->data[0] & 0x03); ++ call->channelno = ie->data[0] & 0x03; ++ if (call->channelno == 3) { ++ call->channelno = -1; // any channel ++ } ++ return 0; + } +-#endif + #ifndef NOAUTO_CHANNEL_SELECTION_SUPPORT +- switch (ie->data[0] & 3) { ++ if ((pri->localtype == PRI_NETWORK) || (pri->localtype == PRI_CPE)) { ++ switch (ie->data[0] & 3) { + case 0: + call->justsignalling = 1; + break; +@@ -288,6 +311,7 @@ + default: + pri_error(pri, "!! Unexpected Channel selection %d\n", ie->data[0] & 3); + return -1; ++ } + } + #endif + if (ie->data[0] & 0x08) +@@ -349,10 +373,16 @@ + } + + /* Start with standard stuff */ +- if (pri->switchtype == PRI_SWITCH_GR303_TMC) ++ if (pri->switchtype == PRI_SWITCH_GR303_TMC) { + ie->data[pos] = 0x69; +- else ++ } else { ++ if ((pri->localtype == PRI_NETWORK) || (pri->localtype == PRI_CPE)) { + ie->data[pos] = 0xa1; ++ } else { ++ // BRI ++ ie->data[pos] = 0x80; ++ } ++ } + /* Add exclusive flag if necessary */ + if (call->chanflags & FLAG_EXCLUSIVE) + ie->data[pos] |= 0x08; +@@ -369,6 +399,7 @@ + } else + pos++; + if ((call->channelno > -1) || (call->slotmap != -1)) { ++ if ((pri->localtype == PRI_NETWORK) || (pri->localtype == PRI_CPE)) { + /* We'll have the octet 8.2 and 8.3's present */ + ie->data[pos++] = 0x83; + if (call->channelno > -1) { +@@ -384,11 +415,43 @@ + ie->data[pos++] = (call->slotmap & 0xff); + return pos + 2; + } +- } ++ } else { ++ // BRI ++ // pri_error(pri, "channelno %d, ds1no %d data %d\n",call->channelno,call->ds1no,ie->data[pos-1]); ++ if (pri->localtype == BRI_CPE_PTMP) { ++ if (msgtype == Q931_SETUP) { ++ // network, you decide! ++ if (call->channelno > -1) { ++ // ie->data[pos-1] = 0x83; ++ ie->data[pos-1] = 0x80 | call->channelno; ++ } ++ } else { ++ if (call->channelno > -1) { ++ ie->data[pos-1] |= call->channelno; ++ } ++ } ++ } else { ++ if (call->channelno > -1) { ++ ie->data[pos-1] |= call->channelno; ++ } ++ } ++ return pos + 2; ++ } ++ } else { ++ if (pri->localtype == BRI_CPE) { ++ ie->data[pos++] = 0x80 | 3; ++ return pos + 2; ++ } ++ } ++ + if (call->ds1no > 0) { + /* We're done */ + return pos + 2; + } ++ if (msgtype == Q931_RESTART_ACKNOWLEDGE) { ++ /* restart complete interface! */ ++ return 0; ++ } + pri_error(pri, "!! No channel map, no channel, and no ds1? What am I supposed to identify?\n"); + return -1; + } +@@ -734,10 +797,11 @@ + 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)) { + num[0] = 0; ++ pri_error(NULL, "q931_get_number received invalid len = %d\n", len); + return; + } + memcpy(num, src, len); +@@ -746,50 +810,78 @@ + + static FUNC_DUMP(dump_called_party_number) + { +- unsigned char cnum[256]; ++ char cnum[256]; ++ if (len >= 3) { ++ q931_get_number(cnum, sizeof(cnum), ie->data + 1, len - 3); ++ pri_message(pri, "%c Called Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d) '%s' ]\n", ++ prefix, len, ie->data[0] >> 7, ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07, npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f, cnum); ++ } else { ++ pri_error(pri, "Called Number (len=%2d) too short.\n", len); ++ } + +- q931_get_number(cnum, sizeof(cnum), ie->data + 1, len - 3); +- pri_message(pri, "%c Called Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d) '%s' ]\n", +- prefix, len, ie->data[0] >> 7, ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07, npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f, cnum); + } + + static FUNC_DUMP(dump_called_party_subaddr) + { +- unsigned char cnum[256]; +- q931_get_number(cnum, sizeof(cnum), ie->data + 1, len - 3); +- pri_message(pri, "%c Called Sub-Address (len=%2d) [ Ext: %d Type: %s (%d) O: %d '%s' ]\n", ++ char cnum[256]; ++ if (len >= 3) { ++ q931_get_number(cnum, sizeof(cnum), ie->data + 1, len - 3); ++ pri_message(pri, "%c Called Sub-Address (len=%2d) [ Ext: %d Type: %s (%d) O: %d '%s' ]\n", + prefix, len, ie->data[0] >> 7, + subaddrtype2str((ie->data[0] & 0x70) >> 4), (ie->data[0] & 0x70) >> 4, + (ie->data[0] & 0x08) >> 3, cnum); ++ } else { ++ pri_error(pri, "Called Party Subaddress (len=%2d) too short.\n", len); ++ } ++ + } + + static FUNC_DUMP(dump_calling_party_number) + { +- unsigned char cnum[256]; +- if (ie->data[0] & 0x80) +- q931_get_number(cnum, sizeof(cnum), ie->data + 1, len - 3); +- else +- q931_get_number(cnum, sizeof(cnum), ie->data + 2, len - 4); +- pri_message(pri, "%c Calling Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d)\n", prefix, len, ie->data[0] >> 7, ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07, npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f); +- if (ie->data[0] & 0x80) ++ char cnum[256]; ++ if ((ie->data[0] & 0x80) && (len >= 3)) { ++ q931_get_number(cnum, sizeof(cnum), ie->data + 1, len - 3); ++ pri_message(pri, "%c Calling Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d)\n", prefix, len, ie->data[0] >> 7, ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07, npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f); + pri_message(pri, "%c Presentation: %s (%d) '%s' ]\n", prefix, pri_pres2str(0), 0, cnum); +- else ++ } else if (len >= 4) { ++ q931_get_number(cnum, sizeof(cnum), ie->data + 2, len - 4); ++ pri_message(pri, "%c Calling Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d)\n", prefix, len, ie->data[0] >> 7, ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07, npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f); + pri_message(pri, "%c Presentation: %s (%d) '%s' ]\n", prefix, pri_pres2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f, cnum); ++ } else { ++ pri_error(pri, "Calling Party Number (len=%2d) too short.\n", len); ++ } ++ + } + + static FUNC_DUMP(dump_calling_party_subaddr) + { +- unsigned char cnum[256]; +- q931_get_number(cnum, sizeof(cnum), ie->data + 1, len - 3); +- pri_message(pri, "%c Calling Sub-Address (len=%2d) [ Ext: %d Type: %s (%d) O: %d '%s' ]\n", ++ char cnum[256]; ++ if (len >= 4) { ++ q931_get_number(cnum, sizeof(cnum), ie->data + 2, len - 4); ++ pri_message(pri, "%c Calling Sub-Address (len=%2d) [ Ext: %d Type: %s (%d) O: %d '%s' ]\n", + prefix, len, ie->data[0] >> 7, + subaddrtype2str((ie->data[0] & 0x70) >> 4), (ie->data[0] & 0x70) >> 4, + (ie->data[0] & 0x08) >> 3, cnum); ++ } else { ++ pri_error(pri, "Calling Party Subaddress (len=%2d) too short.\n", len); ++ } ++} ++ ++static FUNC_DUMP(dump_colp) ++{ ++ char cnum[256]; ++ if (len >= 4) { ++ q931_get_number(cnum, sizeof(cnum), ie->data + 2, len - 4); ++ pri_message(pri, "%c COLP (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d)\n", prefix, len, ie->data[0] >> 7, ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07, npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f); ++ pri_message(pri, "%c Presentation: %s (%d) '%s' ]\n", prefix, pri_pres2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f, cnum); ++ } else { ++ pri_error(pri, "COLP (len=%2d) too short.\n", len); ++ } + } + + static FUNC_DUMP(dump_redirecting_number) + { +- unsigned char cnum[256]; ++ char cnum[256]; + int i = 0; + /* To follow Q.931 (4.5.1), we must search for start of octet 4 by + walking through all bytes until one with ext bit (8) set to 1 */ +@@ -810,13 +902,17 @@ + } + } + while(!(ie->data[i++]& 0x80)); +- q931_get_number(cnum, sizeof(cnum), ie->data + i, ie->len - i); +- pri_message(pri, " '%s' ]\n", cnum); ++ if ((ie->len - i) >= 0) { ++ q931_get_number(cnum, sizeof(cnum), ie->data + i, ie->len - i); ++ pri_message(pri, " '%s' ]\n", cnum); ++ } else { ++ pri_error(pri, "Redirecting Number (len=%2d) too short.\n", len); ++ } + } + + static FUNC_DUMP(dump_connected_number) + { +- unsigned char cnum[256]; ++ char cnum[256]; + int i = 0; + /* To follow Q.931 (4.5.1), we must search for start of octet 4 by + walking through all bytes until one with ext bit (8) set to 1 */ +@@ -833,8 +929,12 @@ + } + } + while(!(ie->data[i++]& 0x80)); +- q931_get_number(cnum, sizeof(cnum), ie->data + i, ie->len - i); +- pri_message(pri, " '%s' ]\n", cnum); ++ if ((ie->len - i) >= 0) { ++ q931_get_number(cnum, sizeof(cnum), ie->data + i, ie->len - i); ++ pri_message(pri, " '%s' ]\n", cnum); ++ } else { ++ pri_error(pri, "Connected Number (len=%2d) too short.\n", len); ++ } + } + + +@@ -858,7 +958,7 @@ + } + } + while(!(ie->data[i++] & 0x80)); +- q931_get_number((unsigned char *) call->redirectingnum, sizeof(call->redirectingnum), ie->data + i, ie->len - i); ++ q931_get_number(call->redirectingnum, sizeof(call->redirectingnum), ie->data + i, ie->len - i); + return 0; + } + +@@ -866,7 +966,7 @@ + { + if (order > 1) + return 0; +- if (call->redirectingnum && *call->redirectingnum) { ++ if (call->redirectingnum && strlen(call->redirectingnum)) { + ie->data[0] = call->redirectingplan; + ie->data[1] = call->redirectingpres; + ie->data[2] = (call->redirectingreason & 0x0f) | 0x80; +@@ -878,67 +978,91 @@ + + static FUNC_DUMP(dump_redirecting_subaddr) + { +- unsigned char cnum[256]; +- q931_get_number(cnum, sizeof(cnum), ie->data + 2, len - 4); +- pri_message(pri, "%c Redirecting Sub-Address (len=%2d) [ Ext: %d Type: %s (%d) O: %d '%s' ]\n", ++ char cnum[256]; ++ if (len >= 4) { ++ q931_get_number(cnum, sizeof(cnum), ie->data + 2, len - 4); ++ pri_message(pri, "%c Redirecting Sub-Address (len=%2d) [ Ext: %d Type: %s (%d) O: %d '%s' ]\n", + prefix, len, ie->data[0] >> 7, + subaddrtype2str((ie->data[0] & 0x70) >> 4), (ie->data[0] & 0x70) >> 4, + (ie->data[0] & 0x08) >> 3, cnum); ++ } else { ++ pri_error(pri, "Redirecting Subaddress (len=%2d) too short.\n", len); ++ } ++ + } + + static FUNC_RECV(receive_calling_party_subaddr) + { + /* copy digits to call->callingsubaddr */ +- q931_get_number((unsigned char *) call->callingsubaddr, sizeof(call->callingsubaddr), ie->data + 1, len - 3); ++ if (len >= 4) { ++ q931_get_number(call->callingsubaddr, sizeof(call->callingsubaddr), ie->data + 2, len - 4); ++ } else { ++ pri_error(call->pri, "Calling Party Subaddress (len=%2d) too short.\n", len); ++ } + return 0; + } + + static FUNC_RECV(receive_called_party_number) + { +- /* copy digits to call->callednum */ +- q931_get_number((unsigned char *) call->callednum, sizeof(call->callednum), ie->data + 1, len - 3); +- call->calledplan = ie->data[0] & 0x7f; ++ /* copy digits to call->callednum or call->digits */ ++ if (len >= 3) { ++ if (msgtype == Q931_INFORMATION) { ++ q931_get_number(call->digits, sizeof(call->digits), ie->data + 1, len - 3); ++ } else { ++ q931_get_number(call->callednum, sizeof(call->callednum), ie->data + 1, len - 3); ++ } ++ call->calledplan = ie->data[0] & 0x7f; ++ } else { ++ pri_error(call->pri, "Called Party Number (len=%2d) too short.\n", len); ++ } + return 0; + } + + static FUNC_SEND(transmit_called_party_number) + { + ie->data[0] = 0x80 | call->calledplan; +- if (*call->callednum) ++ if (strlen(call->callednum)) + memcpy(ie->data + 1, call->callednum, strlen(call->callednum)); + return strlen(call->callednum) + 3; + } + + static FUNC_RECV(receive_calling_party_number) + { +- u_int8_t *data; +- size_t length; +- +- if (ie->data[0] & 0x80) { +- data = ie->data + 1; +- length = len - 3; +- call->callerpres = 0; /* PI presentation allowed SI user-provided, not screened */ ++/// callerani!! ++ if (strlen(call->callernum)) { ++ call->callerplanuser = ie->data[0] & 0x7f; + } else { +- data = ie->data + 2; +- length = len - 4; +- call->callerpres = ie->data[1] & 0x7f; ++ call->callerplan = ie->data[0] & 0x7f; + } + +- if (call->callerpres == PRES_ALLOWED_NETWORK_NUMBER || +- call->callerpres == PRES_PROHIB_NETWORK_NUMBER) { +- q931_get_number((u_int8_t *)call->callerani, sizeof(call->callerani), data, length); +- call->callerplanani = ie->data[0] & 0x7f; +- +- if (!*call->callernum) { /*Copy ANI to CallerID if CallerID is not already set */ +- libpri_copy_string(call->callernum, call->callerani, sizeof(call->callernum)); +- call->callerplan = call->callerplanani; +- } +- ++ if (ie->data[0] & 0x80) { ++ if (len >= 3) { ++ if (strlen(call->callernum)) { ++ // got A NUM already (this is not 100% correct, but the network should do it this way to protect bad implementations ++ q931_get_number(call->callerani, sizeof(call->callerani), ie->data + 1, len - 3); ++ call->callerpresuser = 0; /* PI presentation allowed ++ SI user-provided, not screened */ ++ } else { ++ q931_get_number(call->callernum, sizeof(call->callernum), ie->data + 1, len - 3); ++ call->callerpres = 0; /* PI presentation allowed ++ SI user-provided, not screened */ ++ } + } else { +- q931_get_number((u_int8_t *)call->callernum, sizeof(call->callernum), data, length); +- call->callerplan = ie->data[0] & 0x7f; ++ pri_error(call->pri, "Calling Party Number (len=%2d) too short.\n", len); + } +- ++ } else { ++ if (len >= 4) { ++ if (strlen(call->callernum)) { ++ q931_get_number(call->callerani, sizeof(call->callerani), ie->data + 2, len - 4); ++ call->callerpresuser = ie->data[1] & 0x7f; ++ } else { ++ q931_get_number(call->callernum, sizeof(call->callernum), ie->data + 2, len - 4); ++ call->callerpres = ie->data[1] & 0x7f; ++ } ++ } else { ++ pri_error(call->pri, "Calling Party Number (len=%2d) too short.\n", len); ++ } ++ } + return 0; + } + +@@ -946,7 +1070,7 @@ + { + 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; + } +@@ -964,11 +1088,89 @@ + 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); +@@ -1050,22 +1252,41 @@ + data++; + len--; + } +- q931_get_number((unsigned char *) call->callername, sizeof(call->callername), data, len - 2); ++ if (msgtype == Q931_SETUP) { ++ /* we treat display IEs in the SETUP msg as callername */ ++ if (len >= 2) { ++ q931_get_number(call->callername, sizeof(call->callername), data, len - 2); ++ } else { ++ pri_error(call->pri, "Display (len=%2d) too short.\n", len); ++ } ++ } else { ++ /* in other msgs we will pass it as text to chan_zap */ ++ if (len >= 2) { ++ q931_get_number(call->display, sizeof(call->display), data, len - 2); ++ } else { ++ pri_error(call->pri, "Display (len=%2d) too short.\n", len); ++ } ++ } + return 0; + } + + static FUNC_SEND(transmit_display) + { + int i; +- if ((pri->switchtype != PRI_SWITCH_NI1) && (pri->switchtype != PRI_SWITCH_QSIG) +- && *call->callername) { ++ int cpe = pri->localtype == BRI_CPE || pri->localtype == BRI_CPE_PTMP || pri->localtype == PRI_CPE; ++ if ((pri->switchtype != PRI_SWITCH_NI1) && (pri->switchtype != PRI_SWITCH_QSIG) && strlen(call->callername) && !cpe) { + i = 0; + if(pri->switchtype != PRI_SWITCH_EUROISDN_E1) { + ie->data[0] = 0xb1; + ++i; + } +- memcpy(ie->data + i, call->callername, strlen(call->callername)); +- return 2 + i + strlen(call->callername); ++ if (msgtype == Q931_SETUP_ACKNOWLEDGE) { ++ memcpy(ie->data + i, call->display, strlen(call->display)); ++ return 2 + i + strlen(call->display); ++ } else { ++ memcpy(ie->data + i, call->callername, strlen(call->callername)); ++ return 2 + i + strlen(call->callername); ++ } + } + return 0; + } +@@ -1112,6 +1333,111 @@ + return 0; + } + ++ #if 0 ++ static FUNC_RECV(receive_facility_kpj) ++ { ++ unsigned char cpt_tag, cp_len, invoke_id_tag, invoke_id_len, operation_value_len, operation_value_tag; ++ unsigned char arg_len = 0; ++ unsigned char pos = 0; ++ short invoke_id = 0, operation_value = 0; ++ if ((ie->data[pos++] & 0x1F) == 0x11) { ++ /* service discriminator == supplementary services */ ++ cpt_tag = ie->data[pos++] & 0x1F; ++ cp_len = ie->data[pos++]; ++ switch (cpt_tag) { ++ case 1: /* invoke */ ++ invoke_id_tag = ie->data[pos++]; ++ if (invoke_id_tag != 0x02) { ++ // pri_error(call->pri, "invoke id tag != 0x02\n"); ++ break; ++ } ++ invoke_id_len = ie->data[pos++]; // 4 ++ while (invoke_id_len > 0) { ++ invoke_id = (invoke_id << 8) | (ie->data[pos++] & 0xFF); ++ invoke_id_len--; ++ } ++ operation_value_tag = ie->data[pos++]; ++ if (operation_value_tag != 0x02) { ++ // pri_error(call->pri, "operation value tag != 0x02\n"); ++ break; ++ } ++ operation_value_len = ie->data[pos++]; ++ while (operation_value_len > 0) { ++ operation_value = (operation_value << 8) | (ie->data[pos++] & 0xFF); ++ operation_value_len--; ++ } ++ arg_len = ie->len - pos; ++ switch (operation_value) { ++ case 0x06: /* ECT execute */ ++ call->facility = operation_value; ++ break; ++ case 0x0D: /* call deflection */ ++ call->facility = operation_value; ++ /* dirty hack! */ ++ arg_len -= 6; ++ if (arg_len > 0) { ++ pos += 6; ++ q931_get_number(call->redirectingnum, sizeof(call->redirectingnum), ie->data + pos, arg_len); ++ } ++ /* now retrieve the number */ ++ break; ++ case 0x22: /* AOC-D */ ++ break; ++ case 0x24: /* AOC-E */ ++ break; ++ } ++ break; ++ case 2: /* return result */ ++ break; ++ case 3: /* return error */ ++ break; ++ case 4: /* reject */ ++ break; ++ } ++ } else { ++ /* OLD DIRTY ULAW HACK */ ++ if (ie->len < 14) { ++ pri_error(call->pri, "!! Facility message shorter than 14 bytes\n"); ++ return 0; ++ } ++ if (ie->data[13] + 14 == ie->len) { ++ q931_get_number(call->callername, sizeof(call->callername) - 1, ie->data + 14, ie->len - 14); ++ } ++ call->facility = 0x0; ++ } ++ return 0; ++ } ++ ++ static FUNC_SEND(transmit_facility_kpj) ++ { ++ int i = 0; ++ return i; ++ if (call->aoc && (pri->switchtype == PRI_SWITCH_EUROISDN_E1) && ((pri->localtype == BRI_NETWORK) || (pri->localtype == BRI_NETWORK_PTMP) || (pri->localtype == PRI_NETWORK))) { ++ ie->data[0] = 0x90; /* PP remote operations */ ++ ie->data[i++] = 0x00; /* component tag */ ++ ie->data[i++] = 0x02; /* invoke id tag */ ++ ie->data[i++] = 0x02; /* invoke id len */ ++ ie->data[i++] = 0x34; /* invoke id */ ++ ie->data[i++] = 0x56; /* invoke id */ ++ ie->data[i++] = 0x02; /* operation value tag */ ++ ie->data[i++] = 0x01; /* operation value len */ ++ switch (msgtype) { ++ case Q931_SETUP: ++ ie->data[i++] = 0x26; /* operation value AOC-S */ ++ break; ++ case Q931_DISCONNECT: ++ ie->data[i++] = 0x24; /* operation value AOC-E */ ++ break; ++ default: ++ ie->data[i++] = 0x22; /* operation value AOC-D */ ++ break; ++ } ++ // ARGUMENTS! ++ } ++ // return 2 + i; ++ } ++#endif ++ + static FUNC_SEND(transmit_facility) + { + struct apdu_event *tmp; +@@ -1138,6 +1464,182 @@ + return i + 2; + } + ++#if 0 ++static FUNC_SEND(transmit_facility) ++{ ++ int i = 0, j, first_i, compsp = 0; ++ struct rose_component *comp, *compstk[10]; ++ unsigned char namelen = strlen(call->callername); ++ ++ if ((pri->switchtype == PRI_SWITCH_NI2) && (namelen > 15)) ++ namelen = 15; /* According to GR-1367, for NI2 switches it can't be > 15 characters */ ++ if ((namelen > 0) && ((pri->switchtype == PRI_SWITCH_QSIG) || ++ ((pri->switchtype == PRI_SWITCH_NI2) && (pri->localtype == PRI_NETWORK)))) { ++ do { ++ first_i = i; ++ ie->data[i] = 0x80 | Q932_PROTOCOL_EXTENSIONS; ++ i++; ++ /* Interpretation component */ ++ ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, ie->data, i, 0x00 /* Discard unrecognized invokes */); ++ ++ /* Invoke ID */ ++ ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, ie->data, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ /* Invoke component contents */ ++ /* Invoke ID */ ++ ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, ie->data, i, ++pri->last_invoke); ++ ++ /* Operation Tag */ ++ ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, ie->data, i, SS_CNID_CALLINGNAME); ++ ++ /* Arugement Tag */ ++ j = asn1_string_encode(ROSE_NAME_PRESENTATION_ALLOWED_SIMPLE, &ie->data[i], len - i, 15, call->callername, namelen); ++ if (j < 0) { ++ i = first_i; ++ break; ++ } ++ i += j; ++ ++ /* Fix length of stacked components */ ++ while(compsp > 0) { ++ ASN1_FIXUP(compstk, compsp, ie->data, i); ++ } ++ } while (0); ++ } ++ if (/*(pri->switchtype == PRI_SWITCH_EUROISDN_E1) &&*/ call->redirectingnum && strlen(call->redirectingnum)) { ++ if (!(first_i = i)) { ++ /* Add protocol information header */ ++ ie->data[i++] = 0x80 | Q932_PROTOCOL_ROSE; ++ } ++ ++ /* ROSE invoke component */ ++ ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, ie->data, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ /* ROSE invokeId component */ ++ ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, ie->data, i, ++pri->last_invoke); ++ ++ /* ROSE operationId component */ ++ ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, ie->data, i, ROSE_DIVERTING_LEG_INFORMATION2); ++ ++ /* ROSE ARGUMENT component */ ++ ASN1_ADD_SIMPLE(comp, 0x30, ie->data, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ /* ROSE DivertingLegInformation2.diversionCounter component */ ++ /* Always is 1 because other isn't available in the current design */ ++ ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, ie->data, i, 1); ++ ++ /* ROSE DivertingLegInformation2.diversionReason component */ ++ ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, ie->data, i, redirectingreason_from_q931(pri, call->redirectingreason)); ++ ++ /* ROSE DivertingLegInformation2.divertingNr component */ ++ ASN1_ADD_SIMPLE(comp, 0xA1, ie->data, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ /* Redirecting information always not screened */ ++ switch(call->redirectingpres) { ++ case PRES_ALLOWED_USER_NUMBER_NOT_SCREENED: ++ case PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN: ++ if (call->redirectingnum && strlen(call->redirectingnum)) { ++ ASN1_ADD_SIMPLE(comp, 0xA0, ie->data, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ /* NPI of redirected number is not supported in the current design */ ++ ASN1_ADD_SIMPLE(comp, 0xA1, ie->data, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, ie->data, i, typeofnumber_from_q931(pri, call->redirectingplan >> 4)); ++ ++ j = asn1_string_encode(ASN1_NUMERICSTRING, &ie->data[i], len - i, 20, call->redirectingnum, strlen(call->redirectingnum)); ++ if (j < 0) { ++ i = first_i; ++ goto finish2; ++ } ++ i += j; ++ ASN1_FIXUP(compstk, compsp, ie->data, i); ++ ASN1_FIXUP(compstk, compsp, ie->data, i); ++ break; ++ } ++ /* fall through */ ++ case PRES_PROHIB_USER_NUMBER_PASSED_SCREEN: ++ case PRES_PROHIB_USER_NUMBER_NOT_SCREENED: ++ ASN1_ADD_SIMPLE(comp, 0x81, ie->data, i); ++ break; ++ /* Don't know how to handle this */ ++ case PRES_ALLOWED_NETWORK_NUMBER: ++ case PRES_PROHIB_NETWORK_NUMBER: ++ case PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN: ++ case PRES_PROHIB_USER_NUMBER_FAILED_SCREEN: ++ ASN1_ADD_SIMPLE(comp, 0x81, ie->data, i); ++ break; ++ default: ++ pri_message(pri, "!! Undefined presentation value for redirecting number: %d\n", call->redirectingpres); ++ case PRES_NUMBER_NOT_AVAILABLE: ++ ASN1_ADD_SIMPLE(comp, 0x82, ie->data, i); ++ break; ++ } ++ ASN1_FIXUP(compstk, compsp, ie->data, i); ++ ++ /* ROSE DivertingLegInformation2.originalCalledNr component */ ++ /* This information isn't supported by current design - duplicate divertingNr */ ++ ASN1_ADD_SIMPLE(comp, 0xA2, ie->data, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ /* Redirecting information always not screened */ ++ switch(call->redirectingpres) { ++ case PRES_ALLOWED_USER_NUMBER_NOT_SCREENED: ++ case PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN: ++ if (call->redirectingnum && strlen(call->redirectingnum)) { ++ ASN1_ADD_SIMPLE(comp, 0xA0, ie->data, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ ASN1_ADD_SIMPLE(comp, 0xA1, ie->data, i); ++ ASN1_PUSH(compstk, compsp, comp); ++ ++ ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, ie->data, i, typeofnumber_from_q931(pri, call->redirectingplan >> 4)); ++ ++ j = asn1_string_encode(ASN1_NUMERICSTRING, &ie->data[i], len - i, 20, call->redirectingnum, strlen(call->redirectingnum)); ++ if (j < 0) { ++ i = first_i; ++ goto finish2; ++ } ++ i += j; ++ ASN1_FIXUP(compstk, compsp, ie->data, i); ++ ASN1_FIXUP(compstk, compsp, ie->data, i); ++ break; ++ } ++ /* fall through */ ++ case PRES_PROHIB_USER_NUMBER_PASSED_SCREEN: ++ case PRES_PROHIB_USER_NUMBER_NOT_SCREENED: ++ ASN1_ADD_SIMPLE(comp, 0x81, ie->data, i); ++ break; ++ /* Don't know how to handle this */ ++ case PRES_ALLOWED_NETWORK_NUMBER: ++ case PRES_PROHIB_NETWORK_NUMBER: ++ case PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN: ++ case PRES_PROHIB_USER_NUMBER_FAILED_SCREEN: ++ ASN1_ADD_SIMPLE(comp, 0x81, ie->data, i); ++ break; ++ default: ++ pri_message(pri, "!! Undefined presentation value for redirecting number: %d\n", call->redirectingpres); ++ case PRES_NUMBER_NOT_AVAILABLE: ++ ASN1_ADD_SIMPLE(comp, 0x82, ie->data, i); ++ break; ++ } ++ ASN1_FIXUP(compstk, compsp, ie->data, i); ++ ++ /* Fix length of stacked components */ ++ while(compsp > 0) { ++ ASN1_FIXUP(compstk, compsp, ie->data, i); ++ } ++ } ++finish2: ++ return (i ? i+2 : 0); ++} ++#endif ++ + static FUNC_RECV(receive_facility) + { + int i = 0; +@@ -1346,6 +1848,7 @@ + pri_message(pri, " ]\n"); + } + ++ + static FUNC_DUMP(dump_time_date) + { + pri_message(pri, "%c Time Date (len=%2d) [ ", prefix, len); +@@ -1366,7 +1869,7 @@ + + static FUNC_DUMP(dump_keypad_facility) + { +- char tmp[64]; ++ char tmp[64] = ""; + + if (ie->len == 0 || ie->len > sizeof(tmp)) + return; +@@ -1377,28 +1880,49 @@ + + static FUNC_RECV(receive_keypad_facility) + { +- int mylen; ++ int mylen = 0; + + if (ie->len == 0) + return -1; + + if (ie->len > (sizeof(call->digitbuf) - 1)) +- mylen = (sizeof(call->digitbuf) - 1); ++ mylen = sizeof(call->digitbuf) - 1; + else + mylen = ie->len; + +- memcpy(call->digitbuf, ie->data, mylen); ++ strncpy(call->digitbuf, (char *) ie->data, mylen); + +- call->digitbuf[mylen] = 0; ++ /* I must be really neurotic */ ++ call->digitbuf[sizeof(call->digitbuf)-1] = '\0'; + + return 0; + } + ++static FUNC_RECV(receive_time_date) ++{ ++ return 0; ++} ++ ++static FUNC_SEND(transmit_time_date) { ++ time_t now; ++ struct tm *timedate; ++ time(&now); ++ timedate = localtime(&now); ++ ie->data[0] = timedate->tm_year - 100; // 1900+ ++ ie->data[1] = timedate->tm_mon + 1; ++ ie->data[2] = timedate->tm_mday; ++ ie->data[3] = timedate->tm_hour; ++ ie->data[4] = timedate->tm_min; ++ return 7; ++} ++ ++ ++ + static FUNC_DUMP(dump_display) + { + int x, y; + char *buf = malloc(len + 1); +- char tmp[80]; ++ char tmp[80]=""; + if (buf) { + x=y=0; + if ((x < ie->len) && (ie->data[x] & 0x80)) { +@@ -1413,7 +1937,7 @@ + } + } + +-static void dump_ie_data(unsigned char *c, int len) ++static void dump_ie_data(struct pri *pri, unsigned char *c, int len) + { + char tmp[1024] = ""; + int x=0; +@@ -1423,7 +1947,7 @@ + ((*c >= 'a') && (*c <= 'z')) || + ((*c >= '0') && (*c <= '9'))) { + if (!lastascii) { +- if (*tmp) { ++ if (strlen(tmp)) { + tmp[x++] = ','; + tmp[x++] = ' '; + } +@@ -1435,7 +1959,7 @@ + if (lastascii) { + tmp[x++] = '\''; + } +- if (*tmp) { ++ if (strlen(tmp)) { + tmp[x++] = ','; + tmp[x++] = ' '; + } +@@ -1448,14 +1972,14 @@ + } + if (lastascii) + tmp[x++] = '\''; +- pri_message(NULL, tmp); ++ pri_message(pri, tmp); + } + + static FUNC_DUMP(dump_facility) + { + pri_message(pri, "%c Facility (len=%2d, codeset=%d) [ ", prefix, len, Q931_IE_CODESET(full_ie)); +- dump_ie_data(ie->data, ie->len); +- pri_message(NULL, " ]\n"); ++ dump_ie_data(pri, ie->data, ie->len); ++ pri_message(pri, " ]\n"); + } + + static FUNC_DUMP(dump_network_spec_fac) +@@ -1465,7 +1989,7 @@ + pri_message(pri, code2str(ie->data[1], facilities, sizeof(facilities) / sizeof(facilities[0]))); + } + else +- dump_ie_data(ie->data, ie->len); ++ dump_ie_data(pri, ie->data, ie->len); + pri_message(pri, " ]\n"); + } + +@@ -1932,8 +2456,8 @@ + { 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" }, + { 1, Q931_IE_FACILITY, "Facility" , dump_facility, receive_facility, transmit_facility }, + { 1, Q931_IE_REDIRECTION_NUMBER, "Redirection Number" }, +@@ -1942,11 +2466,11 @@ + { 1, Q931_IE_INFO_REQUEST, "Feature Request" }, + { 1, Q931_IE_FEATURE_IND, "Feature Indication" }, + { 1, Q931_IE_SEGMENTED_MSG, "Segmented Message" }, +- { 1, Q931_IE_CALL_IDENTITY, "Call Identity", dump_call_identity }, ++ { 1, Q931_IE_CALL_IDENTITY, "Call Identity", dump_call_identity, receive_call_identity, transmit_call_identity }, + { 1, Q931_IE_ENDPOINT_ID, "Endpoint Identification" }, + { 1, Q931_IE_NOTIFY_IND, "Notification Indicator", dump_notify, receive_notify, transmit_notify }, + { 1, Q931_DISPLAY, "Display", dump_display, receive_display, transmit_display }, +- { 1, Q931_IE_TIME_DATE, "Date/Time", dump_time_date }, ++ { 1, Q931_IE_TIME_DATE, "Date/Time", dump_time_date, receive_time_date, transmit_time_date }, + { 1, Q931_IE_KEYPAD_FACILITY, "Keypad Facility", dump_keypad_facility, receive_keypad_facility }, + { 0, Q931_IE_SIGNAL, "Signal", dump_signal }, + { 1, Q931_IE_SWITCHHOOK, "Switch-hook" }, +@@ -1954,6 +2478,7 @@ + { 1, Q931_IE_ESCAPE_FOR_EXT, "Escape for Extension" }, + { 1, Q931_IE_CALL_STATUS, "Call Status" }, + { 1, Q931_IE_CHANGE_STATUS, "Change Status" }, ++ { 1, Q931_COLP, "Connect Line ID Presentation", dump_colp}, + { 1, Q931_IE_CONNECTED_ADDR, "Connected Number", dump_connected_number }, + { 1, Q931_IE_CONNECTED_NUM, "Connected Number", dump_connected_number }, + { 1, Q931_IE_ORIGINAL_CALLED_NUMBER, "Original Called Number", dump_redirecting_number, receive_redirecting_number, transmit_redirecting_number }, +@@ -2024,7 +2549,7 @@ + { + if ((ie->ie & 0x80) != 0) + return 1; +- else ++ else + return 2 + ie->len; + } + +@@ -2054,10 +2579,10 @@ + break; + case 1: + cr = h->crv[0]; +- if (cr & 0x80) { ++ /* if (cr & 0x80) { + cr &= ~0x80; + cr |= 0x8000; +- } ++ } */ + break; + default: + pri_error(NULL, "Call Reference Length not supported: %d\n", h->crlen); +@@ -2071,14 +2596,14 @@ + int full_ie = Q931_FULL_IE(codeset, ie->ie); + int base_ie; + +- pri_message(NULL, "%c [", prefix); +- pri_message(NULL, "%02x", ie->ie); ++ pri_message(pri, "%c [", prefix); ++ pri_message(pri, "%02x", ie->ie); + if (!(ie->ie & 0x80)) { +- pri_message(NULL, " %02x", ielen(ie)-2); ++ pri_message(pri, " %02x", ielen(ie)-2); + for (x = 0; x + 2 < ielen(ie); ++x) +- pri_message(NULL, " %02x", ie->data[x]); ++ pri_message(pri, " %02x", ie->data[x]); + } +- pri_message(NULL, "]\n"); ++ pri_message(pri, "]\n"); + + /* Special treatment for shifts */ + if((full_ie & 0xf0) == Q931_LOCKING_SHIFT) +@@ -2098,14 +2623,46 @@ + pri_error(pri, "!! %c Unknown IE %d (len = %d)\n", prefix, base_ie, ielen(ie)); + } + +-static q931_call *q931_getcall(struct pri *pri, int cr) ++static q921_call *q921_getcall(struct pri *pri, struct q931_call *c, int tei) ++{ ++ q921_call *cur; ++ cur = c->phones; ++ while(cur) { ++ if (cur->tei == tei) { ++ return cur; ++ } ++ cur = cur->next; ++ } ++ /* No call exists, make a new one */ ++ if (pri->debug & PRI_DEBUG_Q921_STATE) ++ pri_message(pri, "-- Making new q921 call for cref %d tei %d\n", c->cr, tei); ++ cur = malloc(sizeof(struct q921_call)); ++ memset(cur, 0, sizeof(cur)); ++ cur->tei = tei; ++ cur->proc = 0; ++ cur->channel = -1; ++ cur->next = c->phones; ++ c->phones = cur; ++ return cur; ++} ++ ++static q931_call *q931_getcall(struct pri *pri, int cr, int tei) + { + q931_call *cur, *prev; + cur = *pri->callpool; + prev = NULL; + while(cur) { +- if (cur->cr == cr) +- return cur; ++ if ((pri->localtype == BRI_NETWORK_PTMP) && (tei >= 0)) { ++ // hmm...ok, we might be the 1st responding to the setup ++ // or it is really our call ++ if ((cur->cr == cr) && ((cur->tei == tei) || (cur->tei == 127))) ++ return cur; ++ // or we might not be the 1st responding, then we need to clone ++ // the call struct to hangup properly ++ } else { ++ if (cur->cr == cr) ++ return cur; ++ } + prev = cur; + cur = cur->next; + } +@@ -2118,6 +2675,7 @@ + /* Call reference */ + cur->cr = cr; + cur->pri = pri; ++ cur->tei = tei; + /* Append to end of list */ + if (prev) + prev->next = cur; +@@ -2133,24 +2691,42 @@ + do { + cur = *pri->callpool; + pri->cref++; +- if (pri->cref > 32767) +- pri->cref = 1; ++ if ((pri->localtype == PRI_NETWORK) || (pri->localtype == PRI_CPE)) { ++ if (pri->cref > 32767) ++ pri->cref = 1; ++ } else { ++ // BRI ++ if (pri->cref > 255) ++ pri->cref = 1; ++ } + while(cur) { +- if (cur->cr == (0x8000 | pri->cref)) +- break; ++ if ((pri->localtype == PRI_NETWORK) || (pri->localtype == PRI_CPE)) { ++ if (cur->cr == (0x8000 | pri->cref)) ++ break; ++ } else { ++ // BRIs have only 1 bye cref ++ if (cur->cr == (0x80 | pri->cref)) ++ break; ++ } + cur = cur->next; + } + } while(cur); +- return q931_getcall(pri, pri->cref | 0x8000); ++ if ((pri->localtype == PRI_NETWORK) || (pri->localtype == PRI_CPE)) { ++ return q931_getcall(pri, pri->cref | 0x8000, 0); ++ } else { ++ // BRI ++ return q931_getcall(pri, pri->cref | 0x80, 0); ++ } + } + +-static void q931_destroy(struct pri *pri, int cr, q931_call *c) ++static void q931_destroy(struct pri *pri, int cr, q931_call *c, int tei) + { + q931_call *cur, *prev; + prev = NULL; + cur = *pri->callpool; + while(cur) { +- if ((c && (cur == c)) || (!c && (cur->cr == cr))) { ++// if ((c && (cur == c)) || (!c && (cur->cr == cr))) { ++ if ((c && (cur == c)) || (!c && ((cur->cr == cr) && ((pri->localtype != BRI_NETWORK_PTMP) || (cur->tei == tei))))) { + if (prev) + prev->next = cur->next; + else +@@ -2159,6 +2735,8 @@ + pri_message(pri, "NEW_HANGUP DEBUG: Destroying the call, ourstate %s, peerstate %s\n",callstate2str(cur->ourcallstate),callstate2str(cur->peercallstate)); + if (cur->retranstimer) + pri_schedule_del(pri, cur->retranstimer); ++ if (cur->t303timer) ++ pri_schedule_del(pri, cur->t303timer); + pri_call_apdu_queue_cleanup(cur); + free(cur); + return; +@@ -2169,16 +2747,16 @@ + pri_error(pri, "Can't destroy call %d!\n", cr); + } + +-static void q931_destroycall(struct pri *pri, int cr) ++static void q931_destroycall(struct pri *pri, int cr, int tei) + { +- return q931_destroy(pri, cr, NULL); ++ return q931_destroy(pri, cr, NULL, tei); + } + + + void __q931_destroycall(struct pri *pri, q931_call *c) + { + if (pri && c) +- q931_destroy(pri,0, c); ++ q931_destroy(pri,0, c, c->tei); + return; + } + +@@ -2290,6 +2868,10 @@ + { + unsigned int x; + int full_ie = Q931_FULL_IE(codeset, ie->ie); ++ if (ielen(ie) > Q931_IE_MAX_LEN) { ++ pri_error(pri, "!! Invalid IE length %d (len = %d)\n", full_ie, ielen(ie)); ++ return -1; ++ } + if (pri->debug & PRI_DEBUG_Q931_STATE) + pri_message(pri, "-- Processing IE %d (cs%d, %s)\n", ie->ie, codeset, ie2str(full_ie)); + for (x=0;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 */ +@@ -2330,13 +2927,23 @@ + mh->f = 0; + *hb = h; + *mhb = mh; +- *len -= 5; +- + } + +-static int q931_xmit(struct pri *pri, q931_h *h, int len, int cr) ++static int q931_xmit(struct pri *pri, q931_h *h, int len, int cr, int tei) + { +- q921_transmit_iframe(pri, h, len, cr); ++ q931_mh *mh; ++ if (pri->localtype == BRI_NETWORK_PTMP) { ++ mh = (q931_mh *)(h->contents + 1); ++ if (mh->msg == Q931_SETUP) { ++ q921_transmit_uframe(pri, h, len, cr, tei); ++ } else { ++ q921_transmit_iframe(pri, h, len, cr, tei); ++ } ++ } else if (pri->localtype == BRI_CPE_PTMP) { ++ q921_transmit_iframe(pri, h, len, cr, pri->tei); ++ } else { ++ q921_transmit_iframe(pri, h, len, cr, tei); ++ } + /* The transmit operation might dump the q921 header, so logging the q931 + message body after the transmit puts the sections of the message in the + right order in the log */ +@@ -2362,7 +2969,11 @@ + + memset(buf, 0, sizeof(buf)); + len = sizeof(buf); +- init_header(pri, c, buf, &h, &mh, &len); ++ if ((pri->localtype == PRI_NETWORK) || (pri->localtype == PRI_CPE)) { ++ init_header(pri, c, buf, &h, &mh, &len, 0); ++ } else { ++ init_header(pri, c, buf, &h, &mh, &len, 1); ++ } + mh->msg = msgtype; + x=0; + codeset = 0; +@@ -2397,11 +3008,34 @@ + } + /* Invert the logic */ + len = sizeof(buf) - len; +- q931_xmit(pri, h, len, 1); ++ if (pri->localtype == BRI_CPE_PTMP) { ++ q931_xmit(pri, h, len, 1, pri->tei); ++ } else { ++ q931_xmit(pri, h, len, 1, c->tei); ++ } + c->acked = 1; + return 0; + } + ++static int facility_ies[] = { Q931_IE_FACILITY, -1 }; ++ ++#if 0 ++int q931_facility_kpj(struct pri *pri, q931_call *c, int operation, char *arguments) ++{ ++ switch (operation) { ++ case 0x26: c->aoc = 1; ++ break; ++ case 0x24: c->aoc = 1; ++ break; ++ case 0x22: c->aoc = 1; ++ break; ++ default: ++ return -1; ++ } ++ return send_message(pri, c, Q931_FACILITY, facility_ies); ++} ++#endif ++ + static int status_ies[] = { Q931_CAUSE, Q931_CALL_STATE, -1 }; + + static int q931_status(struct pri *pri, q931_call *c, int cause) +@@ -2439,17 +3073,45 @@ + return send_message(pri, c, Q931_INFORMATION, information_ies); + } + ++static int information_display_ies[] = { Q931_DISPLAY, -1 }; ++ ++int q931_information_display(struct pri *pri, q931_call *c, char *display) ++{ ++ int res=0; ++ char temp[256]; ++ if (!display) return -1; ++ strncpy(temp, c->callername, sizeof(temp)); ++ strncpy(c->callername, display, sizeof(c->callername)); ++ res = send_message(pri, c, Q931_INFORMATION, information_display_ies); ++ strncpy(c->callername, temp, sizeof(c->callername)); ++ return res; ++} ++ ++int q931_add_display(struct pri *pri, q931_call *c, char *display) ++{ ++ strncpy(c->display, display, sizeof(c->display)); ++ return 0; ++} ++ ++/* static int information_special_ies[] = { Q931_IE_SPECIAL, -1 }; ++static int q931_information_special(struct pri *pri, q931_call *c) ++{ ++ return send_message(pri, c, Q931_FACILITY, information_special_ies); ++} ++*/ ++ ++ + static int restart_ack_ies[] = { Q931_CHANNEL_IDENT, Q931_RESTART_INDICATOR, -1 }; + + static int restart_ack(struct pri *pri, q931_call *c) + { + c->ourcallstate = Q931_CALL_STATE_NULL; + c->peercallstate = Q931_CALL_STATE_NULL; ++ c->chanflags &= ~FLAG_PREFERRED; ++ c->chanflags |= FLAG_EXCLUSIVE; + return send_message(pri, c, Q931_RESTART_ACKNOWLEDGE, restart_ack_ies); + } + +-static int facility_ies[] = { Q931_IE_FACILITY, -1 }; +- + int q931_facility(struct pri*pri, q931_call *c) + { + return send_message(pri, c, Q931_FACILITY, facility_ies); +@@ -2463,7 +3125,6 @@ + if ((info > 0x2) || (info < 0x00)) + return 0; + } +- + if (info >= 0) + c->notify = info & 0x7F; + else +@@ -2506,6 +3167,8 @@ + + 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; +@@ -2532,8 +3195,12 @@ + 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) { +@@ -2544,14 +3211,130 @@ + c->progressmask = 0; + c->ourcallstate = Q931_CALL_STATE_CALL_RECEIVED; + c->peercallstate = Q931_CALL_STATE_CALL_DELIVERED; ++ c->alert = 1; + c->alive = 1; +- return send_message(pri, c, Q931_ALERTING, alerting_ies); ++ if ((pri->localtype == PRI_NETWORK) || (pri->localtype == PRI_CPE)) { ++ return send_message(pri, c, Q931_ALERTING, alerting_ies); ++ } else { ++ if ((pri->localtype == BRI_NETWORK) || (pri->localtype == BRI_NETWORK_PTMP)) { ++ return send_message(pri, c, Q931_ALERTING, alerting_ies); ++ } else { ++ /* no PROGRESS_INDICATOR for BRI please */ ++ return send_message(pri, c, Q931_ALERTING, alerting_BRI_ies); ++ } ++ } + } + +-static int connect_ies[] = { Q931_CHANNEL_IDENT, Q931_PROGRESS_INDICATOR, -1 }; ++static int hold_acknowledge_ies[] = { -1 }; ++ ++int q931_hold_acknowledge(struct pri *pri, q931_call *c) ++{ ++ return send_message(pri, c, Q931_HOLD_ACKNOWLEDGE, hold_acknowledge_ies); ++} ++ ++static int hold_reject_ies[] = { Q931_CAUSE, -1 }; ++ ++int q931_hold_reject(struct pri *pri, q931_call *c) ++{ ++ c->cause = 12; ++ c->causecode = CODE_CCITT; ++ c->causeloc = LOC_PRIV_NET_LOCAL_USER; ++ return send_message(pri, c, Q931_HOLD_REJECT, hold_reject_ies); ++} ++ ++static int retrieve_acknowledge_ies[] = { Q931_CHANNEL_IDENT, -1 }; ++ ++int q931_retrieve_acknowledge(struct pri *pri, q931_call *c, int channel) ++{ ++ if (channel) ++ c->channelno = channel; ++ c->chanflags &= ~FLAG_PREFERRED; ++ c->chanflags |= FLAG_EXCLUSIVE; ++ return send_message(pri, c, Q931_RETRIEVE_ACKNOWLEDGE, retrieve_acknowledge_ies); ++} ++ ++static int retrieve_reject_ies[] = { -1 }; ++ ++int q931_retrieve_reject(struct pri *pri, q931_call *c) ++{ ++ return send_message(pri, c, Q931_RETRIEVE_REJECT, retrieve_reject_ies); ++} ++ ++static int suspend_acknowledge_ies[] = { Q931_DISPLAY, -1 }; ++ ++int q931_suspend_acknowledge(struct pri *pri, q931_call *c, char *display) ++{ ++ char tempcallername[256]; ++ int res; ++ c->ourcallstate = Q931_CALL_STATE_NULL; ++ c->peercallstate = Q931_CALL_STATE_NULL; ++ strncpy(tempcallername,c->callername,sizeof(tempcallername)); ++ strncpy(c->callername,display,sizeof(c->callername)); ++ res = send_message(pri, c, Q931_SUSPEND_ACKNOWLEDGE, suspend_acknowledge_ies); ++ strncpy(c->callername,tempcallername,sizeof(c->callername)); ++ __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; +@@ -2569,9 +3352,36 @@ + c->ourcallstate = 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; ++// pri->ev.hangup.cause = c->cause; ++ pri->ev.hangup.cause = PRI_CAUSE_SWITCH_CONGESTION; ++ pri->ev.hangup.call = c; ++ q931_hangup(pri, c, c->cause); ++} ++ + static void pri_connect_timeout(void *data) + { + struct q931_call *c = data; +@@ -2624,6 +3434,7 @@ + + 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; +@@ -2638,22 +3449,37 @@ + c->progressmask = PRI_PROG_CALLED_NOT_ISDN; + } else + c->progressmask = 0; +- c->ourcallstate = Q931_CALL_STATE_CONNECT_REQUEST; ++ if (network) { ++ /* WE decide when the call is up and active */ ++ c->ourcallstate = Q931_CALL_STATE_ACTIVE; ++ } else { ++ c->ourcallstate = Q931_CALL_STATE_CONNECT_REQUEST; ++ } + c->peercallstate = Q931_CALL_STATE_ACTIVE; + c->alive = 1; ++ c->con_acked = 0; + /* Setup timer */ + if (c->retranstimer) + pri_schedule_del(pri, c->retranstimer); + c->retranstimer = 0; +- if ((pri->localtype == PRI_CPE) && (!pri->subchannel)) ++ if (!network && (!pri->subchannel)) { ++ /* make sure that CPEs get a CONNECT_ACKNOWLEDGE */ + c->retranstimer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T313], pri_connect_timeout, c); +- return send_message(pri, c, Q931_CONNECT, connect_ies); ++ } ++ if ((pri->localtype != PRI_CPE) && (pri->localtype != BRI_CPE) && (pri->localtype != BRI_CPE_PTMP)) { ++ // networks may send datetime ++ return send_message(pri, c, Q931_CONNECT, connect_NET_ies); ++ } else { ++ return send_message(pri, c, Q931_CONNECT, connect_ies); ++ } + } + ++static int release_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; + c->ourcallstate = Q931_CALL_STATE_RELEASE_REQUEST; + /* c->peercallstate stays the same */ + if (c->alive) { +@@ -2669,7 +3495,14 @@ + } 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 +@@ -2681,7 +3514,7 @@ + int q931_restart(struct pri *pri, int channel) + { + struct q931_call *c; +- c = q931_getcall(pri, 0 | 0x8000); ++ c = q931_getcall(pri, 0 | 0x8000, 0); + if (!c) + return -1; + if (!channel) +@@ -2698,10 +3531,12 @@ + 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; + c->ourcallstate = Q931_CALL_STATE_DISCONNECT_REQUEST; + c->peercallstate = Q931_CALL_STATE_DISCONNECT_INDICATION; + if (c->alive) { +@@ -2713,14 +3548,27 @@ + 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_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 }; +@@ -2728,7 +3576,12 @@ + int q931_setup(struct pri *pri, q931_call *c, struct pri_sr *req) + { + int res; +- ++ ++ if (pri->localtype == BRI_NETWORK_PTMP) { ++ c->tei = 127; ++ } else { ++ c->tei = 0; ++ } + + c->transcapability = req->transmode; + c->transmoderate = TRANS_MODE_64_CIRCUIT; +@@ -2753,6 +3606,7 @@ + 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; +@@ -2812,14 +3666,19 @@ + res = send_message(pri, c, Q931_SETUP, gr303_setup_ies); + else if (c->justsignalling) + res = send_message(pri, c, Q931_SETUP, cis_setup_ies); ++ else if (pri->localtype == BRI_NETWORK || pri->localtype == BRI_NETWORK_PTMP) ++ res = send_message(pri, c, Q931_SETUP, setup_bri_ies); + else + res = send_message(pri, c, Q931_SETUP, setup_ies); ++ + if (!res) { + c->alive = 1; + /* make sure we call PRI_EVENT_HANGUP_ACK once we send/receive RELEASE_COMPLETE */ + c->sendhangupack = 1; + c->ourcallstate = Q931_CALL_STATE_CALL_INITIATED; + c->peercallstate = Q931_CALL_STATE_OVERLAP_SENDING; ++ c->t303timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T303], pri_setup_response_timeout, c); ++ c->t303running = 1; + } + return res; + +@@ -2835,7 +3694,11 @@ + if (cause > -1) { + c->cause = cause; + c->causecode = CODE_CCITT; +- c->causeloc = LOC_PRIV_NET_LOCAL_USER; ++ if ((pri->localtype == PRI_NETWORK) || (pri->localtype == BRI_NETWORK) || (pri->localtype == BRI_NETWORK_PTMP)) { ++ c->causeloc = LOC_PRIV_NET_LOCAL_USER; ++ } else { ++ c->causeloc = LOC_USER; ++ } + /* release_ies has CAUSE in it */ + res = send_message(pri, c, Q931_RELEASE_COMPLETE, release_ies); + } else +@@ -2860,6 +3723,117 @@ + return 0; + } + ++/* here we cleanly hangup the phones that responded to our call but didnt get the call */ ++int q921_hangup(struct pri *pri, q931_call *c, int tei) ++{ ++ q921_call *cur,*prev; ++ int tc; ++ int ttei; ++ int res=0; ++ ++ if (!pri || !c) ++ return -1; ++ ++ if (pri->localtype != BRI_NETWORK_PTMP){ ++ return 0; ++ } ++// pri_error(pri, "q921_hangup(%d, %d)\n", c->cr, tei); ++ ++ if (tei == 127) { ++ tei = c->tei; ++ } ++// pri_error(pri, "tei %d\n", tei); ++ ++ cur = c->phones; ++ ++ tc = c->cause; ++ ttei = c->tei; ++ while (cur) { ++ if (cur->tei != tei) { ++ c->cause = PRI_CAUSE_NORMAL_CLEARING; ++ c->tei = cur->tei; ++ if (pri->debug & PRI_DEBUG_Q921_STATE) ++ pri_message(pri, "sending RELEASE for TEI %d\n", cur->tei); ++ send_message(pri, c, Q931_RELEASE, release_ies); ++ } ++ prev = cur; ++ cur = cur->next; ++ if (prev) { ++ free(prev); ++ prev = NULL; ++ } ++ } ++ c->phones = NULL; ++ c->tei = ttei; ++ c->cause = tc; ++ ++ if (c->tei == 127) { ++ q931_destroycall(pri, c->cr, c->tei); ++ // make sure * frees the channel ++/* pri_error(pri, "returning PRI_EVENT_HANGUP_ACK\n"); ++ res = Q931_RES_HAVEEVENT; ++ pri->ev.hangup.channel = c->channelno; ++ pri->ev.e = PRI_EVENT_HANGUP_ACK; */ ++ } ++ return res; ++} ++ ++/* here we handle release_completes from the phones ++ because some (elmeg) phones do not send a disconnect ++ message when the phone is busy */ ++int q921_handle_hangup(struct pri *pri, q931_call *c, int tei) ++{ ++ q921_call *cur,*match,*prev=NULL; ++ int left=0; ++ int res=0; ++ ++ if (!pri || !c) ++ return -1; ++ ++ if (pri->localtype != BRI_NETWORK_PTMP){ ++ return 0; ++ } ++ ++ cur = c->phones; ++ ++ while (cur) { ++ if (cur->tei == tei) { ++ match = cur; ++ if (prev) { ++ prev->next = cur->next; ++ cur = prev; ++ } else { ++ c->phones = cur->next; ++ } ++ free(match); ++ } ++ prev = cur; ++ if (cur) cur = cur->next; ++ } ++ ++ cur = c->phones; ++ ++ while (cur) { ++ left++; ++ cur = cur->next; ++ } ++ ++ // if all phones have signalled busy AND the timer is not running anymore! ++ if ((left==0) && (c->cause == PRI_CAUSE_USER_BUSY) && (c->t303running == 0)) { ++ // pri_error(pri, "q921_handle_hangup(%d, %d, %d)\n", c->cr, tei, c->tei); ++ // make sure * frees the channel ++ res = Q931_RES_HAVEEVENT; ++ pri->ev.hangup.cause = PRI_CAUSE_USER_BUSY; ++ pri->ev.hangup.channel = c->channelno | (c->ds1no << 8); ++ pri->ev.hangup.cref = c->cr; ++ pri->ev.hangup.call = c; ++ pri->ev.e = PRI_EVENT_HANGUP; ++ } ++ return res; ++ } ++ ++ ++ + int q931_hangup(struct pri *pri, q931_call *c, int cause) + { + int disconnect = 1; +@@ -2871,7 +3845,7 @@ + /* 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; +@@ -2885,7 +3859,7 @@ + case Q931_CALL_STATE_NULL: + if (c->peercallstate == Q931_CALL_STATE_NULL) + /* free the resources if we receive or send REL_COMPL */ +- q931_destroycall(pri, c->cr); ++ q931_destroycall(pri, c->cr, c->tei); + else if (c->peercallstate == Q931_CALL_STATE_RELEASE_REQUEST) + q931_release_complete(pri,c,cause); + break; +@@ -2911,6 +3885,11 @@ + /* received SETUP_ACKNOWLEDGE */ + /* send DISCONNECT in general */ + if (c->peercallstate != Q931_CALL_STATE_NULL && c->peercallstate != Q931_CALL_STATE_DISCONNECT_REQUEST && c->peercallstate != Q931_CALL_STATE_DISCONNECT_INDICATION && c->peercallstate != Q931_CALL_STATE_RELEASE_REQUEST && c->peercallstate != Q931_CALL_STATE_RESTART_REQUEST && c->peercallstate != Q931_CALL_STATE_RESTART) { ++ if (pri->localtype == BRI_NETWORK_PTMP) { ++ if (c->tei == 127) { ++ break; ++ } ++ } + if (disconnect) + q931_disconnect(pri,c,cause); + else if (release_compl) +@@ -2926,8 +3905,14 @@ + break; + case Q931_CALL_STATE_DISCONNECT_INDICATION: + /* received DISCONNECT */ ++ if (pri->localtype == BRI_NETWORK_PTMP) { ++ if (c->tei == 127) { ++ break; ++ } ++ } + if (c->peercallstate == Q931_CALL_STATE_DISCONNECT_REQUEST) { + c->alive = 1; ++// pri_error(pri, "sending release to %d\n", c->tei); + q931_release(pri,c,cause); + } + break; +@@ -2941,19 +3926,17 @@ + pri_error(pri, "q931_hangup shouldn't be called in this state, ourstate %s, peerstate %s\n",callstate2str(c->ourcallstate),callstate2str(c->peercallstate)); + break; + default: +- pri_error(pri, "We're not yet handling hanging up when our state is %d, contact support@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; +@@ -2965,6 +3948,7 @@ + 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) +@@ -2978,13 +3962,13 @@ + KLUDGE this by changing byte 4 from a 0xf (SERVICE) + to a 0x7 (SERVICE ACKNOWLEDGE) */ + h->raw[h->crlen + 2] -= 0x8; +- q931_xmit(pri, h, len, 1); ++ q931_xmit(pri, h, len, 1, tei); + return 0; + } else if (h->pd != pri->protodisc) { + pri_error(pri, "Warning: unknown/inappropriate protocol discriminator received (%02x/%d)\n", h->pd, h->pd); + return 0; + } +- c = q931_getcall(pri, q931_cr(h)); ++ c = q931_getcall(pri, q931_cr(h), tei); + if (!c) { + pri_error(pri, "Unable to locate call %d\n", q931_cr(h)); + return -1; +@@ -3007,6 +3991,7 @@ + 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; +@@ -3027,28 +4012,44 @@ + c->callername[0] = '\0'; + c->callerani[0] = '\0'; + c->callerplanani = -1; +- c->redirectingplan = -1; +- c->redirectingpres = -1; +- c->redirectingreason = -1; +- c->origcalledplan = -1; +- c->origcalledpres = -1; +- c->origredirectingreason = -1; ++ c->redirectingplan = -1; ++ c->redirectingpres = -1; ++ c->redirectingreason = -1; ++ c->origcalledplan = -1; ++ c->origcalledpres = -1; ++ c->origredirectingreason = -1; + c->redirectingnum[0] = '\0'; + c->origcallednum[0] = '\0'; + c->redirectingname[0] = '\0'; + c->origcalledname[0] = '\0'; +- c->useruserprotocoldisc = -1; ++ c->useruserprotocoldisc = -1; + c->useruserinfo[0] = '\0'; + c->complete = 0; + c->nonisdn = 0; + c->aoc_units = -1; +- /* Fall through */ ++ c->digits[0] = '\0'; ++ c->display[0] = '\0'; ++ c->progress = -1; ++ c->progressmask = 0; ++ break; + case Q931_CONNECT: ++ if (c->t303timer) { ++ c->t303running = 0; ++ pri_schedule_del(pri, c->t303timer); ++ } ++ c->useruserinfo[0] = '\0'; ++ c->t303timer = 0; ++ c->progress = -1; ++ break; + case Q931_ALERTING: + case Q931_PROGRESS: +- c->useruserinfo[0] = '\0'; +- c->cause = -1; ++ c->useruserinfo[0] = '\0'; + case Q931_CALL_PROCEEDING: ++ if (c->t303timer) { ++ c->t303running = 0; ++ pri_schedule_del(pri, c->t303timer); ++ } ++ c->t303timer = 0; + c->progress = -1; + c->progressmask = 0; + break; +@@ -3059,20 +4060,22 @@ + break; + case Q931_RELEASE: + case Q931_DISCONNECT: +- c->cause = -1; +- c->causecode = -1; +- c->causeloc = -1; +- c->aoc_units = -1; ++// c->aoc_units = -1; ++ c->useruserinfo[0] = '\0'; + if (c->retranstimer) + pri_schedule_del(pri, c->retranstimer); + c->retranstimer = 0; +- c->useruserinfo[0] = '\0'; ++ if (c->t303timer) { ++ c->t303running = 0; ++ pri_schedule_del(pri, c->t303timer); ++ } ++ c->t303timer = 0; + break; + case Q931_RELEASE_COMPLETE: + if (c->retranstimer) +- pri_schedule_del(pri, c->retranstimer); ++ pri_schedule_del(pri, c->retranstimer); + c->retranstimer = 0; +- c->useruserinfo[0] = '\0'; ++ c->useruserinfo[0] = '\0'; + case Q931_STATUS: + c->cause = -1; + c->causecode = -1; +@@ -3089,22 +4092,32 @@ + case Q931_STATUS_ENQUIRY: + break; + case Q931_SETUP_ACKNOWLEDGE: ++ if (c->t303timer) { ++ c->t303running = 0; ++ pri_schedule_del(pri, c->t303timer); ++ } ++ c->t303timer = 0; + break; + case Q931_NOTIFY: + break; ++ case Q931_HOLD: ++ break; ++ case Q931_RETRIEVE: ++ break; ++ case Q931_RESUME: ++ c->tei = tei; ++ break; ++ case Q931_SUSPEND: ++ break; + case Q931_USER_INFORMATION: + case Q931_SEGMENT: + case Q931_CONGESTION_CONTROL: +- case Q931_HOLD: + case Q931_HOLD_ACKNOWLEDGE: + case Q931_HOLD_REJECT: +- case Q931_RETRIEVE: + case Q931_RETRIEVE_ACKNOWLEDGE: + case Q931_RETRIEVE_REJECT: +- case Q931_RESUME: + case Q931_RESUME_ACKNOWLEDGE: + case Q931_RESUME_REJECT: +- case Q931_SUSPEND: + case Q931_SUSPEND_ACKNOWLEDGE: + case Q931_SUSPEND_REJECT: + pri_error(pri, "!! Not yet handling pre-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg); +@@ -3113,7 +4126,7 @@ + pri_error(pri, "!! Don't know how to post-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg); + q931_status(pri,c, PRI_CAUSE_MESSAGE_TYPE_NONEXIST); + if (c->newcall) +- q931_destroycall(pri,c->cr); ++ q931_destroycall(pri,c->cr,c->tei); + return -1; + } + memset(mandies, 0, sizeof(mandies)); +@@ -3193,12 +4206,19 @@ + 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++; ++ } + } + } + +@@ -3207,7 +4227,7 @@ + case Q931_RESTART: + if (missingmand) { + q931_status(pri, c, PRI_CAUSE_MANDATORY_IE_MISSING); +- q931_destroycall(pri, c->cr); ++ q931_destroycall(pri, c->cr, c->tei); + break; + } + c->ourcallstate = Q931_CALL_STATE_RESTART; +@@ -3225,6 +4245,7 @@ + } + /* Must be new call */ + if (!c->newcall) { ++ pri_error(pri, "received SETUP message for call that is not a new call (retransmission). \n"); + break; + } + if (c->progressmask & PRI_PROG_CALLER_NOT_ISDN) +@@ -3242,16 +4263,20 @@ + 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->digitbuf)) { ++ libpri_copy_string(pri->ev.ring.callednum, c->digitbuf, 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)); +@@ -3261,11 +4286,13 @@ + 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; +@@ -3275,6 +4302,9 @@ + q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE); + break; + } ++ if (pri->localtype == BRI_NETWORK_PTMP) { ++ l2c = q921_getcall(pri, c, tei); ++ } + c->ourcallstate = Q931_CALL_STATE_CALL_DELIVERED; + c->peercallstate = Q931_CALL_STATE_CALL_RECEIVED; + pri->ev.e = PRI_EVENT_RINGING; +@@ -3295,17 +4325,24 @@ + q931_status(pri, c, PRI_CAUSE_WRONG_MESSAGE); + break; + } ++ /* TEI got the call */ ++ c->tei = tei; + c->ourcallstate = Q931_CALL_STATE_ACTIVE; + c->peercallstate = Q931_CALL_STATE_CONNECT_REQUEST; + pri->ev.e = PRI_EVENT_ANSWER; + pri->ev.answer.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); + pri->ev.answer.cref = c->cr; + pri->ev.answer.call = c; ++ pri->ev.answer.tei = c->tei; + pri->ev.answer.progress = c->progress; + pri->ev.answer.progressmask = c->progressmask; + libpri_copy_string(pri->ev.answer.useruserinfo, c->useruserinfo, sizeof(pri->ev.ring.useruserinfo)); + c->useruserinfo[0] = '\0'; + q931_connect_acknowledge(pri, c); ++ if (pri->localtype == BRI_NETWORK_PTMP) { ++ /* Release all other TEIs */ ++ q921_hangup(pri, c, tei); ++ } + if (c->justsignalling) { /* Make sure WE release when we initiatie a signalling only connection */ + q931_release(pri, c, PRI_CAUSE_NORMAL_CLEARING); + break; +@@ -3313,23 +4350,43 @@ + return Q931_RES_HAVEEVENT; + case Q931_FACILITY: + if (c->newcall) { +- q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE); +- break; +- } +- pri->ev.e = PRI_EVENT_FACNAME; +- libpri_copy_string(pri->ev.facname.callingname, c->callername, sizeof(pri->ev.facname.callingname)); +- libpri_copy_string(pri->ev.facname.callingnum, c->callernum, sizeof(pri->ev.facname.callingnum)); +- pri->ev.facname.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); +- pri->ev.facname.cref = c->cr; +- pri->ev.facname.call = c; +-#if 0 +- pri_message(pri, "Sending facility event (%s/%s)\n", pri->ev.facname.callingname, pri->ev.facname.callingnum); +-#endif ++ if ((pri->localtype == PRI_CPE) || (pri->localtype == PRI_NETWORK)) { ++ q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE); ++ } else { ++ // BRI uses the dummy cref for sservices like ccnr ++ } ++ break; ++ } ++ if (c->facility > 0) { ++ pri->ev.e = PRI_EVENT_FACILITY; ++ pri->ev.facility.channel = c->channelno | (c->ds1no << 8); ++ pri->ev.facility.cref = c->cr; ++ pri->ev.facility.tei = c->tei; ++ pri->ev.facility.call = c; ++ switch (c->facility) { ++ case 0x06: /* ECT execute */ ++ pri->ev.facility.operation = 0x06; ++ break; ++ case 0x0D: /* 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; +@@ -3347,6 +4404,11 @@ + q931_status(pri,c,PRI_CAUSE_WRONG_MESSAGE); + break; + } ++ if (pri->localtype == BRI_NETWORK_PTMP) { ++ l2c = q921_getcall(pri, c, tei); ++ l2c->proc = 1; ++ l2c->channel = c->channelno; ++ } + pri->ev.proceeding.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); + if (mh->msg == Q931_CALL_PROCEEDING) { + pri->ev.e = PRI_EVENT_PROCEEDING; +@@ -3364,16 +4426,21 @@ + break; + } + if (c->ourcallstate != Q931_CALL_STATE_CONNECT_REQUEST) { ++ if ((c->ourcallstate == Q931_CALL_STATE_ACTIVE) && (c->con_acked == 0) && (network)) { ++ /* sending a CONNECT_ACKNOWLEDGE is optional for CPEs */ ++ } else { + q931_status(pri,c,PRI_CAUSE_WRONG_MESSAGE); +- break; ++ } ++ break; + } + c->ourcallstate = 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) { +@@ -3410,31 +4477,69 @@ + if (res) + return res; + } +- break; ++ if (c->peercallstate != c->sugcallstate) { ++ pri_error(pri, "updating callstate, peercallstate %d to %d\n", c->peercallstate, c->sugcallstate); ++ c->peercallstate = c->sugcallstate; ++ if (c->sugcallstate != Q931_CALL_STATE_ACTIVE) { ++ /* pass hangup to upper layer! */ ++ if (c->alive) { ++ pri->ev.e = PRI_EVENT_HANGUP; ++ res = Q931_RES_HAVEEVENT; ++ c->alive = 0; ++ } else if (c->sendhangupack) { ++ res = Q931_RES_HAVEEVENT; ++ pri->ev.e = PRI_EVENT_HANGUP_ACK; ++ q931_hangup(pri, c, c->cause); ++ } else { ++ q931_hangup(pri, c, c->cause); ++ res = 0; ++ if (res) ++ return res; ++ } ++ } ++ } ++ break; + case Q931_RELEASE_COMPLETE: +- c->ourcallstate = Q931_CALL_STATE_NULL; +- c->peercallstate = Q931_CALL_STATE_NULL; +- pri->ev.hangup.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); +- pri->ev.hangup.cref = c->cr; +- pri->ev.hangup.cause = c->cause; +- pri->ev.hangup.call = c; +- libpri_copy_string(pri->ev.hangup.useruserinfo, c->useruserinfo, sizeof(pri->ev.ring.useruserinfo)); +- c->useruserinfo[0] = '\0'; +- /* Free resources */ +- if (c->alive) { +- pri->ev.e = PRI_EVENT_HANGUP; +- res = Q931_RES_HAVEEVENT; +- c->alive = 0; +- } else if (c->sendhangupack) { +- res = Q931_RES_HAVEEVENT; +- pri->ev.e = PRI_EVENT_HANGUP_ACK; +- pri_hangup(pri, c, c->cause); +- } else +- res = 0; +- if (res) +- return res; +- else +- q931_hangup(pri,c,c->cause); ++ if (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)) { ++ c->ourcallstate = Q931_CALL_STATE_NULL; ++ c->peercallstate = Q931_CALL_STATE_NULL; ++ pri->ev.hangup.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); ++ pri->ev.hangup.cref = c->cr; ++ pri->ev.hangup.cause = c->cause; ++ pri->ev.hangup.call = c; ++ libpri_copy_string(pri->ev.hangup.useruserinfo, c->useruserinfo, sizeof(pri->ev.ring.useruserinfo)); ++ c->useruserinfo[0] = '\0'; ++ /* Free resources */ ++ if (c->alive) { ++ pri->ev.e = PRI_EVENT_HANGUP; ++ res = Q931_RES_HAVEEVENT; ++ c->alive = 0; ++ } else if (c->sendhangupack) { ++ res = Q931_RES_HAVEEVENT; ++ pri->ev.e = PRI_EVENT_HANGUP_ACK; ++ pri_hangup(pri, c, c->cause, -1); ++ } else ++ res = 0; ++ if (res) ++ return res; ++ else ++ q931_hangup(pri,c,c->cause); ++ } else { ++ // BRI_NET_PTMP ++ // ignoring relase_complete ++ res = q921_handle_hangup(pri,c,tei); ++ if (res) ++ return res; ++ } + break; + case Q931_RELEASE: + if (missingmand) { +@@ -3450,6 +4555,7 @@ + pri->ev.e = PRI_EVENT_HANGUP; + pri->ev.hangup.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); + pri->ev.hangup.cref = c->cr; ++ pri->ev.hangup.tei = c->tei; + pri->ev.hangup.cause = c->cause; + pri->ev.hangup.call = c; + pri->ev.hangup.aoc_units = c->aoc_units; +@@ -3478,9 +4584,16 @@ + pri->ev.e = PRI_EVENT_HANGUP_REQ; + pri->ev.hangup.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); + pri->ev.hangup.cref = c->cr; ++ pri->ev.hangup.tei = c->tei; + pri->ev.hangup.cause = c->cause; + pri->ev.hangup.call = c; + pri->ev.hangup.aoc_units = c->aoc_units; ++ 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 +@@ -3511,7 +4624,7 @@ + pri->ev.e = PRI_EVENT_INFO_RECEIVED; + pri->ev.ring.call = c; + pri->ev.ring.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); +- libpri_copy_string(pri->ev.ring.callednum, c->callednum, sizeof(pri->ev.ring.callednum)); ++ libpri_copy_string(pri->ev.ring.callednum, c->digits, sizeof(pri->ev.ring.callednum) ); + libpri_copy_string(pri->ev.ring.callingsubaddr, c->callingsubaddr, sizeof(pri->ev.ring.callingsubaddr)); + pri->ev.ring.complete = c->complete; /* this covers IE 33 (Sending Complete) */ + return Q931_RES_HAVEEVENT; +@@ -3547,19 +4660,53 @@ + pri->ev.notify.channel = c->channelno; + pri->ev.notify.info = c->notify; + return Q931_RES_HAVEEVENT; ++ case Q931_HOLD: ++ pri->ev.e = PRI_EVENT_HOLD_REQ; ++ pri->ev.hold_req.call = c; ++ pri->ev.hold_req.cref = c->cr; ++ pri->ev.hold_req.tei = c->tei; ++ pri->ev.hold_req.channel = c->channelno; ++ return Q931_RES_HAVEEVENT; ++ break; ++ case Q931_RETRIEVE: ++ pri->ev.e = PRI_EVENT_RETRIEVE_REQ; ++ pri->ev.retrieve_req.call = c; ++ pri->ev.retrieve_req.cref = c->cr; ++ pri->ev.retrieve_req.tei = c->tei; ++ pri->ev.retrieve_req.channel = c->channelno; ++ return Q931_RES_HAVEEVENT; ++ break; ++ case Q931_SUSPEND: ++ pri->ev.e = PRI_EVENT_SUSPEND_REQ; ++ pri->ev.suspend_req.call = c; ++ pri->ev.suspend_req.cref = c->cr; ++ pri->ev.suspend_req.tei = c->tei; ++ pri->ev.suspend_req.channel = c->channelno; ++ strncpy(pri->ev.suspend_req.callid, c->callid, sizeof(pri->ev.suspend_req.callid) - 1); ++ return Q931_RES_HAVEEVENT; ++ break; ++ case Q931_RESUME: ++ if (pri->localtype == BRI_NETWORK_PTMP) { ++ l2c = q921_getcall(pri, c, tei); ++ } ++ c->newcall = 0; ++ pri->ev.e = PRI_EVENT_RESUME_REQ; ++ pri->ev.resume_req.call = c; ++ pri->ev.resume_req.cref = c->cr; ++ pri->ev.resume_req.tei = c->tei; ++ pri->ev.resume_req.channel = c->channelno; ++ strncpy(pri->ev.resume_req.callid, c->callid, sizeof(pri->ev.resume_req.callid) - 1); ++ return Q931_RES_HAVEEVENT; ++ break; + case Q931_USER_INFORMATION: + case Q931_SEGMENT: + case Q931_CONGESTION_CONTROL: +- case Q931_HOLD: + case Q931_HOLD_ACKNOWLEDGE: + case Q931_HOLD_REJECT: +- case Q931_RETRIEVE: + case Q931_RETRIEVE_ACKNOWLEDGE: + case Q931_RETRIEVE_REJECT: +- case Q931_RESUME: + case Q931_RESUME_ACKNOWLEDGE: + case Q931_RESUME_REJECT: +- case Q931_SUSPEND: + case Q931_SUSPEND_ACKNOWLEDGE: + case Q931_SUSPEND_REJECT: + pri_error(pri, "!! Not yet handling post-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg); +@@ -3569,7 +4716,7 @@ + pri_error(pri, "!! Don't know how to post-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg); + q931_status(pri,c, PRI_CAUSE_MESSAGE_TYPE_NONEXIST); + if (c->newcall) +- q931_destroycall(pri,c->cr); ++ q931_destroycall(pri,c->cr,c->tei); + return -1; + } + return 0; --- libpri-1.2.3.orig/debian/patches/libname.dpatch +++ libpri-1.2.3/debian/patches/libname.dpatch @@ -0,0 +1,88 @@ +#! /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,16 +32,22 @@ + OSARCH=$(shell uname -s) + PROC?=$(shell uname -m) + ++ifdef LIB_SUF ++LIBNAME=pri-$(LIB_SUF) ++else ++LIBNAME=pri ++endif + TOBJS=testpri.o + T2OBJS=testprilib.o +-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 $(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 $(OSARCH), Linux GNU/kFreeBSD)) + 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 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.2.3.orig/debian/patches/00list +++ libpri-1.2.3/debian/patches/00list @@ -0,0 +1 @@ +libname --- libpri-1.2.3.orig/debian/control +++ libpri-1.2.3/debian/control @@ -0,0 +1,27 @@ +Source: libpri +Priority: optional +Section: libs +Maintainer: Debian VoIP Team +Uploaders: Kilian Krause , Jose Carlos Garcia Sogo , Mark Purcell , Santiago Garcia Mantinan , Tzafrir Cohen +Build-Depends: debhelper (>> 4.0.0), dpatch +Standards-Version: 3.6.1 + +Package: libpri-dev +Section: libdevel +Architecture: any +Depends: libpri1.2 (= ${Source-Version}) +Description: Primary Rate ISDN specification development files + Development files for the C implementation of the Primary Rate ISDN + specification. + +Package: libpri1.2 +Section: libs +Architecture: any +Depends: ${shlibs:Depends} ${misc:Depends} +Replaces: libpri1 +Conflicts: libpri1 +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.2.3.orig/debian/libpri1.2.dirs +++ libpri-1.2.3/debian/libpri1.2.dirs @@ -0,0 +1 @@ +usr/lib --- libpri-1.2.3.orig/debian/compat +++ libpri-1.2.3/debian/compat @@ -0,0 +1 @@ +4 --- libpri-1.2.3.orig/debian/libpri1.2.files +++ libpri-1.2.3/debian/libpri1.2.files @@ -0,0 +1 @@ +usr/lib/lib*.so.* --- libpri-1.2.3.orig/debian/watch +++ libpri-1.2.3/debian/watch @@ -0,0 +1,3 @@ +# Site Directory Pattern Version Script +version=2 +http://ftp.digium.com/pub/libpri/ libpri-(.*)\.tar\.gz debian svn-upgrade --- libpri-1.2.3.orig/debian/changelog +++ libpri-1.2.3/debian/changelog @@ -0,0 +1,207 @@ +libpri (1.2.3-1~schmidham.net.1) stable; urgency=low + + * Backport to sarge, no changes. + + -- Korbinian Rosenegger Thu, 21 Sep 2006 00:04:57 +0200 + +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.2.3.orig/debian/copyright +++ libpri-1.2.3/debian/copyright @@ -0,0 +1,29 @@ +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 + +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'. + --- libpri-1.2.3.orig/debian/docs +++ libpri-1.2.3/debian/docs @@ -0,0 +1,2 @@ +README +TODO --- libpri-1.2.3.orig/debian/rules +++ libpri-1.2.3/debian/rules @@ -0,0 +1,130 @@ +#!/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 + +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$$//') + +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. + $(MAKE) +ifeq ($(USE_BRISTUFF),1) + cd $(BRISTUFF_DIR); 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 + 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_movefiles + + dh_installchangelogs ChangeLog + dh_installdocs + dh_installexamples + dh_installman + dh_strip + dh_compress + dh_fixperms + dh_makeshlibs -V + dh_installdeb + dh_shlibdeps + dh_gencontrol + dh_md5sums + dh_builddeb + +print-version: + @@echo "Debian version: $(DEBVERSION)" + @@echo "Upstream version: $(UPVERSION)" + +get-orig-source: + @@dh_testdir + @@[ -d ../tarballs/. ]||mkdir -p ../tarballs + @@echo Downloading $(FILENAME) from $(URL) ... + @@wget -N -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.2.3.orig/debian/libpri-dev.dirs +++ libpri-1.2.3/debian/libpri-dev.dirs @@ -0,0 +1,2 @@ +usr/lib +usr/include --- libpri-1.2.3.orig/debian/libpri-dev.files +++ libpri-1.2.3/debian/libpri-dev.files @@ -0,0 +1,5 @@ +usr/include/* +usr/lib/lib*.a +usr/lib/lib*.so +usr/lib/pkgconfig/* +/usr/lib/*.la