Moving trunk changes back into 1.4

git-svn-id: https://origsvn.digium.com/svn/libpri/branches/1.4@557 2fbb986a-6c06-0410-b554-c9c1f0a7f128
This commit is contained in:
Matthew Fredrickson 2008-05-07 19:51:44 +00:00
parent dee4c9ae0f
commit b9a6ab0c69
13 changed files with 1366 additions and 323 deletions

View File

@ -34,14 +34,19 @@ AWK=awk
OSARCH=$(shell uname -s) OSARCH=$(shell uname -s)
PROC?=$(shell uname -m) PROC?=$(shell uname -m)
# SONAME version; should be changed on every ABI change
# please don't change it needlessly; it's perfectly fine to have a SONAME
# of 1.2 and a version of 1.4.x
SONAME:=1.4
STATIC_LIBRARY=libpri.a STATIC_LIBRARY=libpri.a
DYNAMIC_LIBRARY=libpri.so.1.0 DYNAMIC_LIBRARY:=libpri.so.$(SONAME)
STATIC_OBJS=copy_string.o pri.o q921.o prisched.o q931.o pri_facility.o version.o STATIC_OBJS=copy_string.o pri.o q921.o prisched.o q931.o pri_facility.o version.o
DYNAMIC_OBJS=copy_string.lo pri.lo q921.lo prisched.lo q931.lo pri_facility.lo version.lo DYNAMIC_OBJS=copy_string.lo pri.lo q921.lo prisched.lo q931.lo pri_facility.lo version.lo
CFLAGS=-Wall -Werror -Wstrict-prototypes -Wmissing-prototypes -g -fPIC $(ALERTING) $(LIBPRI_COUNTERS) CFLAGS=-Wall -Werror -Wstrict-prototypes -Wmissing-prototypes -g -fPIC $(ALERTING) $(LIBPRI_COUNTERS)
INSTALL_PREFIX=$(DESTDIR) INSTALL_PREFIX=$(DESTDIR)
INSTALL_BASE=/usr INSTALL_BASE=/usr
SOFLAGS = -Wl,-hlibpri.so.1.0 SOFLAGS:=-Wl,-h$(DYNAMIC_LIBRARY)
LDCONFIG = /sbin/ldconfig LDCONFIG = /sbin/ldconfig
ifneq (,$(findstring X$(OSARCH)X, XLinuxX XGNU/kFreeBSDX)) ifneq (,$(findstring X$(OSARCH)X, XLinuxX XGNU/kFreeBSDX))
LDCONFIG_FLAGS=-n LDCONFIG_FLAGS=-n
@ -56,7 +61,6 @@ ifeq (${OSARCH},SunOS)
CFLAGS += -DSOLARIS -I../zaptel-solaris CFLAGS += -DSOLARIS -I../zaptel-solaris
LDCONFIG = LDCONFIG =
LDCONFIG_FLAGS = \# # Trick to comment out the period in the command below LDCONFIG_FLAGS = \# # Trick to comment out the period in the command below
SOSLINK = ln -sf libpri.so.1.0 libpri.so.1
#INSTALL_PREFIX = /opt/asterisk # Uncomment out to install in standard Solaris location for 3rd party code #INSTALL_PREFIX = /opt/asterisk # Uncomment out to install in standard Solaris location for 3rd party code
endif endif
@ -77,7 +81,16 @@ all: depend $(STATIC_LIBRARY) $(DYNAMIC_LIBRARY)
update: update:
@if [ -d .svn ]; then \ @if [ -d .svn ]; then \
echo "Updating from Subversion..." ; \ echo "Updating from Subversion..." ; \
svn update -q; \ fromrev="`svn info | $(AWK) '/Revision: / {print $$2}'`"; \
svn update | tee update.out; \
torev="`svn info | $(AWK) '/Revision: / {print $$2}'`"; \
echo "`date` Updated from revision $${fromrev} to $${torev}." >> update.log; \
rm -f .version; \
if [ `grep -c ^C update.out` -gt 0 ]; then \
echo ; echo "The following files have conflicts:" ; \
grep ^C update.out | cut -b4- ; \
fi ; \
rm -f update.out; \
else \ else \
echo "Not under version control"; \ echo "Not under version control"; \
fi fi
@ -89,20 +102,19 @@ ifneq (${OSARCH},SunOS)
install -m 644 libpri.h $(INSTALL_PREFIX)$(INSTALL_BASE)/include install -m 644 libpri.h $(INSTALL_PREFIX)$(INSTALL_BASE)/include
install -m 755 $(DYNAMIC_LIBRARY) $(INSTALL_PREFIX)$(INSTALL_BASE)/lib install -m 755 $(DYNAMIC_LIBRARY) $(INSTALL_PREFIX)$(INSTALL_BASE)/lib
if [ -x /usr/sbin/sestatus ] && ( /usr/sbin/sestatus | grep "SELinux status:" | grep -q "enabled"); then /sbin/restorecon -v $(INSTALL_PREFIX)$(INSTALL_BASE)/lib/$(DYNAMIC_LIBRARY); fi if [ -x /usr/sbin/sestatus ] && ( /usr/sbin/sestatus | grep "SELinux status:" | grep -q "enabled"); then /sbin/restorecon -v $(INSTALL_PREFIX)$(INSTALL_BASE)/lib/$(DYNAMIC_LIBRARY); fi
( cd $(INSTALL_PREFIX)$(INSTALL_BASE)/lib ; ln -sf libpri.so.1.0 libpri.so ; ln -sf libpri.so.1.0 libpri.so.1 ) ( cd $(INSTALL_PREFIX)$(INSTALL_BASE)/lib ; ln -sf libpri.so.$(SONAME) libpri.so)
install -m 644 $(STATIC_LIBRARY) $(INSTALL_PREFIX)$(INSTALL_BASE)/lib 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 if test $$(id -u) = 0; then $(LDCONFIG) $(LDCONFIG_FLAGS) $(INSTALL_PREFIX)$(INSTALL_BASE)/lib; fi
else else
install -f $(INSTALL_PREFIX)$(INSTALL_BASE)/include -m 644 libpri.h install -f $(INSTALL_PREFIX)$(INSTALL_BASE)/include -m 644 libpri.h
install -f $(INSTALL_PREFIX)$(INSTALL_BASE)/lib -m 755 $(DYNAMIC_LIBRARY) 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 libpri.so.$(SONAME) libpri.so)
install -f $(INSTALL_PREFIX)$(INSTALL_BASE)/lib -m 644 $(STATIC_LIBRARY) install -f $(INSTALL_PREFIX)$(INSTALL_BASE)/lib -m 644 $(STATIC_LIBRARY)
endif endif
uninstall: uninstall:
@echo "Removing Libpri" @echo "Removing Libpri"
rm -f $(INSTALL_PREFIX)$(INSTALL_BASE)/lib/libpri.so.1.0 rm -f $(INSTALL_PREFIX)$(INSTALL_BASE)/lib/libpri.so.$(SONAME)
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.so
rm -f $(INSTALL_PREFIX)$(INSTALL_BASE)/lib/libpri.a rm -f $(INSTALL_PREFIX)$(INSTALL_BASE)/lib/libpri.a
rm -f $(INSTALL_PREFIX)$(INSTALL_BASE)/include/libpri.h rm -f $(INSTALL_PREFIX)$(INSTALL_BASE)/include/libpri.h
@ -133,9 +145,7 @@ $(STATIC_LIBRARY): $(STATIC_OBJS)
$(DYNAMIC_LIBRARY): $(DYNAMIC_OBJS) $(DYNAMIC_LIBRARY): $(DYNAMIC_OBJS)
$(CC) -shared $(SOFLAGS) -o $@ $(DYNAMIC_OBJS) $(CC) -shared $(SOFLAGS) -o $@ $(DYNAMIC_OBJS)
$(LDCONFIG) $(LDCONFIG_FLAGS) . $(LDCONFIG) $(LDCONFIG_FLAGS) .
ln -sf libpri.so.1.0 libpri.so ln -sf libpri.so.$(SONAME) libpri.so
ln -sf libpri.so.1.0 libpri.so.1
$(SOSLINK)
version.c: version.c:
@build_tools/make_version_c > $@.tmp @build_tools/make_version_c > $@.tmp
@ -143,7 +153,7 @@ version.c:
@rm -f $@.tmp @rm -f $@.tmp
clean: clean:
rm -f *.o *.so *.lo *.so.1 *.so.1.0 rm -f *.o *.so *.lo *.so.$(SONAME)
rm -f testprilib $(STATIC_LIBRARY) $(DYNAMIC_LIBRARY) rm -f testprilib $(STATIC_LIBRARY) $(DYNAMIC_LIBRARY)
rm -f pritest pridump rm -f pritest pridump
rm -f .depend rm -f .depend

116
libpri.h
View File

@ -342,6 +342,8 @@ typedef struct pri_event_facname {
int channel; int channel;
int cref; int cref;
q931_call *call; q931_call *call;
int callingpres; /* Presentation of Calling CallerID */
int callingplan; /* Dialing plan of Calling entity */
} pri_event_facname; } pri_event_facname;
#define PRI_CALLINGPLANANI #define PRI_CALLINGPLANANI
@ -451,77 +453,78 @@ typedef int (*pri_io_cb)(struct pri *pri, void *buf, int buflen);
channel operating in HDLC mode with FCS computed by the fd's driver. Also it 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 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_* */ 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); struct pri *pri_new(int fd, int nodetype, int switchtype);
struct pri *pri_new_bri(int fd, int ptpmode, int nodetype, int switchtype);
/* Create D-channel just as above with user defined I/O callbacks and data */ /* 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); struct pri *pri_new_cb(int fd, int nodetype, int switchtype, pri_io_cb io_read, pri_io_cb io_write, void *userdata);
/* Retrieve the user data associated with the D channel */ /* Retrieve the user data associated with the D channel */
extern void *pri_get_userdata(struct pri *pri); void *pri_get_userdata(struct pri *pri);
/* Set the user data associated with the D channel */ /* Set the user data associated with the D channel */
extern void pri_set_userdata(struct pri *pri, void *userdata); void pri_set_userdata(struct pri *pri, void *userdata);
/* Set Network Specific Facility for PRI */ /* Set Network Specific Facility for PRI */
extern void pri_set_nsf(struct pri *pri, int nsf); void pri_set_nsf(struct pri *pri, int nsf);
/* Set debug parameters on PRI -- see above debug definitions */ /* Set debug parameters on PRI -- see above debug definitions */
extern void pri_set_debug(struct pri *pri, int debug); void pri_set_debug(struct pri *pri, int debug);
/* Get debug parameters on PRI -- see above debug definitions */ /* Get debug parameters on PRI -- see above debug definitions */
extern int pri_get_debug(struct pri *pri); int pri_get_debug(struct pri *pri);
#define PRI_FACILITY_ENABLE #define PRI_FACILITY_ENABLE
/* Enable transmission support of Facility IEs on the pri */ /* Enable transmission support of Facility IEs on the pri */
extern void pri_facility_enable(struct pri *pri); void pri_facility_enable(struct pri *pri);
/* Run PRI on the given D-channel, taking care of any events that /* 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 need to be handled. If block is set, it will block until an event
occurs which needs to be handled */ occurs which needs to be handled */
extern pri_event *pri_dchannel_run(struct pri *pri, int block); pri_event *pri_dchannel_run(struct pri *pri, int block);
/* Check for an outstanding event on the PRI */ /* Check for an outstanding event on the PRI */
pri_event *pri_check_event(struct pri *pri); pri_event *pri_check_event(struct pri *pri);
/* Give a name to a given event ID */ /* Give a name to a given event ID */
extern char *pri_event2str(int id); char *pri_event2str(int id);
/* Give a name to a node type */ /* Give a name to a node type */
extern char *pri_node2str(int id); char *pri_node2str(int id);
/* Give a name to a switch type */ /* Give a name to a switch type */
extern char *pri_switch2str(int id); char *pri_switch2str(int id);
/* Print an event */ /* Print an event */
extern void pri_dump_event(struct pri *pri, pri_event *e); void pri_dump_event(struct pri *pri, pri_event *e);
/* Turn presentation into a string */ /* Turn presentation into a string */
extern char *pri_pres2str(int pres); char *pri_pres2str(int pres);
/* Turn numbering plan into a string */ /* Turn numbering plan into a string */
extern char *pri_plan2str(int plan); char *pri_plan2str(int plan);
/* Turn cause into a string */ /* Turn cause into a string */
extern char *pri_cause2str(int cause); char *pri_cause2str(int cause);
/* Acknowledge a call and place it on the given channel. Set info to non-zero if there /* Acknowledge a call and place it on the given channel. Set info to non-zero if there
is in-band data available on the channel */ is in-band data available on the channel */
extern int pri_acknowledge(struct pri *pri, q931_call *call, int channel, int info); int pri_acknowledge(struct pri *pri, q931_call *call, int channel, int info);
/* Send a digit in overlap mode */ /* Send a digit in overlap mode */
extern int pri_information(struct pri *pri, q931_call *call, char digit); int pri_information(struct pri *pri, q931_call *call, char digit);
#define PRI_KEYPAD_FACILITY_TX #define PRI_KEYPAD_FACILITY_TX
/* Send a keypad facility string of digits */ /* Send a keypad facility string of digits */
extern int pri_keypad_facility(struct pri *pri, q931_call *call, char *digits); int pri_keypad_facility(struct pri *pri, q931_call *call, char *digits);
/* Answer the incomplete(call without called number) call on the given channel. /* 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 */ 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); int pri_need_more_info(struct pri *pri, q931_call *call, int channel, int nonisdn);
/* Answer the call on the given channel (ignored if you called acknowledge already). /* Answer the call on the given channel (ignored if you called acknowledge already).
Set non-isdn to non-zero if you are not connecting to ISDN equipment */ 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); int pri_answer(struct pri *pri, q931_call *call, int channel, int nonisdn);
/* Set CRV reference for GR-303 calls */ /* Set CRV reference for GR-303 calls */
@ -538,60 +541,60 @@ extern int pri_answer(struct pri *pri, q931_call *call, int channel, int nonisdn
/* Hangup a call */ /* Hangup a call */
#define PRI_HANGUP #define PRI_HANGUP
extern int pri_hangup(struct pri *pri, q931_call *call, int cause); int pri_hangup(struct pri *pri, q931_call *call, int cause);
#define PRI_DESTROYCALL #define PRI_DESTROYCALL
extern void pri_destroycall(struct pri *pri, q931_call *call); void pri_destroycall(struct pri *pri, q931_call *call);
#define PRI_RESTART #define PRI_RESTART
extern int pri_restart(struct pri *pri); int pri_restart(struct pri *pri);
extern int pri_reset(struct pri *pri, int channel); int pri_reset(struct pri *pri, int channel);
/* Create a new call */ /* Create a new call */
extern q931_call *pri_new_call(struct pri *pri); q931_call *pri_new_call(struct pri *pri);
/* Retrieve CRV reference for GR-303 calls. Returns >0 on success. */ /* Retrieve CRV reference for GR-303 calls. Returns >0 on success. */
extern int pri_get_crv(struct pri *pri, q931_call *call, int *callmode); int pri_get_crv(struct pri *pri, q931_call *call, int *callmode);
/* Retrieve CRV reference for GR-303 calls. CRV must be >0, call mode should be 0 */ /* Retrieve CRV reference for GR-303 calls. CRV must be >0, call mode should be 0 */
extern int pri_set_crv(struct pri *pri, q931_call *call, int crv, int callmode); int pri_set_crv(struct pri *pri, q931_call *call, int crv, int callmode);
/* How long until you need to poll for a new event */ /* How long until you need to poll for a new event */
extern struct timeval *pri_schedule_next(struct pri *pri); struct timeval *pri_schedule_next(struct pri *pri);
/* Run any pending schedule events */ /* Run any pending schedule events */
extern pri_event *pri_schedule_run(struct pri *pri); extern pri_event *pri_schedule_run(struct pri *pri);
extern pri_event *pri_schedule_run_tv(struct pri *pri, const struct timeval *now); extern pri_event *pri_schedule_run_tv(struct pri *pri, const struct timeval *now);
extern int pri_call(struct pri *pri, q931_call *c, int transmode, int channel, int pri_call(struct pri *pri, q931_call *c, int transmode, int channel,
int exclusive, int nonisdn, char *caller, int callerplan, char *callername, int callerpres, int exclusive, int nonisdn, char *caller, int callerplan, char *callername, int callerpres,
char *called,int calledplan, int ulayer1); char *called,int calledplan, int ulayer1);
extern struct pri_sr *pri_sr_new(void); struct pri_sr *pri_sr_new(void);
extern void pri_sr_free(struct pri_sr *sr); void pri_sr_free(struct pri_sr *sr);
extern int pri_sr_set_channel(struct pri_sr *sr, int channel, int exclusive, int nonisdn); 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); int pri_sr_set_bearer(struct pri_sr *sr, int transmode, int userl1);
extern int pri_sr_set_called(struct pri_sr *sr, char *called, int calledplan, int complete); 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); 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); int pri_sr_set_redirecting(struct pri_sr *sr, char *num, int plan, int pres, int reason);
#define PRI_USER_USER_TX #define PRI_USER_USER_TX
/* Set the user user field. Warning! don't send binary data accross this field */ /* Set the user user field. Warning! don't send binary data accross this field */
extern void pri_sr_set_useruser(struct pri_sr *sr, const char *userchars); void pri_sr_set_useruser(struct pri_sr *sr, const char *userchars);
extern void pri_call_set_useruser(q931_call *sr, const char *userchars); void pri_call_set_useruser(q931_call *sr, const char *userchars);
extern int pri_setup(struct pri *pri, q931_call *call, struct pri_sr *req); int pri_setup(struct pri *pri, q931_call *call, struct pri_sr *req);
/* Set a call has a call indpendent signalling connection (i.e. no bchan) */ /* Set a call has a call indpendent signalling connection (i.e. no bchan) */
extern int pri_sr_set_connection_call_independent(struct pri_sr *req); int pri_sr_set_connection_call_independent(struct pri_sr *req);
/* Send an MWI indication to a remote location. If activate is non zero, activates, if zero, decativates */ /* Send an MWI indication to a remote location. If activate is non zero, activates, if zero, decativates */
extern int pri_mwi_activate(struct pri *pri, q931_call *c, char *caller, int callerplan, char *callername, int callerpres, char *called, int calledplan); int pri_mwi_activate(struct pri *pri, q931_call *c, char *caller, int callerplan, char *callername, int callerpres, char *called, int calledplan);
/* Send an MWI deactivate request to a remote location */ /* Send an MWI deactivate request to a remote location */
extern int pri_mwi_deactivate(struct pri *pri, q931_call *c, char *caller, int callerplan, char *callername, int callerpres, char *called, int calledplan); int pri_mwi_deactivate(struct pri *pri, q931_call *c, char *caller, int callerplan, char *callername, int callerpres, char *called, int calledplan);
#define PRI_2BCT #define PRI_2BCT
/* Attempt to pass the channels back to the NET side if compatable and /* Attempt to pass the channels back to the NET side if compatable and
@ -600,30 +603,30 @@ int pri_channel_bridge(q931_call *call1, q931_call *call2);
/* Override message and error stuff */ /* Override message and error stuff */
#define PRI_NEW_SET_API #define PRI_NEW_SET_API
extern void pri_set_message(void (*__pri_error)(struct pri *pri, char *)); void pri_set_message(void (*__pri_error)(struct pri *pri, char *));
extern void pri_set_error(void (*__pri_error)(struct pri *pri, char *)); void pri_set_error(void (*__pri_error)(struct pri *pri, char *));
/* Set overlap mode */ /* Set overlap mode */
#define PRI_SET_OVERLAPDIAL #define PRI_SET_OVERLAPDIAL
extern void pri_set_overlapdial(struct pri *pri,int state); void pri_set_overlapdial(struct pri *pri,int state);
#define PRI_DUMP_INFO_STR #define PRI_DUMP_INFO_STR
extern char *pri_dump_info_str(struct pri *pri); char *pri_dump_info_str(struct pri *pri);
/* Get file descriptor */ /* Get file descriptor */
extern int pri_fd(struct pri *pri); int pri_fd(struct pri *pri);
#define PRI_PROGRESS #define PRI_PROGRESS
/* Send call proceeding */ /* Send call proceeding */
extern int pri_progress(struct pri *pri, q931_call *c, int channel, int info); int pri_progress(struct pri *pri, q931_call *c, int channel, int info);
#define PRI_PROCEEDING_FULL #define PRI_PROCEEDING_FULL
/* Send call proceeding */ /* Send call proceeding */
extern int pri_proceeding(struct pri *pri, q931_call *c, int channel, int info); int pri_proceeding(struct pri *pri, q931_call *c, int channel, int info);
/* Enslave a PRI to another, so they share the same call list /* Enslave a PRI to another, so they share the same call list
(and maybe some timers) */ (and maybe some timers) */
extern void pri_enslave(struct pri *master, struct pri *slave); void pri_enslave(struct pri *master, struct pri *slave);
#define PRI_GR303_SUPPORT #define PRI_GR303_SUPPORT
#define PRI_ENSLAVE_SUPPORT #define PRI_ENSLAVE_SUPPORT
@ -634,13 +637,13 @@ extern void pri_enslave(struct pri *master, struct pri *slave);
#define PRI_ANI #define PRI_ANI
/* Send notification */ /* Send notification */
extern int pri_notify(struct pri *pri, q931_call *c, int channel, int info); int pri_notify(struct pri *pri, q931_call *c, int channel, int info);
/* Get/Set PRI Timers */ /* Get/Set PRI Timers */
#define PRI_GETSET_TIMERS #define PRI_GETSET_TIMERS
extern int pri_set_timer(struct pri *pri, int timer, int value); int pri_set_timer(struct pri *pri, int timer, int value);
extern int pri_get_timer(struct pri *pri, int timer); int pri_get_timer(struct pri *pri, int timer);
extern int pri_timer2idx(char *timer); int pri_timer2idx(char *timer);
#define PRI_MAX_TIMERS 32 #define PRI_MAX_TIMERS 32
@ -675,6 +678,9 @@ extern int pri_timer2idx(char *timer);
#define PRI_TIMER_T321 26 #define PRI_TIMER_T321 26
#define PRI_TIMER_T322 27 #define PRI_TIMER_T322 27
#define PRI_TIMER_TM20 28 /* maximum time avaiting XID response */
#define PRI_TIMER_NM20 29 /* number of XID retransmits */
/* Get PRI version */ /* Get PRI version */
const char *pri_get_version(void); const char *pri_get_version(void);

55
pri.c
View File

@ -81,7 +81,7 @@ char *pri_switch2str(int sw)
static void pri_default_timers(struct pri *pri, int switchtype) static void pri_default_timers(struct pri *pri, int switchtype)
{ {
int defaulttimers[20][PRI_MAX_TIMERS] = PRI_TIMERS_ALL; static const int defaulttimers[20][PRI_MAX_TIMERS] = PRI_TIMERS_ALL;
int x; int x;
for (x = 0; x<PRI_MAX_TIMERS; x++) { for (x = 0; x<PRI_MAX_TIMERS; x++) {
@ -187,12 +187,20 @@ static int __pri_write(struct pri *pri, void *buf, int buflen)
return res; 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) /* Pass in the master for this function */
void __pri_free_tei(struct pri * p)
{
free (p);
}
struct pri *__pri_new_tei(int fd, int node, int switchtype, struct pri *master, pri_io_cb rd, pri_io_cb wr, void *userdata, int tei, int bri)
{ {
struct pri *p; struct pri *p;
p = malloc(sizeof(struct pri));
if (p) { if (!(p = calloc(1, sizeof(*p))))
memset(p, 0, sizeof(struct pri)); return NULL;
p->bri = bri;
p->fd = fd; p->fd = fd;
p->read_func = rd; p->read_func = rd;
p->write_func = wr; p->write_func = wr;
@ -200,13 +208,18 @@ static struct pri *__pri_new(int fd, int node, int switchtype, struct pri *maste
p->localtype = node; p->localtype = node;
p->switchtype = switchtype; p->switchtype = switchtype;
p->cref = 1; p->cref = 1;
p->sapi = Q921_SAPI_CALL_CTRL; p->sapi = (tei == Q921_TEI_GROUP) ? Q921_SAPI_LAYER2_MANAGEMENT : Q921_SAPI_CALL_CTRL;
p->tei = 0; p->tei = tei;
p->nsf = PRI_NSF_NONE; p->nsf = PRI_NSF_NONE;
p->protodisc = Q931_PROTOCOL_DISCRIMINATOR; p->protodisc = Q931_PROTOCOL_DISCRIMINATOR;
p->master = master; p->master = master;
p->callpool = &p->localpool; p->callpool = &p->localpool;
pri_default_timers(p, switchtype); pri_default_timers(p, switchtype);
if (master) {
pri_set_debug(p, master->debug);
if (master->sendfacility)
pri_facility_enable(p);
}
#ifdef LIBPRI_COUNTERS #ifdef LIBPRI_COUNTERS
p->q921_rxcount = 0; p->q921_rxcount = 0;
p->q921_txcount = 0; p->q921_txcount = 0;
@ -217,7 +230,7 @@ static struct pri *__pri_new(int fd, int node, int switchtype, struct pri *maste
p->protodisc = GR303_PROTOCOL_DISCRIMINATOR; p->protodisc = GR303_PROTOCOL_DISCRIMINATOR;
p->sapi = Q921_SAPI_GR303_EOC; p->sapi = Q921_SAPI_GR303_EOC;
p->tei = Q921_TEI_GR303_EOC_OPS; 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_tei(-1, node, PRI_SWITCH_GR303_EOC_PATH, p, NULL, NULL, NULL, Q921_TEI_GR303_EOC_PATH, 0);
if (!p->subchannel) { if (!p->subchannel) {
free(p); free(p);
p = NULL; p = NULL;
@ -226,7 +239,7 @@ static struct pri *__pri_new(int fd, int node, int switchtype, struct pri *maste
p->protodisc = GR303_PROTOCOL_DISCRIMINATOR; p->protodisc = GR303_PROTOCOL_DISCRIMINATOR;
p->sapi = Q921_SAPI_GR303_TMC_CALLPROC; p->sapi = Q921_SAPI_GR303_TMC_CALLPROC;
p->tei = Q921_TEI_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_tei(-1, node, PRI_SWITCH_GR303_TMC_SWITCHING, p, NULL, NULL, NULL, Q921_TEI_GR303_TMC_SWITCHING, 0);
if (!p->subchannel) { if (!p->subchannel) {
free(p); free(p);
p = NULL; p = NULL;
@ -243,7 +256,7 @@ static struct pri *__pri_new(int fd, int node, int switchtype, struct pri *maste
/* Start Q.921 layer, Wait if we're the network */ /* Start Q.921 layer, Wait if we're the network */
if (p) if (p)
q921_start(p, p->localtype == PRI_CPE); q921_start(p, p->localtype == PRI_CPE);
}
return p; return p;
} }
@ -270,7 +283,15 @@ int pri_restart(struct pri *pri)
struct pri *pri_new(int fd, int nodetype, int switchtype) struct pri *pri_new(int fd, int nodetype, int switchtype)
{ {
return __pri_new(fd, nodetype, switchtype, NULL, __pri_read, __pri_write, NULL); return __pri_new_tei(fd, nodetype, switchtype, NULL, __pri_read, __pri_write, NULL, Q921_TEI_PRI, 0);
}
struct pri *pri_new_bri(int fd, int ptpmode, int nodetype, int switchtype)
{
if (ptpmode)
return __pri_new_tei(fd, nodetype, switchtype, NULL, __pri_read, __pri_write, NULL, Q921_TEI_PRI, 1);
else
return __pri_new_tei(fd, nodetype, switchtype, NULL, __pri_read, __pri_write, NULL, Q921_TEI_GROUP, 1);
} }
struct pri *pri_new_cb(int fd, int nodetype, int switchtype, pri_io_cb io_read, pri_io_cb io_write, void *userdata) 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 +300,7 @@ struct pri *pri_new_cb(int fd, int nodetype, int switchtype, pri_io_cb io_read,
io_read = __pri_read; io_read = __pri_read;
if (!io_write) if (!io_write)
io_write = __pri_write; io_write = __pri_write;
return __pri_new(fd, nodetype, switchtype, NULL, io_read, io_write, userdata); return __pri_new_tei(fd, nodetype, switchtype, NULL, io_read, io_write, userdata, Q921_TEI_PRI, 0);
} }
void *pri_get_userdata(struct pri *pri) void *pri_get_userdata(struct pri *pri)
@ -556,6 +577,14 @@ int pri_channel_bridge(q931_call *call1, q931_call *call2)
else else
return 0; return 0;
break; break;
case PRI_SWITCH_QSIG:
call1->bridged_call = call2;
call2->bridged_call = call1;
if (anfpr_initiate_transfer(call1->pri, call1, call2))
return -1;
else
return 0;
break;
default: default:
return -1; return -1;
} }
@ -821,7 +850,7 @@ void pri_enslave(struct pri *master, struct pri *slave)
struct pri_sr *pri_sr_new(void) struct pri_sr *pri_sr_new(void)
{ {
struct pri_sr *req; struct pri_sr *req;
req = malloc(sizeof(struct pri_sr)); req = malloc(sizeof(*req));
if (req) if (req)
pri_sr_init(req); pri_sr_init(req);
return req; return req;

View File

@ -167,9 +167,18 @@ static unsigned char get_invokeid(struct pri *pri)
struct addressingdataelements_presentednumberunscreened { struct addressingdataelements_presentednumberunscreened {
char partyaddress[21]; char partyaddress[21];
char partysubaddress[21]; char partysubaddress[21];
int npi; int npi; /* Numbering Plan Indicator */
int ton; int ton; /* Type Of Number */
int pres; int pres; /* Presentation */
};
struct addressingdataelements_presentednumberscreened {
char partyaddress[21];
char partysubaddress[21];
int npi; /* Numbering Plan Indicator */
int ton; /* Type Of Number */
int pres; /* Presentation */
int scrind; /* Screening Indicator */
}; };
#define PRI_CHECKOVERFLOW(size) \ #define PRI_CHECKOVERFLOW(size) \
@ -453,6 +462,35 @@ static int rose_public_party_number_decode(struct pri *pri, q931_call *call, uns
return -1; return -1;
} }
static int rose_private_party_number_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value)
{
int i = 0;
struct rose_component *comp = NULL;
unsigned char *vdata = data;
int ton;
int res = 0;
if (len < 2)
return -1;
do {
GET_COMPONENT(comp, i, vdata, len);
CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Don't know what to do with PrivatePartyNumber ROSE component type 0x%x\n");
ASN1_GET_INTEGER(comp, ton);
NEXT_COMPONENT(comp, i);
ton = typeofnumber_for_q931(pri, ton);
res = rose_number_digits_decode(pri, call, &vdata[i], len-i, value);
if (res < 0)
return -1;
value->ton = ton;
return res + 3;
} while(0);
return -1;
}
static int rose_address_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value) static int rose_address_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value)
{ {
int i = 0; int i = 0;
@ -503,9 +541,11 @@ static int rose_address_decode(struct pri *pri, q931_call *call, unsigned char *
pri_message(pri, "!! telexPartyNumber isn't handled\n"); pri_message(pri, "!! telexPartyNumber isn't handled\n");
return -1; return -1;
case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_5): /* [5] priavePartyNumber */ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_5): /* [5] priavePartyNumber */
pri_message(pri, "!! privatePartyNumber isn't handled\n"); res = rose_private_party_number_decode(pri, call, comp->data, comp->len, value);
value->npi = PRI_NPI_PRIVATE; if (res < 0)
return -1; return -1;
value->npi = PRI_NPI_PRIVATE;
break;
case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_8): /* [8] nationalStandardPartyNumber */ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_8): /* [8] nationalStandardPartyNumber */
res = rose_number_digits_decode(pri, call, comp->data, comp->len, value); res = rose_number_digits_decode(pri, call, comp->data, comp->len, value);
if (res < 0) if (res < 0)
@ -589,6 +629,8 @@ static int rose_diverting_leg_information2_decode(struct pri *pri, q931_call *ca
struct rose_component *comp = NULL; struct rose_component *comp = NULL;
unsigned char *vdata = sequence->data; unsigned char *vdata = sequence->data;
int res = 0; int res = 0;
memset(&divertingnr, 0, sizeof(divertingnr));
memset(&originalcallednr, 0, sizeof(originalcallednr));
/* Data checks */ /* Data checks */
if (sequence->type != (ASN1_CONSTRUCTOR | ASN1_SEQUENCE)) { /* Constructed Sequence */ if (sequence->type != (ASN1_CONSTRUCTOR | ASN1_SEQUENCE)) { /* Constructed Sequence */
@ -670,6 +712,9 @@ static int rose_diverting_leg_information2_decode(struct pri *pri, q931_call *ca
if (pri->debug & PRI_DEBUG_APDU) if (pri->debug & PRI_DEBUG_APDU)
pri_message(pri, " Received Originally Called Name '%s'\n", origcalledname); pri_message(pri, " Received Originally Called Name '%s'\n", origcalledname);
break; break;
case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_5):
pri_message(pri, "!! Ignoring DivertingLegInformation2 component 0x%X\n", comp->type);
break;
default: default:
if (comp->type == 0 && comp->len == 0) { if (comp->type == 0 && comp->len == 0) {
break; /* Found termination characters */ break; /* Found termination characters */
@ -684,11 +729,13 @@ static int rose_diverting_leg_information2_decode(struct pri *pri, q931_call *ca
call->redirectingpres = divertingnr.pres; call->redirectingpres = divertingnr.pres;
call->redirectingreason = diversion_reason; call->redirectingreason = diversion_reason;
libpri_copy_string(call->redirectingnum, divertingnr.partyaddress, sizeof(call->redirectingnum)); libpri_copy_string(call->redirectingnum, divertingnr.partyaddress, sizeof(call->redirectingnum));
pri_message(pri, " Received redirectingnum '%s' (%d)\n", call->redirectingnum, (int)call->redirectingnum[0]);
} }
if (originalcallednr.pres >= 0) { if (originalcallednr.pres >= 0) {
call->origcalledplan = originalcallednr.npi; call->origcalledplan = originalcallednr.npi;
call->origcalledpres = originalcallednr.pres; call->origcalledpres = originalcallednr.pres;
libpri_copy_string(call->origcallednum, originalcallednr.partyaddress, sizeof(call->origcallednum)); libpri_copy_string(call->origcallednum, originalcallednr.partyaddress, sizeof(call->origcallednum));
pri_message(pri, " Received origcallednum '%s' (%d)\n", call->origcallednum, (int)call->origcallednum[0]);
} }
libpri_copy_string(call->redirectingname, redirectingname, sizeof(call->redirectingname)); libpri_copy_string(call->redirectingname, redirectingname, sizeof(call->redirectingname));
libpri_copy_string(call->origcalledname, origcalledname, sizeof(call->origcalledname)); libpri_copy_string(call->origcalledname, origcalledname, sizeof(call->origcalledname));
@ -1134,6 +1181,162 @@ int eect_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2)
} }
/* End EECT */ /* End EECT */
static int anfpr_pathreplacement_respond(struct pri *pri, q931_call *call, q931_ie *ie)
{
int res;
res = pri_call_apdu_queue_cleanup(call->bridged_call);
if (res) {
pri_message(pri, "Could not Clear queue ADPU\n");
return -1;
}
/* Send message */
res = pri_call_apdu_queue(call->bridged_call, Q931_FACILITY, ie->data, ie->len, 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(call->bridged_call->pri, call->bridged_call);
if (res) {
pri_message(pri, "Could not schedule facility message for call %d\n", call->bridged_call->cr);
return -1;
}
return 0;
}
/* AFN-PR */
extern int anfpr_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2)
{
/* Did all the tests to see if we're on the same PRI and
* are on a compatible switchtype */
/* TODO */
int i = 0;
int res = 0;
unsigned char buffer[255] = "";
unsigned short call_reference = c2->cr;
struct rose_component *comp = NULL, *compstk[10];
unsigned char buffer2[255] = "";
int compsp = 0;
static unsigned char op_tag[] = {
0x0C,
};
/* Channel 1 */
buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS);
/* Interpretation component */
ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer, i);
ASN1_PUSH(compstk, compsp, comp);
ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i, 0);
ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i, 0);
ASN1_FIXUP(compstk, compsp, buffer, i);
ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 2); /* reject - to get feedback from QSIG switch */
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));
res = asn1_string_encode(ASN1_INTEGER, &buffer[i], sizeof(buffer)-i, sizeof(op_tag), op_tag, sizeof(op_tag));
if (res < 0)
return -1;
i += res;
ASN1_ADD_SIMPLE(comp, (ASN1_SEQUENCE | ASN1_CONSTRUCTOR), buffer, i);
ASN1_PUSH(compstk, compsp, comp);
buffer[i++] = (0x0a);
buffer[i++] = (0x01);
buffer[i++] = (0x00);
buffer[i++] = (0x81);
buffer[i++] = (0x00);
buffer[i++] = (0x0a);
buffer[i++] = (0x01);
buffer[i++] = (0x01);
ASN1_ADD_WORDCOMP(comp, ASN1_INTEGER, buffer, i, call_reference);
ASN1_FIXUP(compstk, compsp, buffer, i);
ASN1_FIXUP(compstk, compsp, buffer, i);
res = pri_call_apdu_queue(c1, Q931_FACILITY, 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(c1->pri, c1);
if (res) {
pri_message(pri, "Could not schedule facility message for call %d\n", c1->cr);
return -1;
}
/* Channel 2 */
i = 0;
res = 0;
compsp = 0;
buffer2[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS);
/* Interpretation component */
ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer2, i);
ASN1_PUSH(compstk, compsp, comp);
ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer2, i, 0);
ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer2, i, 0);
ASN1_FIXUP(compstk, compsp, buffer2, i);
ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer2, i, 2); /* reject */
ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer2, i);
ASN1_PUSH(compstk, compsp, comp);
ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer2, i, get_invokeid(pri));
res = asn1_string_encode(ASN1_INTEGER, &buffer2[i], sizeof(buffer2)-i, sizeof(op_tag), op_tag, sizeof(op_tag));
if (res < 0)
return -1;
i += res;
ASN1_ADD_SIMPLE(comp, (ASN1_SEQUENCE | ASN1_CONSTRUCTOR), buffer2, i);
ASN1_PUSH(compstk, compsp, comp);
buffer2[i++] = (0x0a);
buffer2[i++] = (0x01);
buffer2[i++] = (0x01);
buffer2[i++] = (0x81);
buffer2[i++] = (0x00);
buffer2[i++] = (0x0a);
buffer2[i++] = (0x01);
buffer2[i++] = (0x01);
ASN1_ADD_WORDCOMP(comp, ASN1_INTEGER, buffer2, i, call_reference);
ASN1_FIXUP(compstk, compsp, buffer2, i);
ASN1_FIXUP(compstk, compsp, buffer2, i);
res = pri_call_apdu_queue(c2, Q931_FACILITY, buffer2, 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(c2->pri, c2);
if (res) {
pri_message(pri, "Could not schedule facility message for call %d\n", c1->cr);
return -1;
}
return 0;
}
/* End AFN-PR */
/* AOC */ /* AOC */
static int aoc_aoce_charging_request_decode(struct pri *pri, q931_call *call, unsigned char *data, int len) static int aoc_aoce_charging_request_decode(struct pri *pri, q931_call *call, unsigned char *data, int len)
{ {
@ -1340,7 +1543,433 @@ static int aoc_aoce_charging_unit_encode(struct pri *pri, q931_call *c, long cha
} }
/* End AOC */ /* End AOC */
int rose_reject_decode(struct pri *pri, q931_call *call, unsigned char *data, int len) /* ===== Call Transfer Supplementary Service (ECMA-178) ===== */
static int rose_party_number_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;
do {
GET_COMPONENT(comp, i, vdata, len);
switch(comp->type) {
case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0): /* [0] IMPLICIT NumberDigits -- default: unknownPartyNumber */
if (pri->debug & PRI_DEBUG_APDU)
pri_message(pri, " PartyNumber: UnknownPartyNumber len=%d\n", len);
size = rose_number_digits_decode(pri, call, comp->data, comp->len, value);
if (size < 0)
return -1;
value->npi = PRI_NPI_UNKNOWN;
value->ton = PRI_TON_UNKNOWN;
break;
case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1): /* [1] IMPLICIT PublicPartyNumber */
if (pri->debug & PRI_DEBUG_APDU)
pri_message(pri, " PartyNumber: PublicPartyNumber len=%d\n", len);
size = rose_public_party_number_decode(pri, call, comp->data, comp->len, value);
if (size < 0)
return -1;
value->npi = PRI_NPI_E163_E164;
break;
case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3): /* [3] IMPLICIT NumberDigits -- not used: dataPartyNumber */
pri_message(pri, "!! PartyNumber: dataPartyNumber is reserved!\n");
size = rose_number_digits_decode(pri, call, comp->data, comp->len, value);
if (size < 0)
return -1;
value->npi = PRI_NPI_X121 /* ??? */;
value->ton = PRI_TON_UNKNOWN /* ??? */;
break;
case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_4): /* [4] IMPLICIT NumberDigits -- not used: telexPartyNumber */
pri_message(pri, "!! PartyNumber: telexPartyNumber is reserved!\n");
size = rose_number_digits_decode(pri, call, comp->data, comp->len, value);
if (size < 0)
return -1;
value->npi = PRI_NPI_F69 /* ??? */;
value->ton = PRI_TON_UNKNOWN /* ??? */;
break;
case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_5): /* [5] IMPLICIT PrivatePartyNumber */
if (pri->debug & PRI_DEBUG_APDU)
pri_message(pri, " PartyNumber: PrivatePartyNumber len=%d\n", len);
size = rose_private_party_number_decode(pri, call, comp->data, comp->len, value);
if (size < 0)
return -1;
value->npi = PRI_NPI_PRIVATE;
break;
case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_8): /* [8] IMPLICIT NumberDigits -- not used: nationalStandatdPartyNumber */
pri_message(pri, "!! PartyNumber: nationalStandardPartyNumber is reserved!\n");
size = rose_number_digits_decode(pri, call, comp->data, comp->len, value);
if (size < 0)
return -1;
value->npi = PRI_NPI_NATIONAL;
value->ton = PRI_TON_NATIONAL;
break;
default:
pri_message(pri, "Invalid PartyNumber component 0x%X\n", comp->type);
return -1;
}
ASN1_FIXUP_LEN(comp, size);
if (pri->debug & PRI_DEBUG_APDU)
pri_message(pri, " PartyNumber: '%s' size=%d len=%d\n", value->partyaddress, size, len);
return size;
}
while (0);
return -1;
}
static int rose_number_screened_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberscreened *value)
{
int i = 0;
int size = 0;
struct rose_component *comp = NULL;
unsigned char *vdata = data;
int scrind = -1;
do {
/* Party Number */
GET_COMPONENT(comp, i, vdata, len);
size = rose_party_number_decode(pri, call, (u_int8_t *)comp, comp->len + 2, (struct addressingdataelements_presentednumberunscreened*) value);
if (size < 0)
return -1;
comp->len = size;
NEXT_COMPONENT(comp, i);
/* Screening Indicator */
GET_COMPONENT(comp, i, vdata, len);
CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Don't know what to do with NumberScreened ROSE component type 0x%x\n");
ASN1_GET_INTEGER(comp, scrind);
// Todo: scrind = screeningindicator_for_q931(pri, scrind);
NEXT_COMPONENT(comp, i);
value->scrind = scrind;
if (pri->debug & PRI_DEBUG_APDU)
pri_message(pri, " NumberScreened: '%s' ScreeningIndicator=%d i=%d len=%d\n", value->partyaddress, scrind, i, len);
return i-2; // We do not have a sequence header here.
}
while (0);
return -1;
}
static int rose_presented_number_screened_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberscreened *value)
{
int i = 0;
int size = 0;
struct rose_component *comp = NULL;
unsigned char *vdata = data;
/* Fill in default values */
value->ton = PRI_TON_UNKNOWN;
value->npi = PRI_NPI_UNKNOWN;
value->pres = -1; /* Data is not available */
do {
GET_COMPONENT(comp, i, vdata, len);
switch(comp->type) {
case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0): /* [0] IMPLICIT presentationAllowedNumber */
if (pri->debug & PRI_DEBUG_APDU)
pri_message(pri, " PresentedNumberScreened: presentationAllowedNumber comp->len=%d\n", comp->len);
value->pres = PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN;
size = rose_number_screened_decode(pri, call, comp->data, comp->len, value);
if (size < 0)
return -1;
ASN1_FIXUP_LEN(comp, size);
return size + 2;
case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1): /* [1] IMPLICIT presentationRestricted */
if (pri->debug & PRI_DEBUG_APDU)
pri_message(pri, " PresentedNumberScreened: presentationRestricted comp->len=%d\n", comp->len);
if (comp->len != 0) { /* must be NULL */
pri_error(pri, "!! Invalid PresentationRestricted component received (len != 0)\n");
return -1;
}
value->pres = PRES_PROHIB_USER_NUMBER_PASSED_SCREEN;
return 2;
case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2): /* [2] IMPLICIT numberNotAvailableDueToInterworking */
if (pri->debug & PRI_DEBUG_APDU)
pri_message(pri, " PresentedNumberScreened: NumberNotAvailableDueToInterworking comp->len=%d\n", comp->len);
if (comp->len != 0) { /* must be NULL */
pri_error(pri, "!! Invalid NumberNotAvailableDueToInterworking component received (len != 0)\n");
return -1;
}
value->pres = PRES_NUMBER_NOT_AVAILABLE;
if (pri->debug & PRI_DEBUG_APDU)
pri_message(pri, " PresentedNumberScreened: numberNotAvailableDueToInterworking Type=0x%X i=%d len=%d size=%d\n", comp->type, i, len);
return 2;
case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3): /* [3] IMPLICIT presentationRestrictedNumber */
if (pri->debug & PRI_DEBUG_APDU)
pri_message(pri, " PresentedNumberScreened: presentationRestrictedNumber comp->len=%d\n", comp->len);
value->pres = PRES_PROHIB_USER_NUMBER_PASSED_SCREEN;
size = rose_number_screened_decode(pri, call, comp->data, comp->len, value);
if (size < 0)
return -1;
ASN1_FIXUP_LEN(comp, size);
return size + 2;
default:
pri_message(pri, "Invalid PresentedNumberScreened component 0x%X\n", comp->type);
}
return -1;
}
while (0);
return -1;
}
static int rose_call_transfer_complete_decode(struct pri *pri, q931_call *call, struct rose_component *sequence, int len)
{
int i = 0;
struct rose_component *comp = NULL;
unsigned char *vdata = sequence->data;
int res = 0;
int end_designation = 0;
struct addressingdataelements_presentednumberscreened redirection_number;
char redirection_name[50] = "";
int call_status = 0;
redirection_number.partyaddress[0] = 0;
redirection_number.partysubaddress[0] = 0;
call->callername[0] = 0;
call->callernum[0] = 0;
/* Data checks */
if (sequence->type != (ASN1_CONSTRUCTOR | ASN1_SEQUENCE)) { /* Constructed Sequence */
pri_message(pri, "Invalid callTransferComplete argument. (Not a sequence)\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;
if (pri->debug & PRI_DEBUG_APDU)
pri_message(pri, " CT-Complete: len=%d\n", len);
do {
/* End Designation */
GET_COMPONENT(comp, i, vdata, len);
CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Invalid endDesignation type 0x%X of ROSE callTransferComplete component received\n");
ASN1_GET_INTEGER(comp, end_designation);
NEXT_COMPONENT(comp, i);
if (pri->debug & PRI_DEBUG_APDU)
pri_message(pri, " CT-Complete: Received endDesignation=%d\n", end_designation);
/* Redirection Number */
GET_COMPONENT(comp, i, vdata, len);
res = rose_presented_number_screened_decode(pri, call, (u_int8_t *)comp, comp->len + 2, &redirection_number);
if (res < 0)
return -1;
comp->len = res;
if (res > 2) {
if (pri->debug & PRI_DEBUG_APDU)
pri_message(pri, " CT-Complete: Received redirectionNumber=%s\n", redirection_number.partyaddress);
strncpy(call->callernum, redirection_number.partyaddress, 20);
call->callernum[20] = 0;
}
NEXT_COMPONENT(comp, i);
#if 0 /* This one is optional. How do we check if it is there? */
/* Basic Call Info Elements */
GET_COMPONENT(comp, i, vdata, len);
NEXT_COMPONENT(comp, i);
#endif
/* Redirection Name */
GET_COMPONENT(comp, i, vdata, len);
res = asn1_name_decode((u_int8_t *)comp, comp->len + 2, redirection_name, sizeof(redirection_name));
if (res < 0)
return -1;
memcpy(call->callername, comp->data, comp->len);
call->callername[comp->len] = 0;
ASN1_FIXUP_LEN(comp, res);
comp->len = res;
NEXT_COMPONENT(comp, i);
if (pri->debug & PRI_DEBUG_APDU)
pri_message(pri, " CT-Complete: Received redirectionName '%s'\n", redirection_name);
/* Call Status */
GET_COMPONENT(comp, i, vdata, len);
CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Invalid callStatus type 0x%X of ROSE callTransferComplete component received\n");
ASN1_GET_INTEGER(comp, call_status);
NEXT_COMPONENT(comp, i);
if (pri->debug & PRI_DEBUG_APDU)
pri_message(pri, " CT-Complete: Received callStatus=%d\n", call_status);
/* Argument Extension */
#if 0 /* Not supported */
GET_COMPONENT(comp, i, vdata, len);
switch (comp->type) {
case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_9): /* [9] IMPLICIT Extension */
res = rose_extension_decode(pri, call, comp->data, comp->len, &redirection_number);
if (res < 0)
return -1;
ASN1_FIXUP_LEN(comp, res);
comp->len = res;
case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_10): /* [10] IMPLICIT SEQUENCE OF Extension */
res = rose_sequence_of_extension_decode(pri, call, comp->data, comp->len, &redirection_number);
if (res < 0)
return -1;
ASN1_FIXUP_LEN(comp, res);
comp->len = res;
default:
pri_message(pri, " CT-Complete: !! Unknown argumentExtension received 0x%X\n", comp->type);
return -1;
}
#else
GET_COMPONENT(comp, i, vdata, len);
ASN1_FIXUP_LEN(comp, res);
NEXT_COMPONENT(comp, i);
#endif
if(i < len)
pri_message(pri, " CT-Complete: !! not all information is handled !! i=%d / len=%d\n", i, len);
return 0;
}
while (0);
return -1;
}
static int rose_call_transfer_update_decode(struct pri *pri, q931_call *call, struct rose_component *sequence, int len)
{
int i = 0;
struct rose_component *comp = NULL;
unsigned char *vdata = sequence->data;
int res = 0;
struct addressingdataelements_presentednumberscreened redirection_number;
redirection_number.partyaddress[0] = 0;
redirection_number.partysubaddress[0] = 0;
char redirection_name[50] = "";
call->callername[0] = 0;
call->callernum[0] = 0;
/* Data checks */
if (sequence->type != (ASN1_CONSTRUCTOR | ASN1_SEQUENCE)) { /* Constructed Sequence */
pri_message(pri, "Invalid callTransferComplete argument. (Not a sequence)\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;
if (pri->debug & PRI_DEBUG_APDU)
pri_message(pri, " CT-Complete: len=%d\n", len);
do {
/* Redirection Number */
GET_COMPONENT(comp, i, vdata, len);
res = rose_presented_number_screened_decode(pri, call, (u_int8_t *)comp, comp->len + 2, &redirection_number);
if (res < 0)
return -1;
comp->len = res;
if (res > 2) {
if (pri->debug & PRI_DEBUG_APDU)
pri_message(pri, " CT-Complete: Received redirectionNumber=%s\n", redirection_number.partyaddress);
strncpy(call->callernum, redirection_number.partyaddress, 20);
call->callernum[20] = 0;
}
NEXT_COMPONENT(comp, i);
/* Redirection Name */
GET_COMPONENT(comp, i, vdata, len);
res = asn1_name_decode((u_int8_t *)comp, comp->len + 2, redirection_name, sizeof(redirection_name));
if (res < 0)
return -1;
memcpy(call->callername, comp->data, comp->len);
call->callername[comp->len] = 0;
ASN1_FIXUP_LEN(comp, res);
comp->len = res;
NEXT_COMPONENT(comp, i);
if (pri->debug & PRI_DEBUG_APDU)
pri_message(pri, " CT-Complete: Received redirectionName '%s'\n", redirection_name);
#if 0 /* This one is optional. How do we check if it is there? */
/* Basic Call Info Elements */
GET_COMPONENT(comp, i, vdata, len);
NEXT_COMPONENT(comp, i);
#endif
/* Argument Extension */
#if 0 /* Not supported */
GET_COMPONENT(comp, i, vdata, len);
switch (comp->type) {
case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_9): /* [9] IMPLICIT Extension */
res = rose_extension_decode(pri, call, comp->data, comp->len, &redirection_number);
if (res < 0)
return -1;
ASN1_FIXUP_LEN(comp, res);
comp->len = res;
case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_10): /* [10] IMPLICIT SEQUENCE OF Extension */
res = rose_sequence_of_extension_decode(pri, call, comp->data, comp->len, &redirection_number);
if (res < 0)
return -1;
ASN1_FIXUP_LEN(comp, res);
comp->len = res;
default:
pri_message(pri, " CT-Complete: !! Unknown argumentExtension received 0x%X\n", comp->type);
return -1;
}
#else
GET_COMPONENT(comp, i, vdata, len);
ASN1_FIXUP_LEN(comp, res);
NEXT_COMPONENT(comp, i);
#endif
if(i < len)
pri_message(pri, " CT-Complete: !! not all information is handled !! i=%d / len=%d\n", i, len);
return 0;
}
while (0);
return -1;
}
/* ===== End Call Transfer Supplementary Service (ECMA-178) ===== */
int rose_reject_decode(struct pri *pri, q931_call *call, q931_ie *ie, unsigned char *data, int len)
{ {
int i = 0; int i = 0;
int problemtag = -1; int problemtag = -1;
@ -1408,7 +2037,7 @@ int rose_reject_decode(struct pri *pri, q931_call *call, unsigned char *data, in
return -1; return -1;
} }
int rose_return_error_decode(struct pri *pri, q931_call *call, unsigned char *data, int len) int rose_return_error_decode(struct pri *pri, q931_call *call, q931_ie *ie, unsigned char *data, int len)
{ {
int i = 0; int i = 0;
int errorvalue = -1; int errorvalue = -1;
@ -1472,7 +2101,7 @@ int rose_return_error_decode(struct pri *pri, q931_call *call, unsigned char *da
return -1; return -1;
} }
int rose_return_result_decode(struct pri *pri, q931_call *call, unsigned char *data, int len) int rose_return_result_decode(struct pri *pri, q931_call *call, q931_ie *ie, unsigned char *data, int len)
{ {
int i = 0; int i = 0;
int operationidvalue = -1; int operationidvalue = -1;
@ -1534,9 +2163,10 @@ int rose_return_result_decode(struct pri *pri, q931_call *call, unsigned char *d
return -1; return -1;
} }
int rose_invoke_decode(struct pri *pri, q931_call *call, unsigned char *data, int len) int rose_invoke_decode(struct pri *pri, q931_call *call, q931_ie *ie, unsigned char *data, int len)
{ {
int i = 0; int i = 0;
int res = 0;
int operation_tag; int operation_tag;
unsigned char *vdata = data; unsigned char *vdata = data;
struct rose_component *comp = NULL, *invokeid = NULL, *operationid = NULL; struct rose_component *comp = NULL, *invokeid = NULL, *operationid = NULL;
@ -1587,6 +2217,50 @@ int rose_invoke_decode(struct pri *pri, q931_call *call, unsigned char *data, in
return -1; return -1;
} }
break; break;
case ROSE_CALL_TRANSFER_IDENTIFY:
if (pri->debug & PRI_DEBUG_APDU)
pri_message(pri, "ROSE %i: CallTransferIdentify - not handled!\n", operation_tag);
dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
return -1;
case ROSE_CALL_TRANSFER_ABANDON:
if (pri->debug & PRI_DEBUG_APDU)
pri_message(pri, "ROSE %i: CallTransferAbandon - not handled!\n", operation_tag);
dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
return -1;
case ROSE_CALL_TRANSFER_INITIATE:
if (pri->debug & PRI_DEBUG_APDU)
pri_message(pri, "ROSE %i: CallTransferInitiate - not handled!\n", operation_tag);
dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
return -1;
case ROSE_CALL_TRANSFER_SETUP:
if (pri->debug & PRI_DEBUG_APDU)
pri_message(pri, "ROSE %i: CallTransferSetup - not handled!\n", operation_tag);
dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
return -1;
case ROSE_CALL_TRANSFER_ACTIVE:
if (pri->debug & PRI_DEBUG_APDU)
pri_message(pri, "ROSE %i: CallTransferActive - not handled!\n", operation_tag);
dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
return -1;
case ROSE_CALL_TRANSFER_COMPLETE:
if (pri->debug & PRI_DEBUG_APDU)
{
pri_message(pri, "ROSE %i: Handle CallTransferComplete\n", operation_tag);
dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
}
return rose_call_transfer_complete_decode(pri, call, comp, len-i);
case ROSE_CALL_TRANSFER_UPDATE:
if (pri->debug & PRI_DEBUG_APDU)
{
pri_message(pri, "ROSE %i: Handle CallTransferUpdate\n", operation_tag);
dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
}
return rose_call_transfer_update_decode(pri, call, comp, len-i);
case ROSE_SUBADDRESS_TRANSFER:
if (pri->debug & PRI_DEBUG_APDU)
pri_message(pri, "ROSE %i: SubaddressTransfer - not handled!\n", operation_tag);
dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
return -1;
case ROSE_DIVERTING_LEG_INFORMATION2: case ROSE_DIVERTING_LEG_INFORMATION2:
if (pri->debug & PRI_DEBUG_APDU) if (pri->debug & PRI_DEBUG_APDU)
pri_message(pri, " Handle DivertingLegInformation2\n"); pri_message(pri, " Handle DivertingLegInformation2\n");
@ -1641,6 +2315,15 @@ int rose_invoke_decode(struct pri *pri, q931_call *call, unsigned char *data, in
dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
} }
return -1; return -1;
case SS_ANFPR_PATHREPLACEMENT:
/* Clear Queue */
res = pri_call_apdu_queue_cleanup(call->bridged_call);
if (res) {
pri_message(pri, "Could not Clear queue ADPU\n");
return -1;
}
anfpr_pathreplacement_respond(pri, call, ie);
break;
default: default:
if (pri->debug & PRI_DEBUG_APDU) { if (pri->debug & PRI_DEBUG_APDU) {
pri_message(pri, "!! Unable to handle ROSE operation %d", operation_tag); pri_message(pri, "!! Unable to handle ROSE operation %d", operation_tag);
@ -1661,19 +2344,16 @@ int pri_call_apdu_queue(q931_call *call, int messagetype, void *apdu, int apdu_l
if (!call || !messagetype || !apdu || (apdu_len < 1) || (apdu_len > 255)) if (!call || !messagetype || !apdu || (apdu_len < 1) || (apdu_len > 255))
return -1; return -1;
new_event = malloc(sizeof(struct apdu_event)); if (!(new_event = calloc(1, sizeof(*new_event)))) {
pri_error(call->pri, "!! Malloc failed!\n");
return -1;
}
if (new_event) {
memset(new_event, 0, sizeof(struct apdu_event));
new_event->message = messagetype; new_event->message = messagetype;
new_event->callback = function; new_event->callback = function;
new_event->data = data; new_event->data = data;
memcpy(new_event->apdu, apdu, apdu_len); memcpy(new_event->apdu, apdu, apdu_len);
new_event->apdu_len = apdu_len; new_event->apdu_len = apdu_len;
} else {
pri_error(call->pri, "!! Malloc failed!\n");
return -1;
}
if (call->apdus) { if (call->apdus) {
cur = call->apdus; cur = call->apdus;

View File

@ -9,6 +9,7 @@
#ifndef _PRI_FACILITY_H #ifndef _PRI_FACILITY_H
#define _PRI_FACILITY_H #define _PRI_FACILITY_H
#include "pri_q931.h"
/* Protocol Profile field */ /* Protocol Profile field */
#define Q932_PROTOCOL_ROSE 0x11 /* X.219 & X.229 */ #define Q932_PROTOCOL_ROSE 0x11 /* X.219 & X.229 */
@ -32,6 +33,15 @@
#define COMP_TYPE_NFE 0xAA #define COMP_TYPE_NFE 0xAA
/* Operation ID values */ /* Operation ID values */
/* Q.952.7 (ECMA-178) ROSE operations (Transfer) */
#define ROSE_CALL_TRANSFER_IDENTIFY 7
#define ROSE_CALL_TRANSFER_ABANDON 8
#define ROSE_CALL_TRANSFER_INITIATE 9
#define ROSE_CALL_TRANSFER_SETUP 10
#define ROSE_CALL_TRANSFER_ACTIVE 11
#define ROSE_CALL_TRANSFER_COMPLETE 12
#define ROSE_CALL_TRANSFER_UPDATE 13
#define ROSE_SUBADDRESS_TRANSFER 14
/* Q.952 ROSE operations (Diverting) */ /* Q.952 ROSE operations (Diverting) */
#define ROSE_DIVERTING_LEG_INFORMATION1 18 #define ROSE_DIVERTING_LEG_INFORMATION1 18
#define ROSE_DIVERTING_LEG_INFORMATION2 0x15 #define ROSE_DIVERTING_LEG_INFORMATION2 0x15
@ -48,6 +58,7 @@
#define ROSE_AOC_IDENTIFICATION_OF_CHARGE 37 #define ROSE_AOC_IDENTIFICATION_OF_CHARGE 37
/* Q.SIG operations */ /* Q.SIG operations */
#define SS_CNID_CALLINGNAME 0 #define SS_CNID_CALLINGNAME 0
#define SS_ANFPR_PATHREPLACEMENT 4
#define SS_DIVERTING_LEG_INFORMATION2 21 #define SS_DIVERTING_LEG_INFORMATION2 21
#define SS_MWI_ACTIVATE 80 #define SS_MWI_ACTIVATE 80
#define SS_MWI_DEACTIVATE 81 #define SS_MWI_DEACTIVATE 81
@ -146,7 +157,8 @@ struct rose_component {
u_int8_t data[0]; u_int8_t data[0];
}; };
#define GET_COMPONENT(component, idx, ptr, length) \ #if 1
#define GET_COMPONENT(component, idx, ptr, length) \
if ((idx)+2 > (length)) \ if ((idx)+2 > (length)) \
break; \ break; \
(component) = (struct rose_component*)&((ptr)[idx]); \ (component) = (struct rose_component*)&((ptr)[idx]); \
@ -154,16 +166,24 @@ struct rose_component {
if ((component)->len != ASN1_LEN_INDEF) \ if ((component)->len != ASN1_LEN_INDEF) \
pri_message(pri, "Length (%d) of 0x%X component is too long\n", (component)->len, (component)->type); \ pri_message(pri, "Length (%d) of 0x%X component is too long\n", (component)->len, (component)->type); \
} }
/* #else /* Debugging */
pri_message("XX Got component %d (0x%02X), length %d\n", (component)->type, (component)->type, (component)->len); \ #define GET_COMPONENT(component, idx, ptr, length) \
if ((idx)+2 > (length)) \
break; \
(component) = (struct rose_component*)&((ptr)[idx]); \
if ((idx)+(component)->len+2 > (length)) { \
if ((component)->len != 128) \
pri_message(pri, "Length (%d) of 0x%X component is too long\n", (component)->len, (component)->type); \
} \
pri_message(pri, "XX %s:%d Got component %d (0x%02X), length %d\n", __FUNCTION__, __LINE__, (component)->type, (component)->type, (component)->len); \
if ((component)->len > 0) { \ if ((component)->len > 0) { \
int zzz; \ int zzz; \
pri_message("XX Data:"); \ pri_message(pri, "XX Data:"); \
for (zzz = 0; zzz < (component)->len; ++zzz) \ for (zzz = 0; zzz < (component)->len; ++zzz) \
pri_message(" %02X", (component)->data[zzz]); \ pri_message(pri, " %02X", (component)->data[zzz]); \
pri_message("\n"); \ pri_message(pri, "\n"); \
} }
*/ #endif
#define NEXT_COMPONENT(component, idx) \ #define NEXT_COMPONENT(component, idx) \
(idx) += (component)->len + 2 (idx) += (component)->len + 2
@ -236,16 +256,16 @@ struct rose_component {
} while (0) } while (0)
/* Decoder for the invoke ROSE component */ /* Decoder for the invoke ROSE component */
int rose_invoke_decode(struct pri *pri, struct q931_call *call, unsigned char *data, int len); int rose_invoke_decode(struct pri *pri, struct q931_call *call, q931_ie *ie, unsigned char *data, int len);
/* Decoder for the return result ROSE component */ /* Decoder for the return result ROSE component */
int rose_return_result_decode(struct pri *pri, struct q931_call *call, unsigned char *data, int len); int rose_return_result_decode(struct pri *pri, struct q931_call *call, q931_ie *ie, unsigned char *data, int len);
/* Decoder for the return error ROSE component */ /* Decoder for the return error ROSE component */
int rose_return_error_decode(struct pri *pri, struct q931_call *call, unsigned char *data, int len); int rose_return_error_decode(struct pri *pri, struct q931_call *call, q931_ie *ie, unsigned char *data, int len);
/* Decoder for the reject ROSE component */ /* Decoder for the reject ROSE component */
int rose_reject_decode(struct pri *pri, struct q931_call *call, unsigned char *data, int len); int rose_reject_decode(struct pri *pri, struct q931_call *call, q931_ie *ie, unsigned char *data, int len);
int asn1_copy_string(char * buf, int buflen, struct rose_component *comp); int asn1_copy_string(char * buf, int buflen, struct rose_component *comp);
@ -266,6 +286,9 @@ int eect_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2);
int rlt_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2); int rlt_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2);
/* starts a QSIG Path Replacement */
extern int anfpr_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2);
/* Use this function to queue a facility-IE born APDU onto a call /* Use this function to queue a facility-IE born APDU onto a call
* call is the call to use, messagetype is any one of the Q931 messages, * call is the call to use, messagetype is any one of the Q931 messages,
* apdu is the apdu data, apdu_len is the length of the apdu data */ * apdu is the apdu data, apdu_len is the length of the apdu data */

View File

@ -61,6 +61,7 @@ struct pri {
int localtype; /* Local network type (unknown, network, cpe) */ int localtype; /* Local network type (unknown, network, cpe) */
int remotetype; /* Remote network type (unknown, network, cpe) */ int remotetype; /* Remote network type (unknown, network, cpe) */
int bri;
int sapi; int sapi;
int tei; int tei;
int protodisc; int protodisc;
@ -83,7 +84,11 @@ struct pri {
/* Various timers */ /* Various timers */
int sabme_timer; /* SABME retransmit */ int sabme_timer; /* SABME retransmit */
int sabme_count; /* SABME retransmit counter for BRI */
int t203_timer; /* Max idle time */ int t203_timer; /* Max idle time */
int t202_timer;
int n202_counter;
int ri;
int t200_timer; /* T-200 retransmission timer */ int t200_timer; /* T-200 retransmission timer */
/* All ISDN Timer values */ /* All ISDN Timer values */
int timers[MAX_TIMERS]; int timers[MAX_TIMERS];
@ -247,6 +252,9 @@ struct q931_call {
int transferable; int transferable;
unsigned int rlt_call_id; /* RLT call id */ unsigned int rlt_call_id; /* RLT call id */
/* Bridged call info */
q931_call *bridged_call; /* Pointer to other leg of bridged call */
}; };
extern int pri_schedule_event(struct pri *pri, int ms, void (*function)(void *data), void *data); extern int pri_schedule_event(struct pri *pri, int ms, void (*function)(void *data), void *data);
@ -263,4 +271,8 @@ extern void pri_error(struct pri *pri, char *fmt, ...);
void libpri_copy_string(char *dst, const char *src, size_t size); void libpri_copy_string(char *dst, const char *src, size_t size);
struct pri *__pri_new_tei(int fd, int node, int switchtype, struct pri *master, pri_io_cb rd, pri_io_cb wr, void *userdata, int tei, int bri);
void __pri_free_tei(struct pri *p);
#endif #endif

View File

@ -47,6 +47,7 @@
#define Q921_FRAMETYPE_S 0x1 #define Q921_FRAMETYPE_S 0x1
#define Q921_TEI_GROUP 127 #define Q921_TEI_GROUP 127
#define Q921_TEI_PRI 0
#define Q921_TEI_GR303_EOC_PATH 0 #define Q921_TEI_GR303_EOC_PATH 0
#define Q921_TEI_GR303_EOC_OPS 4 #define Q921_TEI_GR303_EOC_OPS 4
#define Q921_TEI_GR303_TMC_SWITCHING 0 #define Q921_TEI_GR303_TMC_SWITCHING 0
@ -63,6 +64,14 @@
#define Q921_SAPI_LAYER2_MANAGEMENT 63 #define Q921_SAPI_LAYER2_MANAGEMENT 63
#define Q921_TEI_IDENTITY_REQUEST 1
#define Q921_TEI_IDENTITY_ASSIGNED 2
#define Q921_TEI_IDENTITY_DENIED 3
#define Q921_TEI_IDENTITY_CHECK_REQUEST 4
#define Q921_TEI_IDENTITY_CHECK_RESPONSE 5
#define Q921_TEI_IDENTITY_REMOVE 6
#define Q921_TEI_IDENTITY_VERIFY 7
typedef struct q921_header { typedef struct q921_header {
#if __BYTE_ORDER == __BIG_ENDIAN #if __BYTE_ORDER == __BIG_ENDIAN
u_int8_t sapi:6; /* Service Access Point Indentifier (always 0 for PRI) (0) */ u_int8_t sapi:6; /* Service Access Point Indentifier (always 0 for PRI) (0) */
@ -154,6 +163,12 @@ typedef struct q921_frame {
#define Q921_INC(j) (j) = (((j) + 1) % 128) #define Q921_INC(j) (j) = (((j) + 1) % 128)
typedef enum q921_state { typedef enum q921_state {
Q921_DOWN = 0,
Q921_TEI_UNASSIGNED,
Q921_TEI_AWAITING_ESTABLISH,
Q921_TEI_AWAITING_ASSIGN,
Q921_TEI_ASSIGNED,
Q921_NEGOTIATION,
Q921_LINK_CONNECTION_RELEASED, /* Also known as TEI_ASSIGNED */ Q921_LINK_CONNECTION_RELEASED, /* Also known as TEI_ASSIGNED */
Q921_LINK_CONNECTION_ESTABLISHED, Q921_LINK_CONNECTION_ESTABLISHED,
Q921_AWAITING_ESTABLISH, Q921_AWAITING_ESTABLISH,

View File

@ -26,13 +26,14 @@
#define _PRI_TIMERS_H #define _PRI_TIMERS_H
/* -1 means we dont currently support the timer/counter */ /* -1 means we dont currently support the timer/counter */
#define PRI_TIMERS_DEFAULT { 3, /* N200 */ \ #define PRI_TIMERS_DEFAULT { \
3, /* N200 */ \
-1, /* N201 */ \ -1, /* N201 */ \
-1, /* N202 */ \ 3, /* N202 */ \
7, /* K */ \ 7, /* K */ \
1000, /* T200 */ \ 1000, /* T200 */ \
-1, /* T201 */ \ -1, /* T201 */ \
-1, /* T202 */ \ 10000, /* T202 */ \
10000, /* T203 */ \ 10000, /* T203 */ \
-1, /* T300 */ \ -1, /* T300 */ \
-1, /* T301 */ \ -1, /* T301 */ \
@ -53,7 +54,9 @@
-1, /* T319 */ \ -1, /* T319 */ \
-1, /* T320 */ \ -1, /* T320 */ \
-1, /* T321 */ \ -1, /* T321 */ \
-1 /* T322 */ \ -1, /* T322 */ \
2500, /* TM20 - Q.921 Appendix IV */ \
3, /* NM20 - Q.921 Appendix IV */ \
} }
/* XXX Only our default timers are setup now XXX */ /* XXX Only our default timers are setup now XXX */

View File

@ -35,6 +35,9 @@ int pri_schedule_event(struct pri *pri, int ms, void (*function)(void *data), vo
{ {
int x; int x;
struct timeval tv; struct timeval tv;
/* Scheduling runs on master channels only */
while (pri->master)
pri = pri->master;
for (x=1;x<MAX_SCHED;x++) for (x=1;x<MAX_SCHED;x++)
if (!pri->pri_sched[x].callback) if (!pri->pri_sched[x].callback)
break; break;
@ -113,6 +116,8 @@ pri_event *pri_schedule_run(struct pri *pri)
void pri_schedule_del(struct pri *pri,int id) void pri_schedule_del(struct pri *pri,int id)
{ {
while (pri->master)
pri = pri->master;
if ((id >= MAX_SCHED) || (id < 0)) if ((id >= MAX_SCHED) || (id < 0))
pri_error(pri, "Asked to delete sched id %d???\n", id); pri_error(pri, "Asked to delete sched id %d???\n", id);
pri->pri_sched[id].callback = NULL; pri->pri_sched[id].callback = NULL;

View File

@ -294,7 +294,7 @@ static int run_pri(int dfd, int swtype, int node)
fd_set rfds, efds; fd_set rfds, efds;
int res,x; int res,x;
pri = pri_new(dfd, node, swtype); pri = pri_new_bri(dfd, 1, node, swtype);
if (!pri) { if (!pri) {
fprintf(stderr, "Unable to create PRI\n"); fprintf(stderr, "Unable to create PRI\n");
return -1; return -1;

227
q921.c
View File

@ -51,6 +51,8 @@
} while(0) } while(0)
static void reschedule_t203(struct pri *pri); static void reschedule_t203(struct pri *pri);
static void q921_restart(struct pri *pri, int now);
static void q921_tei_release_and_reacquire(struct pri *master);
static void q921_discard_retransmissions(struct pri *pri) static void q921_discard_retransmissions(struct pri *pri)
{ {
@ -68,8 +70,10 @@ static void q921_discard_retransmissions(struct pri *pri)
static int q921_transmit(struct pri *pri, q921_h *h, int len) static int q921_transmit(struct pri *pri, q921_h *h, int len)
{ {
int res; int res;
if (pri->master) if (pri->master)
return q921_transmit(pri->master, h, len); pri = pri->master;
#ifdef RANDOM_DROPS #ifdef RANDOM_DROPS
if (!(random() % 3)) { if (!(random() % 3)) {
pri_message(pri, " === Dropping Packet ===\n"); pri_message(pri, " === Dropping Packet ===\n");
@ -92,6 +96,49 @@ static int q921_transmit(struct pri *pri, q921_h *h, int len)
return 0; return 0;
} }
static void q921_send_tei(struct pri *pri, int message, int ri, int ai, int iscommand)
{
q921_u *f;
if (!(f = calloc(1, sizeof(*f) + 5)))
return;
Q921_INIT(pri, *f);
f->h.c_r = (pri->localtype == PRI_NETWORK) ? iscommand : !iscommand;
f->ft = Q921_FRAMETYPE_U;
f->data[0] = 0x0f; /* Management entity */
f->data[1] = (ri >> 8) & 0xff;
f->data[2] = ri & 0xff;
f->data[3] = message;
f->data[4] = (ai << 1) | 1;
if (pri->debug & PRI_DEBUG_Q921_STATE)
pri_message(pri, "Sending TEI management message %d, TEI=%d\n", message, ai);
q921_transmit(pri, (q921_h *)f, 8);
free(f);
}
static void q921_tei_request(void *vpri)
{
struct pri *pri = (struct pri *)vpri;
if (pri->subchannel) {
pri_error(pri, "Cannot request TEI while its already assigned\n");
return;
}
pri->n202_counter++;
#if 0
if (pri->n202_counter > pri->timers[PRI_TIMER_N202]) {
pri_error(pri, "Unable to assign TEI from network\n");
return;
}
#endif
pri->ri = random() % 65535;
q921_send_tei(pri, Q921_TEI_IDENTITY_REQUEST, pri->ri, Q921_TEI_GROUP, 1);
if (pri->t202_timer)
pri_schedule_del(pri, pri->t202_timer);
pri->t202_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T202], q921_tei_request, pri);
}
static void q921_send_ua(struct pri *pri, int pfbit) static void q921_send_ua(struct pri *pri, int pfbit)
{ {
q921_h h; q921_h h;
@ -143,6 +190,15 @@ static void q921_send_sabme(void *vpri, int now)
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 U/A on a type %d node\n", pri->localtype);
return; return;
} }
if (pri->bri && (pri->state == Q921_AWAITING_ESTABLISH)) {
if (pri->sabme_count >= pri->timers[PRI_TIMER_N200]) {
pri_schedule_del(pri, pri->sabme_timer);
pri->sabme_timer = 0;
q921_tei_release_and_reacquire(pri->master);
} else {
pri->sabme_count++;
}
}
if (pri->debug & (PRI_DEBUG_Q921_STATE | PRI_DEBUG_Q921_DUMP)) if (pri->debug & (PRI_DEBUG_Q921_STATE | PRI_DEBUG_Q921_DUMP))
pri_message(pri, "Sending Set Asynchronous Balanced Mode Extended\n"); pri_message(pri, "Sending Set Asynchronous Balanced Mode Extended\n");
q921_transmit(pri, &h, 3); q921_transmit(pri, &h, 3);
@ -376,10 +432,15 @@ static void t200_expire(void *vpri)
pri_message(pri, DBGHEAD "q921_state now is Q921_LINK_CONNECTION_RELEASED\n", DBGINFO); pri_message(pri, DBGHEAD "q921_state now is Q921_LINK_CONNECTION_RELEASED\n", DBGINFO);
pri->q921_state = Q921_LINK_CONNECTION_RELEASED; pri->q921_state = Q921_LINK_CONNECTION_RELEASED;
pri->t200_timer = 0; pri->t200_timer = 0;
if (pri->bri && pri->master) {
q921_tei_release_and_reacquire(pri->master);
return;
} else {
q921_dchannel_down(pri); q921_dchannel_down(pri);
q921_start(pri, 1); q921_start(pri, 1);
pri->schedev = 1; pri->schedev = 1;
} }
}
} else { } else {
pri_error(pri, "T200 counter expired, nothing to send...\n"); pri_error(pri, "T200 counter expired, nothing to send...\n");
pri->t200_timer = 0; pri->t200_timer = 0;
@ -389,10 +450,10 @@ static void t200_expire(void *vpri)
int q921_transmit_iframe(struct pri *pri, void *buf, int len, int cr) int q921_transmit_iframe(struct pri *pri, void *buf, int len, int cr)
{ {
q921_frame *f, *prev=NULL; q921_frame *f, *prev=NULL;
for (f=pri->txqueue; f; f = f->next) prev = f; for (f=pri->txqueue; f; f = f->next) prev = f;
f = malloc(sizeof(q921_frame) + len + 2); f = calloc(1, sizeof(q921_frame) + len + 2);
if (f) { if (f) {
memset(f,0,sizeof(q921_frame) + len + 2);
Q921_INIT(pri, f->h); Q921_INIT(pri, f->h);
switch(pri->localtype) { switch(pri->localtype) {
case PRI_NETWORK: case PRI_NETWORK:
@ -654,8 +715,10 @@ static pri_event *q921_dchannel_up(struct pri *pri)
q921_reset(pri); q921_reset(pri);
/* Stop any SABME retransmissions */ /* Stop any SABME retransmissions */
if (pri->sabme_timer) {
pri_schedule_del(pri, pri->sabme_timer); pri_schedule_del(pri, pri->sabme_timer);
pri->sabme_timer = 0; pri->sabme_timer = 0;
}
/* Reset any rejects */ /* Reset any rejects */
pri->sentrej = 0; pri->sentrej = 0;
@ -698,10 +761,14 @@ void q921_reset(struct pri *pri)
pri->v_na = 0; pri->v_na = 0;
pri->window = pri->timers[PRI_TIMER_K]; pri->window = pri->timers[PRI_TIMER_K];
pri->windowlen = 0; pri->windowlen = 0;
if (pri->sabme_timer)
pri_schedule_del(pri, pri->sabme_timer); pri_schedule_del(pri, pri->sabme_timer);
if (pri->t203_timer)
pri_schedule_del(pri, pri->t203_timer); pri_schedule_del(pri, pri->t203_timer);
if (pri->t200_timer)
pri_schedule_del(pri, pri->t200_timer); pri_schedule_del(pri, pri->t200_timer);
pri->sabme_timer = 0; pri->sabme_timer = 0;
pri->sabme_count = 0;
pri->t203_timer = 0; pri->t203_timer = 0;
pri->t200_timer = 0; pri->t200_timer = 0;
pri->busy = 0; pri->busy = 0;
@ -716,6 +783,101 @@ void q921_reset(struct pri *pri)
q921_discard_retransmissions(pri); q921_discard_retransmissions(pri);
} }
static void q921_tei_release_and_reacquire(struct pri *master)
{
/* Make sure the master is passed into this function */
q921_dchannel_down(master->subchannel);
__pri_free_tei(master->subchannel);
master->subchannel = NULL;
master->ev.gen.e = PRI_EVENT_DCHAN_DOWN;
master->schedev = 1;
q921_start(master, master->localtype == PRI_CPE);
}
static pri_event *q921_receive_MDL(struct pri *pri, q921_u *h, int len)
{
int ri;
struct pri *sub;
int tei;
if (pri->debug & PRI_DEBUG_Q921_STATE)
pri_message(pri, "Received MDL message\n");
if (h->data[0] != 0x0f) {
pri_error(pri, "Received MDL with unsupported management entity %02x\n", h->data[0]);
return NULL;
}
if (!(h->data[4] & 0x01)) {
pri_error(pri, "Received MDL with multibyte TEI identifier\n");
return NULL;
}
ri = (h->data[1] << 8) | h->data[2];
tei = (h->data[4] >> 1);
switch(h->data[3]) {
case Q921_TEI_IDENTITY_REQUEST:
if (tei != 127) {
pri_error(pri, "Received TEI identity request with invalid TEI %d\n", tei);
q921_send_tei(pri, Q921_TEI_IDENTITY_DENIED, ri, tei, 1);
}
/* Go to master */
for (sub = pri; sub->master; sub = sub->master);
tei = 64;
while(sub->subchannel) {
if(sub->subchannel->tei == tei)
++tei;
}
sub->subchannel = __pri_new_tei(-1, pri->localtype, pri->switchtype, pri, NULL, NULL, NULL, tei, 1);
if (!sub->subchannel) {
pri_error(pri, "Unable to allocate D-channel for new TEI %d\n", tei);
return NULL;
}
q921_send_tei(pri, Q921_TEI_IDENTITY_ASSIGNED, ri, tei, 1);
break;
case Q921_TEI_IDENTITY_ASSIGNED:
if (ri != pri->ri) {
pri_message(pri, "TEI assignment received for invalid Ri %02x (our is %02x)\n", ri, pri->ri);
return NULL;
}
if (pri->t202_timer) {
pri_schedule_del(pri, pri->t202_timer);
pri->t202_timer = 0;
}
if (pri->subchannel && (pri->subchannel->tei == tei)) {
pri_error(pri, "TEI already assigned (new is %d, current is %d)\n", tei, pri->subchannel->tei);
q921_tei_release_and_reacquire(pri);
return NULL;
}
pri_message(pri, "TEI assiged to %d\n", tei);
pri->subchannel = __pri_new_tei(-1, pri->localtype, pri->switchtype, pri, NULL, NULL, NULL, tei, 1);
if (!pri->subchannel) {
pri_error(pri, "Unable to allocate D-channel for new TEI %d\n", tei);
return NULL;
}
pri->q921_state = Q921_TEI_ASSIGNED;
break;
case Q921_TEI_IDENTITY_CHECK_REQUEST:
/* We're assuming one TEI per PRI in TE PTMP mode */
/* If no subchannel (TEI) ignore */
if (!pri->subchannel)
return NULL;
/* If it's addressed to the group TEI or to our TEI specifically, we respond */
if ((tei == Q921_TEI_GROUP) || (tei == pri->subchannel->tei))
q921_send_tei(pri, Q921_TEI_IDENTITY_CHECK_RESPONSE, random() % 65535, pri->subchannel->tei, 1);
break;
case Q921_TEI_IDENTITY_REMOVE:
/* XXX: Assuming multiframe mode has been disconnected already */
if (!pri->subchannel)
return NULL;
if ((tei == Q921_TEI_GROUP) || (tei == pri->subchannel->tei)) {
q921_tei_release_and_reacquire(pri);
}
}
return NULL; /* Do we need to return something??? */
}
static pri_event *__q921_receive_qualified(struct pri *pri, q921_h *h, int len) static pri_event *__q921_receive_qualified(struct pri *pri, q921_h *h, int len)
{ {
q921_frame *f; q921_frame *f;
@ -768,7 +930,7 @@ static pri_event *__q921_receive_qualified(struct pri *pri, q921_h *h, int len)
break; break;
case 1: case 1:
/* Receiver not ready */ /* Receiver not ready */
if (pri->debug & PRI_DEBUG_Q921_DUMP) if (pri->debug & PRI_DEBUG_Q921_STATE)
pri_message(pri, "-- Got receiver not ready\n"); pri_message(pri, "-- Got receiver not ready\n");
if(h->s.p_f) { if(h->s.p_f) {
/* Send RR if poll bit set */ /* Send RR if poll bit set */
@ -778,7 +940,7 @@ static pri_event *__q921_receive_qualified(struct pri *pri, q921_h *h, int len)
break; break;
case 2: case 2:
/* Just retransmit */ /* Just retransmit */
if (pri->debug & PRI_DEBUG_Q921_DUMP) if (pri->debug & PRI_DEBUG_Q921_STATE)
pri_message(pri, "-- Got reject requesting packet %d... Retransmitting.\n", h->s.n_r); pri_message(pri, "-- Got reject requesting packet %d... Retransmitting.\n", h->s.n_r);
if (h->s.p_f) { if (h->s.p_f) {
/* If it has the poll bit set, send an appropriate supervisory response */ /* If it has the poll bit set, send an appropriate supervisory response */
@ -839,7 +1001,7 @@ static pri_event *__q921_receive_qualified(struct pri *pri, q921_h *h, int len)
pri_message(pri, "-- Got DM Mode from peer.\n"); pri_message(pri, "-- Got DM Mode from peer.\n");
/* Disconnected mode, try again after T200 */ /* Disconnected mode, try again after T200 */
ev = q921_dchannel_down(pri); ev = q921_dchannel_down(pri);
q921_start(pri, 0); q921_restart(pri, 0);
return ev; return ev;
} else { } else {
@ -847,12 +1009,23 @@ static pri_event *__q921_receive_qualified(struct pri *pri, q921_h *h, int len)
pri_message(pri, "-- Ignoring unsolicited DM with p/f set to 0\n"); pri_message(pri, "-- Ignoring unsolicited DM with p/f set to 0\n");
#if 0 #if 0
/* Requesting that we start */ /* Requesting that we start */
q921_start(pri, 0); q921_restart(pri, 0);
#endif #endif
} }
break; break;
} else if (!h->u.m2) { } else if (!h->u.m2) {
pri_message(pri, "XXX Unnumbered Information not implemented XXX\n"); if ((pri->sapi == Q921_SAPI_LAYER2_MANAGEMENT) && (pri->tei == Q921_TEI_GROUP))
q921_receive_MDL(pri, (q921_u *)h, len);
else {
int res;
res = q931_receive(pri, (q931_h *) h->u.data, len - 3);
if (res == -1) {
return NULL;
}
if (res & Q931_RES_HAVEEVENT)
return &pri->ev;
}
} }
break; break;
case 2: case 2:
@ -861,7 +1034,7 @@ static pri_event *__q921_receive_qualified(struct pri *pri, q921_h *h, int len)
/* Acknowledge */ /* Acknowledge */
q921_send_ua(pri, h->u.p_f); q921_send_ua(pri, h->u.p_f);
ev = q921_dchannel_down(pri); ev = q921_dchannel_down(pri);
q921_start(pri, 0); q921_restart(pri, 0);
return ev; return ev;
case 3: case 3:
if (h->u.m2 == 3) { if (h->u.m2 == 3) {
@ -892,8 +1065,17 @@ static pri_event *__q921_receive_qualified(struct pri *pri, q921_h *h, int len)
pri_message(pri, "-- Got UA from %s peer Link up.\n", h->h.c_r ? "cpe" : "network"); pri_message(pri, "-- Got UA from %s peer Link up.\n", h->h.c_r ? "cpe" : "network");
} }
return q921_dchannel_up(pri); return q921_dchannel_up(pri);
} else } else if ((pri->q921_state >= Q921_TEI_ASSIGNED) && pri->bri) {
/* Possible duplicate TEI assignment */
if (pri->master)
q921_tei_release_and_reacquire(pri->master);
else
pri_error(pri, "Huh!? no master found\n");
} else {
/* Since we're not in the AWAITING_ESTABLISH STATE, it's unsolicited */
pri_error(pri, "!! Got a UA, but i'm in state %d\n", pri->q921_state); pri_error(pri, "!! Got a UA, but i'm in state %d\n", pri->q921_state);
}
} else } else
pri_error(pri, "!! Weird frame received (m3=3, m2 = %d)\n", h->u.m2); pri_error(pri, "!! Weird frame received (m3=3, m2 = %d)\n", h->u.m2);
break; break;
@ -925,21 +1107,24 @@ static pri_event *__q921_receive(struct pri *pri, q921_h *h, int len)
if (h->h.ea1 || !(h->h.ea2)) if (h->h.ea1 || !(h->h.ea2))
return NULL; return NULL;
#if 0 /* Will be rejected by subchannel analyzis */
/* Check for broadcasts - not yet handled */ /* Check for broadcasts - not yet handled */
if (h->h.tei == Q921_TEI_GROUP) if (h->h.tei == Q921_TEI_GROUP)
return NULL; return NULL;
#endif
if (!((h->h.sapi == pri->sapi) && ((h->h.tei == pri->tei) || (h->h.tei == Q921_TEI_GROUP)))) {
/* Check for SAPIs we don't yet handle */ /* Check for SAPIs we don't yet handle */
if ((h->h.sapi != pri->sapi) || (h->h.tei != pri->tei)) {
#ifdef PROCESS_SUBCHANNELS
/* If it's not us, try any subchannels we have */ /* If it's not us, try any subchannels we have */
if (pri->subchannel) if (pri->subchannel)
return q921_receive(pri->subchannel, h, len + 2); return q921_receive(pri->subchannel, h, len + 2);
else else {
#endif
return NULL; return NULL;
}
} }
if (pri->debug & PRI_DEBUG_Q921_DUMP)
pri_message(pri, "Handling message for SAPI/TEI=%d/%d\n", h->h.sapi, h->h.tei);
ev = __q921_receive_qualified(pri, h, len); ev = __q921_receive_qualified(pri, h, len);
reschedule_t203(pri); reschedule_t203(pri);
return ev; return ev;
@ -955,7 +1140,7 @@ pri_event *q921_receive(struct pri *pri, q921_h *h, int len)
return e; return e;
} }
void q921_start(struct pri *pri, int now) static void q921_restart(struct pri *pri, int now)
{ {
if (pri->q921_state != Q921_LINK_CONNECTION_RELEASED) { if (pri->q921_state != Q921_LINK_CONNECTION_RELEASED) {
pri_error(pri, "!! q921_start: Not in 'Link Connection Released' state\n"); pri_error(pri, "!! q921_start: Not in 'Link Connection Released' state\n");
@ -966,3 +1151,15 @@ void q921_start(struct pri *pri, int now)
/* Do the SABME XXX Maybe we should implement T_WAIT? XXX */ /* Do the SABME XXX Maybe we should implement T_WAIT? XXX */
q921_send_sabme(pri, now); q921_send_sabme(pri, now);
} }
void q921_start(struct pri *pri, int isCPE)
{
q921_reset(pri);
if ((pri->sapi == Q921_SAPI_LAYER2_MANAGEMENT) && (pri->tei == Q921_TEI_GROUP)) {
pri->q921_state = Q921_DOWN;
if (isCPE)
q921_tei_request(pri);
} else {
q921_send_sabme(pri, isCPE);
}
}

121
q931.c
View File

@ -255,18 +255,10 @@ static char *code2str(int code, struct msgtype *codes, int max)
static void call_init(struct q931_call *c) static void call_init(struct q931_call *c)
{ {
memset(c, 0, sizeof(*c));
c->alive = 0;
c->sendhangupack = 0;
c->forceinvert = -1; c->forceinvert = -1;
c->cr = -1; c->cr = -1;
c->slotmap = -1; c->slotmap = -1;
c->channelno = -1; c->channelno = -1;
c->ds1no = 0;
c->ds1explicit = 0;
c->chanflags = 0;
c->next = NULL;
c->sentchannel = 0;
c->newcall = 1; c->newcall = 1;
c->ourcallstate = Q931_CALL_STATE_NULL; c->ourcallstate = Q931_CALL_STATE_NULL;
c->peercallstate = Q931_CALL_STATE_NULL; c->peercallstate = Q931_CALL_STATE_NULL;
@ -294,6 +286,12 @@ static FUNC_RECV(receive_channel_id)
} }
#endif #endif
#ifndef NOAUTO_CHANNEL_SELECTION_SUPPORT #ifndef NOAUTO_CHANNEL_SELECTION_SUPPORT
if (pri->bri) {
if (!(ie->data[0] & 3))
call->justsignalling = 1;
else
call->channelno = ie->data[0] & 3;
} else {
switch (ie->data[0] & 3) { switch (ie->data[0] & 3) {
case 0: case 0:
call->justsignalling = 1; call->justsignalling = 1;
@ -304,6 +302,7 @@ static FUNC_RECV(receive_channel_id)
pri_error(pri, "!! Unexpected Channel selection %d\n", ie->data[0] & 3); pri_error(pri, "!! Unexpected Channel selection %d\n", ie->data[0] & 3);
return -1; return -1;
} }
}
#endif #endif
if (ie->data[0] & 0x08) if (ie->data[0] & 0x08)
call->chanflags = FLAG_EXCLUSIVE; call->chanflags = FLAG_EXCLUSIVE;
@ -366,7 +365,11 @@ static FUNC_SEND(transmit_channel_id)
/* Start with standard stuff */ /* Start with standard stuff */
if (pri->switchtype == PRI_SWITCH_GR303_TMC) if (pri->switchtype == PRI_SWITCH_GR303_TMC)
ie->data[pos] = 0x69; ie->data[pos] = 0x69;
else else if (pri->bri) {
ie->data[pos] = 0x80;
if (call->channelno > -1)
ie->data[pos] |= (call->channelno & 0x3);
} else
ie->data[pos] = 0xa1; ie->data[pos] = 0xa1;
/* Add exclusive flag if necessary */ /* Add exclusive flag if necessary */
if (call->chanflags & FLAG_EXCLUSIVE) if (call->chanflags & FLAG_EXCLUSIVE)
@ -383,6 +386,10 @@ static FUNC_SEND(transmit_channel_id)
ie->data[pos++] = 0x80 | call->ds1no; ie->data[pos++] = 0x80 | call->ds1no;
} else } else
pos++; pos++;
if (pri->bri)
return pos + 2;
if ((call->channelno > -1) || (call->slotmap != -1)) { if ((call->channelno > -1) || (call->slotmap != -1)) {
/* We'll have the octet 8.2 and 8.3's present */ /* We'll have the octet 8.2 and 8.3's present */
ie->data[pos++] = 0x83; ie->data[pos++] = 0x83;
@ -781,7 +788,7 @@ static FUNC_SEND(transmit_bearer_capability)
return 0; return 0;
tc = call->transcapability; tc = call->transcapability;
if (pri->subchannel) { if (pri->subchannel && !pri->bri) {
/* Bearer capability is *hard coded* in GR-303 */ /* Bearer capability is *hard coded* in GR-303 */
ie->data[0] = 0x88; ie->data[0] = 0x88;
ie->data[1] = 0x90; ie->data[1] = 0x90;
@ -1326,7 +1333,7 @@ static FUNC_RECV(receive_facility)
state = my_state; \ state = my_state; \
if (pri->debug) \ if (pri->debug) \
pri_message(pri, "Handle Q.932 %s component\n", name); \ pri_message(pri, "Handle Q.932 %s component\n", name); \
(handler)(pri, call, comp->data, comp->len); \ (handler)(pri, call, ie, comp->data, comp->len); \
break; break;
#define Q932_HANDLE_NULL(component, my_state, name, handle) \ #define Q932_HANDLE_NULL(component, my_state, name, handle) \
case component: \ case component: \
@ -1421,7 +1428,7 @@ static FUNC_SEND(transmit_progress_indicator)
{ {
int code, mask; int code, mask;
/* Can't send progress indicator on GR-303 -- EVER! */ /* Can't send progress indicator on GR-303 -- EVER! */
if (pri->subchannel) if (pri->subchannel && !pri->bri)
return 0; return 0;
if (call->progressmask > 0) { if (call->progressmask > 0) {
if (call->progressmask & (mask = PRI_PROG_CALL_NOT_E2E_ISDN)) if (call->progressmask & (mask = PRI_PROG_CALL_NOT_E2E_ISDN))
@ -2313,10 +2320,18 @@ static inline void q931_dumpie(struct pri *pri, int codeset, q931_ie *ie, char p
pri_error(pri, "!! %c Unknown IE %d (cs%d, len = %d)\n", prefix, Q931_IE_IE(base_ie), Q931_IE_CODESET(base_ie), ielen(ie)); pri_error(pri, "!! %c Unknown IE %d (cs%d, len = %d)\n", prefix, Q931_IE_IE(base_ie), Q931_IE_CODESET(base_ie), ielen(ie));
} }
static q931_call *q931_getcall(struct pri *pri, int cr) static q931_call *q931_getcall(struct pri *pri, int cr, int outboundnew)
{ {
q931_call *cur, *prev; q931_call *cur, *prev;
cur = *pri->callpool; struct pri *master;
/* Find the master - He has the call pool */
if (pri->master)
master = pri->master;
else
master = pri;
cur = *master->callpool;
prev = NULL; prev = NULL;
while(cur) { while(cur) {
if (cur->cr == cr) if (cur->cr == cr)
@ -2327,41 +2342,59 @@ static q931_call *q931_getcall(struct pri *pri, int cr)
/* No call exists, make a new one */ /* No call exists, make a new one */
if (pri->debug & PRI_DEBUG_Q931_STATE) if (pri->debug & PRI_DEBUG_Q931_STATE)
pri_message(pri, "-- Making new call for cr %d\n", cr); pri_message(pri, "-- Making new call for cr %d\n", cr);
cur = malloc(sizeof(struct q931_call));
if (cur) { if (!(cur = calloc(1, sizeof(*cur))))
return NULL;
call_init(cur); call_init(cur);
/* Call reference */ /* Call reference */
cur->cr = cr; cur->cr = cr;
/* PRI is set to whoever called us */
if (pri->bri && (pri->localtype == PRI_CPE) && pri->subchannel && outboundnew)
cur->pri = pri->subchannel;
else
cur->pri = pri; cur->pri = pri;
/* Append to end of list */ /* Append to end of list */
if (prev) if (prev)
prev->next = cur; prev->next = cur;
else else
*pri->callpool = cur; *master->callpool = cur;
}
return cur; return cur;
} }
q931_call *q931_new_call(struct pri *pri) q931_call *q931_new_call(struct pri *pri)
{ {
q931_call *cur; q931_call *cur;
do { do {
cur = *pri->callpool; cur = *pri->callpool;
pri->cref++; pri->cref++;
if (!pri->bri) {
if (pri->cref > 32767) if (pri->cref > 32767)
pri->cref = 1; pri->cref = 1;
} else {
if (pri->cref > 127)
pri->cref = 1;
}
while(cur) { while(cur) {
if (cur->cr == (0x8000 | pri->cref)) if (cur->cr == (0x8000 | pri->cref))
break; break;
cur = cur->next; cur = cur->next;
} }
} while(cur); } while(cur);
return q931_getcall(pri, pri->cref | 0x8000);
return q931_getcall(pri, pri->cref | 0x8000, 1);
} }
static void q931_destroy(struct pri *pri, int cr, q931_call *c) static void q931_destroy(struct pri *pri, int cr, q931_call *c)
{ {
q931_call *cur, *prev; q931_call *cur, *prev;
/* For destroying, make sure we are using the master span, since it maintains the call pool */
for (;pri->master; pri = pri->master);
prev = NULL; prev = NULL;
cur = *pri->callpool; cur = *pri->callpool;
while(cur) { while(cur) {
@ -2526,9 +2559,10 @@ static void init_header(struct pri *pri, q931_call *call, unsigned char *buf, q9
{ {
/* Returns header and message header and modifies length in place */ /* Returns header and message header and modifies length in place */
q931_h *h = (q931_h *)buf; q931_h *h = (q931_h *)buf;
q931_mh * mh = (q931_mh *)(h->contents + 2); q931_mh * mh;
h->pd = pri->protodisc; h->pd = pri->protodisc;
h->x0 = 0; /* Reserved 0 */ h->x0 = 0; /* Reserved 0 */
if (!pri->bri) {
h->crlen = 2; /* Two bytes of Call Reference. Invert the top bit to make it from our sense */ h->crlen = 2; /* Two bytes of Call Reference. Invert the top bit to make it from our sense */
if (call->cr || call->forceinvert) { if (call->cr || call->forceinvert) {
h->crv[0] = ((call->cr ^ 0x8000) & 0xff00) >> 8; h->crv[0] = ((call->cr ^ 0x8000) & 0xff00) >> 8;
@ -2538,14 +2572,27 @@ static void init_header(struct pri *pri, q931_call *call, unsigned char *buf, q9
h->crv[0] = 0; h->crv[0] = 0;
h->crv[1] = 0; h->crv[1] = 0;
} }
if (pri->subchannel) { if (pri->subchannel && !pri->bri) {
/* On GR-303, top bit is always 0 */ /* On GR-303, top bit is always 0 */
h->crv[0] &= 0x7f; h->crv[0] &= 0x7f;
} }
} else {
h->crlen = 1;
if (call->cr || call->forceinvert) {
h->crv[0] = (((call->cr ^ 0x8000) & 0x8000) >> 8) | (call->cr & 0x7f);
} else {
/* Unless of course this has no call reference */
h->crv[0] = 0;
}
}
mh = (q931_mh *)(h->contents + h->crlen);
mh->f = 0; mh->f = 0;
*hb = h; *hb = h;
*mhb = mh; *mhb = mh;
if (h->crlen == 2)
*len -= 5; *len -= 5;
else
*len -= 4;
} }
@ -2594,7 +2641,7 @@ static int send_message(struct pri *pri, q931_call *c, int msgtype, int ies[])
} }
/* Invert the logic */ /* Invert the logic */
len = sizeof(buf) - len; len = sizeof(buf) - len;
q931_xmit(pri, h, len, 1); q931_xmit(c->pri, h, len, 1);
c->acked = 1; c->acked = 1;
return 0; return 0;
} }
@ -2777,6 +2824,7 @@ int q931_setup_ack(struct pri *pri, q931_call *c, int channel, int nonisdn)
return send_message(pri, c, Q931_SETUP_ACKNOWLEDGE, connect_ies); return send_message(pri, c, Q931_SETUP_ACKNOWLEDGE, connect_ies);
} }
/* T313 expiry, first time */
static void pri_connect_timeout(void *data) static void pri_connect_timeout(void *data)
{ {
struct q931_call *c = data; struct q931_call *c = data;
@ -2787,6 +2835,7 @@ static void pri_connect_timeout(void *data)
} }
/* T308 expiry, first time */
static void pri_release_timeout(void *data) static void pri_release_timeout(void *data)
{ {
struct q931_call *c = data; struct q931_call *c = data;
@ -2795,9 +2844,12 @@ static void pri_release_timeout(void *data)
pri_message(pri, "Timed out looking for release complete\n"); pri_message(pri, "Timed out looking for release complete\n");
c->t308_timedout++; c->t308_timedout++;
c->alive = 1; c->alive = 1;
q931_release(pri, c, PRI_CAUSE_NORMAL_CLEARING);
/* The call to q931_release will re-schedule T308 */
q931_release(pri, c, c->cause);
} }
/* T308 expiry, second time */
static void pri_release_finaltimeout(void *data) static void pri_release_finaltimeout(void *data)
{ {
struct q931_call *c = data; struct q931_call *c = data;
@ -2819,6 +2871,7 @@ static void pri_release_finaltimeout(void *data)
q931_hangup(pri, c, c->cause); q931_hangup(pri, c, c->cause);
} }
/* T305 expiry, first time */
static void pri_disconnect_timeout(void *data) static void pri_disconnect_timeout(void *data)
{ {
struct q931_call *c = data; struct q931_call *c = data;
@ -2855,7 +2908,7 @@ int q931_connect(struct pri *pri, q931_call *c, int channel, int nonisdn)
if (c->retranstimer) if (c->retranstimer)
pri_schedule_del(pri, c->retranstimer); pri_schedule_del(pri, c->retranstimer);
c->retranstimer = 0; c->retranstimer = 0;
if ((c->ourcallstate == Q931_CALL_STATE_CONNECT_REQUEST) && (!pri->subchannel)) if ((c->ourcallstate == Q931_CALL_STATE_CONNECT_REQUEST) && (pri->bri || (!pri->subchannel)))
c->retranstimer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T313], pri_connect_timeout, c); c->retranstimer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T313], pri_connect_timeout, c);
return send_message(pri, c, Q931_CONNECT, connect_ies); return send_message(pri, c, Q931_CONNECT, connect_ies);
} }
@ -2891,7 +2944,7 @@ static int restart_ies[] = { Q931_CHANNEL_IDENT, Q931_RESTART_INDICATOR, -1 };
int q931_restart(struct pri *pri, int channel) int q931_restart(struct pri *pri, int channel)
{ {
struct q931_call *c; struct q931_call *c;
c = q931_getcall(pri, 0 | 0x8000); c = q931_getcall(pri, 0 | 0x8000, 0);
if (!c) if (!c)
return -1; return -1;
if (!channel) if (!channel)
@ -2951,7 +3004,7 @@ int q931_setup(struct pri *pri, q931_call *c, struct pri_sr *req)
c->ds1no = (req->channel & 0xff00) >> 8; c->ds1no = (req->channel & 0xff00) >> 8;
c->ds1explicit = (req->channel & 0x10000) >> 16; c->ds1explicit = (req->channel & 0x10000) >> 16;
req->channel &= 0xff; req->channel &= 0xff;
if ((pri->localtype == PRI_CPE) && pri->subchannel) { if ((pri->localtype == PRI_CPE) && pri->subchannel && !pri->bri) {
req->channel = 0; req->channel = 0;
req->exclusive = 0; req->exclusive = 0;
} }
@ -3021,7 +3074,7 @@ int q931_setup(struct pri *pri, q931_call *c, struct pri_sr *req)
pri_call_add_standard_apdus(pri, c); pri_call_add_standard_apdus(pri, c);
if (pri->subchannel) if (pri->subchannel && !pri->bri)
res = send_message(pri, c, Q931_SETUP, gr303_setup_ies); res = send_message(pri, c, Q931_SETUP, gr303_setup_ies);
else if (c->justsignalling) else if (c->justsignalling)
res = send_message(pri, c, Q931_SETUP, cis_setup_ies); res = send_message(pri, c, Q931_SETUP, cis_setup_ies);
@ -3065,7 +3118,7 @@ static int gr303_connect_acknowledge_ies[] = { Q931_CHANNEL_IDENT, -1 };
static int q931_connect_acknowledge(struct pri *pri, q931_call *c) static int q931_connect_acknowledge(struct pri *pri, q931_call *c)
{ {
if (pri->subchannel) { if (pri->subchannel && !pri->bri) {
if (pri->localtype == PRI_CPE) if (pri->localtype == PRI_CPE)
return send_message(pri, c, Q931_CONNECT_ACKNOWLEDGE, gr303_connect_acknowledge_ies); return send_message(pri, c, Q931_CONNECT_ACKNOWLEDGE, gr303_connect_acknowledge_ies);
} else } else
@ -3199,7 +3252,7 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
pri_error(pri, "Warning: unknown/inappropriate protocol discriminator received (%02x/%d)\n", h->pd, h->pd); pri_error(pri, "Warning: unknown/inappropriate protocol discriminator received (%02x/%d)\n", h->pd, h->pd);
return 0; return 0;
} }
c = q931_getcall(pri, q931_cr(h)); c = q931_getcall(pri, q931_cr(h), 0);
if (!c) { if (!c) {
pri_error(pri, "Unable to locate call %d\n", q931_cr(h)); pri_error(pri, "Unable to locate call %d\n", q931_cr(h));
return -1; return -1;
@ -3548,6 +3601,8 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
libpri_copy_string(pri->ev.facname.callingname, c->callername, sizeof(pri->ev.facname.callingname)); 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)); 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.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
pri->ev.facname.callingpres = c->callerpres;
pri->ev.facname.callingplan = c->callerplan;
pri->ev.facname.cref = c->cr; pri->ev.facname.cref = c->cr;
pri->ev.facname.call = c; pri->ev.facname.call = c;
#if 0 #if 0
@ -3626,7 +3681,15 @@ int q931_receive(struct pri *pri, q931_h *h, int len)
(c->cause != PRI_CAUSE_INTERWORKING)) (c->cause != PRI_CAUSE_INTERWORKING))
pri_error(pri, "Received unsolicited status: %s\n", pri_cause2str(c->cause)); pri_error(pri, "Received unsolicited status: %s\n", pri_cause2str(c->cause));
/* Workaround for S-12 ver 7.3 - it responds for invalid/non-implemented IEs at SETUP with null call state */ /* Workaround for S-12 ver 7.3 - it responds for invalid/non-implemented IEs at SETUP with null call state */
#if 0
if (!c->sugcallstate && (c->ourcallstate != Q931_CALL_STATE_CALL_INITIATED)) { if (!c->sugcallstate && (c->ourcallstate != Q931_CALL_STATE_CALL_INITIATED)) {
#else
/* Remove "workaround" since it breaks certification testing. If we receive a STATUS message of call state
* NULL and we are not in the call state NULL we must clear resources and return to the call state to pass
* testing. See section 5.8.11 of Q.931 */
if (!c->sugcallstate) {
#endif
pri->ev.hangup.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); pri->ev.hangup.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
pri->ev.hangup.cause = c->cause; pri->ev.hangup.cause = c->cause;
pri->ev.hangup.cref = c->cr; pri->ev.hangup.cref = c->cr;

View File

@ -64,7 +64,7 @@ static struct pri *first, *cur;
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
#define TEST_CALLS 32 #define TEST_CALLS 1
static void event1(struct pri *pri, pri_event *e) static void event1(struct pri *pri, pri_event *e)
{ {
@ -232,9 +232,9 @@ static void *dchan(void *data)
} }
if (e) { if (e) {
if (first == pri) { if (first == pri) {
event1(pri, e); event1(e->gen.pri, e);
} else { } else {
event2(pri, e); event2(e->gen.pri, e);
} }
} }
pthread_mutex_unlock(&lock); pthread_mutex_unlock(&lock);
@ -254,7 +254,7 @@ int main(int argc, char *argv[])
perror("socketpair"); perror("socketpair");
exit(1); exit(1);
} }
if (!(pri = pri_new(pair[0], PRI_NETWORK, PRI_DEF_SWITCHTYPE))) { if (!(pri = pri_new_bri(pair[0], 0, PRI_NETWORK, PRI_DEF_SWITCHTYPE))) {
perror("pri(0)"); perror("pri(0)");
exit(1); exit(1);
} }
@ -265,7 +265,7 @@ int main(int argc, char *argv[])
perror("thread(0)"); perror("thread(0)");
exit(1); exit(1);
} }
if (!(pri = pri_new(pair[1], PRI_CPE, PRI_DEF_SWITCHTYPE))) { if (!(pri = pri_new_bri(pair[1], 0, PRI_CPE, PRI_DEF_SWITCHTYPE))) {
perror("pri(1)"); perror("pri(1)");
exit(1); exit(1);
} }