Compare commits

...

No commits in common. "master" and "cvsimport" have entirely different histories.

217 changed files with 26390 additions and 49140 deletions

50
.gitignore vendored
View File

@ -1,50 +0,0 @@
#
# NOTE! Don't add files that are generated in specific
# subdirectories here. Add them in the ".gitignore" file
# in that subdirectory instead.
#
# NOTE! Please use 'git ls-files -i --exclude-standard'
# command after changing this file, to see if there are
# any tracked files which get ignored after the change.
#
# Normal rules
#
.deps
.libs
*.la
*.lo
*.o
*.o.*
*.a
*.s
*.so
*.so.dbg
*.i
*.lst
*~
test_file.in
test_file.out
45-misdn.rules
autom4te.cache
ChangeLog
config.log
config.status
Makefile
Makefile.in
configure
ltmain.sh
m4
aclocal.m4
depcomp
missing
install-sh
config.guess
config.sub
DEADJOE
.dirstamp
libtool
ar-lib
capi20/m_capi_sock.h
ylwrap

View File

@ -1,2 +0,0 @@
# mISDN devices
KERNEL=="mISDNtimer*" , MODE="664", GROUP="@MISDN_GROUP@"

View File

@ -1,6 +0,0 @@
Andreas Eversberg <andreas@eversberg.eu>
Christian Richter <christian.richter@beronet.com>
Karsten Keil <kkeil@linux-pingi.de>
Martin Bachem <m.bachem@gmx.de>
Matthias Urlichs <smurf@smurf.noris.de>
Peter Schlaile <peter@schlaile.de>

2
CHANGES Normal file
View File

@ -0,0 +1,2 @@
mISDNuser-1-1-2:
- nothin changed

View File

@ -1,37 +0,0 @@
#!/bin/sh
#
# I would prefer, if the source code for the mISDNuser project
# follow the some common style.
#
# This is the my prefered option but I also accept others - but maybe I will
# reformat it.
#
# It is nearly the same style the Linux kernel is using, with the exception
# that I allow 132 characters per line (kernel has a strict 80 character limit).
#
# To get your file reformatted with this style, simple run this file as script:
#
# ./CodeStyle <path to source file>
#
# The script part was copied from the linux kernel sources.
#
# Karsten Keil <kkeil@linux-pingi.de>
#
#
PARAM="-npro -kr -i8 -ts8 -sob -l132 -ss -ncs -cp1"
RES=`indent --version`
V1=`echo $RES | cut -d' ' -f3 | cut -d'.' -f1`
V2=`echo $RES | cut -d' ' -f3 | cut -d'.' -f2`
V3=`echo $RES | cut -d' ' -f3 | cut -d'.' -f3`
if [ $V1 -gt 2 ]; then
PARAM="$PARAM -il0"
elif [ $V1 -eq 2 ]; then
if [ $V2 -gt 2 ]; then
PARAM="$PARAM -il0";
elif [ $V2 -eq 2 ]; then
if [ $V3 -ge 10 ]; then
PARAM="$PARAM -il0"
fi
fi
fi
indent $PARAM "$@"

View File

@ -1,42 +0,0 @@
all:
@if test ! -f configure ; then \
$(MAKE) configure ; \
fi
@if test ! -f Makefile.in ; then \
$(MAKE) Makefile.in ; \
fi
@if test -f Makefile ; then \
$(MAKE) -f Makefile $@; \
else \
echo "Please run ./configure"; \
fi
%:
@if test -f Makefile ; then \
$(MAKE) -f Makefile $@; \
else \
echo "Please run ./configure"; \
fi
aclocal.m4:
aclocal
ltmain.sh:
libtoolize --install
Makefile.in: aclocal.m4
-automake --add-missing
autoconf
configure: ltmain.sh Makefile.in aclocal.m4
cleanauto:
-if test -f Makefile ; then \
$(MAKE) -f Makefile distclean ; \
fi
-rm -rf m4 autom4te.cache
-rm install-sh missing aclocal.m4 ltmain.sh depcomp
-rm config.sub config.guess configure
-find . -name Makefile.in -exec rm {} \;
.PHONY: all configure

238
INSTALL
View File

@ -1,238 +0,0 @@
Installation Instructions
*************************
Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
2006, 2007 Free Software Foundation, Inc.
This file is free documentation; the Free Software Foundation gives
unlimited permission to copy, distribute and modify it.
Basic Installation
==================
Briefly, the shell commands `./configure; make; make install' should
configure, build, and install this package. The following
more-detailed instructions are generic; see the `README' file for
instructions specific to this package.
The `configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation. It uses
those values to create a `Makefile' in each directory of the package.
It may also create one or more `.h' files containing system-dependent
definitions. Finally, it creates a shell script `config.status' that
you can run in the future to recreate the current configuration, and a
file `config.log' containing compiler output (useful mainly for
debugging `configure').
It can also use an optional file (typically called `config.cache'
and enabled with `--cache-file=config.cache' or simply `-C') that saves
the results of its tests to speed up reconfiguring. Caching is
disabled by default to prevent problems with accidental use of stale
cache files.
If you need to do unusual things to compile the package, please try
to figure out how `configure' could check whether to do them, and mail
diffs or instructions to the address given in the `README' so they can
be considered for the next release. If you are using the cache, and at
some point `config.cache' contains results you don't want to keep, you
may remove or edit it.
The file `configure.ac' (or `configure.in') is used to create
`configure' by a program called `autoconf'. You need `configure.ac' if
you want to change it or regenerate `configure' using a newer version
of `autoconf'.
The simplest way to compile this package is:
1. `cd' to the directory containing the package's source code and type
`make' to generate the configure script. Then run
`./configure' to configure the package for your system.
Running `configure' might take a while. While running, it prints
some messages telling which features it is checking for.
2. Type `make' to compile the package.
3. Optionally, type `make check' to run any self-tests that come with
the package.
4. Type `make install' to install the programs and any data files and
documentation.
5. You can remove the program binaries and object files from the
source code directory by typing `make clean'. To also remove the
files that `configure' created (so you can compile the package for
a different kind of computer), type `make distclean'. There is
also a `make maintainer-clean' target, but that is intended mainly
for the package's developers. If you use it, you may have to get
all sorts of other programs in order to regenerate files that came
with the distribution.
6. Often, you can also type `make uninstall' to remove the installed
files again.
Compilers and Options
=====================
Some systems require unusual options for compilation or linking that the
`configure' script does not know about. Run `./configure --help' for
details on some of the pertinent environment variables.
You can give `configure' initial values for configuration parameters
by setting variables in the command line or in the environment. Here
is an example:
./configure CC=c99 CFLAGS=-g LIBS=-lposix
*Note Defining Variables::, for more details.
Compiling For Multiple Architectures
====================================
You can compile the package for more than one kind of computer at the
same time, by placing the object files for each architecture in their
own directory. To do this, you can use GNU `make'. `cd' to the
directory where you want the object files and executables to go and run
the `configure' script. `configure' automatically checks for the
source code in the directory that `configure' is in and in `..'.
With a non-GNU `make', it is safer to compile the package for one
architecture at a time in the source code directory. After you have
installed the package for one architecture, use `make distclean' before
reconfiguring for another architecture.
Installation Names
==================
By default, `make install' installs the package's commands under
`/usr/local/bin', include files under `/usr/local/include', etc. You
can specify an installation prefix other than `/usr/local' by giving
`configure' the option `--prefix=PREFIX'.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
pass the option `--exec-prefix=PREFIX' to `configure', the package uses
PREFIX as the prefix for installing programs and libraries.
Documentation and other data files still use the regular prefix.
In addition, if you use an unusual directory layout you can give
options like `--bindir=DIR' to specify different values for particular
kinds of files. Run `configure --help' for a list of the directories
you can set and what kinds of files go in them.
If the package supports it, you can cause programs to be installed
with an extra prefix or suffix on their names by giving `configure' the
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
Optional Features
=================
Some packages pay attention to `--enable-FEATURE' options to
`configure', where FEATURE indicates an optional part of the package.
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
is something like `gnu-as' or `x' (for the X Window System). The
`README' should mention any `--enable-' and `--with-' options that the
package recognizes.
For packages that use the X Window System, `configure' can usually
find the X include and library files automatically, but if it doesn't,
you can use the `configure' options `--x-includes=DIR' and
`--x-libraries=DIR' to specify their locations.
Specifying the System Type
==========================
There may be some features `configure' cannot figure out automatically,
but needs to determine by the type of machine the package will run on.
Usually, assuming the package is built to be run on the _same_
architectures, `configure' can figure that out, but if it prints a
message saying it cannot guess the machine type, give it the
`--build=TYPE' option. TYPE can either be a short name for the system
type, such as `sun4', or a canonical name which has the form:
CPU-COMPANY-SYSTEM
where SYSTEM can have one of these forms:
OS KERNEL-OS
See the file `config.sub' for the possible values of each field. If
`config.sub' isn't included in this package, then this package doesn't
need to know the machine type.
If you are _building_ compiler tools for cross-compiling, you should
use the option `--target=TYPE' to select the type of system they will
produce code for.
If you want to _use_ a cross compiler, that generates code for a
platform different from the build platform, you should specify the
"host" platform (i.e., that on which the generated programs will
eventually be run) with `--host=TYPE'.
Sharing Defaults
================
If you want to set default values for `configure' scripts to share, you
can create a site shell script called `config.site' that gives default
values for variables like `CC', `cache_file', and `prefix'.
`configure' looks for `PREFIX/share/config.site' if it exists, then
`PREFIX/etc/config.site' if it exists. Or, you can set the
`CONFIG_SITE' environment variable to the location of the site script.
A warning: not all `configure' scripts look for a site script.
Defining Variables
==================
Variables not defined in a site shell script can be set in the
environment passed to `configure'. However, some packages may run
configure again during the build, and the customized values of these
variables may be lost. In order to avoid this problem, you should set
them in the `configure' command line, using `VAR=value'. For example:
./configure CC=/usr/local2/bin/gcc
causes the specified `gcc' to be used as the C compiler (unless it is
overridden in the site shell script).
Unfortunately, this technique does not work for `CONFIG_SHELL' due to
an Autoconf bug. Until the bug is fixed you can use this workaround:
CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
`configure' Invocation
======================
`configure' recognizes the following options to control how it operates.
`--help'
`-h'
Print a summary of the options to `configure', and exit.
`--version'
`-V'
Print the version of Autoconf used to generate the `configure'
script, and exit.
`--cache-file=FILE'
Enable the cache: use and save the results of the tests in FILE,
traditionally `config.cache'. FILE defaults to `/dev/null' to
disable caching.
`--config-cache'
`-C'
Alias for `--cache-file=config.cache'.
`--quiet'
`--silent'
`-q'
Do not print messages saying which checks are being made. To
suppress all normal output, redirect it to `/dev/null' (any error
messages will still be shown).
`--srcdir=DIR'
Look for the package's source code in directory DIR. Usually
`configure' can determine that directory automatically.
`configure' also accepts some other, not widely useful, options. Run
`configure --help' for more details.

132
Makefile Normal file
View File

@ -0,0 +1,132 @@
MAJOR=1
MINOR=1
SUBMINOR=2
#
# Set this to your local copy of mISDN
#
MISDNDIR := /usr/src/mqueue/mISDN
PWD=$(shell pwd)
#
# Change this to create an install prefix for the shared libs, programms and
# includes
#
INSTALL_PREFIX := /
export INSTALL_PREFIX
MISDNINCLUDEDIR := $(MISDNDIR)/include
export MISDNINCLUDEDIR
mISDN_DIR := $(PWD)
export mISDN_DIR
INCLUDEDIR := $(mISDN_DIR)/include
export INCLUDEDIR
LIBDIR=/usr/lib
export LIBDIR
CFLAGS:= -g -Wall -I $(INCLUDEDIR) -I $(MISDNINCLUDEDIR)
CFLAGS+= -D CLOSE_REPORT=1
#disable this if your system does not support PIC (position independent code)
ifeq ($(shell uname -m),x86_64)
CFLAGS += -fPIC
endif
export CFLAGS
mISDNLIB := $(PWD)/lib/libmISDN.a
mISDNNETLIB := $(PWD)/i4lnet/libmisdnnet.a
export mISDNLIB
export mISDNNETLIB
SUBDIRS := lib example
SUBDIRS += $(shell if test -d i4lnet ; then echo i4lnet; fi)
SUBDIRS += $(shell if test -d tenovis ; then echo tenovis; fi)
SUBDIRS += $(shell if test -d voip ; then echo voip; fi)
SUBDIRS += $(shell if test -d suppserv ; then echo suppserv; fi)
LIBS := lib/libmISDN.a
all: test_misdn_includes
$(MAKE) TARGET=$@ subdirs
install_path:
mkdir -p $(INSTALL_PREFIX)/usr/bin/
mkdir -p $(INSTALL_PREFIX)/usr/include/mISDNuser/
mkdir -p $(INSTALL_PREFIX)/$(LIBDIR)
install: install_path all
$(MAKE) TARGET=install subdirs
cp include/*.h $(INSTALL_PREFIX)/usr/include/mISDNuser/
subdirs:
set -e; for i in $(SUBDIRS) ; do $(MAKE) -C $$i $(TARGET); done
clean:
$(MAKE) TARGET=$@ subdirs
rm -f *.o *~ DEADJOE $(INCLUDEDIR)/*~ $(INCLUDEDIR)/DEADJOE
distclean: clean
$(MAKE) TARGET=$@ subdirs
rm -f *.o *~ testlog
MAINDIR := $(shell basename $(PWD))
ARCHIVDIR = /usr/src/packages/SOURCES
ARCHIVOPT := -v
# VERSION := $(shell date +"%Y%m%d")
VERSION := 20030423
ARCHIVNAME := $(ARCHIVDIR)/$(MAINDIR)-$(VERSION).tar.bz2
archiv: distclean
cd ../; tar c $(ARCHIVOPT) -f - $(MAINDIR) | bzip2 > $(ARCHIVNAME)
basearchiv: ARCHIVOPT += --exclude i4lnet --exclude voip --exclude tenovis
basearchiv: ARCHIVNAME := $(ARCHIVDIR)/$(MAINDIR)_base-$(VERSION).tar.bz2
basearchiv: archiv
mainarchiv: ARCHIVOPT += --exclude voip --exclude tenovis
mainarchiv: ARCHIVNAME := $(ARCHIVDIR)/$(MAINDIR)_main-$(VERSION).tar.bz2
mainarchiv: archiv
tenovisarchiv: ARCHIVOPT += --exclude voip --exclude i4lnet
tenovisarchiv: ARCHIVNAME := $(ARCHIVDIR)/$(MAINDIR)_tenovis-$(VERSION).tar.bz2
tenovisarchiv: archiv
voiparchiv: ARCHIVOPT += --exclude tenovis
voiparchiv: ARCHIVNAME := $(ARCHIVDIR)/$(MAINDIR)_voip-$(VERSION).tar.bz2
voiparchiv: archiv
test_misdn_includes:
@if ! echo "#include <linux/mISDNif.h>" | gcc -I$(MISDNINCLUDEDIR) -C -E - >/dev/null ; then echo -e "\n\nYou either don't seem to have installed mISDN properly\nor you haven't set the MISDNDIR variable in this very Makefile.\n\nPlease either install mISDN or set the MISDNDIR properly\n"; exit 1; fi
VERSION:
echo $(MAJOR)_$(MINOR)_$(SUBMINOR) > VERSION
snapshot: clean
DIR=mISDNuser-$$(date +"20%y_%m_%d") ; \
echo $$(date +"20%y_%m_%d" | sed -e "s/\//_/g") > VERSION ; \
mkdir -p /tmp/$$DIR ; \
cp -a * /tmp/$$DIR ; \
cd /tmp/; \
tar czf $$DIR.tar.gz $$DIR
release: clean
DIR=mISDNuser-$(MAJOR)_$(MINOR)_$(SUBMINOR) ; \
echo $(MAJOR)_$(MINOR)_$(SUBMINOR) > VERSION ; \
mkdir -p /tmp/$$DIR ; \
cp -a * /tmp/$$DIR ; \
cd /tmp/; \
tar czf $$DIR.tar.gz $$DIR
.PHONY: VERSION clean

View File

@ -1,46 +0,0 @@
ACLOCAL_AMFLAGS = -I m4
export _MEMLEAKDEBUG MISDN_CAPI_GROUP
MISDN_CAPI_GROUP=@MISDN_GROUP@
if MEMLEAKDEBUG
_MEMLEAKDEBUG = "-DMEMLEAK_DEBUG=1"
else
_MEMLEAKDEBUG =
endif
if OPT_EXAMPLE
MAYBE_EXAMPLE = example
endif
if OPT_GUI
MAYBE_GUI = guitools
endif
if OPT_CAPI
MAYBE_CAPI = capi20 capi20/module
endif
SUBDIRS = include lib tools bridge l1oip $(MAYBE_EXAMPLE) $(MAYBE_GUI) $(MAYBE_CAPI)
CLEANFILES = *~
DISTCLEANFILES = 45-misdn.rules
EXTRA_DIST = m4
if GIT_REPO
ChangeLog: $(srcdir)/.git/objects
git log > $@
endif
install-data-local:
install -d $(DESTDIR)$(sysconfdir)/udev/rules.d
install -m 644 45-misdn.rules $(DESTDIR)$(sysconfdir)/udev/rules.d/45-misdn.rules
distuninstallcheck_listfiles = \
find . -type f -print | grep -v '45-misdn.rules'

8
NEWS
View File

@ -1,8 +0,0 @@
Version 2.0.2
- new compatibility handling for AF_ISDN
- small bugfixes
Version 2.0.1
- use GNU autotools
- public includes are now in <mISDN/*>

13
README
View File

@ -1,13 +0,0 @@
This package contain the libmisdn library and some utilities for the
mISDN version 2 Linux ISDN stack.
To build it you need the GNU autotools:
automake
autoconf
libtools
You can create the files automatically with running make.
After this run ./configure with your options and make again.

View File

@ -1 +0,0 @@
theme: jekyll-theme-merlot

View File

@ -1,53 +0,0 @@
AC_DEFUN([MISDN_CHECK_AF_ISDN], [
ac_af_isdn=-1
AC_ARG_WITH(AF_ISDN,
AC_HELP_STRING([--with-AF_ISDN=PNR], [alternative AF_ISDN protocol number, needed if AF_ISDN is not defined]),
[
ac_af_isdn="$withval"
]
)
AC_COMPILE_IFELSE(
[AC_LANG_SOURCE([[#include <sys/socket.h>]],
[[int xdummy = AF_ISDN;]]
)],[
AC_COMPUTE_INT(AF_ISDN_VAL, AF_ISDN, [
AC_INCLUDES_DEFAULT()
#include <sys/socket.h>
],[
AC_MSG_ERROR([cannot evaluate value of AF_ISDN])
])
if test $ac_af_isdn -gt -1 -a $ac_af_isdn != $AF_ISDN_VAL
then
AC_MSG_WARN([Overwriting default AF_ISDN value $AF_ISDN_VAL with $ac_af_isdn])
fi
],[
AF_ISDN_VAL=-1
if test $ac_af_isdn -lt 0
then
AC_MSG_ERROR([AF_ISDN undefined and need to be set with --with-AF_ISDN=PROTOCOLNUMBER])
fi
]
)
MISDN_AF_ISDN_VAL=$ac_af_isdn
AC_SUBST(MISDN_AF_ISDN_VAL)
AC_SUBST(AF_ISDN_VAL)
])
AC_DEFUN([AC_MISDN_GROUP], [
AC_ARG_WITH([mISDN_group],
AS_HELP_STRING([--with-mISDN_group=<unix group name>], [unix access group for mISDN]), [
if test -n "$withval"
then
MISDN_GROUP="$withval"
else
MISDN_GROUP="dialout"
fi
],
[
MISDN_GROUP="dialout"
])
])

1
bridge/.gitignore vendored
View File

@ -1 +0,0 @@
/misdn_bridge

View File

@ -1,6 +0,0 @@
bin_PROGRAMS = misdn_bridge
misdn_bridge_SOURCES = bridge.c
AM_CPPFLAGS = -Wall -Werror -I$(top_srcdir)/include
CLEANFILES = *~

View File

@ -1,906 +0,0 @@
/*****************************************************************************\
** **
** isdnbridge **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg (GPL) **
** **
** user space utility to bridge two mISDN ports via layer 1 **
** **
\*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <errno.h>
#include <mISDN/mISDNif.h>
#include <mISDN/af_isdn.h>
int portcount = 0; /* counts all open ports for finding pair */
int mISDNsocket = -1;
/* quit flag */
int quit = 0;
/* option stuff */
int nooutput = 0;
int traffic = 0;
int debug = 0;
pid_t dsp_pid = 0;
/* mISDN port structure list */
struct mISDNport {
struct mISDNport *next, *prev;
int count; /* port count */
int portnum; /* port number */
int l1link; /* if l1 is available (only works with nt-mode) */
time_t l1establish; /* time until establishing after link failure */
int ntmode; /* is TRUE if port is nt mode */
int pri; /* is TRUE if port is a primary rate interface */
int d_sock;
int b_num; /* number of ports */
int b_sock[256];
int b_state[256]; /* state 0 = IDLE */
unsigned char que_frm[2048]; /* queue while layer 1 is down */
int que_len;
};
struct mISDNport *mISDNport_first = NULL;
enum { B_STATE_IDLE, B_STATE_ACTIVATING, B_STATE_ACTIVE, B_STATE_DEACTIVATING };
/*
* show state
*/
static void show_state(struct mISDNport *m1)
{
struct mISDNport *m2 = m1;
if (nooutput)
return;
if (m1->count & 1)
m1 = m1->prev;
else
m2 = m2->next;
printf("Port %2d %s <-> Port %2d %s\n", m1->portnum, (m1->l1link)?"ACTIVE":"inactive", m2->portnum, (m2->l1link)?"ACTIVE":"inactive");
}
/*
* show traffic
*/
static void show_traffic(struct mISDNport *m1, unsigned char *data, int len)
{
struct mISDNport *m2 = m1;
int right, i;
if (nooutput)
return;
if (m1->count & 1)
{
m1 = m1->prev;
right = 0;
} else
{
m2 = m2->next;
right = 1;
}
printf("Port %2d %s Port %2d :", m1->portnum, right?"-->":"<--", m2->portnum);
i = 0;
while(i < len)
{
printf(" %02x", data[i]);
i++;
}
printf("\n");
}
/*
* debug output
*/
#define PDEBUG(fmt, arg...) _printdebug(__FUNCTION__, __LINE__, fmt, ## arg)
static void _printdebug(const char *function, int line, const char *fmt, ...)
{
char buffer[4096];
va_list args;
if (!debug || nooutput)
return;
va_start(args,fmt);
vsnprintf(buffer, sizeof(buffer)-1, fmt, args);
buffer[sizeof(buffer)-1]=0;
va_end(args);
printf("%s, line %d: %s", function, line, buffer);
}
/*
* signal handler to interrupt main loop
*/
static void sighandler(int sigset)
{
if (sigset == SIGHUP)
return;
if (sigset == SIGPIPE)
return;
fprintf(stderr, "Signal received: %d\n", sigset);
if (!quit)
quit = 1;
}
/*
* send control information to the channel (dsp-module)
*/
static void ph_control(int sock, int c1, int c2)
{
unsigned char data[MISDN_HEADER_LEN+sizeof(int)+sizeof(int)];
struct mISDNhead *hh = (struct mISDNhead *)data;
int len;
int *d = (int *)(data + MISDN_HEADER_LEN);
hh->prim = PH_CONTROL_REQ;
hh->id = 0;
len = MISDN_HEADER_LEN + sizeof(unsigned long)*2;
*d++ = c1;
*d++ = c2;
len = sendto(sock, hh, len, 0, NULL, 0);
if (len <= 0)
fprintf(stderr, "Failed to send to socket %d\n", sock);
}
void ph_control_block(int sock, int c1, void *c2, int c2_len)
{
unsigned char data[MISDN_HEADER_LEN+sizeof(int)+c2_len];
struct mISDNhead *hh = (struct mISDNhead *)data;
int len;
int *d = (int *)(data + MISDN_HEADER_LEN);
hh->prim = PH_CONTROL_REQ;
hh->id = 0;
len = MISDN_HEADER_LEN + sizeof(unsigned long) + c2_len;
*d++ = c1;
memcpy(d, c2, c2_len);
len = sendto(sock, hh, len, 0, NULL, 0);
if (len <= 0)
fprintf(stderr, "Failed to send to socket %d\n", sock);
}
/*
* activate / deactivate bchannel
*/
static void bchannel_activate(struct mISDNport *mISDNport, int i)
{
struct mISDNhead hh;
int len;
/* we must activate if we are deactivated */
if (mISDNport->b_state[i] == B_STATE_IDLE)
{
/* activate bchannel */
PDEBUG("activating bchannel (index %d), because currently idle.\n", i);
hh.prim = PH_ACTIVATE_REQ;
hh.id = 0;
len = sendto(mISDNport->b_sock[i], &hh, MISDN_HEADER_LEN, 0, NULL, 0);
if (len <= 0)
fprintf(stderr, "Failed to send to socket %d of port %d channel index %d\n", mISDNport->b_sock[i], mISDNport->portnum, i);
mISDNport->b_state[i] = B_STATE_ACTIVATING;
return;
}
/* if we are active, we configure our channel */
if (mISDNport->b_state[i] == B_STATE_ACTIVE)
{
/* it is an error if this channel is not associated with a port object */
PDEBUG("during activation, we set rxoff.\n");
ph_control(mISDNport->b_sock[i], DSP_RECEIVE_OFF, 0);
PDEBUG("during activation, we add conference to %d.\n", ((mISDNport->count&(~1)) << 23) + (i<<16) + dsp_pid);
ph_control(mISDNport->b_sock[i], DSP_CONF_JOIN, ((mISDNport->count&(~1)) << 23) + (i<<16) + dsp_pid);
#if 0
if (sadks->crypt)
{
PDEBUG("during activation, we set crypt to crypt=%d.\n", mISDNport->b_port[i]->p_m_crypt);
ph_control_block(mISDNport->b_addr[i], BF_ENABLE_KEY, mISDNport->b_port[i]->p_m_crypt_key, mISDNport->b_port[i]->p_m_crypt_key_len);
}
#endif
}
}
static void bchannel_deactivate(struct mISDNport *mISDNport, int i)
{
struct mISDNhead hh;
int len;
if (mISDNport->b_state[i] == B_STATE_ACTIVE)
{
ph_control(mISDNport->b_sock[i], DSP_CONF_SPLIT, 0);
ph_control(mISDNport->b_sock[i], DSP_RECEIVE_ON, 0);
/* deactivate bchannel */
PDEBUG("deactivating bchannel (index %d), because currently active.\n", i);
hh.prim = PH_DEACTIVATE_REQ;
hh.id = 0;
len = sendto(mISDNport->b_sock[i], &hh, MISDN_HEADER_LEN, 0, NULL, 0);
if (len <= 0)
fprintf(stderr, "Failed to send to socket %d of port %d channel index %d\n", mISDNport->b_sock[i], mISDNport->portnum, i);
mISDNport->b_state[i] = B_STATE_DEACTIVATING;
return;
}
}
/*
* main loop for processing messages from mISDN device
*/
int mISDN_handler(void)
{
struct mISDNport *mISDNport;
int i;
unsigned char data[2048];
struct mISDNhead *hh = (struct mISDNhead *)data;
int len;
int work = 0;
/* handle all ports */
mISDNport = mISDNport_first;
while(mISDNport)
{
len = recv(mISDNport->d_sock, data, sizeof(data), 0);
if (len >= (int)MISDN_HEADER_LEN)
{
work = 1;
/* d-message */
switch(hh->prim)
{
case PH_ACTIVATE_CNF:
case PH_ACTIVATE_IND:
PDEBUG("Received PH_ACTIVATE for port %d.\n", mISDNport->portnum);
if (!mISDNport->l1link)
{
mISDNport->l1link = 1;
show_state(mISDNport);
}
if (mISDNport->que_len)
{
PDEBUG("Data in que, due to inactive link on port %d.\n", mISDNport->portnum);
len = sendto(mISDNport->d_sock, mISDNport->que_frm, mISDNport->que_len, 0, NULL, 0);
if (len <= 0)
fprintf(stderr, "Failed to send to socket %d of port %d\n", mISDNport->d_sock, mISDNport->portnum);
mISDNport->que_len = 0;
}
break;
case PH_DEACTIVATE_CNF:
case PH_DEACTIVATE_IND:
PDEBUG("Received PH_DEACTIVATE for port %d.\n", mISDNport->portnum);
if (mISDNport->l1link)
{
mISDNport->l1link = 0;
show_state(mISDNport);
}
mISDNport->que_len = 0;
break;
case PH_CONTROL_CNF:
case PH_CONTROL_IND:
PDEBUG("Received PH_CONTROL for port %d.\n", mISDNport->portnum);
break;
case PH_DATA_IND:
if (traffic)
show_traffic(mISDNport, data + MISDN_HEADER_LEN, len-MISDN_HEADER_LEN);
PDEBUG("GOT data from %s port %d prim 0x%x id 0x%x\n", (mISDNport->ntmode)?"NT":"TE", mISDNport->portnum, hh->prim, hh->id);
if (mISDNport->count & 1)
{
if (mISDNport->prev == NULL)
{
printf("soft error, no prev where expected.\n");
exit (0);
}
/* sending to previous port */
PDEBUG("sending to %s port %d prim 0x%x id 0x%x\n", (mISDNport->prev->ntmode)?"NT":"TE", mISDNport->prev->portnum, hh->prim, hh->id);
hh->prim = PH_DATA_REQ;
if (mISDNport->prev->l1link)
{
len = sendto(mISDNport->prev->d_sock, data, len, 0, NULL, 0);
if (len <= 0)
fprintf(stderr, "Failed to send to socket %d of port %d\n", mISDNport->d_sock, mISDNport->portnum);
} else {
PDEBUG("layer 1 is down, so we queue and activate link.\n");
memcpy(mISDNport->prev->que_frm, data, len);
mISDNport->prev->que_len = len;
hh->prim = PH_ACTIVATE_REQ;
hh->id = 0;
len = sendto(mISDNport->prev->d_sock, data, MISDN_HEADER_LEN, 0, NULL, 0);
if (len <= 0)
fprintf(stderr, "Failed to send to socket %d of port %d\n", mISDNport->d_sock, mISDNport->portnum);
}
} else {
if (mISDNport->next == NULL)
{
printf("soft error, no next where expected.\n");
exit (0);
}
/* sending to next port */
PDEBUG("sending to %s port %d prim 0x%x id 0x%x\n", (mISDNport->next->ntmode)?"NT":"TE", mISDNport->next->portnum, hh->prim, hh->id);
hh->prim = PH_DATA_REQ;
if (mISDNport->next->l1link)
{
len = sendto(mISDNport->next->d_sock, data, len, 0, NULL, 0);
if (len <= 0)
fprintf(stderr, "Failed to send to socket %d of port %d\n", mISDNport->d_sock, mISDNport->portnum);
} else {
PDEBUG("layer 1 is down, so we queue and activate link.\n");
memcpy(mISDNport->next->que_frm, data, len);
mISDNport->next->que_len = len;
hh->prim = PH_ACTIVATE_REQ;
hh->id = 0;
len = sendto(mISDNport->next->d_sock, data, MISDN_HEADER_LEN, 0, NULL, 0);
if (len <= 0)
fprintf(stderr, "Failed to send to socket %d of port %d\n", mISDNport->d_sock, mISDNport->portnum);
}
}
break;
case PH_DATA_CNF:
//PDEBUG("GOT confirm from %s port %d prim 0x%x id 0x%x\n", (mISDNport->ntmode)?"NT":"TE", mISDNport->portnum, hh->prim, hh->id);
break;
case PH_DATA_REQ:
//PDEBUG("GOT strange PH_DATA REQUEST from %s port %d prim 0x%x id 0x%x 0x%x\n", (mISDNport->ntmode)?"NT":"TE", mISDNport->portnum, hh->prim, hh->id);
break;
default:
break;
}
}
i = 0;
while(i < mISDNport->b_num)
{
len = recv(mISDNport->b_sock[i], data, sizeof(data), 0);
if (len >= (int)MISDN_HEADER_LEN)
{
work = 1;
/* b-message */
switch(hh->prim)
{
/* we don't care about confirms, we use rx data to sync tx */
case PH_DATA_CNF:
//case DL_DATA_CNF:
break;
/* we receive audio data, we respond to it AND we send tones */
case PH_DATA_IND:
case DL_DATA_IND:
PDEBUG("got B-channel data, this should not happen all the time. (just a few until DSP release tx-data are ok)\n");
break;
case PH_CONTROL_IND:
break;
case PH_ACTIVATE_IND:
case DL_ESTABLISH_IND:
case PH_ACTIVATE_CNF:
case DL_ESTABLISH_CNF:
PDEBUG("DL_ESTABLISH confirm: bchannel is now activated (port %d index %i).\n", mISDNport->portnum, i);
mISDNport->b_state[i] = B_STATE_ACTIVE;
bchannel_activate(mISDNport, i);
break;
case PH_DEACTIVATE_IND:
case DL_RELEASE_IND:
case PH_DEACTIVATE_CNF:
case DL_RELEASE_CNF:
PDEBUG("DL_RELEASE confirm: bchannel is now de-activated (port %d index %i).\n", mISDNport->portnum, i);
mISDNport->b_state[i] = B_STATE_IDLE;
break;
default:
PDEBUG("unknown bchannel data (port %d index %i).\n", mISDNport->portnum, i);
}
}
i++;
}
mISDNport = mISDNport->next;
}
return(work);
}
/*
* global function to add a new card (port)
*/
struct mISDNport *mISDN_port_open(int port, int nt_mode, int hdlc)
{
int ret;
struct mISDNhead hh;
struct mISDNport *mISDNport, **mISDNportp, *mISDNport_prev;
int i, cnt;
int bri = 0, pri = 0, pots = 0;
int nt = 0, te = 0;
struct mISDN_devinfo devinfo;
unsigned long on = 1;
struct sockaddr_mISDN addr;
/* query port's requirements */
ret = ioctl(mISDNsocket, IMGETCOUNT, &cnt);
if (ret < 0)
{
fprintf(stderr, "Cannot get number of mISDN devices. (ioctl IMGETCOUNT failed ret=%d)\n", ret);
return(NULL);
}
if (cnt <= 0)
{
fprintf(stderr, "Found no card. Please be sure to load card drivers.\n");
return(NULL);
}
if (port < 0)
{
fprintf(stderr, "Port number cannot be negative\n");
return(NULL);
}
devinfo.id = port;
ret = ioctl(mISDNsocket, IMGETDEVINFO, &devinfo);
if (ret < 0)
{
fprintf(stderr, "Cannot get device information for port %d. (ioctl IMGETDEVINFO failed ret=%d)\n", port, ret);
return(NULL);
}
/* output the port info */
if (devinfo.Dprotocols & (1 << ISDN_P_TE_S0))
{
bri = 1;
te = 1;
}
if (devinfo.Dprotocols & (1 << ISDN_P_NT_S0))
{
bri = 1;
nt = 1;
}
if (devinfo.Dprotocols & (1 << ISDN_P_TE_E1))
{
pri = 1;
te = 1;
}
if (devinfo.Dprotocols & (1 << ISDN_P_NT_E1))
{
pri = 1;
nt = 1;
}
#ifdef ISDN_P_FXS
if (devinfo.Dprotocols & (1 << ISDN_P_FXS))
{
pots = 1;
te = 1;
}
#endif
#ifdef ISDN_P_FXO
if (devinfo.Dprotocols & (1 << ISDN_P_FXO))
{
pots = 1;
nt = 1;
}
#endif
if (bri && pri)
{
fprintf(stderr, "Port %d supports BRI and PRI?? What kind of controller is that?. (Can't use this!)\n", port);
return(NULL);
}
if (pots && !bri && !pri)
{
fprintf(stderr, "Port %d supports POTS, we can't!\n", port);
return(NULL);
}
if (!bri && !pri)
{
fprintf(stderr, "Port %d does not support BRI nor PRI!\n", port);
return(NULL);
}
if (!nt && !te)
{
fprintf(stderr, "Port %d does not support NT-mode nor TE-mode!\n", port);
return(NULL);
}
if (!nt && nt_mode)
{
fprintf(stderr, "Port %d does not support NT-mode as requested!\n", port);
return(NULL);
}
if (!te && !nt_mode)
{
fprintf(stderr, "Port %d does not support TE-mode as requested!\n", port);
return(NULL);
}
/* add mISDNport structure */
mISDNport = mISDNport_first;
mISDNportp = &mISDNport_first;
mISDNport_prev = NULL;
while(mISDNport)
{
mISDNport_prev=mISDNport;
mISDNportp = &mISDNport->next;
mISDNport = mISDNport->next;
}
mISDNport = (struct mISDNport *)calloc(1, sizeof(struct mISDNport));
if (!mISDNport)
{
fprintf(stderr, "Cannot alloc mISDNport structure\n");
return(NULL);
}
memset(mISDNport, 0, sizeof(struct mISDNport));
*mISDNportp = mISDNport;
mISDNport->prev = mISDNport_prev;
/* allocate ressources of port */
mISDNport->count = portcount++;
mISDNport->portnum = port;
mISDNport->b_num = devinfo.nrbchan;
mISDNport->ntmode = nt_mode;
mISDNport->pri = pri;
/* open dchannel */
if (nt_mode)
mISDNport->d_sock = socket(PF_ISDN, SOCK_DGRAM, pri?ISDN_P_NT_E1:ISDN_P_NT_S0);
else
mISDNport->d_sock = socket(PF_ISDN, SOCK_DGRAM, pri?ISDN_P_TE_E1:ISDN_P_TE_S0);
if (mISDNport->d_sock < 0)
{
return(NULL);
}
/* set nonblocking io */
ret = ioctl(mISDNport->d_sock, FIONBIO, &on);
if (ret < 0)
{
fprintf(stderr, "Error: Failed to set dchannel-socket into nonblocking IO\n");
return(NULL);
}
/* bind socket to dchannel */
memset(&addr, 0, sizeof(addr));
addr.family = AF_ISDN;
addr.dev = mISDNport->portnum;
addr.channel = 0;
ret = bind(mISDNport->d_sock, (struct sockaddr *)&addr, sizeof(addr));
if (ret < 0)
{
fprintf(stderr, "Error: Failed to bind dchannel-socket.\n");
return(NULL);
}
PDEBUG("Port %d (%s) opened with %d b-channels.\n", port, devinfo.name, mISDNport->b_num);
/* open bchannels */
i = 0;
while(i < mISDNport->b_num)
{
mISDNport->b_sock[i] = -1;
i++;
}
i = 0;
while(i < mISDNport->b_num)
{
mISDNport->b_sock[i] = socket(PF_ISDN, SOCK_DGRAM, (hdlc)?ISDN_P_B_L2DSPHDLC:ISDN_P_B_L2DSP);
if (mISDNport->b_sock[i] < 0)
{
fprintf(stderr, "Error: Failed to open bchannel-socket for index %d with mISDN-DSP layer. Did you load mISDNdsp.ko?\n", i);
return(NULL);
}
/* set nonblocking io */
ret = ioctl(mISDNport->b_sock[i], FIONBIO, &on);
if (ret < 0)
{
fprintf(stderr, "Error: Failed to set bchannel-socket index %d into nonblocking IO\n", i);
return(NULL);
}
/* bind socket to bchannel */
memset(&addr, 0, sizeof(addr));
addr.family = AF_ISDN;
addr.dev = mISDNport->portnum;
addr.channel = i+1+(i>=15);
ret = bind(mISDNport->b_sock[i], (struct sockaddr *)&addr, sizeof(addr));
if (ret < 0)
{
fprintf(stderr, "Error: Failed to bind bchannel-socket for index %d with mISDN-DSP layer. Did you load mISDNdsp.ko?\n", i);
return(NULL);
}
i++;
}
/* try to activate link layer 1 */
hh.prim = PH_ACTIVATE_REQ;
hh.id = 0;
ret = sendto(mISDNport->d_sock, &hh, MISDN_HEADER_LEN, 0, NULL, 0);
if (ret <= 0)
fprintf(stderr, "Failed to send to socket %d of port %d\n", mISDNport->d_sock, mISDNport->portnum);
/* initially, we assume that the link is down */
mISDNport->l1link = 0;
PDEBUG("using 'mISDN_dsp.o' module\n");
printf("Port %d (%s) %s %s %d b-channels\n", mISDNport->portnum, devinfo.name, (mISDNport->ntmode)?"NT-mode":"TE-mode", pri?"PRI":"BRI", mISDNport->b_num);
return(mISDNport);
}
/*
* global function to free ALL cards (ports)
*/
void mISDN_port_close(void)
{
struct mISDNport *mISDNport, *mISDNporttemp;
int i;
/* free all ports */
mISDNport = mISDNport_first;
while(mISDNport)
{
i = 0;
while(i < mISDNport->b_num)
{
bchannel_deactivate(mISDNport, i);
PDEBUG("freeing %s port %d bchannel (index %d).\n", (mISDNport->ntmode)?"NT":"TE", mISDNport->portnum, i);
if (mISDNport->b_sock[i])
close(mISDNport->b_sock[i]);
i++;
}
PDEBUG("freeing d-stack.\n");
if (mISDNport->d_sock)
close(mISDNport->d_sock);
mISDNporttemp = mISDNport;
mISDNport = mISDNport->next;
memset(mISDNporttemp, 0, sizeof(struct mISDNport));
free(mISDNporttemp);
}
mISDNport_first = NULL;
}
/*
* main routine and loop
*/
int main(int argc, char *argv[])
{
struct mISDNport *mISDNport_a, *mISDNport_b;
int i, j, nt_a, nt_b;
int forking = 0, hdlc = 0;
dsp_pid = getpid();
if (argc <= 1)
{
usage:
printf("Usage: %s [--<option> [...]] te|nt <port a> te|nt <port b> \\\n"
" [te|nt <port c> te|nt <port d> [...]]\n\n", argv[0]);
printf("Example: %s --traffic te 0 nt 1 # bridges port 0 (TE-mode) with port 1 (NT-mode)\n", argv[0]);
printf("Bridges given pairs of ports. The number of given ports must be even.\n");
printf("Each pair of ports must be the same interface size (equal channel number).\n");
printf("Both ports may have same mode, e.g. 'te', to bridge ISDN leased line.\n");
printf("Also bridging a card to ISDN over IP tunnel is possible. (L1oIP)\n");
printf("Use the following options before listing mode and ports:\n");
printf("--af_isdn <nr> use a alternativ address family number.\n");
printf("--fork will make a daemon fork.\n");
printf("--traffic will show D-channel traffic.\n");
printf("--hdlc will bridge all bchannel via HDLC.\n");
printf("--debug will show debug info.\n");
return(0);
}
if (strstr("help", argv[1]))
goto usage;
/* try to open raw socket to check kernel */
mISDNsocket = socket(PF_ISDN, SOCK_RAW, ISDN_P_BASE);
if (mISDNsocket < 0)
{
fprintf(stderr, "Cannot open mISDN due to '%s'. (Does your Kernel support socket based mISDN?)\n", strerror(errno));
return(mISDNsocket);
}
/* read options and ports */
i = 1;
while (i < argc)
{
usleep(200000);
if (!strcmp(argv[i], "--af_isdn"))
{
i++;
if (i == argc) {
fprintf(stderr, "Expecting address family number after --af_isdn\n\n");
goto error;
}
j = strtol(argv[i], NULL, 0);
if (set_af_isdn(j) < 0) {
fprintf(stderr, "Wrong address family number %s\n", argv[i]);
goto error;
}
continue;
}
if (!strcmp(argv[i], "--traffic"))
{
traffic = 1;
i++;
continue;
}
if (!strcmp(argv[i], "--fork"))
{
forking = 1;
i++;
continue;
}
if (!strcmp(argv[i], "--hdlc"))
{
hdlc = 1;
i++;
continue;
}
if (!strcmp(argv[i], "--debug"))
{
debug = 1;
i++;
continue;
}
/* get mode a */
if (!strcasecmp(argv[i], "te"))
nt_a = 0;
else if (!strcasecmp(argv[i], "nt"))
nt_a = 1;
else {
fprintf(stderr, "Expecting 'te' or 'nt' keyword for argument #%d\n\n", i);
goto error;
}
i++; // first port
if (i == argc)
{
fprintf(stderr, "Expecting port a number after given mode.\n\n");
goto error;
}
/* open port a */
mISDNport_a = mISDN_port_open(strtol(argv[i], NULL, 0), nt_a, hdlc);
if (!mISDNport_a)
goto error;
printf("port A: #%d %s, %d b-channels\n", mISDNport_a->portnum, (mISDNport_a->ntmode)?"NT-mode":"TE-mode", mISDNport_a->b_num);
i++; // second mode
if (i == argc)
{
fprintf(stderr, "The number of ports given are not even.\nYou may only bridge two or more pairs of ports.\n\n");
goto error;
}
/* get mode b */
if (!strcasecmp(argv[i], "te"))
nt_b = 0;
else if (!strcasecmp(argv[i], "nt"))
nt_b = 1;
else {
fprintf(stderr, "Expecting 'te' or 'nt' keyword for argument #%d\n\n", i);
goto error;
}
i++; // second port
if (i == argc)
{
fprintf(stderr, "Expecting port b number after given mode.\n\n");
goto error;
}
/* open port b */
mISDNport_b = mISDN_port_open(strtol(argv[i], NULL, 0), nt_b, hdlc);
if (!mISDNport_b)
goto error;
printf("port B: #%d %s, %d b-channels\n", mISDNport_b->portnum, (mISDNport_b->ntmode)?"NT-mode":"TE-mode", mISDNport_b->b_num);
i++; // next port / arg
if (mISDNport_a->b_num != mISDNport_b->b_num)
{
fprintf(stderr, "The pair of ports are not compatible for bridging.\n");
fprintf(stderr, "The number ob B-channels are different: port(%d)=%d, port(%d)=%d\n", mISDNport_a->portnum, mISDNport_a->b_num, mISDNport_b->portnum, mISDNport_b->b_num);
mISDN_port_close();
goto error;
}
/* opening and bridge each pair of bchannels */
j = 0;
while(j < mISDNport_a->b_num)
{
bchannel_activate(mISDNport_a, j);
usleep(5000);
while(mISDN_handler())
;
j++;
}
j = 0;
while(j < mISDNport_b->b_num)
{
bchannel_activate(mISDNport_b, j);
usleep(5000);
while(mISDN_handler())
;
j++;
}
}
printf("%s now started\n",argv[0]);
/* forking */
if (forking) {
pid_t pid;
/* do daemon fork */
pid = fork();
if (pid < 0)
{
fprintf(stderr, "Cannot fork!\n");
goto free;
}
if (pid != 0)
{
exit(0);
}
usleep(30000);
printf("\n");
/* do second fork */
pid = fork();
if (pid < 0)
{
fprintf(stderr, "Cannot fork!\n");
goto free;
}
if (pid != 0)
{
printf("PBX: Starting daemon.\n");
exit(0);
}
nooutput = 1;
}
/* signal handlers */
signal(SIGINT,sighandler);
signal(SIGHUP,sighandler);
signal(SIGTERM,sighandler);
signal(SIGPIPE,sighandler);
while(!quit)
{
//mISDNport_a->l1link = 1;
if (!mISDN_handler())
usleep(30000);
}
/* remove signal handler */
signal(SIGINT,SIG_DFL);
signal(SIGHUP,SIG_DFL);
signal(SIGTERM,SIG_DFL);
signal(SIGPIPE,SIG_DFL);
free:
mISDN_port_close();
close(mISDNsocket);
return(0);
error:
mISDN_port_close();
close(mISDNsocket);
return(-1);
}

2
capi20/.gitignore vendored
View File

@ -1,2 +0,0 @@
Makefile
mISDNcapid

View File

@ -1,29 +0,0 @@
export _USE_SOFTFAX
sbin_PROGRAMS = mISDNcapid
mISDNcapid_SOURCES = daemon.c application.c lplci.c mplci.c ncci.c m_capi.h m_capi_sock.h ncci.h \
mc_buffer.c mc_buffer.h SupplementaryService.h SupplementaryService.c listen.c faxl3.c alaw.c alaw.h \
sff.h sff.c g3_mh.h g3_mh.c capi_obj.c
mISDNcapid_LDADD = ../lib/libmisdn.la -lcapi20
mISDNcapid_LDFLAGS = -shared
if OPT_SOFTDSP
_USE_SOFTFAX = "-DUSE_SOFTFAX"
mISDNcapid_LDADD += -lspandsp -ltiff
else
_USE_SOFTFAX =
endif
AM_CPPFLAGS = -I$(top_srcdir)/include -Werror -Wall $(_USE_SOFTFAX) $(_MEMLEAKDEBUG) -DMISDN_GROUP=\"$(MISDN_GROUP)\"
EXTRA_DIST = capi20.conf.sample
CLEANFILES = *~
install-data-local:
install -d $(DESTDIR)$(sysconfdir)
install -m 644 capi20.conf.sample $(DESTDIR)$(sysconfdir)/capi20.conf
distuninstallcheck_listfiles = \
find . -type f -print | grep -v 'capi20.conf'

View File

@ -1,31 +0,0 @@
/*
* SupplementaryService.c
*
* Author Karsten Keil <kkeil@linux-pingi.de>
*
* Copyright 2011 by Karsten Keil <kkeil@linux-pingi.de>
*
* This code is free software; you can redistribute it and/or modify
* it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE
* version 2.1 as published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU LESSER GENERAL PUBLIC LICENSE for more details.
*
*/
#include "m_capi.h"
#include "SupplementaryService.h"
int SendSSNotificationEvent(struct lPLCI *lp, uint16_t Info)
{
return 0;
}
int capiEncodeFacIndSuspend(unsigned char *p, uint16_t Info)
{
return 0;
}

View File

@ -1,134 +0,0 @@
/*
* SupplementaryService.h
*
* Author Karsten Keil <kkeil@linux-pingi.de>
*
* Copyright 2011 by Karsten Keil <kkeil@linux-pingi.de>
*
* This code is free software; you can redistribute it and/or modify
* it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE
* version 2.1 as published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU LESSER GENERAL PUBLIC LICENSE for more details.
*
*/
#ifndef _SUPPLEMENTARYSERVICE_H
#define _SUPPLEMENTARYSERVICE_H
#ifdef __cplusplus
extern "C" {
#endif
// ---------------------------------------------------------------------------
// Supplementary Services
// ---------------------------------------------------------------------------
#define SuppServiceHR 0x00000001
#define SuppServiceTP 0x00000002
#define SuppServiceECT 0x00000004
#define SuppService3PTY 0x00000008
#define SuppServiceCF 0x00000010
#define SuppServiceCD 0x00000020
#define SuppServiceMCID 0x00000040
#define SuppServiceCCBS 0x00000080
#define mISDNSupportedServices (SuppServiceCD | \
SuppServiceCF | \
SuppServiceTP | \
SuppServiceHR)
#define CapiSupplementaryServiceNotSupported 0x300e
#define CapiRequestNotAllowedInThisState 0x3010
// ---------------------------------------------------------------------------
// structs for Facillity requests
// ---------------------------------------------------------------------------
struct FacReqListen {
uint32_t NotificationMask;
};
struct FacReqSuspend {
unsigned char *CallIdentity;
};
struct FacReqResume {
unsigned char *CallIdentity;
};
struct FacReqCFActivate {
uint32_t Handle;
uint16_t Procedure;
uint16_t BasicService;
unsigned char *ServedUserNumber;
unsigned char *ForwardedToNumber;
unsigned char *ForwardedToSubaddress;
};
struct FacReqCFDeactivate {
uint32_t Handle;
uint16_t Procedure;
uint16_t BasicService;
unsigned char *ServedUserNumber;
};
struct FacReqCDeflection {
uint16_t PresentationAllowed;
unsigned char *DeflectedToNumber;
unsigned char *DeflectedToSubaddress;
};
#define FacReqCFInterrogateParameters FacReqCFDeactivate
struct FacReqCFInterrogateNumbers {
uint32_t Handle;
};
struct FacReqParm {
uint16_t Function;
union {
struct FacReqListen Listen;
struct FacReqSuspend Suspend;
struct FacReqResume Resume;
struct FacReqCFActivate CFActivate;
struct FacReqCFDeactivate CFDeactivate;
struct FacReqCFInterrogateParameters CFInterrogateParameters;
struct FacReqCFInterrogateNumbers CFInterrogateNumbers;
struct FacReqCDeflection CDeflection;
} u;
};
// ---------------------------------------------------------------------------
// structs for Facillity confirms
// ---------------------------------------------------------------------------
struct FacConfGetSupportedServices {
uint16_t SupplementaryServiceInfo;
uint32_t SupportedServices;
};
struct FacConfInfo {
uint16_t SupplementaryServiceInfo;
};
struct FacConfParm {
uint16_t Function;
union {
struct FacConfGetSupportedServices GetSupportedServices;
struct FacConfInfo Info;
} u;
};
int SendSSNotificationEvent(struct lPLCI *, uint16_t);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,121 +0,0 @@
#include "alaw.h"
signed char lin2alaw[65536]; // 16bit unsigned index
signed char *slin2alaw; // 16bit signed index
uint16_t alaw2lin[256]; // alaw -> 16bit PCM, Mono, 8000 hz
// alaw -> signed 16-bit
static short alaw_to_lin[] = {
0x13fc, 0xec04, 0x0144, 0xfebc, 0x517c, 0xae84, 0x051c, 0xfae4,
0x0a3c, 0xf5c4, 0x0048, 0xffb8, 0x287c, 0xd784, 0x028c, 0xfd74,
0x1bfc, 0xe404, 0x01cc, 0xfe34, 0x717c, 0x8e84, 0x071c, 0xf8e4,
0x0e3c, 0xf1c4, 0x00c4, 0xff3c, 0x387c, 0xc784, 0x039c, 0xfc64,
0x0ffc, 0xf004, 0x0104, 0xfefc, 0x417c, 0xbe84, 0x041c, 0xfbe4,
0x083c, 0xf7c4, 0x0008, 0xfff8, 0x207c, 0xdf84, 0x020c, 0xfdf4,
0x17fc, 0xe804, 0x018c, 0xfe74, 0x617c, 0x9e84, 0x061c, 0xf9e4,
0x0c3c, 0xf3c4, 0x0084, 0xff7c, 0x307c, 0xcf84, 0x030c, 0xfcf4,
0x15fc, 0xea04, 0x0164, 0xfe9c, 0x597c, 0xa684, 0x059c, 0xfa64,
0x0b3c, 0xf4c4, 0x0068, 0xff98, 0x2c7c, 0xd384, 0x02cc, 0xfd34,
0x1dfc, 0xe204, 0x01ec, 0xfe14, 0x797c, 0x8684, 0x07bc, 0xf844,
0x0f3c, 0xf0c4, 0x00e4, 0xff1c, 0x3c7c, 0xc384, 0x03dc, 0xfc24,
0x11fc, 0xee04, 0x0124, 0xfedc, 0x497c, 0xb684, 0x049c, 0xfb64,
0x093c, 0xf6c4, 0x0028, 0xffd8, 0x247c, 0xdb84, 0x024c, 0xfdb4,
0x19fc, 0xe604, 0x01ac, 0xfe54, 0x697c, 0x9684, 0x069c, 0xf964,
0x0d3c, 0xf2c4, 0x00a4, 0xff5c, 0x347c, 0xcb84, 0x034c, 0xfcb4,
0x12fc, 0xed04, 0x0134, 0xfecc, 0x4d7c, 0xb284, 0x04dc, 0xfb24,
0x09bc, 0xf644, 0x0038, 0xffc8, 0x267c, 0xd984, 0x026c, 0xfd94,
0x1afc, 0xe504, 0x01ac, 0xfe54, 0x6d7c, 0x9284, 0x06dc, 0xf924,
0x0dbc, 0xf244, 0x00b4, 0xff4c, 0x367c, 0xc984, 0x036c, 0xfc94,
0x0f3c, 0xf0c4, 0x00f4, 0xff0c, 0x3e7c, 0xc184, 0x03dc, 0xfc24,
0x07bc, 0xf844, 0x0008, 0xfff8, 0x1efc, 0xe104, 0x01ec, 0xfe14,
0x16fc, 0xe904, 0x0174, 0xfe8c, 0x5d7c, 0xa284, 0x05dc, 0xfa24,
0x0bbc, 0xf444, 0x0078, 0xff88, 0x2e7c, 0xd184, 0x02ec, 0xfd14,
0x14fc, 0xeb04, 0x0154, 0xfeac, 0x557c, 0xaa84, 0x055c, 0xfaa4,
0x0abc, 0xf544, 0x0058, 0xffa8, 0x2a7c, 0xd584, 0x02ac, 0xfd54,
0x1cfc, 0xe304, 0x01cc, 0xfe34, 0x757c, 0x8a84, 0x075c, 0xf8a4,
0x0ebc, 0xf144, 0x00d4, 0xff2c, 0x3a7c, 0xc584, 0x039c, 0xfc64,
0x10fc, 0xef04, 0x0114, 0xfeec, 0x457c, 0xba84, 0x045c, 0xfba4,
0x08bc, 0xf744, 0x0018, 0xffe8, 0x227c, 0xdd84, 0x022c, 0xfdd4,
0x18fc, 0xe704, 0x018c, 0xfe74, 0x657c, 0x9a84, 0x065c, 0xf9a4,
0x0cbc, 0xf344, 0x0094, 0xff6c, 0x327c, 0xcd84, 0x032c, 0xfcd4
};
static unsigned char linear2alaw(short sample)
{
int best = -1;
int i = 0;
int diff = 0;
int best_diff = 0;
while (i < 256) {
diff = alaw_to_lin[i] - sample;
if (diff < 0)
diff = 0 - diff;
if (diff < best_diff || best < 0) {
best_diff = diff;
best = i;
}
i++;
}
return (best);
}
static int alaw2linear(unsigned char sample)
{
signed short r = 0, sign = 1;
// Must reverse bit order.
sample = ((sample & 0xaaaa) >> 1) | ((sample & 0x5555) << 1);
sample = ((sample & 0xcccc) >> 2) | ((sample & 0x3333) << 2);
sample = (sample >> 4) | (sample << 4);
if (sample & 0x80) {
sample ^= 0xd5; // Flip bits for positive values
} else {
sample ^= 0x55; // Flip bits for negative values
sign = -1; // Remember sign
}
switch (sample & 0x70) {
case 0x70: // Segment 7 (0x800..0xfff)
r = 0x840 | ((sample & 0xf) << 7);
break;
case 0x60: // Segment 6 (0x400..0x7ff)
r = 0x420 | ((sample & 0xf) << 6);
break;
case 0x50: // Segment 5 (0x200..0x3ff)
r = 0x210 | ((sample & 0xf) << 5);
break;
case 0x40: // Segment 4 (0x100..0x1ff)
r = 0x108 | ((sample & 0xf) << 4);
break;
case 0x30: // Segment 3 (0x080..0x0ff)
r = 0x084 | ((sample & 0xf) << 3);
break;
case 0x20: // Segment 2 (0x040..0x07f)
r = 0x042 | ((sample & 0xf) << 2);
break;
default: // Segment 1 (0x000..0x03f)
r = 0x001 | ((sample & 0x1f) << 1);
}
return (r * sign) << 3;
}
// Build table .. makes encoding pretty fast :)
void create_lin2alaw_table(void)
{
int i;
slin2alaw = &lin2alaw[32768];
// build law->linear16
for (i = 0; i < 65535; i++)
slin2alaw[i - 32768] = linear2alaw((short)i - 32768);
// build linear16->law
for (i = 0; i < 256; i++) {
alaw2lin[i] = alaw2linear((unsigned char)i);
}
}

View File

@ -1,10 +0,0 @@
#ifndef _ALAW_H
#define _ALAW_H
#include <stdint.h>
extern signed char lin2alaw[65536]; // 16bit unsigned index
extern signed char *slin2alaw; // 16bit signed index
extern uint16_t alaw2lin[256]; // alaw -> 16bit PCM, Mono, 8000 hz
void create_lin2alaw_table(void);
#endif

View File

@ -1,677 +0,0 @@
/*
* application.c
*
* Written by Karsten Keil <kkeil@linux-pingi.de>
*
* Copyright (C) 2011 Karsten Keil <kkeil@linux-pingi.de>
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2 as published by the
* Free Software Foundation. See the LICENSE file included with
* this package for more details.
*/
#define _GNU_SOURCE
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "m_capi.h"
#include "mc_buffer.h"
static struct mCAPIobj AppRoot;
/* not in capi header files yet */
void capi_freeapplid(unsigned);
int mApplication_init(void)
{
int ret;
memset(&AppRoot, 0, sizeof(AppRoot));
ret = init_cobj(&AppRoot, NULL, Cot_Root, 0, 0);
return ret;
}
static void app_sendcontrol(struct mApplication *appl, int cmd)
{
int ret;
if (appl->cpipe[1] > 0) {
ret = write(appl->cpipe[1], &cmd, sizeof(cmd));
if (ret < sizeof(cmd))
eprint("%s: refcount %d cannot write cmd=%x to controlpipe(%d) ret=%d - %s\n",
CAPIobjIDstr(&appl->cobj), appl->cobj.refcnt, cmd, appl->cpipe[1], ret, strerror(errno));
} else
eprint("%s: refcount %d cannot write cmd=%x - control pipe closed\n",
CAPIobjIDstr(&appl->cobj), appl->cobj.refcnt, cmd);
}
struct mApplication *RegisterApplication(uint16_t ApplId, uint32_t MaxB3Connection, uint32_t MaxB3Blks, uint32_t MaxSizeB3)
{
struct mApplication *appl;
int ret;
appl = calloc(1, sizeof(*appl));
if (appl) {
appl->lcl = calloc(mI_ControllerCount, sizeof(void *));
if (appl->lcl) {
appl->cobj.id2 = ApplId;
ret = init_cobj_registered(&appl->cobj, &AppRoot, Cot_Application, 0);
if (ret) {
eprint("Appl %d: Error on init CapiObj - %s\n", ApplId, strerror(ret));
free(appl->lcl);
free(appl);
appl = NULL;
} else {
if (ret) {
wprint("Application %d already registered\n", ApplId);
put_cobj(&AppRoot);
free(appl->lcl);
free(appl);
appl = NULL;
} else {
appl->MaxB3Con = MaxB3Connection;
appl->MaxB3Blk = MaxB3Blks;
appl->MaxB3Size = MaxSizeB3;
appl->cpipe[0] = -1;
appl->cpipe[1] = -1;
}
}
} else {
eprint("Appl %d: No memory for lController array\n", ApplId);
free(appl);
appl = NULL;
}
} else {
eprint("Appl %d: No memory for application (%zd bytes)\n", ApplId, sizeof(*appl));
}
return appl;
}
int register_lController(struct mApplication *appl, struct lController *lc)
{
unsigned int i;
i = lc->cobj.id - 1;
if (i >= mI_ControllerCount) {
eprint("%s: Register invalid controller ID:%d\n", CAPIobjIDstr(&appl->cobj), lc->cobj.id);
return -EINVAL;
}
if (appl->lcl[i]) {
eprint("%s: controller idx %d ID:%d\already registered\n", CAPIobjIDstr(&appl->cobj), i, lc->cobj.id);
return -EBUSY;
}
if (get_cobj(&lc->cobj)) {
appl->lcl[i] = lc;
} else {
eprint("%s: controller idx %d cannot get controller object %s\n", CAPIobjIDstr(&appl->cobj), i, CAPIobjIDstr(&lc->cobj));
return -EINVAL;
}
return 0;
}
/*
* Release the Application
*
* depending who initiate this we cannot release imediatly, if
* any AppPlci is still in use.
*
* @who: 0 - a AppPlci is released in state APPL_STATE_RELEASE
* 1 - Application is released from CAPI application
* 2 - the controller is resetted
* 3 - the controller is removed
* 4 - the CAPI module will be unload
*/
void ReleaseApplication(struct mApplication *appl, int unregister)
{
int ret;
unsigned int i;
pthread_rwlock_wrlock(&appl->cobj.lock);
if (appl->cobj.cleaned) {
pthread_rwlock_unlock(&appl->cobj.lock);
wprint("%s: already cleaned\n", CAPIobjIDstr(&appl->cobj));
return;
} else
appl->cobj.cleaned = 1;
appl->unregistered = unregister;
if (appl->cpipe[0] > -1 && appl->cpipe[1] > -1) {
wprint("%s appl->cpipe(%d, %d) still open - reuse fds\n", CAPIobjIDstr(&appl->cobj), appl->cpipe[0], appl->cpipe[1]);
} else {
ret = pipe2(appl->cpipe, O_NONBLOCK);
if (ret)
eprint("%s: Cannot open control pipe - %s\n", CAPIobjIDstr(&appl->cobj), strerror(errno));
else
dprint(MIDEBUG_CONTROLLER, "create appl->cpipe(%d, %d)\n", appl->cpipe[0], appl->cpipe[1]);
}
dprint(MIDEBUG_CONTROLLER, "close appl->fd %d\n", appl->fd);
close(appl->fd);
appl->fd = -1;
pthread_rwlock_unlock(&appl->cobj.lock);
/* Signal assigned logical controllers Application is gone */
for (i = 0; i < mI_ControllerCount; i++) {
if (appl->lcl[i]) {
release_lController(appl->lcl[i]);
cleanup_lController(appl->lcl[i]);
}
}
dprint(MIDEBUG_CAPIMSG, "%s: cleaning done refcnt:%d\n", CAPIobjIDstr(&appl->cobj), appl->cobj.refcnt);
app_sendcontrol(appl, MI_PUT_APPLICATION);
}
int ReleaseAllApplications(void)
{
struct mApplication *appl;
struct mCAPIobj *co;
int ret, cnt = 0, fd;
co = get_next_cobj(&AppRoot, NULL);
while (co) {
appl = container_of(co, struct mApplication, cobj);
fd = appl->fd;
ReleaseApplication(appl, 0);
ret = mIcapi_mainpoll_releaseApp(fd, appl->cpipe[0]);
if (ret < 0)
eprint("%s mainpoll not released\n", CAPIobjIDstr(&appl->cobj));
co = get_next_cobj(&AppRoot, co);
cnt++;
}
return cnt;
}
void Free_Application(struct mCAPIobj *co)
{
unsigned int i;
struct mApplication *appl = container_of(co, struct mApplication, cobj);
struct lController *lc;
delist_cobj(&appl->cobj);
if (appl->lcl) {
for (i = 0; i < mI_ControllerCount; i++) {
lc = appl->lcl[i];
appl->lcl[i] = NULL;
if (lc) {
release_lController(lc);
Free_lController(&lc->cobj);
}
}
}
if (!appl->unregistered) /* filedescriptor was closed */
capi_freeapplid(appl->cobj.id2);
dprint(MIDEBUG_CONTROLLER, "close appl->fd %d\n", appl->fd);
if (appl->fd > 0)
close(appl->fd);
appl->fd = -1;
dprint(MIDEBUG_CONTROLLER, "close appl->cpipe(%d, %d)\n", appl->cpipe[0], appl->cpipe[1]);
if (appl->cpipe[1] > 0)
close(appl->cpipe[1]);
appl->cpipe[1] = -1;
if (appl->cpipe[0] > 0)
close(appl->cpipe[0]);
appl->cpipe[0] = -1;
put_cobj(appl->cobj.parent);
appl->cobj.parent = NULL;
iprint("%s: refcnt=%d freed\n", CAPIobjIDstr(&appl->cobj), appl->cobj.refcnt);
pthread_rwlock_destroy(&appl->cobj.lock);
if (appl->lcl)
free(appl->lcl);
appl->lcl = NULL;
free_capiobject(&appl->cobj, appl);
}
void dump_applications(void)
{
struct mApplication *ap;
struct mCAPIobj *co;
unsigned int i;
if (pthread_rwlock_tryrdlock(&AppRoot.lock)) {
wprint("Cannot read lock application list for dumping\n");
return;
}
co = AppRoot.listhead;
while (co) {
ap = container_of(co, struct mApplication, cobj);
iprint("%s: MaxB3Con:%d MaxB3Blk:%d MaxB3Size:%d\n", CAPIobjIDstr(&ap->cobj),
ap->MaxB3Con, ap->MaxB3Blk, ap->MaxB3Size);
iprint("%s: Refs:%d cleaned:%s unregistered:%s cpipe(%d, %d)\n", CAPIobjIDstr(&ap->cobj),
ap->cobj.refcnt, ap->cobj.cleaned ? "yes" : "no", ap->unregistered ? "yes" : "no",
ap->cpipe[0], ap->cpipe[1]);
for (i = 0; i < mI_ControllerCount; i++) {
if (ap->lcl[i]) {
dump_lcontroller(ap->lcl[i]);
ap->lcl[i]->listed = 1;
}
}
co = co->next;
}
pthread_rwlock_unlock(&AppRoot.lock);
}
void Put_Application_cleaned(struct mCAPIobj *co)
{
struct mApplication *appl = container_of(co, struct mApplication, cobj);
if (appl->cobj.cleaned && appl->cpipe[1] > 0)
app_sendcontrol(appl, MI_PUT_APPLICATION);
}
void delisten_application(struct lController *lc)
{
unsigned int i;
struct mApplication *appl;
appl = lc->Appl;
if (!appl) {
wprint("Appl not linked\n");
return;
}
lc->Appl = NULL;
i = lc->cobj.id;
i--;
if (i < mI_ControllerCount) {
if (appl->lcl[i])
put_cobj(&lc->cobj);
appl->lcl[i] = NULL;
}
put_cobj(&appl->cobj);
}
struct lController *get_lController(struct mApplication *appl, unsigned int cont)
{
struct lController *lc;
if (cont > 0 && cont <= mI_ControllerCount)
lc = appl->lcl[cont - 1];
else {
wprint("%s: wrong controller id %d (max %d)\n", CAPIobjIDstr(&appl->cobj), cont, mI_ControllerCount);
lc = NULL;
}
if (lc) {
if (!get_cobj(&lc->cobj)) {
wprint("%s: cannot get controller object %s\n", CAPIobjIDstr(&appl->cobj), CAPIobjIDstr(&lc->cobj));
lc = NULL;
}
}
return lc;
}
static struct lController *find_lController(struct mApplication *appl, unsigned int cont)
{
struct lController *lc;
if (cont > 0 && cont <= mI_ControllerCount)
lc = appl->lcl[cont - 1];
else {
wprint("%s: wrong controller id %d (max %d)\n", CAPIobjIDstr(&appl->cobj), cont, mI_ControllerCount);
lc = NULL;
}
return lc;
}
void SendMessage2Application(struct mApplication *appl, struct mc_buf *mc)
{
int ret;
if (mI_debug_mask & MIDEBUG_CAPIMSG)
mCapi_message2str(mc);
ret = send(appl->fd, mc->rb, mc->len, 0);
if (ret != mc->len)
wprint("Message send error len=%d ret=%d - %s\n", mc->len, ret, strerror(errno));
}
void SendCmsg2Application(struct mApplication *appl, struct mc_buf *mc)
{
int ret;
if (appl->cobj.cleaned || appl->fd < 0) {
/* Application is gone so we need answer INDICATIONS to avoid blocking the state machine */
wprint("%s: Cannot send %s to released application\n", CAPIobjIDstr(&appl->cobj),
capi20_cmd2str(mc->cmsg.Command, mc->cmsg.Subcommand));
if (mc->cmsg.Subcommand != CAPI_IND)
return;
switch(mc->cmsg.Command) {
// for NCCI state machine
case CAPI_CONNECT_B3:
mc->cmsg.Reject = 2;
case CAPI_CONNECT_B3_ACTIVE:
case CAPI_DISCONNECT_B3:
break;
// for PLCI state machine
case CAPI_CONNECT:
mc->cmsg.Reject = 2;
case CAPI_CONNECT_ACTIVE:
case CAPI_DISCONNECT:
break;
case CAPI_FACILITY:
case CAPI_MANUFACTURER:
case CAPI_INFO:
wprint("%s %s ignored\n", CAPIobjIDstr(&appl->cobj),
capi20_cmd2str(mc->cmsg.Command, mc->cmsg.Subcommand));
return;
default:
wprint("%s: %s not handled\n", CAPIobjIDstr(&appl->cobj),
capi20_cmd2str(mc->cmsg.Command, mc->cmsg.Subcommand));
return;
}
capi20_cmsg_answer(&mc->cmsg);
capi_cmsg2message(&mc->cmsg, mc->rb);
mc->len = CAPIMSG_LEN(mc->rb);
mc->refcnt++; /* The message is reused, so increment the refcnt to allow double free */
dprint(MIDEBUG_CONTROLLER, "%s: sent emulated answer %s to PutMessageApplication\n",
CAPIobjIDstr(&appl->cobj), capi20_cmd2str(mc->cmsg.Command, mc->cmsg.Subcommand));
ret = PutMessageApplication(appl, mc);
if (ret)
dprint(MIDEBUG_CONTROLLER, "%s: sent emulated answer %s to PutMessageApplication returned=%d\n",
CAPIobjIDstr(&appl->cobj), capi20_cmd2str(mc->cmsg.Command, mc->cmsg.Subcommand), ret);
} else {
capi_cmsg2message(&mc->cmsg, mc->rb);
mc->len = CAPIMSG_LEN(mc->rb);
if (mI_debug_mask & MIDEBUG_CAPIMSG)
mCapi_message2str(mc);
ret = send(appl->fd, mc->rb, mc->len, 0);
if (ret != mc->len)
eprint("%s: Message send error fd=%d len=%d ret=%d - %s\n",
CAPIobjIDstr(&appl->cobj), appl->fd, mc->len, ret, strerror(errno));
}
}
void SendCmsgAnswer2Application(struct mApplication *appl, struct mc_buf *mc, __u16 Info)
{
capi_cmsg_answer(&mc->cmsg);
mc->cmsg.Info = Info;
SendCmsg2Application(appl, mc);
}
struct lPLCI *get_lPLCI4plci(struct mApplication *appl, uint32_t id)
{
struct lPLCI *lp = NULL;;
struct lController *lc;
struct mPLCI *plci;
lc = find_lController(appl, id & 0x7f);
if (lc) {
plci = getPLCI4Id(p4lController(lc), id & 0xFFFF);
if (plci) {
lp = get_lPLCI4Id(plci, appl->cobj.id2);
put_cobj(&plci->cobj);
}
}
return lp;
}
#define CapiFacilityNotSupported 0x300b
static int FacilityMessage(struct mApplication *appl, struct pController *pc, struct mc_buf *mc)
{
int ret = CapiNoError;
struct mPLCI *plci;
struct lPLCI *lp;
struct BInstance *bi;
unsigned char tmp[64], *p;
p = tmp;
switch (mc->cmsg.FacilitySelector) {
#if 0
case 0x0000: // Handset
#endif
case 0x0001: // DTMF
dprint(MIDEBUG_CONTROLLER, "DTMF addr %06x\n", mc->cmsg.adr.adrNCCI);
plci = getPLCI4Id(pc, mc->cmsg.adr.adrPLCI & 0xFFFF);
lp = get_lPLCI4Id(plci, mc->cmsg.ApplId);
if (plci)
put_cobj(&plci->cobj);
bi = lp ? lp->BIlink : NULL;
if (bi) {
ret = bi->from_up(bi, mc);
} else {
wprint("DTMF addr %06x lPLCI not found\n", mc->cmsg.adr.adrNCCI);
ret = CapiIllController;
}
if (lp)
put_cobj(&lp->cobj);
break;
case 0x0003: // SupplementaryServices
// ret = SupplementaryFacilityReq(appl, mc);
capimsg_setu8(p, 0, 9);
capimsg_setu16(p, 1, 0);
capimsg_setu8(p, 3, 6);
capimsg_setu16(p, 4, 0);
capimsg_setu32(p, 6, 0);
mc->cmsg.FacilityConfirmationParameter = tmp;
SendCmsgAnswer2Application(appl, mc, ret);
free_mc_buf(mc);
ret = CapiNoError;
break;
default:
ret = CapiFacilityNotSupported;
break;
}
return ret;
}
int PutMessageApplication(struct mApplication *appl, struct mc_buf *mc)
{
unsigned int id;
struct pController *pc;
struct lController *lc;
struct mPLCI *plci = NULL;
struct lPLCI *lp = NULL;
struct BInstance *bi;
uint8_t cmd, subcmd;
int ret = CapiNoError;
cmd = CAPIMSG_COMMAND(mc->rb);
subcmd = CAPIMSG_SUBCOMMAND(mc->rb);
if (cmd != CAPI_DATA_B3 && mI_debug_mask & MIDEBUG_CAPIMSG)
mCapi_message2str(mc);
if (mc->len < 12) {
eprint("message %02x/%02x %s too short (%d)\n", cmd, subcmd, capi20_cmd2str(cmd, subcmd), mc->len);
ret = CapiIllCmdOrSubcmdOrMsgToSmall;
SendCmsgAnswer2Application(appl, mc, ret);
return ret;
}
id = CAPIMSG_CONTROL(mc->rb);
lc = get_lController(appl, id & 0x7f);
if (lc)
pc = p4lController(lc);
else
pc = get_cController(id & 0x7f);
if (!pc) {
eprint("message %x controller for id %06x not found\n", cmd, id);
}
dprint(MIDEBUG_CONTROLLER, "%s: ID:%06x cmd %02x/%02x %s\n", CAPIobjIDstr(&appl->cobj),
id, cmd, subcmd, capi20_cmd2str(cmd, subcmd));
switch (cmd) {
// for NCCI state machine
case CAPI_DATA_B3:
case CAPI_CONNECT_B3_ACTIVE:
case CAPI_RESET_B3:
mcbuf_rb2cmsg(mc);
if ((subcmd == CAPI_REQ) || (subcmd == CAPI_RESP)) {
plci = getPLCI4Id(pc, mc->cmsg.adr.adrPLCI & 0xFFFF);
lp = get_lPLCI4Id(plci, mc->cmsg.ApplId);
bi = lp ? lp->BIlink : NULL;
if (bi) {
ret = bi->from_up(bi, mc);
} else {
wprint("%s: cmd %x (%s) %s %s BIlink not found\n", CAPIobjIDstr(&appl->cobj), cmd,
capi20_cmd2str(mc->cmsg.Command, mc->cmsg.Subcommand),
plci ? CAPIobjIDstr(&plci->cobj) : "no plci",
lp ? CAPIobjIDstr(&lp->cobj) : "no lplci");
ret = CapiIllController;
}
} else
ret = CapiIllCmdOrSubcmdOrMsgToSmall;
break;
case CAPI_DISCONNECT_B3:
mcbuf_rb2cmsg(mc);
if ((subcmd == CAPI_REQ) || (subcmd == CAPI_RESP)) {
plci = getPLCI4Id(pc, mc->cmsg.adr.adrPLCI & 0xFFFF);
lp = get_lPLCI4Id(plci, mc->cmsg.ApplId);
bi = lp ? lp->BIlink : NULL;
if (bi) {
ret = bi->from_up(bi, mc);
} else if (subcmd == CAPI_RESP) {
dprint(MIDEBUG_CONTROLLER, "%s: cmd %x (%s) %s %s BIlink already gone - OK\n", CAPIobjIDstr(&appl->cobj), cmd,
capi20_cmd2str(mc->cmsg.Command, mc->cmsg.Subcommand),
plci ? CAPIobjIDstr(&plci->cobj) : "no plci",
lp ? CAPIobjIDstr(&lp->cobj) : "no lplci");
ret = 1; /* free msg in calling function main_recv() */
} else {
ret = CapiIllController;
}
} else
ret = CapiIllCmdOrSubcmdOrMsgToSmall;
break;
case CAPI_CONNECT_B3:
mcbuf_rb2cmsg(mc);
plci = getPLCI4Id(pc, mc->cmsg.adr.adrPLCI & 0xFFFF);
lp = get_lPLCI4Id(plci, mc->cmsg.ApplId);
bi = lp ? lp->BIlink : NULL;
if (bi) {
ret = bi->from_up(bi, mc);
} else {
wprint("%s: cmd %x (%s) %s %s BIlink not found\n", CAPIobjIDstr(&appl->cobj), cmd,
capi20_cmd2str(mc->cmsg.Command, mc->cmsg.Subcommand),
plci ? CAPIobjIDstr(&plci->cobj) : "no plci",
lp ? CAPIobjIDstr(&lp->cobj) : "no lplci");
ret = CapiIllController;
}
break;
// for PLCI state machine
case CAPI_CONNECT:
case CAPI_INFO:
mcbuf_rb2cmsg(mc);
plci = getPLCI4Id(pc, mc->cmsg.adr.adrPLCI);
dprint(MIDEBUG_PLCI, "%s adrPLCI %06x plci:%04x ApplId %d\n", capi20_cmd2str(cmd, subcmd), mc->cmsg.adr.adrPLCI,
plci ? plci->cobj.id : 0xffff, mc->cmsg.ApplId);
if (subcmd == CAPI_REQ) {
if (plci) {
lp = get_lPLCI4Id(plci, mc->cmsg.ApplId);
if (lp)
ret = lPLCISendMessage(lp, mc);
else {
wprint("%s adrPLCI %06x plci:%04x ApplId %d no plci found\n", capi20_cmd2str(cmd, subcmd),
mc->cmsg.adr.adrPLCI, plci ? plci->cobj.id : 0xffff, mc->cmsg.ApplId);
ret = CapiIllController;
}
} else {
if (!lc) {
if (pc) {
lc = addlController(appl, pc, 1);
if (!lc) {
ret = CapiMsgOSResourceErr;
break;
}
} else {
ret = CapiIllController;
break;
}
}
ret = mPLCISendMessage(lc, mc);
}
} else if (subcmd == CAPI_RESP) {
lp = get_lPLCI4Id(plci, mc->cmsg.ApplId);
if (lp)
ret = lPLCISendMessage(lp, mc);
else {
wprint("%s adrPLCI %06x plci:%04x ApplId %d no plci found\n", capi20_cmd2str(cmd, subcmd),
mc->cmsg.adr.adrPLCI, plci ? plci->cobj.id : 0xffff, mc->cmsg.ApplId);
ret = CapiIllController;
}
} else
ret = CapiIllCmdOrSubcmdOrMsgToSmall;
break;
case CAPI_ALERT:
case CAPI_CONNECT_ACTIVE:
case CAPI_DISCONNECT:
case CAPI_SELECT_B_PROTOCOL:
mcbuf_rb2cmsg(mc);
if ((subcmd == CAPI_REQ) || (subcmd == CAPI_RESP)) {
plci = getPLCI4Id(pc, mc->cmsg.adr.adrPLCI);
lp = get_lPLCI4Id(plci, mc->cmsg.ApplId);
dprint(MIDEBUG_PLCI, "adrPLCI %06x plci:%04x ApplId %d lp %p\n", mc->cmsg.adr.adrPLCI,
plci ? plci->cobj.id : 0xffff, mc->cmsg.ApplId, lp);
if (lp)
ret = lPLCISendMessage(lp, mc);
else
ret = CapiIllController;
} else
ret = CapiIllCmdOrSubcmdOrMsgToSmall;
break;
case CAPI_LISTEN:
if (subcmd != CAPI_REQ) {
ret = CapiIllCmdOrSubcmdOrMsgToSmall;
break;
}
mcbuf_rb2cmsg(mc);
if (!lc) {
if (pc) {
lc = addlController(appl, pc, 0);
if (!lc) {
ret = CapiMsgOSResourceErr;
break;
}
} else {
ret = CapiIllController;
break;
}
}
if (!ret)
ret = listenRequest(lc, mc);
break;
case CAPI_FACILITY:
mcbuf_rb2cmsg(mc);
ret = FacilityMessage(appl, pc, mc);
break;
default:
ret = CapiIllCmdOrSubcmdOrMsgToSmall;
wprint("message %x (%s)for controller id %06x not supported yet\n", cmd, capi20_cmd2str(cmd, subcmd), id);
break;
}
if (ret && subcmd != CAPI_RESP)
SendCmsgAnswer2Application(appl, mc, ret);
if (lp)
put_cobj(&lp->cobj);
if (plci)
put_cobj(&plci->cobj);
if (lc)
put_cobj(&lc->cobj);
return ret;
}
void mCapi_cmsg2str(struct mc_buf *mc)
{
char *decmsg, *line;
if (mI_debug_mask & MIDEBUG_CAPIMSG) {
decmsg = capi_cmsg2str(&mc->cmsg);
while (decmsg) {
line = strsep(&decmsg, "\n");
if (line)
dprint(MIDEBUG_CAPIMSG, "%s\n", line);
}
}
}
void mCapi_message2str(struct mc_buf *mc)
{
char *decmsg, *line;
if (mI_debug_mask & MIDEBUG_CAPIMSG) {
decmsg = capi_message2str(mc->rb);
while (decmsg) {
line = strsep(&decmsg, "\n");
if (line)
dprint(MIDEBUG_CAPIMSG, "%s\n", line);
}
}
}

View File

@ -1,15 +0,0 @@
# This is a example config file for mISDNcapid
# columns starting with "#", "!", ";" or newline are ignored
# first column controller type (for mISDNcapi only lines starting with mISDN are used)
# first column could be also a global parameter (e.g. debugmask is supported)
# second column is the number of the mISDN controller (0 -126)
# third column is the CAPI controller number (1-127) default mISDN controller + 1
# forth column is 0 (controller is disabled for CAPI20) or 1 (enabled - default)
# with no config file or a empty config file all mISDN controllers are used for CAPI
debugmask 0x13 - example default debuglevel
mISDN 0 1 1 - first mISDN device is mapped to CAPI20 controller 1 and enabled
mISDN 1 2 0 - second mISDN device is disabled for CAPI20

View File

@ -1,623 +0,0 @@
/*
* capi_obj.c
*
* Author Karsten Keil <kkeil@linux-pingi.de>
*
* Copyright 2012 by Karsten Keil <kkeil@linux-pingi.de>
*
* This code is free software; you can redistribute it and/or modify
* it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE
* version 2.1 as published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU LESSER GENERAL PUBLIC LICENSE for more details.
*
*/
#include "m_capi.h"
#include "mc_buffer.h"
#include "../lib/include/helper.h"
static pthread_rwlock_t danglinglock;
static struct mCAPIobj *danglinglist;
static pthread_mutex_t uniqLock = PTHREAD_MUTEX_INITIALIZER;
static unsigned int uniqID = 1;
static pthread_mutex_t rootLock = PTHREAD_MUTEX_INITIALIZER;
#ifdef MISDN_CAPI_REFCOUNT_DEBUG
#define cobj_dbg(fmt, ...) do {\
if (file && (MIDEBUG_CAPIOBJ & mI_debug_mask))\
mi_printf(file, lineno, __func__, MISDN_LIBDEBUG_DEBUG, fmt, ##__VA_ARGS__);\
} while (0)
#define coref_dbg(fmt, ...) do {\
if (file && (MIDEBUG_CAPIOBJ & mI_debug_mask))\
mi_printf(file, lineno, __func__, MISDN_LIBDEBUG_DEBUG, fmt, ##__VA_ARGS__);\
} while (0)
#define cobj_err(fmt, ...) mi_printf(file, lineno, __func__, MISDN_LIBDEBUG_ERROR, fmt, ##__VA_ARGS__)
#define cobj_warn(fmt, ...) mi_printf(file, lineno, __func__, MISDN_LIBDEBUG_WARN, fmt, ##__VA_ARGS__)
#else
#define cobj_dbg(fmt, ...) dprint(MIDEBUG_CAPIOBJ, fmt, ##__VA_ARGS__)
#define coref_dbg(fmt, ...) do {} while (0)
#define cobj_err(fmt, ...) eprint(fmt, ##__VA_ARGS__)
#define cobj_warn(fmt, ...) wprint(fmt, ##__VA_ARGS__)
#endif
static int ShutdownNow = 0;
#ifdef MISDN_CAPI_REFCOUNT_DEBUG
#define cobj_free(c) __cobj_free(c, __FILE__, __LINE__)
static void __cobj_free(struct mCAPIobj *, const char *, int);
#else
static void cobj_free(struct mCAPIobj *);
#endif
#ifdef MISDN_CAPIOBJ_NO_FREE
static struct mCAPIobj *freelist;
static int freelistCnt = 0;
#endif
void free_capiobject(struct mCAPIobj *co, void *ptr)
{
struct mCAPIobj *c;
if (ShutdownNow) {
free(ptr);
return;
}
if (co->freed) {
eprint("%s: uid=%i double free\n", CAPIobjIDstr(co), co->uid);
return;
}
co->freed = 1;
#ifdef MISDN_CAPIOBJ_NO_FREE
co->freep = ptr;
#endif
if (co->unlisted) {
pthread_rwlock_wrlock(&danglinglock);
c = danglinglist;
while(c) {
if (c == co) {
danglinglist = co->nextD;
break;
}
if (c->nextD == co) {
c->nextD = co->nextD;
break;
}
c = c->nextD;
}
if (!c) {
eprint("%s: not in dangling list corrupted ?\n", CAPIobjIDstr(co));
}
#ifdef MISDN_CAPIOBJ_NO_FREE
co->nextD = freelist;
freelist = co;
freelistCnt++;
#endif
pthread_rwlock_unlock(&danglinglock);
} else {
iprint("%s: not unlisted\n", CAPIobjIDstr(co));
#ifdef MISDN_CAPIOBJ_NO_FREE
pthread_rwlock_wrlock(&danglinglock);
co->nextD = freelist;
freelist = co;
freelistCnt++;
pthread_rwlock_unlock(&danglinglock);
#endif
}
#ifndef MISDN_CAPIOBJ_NO_FREE
free(ptr);
#endif
}
void CAPIobj_init(void)
{
pthread_rwlock_init(&danglinglock, NULL);
danglinglist = NULL;
#ifdef MISDN_CAPIOBJ_NO_FREE
freelist = NULL;
#endif
}
void CAPIobj_exit(void)
{
struct mCAPIobj *co, *cn;
pthread_rwlock_wrlock(&danglinglock);
ShutdownNow = 1;
co = danglinglist;
while (co) {
cn = co->nextD;
eprint("%s: uid=%i refcnt %d in dangling list - freeing now\n", CAPIobjIDstr(co), co->uid, co->refcnt);
co->cleaned = 1;
cobj_free(co);
co = cn;
}
#ifdef MISDN_CAPIOBJ_NO_FREE
co = freelist;
while (co) {
cn = co->nextD;
eprint("%s: uid=%d refcnt %d in free list - freeing now\n", CAPIobjIDstr(co), co->uid, co->refcnt);
free(co->freep);
co = cn;
}
#endif
pthread_rwlock_unlock(&danglinglock);
}
void dump_cobjects(void)
{
struct mCAPIobj *co;
if (pthread_rwlock_tryrdlock(&danglinglock)) {
wprint("Cannot read lock dangling list for dumping\n");
return;
}
co = danglinglist;
iprint("Next unique ID=%i\n", uniqID);
if (!co)
iprint("No items in dangling list\n");
while (co) {
iprint("%s: uid=%i refcnt %d in dangling list\n", CAPIobjIDstr(co), co->uid, co->refcnt);
co = co->nextD;
}
pthread_rwlock_unlock(&danglinglock);
#ifdef MISDN_CAPIOBJ_NO_FREE
iprint("%d items in freelist\n", freelistCnt);
#endif
}
#ifdef MISDN_CAPIOBJ_NO_FREE
void dump_cobjects_free(void)
{
struct mCAPIobj *co;
if (pthread_rwlock_tryrdlock(&danglinglock)) {
wprint("Cannot read lock dangling list for dumping\n");
return;
}
co = freelist;
if (!co)
iprint("No items in free list\n");
while (co) {
iprint("%s: uid=%i refcnt %d in free list\n", CAPIobjIDstr(co), co->uid, co->refcnt);
co = co->nextD;
}
pthread_rwlock_unlock(&danglinglock);
}
#endif
void cobj_unlisted(struct mCAPIobj *co)
{
if (ShutdownNow)
return;
if (co->unlisted) {
eprint("%s: refcnt %d double unlist\n", CAPIobjIDstr(co), co->refcnt);
return;
}
co->unlisted = 1;
pthread_rwlock_wrlock(&danglinglock);
co->nextD = danglinglist;
danglinglist = co;
pthread_rwlock_unlock(&danglinglock);
}
const char *__eCAPIobjtype_s[] = {
"None",
"Root",
"Application",
"lController",
"PLCI",
"lPLCI",
"NCCI",
"Fax",
"Undef",
"Null object"
};
const char *CAPIobjt2str(struct mCAPIobj *co)
{
unsigned int i;
if (co) {
i = co->type;
if (i > Cot_Last)
i = 1 + Cot_Last;
} else
i = 2 + Cot_Last;
return __eCAPIobjtype_s[i];
}
static const char *__CAPIobjt2str(enum eCAPIobjtype cot)
{
unsigned int i;
i = cot;
if (i > Cot_Last)
i = 1 + Cot_Last;
return __eCAPIobjtype_s[i];
}
const char *CAPIobjIDstr(struct mCAPIobj *co)
{
int used;
char stat[8], *p, *s;
if (co) {
s = co->idstr;
if (co->type > Cot_Last) {
used = snprintf(s, CAPIobj_IDSIZE, "%s%d id:%x id2:%x", CAPIobjt2str(co), co->type, co->id, co->id2);
} else {
switch (co->type) {
case Cot_None:
used = snprintf(s, CAPIobj_IDSIZE, "NoneObj id:%x-%x", co->id, co->id2);
break;
case Cot_Root:
used = snprintf(s, CAPIobj_IDSIZE, "RootObj id:%x-%x", co->id, co->id2);
break;
case Cot_Application:
used = snprintf(s, CAPIobj_IDSIZE, "Appl-id:%d", co->id2);
break;
case Cot_lController:
used = snprintf(s, CAPIobj_IDSIZE, "LContr-%02d Appl-%03d", co->id, co->id2);
break;
case Cot_PLCI:
used = snprintf(s, CAPIobj_IDSIZE, " PLCI%04x PID:%08x", co->id, co->id2);
break;
case Cot_lPLCI:
used = snprintf(s, CAPIobj_IDSIZE, " LPLCI%04x Appl-%03d", co->id, co->id2);
break;
case Cot_NCCI:
used = snprintf(s, CAPIobj_IDSIZE, "NCCI%06x Appl-%03d", co->id, co->id2);
break;
case Cot_FAX:
used = snprintf(s, CAPIobj_IDSIZE, " FAX%06x B%d", co->id, co->id2);
break;
}
#ifdef MISDN_CAPI_REFCOUNT_DEBUG
used += snprintf(&s[used], CAPIobj_IDSIZE - used, " *%d", co->refcnt);
#endif
p = stat;
if (co->cleaned)
*p++ = 'C';
if (co->unlisted)
*p++ = co->parent ? 'u' : 'U';
if (co->freeing)
*p++ = (co->freed) ? 'F' : 'f';
*p = 0;
if (p != stat) {
used += snprintf(&s[used], CAPIobj_IDSIZE - used, " %s", stat);
if (used >= CAPIobj_IDSIZE)
wprint("Overflow %d >= %d\n", used, CAPIobj_IDSIZE);
}
}
} else {
s = (char *)CAPIobjt2str(NULL);
}
return s;
}
#ifdef MISDN_CAPI_REFCOUNT_DEBUG
#undef cobj_free
#define cobj_free(c) __cobj_free(c, file, lineno)
static void __cobj_free(struct mCAPIobj *co, const char *file, int lineno)
{
if (!file)
file = "(none)";
#else
static void cobj_free(struct mCAPIobj *co)
{
#endif
if (co->freeing) {
cobj_err("%s: uid=%i refcnt %d called again -- double free attempt\n", CAPIobjIDstr(co), co->uid, co->refcnt);
return;
}
co->freeing = 1;
cobj_dbg("%s: uid=%i freeing now\n", CAPIobjIDstr(co), co->uid);
/* sanity check */
if (co->itemcnt || co->listhead) {
cobj_err("%s: Still %d items in %slist\n", CAPIobjIDstr(co), co->itemcnt, co->listhead ? "" : "NULL ");
}
switch(co->type) {
case Cot_None:
case Cot_Root:
/* we never free these */
wprint("%s: try to free\n", CAPIobjIDstr(co));
break;
case Cot_Application:
Free_Application(co);
break;
case Cot_lController:
Free_lController(co);
break;
case Cot_PLCI:
Free_PLCI(co);
break;
case Cot_lPLCI:
Free_lPLCI(co);
break;
case Cot_NCCI:
Free_NCCI(co);
break;
case Cot_FAX:
Free_Faxobject(co);
break;
}
};
#ifdef MISDN_CAPI_REFCOUNT_DEBUG
struct mCAPIobj *__get_cobj(struct mCAPIobj *co, const char *file, int lineno)
#else
struct mCAPIobj *get_cobj(struct mCAPIobj *co)
#endif
{
struct mCAPIobj *p;
if (co) {
p = co->parent;
if (p) {
pthread_rwlock_wrlock(&p->lock);
} else {
if (co->type != Cot_Root) { /* has no parent */
cobj_err("%s: parent not assigned\n", CAPIobjIDstr(co));
return NULL;
}
pthread_mutex_lock(&rootLock);
}
if (co->cleaned) {
cobj_warn("%s: pending free detected - do not get object\n", CAPIobjIDstr(co));
co = NULL;
} else {
if (co->freeing)
cobj_err("Currently freeing %s refcnt: %d\n", CAPIobjIDstr(co), co->refcnt);
co->refcnt++;
coref_dbg("%s\n", CAPIobjIDstr(co));
}
if (p)
pthread_rwlock_unlock(&p->lock);
else
pthread_mutex_unlock(&rootLock);
} else
coref_dbg("No CAPIobj\n");
return co;
}
#ifdef MISDN_CAPI_REFCOUNT_DEBUG
int __put_cobj(struct mCAPIobj *co, const char *file, int lineno)
#else
int put_cobj(struct mCAPIobj *co)
#endif
{
struct mCAPIobj *p;
int ret = -ENODEV;
if (co) {
if (co->freeing)
cobj_err("Currently freeing %s refcnt: %d\n", CAPIobjIDstr(co), co->refcnt);
p = co->parent;
if (p) {
pthread_rwlock_wrlock(&p->lock);
coref_dbg("%s\n", CAPIobjIDstr(co));
co->refcnt--;
if (co->refcnt < 0) {
cobj_err("%s: refcnt reached %d - list items:%d\n", CAPIobjIDstr(co), co->refcnt, co->itemcnt);
}
ret = co->refcnt;
if (co->cleaned && co->refcnt <= 0) { /* last ref */
pthread_rwlock_unlock(&p->lock);
/* OK not perfect but scheduling here should prevent us from access of freed memory, if a other thread
still pending on the lock - a cleaned object is not longer listed and do not return success in get_obj()
so getting a new reference should not happen after this point */
sched_yield();
cobj_free(co);
} else {
pthread_rwlock_unlock(&p->lock);
if (co->cleaned) {
switch (co->type) {
case Cot_Application: /* Application has a special put handler */
Put_Application_cleaned(co);
break;
default:
break;
}
}
}
} else {
if (co->type == Cot_Root) { /* has no parent */
pthread_mutex_lock(&rootLock);
coref_dbg("%s\n", CAPIobjIDstr(co));
co->refcnt--;
ret = co->refcnt;
pthread_mutex_unlock(&rootLock);
} else
cobj_warn("%s: parent not assigned\n", CAPIobjIDstr(co));
}
} else
cobj_dbg("No CAPIobj\n");
return ret;
}
#ifdef MISDN_CAPI_REFCOUNT_DEBUG
struct mCAPIobj *__get_next_cobj(struct mCAPIobj *parent, struct mCAPIobj *cur, const char *file, int lineno)
#else
struct mCAPIobj *get_next_cobj(struct mCAPIobj *parent, struct mCAPIobj *cur)
#endif
{
struct mCAPIobj *next;
if (parent) {
pthread_rwlock_wrlock(&parent->lock);
if (cur)
next = cur->next;
else
next = parent->listhead;
if (next) {
if (next->cleaned) {
cobj_warn("%s: pending free detected - do not get next\n", CAPIobjIDstr(next));
next = NULL;
} else {
next->refcnt++;
coref_dbg("%s: next %s\n", CAPIobjIDstr(cur), CAPIobjIDstr(next));
}
}
pthread_rwlock_unlock(&parent->lock);
if (parent->freeing)
cobj_err("Currently freeing %s refcnt: %d Next: %s\n", CAPIobjIDstr(parent), parent->refcnt, CAPIobjIDstr(next));
} else
next = NULL;
if (cur) {
#ifdef MISDN_CAPI_REFCOUNT_DEBUG
if (next) {
__put_cobj(cur, NULL, lineno);
} else {
__put_cobj(cur, file, lineno);
}
#else
put_cobj(cur);
#endif
}
return next;
}
static unsigned int get_uniqID(void)
{
unsigned int uid;
pthread_mutex_lock(&uniqLock);
uid = uniqID++;
pthread_mutex_unlock(&uniqLock);
return uid;
}
int init_cobj(struct mCAPIobj *co, struct mCAPIobj *parent, enum eCAPIobjtype cot, unsigned int id, unsigned int id2)
{
int ret;
ret = pthread_rwlock_init(&co->lock, NULL);
co->type = cot;
co->uid = get_uniqID();
if (parent)
co->parent = get_cobj(parent);
else
co->parent = NULL;
co->id = id;
co->id2 = id2;
co->refcnt = 1;
dprint(MIDEBUG_CAPIOBJ, "%s: uid=%i initialized\n", CAPIobjIDstr(co), co->uid);
return ret;
}
int init_cobj_registered(struct mCAPIobj *co, struct mCAPIobj *parent, enum eCAPIobjtype cot, unsigned int idmask)
{
unsigned int id, m = 0, lastid;
int ret = 0;
pthread_rwlock_wrlock(&parent->lock);
co->type = cot;
co->uid = get_uniqID();
id = 0;
if (parent->listhead)
lastid = parent->listhead->id;
else
lastid = 0;
if (cot == Cot_PLCI) {
id = NextFreePLCI(parent);
if (!id)
ret = -EBUSY;
} else {
if (idmask) {
for (m = 0xff; m < 0xff000000; m <<= 8) {
if ((m & idmask) == m) {
id &= idmask;
} else {
id += (lastid & m) + (idmask & m);
if ((id & m) == m) {
ret = -EBUSY; /* overflow */
break;
}
idmask &= ~m;
}
}
}
}
if (ret) {
pthread_rwlock_unlock(&parent->lock);
wprint("%s: uid=%i new id overflow lastid %x id %x test mask %x\n", CAPIobjt2str(co), co->uid, lastid, id, m);
return ret;
}
co->id = id | (idmask & parent->id);
ret = pthread_rwlock_init(&co->lock, NULL);
if (ret == 0) {
co->next = parent->listhead;
parent->listhead = co;
parent->itemcnt++;
co->refcnt = 2;
} else {
eprint("%s: error %s on init lock\n", CAPIobjt2str(co), strerror(errno));
return ret;
}
pthread_rwlock_unlock(&parent->lock);
if (ret == 0)
co->parent = get_cobj(parent);
dprint(MIDEBUG_CAPIOBJ, "%s: uid=%i initialized\n", CAPIobjIDstr(co), co->uid);
return ret;
}
#ifdef MISDN_CAPI_REFCOUNT_DEBUG
int __delist_cobj(struct mCAPIobj *co, const char *file, int lineno)
#else
int delist_cobj(struct mCAPIobj *co)
#endif
{
int r, ret = -EINVAL;
int old __attribute__((unused));
enum eCAPIobjtype pt __attribute__((unused));
struct mCAPIobj *p, *c;
unsigned int uid;
if (co) {
p = co->parent;
if (p) {
pthread_rwlock_wrlock(&p->lock);
c = p->listhead;
old = p->itemcnt;
while (c) {
if (c == co) {
p->listhead = co->next;
break;
}
if (c->next == co) {
c->next = co->next;
break;
}
c = c->next;
}
if (c) {
p->itemcnt--;
cobj_unlisted(co);
}
ret = p->itemcnt;
r = co->refcnt;
uid = co->uid;
pt = p->type;
pthread_rwlock_unlock(&p->lock);
if (c)
r = put_cobj(co);
if (r > 0)
coref_dbg("%s: parent %s items %d->%d\n", CAPIobjIDstr(co), __CAPIobjt2str(pt), old, ret);
else
coref_dbg("Object uid=%i delisted and freed parent %s items %d->%d\n", uid, __CAPIobjt2str(pt), old, ret);
} else
cobj_warn("%s: no parent assigned\n", CAPIobjt2str(co));
}
return ret;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,588 +0,0 @@
/*
* G3 decoding
*
* Written by Karsten Keil <kkeil@linux-pingi.de>
*
* Copyright (C) 2011 Karsten Keil <kkeil@linux-pingi.de>
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2 as published by the
* Free Software Foundation. See the LICENSE file included with
* this package for more details.
*/
#ifdef USE_SOFTFAX
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include "m_capi.h"
#include "g3_mh.h"
/* This debug will generate huge amount of data and slow down the process a lot */
//#define G3_VERBOSE_DEBUG 1
struct g3_mh_code tr_white[64] = {
{ 0, 0x0ac, 0x0ff, 8, 0},
{ 1, 0x038, 0x03f, 6, 0},
{ 2, 0x00e, 0x00f, 4, 0},
{ 3, 0x001, 0x00f, 4, 0},
{ 4, 0x00d, 0x00f, 4, 0},
{ 5, 0x003, 0x00f, 4, 0},
{ 6, 0x007, 0x00f, 4, 0},
{ 7, 0x00f, 0x00f, 4, 0},
{ 8, 0x019, 0x01f, 5, 0},
{ 9, 0x005, 0x01f, 5, 0},
{ 10, 0x01c, 0x01f, 5, 0},
{ 11, 0x002, 0x01f, 5, 0},
{ 12, 0x004, 0x03f, 6, 0},
{ 13, 0x030, 0x03f, 6, 0},
{ 14, 0x00b, 0x03f, 6, 0},
{ 15, 0x02b, 0x03f, 6, 0},
{ 16, 0x015, 0x03f, 6, 0},
{ 17, 0x035, 0x03f, 6, 0},
{ 18, 0x072, 0x07f, 7, 0},
{ 19, 0x018, 0x07f, 7, 0},
{ 20, 0x008, 0x07f, 7, 0},
{ 21, 0x074, 0x07f, 7, 0},
{ 22, 0x060, 0x07f, 7, 0},
{ 23, 0x010, 0x07f, 7, 0},
{ 24, 0x00a, 0x07f, 7, 0},
{ 25, 0x06a, 0x07f, 7, 0},
{ 26, 0x064, 0x07f, 7, 0},
{ 27, 0x012, 0x07f, 7, 0},
{ 28, 0x00c, 0x07f, 7, 0},
{ 29, 0x040, 0x0ff, 8, 0},
{ 30, 0x0c0, 0x0ff, 8, 0},
{ 31, 0x058, 0x0ff, 8, 0},
{ 32, 0x0d8, 0x0ff, 8, 0},
{ 33, 0x048, 0x0ff, 8, 0},
{ 34, 0x0c8, 0x0ff, 8, 0},
{ 35, 0x028, 0x0ff, 8, 0},
{ 36, 0x0a8, 0x0ff, 8, 0},
{ 37, 0x068, 0x0ff, 8, 0},
{ 38, 0x0e8, 0x0ff, 8, 0},
{ 39, 0x014, 0x0ff, 8, 0},
{ 40, 0x094, 0x0ff, 8, 0},
{ 41, 0x054, 0x0ff, 8, 0},
{ 42, 0x0d4, 0x0ff, 8, 0},
{ 43, 0x034, 0x0ff, 8, 0},
{ 44, 0x0b4, 0x0ff, 8, 0},
{ 45, 0x020, 0x0ff, 8, 0},
{ 46, 0x0a0, 0x0ff, 8, 0},
{ 47, 0x050, 0x0ff, 8, 0},
{ 48, 0x0d0, 0x0ff, 8, 0},
{ 49, 0x04a, 0x0ff, 8, 0},
{ 50, 0x0ca, 0x0ff, 8, 0},
{ 51, 0x02a, 0x0ff, 8, 0},
{ 52, 0x0aa, 0x0ff, 8, 0},
{ 53, 0x024, 0x0ff, 8, 0},
{ 54, 0x0a4, 0x0ff, 8, 0},
{ 55, 0x01a, 0x0ff, 8, 0},
{ 56, 0x09a, 0x0ff, 8, 0},
{ 57, 0x05a, 0x0ff, 8, 0},
{ 58, 0x0da, 0x0ff, 8, 0},
{ 59, 0x052, 0x0ff, 8, 0},
{ 60, 0x0d2, 0x0ff, 8, 0},
{ 61, 0x04c, 0x0ff, 8, 0},
{ 62, 0x0cc, 0x0ff, 8, 0},
{ 63, 0x02c, 0x0ff, 8, 0}
};
/* make-up codes white */
struct g3_mh_code mk_white[27] = {
{ 64, 0x01b, 0x01f, 5, 1},
{ 128, 0x009, 0x01f, 5, 1},
{ 192, 0x03a, 0x03f, 6, 1},
{ 256, 0x076, 0x07f, 7, 1},
{ 320, 0x06c, 0x0ff, 8, 1},
{ 384, 0x0ec, 0x0ff, 8, 1},
{ 448, 0x026, 0x0ff, 8, 1},
{ 512, 0x0a6, 0x0ff, 8, 1},
{ 576, 0x016, 0x0ff, 8, 1},
{ 640, 0x0e6, 0x0ff, 8, 1},
{ 704, 0x066, 0x1ff, 9, 1},
{ 768, 0x166, 0x1ff, 9, 1},
{ 832, 0x096, 0x1ff, 9, 1},
{ 896, 0x196, 0x1ff, 9, 1},
{ 960, 0x056, 0x1ff, 9, 1},
{ 1024, 0x156, 0x1ff, 9, 1},
{ 1088, 0x0d6, 0x1ff, 9, 1},
{ 1152, 0x1d6, 0x1ff, 9, 1},
{ 1216, 0x036, 0x1ff, 9, 1},
{ 1280, 0x136, 0x1ff, 9, 1},
{ 1344, 0x0b6, 0x1ff, 9, 1},
{ 1408, 0x1b6, 0x1ff, 9, 1},
{ 1472, 0x032, 0x1ff, 9, 1},
{ 1536, 0x132, 0x1ff, 9, 1},
{ 1600, 0x0b2, 0x1ff, 9, 1},
{ 1664, 0x006, 0x03f, 6, 1},
{ 1728, 0x1b2, 0x1ff, 9, 1}
};
struct g3_mh_code tr_black[64] = {
{ 0, 0x3b0, 0x3ff, 10, 0},
{ 1, 0x002, 0x007, 3, 0},
{ 2, 0x003, 0x003, 2, 0},
{ 3, 0x001, 0x003, 2, 0},
{ 4, 0x006, 0x007, 3, 0},
{ 5, 0x00c, 0x00f, 4, 0},
{ 6, 0x004, 0x00f, 4, 0},
{ 7, 0x018, 0x01f, 5, 0},
{ 8, 0x028, 0x03f, 6, 0},
{ 9, 0x008, 0x03f, 6, 0},
{ 10, 0x010, 0x07f, 7, 0},
{ 11, 0x050, 0x07f, 7, 0},
{ 12, 0x070, 0x07f, 7, 0},
{ 13, 0x020, 0x0ff, 8, 0},
{ 14, 0x0e0, 0x0ff, 8, 0},
{ 15, 0x030, 0x1ff, 9, 0},
{ 16, 0x3a0, 0x3ff, 10, 0},
{ 17, 0x060, 0x3ff, 10, 0},
{ 18, 0x040, 0x3ff, 10, 0},
{ 19, 0x730, 0x7ff, 11, 0},
{ 20, 0x0b0, 0x7ff, 11, 0},
{ 21, 0x1b0, 0x7ff, 11, 0},
{ 22, 0x760, 0x7ff, 11, 0},
{ 23, 0x0a0, 0x7ff, 11, 0},
{ 24, 0x740, 0x7ff, 11, 0},
{ 25, 0x0c0, 0x7ff, 11, 0},
{ 26, 0x530, 0xfff, 12, 0},
{ 27, 0xd30, 0xfff, 12, 0},
{ 28, 0x330, 0xfff, 12, 0},
{ 29, 0xb30, 0xfff, 12, 0},
{ 30, 0x160, 0xfff, 12, 0},
{ 31, 0x960, 0xfff, 12, 0},
{ 32, 0x560, 0xfff, 12, 0},
{ 33, 0xd60, 0xfff, 12, 0},
{ 34, 0x4b0, 0xfff, 12, 0},
{ 35, 0xcb0, 0xfff, 12, 0},
{ 36, 0x2b0, 0xfff, 12, 0},
{ 37, 0xab0, 0xfff, 12, 0},
{ 38, 0x6b0, 0xfff, 12, 0},
{ 39, 0xeb0, 0xfff, 12, 0},
{ 40, 0x360, 0xfff, 12, 0},
{ 41, 0xb60, 0xfff, 12, 0},
{ 42, 0x5b0, 0xfff, 12, 0},
{ 43, 0xdb0, 0xfff, 12, 0},
{ 44, 0x2a0, 0xfff, 12, 0},
{ 45, 0xaa0, 0xfff, 12, 0},
{ 46, 0x6a0, 0xfff, 12, 0},
{ 47, 0xea0, 0xfff, 12, 0},
{ 48, 0x260, 0xfff, 12, 0},
{ 49, 0xa60, 0xfff, 12, 0},
{ 50, 0x4a0, 0xfff, 12, 0},
{ 51, 0xca0, 0xfff, 12, 0},
{ 52, 0x240, 0xfff, 12, 0},
{ 53, 0xec0, 0xfff, 12, 0},
{ 54, 0x1c0, 0xfff, 12, 0},
{ 55, 0xe40, 0xfff, 12, 0},
{ 56, 0x140, 0xfff, 12, 0},
{ 57, 0x1a0, 0xfff, 12, 0},
{ 58, 0x9a0, 0xfff, 12, 0},
{ 59, 0xd40, 0xfff, 12, 0},
{ 60, 0x340, 0xfff, 12, 0},
{ 61, 0x5a0, 0xfff, 12, 0},
{ 62, 0x660, 0xfff, 12, 0},
{ 63, 0xe60, 0xfff, 12, 0}
};
struct g3_mh_code mk_black[27] = {
{ 64, 0x3c0, 0x03ff, 10, 1},
{ 128, 0x130, 0x0fff, 12, 1},
{ 192, 0x930, 0x0fff, 12, 1},
{ 256, 0xda0, 0x0fff, 12, 1},
{ 320, 0xcc0, 0x0fff, 12, 1},
{ 384, 0x2c0, 0x0fff, 12, 1},
{ 448, 0xac0, 0x0fff, 12, 1},
{ 512, 0x6c0, 0x1fff, 13, 1},
{ 576, 0x16c0, 0x1fff, 13, 1},
{ 640, 0xa40, 0x1fff, 13, 1},
{ 704, 0x1a40, 0x1fff, 13, 1},
{ 768, 0x640, 0x1fff, 13, 1},
{ 832, 0x1640, 0x1fff, 13, 1},
{ 896, 0x9c0, 0x1fff, 13, 1},
{ 960, 0x19c0, 0x1fff, 13, 1},
{ 1024, 0x5c0, 0x1fff, 13, 1},
{ 1088, 0x15c0, 0x1fff, 13, 1},
{ 1152, 0xdc0, 0x1fff, 13, 1},
{ 1216, 0x1dc0, 0x1fff, 13, 1},
{ 1280, 0x940, 0x1fff, 13, 1},
{ 1344, 0x1940, 0x1fff, 13, 1},
{ 1408, 0x540, 0x1fff, 13, 1},
{ 1472, 0x1540, 0x1fff, 13, 1},
{ 1536, 0xb40, 0x1fff, 13, 1},
{ 1600, 0x1b40, 0x1fff, 13, 1},
{ 1664, 0x4c0, 0x1fff, 13, 1},
{ 1728, 0x14c0, 0x1fff, 13, 1}
};
struct g3_mh_code special_cw[2] = {
{ 0, 0x0000, 0x0fff, 12, 3},
{ 0, 0x0800, 0x0fff, 12, 2}
};
struct g3_mh_code **white_rev;
struct g3_mh_code **black_rev;
/* white run length table wrunlen_tbl[bitpos to start][val of byte] */
static uint8_t wrunlen_tbl[8][256];
static uint8_t bit_swap[256];
/* we use 13 bit tables */
#define G3_REVERSE_TBL_SIZE 8192
#define G3_REVERSE_MASK 0x1fff
#define G3_REVERSE_BITS 13
static int fill_rev_tbl(struct g3_mh_code **tbl, struct g3_mh_code *code)
{
uint16_t i_cnt, shift, idx;
i_cnt = 0;
shift = code->bits;
idx = code->val | (i_cnt << shift);
while (idx < G3_REVERSE_TBL_SIZE) {
if (!tbl[idx]) {
tbl[idx] = code;
} else {
wprint("Error during fill %x/%d idx %x already filled with %x/%d\n",
code->val, shift, idx, tbl[idx]->val, tbl[idx]->bits);
return -1;
}
i_cnt++;
idx = code->val | (i_cnt << shift);
};
return 0;
}
static inline uint8_t calc_byte_runlen(uint8_t val, uint8_t sb)
{
uint8_t i = sb, bm = 1 << sb;
while (i < 8) {
if ( val & bm)
break;
i++;
bm <<= 1;
}
return i - sb;
}
void g3_gen_tables(void)
{
uint8_t i, v;
white_rev = calloc(G3_REVERSE_TBL_SIZE, sizeof(*white_rev));
black_rev = calloc(G3_REVERSE_TBL_SIZE, sizeof(*black_rev));
for (i = 0; i < 64; i++) {
if (fill_rev_tbl(white_rev, &tr_white[i]))
wprint("Error during white term fill\n");
}
for (i = 0; i < 27; i++) {
if (fill_rev_tbl(white_rev, &mk_white[i]))
wprint("Error during white makeup fill\n");
}
if (fill_rev_tbl(white_rev, &special_cw[0]))
wprint("Error during white skip fill\n");
if (fill_rev_tbl(white_rev, &special_cw[1]))
wprint("Error during white EOL fill\n");
for (i = 0; i < 64; i++) {
if (fill_rev_tbl(black_rev, &tr_black[i]))
wprint("Error during black term fill\n");
}
for (i = 0; i < 27; i++) {
if (fill_rev_tbl(black_rev, &mk_black[i]))
wprint("Error during black makeup fill\n");
}
if (fill_rev_tbl(black_rev, &special_cw[0]))
wprint("Error during black skip fill\n");
if (fill_rev_tbl(black_rev, &special_cw[1]))
wprint("Error during black EOL fill\n");
special_cw[0].bits = 1; /* skip only one bit a time */
/* run length table */
for (i = 0; i < 8; i++) {
v = 0;
do {
wrunlen_tbl[i][v] = calc_byte_runlen(v, i);
v++;
} while (v != 0);
}
/* bit order tab */
v = 0;
do {
bit_swap[v] = (((v & 0x01) << 7) | ((v & 0x02) << 5) | ((v & 0x04) << 3) | ((v & 0x08) << 1) |
((v & 0x10) >> 1) | ((v & 0x20) >> 3) | ((v & 0x40) >> 5) | ((v & 0x80) >> 7));
v++;
} while (v != 0);
}
void g3_destroy_tables(void)
{
free(white_rev);
white_rev = NULL;
free(black_rev);
black_rev =NULL;
}
static struct g3_mh_code *g3_lookup_code(uint16_t val, int black)
{
struct g3_mh_code *code;
if (black)
code = black_rev[val & G3_REVERSE_MASK];
else
code = white_rev[val & G3_REVERSE_MASK];
return code;
}
static inline void _update_nb(struct g3_mh_line_s *ls)
{
if (ls->dp) {
ls->nb = *ls->dp++;
if (ls->dp >= (ls->line + ls->len))
ls->dp = NULL; /* EOL */
} else
ls->nb = 0; /* fill with 0 bits */
ls->nb_bits = 8;
ls->sreg |= ls->nb << 16;
}
static void advance_sreg(struct g3_mh_line_s *ls, uint8_t bits)
{
uint8_t b;
while (bits) {
if (!ls->nb_bits)
_update_nb(ls);
b = bits;
if (b > ls->nb_bits)
b = ls->nb_bits;
ls->sreg >>= b;
ls->nb_bits -= b;
bits -= b;
}
}
static void put_black_run(struct g3_mh_line_s *ls, int bits)
{
uint8_t bitp, bm, b, bb;
uint16_t bytep;
while (bits > 0) {
b = 0xff;
bb = 8;
bitp = ls->bitpos & 7;
bytep = ls->bitpos >> 3;
if (bitp) {
b <<= bitp;
bb -= bitp;
}
if (bits < bb) {
bb = bits;
bm = b;
bm <<= bb;
bm = ~bm;
b &= bm;
}
ls->rawline[bytep] |= bit_swap[b];
ls->bitpos += bb;
bits -= bb;
}
}
const char *code_type_str[] = {
"termination",
"markup",
"EOL",
"FillBit",
};
int g3_decode_line(struct g3_mh_line_s *ls)
{
struct g3_mh_code *cc;
int col = 0; /* start white */
int bits = 0;
// int wlen, ret;
ls->dp = ls->line;
ls->sreg = *ls->dp++;
ls->nb = *ls->dp++;
ls->sreg |= (ls->nb << 8);
ls->nb_bits = 0;
ls->bitcnt = 0;
ls->bitpos = 0;
memset(ls->rawline, 0, ((ls->linelen + 7) >> 3));
#ifdef G3_VERBOSE_DEBUG
dprint(MIDEBUG_NCCI_DATA, "Start decoding line %d, len=%d\n", ls->nr, ls->len);
#endif
while (ls->bitcnt <= ls->linelen) {
cc = g3_lookup_code(ls->sreg, col);
if (cc) {
ls->bitcnt += cc->rl;
#ifdef G3_VERBOSE_DEBUG
dprint(MIDEBUG_NCCI_DATA, "sreg = %04x %s %s code %x %d bits runlen %d sum %4d\n",
ls->sreg, col ? "black" : "white", code_type_str[cc->type],
cc->val, cc->bits, cc->rl, ls->bitcnt);
#endif
advance_sreg(ls, cc->bits);
switch(cc->type) {
case G3_CWTYPE_TERMINATION:
bits += cc->rl;
if (col)
put_black_run(ls, bits);
else
ls->bitpos += bits;
bits = 0;
col = !col;
break;
case G3_CWTYPE_MAKEUP:
bits += cc->rl;
break;
default:
break;
}
} else {
wprint("sreg = %04x no code found\n", ls->sreg);
break;
}
if (ls->bitcnt == ls->linelen && ls->sreg == 0)
break;
}
#ifdef G3_VERBOSE_DEBUG
dprint(MIDEBUG_NCCI_DATA, "Stop decoding line %d, len=%d\n", ls->nr, ls->bitcnt);
#endif
// g3_print_hex(stdout, ls->rawline, (ls->bitcnt +7)>>3);
#if 0
if (ls->fd >= 0) {
/* Write raw linedata */
wlen = (ls->linelen + 7) >> 3;
ret = write(ls->fd, ls->rawline, wlen);
if (ret != wlen) {
wprint("Cannot write %d bytes (ret = %d) to plain file - %s\n", wlen, ret, strerror(errno));
}
}
#endif
return ls->bitcnt;
}
static int calc_current_runlen(struct g3_mh_line_s *ls, int col)
{
uint16_t sval = ls->bitcnt;
uint16_t bitsleft, crl, rl = 0;
uint8_t val, sbit, bitcnt;
bitsleft = ls->linelen - ls->bitcnt;
while (bitsleft) {
sbit = sval & 7;
val = bit_swap[ls->rawline[sval >> 3]];
if (col)
val ^= 0xff;
bitcnt = 8 - sbit;
if (bitsleft < bitcnt)
bitcnt = bitsleft;
crl = wrunlen_tbl[sbit][val];
if (crl > bitcnt)
crl = bitcnt;
rl += crl;
if (crl < bitcnt) {
/* found new color */
sval += crl;
break;
}
sval += bitcnt;
bitsleft -= bitcnt;
}
ls->bitcnt = sval;
return rl;
}
static void write_mh_code(struct g3_mh_line_s *ls, struct g3_mh_code *cc, int col)
{
uint32_t creg;
uint16_t bits, bitoff, idx;
creg = cc->val;
bitoff = ls->bitpos & 7;
idx = ls->bitpos >> 3;
creg <<= bitoff;
bits = cc->bits;
ls->sreg |= creg;
ls->line[idx] = ls->sreg & 0xff;
ls->bitpos += bits;
bits += bitoff;
#ifdef G3_VERBOSE_DEBUG
dprint(MIDEBUG_NCCI_DATA, "sreg = %04x %s %s code %x %d bits runlen %d sum %4d\n",
ls->sreg, col ? "black" : "white", code_type_str[cc->type],
cc->val, cc->bits, cc->rl, ls->bitpos);
#endif
while (bits > 7) {
ls->line[idx] = ls->sreg & 0xff;
idx++;
bits -= 8;
ls->sreg >>= 8;
}
ls->line[idx] = ls->sreg & 0xff;
}
static int put_runlen(struct g3_mh_line_s *ls, uint16_t rl, int col)
{
uint16_t tidx, midx;
struct g3_mh_code *cc;
tidx = rl & 0x3f;
midx = rl >> 6;
if (midx) {
if (midx > 28) {
wprint("runlen too big - not supported yet\n");
return -1;
}
midx--;
cc = col ? &mk_black[midx] : &mk_white[midx];
write_mh_code(ls, cc, col);
}
cc = col ? &tr_black[tidx] : &tr_white[tidx];
write_mh_code(ls, cc, col);
return 0;
}
int g3_encode_line(struct g3_mh_line_s *ls)
{
int col = 0;
uint16_t rl;
ls->dp = ls->line;
ls->bitpos = 0;
ls->bitcnt = 0;
ls->sreg = 0;
#ifdef G3_VERBOSE_DEBUG
dprint(MIDEBUG_NCCI_DATA, "Start encoding line %d, len=%d\n", ls->nr, ls->linelen);
#endif
while (ls->bitcnt < ls->linelen) {
rl = calc_current_runlen(ls, col);
put_runlen(ls, rl, col);
col = !col;
}
ls->len = (ls->bitpos + 7) >> 3;
#ifdef G3_VERBOSE_DEBUG
dprint(MIDEBUG_NCCI_DATA, "Stop encoding line %d, compressed bits: %d len %d\n", ls->nr, ls->bitpos, ls->len);
#endif
return ls->len;
}
/* USE_SOFTFAX */
#endif

View File

@ -1,64 +0,0 @@
/*
* G3 decoding
*
* Written by Karsten Keil <kkeil@linux-pingi.de>
*
* Copyright (C) 2011 Karsten Keil <kkeil@linux-pingi.de>
*
* This code is free software; you can redistribute it and/or modify
* it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE
* version 2.1 as published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU LESSER GENERAL PUBLIC LICENSE for more details.
*
*/
#ifndef _G3_MH_H
#define _G3_MH_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
struct g3_mh_code {
uint16_t rl;
uint16_t val;
uint16_t bitm;
uint8_t bits;
uint8_t type;
};
#define G3_CWTYPE_TERMINATION 0
#define G3_CWTYPE_MAKEUP 1
extern void g3_gen_tables(void);
extern void g3_destroy_tables(void);
struct g3_mh_line_s {
unsigned char *line;
unsigned char *dp;
unsigned char *rawline;
uint16_t bitpos;
uint16_t len;
uint32_t sreg;
uint8_t nb;
uint16_t linelen;
uint16_t nb_bits;
uint16_t bitcnt;
int nr;
};
extern int g3_decode_line(struct g3_mh_line_s *);
extern int g3_encode_line(struct g3_mh_line_s *);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,261 +0,0 @@
/* $Id: listen.c,v 1.8 2004/01/26 22:21:30 keil Exp $
*
*/
#include "m_capi.h"
#include "../lib/include/helper.h"
// --------------------------------------------------------------------
// LISTEN state machine
enum {
ST_LISTEN_L_0,
ST_LISTEN_L_0_1,
ST_LISTEN_L_1,
ST_LISTEN_L_1_1,
} const ST_LISTEN_COUNT = ST_LISTEN_L_1_1 + 1;
static const char *str_st_listen[] = {
"ST_LISTEN_L_0",
"ST_LISTEN_L_0_1",
"ST_LISTEN_L_1",
"ST_LISTEN_L_1_1",
};
enum {
EV_LISTEN_REQ,
EV_LISTEN_CONF,
} const EV_LISTEN_COUNT = EV_LISTEN_CONF + 1;
static const char *str_ev_listen[] = {
"EV_LISTEN_REQ",
"EV_LISTEN_CONF",
};
static struct Fsm listen_fsm = { 0, 0, 0, 0, 0 };
static void listen_debug(struct FsmInst *fi, const char *fmt, ...)
{
char tmp[128];
va_list args;
struct lController *lc = fi->userdata;
if (!fi->debug)
return;
va_start(args, fmt);
vsnprintf(tmp, 128, fmt, args);
dprint(MIDEBUG_STATES, "%s: listen %s\n", CAPIobjIDstr(&lc->cobj), tmp);
va_end(args);
}
static void listen_req_l_x(struct FsmInst *fi, int event, void *arg, int state)
{
struct lController *lc = fi->userdata;
struct mc_buf *mc = arg;
const char *ids;
FsmChangeState(fi, state);
ids = CAPIobjIDstr(&lc->cobj);
dprint(MIDEBUG_CONTROLLER, "%s: set InfoMask %08x -> %08x\n", ids, lc->InfoMask, mc->cmsg.InfoMask);
dprint(MIDEBUG_CONTROLLER, "%s: set CIPmask %08x -> %08x\n", ids, lc->CIPmask, mc->cmsg.CIPmask);
dprint(MIDEBUG_CONTROLLER, "%s: set CIPmask2 %08x -> %08x\n", ids, lc->CIPmask2, mc->cmsg.CIPmask2);
lc->InfoMask = mc->cmsg.InfoMask;
lc->CIPmask = mc->cmsg.CIPmask;
lc->CIPmask2 = mc->cmsg.CIPmask2;
ListenController(p4lController(lc));
capi_cmsg_answer(&mc->cmsg);
mc->cmsg.Info = CapiNoError;
FsmEvent(&lc->listen_m, EV_LISTEN_CONF, mc);
}
static void listen_req_l_0(struct FsmInst *fi, int event, void *arg)
{
listen_req_l_x(fi, event, arg, ST_LISTEN_L_0_1);
}
static void listen_req_l_1(struct FsmInst *fi, int event, void *arg)
{
listen_req_l_x(fi, event, arg, ST_LISTEN_L_1_1);
}
static void listen_conf_l_x_1(struct FsmInst *fi, int event, void *arg, int state)
{
struct lController *lc = fi->userdata;
struct mc_buf *mc = arg;
if (mc->cmsg.Info != CapiNoError) {
FsmChangeState(fi, state);
} else { // Info == 0
if (lc->CIPmask == 0) {
FsmChangeState(fi, ST_LISTEN_L_0);
} else {
FsmChangeState(fi, ST_LISTEN_L_1);
}
}
SendCmsg2Application(lc->Appl, mc);
}
static void listen_conf_l_0_1(struct FsmInst *fi, int event, void *arg)
{
listen_conf_l_x_1(fi, event, arg, ST_LISTEN_L_0);
}
static void listen_conf_l_1_1(struct FsmInst *fi, int event, void *arg)
{
listen_conf_l_x_1(fi, event, arg, ST_LISTEN_L_1);
}
static struct FsmNode fn_listen_list[] = {
{ST_LISTEN_L_0, EV_LISTEN_REQ, listen_req_l_0},
{ST_LISTEN_L_0_1, EV_LISTEN_CONF, listen_conf_l_0_1},
{ST_LISTEN_L_1, EV_LISTEN_REQ, listen_req_l_1},
{ST_LISTEN_L_1_1, EV_LISTEN_CONF, listen_conf_l_1_1},
};
const int FN_LISTEN_COUNT = sizeof(fn_listen_list) / sizeof(struct FsmNode);
struct lController *addlController(struct mApplication *app, struct pController *pc, int openl3)
{
struct lController *lc;
int ret;
if (openl3) {
if (OpenLayer3(pc)) {
eprint("Controller%d: Application %d - cannot open L3 instance\n", pc->profile.ncontroller, app->cobj.id2);
return NULL;
}
}
lc = calloc(1, sizeof(*lc));
if (lc) {
lc->cobj.id2 = app->cobj.id2;
if (!get_cobj(&app->cobj)) {
eprint("Cannot get application object\n");
free(lc);
return NULL;
}
ret = init_cobj_registered(&lc->cobj, &pc->cobjLC, Cot_lController, 0x0000ff);
if (ret) {
eprint("Controller%d: Application %d - cannot init\n", pc->profile.ncontroller, app->cobj.id2);
put_cobj(&app->cobj);
free(lc);
lc = NULL;
} else {
lc->Appl = app;
lc->listen_m.fsm = &listen_fsm;
lc->listen_m.state = ST_LISTEN_L_0;
lc->listen_m.debug = MIDEBUG_CONTROLLER & mI_debug_mask;
lc->listen_m.userdata = lc;
lc->listen_m.printdebug = listen_debug;
lc->InfoMask = 0;
lc->CIPmask = 0;
lc->CIPmask2 = 0;
ret = register_lController(app, lc);
if (ret) {
lc->Appl = NULL;
put_cobj(&app->cobj);
eprint("Controller%d: - cannot register LC on Application %d - %s\n", pc->profile.ncontroller,
app->cobj.id2, strerror(-ret));
lc->cobj.cleaned = 1;
delist_cobj(&lc->cobj);
put_cobj(&lc->cobj);
lc = NULL;
}
}
} else
eprint("Controller%d: Application %d - no memory for lController\n", pc->profile.ncontroller, app->cobj.id2);
return lc;
}
void dump_lControllers(struct pController *pc)
{
struct mCAPIobj *co;
struct lController *lc;
if (pthread_rwlock_tryrdlock(&pc->cobjLC.lock)) {
wprint("Cannot read lock LC list for dumping\n");
return;
}
co = pc->cobjLC.listhead;
while (co) {
lc = container_of(co, struct lController, cobj);
if (lc->listed)
lc->listed = 0;
else
dump_lcontroller(lc);
co = co->next;
}
pthread_rwlock_unlock(&pc->cobjLC.lock);
}
void cleanup_lController(struct lController *lc)
{
struct pController *pc = p4lController(lc);
dprint(MIDEBUG_CONTROLLER, "%s: cleaning now refcnt %d (%scleaned)\n", CAPIobjIDstr(&lc->cobj),
lc->cobj.refcnt, lc->cobj.cleaned ? "" : "not ");
if (lc->cobj.cleaned) {
return;
}
lc->cobj.cleaned = 1;
delisten_application(lc);
delist_cobj(&lc->cobj);
if (pc)
ListenController(pc);
}
void Free_lController(struct mCAPIobj *co)
{
struct lController *lc = container_of(co, struct lController, cobj);
struct pController *pc = p4lController(lc);
if (lc->Appl)
delisten_application(lc);
if (pc) {
co->cleaned = 1;
if (co->parent) {
delist_cobj(co);
put_cobj(co->parent);
co->parent = NULL;
}
/* update controller masks */
ListenController(pc);
}
dprint(MIDEBUG_CONTROLLER, "%s: freeing done\n", CAPIobjIDstr(co));
free_capiobject(co, lc);
}
int listenRequest(struct lController *lc, struct mc_buf *mc)
{
FsmEvent(&lc->listen_m, EV_LISTEN_REQ, mc);
free_mc_buf(mc);
return CapiNoError;
}
int listenHandle(struct lController *lc, uint16_t CIPValue)
{
if ((lc->CIPmask & 1) || (lc->CIPmask & (1 << CIPValue)))
return 1;
return 0;
}
void dump_lcontroller(struct lController *lc)
{
iprint("%s: Refs:%d state:%s Info:%08x CIP:%08x CIP2:%08x\n", CAPIobjIDstr(&lc->cobj), lc->cobj.refcnt,
str_st_listen[lc->listen_m.state], lc->InfoMask, lc->CIPmask, lc->CIPmask2);
}
void init_listen(void)
{
listen_fsm.state_count = ST_LISTEN_COUNT;
listen_fsm.event_count = EV_LISTEN_COUNT;
listen_fsm.strEvent = str_ev_listen;
listen_fsm.strState = str_st_listen;
FsmNew(&listen_fsm, fn_listen_list, FN_LISTEN_COUNT);
}
void free_listen(void)
{
FsmFree(&listen_fsm);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,570 +0,0 @@
/* m_capi.h
*
* Author Karsten Keil <kkeil@linux-pingi.de>
*
* Copyright 2011 by Karsten Keil <kkeil@linux-pingi.de>
*
* This code is free software; you can redistribute it and/or modify
* it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE
* version 2.1 as published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU LESSER GENERAL PUBLIC LICENSE for more details.
*
*/
#ifndef _M_CAPI_H
#define _M_CAPI_H
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <string.h>
#include <pthread.h>
#include <poll.h>
#include <semaphore.h>
#include <mISDN/mISDNif.h>
#include <mISDN/mlayer3.h>
#include <mISDN/q931.h>
#include <capi20.h>
#include "mc_buffer.h"
#include "../lib/include/fsm.h"
#include "../lib/include/debug.h"
//#include "../lib/include/mlist.h"
#include "../lib/include/helper.h"
/* Some DEBUG features defines */
/* Refcounting functions will log, if debug mask bit 31 is set */
#define MISDN_CAPI_REFCOUNT_DEBUG 1
/* this define is only for developing if double frees are detected, it never free any object !!! - big memory leak */
/* #define MISDN_CAPIOBJ_NO_FREE 1 */
/* Some globals */
extern int KeepTemporaryFiles;
extern int WriteWaveFiles;
extern char *TempDirectory;
extern pid_t gettid(void);
/* Master control defines */
#define MICD_EV_MASK 0xffff0000
#define MICD_EV_LEN 0x0000ffff
#define MICD_CTRL_SHUTDOWN 0x42010000
#define MICD_CTRL_DISABLE_POLL 0x42020000
#define MICD_CTRL_ENABLE_POLL 0x42030000
#define MICD_CTRL_REOPEN_LOG 0x42040000
#define MICD_CTRL_DUMP_1 0x42050000
#define MICD_CTRL_DUMP_2 0x42060000
int send_master_control(int, int, void *);
struct mCAPIobj;
struct mApplication;
struct mPLCI;
struct lPLCI;
struct mNCCI;
struct pController;
struct lController;
struct BInstance;
extern int mI_ControllerCount;
extern struct timer_base *mICAPItimer_base;
struct Bprotocol {
uint16_t B1;
uint16_t B2;
uint16_t B3;
unsigned char B1cfg[16];
unsigned char B2cfg[16];
unsigned char B3cfg[132];
};
typedef int (BDataTrans_t)(struct BInstance *, struct mc_buf *);
enum BType {
BType_None = 0,
BType_Direct = 1,
BType_Fax = 2,
BType_tty = 3
};
const char *BItype2str(enum BType);
enum eCAPIobjtype {
Cot_None = 0,
Cot_Root,
Cot_Application,
Cot_lController,
Cot_PLCI,
Cot_lPLCI,
Cot_NCCI,
Cot_FAX
};
#define Cot_Last Cot_FAX
#ifdef MISDN_CAPI_REFCOUNT_DEBUG
#define CAPIobj_IDSIZE 48
#else
#define CAPIobj_IDSIZE 32
#endif
struct mCAPIobj {
struct mCAPIobj *next;
struct mCAPIobj *nextD;
enum eCAPIobjtype type;
int refcnt;
struct mCAPIobj *parent;
pthread_rwlock_t lock;
struct mCAPIobj *listhead;
int itemcnt;
unsigned int id;
unsigned int id2;
unsigned int uid;
unsigned int cleaned:1;
unsigned int unlisted:1;
unsigned int freeing:1;
unsigned int freed:1;
char idstr[CAPIobj_IDSIZE];
#ifdef MISDN_CAPIOBJ_NO_FREE
void *freep;
#endif
};
#if __GNUC_PREREQ (3,4)
# define __WUR __attribute__ ((__warn_unused_result__))
#else
# define __WUR
#endif
#ifdef MISDN_CAPI_REFCOUNT_DEBUG
struct mCAPIobj *__get_cobj(struct mCAPIobj *, const char *, int) __WUR;
int __put_cobj(struct mCAPIobj *, const char *, int);
struct mCAPIobj *__get_next_cobj(struct mCAPIobj *, struct mCAPIobj *, const char *, int) __WUR;
int __delist_cobj(struct mCAPIobj *, const char *, int);
#define get_cobj(co) __get_cobj(co, __FILE__, __LINE__)
#define put_cobj(co) __put_cobj(co, __FILE__, __LINE__)
#define get_next_cobj(pa, co) __get_next_cobj(pa, co, __FILE__, __LINE__)
#define delist_cobj(co) __delist_cobj(co, __FILE__, __LINE__)
#else
struct mCAPIobj *get_cobj(struct mCAPIobj *) __WUR;
int put_cobj(struct mCAPIobj *);
struct mCAPIobj *get_next_cobj(struct mCAPIobj *, struct mCAPIobj *) __WUR;
int delist_cobj(struct mCAPIobj *);
#endif
void dump_cobjects(void);
void CAPIobj_init(void);
void CAPIobj_exit(void);
void free_capiobject(struct mCAPIobj *, void *);
#ifdef MISDN_CAPIOBJ_NO_FREE
void dump_cobjects_free(void);
#endif
int init_cobj(struct mCAPIobj *, struct mCAPIobj *, enum eCAPIobjtype, unsigned int, unsigned int);
int init_cobj_registered(struct mCAPIobj *, struct mCAPIobj *, enum eCAPIobjtype cot, unsigned int);
const char *CAPIobjt2str(struct mCAPIobj *);
const char *CAPIobjIDstr(struct mCAPIobj *);
struct BInstance {
int nr;
int usecnt;
int proto;
int fd;
int tty;
int tty_received;
int rx_min;
int rx_max;
int org_rx_min;
int org_rx_max;
enum BType type;
uint16_t DownId; /* Ids for send down messages */
uint16_t UpId; /* Ids for send up messages */
struct pController *pc;
struct lPLCI *lp;
void *b3data;
pthread_mutex_t lock;
BDataTrans_t *from_down;
BDataTrans_t *from_up;
pthread_t thread;
pid_t tid;
struct pollfd pfd[4];
int pcnt;
int timeout;
int cpipe[2];
sem_t wait;
unsigned int running:1;
unsigned int waiting:1;
unsigned int release_pending:1;
unsigned int got_timeout:1;
unsigned int closing:1;
unsigned int detached:1;
unsigned int joined:1;
unsigned int closed:1;
};
#define DEFAULT_FAX_PKT_SIZE 512
int OpenBInstance(struct BInstance *, struct lPLCI *);
int CloseBInstance(struct BInstance *);
int ReleaseBchannel(struct BInstance *);
int activate_bchannel(struct BInstance *);
struct capi_profile {
uint16_t ncontroller; /* number of installed controller */
uint16_t nbchannel; /* number of B-Channels */
uint32_t goptions; /* global options */
uint32_t support1; /* B1 protocols support */
uint32_t support2; /* B2 protocols support */
uint32_t support3; /* B3 protocols support */
uint32_t reserved[6]; /* reserved */
uint32_t manu[5]; /* manufacturer specific information */
};
/* physical controller access */
struct pController {
struct mCAPIobj cobjLC;
struct mCAPIobj cobjPLCI;
int mNr;
int enable;
struct mISDN_devinfo devinfo;
struct capi_profile profile;
uint32_t L3Proto;
uint32_t L3Flags;
struct mlayer3 *l3;
uint32_t lastPLCI; /* used only in unique PLCI debugmode */
int appCnt;
int BImax; /* Nr of BInstances */
struct BInstance *BInstances; /* Array of BInstances [0 ... BImax - 1] */
pthread_rwlock_t Block;
uint32_t InfoMask; /* Listen info mask all active applications */
uint32_t CIPmask; /* Listen CIP mask all active applications */
uint32_t CIPmask2; /* Listen CIP mask 2 all active applications */
};
struct pController *get_mController(int);
struct pController *get_cController(int);
struct BInstance *ControllerSelChannel(struct pController *, int, int);
int ControllerDeSelChannel(struct BInstance *);
uint32_t NextFreePLCI(struct mCAPIobj *);
int OpenLayer3(struct pController *);
int check_free_bchannels(struct pController *);
void dump_controller_plci(struct pController *);
/* This is a struct for the logical controller per application, also has the listen statemachine */
struct lController {
struct mCAPIobj cobj;
struct mApplication *Appl; /* pointer to the CAPI application */
struct FsmInst listen_m; /* Listen state machine */
uint32_t InfoMask; /* Listen info mask */
uint32_t CIPmask; /* Listen CIP mask */
uint32_t CIPmask2; /* Listen CIP mask 2 */
unsigned int listed;
};
#define p4lController(l) ((l) ? container_of((l)->cobj.parent, struct pController, cobjLC) : NULL)
/* listen.c */
struct lController *get_lController(struct mApplication *, unsigned int);
void init_listen(void);
void free_listen(void);
struct lController *addlController(struct mApplication *, struct pController *, int);
void cleanup_lController(struct lController *);
void Free_lController(struct mCAPIobj *);
int listenRequest(struct lController *, struct mc_buf *);
void dump_lControllers(struct pController *);
void dump_lcontroller(struct lController *);
struct mApplication {
struct mCAPIobj cobj;
int fd; /* Filedescriptor for CAPI messages */
uint16_t MsgId; /* next message number */
int MaxB3Con;
int MaxB3Blk;
int MaxB3Size;
struct lController **lcl;
uint32_t UserFlags;
int cpipe[2];
unsigned int unregistered:1;
};
int mApplication_init(void);
struct mApplication *RegisterApplication(uint16_t, uint32_t, uint32_t, uint32_t);
void ReleaseApplication(struct mApplication *, int);
void Free_Application(struct mCAPIobj *);
int ReleaseAllApplications(void);
int register_lController(struct mApplication *, struct lController *);
void delisten_application(struct lController *);
int PutMessageApplication(struct mApplication *, struct mc_buf *);
void SendMessage2Application(struct mApplication *, struct mc_buf *);
void SendCmsg2Application(struct mApplication *, struct mc_buf *);
void SendCmsgAnswer2Application(struct mApplication *, struct mc_buf *, uint16_t);
int ListenController(struct pController *);
void Put_Application_cleaned(struct mCAPIobj *);
void dump_applications(void);
struct mPLCI {
struct mCAPIobj cobj;
struct pController *pc;
unsigned int alerting:1;
unsigned int outgoing:1;
int cause;
int cause_loc;
};
/* PLCI state flags */
struct mPLCI *new_mPLCI(struct pController *, unsigned int);
void plciDetachlPLCI(struct lPLCI *);
void Free_PLCI(struct mCAPIobj *);
unsigned int plci_new_pid(struct mPLCI *);
struct mPLCI *getPLCI4Id(struct pController *, uint32_t);
struct lPLCI *get_lPLCI4Id(struct mPLCI *, uint16_t);
struct mPLCI *getPLCI4pid(struct pController *, int);
int mPLCISendMessage(struct lController *, struct mc_buf *);
int plciL4L3(struct mPLCI *, int, struct l3_msg *);
int plci_l3l4(struct mPLCI *, int, struct l3_msg *);
void release_lController(struct lController *);
struct lPLCI {
struct mCAPIobj cobj;
int pid; /* L3 pid */
struct lController *lc;
struct mApplication *Appl;
struct FsmInst plci_m;
int proto;
enum BType btype;
struct BInstance *BIlink;
struct mtimer atimer;
int cause;
int cause_loc;
struct misdn_channel_info chid;
struct Bprotocol Bprotocol;
uint32_t cipmask;
unsigned int l1dtmf:1;
unsigned int autohangup:1;
unsigned int disc_req:1;
unsigned int rel_req:1;
unsigned int ignored:1;
unsigned int req_relcomplete:1;
};
#define p4lPLCI(l) ((l) ? container_of(((struct lPLCI *)(l))->cobj.parent, struct mPLCI, cobj) : NULL)
#define pc4lPLCI(l) ((struct mPLCI *)p4lPLCI(l))->pc
void init_lPLCI_fsm(void);
void free_lPLCI_fsm(void);
int lPLCICreate(struct lPLCI **, struct lController *, struct mPLCI *, uint32_t);
void cleanup_lPLCI(struct lPLCI *);
void Free_lPLCI(struct mCAPIobj *);
void lPLCIRelease(struct lPLCI *);
void lPLCI_l3l4(struct lPLCI *, int, struct mc_buf *);
uint16_t lPLCISendMessage(struct lPLCI *, struct mc_buf *);
uint32_t q931CIPMask(struct mc_buf *);
uint16_t CIPMask2CIPValue(uint32_t);
void lPLCIDelNCCI(struct mNCCI *);
struct mNCCI *ConnectB3Request(struct lPLCI *, struct mc_buf *);
void B3ReleaseLink(struct lPLCI *, struct BInstance *);
struct lPLCI *get_lPLCI4plci(struct mApplication *, uint32_t);
void dump_Lplcis(struct lPLCI *);
struct _ConfQueue {
uint32_t PktId;
uint16_t DataHandle;
uint16_t MsgId;
uint16_t dlen;
uint16_t sent;
struct mc_buf *pkt;
unsigned char *sp;
};
#define CAPI_MAXDATAWINDOW 8
enum _flowmode {
flmNone = 0,
flmPHDATA = 1,
flmIndication = 2,
};
struct mNCCI {
struct mCAPIobj cobj;
struct mApplication *appl;
struct BInstance *BIlink;
int window;
struct FsmInst ncci_m;
pthread_mutex_t lock;
struct _ConfQueue xmit_handles[CAPI_MAXDATAWINDOW];
uint32_t recv_handles[CAPI_MAXDATAWINDOW];
enum _flowmode flowmode;
_cbyte *ncpi;
uint16_t Reason_B3;
uint16_t isize;
uint16_t osize;
uint16_t iidx;
uint16_t oidx;
int ridx;
struct msghdr down_msg;
struct iovec down_iv[3];
struct mISDNhead down_header;
struct msghdr up_msg;
struct iovec up_iv[2];
unsigned char up_header[30];
unsigned int dtmflisten:1;
unsigned int l1direct:1;
unsigned int l1trans:1;
unsigned int l2trans:1;
unsigned int l3trans:1;
unsigned int dlbusy:1;
};
#define lPLCI4NCCI(n) ((n) ? container_of(((struct mNCCI *)(n))->cobj.parent, struct lPLCI, cobj) : NULL)
void init_ncci_fsm(void);
void free_ncci_fsm(void);
struct mNCCI *ncciCreate(struct lPLCI *);
void Free_NCCI(struct mCAPIobj *);
int recvBdirect(struct BInstance *, struct mc_buf *);
int ncciB3Data(struct BInstance *, struct mc_buf *);
void ncciReleaseLink(struct mNCCI *);
void cleanup_ncci(struct mNCCI *);
int ncciL4L3(struct mNCCI *, uint32_t, int, int, void *, struct mc_buf *);
void dump_ncci(struct lPLCI *);
#ifdef USE_SOFTFAX
int FaxRecvBData(struct BInstance *, struct mc_buf *);
int FaxB3Message(struct BInstance *, struct mc_buf *);
void FaxReleaseLink(struct BInstance *);
void Free_Faxobject(struct mCAPIobj *);
void dump_fax_status(struct BInstance *);
#else
static inline void Free_Faxobject(struct mCAPIobj *co) {};
static inline void dump_fax_status(struct BInstance *bi) {};
#endif
#define MC_BUF_ALLOC(a) if (!(a = alloc_mc_buf())) {eprint("Cannot allocate mc_buff\n");return;}
#define CMSGCMD(cm) CAPICMD((cm)->Command, (cm)->Subcommand)
/* Debug MASK */
#define MC_DEBUG_POLL 0x01
#define MC_DEBUG_CONTROLLER 0x02
#define MC_DEBUG_CAPIMSG 0x04
#define MC_DEBUG_STATES 0x08
#define MC_DEBUG_PLCI 0x10
#define MC_DEBUG_NCCI 0x20
#define MC_DEBUG_NCCI_DATA 0x40
#define MC_DEBUG_CAPIOBJ 0x80
#define MIDEBUG_POLL (MC_DEBUG_POLL << 24)
#define MIDEBUG_CONTROLLER (MC_DEBUG_CONTROLLER << 24)
#define MIDEBUG_CAPIMSG (MC_DEBUG_CAPIMSG << 24)
#define MIDEBUG_STATES (MC_DEBUG_STATES << 24)
#define MIDEBUG_PLCI (MC_DEBUG_PLCI << 24)
#define MIDEBUG_NCCI (MC_DEBUG_NCCI << 24)
#define MIDEBUG_NCCI_DATA (MC_DEBUG_NCCI_DATA << 24)
#define MIDEBUG_CAPIOBJ (MC_DEBUG_CAPIOBJ << 24)
#define MI_PUT_APPLICATION 0x42000000
int mIcapi_mainpoll_releaseApp(int, int);
void mCapi_cmsg2str(struct mc_buf *);
void mCapi_message2str(struct mc_buf *);
/* missing capi errors */
#define CapiMessageNotSupportedInCurrentState 0x2001
#define CapiIllController 0x2002
#define CapiNoPLCIAvailable 0x2003
#define CapiNoNCCIAvailable 0x2004
#define CapiIllMessageParmCoding 0x2007
#define CapiB1ProtocolNotSupported 0x3001
#define CapiB2ProtocolNotSupported 0x3002
#define CapiB3ProtocolNotSupported 0x3003
#define CapiB1ProtocolParameterNotSupported 0x3004
#define CapiB2ProtocolParameterNotSupported 0x3005
#define CapiB3ProtocolParameterNotSupported 0x3006
#define CapiProtocolCombinationNotSupported 0x3007
#define CapiNCPINotSupported 0x3008
#define CapiProtocolErrorLayer1 0x3301
#define CapiProtocolErrorLayer2 0x3302
#define CapiProtocolErrorLayer3 0x3303
#define CapiConnectionNoSuccess_noG3 0x3311
#define CapiConnectionNoSuccess_TrainingErr 0x3312
#define CapiDisconnectBeforeTrans_Unsuppoted 0x3313
#define CapiDisconnectDuringTrans_RemoteAbort 0x3314
#define CapiDisconnectDuringTrans_ProcedureErr 0x3315
#define CapiDisconnectDuringTrans_TXunderflow 0x3316
#define CapiDisconnectDuringTrans_RXoverflow 0x3317
#define CapiDisconnectDuringTrans_LocalAbort 0x3318
#define CapiIllegalParameterCoding 0x3319
/* internal used errors */
#define CapiBchannelNotAvailable 0x3f01
#define FAX_B3_FORMAT_SFF 0
#define FAX_B3_FORMAT_PLAIN 1
#define FAX_B3_FORMAT_PCX 2
#define FAX_B3_FORMAT_DCX 3
#define FAX_B3_FORMAT_TIFF 4
#define FAX_B3_FORMAT_ASCII 5
#define FAX_B3_FORMAT_EXT_ANSI 6
#define FAX_B3_FORMAT_BINARY 7
/* Info mask bits */
#define CAPI_INFOMASK_CAUSE 0x0001
#define CAPI_INFOMASK_DATETIME 0x0002
#define CAPI_INFOMASK_DISPLAY 0x0004
#define CAPI_INFOMASK_USERUSER 0x0008
#define CAPI_INFOMASK_PROGRESS 0x0010
#define CAPI_INFOMASK_FACILITY 0x0020
#define CAPI_INFOMASK_CHARGE 0x0040
#define CAPI_INFOMASK_CALLEDPN 0x0080
#define CAPI_INFOMASK_CHANNELID 0x0100
#define CAPI_INFOMASK_EARLYB3 0x0200
#define CAPI_INFOMASK_REDIRECT 0x0400
#define CAPI_INFOMASK_COMPLETE 0x1000
#define CAPIMSG_REQ_DATAHANDLE(m) (m[18] | (m[19]<<8))
#define CAPIMSG_RESP_DATAHANDLE(m) (m[12] | (m[13]<<8))
#define CAPIMSG_REQ_FLAGS(m) (m[20] | (m[21]<<8))
#define CAPI_B3_DATA_IND_HEADER_SIZE ((4 == sizeof(void *)) ? 22 : 30)
#define CAPIFLAG_HIGHJACKING 1
#define CAPI_DATA_TTY 0xe0
/* some helper */
static inline int capiEncodeWord(unsigned char *p, uint16_t i)
{
*p++ = i;
*p++ = i >> 8;
return 2;
}
static inline int capiEncodeDWord(unsigned char *p, uint32_t i)
{
*p++ = i;
*p++ = i >> 8;
*p++ = i >> 16;
*p++ = i >> 24;
return 4;
}
int capiEncodeFacIndSuspend(unsigned char *, uint16_t);
#endif

View File

@ -1,50 +0,0 @@
/*
* m_capi_sock.h
*
* Author Karsten Keil <kkeil@linux-pingi.de>
*
* Copyright 2011,2016 by Karsten Keil <kkeil@linux-pingi.de>
*
* This code is free software; you can redistribute it and/or modify
* it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE
* version 2.1 as published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU LESSER GENERAL PUBLIC LICENSE for more details.
*
*/
#ifndef _M_CAPI_SOCK_H
#define _M_CAPI_SOCK_H
#include <capiutils.h>
#ifdef __cplusplus
extern "C" {
#endif
#define MISDN_CAPI_SOCKET_NAME "@MISDN_CAPI_SOCKET_NAME@"
#define MISDN_CAPI_SOCKET_DIR "@MISDN_CAPI_SOCKET_DIR@"
#define MIC_INFO_CODING_ERROR 1
/* mISDN CAPI commands */
#define MIC_GET_PROFILE_REQ CAPICMD(0xf0, 0xff)
#define MIC_REGISTER_REQ CAPICMD(0xf1, 0xff)
#define MIC_RELEASE_REQ CAPICMD(0xf2, 0xff)
#define MIC_SERIAL_NUMBER_REQ CAPICMD(0xf3, 0xff)
#define MIC_VERSION_REQ CAPICMD(0xf4, 0xff)
#define MIC_GET_MANUFACTURER_REQ CAPICMD(0xf5, 0xff)
#define MIC_MANUFACTURER_REQ CAPICMD(0xf6, 0xff)
#define MIC_USERFLAG_REQ CAPICMD(0xf7, 0xff)
#define MIC_TTYNAME_REQ CAPICMD(0xf8, 0xff)
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,221 +0,0 @@
/*
* mc_buffer.c
*
* Author Karsten Keil <kkeil@linux-pingi.de>
*
* Copyright 2011 by Karsten Keil <kkeil@linux-pingi.de>
*
* This code is free software; you can redistribute it and/or modify
* it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE
* version 2.1 as published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU LESSER GENERAL PUBLIC LICENSE for more details.
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "mc_buffer.h"
#ifdef MI_MCBUFFER_DEBUG
#include "m_capi.h"
#define MI_MCBUFFER_DEBUG_BACKLOG 100 /* number of buffers before reuse */
static pthread_mutex_t mcb_lock;
static struct mc_buf *mcb_lost_start = NULL;
static struct mc_buf *mcb_lost_last = NULL;
static struct mc_buf *mcb_free_start = NULL;
static struct mc_buf *mcb_free_last = NULL;
static int mcb_alloc_count = 0;
static int mcb_free_count = 0;
static int *crash = NULL;
void mc_buffer_init(void)
{
pthread_mutex_init(&mcb_lock, NULL);
iprint("Setup mc buffer MI_MCBUFFER_DEBUG\n");
}
void mc_buffer_cleanup(void)
{
struct mc_buf *mc;
const char *deb;
struct mISDNhead *hh;
iprint("Clean up mc buffers %d (min backlog %d) buffers alloc %d lost %d\n",
mcb_free_count, MI_MCBUFFER_DEBUG_BACKLOG, mcb_alloc_count,
mcb_alloc_count - mcb_free_count);
pthread_mutex_lock(&mcb_lock);
mI_debug_mask |= MIDEBUG_CAPIMSG;
while (mcb_lost_start) {
mc = mcb_lost_start;
mcb_lost_start = mc->next;
eprint("Buffer %p state %x len:%d refcnt:%d allocated at %s:%d not freed\n",
mc, mc->state, mc->len, mc->refcnt, mc->filename, mc->line);
hh = (struct mISDNhead *)mc->rb;
deb = mi_msg_type2str(hh->prim);
if (deb)
eprint("Buffer: prim %s (%x) pid = %x\n", deb, hh->prim, hh->id);
if (mc->cmsg.Command != 0) /* it may crash if Command is undefined */
mCapi_cmsg2str(mc);
if (mc->l3m) {
deb = mi_msg_type2str(mc->l3m->type);
eprint("l3m: prim %s pid: %x\n", deb, mc->l3m->pid);
free_l3_msg(mc->l3m);
}
free(mc);
mcb_alloc_count--;
}
while (mcb_free_start) {
mc = mcb_free_start;
mcb_free_start = mc->next;
free(mc);
mcb_free_count--;
}
mcb_free_last = NULL;
pthread_mutex_unlock(&mcb_lock);
iprint("Clean up mc buffers finished count %d\n", mcb_free_count);
}
void mc_buffer_dump_status(void)
{
iprint("mc buffer status: %d (min backlog %d) buffers allocated %d free %d in use\n",
mcb_alloc_count, MI_MCBUFFER_DEBUG_BACKLOG, mcb_free_count, mcb_alloc_count - mcb_free_count);
}
struct mc_buf *__alloc_mc_buf(const char *file, int lineno, const char *func)
{
struct mc_buf *mc;
pthread_mutex_lock(&mcb_lock);
if (mcb_free_count > MI_MCBUFFER_DEBUG_BACKLOG) {
mc = mcb_free_start;
mcb_free_start = mc->next;
mcb_free_count--;
memset(mc, 0, sizeof(*mc));
mc->state = MSt_reused;
} else {
#ifdef MEMLEAK_DEBUG
mc = __mi_calloc(1, sizeof(struct mc_buf), __FILE__, __LINE__, __PRETTY_FUNCTION__);
#else
mc = calloc(1, sizeof(struct mc_buf));
#endif
mc->state = MSt_fresh;
mcb_alloc_count++;
}
strncpy(mc->filename, file, 79);
mc->line = lineno;
if (mcb_lost_last)
mcb_lost_last->next = mc;
mc->prev = mcb_lost_last;
mc->next = NULL;
mcb_lost_last = mc;
if (!mcb_lost_start)
mcb_lost_start = mc;
pthread_mutex_unlock(&mcb_lock);
return mc;
}
void __free_mc_buf(struct mc_buf *mc, const char *file, int lineno, const char *func)
{
/* Best we can do on free error is crash (dump core) to analyse via debugger */
if (!mc)
*crash = 99; /* crash NULL msg*/
else if (mc->state == MSt_free)
*crash = 100; /* crash double free */
else if (mc->state == Mst_NoAlloc)
*crash = 101; /* crash not allocated buffer */
else if (mc->refcnt < 0)
*crash = 102; /* crash negative refcnt */
if (mc->refcnt) {
iprint("buffer %p refcnt %d not freed at %s:%d\n", mc, mc->refcnt, file, lineno);
mc->refcnt--;
return;
}
if (mc->l3m) {
#ifdef MEMLEAK_DEBUG
__free_l3_msg(mc->l3m, file, lineno, func);
#else
free_l3_msg(mc->l3m);
#endif
mc->l3m = NULL;
}
strncpy(mc->filename, file, 79);
mc->line = lineno;
mc->state = MSt_free;
pthread_mutex_lock(&mcb_lock);
if (mc->prev)
mc->prev->next = mc->next;
if (mc->next)
mc->next->prev = mc->prev;
if (mcb_lost_last == mc)
mcb_lost_last = mc->prev;
if (mcb_lost_start == mc)
mcb_lost_start = mc->next;
if (mcb_free_last)
mcb_free_last->next = mc;
mc->prev = mcb_free_last;
mc->next = NULL;
mcb_free_last = mc;
if (!mcb_free_start)
mcb_free_start = mc;
mcb_free_count++;
pthread_mutex_unlock(&mcb_lock);
}
#else
void mc_buffer_init(void)
{
}
void mc_buffer_cleanup(void)
{
}
void mc_buffer_dump_status(void)
{
}
#ifdef MEMLEAK_DEBUG
/*
* free the message
*/
void __free_mc_buf(struct mc_buf *mc, const char *file, int lineno, const char *func)
{
if (mc->refcnt) {
mc->refcnt--;
return;
}
if (mc->l3m)
__free_l3_msg(mc->l3m, file, lineno, func);
__mi_free(mc, file, lineno, func);
}
#else
/*
* free the message
*/
void free_mc_buf(struct mc_buf *mc)
{
if (mc->refcnt) {
mc->refcnt--;
return;
}
if (mc->l3m)
free_l3_msg(mc->l3m);
free(mc);
}
#endif
#endif
void mc_clear_cmsg(struct mc_buf *mc)
{
memset(&mc->cmsg, 0, sizeof(mc->cmsg));
}

View File

@ -1,105 +0,0 @@
/*
* mc_buffer.h
*
* Author Karsten Keil <kkeil@linux-pingi.de>
*
* Copyright 2011 by Karsten Keil <kkeil@linux-pingi.de>
*
* This code is free software; you can redistribute it and/or modify
* it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE
* version 2.1 as published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU LESSER GENERAL PUBLIC LICENSE for more details.
*
*/
#ifndef _MC_BUFFER_H
#define _MC_BUFFER_H
#define MI_MCBUFFER_DEBUG 1
#ifdef __cplusplus
extern "C" {
#endif
#include <mISDN/mbuffer.h>
#include <capiutils.h>
#define MC_RB_SIZE 2112
#ifdef MI_MCBUFFER_DEBUG
enum mstate {
Mst_NoAlloc = 0,
MSt_fresh = 0x5555aaaa,
MSt_free = 0x42424242,
MSt_reused = 0x55aa55aa
};
#endif
struct mc_buf {
struct l3_msg *l3m;
_cmsg cmsg;
int refcnt;
int len;
unsigned char rb[MC_RB_SIZE];
unsigned char *rp;
#ifdef MI_MCBUFFER_DEBUG
enum mstate state;
char filename[80];
int line;
struct mc_buf *next;
struct mc_buf *prev;
#endif
};
extern void mc_buffer_init(void);
extern void mc_buffer_cleanup(void);
extern void mc_buffer_dump_status(void);
#ifdef MI_MCBUFFER_DEBUG
extern void __free_mc_buf(struct mc_buf *, const char *file, int lineno, const char *func);
#define free_mc_buf(p) __free_mc_buf(p, __FILE__, __LINE__, __PRETTY_FUNCTION__)
extern struct mc_buf *__alloc_mc_buf(const char *file, int lineno, const char *func);
#define alloc_mc_buf() __alloc_mc_buf( __FILE__, __LINE__, __PRETTY_FUNCTION__)
#else
#ifdef MEMLEAK_DEBUG
/*
* alloc a new mbuffer
*/
#define alloc_mc_buf() __mi_calloc(1, sizeof(struct mc_buf), __FILE__, __LINE__, __PRETTY_FUNCTION__)
/*
* free the message
*/
extern void __free_mc_buf(struct mc_buf *, const char *file, int lineno, const char *func);
#define free_mc_buf(p) __free_mc_buf(p, __FILE__, __LINE__, __PRETTY_FUNCTION__)
#else
/*
* alloc a new mbuffer
*/
#define alloc_mc_buf() calloc(1, sizeof(struct mc_buf))
/*
* free the message
*/
extern void free_mc_buf(struct mc_buf *);
#endif
#endif
#define mcbuf_rb2cmsg(m) capi_message2cmsg(&(m)->cmsg, (m)->rb)
extern void mc_clear_cmsg(struct mc_buf *);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,11 +0,0 @@
lib_capi_mod_misdn_la_SOURCES = capi_mod_misdn.c
lib_capi_mod_misdn_la_CFLAGS = -fno-strict-aliasing -Wall -DHAVE_OLDCAPIMOD=@HAVE_OLDCAPIMOD@
lib_capi_mod_misdn_la_LDFLAGS = -shared -version-info @CAPI_MODULE_LOADER_VERSION@:0:0
modulesdir = $(libdir)/capi
modules_LTLIBRARIES = lib_capi_mod_misdn.la
AM_CPPFLAGS = -I$(top_srcdir)/include -Wall -Werror
CLEANFILES = *~

View File

@ -1,562 +0,0 @@
/*
* capi_mod_misdn.c
*
* Author Karsten Keil <kkeil@linux-pingi.de>
*
* Copyright 2011 by Karsten Keil <kkeil@linux-pingi.de>
*
* This code is free software; you can redistribute it and/or modify
* it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE
* version 2.1 as published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU LESSER GENERAL PUBLIC LICENSE for more details.
*
*/
/**
* \file capi_mod_misdn.c
* CAPI 2.0 module for mISDN
*/
#include <sys/socket.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <linux/capi.h>
#include <errno.h>
#include <unistd.h>
#include <sys/un.h>
#include <poll.h>
#include <capi20.h>
#include <capi_mod.h>
#include <capiutils.h>
#include "../m_capi_sock.h"
#ifdef MISDND_CAPI_MODULE_DEBUG
static FILE *mIm_debug = NULL;
static char mIm_debug_file[128];
#define mId_print(fmt, ...) do { \
if (mIm_debug) { \
fprintf(mIm_debug, fmt, ##__VA_ARGS__); \
fflush(mIm_debug); \
} \
} while(0)
#else
#define mId_print(fmt, ...) do {} while(0)
#endif
/**
* \brief Create a socket to mISDNcapid
* \return socket number
*/
static int misdnOpenSocket(void)
{
struct sockaddr_un mcaddr;
int nHandle;
/* Create new socket */
nHandle = socket(AF_UNIX, SOCK_SEQPACKET, 0);
if (nHandle < 0) {
return -1;
}
mcaddr.sun_family = AF_UNIX;
sprintf(mcaddr.sun_path, "%s/%s", MISDN_CAPI_SOCKET_DIR, MISDN_CAPI_SOCKET_NAME);
/* Connect socket to address */
if (!connect(nHandle, (struct sockaddr *)&mcaddr, sizeof(mcaddr))) {
/* no errors, return handle */
return nHandle;
}
close(nHandle);
return -1;
}
/**
* \brief Send message to socket and wait for response
* \param nHandle socket handle
* \param pnBuffer data buffer pointer
* \param nLen number of bytes to write from pnBuffer
* \param nConf current configuration id
* \return number of bytes read
*/
static int misdnRemoteCommand(int nHandle, unsigned char *pnBuffer, int nLen, int nConf)
{
struct pollfd mypoll;
int ret;
/* write message to socket */
ret = send(nHandle, pnBuffer, nLen, 0);
if (ret != nLen)
return -1;
mypoll.fd = nHandle;
mypoll.events = POLLIN | POLLPRI;
/* wait max 1 sec for a answer */
ret = poll(&mypoll, 1, 1000);
if (ret < 1)
return -2;
/* read data */
ret = recv(nHandle, pnBuffer, 1024, 0);
return ret;
}
/**
* \brief Add standard misdn header to buffer pointer
* \param ppnPtr data buffer pointer
* \param nLen length of message
* \param nCmd command id
*/
static void misdnSetHeader(unsigned char *p, _cword nLen, _cword AppId, _cword nCmd, _cword Contr)
{
CAPIMSG_SETLEN(p, nLen);
CAPIMSG_SETAPPID(p, AppId);
capimsg_setu8(p, 4, nCmd >> 8);
capimsg_setu8(p, 5, nCmd & 0xff);
capimsg_setu16(p, 8, Contr);
}
#if 0
/**
* \brief Debug purpose, write capi data to file
* \param nSend send
* \param pnBuffer data buffer
* \param nLength length of buffer
* \param nDataMsg data message len
*/
static void misdnWriteCapiTrace(int nSend, unsigned char *pnBuffer, int nLength, int nDataMsg)
{
int nHandle;
_cdword nTime;
unsigned char anHeader[7];
char *pnTraceFile = getTraceFile();
if (strlen(pnTraceFile) <= 0) {
return;
}
if (getTraceLevel() < (nDataMsg + 1)) {
return;
}
nHandle = open(pnTraceFile, O_WRONLY | O_CREAT | O_APPEND, 0644);
if (nHandle >= 0) {
nTime = (_cdword) time(NULL);
capimsg_setu16(anHeader, 0, nLength + sizeof(anHeader));
capimsg_setu32(anHeader, 2, nTime);
anHeader[6] = (nSend) ? 0x80 : 0x81;
close(nHandle);
}
}
#endif
#if HAVE_OLDCAPIMOD
#define ISINSTALLTYPE unsigned
#else
#define ISINSTALLTYPE int
#endif
/**
* \brief Check if misdn interface is available
* \return file descriptor of socket, or error code
*/
static ISINSTALLTYPE misdnIsInstalled(void)
{
ISINSTALLTYPE nHandle;
nHandle = misdnOpenSocket();
#ifdef MISDND_CAPI_MODULE_DEBUG
if (nHandle >= 0 && !mIm_debug) {
int pid;
pid = getpid();
sprintf(mIm_debug_file, "/tmp/mIm_debug_%05d.log", pid);
mIm_debug = fopen(mIm_debug_file, "wt");
}
#endif
return nHandle;
}
/**
* \brief Register at misdn
* \param nMaxB3Connection maximum b3 connection
* \param nMaxB3Blks maximum b3 blocks
* \param nMaxSizeB3 maximum b3 size
* \param pnApplId pointer where we store the new application id
* \return new socket handle
*/
static unsigned misdnRegister(unsigned nMaxB3Connection, unsigned nMaxB3Blks, unsigned nMaxSizeB3, unsigned *pnApplId)
{
unsigned char anBuf[100];
int nSock, ret;
uint16_t ApplId;
*pnApplId = -1;
/* open a new socket for communication */
nSock = misdnOpenSocket();
if (nSock < 0)
return nSock;
ApplId = capi_alloc_applid(nSock);
misdnSetHeader(anBuf, 20, ApplId, MIC_REGISTER_REQ, 0);
capimsg_setu32(anBuf, 8, nMaxB3Connection);
capimsg_setu32(anBuf, 12, nMaxB3Blks);
capimsg_setu32(anBuf, 16, nMaxSizeB3);
/* Send message to socket and wait for answer */
ret = misdnRemoteCommand(nSock, anBuf, 20, MIC_REGISTER_REQ);
if (ret != 10) {
close(nSock);
return -2;
}
ret = CAPIMSG_U16(anBuf, 8);
if (ret == CapiNoError) {
/* No error set it to pnApplId */
*pnApplId = ApplId;
mId_print("%s: fd=%d ApplId=%d\n", __func__, nSock, ApplId);
} else {
/* error occured, close socket give back ApplId and return -1 */
capi_freeapplid(ApplId);
close(nSock);
nSock = -1;
}
return nSock;
}
/**
* \brief Put capi message to misdn
* \param nSock socket handle
* \param nApplId application id
* \param pnMsg message pointer
* \return error code
*/
static unsigned misdnPutMessage(int nSock, unsigned nApplId, unsigned char *pnMsg)
{
int nLen = CAPIMSG_LEN(pnMsg);
int nCommand = CAPIMSG_COMMAND(pnMsg);
int nSubCommand = CAPIMSG_SUBCOMMAND(pnMsg);
int ret = -1, tot = 0, dlen = 0;
#ifdef MISDND_CAPI_MODULE_DEBUG
uint8_t d = 0;
#endif
uint16_t dh;
void *dp = NULL;
struct msghdr msg;
struct iovec iv[2];
if (nCommand == CAPI_DATA_B3) {
if (nSubCommand == CAPI_REQ) {
dlen = CAPIMSG_DATALEN(pnMsg);
if (sizeof(dp) == 4)
dp = (void *)((unsigned long)CAPIMSG_U32(pnMsg, 12));
else
dp = (void *)((unsigned long)CAPIMSG_U64(pnMsg, 22));
#ifdef MISDND_CAPI_MODULE_DEBUG
d = *((unsigned char *)dp);
#endif
iv[0].iov_base = pnMsg;
iv[0].iov_len = nLen;
iv[1].iov_base = dp;
iv[1].iov_len = dlen;
tot = dlen + nLen;
memset(&msg, 0, sizeof(msg));
msg.msg_iov = iv;
msg.msg_iovlen = 2;
ret = sendmsg(nSock, &msg, 0);
} else if (CAPI_RESP) {
dh = CAPIMSG_U16(pnMsg, 12);
dh = capi_return_buffer(nApplId, dh);
capimsg_setu16(pnMsg, 12, dh);
ret = send(nSock, pnMsg, nLen, 0);
tot = nLen;
}
} else {
ret = send(nSock, pnMsg, nLen, 0);
tot = nLen;
}
mId_print("%s: %s fd=%d len=%d dp=%p dlen=%d tot=%d d=%02x ret=%d (%d - %s)\n", __func__, capi20_cmd2str(nCommand, nSubCommand),
nSock, nLen, dp, dlen, tot, d, ret, errno, strerror(errno));
if (tot != ret) {
ret = CapiMsgOSResourceErr;
} else
ret = CapiNoError;
return ret;
}
/**
* \brief Get message from misdn
* \param nSock socket handle
* \param nApplId application id
* \param ppnBuffer pointer to data buffer pointer (where we store the data)
* \return error code
*/
static unsigned misdnGetMessage(int nSock, unsigned nApplId, unsigned char **ppnBuffer)
{
unsigned char *pnBuffer;
unsigned nOffset;
size_t nBufSize;
int nRet;
uint16_t ml;
unsigned long nData;
/* try to get a new buffer from queue */
if ((*ppnBuffer = pnBuffer = (unsigned char *)capi_get_buffer(nApplId, &nBufSize, &nOffset)) == 0) {
mId_print("%s: no pnBuffer\n", __func__);
return CapiMsgOSResourceErr;
}
/* Get message */
nRet = recv(nSock, pnBuffer, nBufSize, MSG_DONTWAIT);
if (nRet > 0) {
/* DATA_B3? Then set buffer address */
if ((CAPIMSG_COMMAND(pnBuffer) == CAPI_DATA_B3) && (CAPIMSG_SUBCOMMAND(pnBuffer) == CAPI_IND)) {
capi_save_datahandle(nApplId, nOffset, CAPIMSG_U16(pnBuffer, 18), CAPIMSG_U32(pnBuffer, 8));
/* patch datahandle */
capimsg_setu16(pnBuffer, 18, nOffset);
ml = CAPIMSG_LEN(pnBuffer);
nData = (unsigned long) pnBuffer + ml;
if (sizeof(void *) == 4) {
pnBuffer[12] = nData & 0xFF;
pnBuffer[13] = (nData >> 8) & 0xFF;
pnBuffer[14] = (nData >> 16) & 0xFF;
pnBuffer[15] = (nData >> 24) & 0xFF;
ml = 22;
} else {
capimsg_setu32(pnBuffer, 12, 0);
capimsg_setu64(pnBuffer, 22, nData);
ml = 30;
}
CAPIMSG_SETLEN(pnBuffer, ml);
/* keep buffer */
return CapiNoError;
}
/* buffer is not needed, return it */
capi_return_buffer(nApplId, nOffset);
return CapiNoError;
}
capi_return_buffer(nApplId, nOffset);
if (nRet == 0) {
return CapiReceiveQueueEmpty;
}
switch (errno) {
case EMSGSIZE:
nRet = CapiIllCmdOrSubcmdOrMsgToSmall;
break;
case EAGAIN:
nRet = CapiReceiveQueueEmpty;
break;
default:
nRet = CapiMsgOSResourceErr;
break;
}
return nRet;
}
/**
* \brief Get manufactor informations
* \param nHandle socket handle
* \param nController controller id
* \param pnBuffer buffer pointer we write our informations to
* \return pnBuffer
*/
static unsigned char *misdnGetManufactor(int nHandle, unsigned nController, unsigned char *pnBuffer)
{
unsigned char anBuf[100];
int ret;
misdnSetHeader(anBuf, 10, 0, MIC_GET_MANUFACTURER_REQ, nController);
ret = misdnRemoteCommand(nHandle, anBuf, 10, MIC_GET_MANUFACTURER_REQ);
if (ret == 74)
memcpy(pnBuffer, &anBuf[10], 64);
else
memset(pnBuffer, 0, 64);
return pnBuffer;
}
/**
* \brief Get version informations
* \param nHandle socket handle
* \param nController controller id
* \param pnBuffer buffer pointer we write our informations to
* \return pnBuffer
*/
static unsigned char *misdnGetVersion(int nHandle, unsigned nController, unsigned char *pnBuffer)
{
unsigned char anBuf[100];
int ret;
misdnSetHeader(anBuf, 10, 0, MIC_VERSION_REQ, nController);
ret = misdnRemoteCommand(nHandle, anBuf, 10, MIC_VERSION_REQ);
if (ret == 26)
memcpy(pnBuffer, &anBuf[10], 16);
else
memset(pnBuffer, 0, 16);
return pnBuffer;
}
/**
* \brief Get serial number informations
* \param nHandle socket handle
* \param nController controller id
* \param pnBuffer buffer pointer we write our informations to
* \return pnBuffer
*/
static unsigned char *misdnGetSerialNumber(int nHandle, unsigned nController, unsigned char *pnBuffer)
{
unsigned char anBuf[100];
int ret;
misdnSetHeader(anBuf, 10, 0, MIC_SERIAL_NUMBER_REQ, nController);
ret = misdnRemoteCommand(nHandle, anBuf, 10, MIC_SERIAL_NUMBER_REQ);
*pnBuffer = 0;
if (ret == 18)
memcpy(pnBuffer, &anBuf[10], 8);
return pnBuffer;
}
/**
* \brief Get profile from fritzbox
* \param nHandle socket handle
* \param nControllerId controller
* \param pnBuf buffer
* \return error code
*/
static unsigned misdnGetProfile(int nHandle, unsigned nController, unsigned char *pnBuf)
{
unsigned char anBuf[100];
uint16_t err;
int ret;
misdnSetHeader(anBuf, 10, 0, MIC_GET_PROFILE_REQ, nController);
ret = misdnRemoteCommand(nHandle, anBuf, 10, MIC_GET_PROFILE_REQ);
if (ret != 74)
return CapiMsgOSResourceErr;
err = CAPIMSG_U16(anBuf, 8);
if (err == CapiNoError) {
/* Important !!! Only copy 2 bytes if the number of controllers is requested */
if (nController)
memcpy(pnBuf, &anBuf[10], 64);
else
memcpy(pnBuf, &anBuf[10], 2);
}
return err;
}
static int misdnFlagReq(uint16_t ApplId, uint32_t set_f, uint32_t clr_f)
{
unsigned char anBuf[100];
int ret, fd;
fd = capi_applid2fd(ApplId);
if (fd < 0)
return -1;
misdnSetHeader(anBuf, 16, ApplId, MIC_USERFLAG_REQ, 0);
capimsg_setu32(anBuf, 8, set_f);
capimsg_setu32(anBuf, 12, clr_f);
ret = misdnRemoteCommand(fd, anBuf, 16, MIC_USERFLAG_REQ);
if (ret == 12)
ret = CAPIMSG_U32(anBuf, 8);
else
ret = -1;
return ret;
}
static int misdnGetFlags(unsigned nApplId, unsigned *pnFlagsPtr)
{
int ret;
ret = misdnFlagReq(nApplId, 0, 0);
if (ret < 0)
*pnFlagsPtr = 0;
else {
*pnFlagsPtr = ret;
ret = 0;
}
return ret;
}
static int misdnSetFlags(unsigned nApplId, unsigned nFlags)
{
int ret;
ret = misdnFlagReq(nApplId, nFlags, 0);
if (ret >= 0)
ret = 0;
return ret;
}
static int misdnClearFlags(unsigned nApplId, unsigned nFlags)
{
int ret;
ret = misdnFlagReq(nApplId, 0, nFlags);
if (ret >= 0)
ret = 0;
return ret;
}
static char *misdnGetTtyDeviceName(unsigned nApplId,unsigned nNcci, char *pnBuffer, size_t nSize)
{
unsigned char *anBuf;
int ret, fd;
fd = capi_applid2fd(nApplId);
if (fd < 0)
return NULL;
if (nSize > 64)
nSize = 64;
anBuf = malloc(nSize + 12);
if (!anBuf)
return NULL;
misdnSetHeader(anBuf, 16, nApplId, MIC_TTYNAME_REQ, 0);
capimsg_setu32(anBuf, 8, nNcci);
capimsg_setu32(anBuf, 12, nSize & 0xff);
ret = misdnRemoteCommand(fd, anBuf, 16, MIC_TTYNAME_REQ);
if (ret > 8) {
ret = ret - 8;
memcpy(pnBuffer, &anBuf[8], ret);
pnBuffer[ret] = 0;
} else
return NULL;
free(anBuf);
return pnBuffer;
}
/** Module operations structure */
static struct sModuleOperations sRemoteCapi = {
misdnIsInstalled,
misdnRegister,
NULL,
misdnPutMessage,
misdnGetMessage,
misdnGetManufactor,
misdnGetVersion,
misdnGetSerialNumber,
misdnGetProfile,
NULL,
misdnGetFlags,
misdnSetFlags,
misdnClearFlags,
misdnGetTtyDeviceName,
NULL,
NULL
};
MODULE_INIT("misdn", &sRemoteCapi);

View File

@ -1,393 +0,0 @@
/*
* mplci.c
*
* Author Karsten Keil <kkeil@linux-pingi.de>
*
* Copyright 2011 by Karsten Keil <kkeil@linux-pingi.de>
*
* This code is free software; you can redistribute it and/or modify
* it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE
* version 2.1 as published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU LESSER GENERAL PUBLIC LICENSE for more details.
*
*/
#include <sched.h>
#include "m_capi.h"
#include "mc_buffer.h"
#include <mISDN/q931.h>
struct mPLCI *new_mPLCI(struct pController *pc, unsigned int pid)
{
struct mPLCI *plci;
int ret;
plci = calloc(1, sizeof(*plci));
if (!plci) {
eprint("Controller:%x PID:%x no memory for PLCI\n", pc->mNr, pid);
return NULL;
}
ret = init_cobj_registered(&plci->cobj, &pc->cobjPLCI, Cot_PLCI, 0x01ff);
if (ret) {
eprint("Controller:%x PID:%x Error on init - no IDs left\n", pc->mNr, pid);
free(plci);
plci = NULL;
} else {
plci->cobj.id2 = pid;
plci->pc = pc;
}
return plci;
}
void dump_controller_plci(struct pController *pc)
{
struct mCAPIobj *co;
struct mPLCI *plci;
pthread_rwlock_rdlock(&pc->cobjPLCI.lock);
co = pc->cobjPLCI.listhead;
while (co) {
plci = container_of(co, struct mPLCI, cobj);
iprint("%s refcnt:%d number lPLCI:%d %s%s\n", CAPIobjIDstr(co), co->refcnt, co->itemcnt,
plci->alerting ? "alerting " : "", plci->outgoing ? "outgoing" : "incoming");
pthread_rwlock_rdlock(&co->lock);
if (co->listhead)
dump_Lplcis(container_of(co->listhead, struct lPLCI, cobj));
pthread_rwlock_unlock(&co->lock);
co = co->next;
}
pthread_rwlock_unlock(&pc->cobjPLCI.lock);
}
void Free_PLCI(struct mCAPIobj *co)
{
struct mPLCI *plci = container_of(co, struct mPLCI, cobj);
if (!co->cleaned) {
delist_cobj(co);
co->cleaned = 1;
}
plci->pc = NULL;
if (co->parent) {
put_cobj(co->parent);
co->parent = NULL;
}
dprint(MIDEBUG_PLCI, "%s: freeing done\n", CAPIobjIDstr(co));
free_capiobject(co, plci);
}
static void cleanup_mPLCI(struct mPLCI *plci)
{
struct pController *pc = plci->pc;
struct mCAPIobj *co;
struct lPLCI *lp;
plci->cobj.cleaned = 1;
co = get_next_cobj(&plci->cobj, NULL);
while (co) {
lp = container_of(co, struct lPLCI, cobj);
cleanup_lPLCI(lp);
co = get_next_cobj(&plci->cobj, co);
}
if (plci->cobj.itemcnt) {
wprint("%s: lPLCI count %d not zero\n", CAPIobjIDstr(&plci->cobj), plci->cobj.itemcnt);
}
if (pc) {
plci->pc = NULL;
delist_cobj(&plci->cobj);
} else
eprint("%s: no pcontroller assigned\n", CAPIobjIDstr(&plci->cobj));
}
void plciDetachlPLCI(struct lPLCI *lp)
{
struct mPLCI *p;
int mt;
struct l3_msg *l3m;
p = p4lPLCI(lp);
if (!p) {
eprint("%s: detach no PLCI\n", CAPIobjIDstr(&lp->cobj));
return;
}
if (lp->rel_req) {
/* need to store cause for final answer */
if (lp->cause_loc == CAUSE_LOC_USER) {
dprint(MIDEBUG_PLCI, "%s: set final cause plci:#%d lplci:#%d\n",
CAPIobjIDstr(&lp->cobj), p->cause, lp->cause);
if (p->cause <= 0) {
p->cause = lp->cause;
} else if (lp->cause < p->cause) {
/* for now we prefer lower values, maybe need changed */
p->cause = lp->cause;
}
p->cause_loc = CAUSE_LOC_USER;
} else
wprint("%s: cause got owerwritten loc:#%d cause #%d - not stored\n",
CAPIobjIDstr(&lp->cobj), lp->cause_loc, lp->cause);
}
delist_cobj(&lp->cobj);
if (p->cobj.itemcnt == 0) {
if (p->cause > 0) {
dprint(MIDEBUG_PLCI, "%s: last lPLCI gone clear call cause #%d\n",
CAPIobjIDstr(&p->cobj), p->cause);
l3m = alloc_l3_msg();
if (!l3m) {
eprint("%s: disconnect not send no l3m\n", CAPIobjIDstr(&p->cobj));
} else {
if (p->alerting)
mt = MT_DISCONNECT;
else
mt = MT_RELEASE_COMPLETE;
mi_encode_cause(l3m, p->cause, p->cause_loc, 0, NULL);
plciL4L3(p, mt, l3m);
}
}
dprint(MIDEBUG_PLCI, "%s: All lPLCIs are gone remove PLCI now\n", CAPIobjIDstr(&p->cobj));
cleanup_mPLCI(p);
}
}
static void plciHandleSetupInd(struct mPLCI *plci, int pr, struct mc_buf *mc)
{
uint32_t CIPmask, cipm;
struct pController *pc;
struct mCAPIobj *co;
struct lController *lc;
struct lPLCI *lp;
uint8_t found = 0;
int cause = CAUSE_INCOMPATIBLE_DEST;
int ret, *fds, *cur;
if (!mc || !mc->l3m) {
eprint("%s: SETUP without message\n", CAPIobjIDstr(&plci->cobj));
return;
}
CIPmask = q931CIPMask(mc);
pc = plci->pc;
dprint(MIDEBUG_PLCI, "%s: check CIPMask(%08x) with controller CIPmask %08x chanIE:%s\n",
CAPIobjIDstr(&plci->cobj), CIPmask, pc->CIPmask, mc->l3m->channel_id ? "yes" : "no");
if (CIPmask & pc->CIPmask) {
/* at least one Application is listen for this service */
co = get_next_cobj(&pc->cobjLC, NULL);
while (co) {
lc = container_of(co, struct lController, cobj);
cipm = lc->CIPmask & CIPmask;
if ((lc->CIPmask & CIPmask) || (lc->CIPmask & 1)) {
ret = lPLCICreate(&lp, lc, plci, cipm);
if (ret == 0) {
found++;
put_cobj(&lp->cobj);
} else {
wprint("%s: cannot create lPLCI\n", CAPIobjIDstr(&plci->cobj));
}
}
co = get_next_cobj(&pc->cobjLC, co);
}
if (plci->cobj.itemcnt) {
/* at least one lplci was created */
fds = calloc(found, sizeof(int));
if (!fds)
eprint("%s: cannot allocate fds buffer for %d fd - will crash soon\n", CAPIobjIDstr(&plci->cobj), found);
cur = fds;
pthread_rwlock_rdlock(&plci->cobj.lock);
co = plci->cobj.listhead;
while (co) {
lp = container_of(co, struct lPLCI, cobj);
*cur++ = lp->Appl->fd;
co = co->next;
}
pthread_rwlock_unlock(&plci->cobj.lock);
/* disable answers until all controller are informed */
send_master_control(MICD_CTRL_DISABLE_POLL, found * sizeof(int), fds);
sched_yield(); /* make sure that the disable could be processed */
co = get_next_cobj(&plci->cobj, NULL);
while (co) {
lp = container_of(co, struct lPLCI, cobj);
lPLCI_l3l4(lp, pr, mc);
dprint(MIDEBUG_PLCI, "%s: SETUP %s\n",
CAPIobjIDstr(&lp->cobj), lp->ignored ? "ignored - no B-channel" : "delivered");
if (lp->ignored)
cleanup_lPLCI(lp);
co = get_next_cobj(&plci->cobj, co);
}
/* Now enable answers again */
send_master_control(MICD_CTRL_ENABLE_POLL, found * sizeof(int), fds);
free(fds);
}
}
if (found == 0) {
struct l3_msg *l3m;
l3m = alloc_l3_msg();
if (l3m) {
dprint(MIDEBUG_PLCI, "%s: send %s cause #%d (0x%02x) to layer3\n",
CAPIobjIDstr(&plci->cobj), _mi_msg_type2str(MT_RELEASE_COMPLETE), cause, cause);
if (!mi_encode_cause(l3m, cause, CAUSE_LOC_USER, 0, NULL)) {
ret = pc->l3->to_layer3(pc->l3, MT_RELEASE_COMPLETE, plci->cobj.id2, l3m);
if (ret) {
wprint("%s: Error %d - %s on sending %s to pid %x\n", CAPIobjIDstr(&plci->cobj), ret,
strerror(-ret), _mi_msg_type2str(MT_RELEASE_COMPLETE), plci->cobj.id2);
free_l3_msg(l3m);
}
}
} else
eprint("%s: cannot allocate l3 message plci\n", CAPIobjIDstr(&plci->cobj));
cleanup_mPLCI(plci);
}
}
int plci_l3l4(struct mPLCI *plci, int pr, struct l3_msg *l3m)
{
struct mc_buf *mc;
struct mCAPIobj *co;
mc = alloc_mc_buf();
if (!mc) {
wprint("%s: Cannot allocate mc_buf for %s\n", CAPIobjIDstr(&plci->cobj), _mi_msg_type2str(pr));
return -ENOMEM;
}
mc->l3m = l3m;
switch (pr) {
case MT_SETUP:
plciHandleSetupInd(plci, pr, mc);
break;
default:
co = get_next_cobj(&plci->cobj, NULL);
while (co) {
lPLCI_l3l4(container_of(co, struct lPLCI, cobj), pr, mc);
co = get_next_cobj(&plci->cobj, co);
}
break;
}
free_mc_buf(mc);
return 0;
}
int mPLCISendMessage(struct lController *lc, struct mc_buf *mc)
{
struct mPLCI *plci;
struct lPLCI *lp;
int ret;
struct pController *pc;
pc = p4lController(lc);
switch (mc->cmsg.Command) {
case CAPI_CONNECT:
plci = new_mPLCI(pc, 0);
if (plci) {
ret = lPLCICreate(&lp, lc, plci, 0);
if (!ret) {
ret = lPLCISendMessage(lp, mc);
put_cobj(&lp->cobj);
} else {
wprint("%s: cannot create lPLCI Appl-%03d", CAPIobjIDstr(&plci->cobj), lc->cobj.id2);
ret = CapiMsgOSResourceErr;
}
put_cobj(&plci->cobj);
} else {
wprint("Cannot create PLCI for controller %d\n", pc->profile.ncontroller);
ret = CapiMsgOSResourceErr;
}
break;
default:
wprint("Message %s not handled yet\n", capi20_cmd2str(mc->cmsg.Command, mc->cmsg.Subcommand));
ret = CapiMessageNotSupportedInCurrentState;
break;
}
return ret;
}
struct lPLCI *get_lPLCI4Id(struct mPLCI *plci, uint16_t appId)
{
struct mCAPIobj *co;
if (!plci)
return NULL;
co = get_next_cobj(&plci->cobj, NULL);
while (co) {
if (appId == co->id2)
break;
co = get_next_cobj(&plci->cobj, co);
}
return co ? container_of(co, struct lPLCI, cobj) : NULL;
}
struct mPLCI *getPLCI4pid(struct pController *pc, int pid)
{
struct mCAPIobj *co;
co = get_next_cobj(&pc->cobjPLCI, NULL);
while (co) {
if (co->id2 == pid)
break;
co = get_next_cobj(&pc->cobjPLCI, co);
}
return co ? container_of(co, struct mPLCI, cobj) : NULL;
}
struct mPLCI *getPLCI4Id(struct pController *pc, uint32_t id)
{
struct mCAPIobj *co;
co = get_next_cobj(&pc->cobjPLCI, NULL);
while (co) {
if (co->id == id)
break;
co = get_next_cobj(&pc->cobjPLCI, co);
}
return co ? container_of(co, struct mPLCI, cobj) : NULL;
}
int plciL4L3(struct mPLCI *plci, int mt, struct l3_msg *l3m)
{
int ret;
ret = plci->pc->l3->to_layer3(plci->pc->l3, mt, plci->cobj.id2, l3m);
if (ret < 0) {
wprint("%s: Error sending %s to controller %d pid %x %s msg\n", CAPIobjIDstr(&plci->cobj), _mi_msg_type2str(mt),
plci->pc->profile.ncontroller, plci->cobj.id2, l3m ? "with" : "no");
if (l3m)
free_l3_msg(l3m);
}
dprint(MIDEBUG_PLCI, "%s: Sending %s to layer3 %s msg\n",
CAPIobjIDstr(&plci->cobj), _mi_msg_type2str(mt), l3m ? "with" : "no");
return ret;
}
unsigned int plci_new_pid(struct mPLCI *plci)
{
return request_new_pid(plci->pc->l3);
}
void release_lController(struct lController *lc)
{
struct mCAPIobj *cop, *colp;
struct lPLCI *lp;
struct pController *pc = p4lController(lc);
if (pc) {
cop = get_next_cobj(&pc->cobjPLCI, NULL);
while (cop) {
colp = get_next_cobj(cop, NULL);
while (colp) {
lp = container_of(colp, struct lPLCI, cobj);
if (lc == lp->lc) {
if (!lp->rel_req) {
dprint(MIDEBUG_PLCI, "%s do release\n", CAPIobjIDstr(colp));
lPLCIRelease(lp);
} else
dprint(MIDEBUG_PLCI, "%s: release already done\n", CAPIobjIDstr(colp));
}
colp = get_next_cobj(cop, colp);
}
cop = get_next_cobj(&pc->cobjPLCI, cop);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,81 +0,0 @@
/*
* ncci.h
*
* Author Karsten Keil <kkeil@linux-pingi.de>
*
* Copyright 2011 by Karsten Keil <kkeil@linux-pingi.de>
*
* This code is free software; you can redistribute it and/or modify
* it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE
* version 2.1 as published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU LESSER GENERAL PUBLIC LICENSE for more details.
*
*/
#ifndef _NCCI_H
#define _NCCI_H
// --------------------------------------------------------------------
// NCCI state machine
//
// Some rules:
// * EV_AP_* events come from CAPI Application
// * EV_DL_* events come from the ISDN stack
// * EV_NC_* events generated in NCCI handling
// * messages are send in the routine that handle the event
//
// --------------------------------------------------------------------
enum st_ncci_e {
ST_NCCI_N_0,
ST_NCCI_N_0_1,
ST_NCCI_N_1,
ST_NCCI_N_2,
ST_NCCI_N_ACT,
ST_NCCI_N_3,
ST_NCCI_N_4,
ST_NCCI_N_5,
};
enum ev_ncci_e {
EV_AP_CONNECT_B3_REQ,
EV_NC_CONNECT_B3_CONF,
EV_NC_CONNECT_B3_IND,
EV_AP_CONNECT_B3_RESP,
EV_NC_CONNECT_B3_ACTIVE_IND,
EV_AP_CONNECT_B3_ACTIVE_RESP,
EV_AP_RESET_B3_REQ,
EV_NC_RESET_B3_IND,
EV_NC_RESET_B3_CONF,
EV_AP_RESET_B3_RESP,
EV_NC_CONNECT_B3_T90_ACTIVE_IND,
EV_AP_DISCONNECT_B3_REQ,
EV_NC_DISCONNECT_B3_IND,
EV_NC_DISCONNECT_B3_CONF,
EV_AP_DISCONNECT_B3_RESP,
EV_L3_DISCONNECT_IND,
EV_AP_FACILITY_REQ,
EV_AP_MANUFACTURER_REQ,
EV_DL_ESTABLISH_IND,
EV_DL_ESTABLISH_CONF,
EV_DL_RELEASE_IND,
EV_DL_RELEASE_CONF,
EV_DL_DOWN_IND,
EV_NC_LINKDOWN,
EV_AP_RELEASE,
};
struct mNCCI;
const char *_mi_ncci_st2str(struct mNCCI *);
const char *_mi_ncci_ev2str(enum ev_ncci_e);
void ncciCmsgHeader(struct mNCCI *, struct mc_buf *, uint8_t, uint8_t);
int ncciB3Message(struct mNCCI *, struct mc_buf *);
void AnswerDataB3Req(struct mNCCI *, struct mc_buf *, uint16_t);
#endif

View File

@ -1,749 +0,0 @@
/*
* SFF to TIFF and TIFF to SFF
*
* Written by Karsten Keil <kkeil@linux-pingi.de>
*
* Copyright (C) 2011 Karsten Keil <kkeil@linux-pingi.de>
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2 as published by the
* Free Software Foundation. See the LICENSE file included with
* this package for more details.
*/
#ifdef USE_SOFTFAX
#include <tiffio.h>
#include "m_capi.h"
#include "mc_buffer.h"
#include "sff.h"
#include "g3_mh.h"
/* This debug will generate huge amount of data and slow down the process a lot */
//#define SFF_VERBOSE_DEBUG 1
#define SFF_DATA_BLOCK_SIZE (64 * 1024)
struct sff_page {
enum SFFState state;
int nr;
struct sff_page_head head;
unsigned char *headp;
unsigned char *start;
unsigned char *ep; /* last byte of page */
unsigned char *dp;
unsigned char *CStrip;
int CStrip_size;
unsigned char *sp;
unsigned char *RStrip;
int lines;
int line_size; /* size in bytes to hold 1 line - linelen is pixel ! */
int size;
TIFF *tiff;
struct sff_page *next;
};
static int sff_read_page_header(struct sff_state *sf)
{
struct sff_page *pg;
pg = calloc(1, sizeof(*pg));
if (!pg) {
eprint("No memory for page data\n");
return -ENOMEM;
}
if (!sf->firstpage)
sf->firstpage = pg;
pg->nr = sf->page_cnt + 1;
pg->headp = sf->dp;
pg->dp = pg->headp;
pg->head.rectype = *pg->dp;
pg->dp++;
pg->head.pageheaderlen = *pg->dp;
pg->dp++;
pg->head.res_vertical = *pg->dp;
pg->dp++;
pg->head.res_horizontal = *pg->dp;
pg->dp++;
pg->head.coding = *pg->dp;
pg->dp++;
pg->head.reserved = *pg->dp;
pg->dp++;
pg->head.linelen = CAPIMSG_U16(pg->dp, 0);
pg->dp += 2;
pg->line_size = (pg->head.linelen + 7) >> 3;
pg->head.pagelen = CAPIMSG_U16(pg->dp, 0);
pg->dp += 2;
pg->head.o_previous_page = CAPIMSG_U32(pg->dp, 0);
pg->dp += 4;
pg->head.o_next_page = CAPIMSG_U32(pg->dp, 0);
pg->dp += 4;
sf->state = SFF_PageHeader;
pg->state = SFF_PageHeader;
pg->start = pg->headp + 2 + pg->head.pageheaderlen;
pg->dp = pg->start;
sf->dp = pg->start;
if (sf->lastpage)
sf->lastpage->next = pg;
sf->lastpage = pg;
sf->page_cnt++;
return 0;
}
static int sff_read_file_header(struct sff_state *sf)
{
sf->dp = sf->data;
if (sf->size < SFF_FILE_HEADER_SIZE) {
wprint("SFF too small(%zu/%zu\n", sf->size, sizeof(sf->fh));
return 1;
}
sf->fh.magic = CAPIMSG_U32(sf->dp, 0);
sf->fh.version = CAPIMSG_U8(sf->dp, 4);
sf->fh.reserved = CAPIMSG_U8(sf->dp, 5);
sf->fh.userinfo = CAPIMSG_U16(sf->dp, 6);
sf->fh.pagecount = CAPIMSG_U16(sf->dp, 8);
sf->fh.o_firstpageheader = CAPIMSG_U16(sf->dp, 10);
sf->fh.o_lastpageheader = CAPIMSG_U32(sf->dp, 12);
sf->fh.o_docend = CAPIMSG_U32(sf->dp, 16);
sf->dp = sf->data + sf->fh.o_firstpageheader;
sf->state = SFF_Header;
return 0;
}
#if 0
static int add_eol(unsigned char *p)
{
*p++ = 0x00;
*p++ = 0x80;
return 2;
}
static int add_empty_line(unsigned char *tp, struct g3_mh_line_s *ls)
{
unsigned char *p = tp;
*p++ = 0xB2;
*p++ = 0x59;
*p++ = 0x01;
*p++ = 0x80;
ls->len = (uint16_t)(p - tp);
ls->line = tp;
g3_decode_line(ls);
return ls->len;
}
static int add_empty_lines(unsigned char *p, int cnt, struct g3_mh_line_s *ls)
{
int i,l, ret = 0;
for (i = 0; i < cnt; i++) {
l = add_empty_line(p, ls);
p += l;
ret += l;
}
return ret;
}
static int add_line(unsigned char *p, unsigned char *s, int len, struct g3_mh_line_s *ls)
{
struct g3_mh_line_s lo;
lo.nr = ls->nr;
lo.rawline = ls->rawline;
lo.linelen = ls->linelen;
lo.line = calloc(1, ((lo.linelen + 7) >> 3));
memcpy(p, s, len);
ls->line = p;
ls->len = len;
g3_decode_line(ls);
#if 0
if (Out_TiffF) {
if (TIFFWriteScanline(Out_TiffF, ls->rawline, ls->nr - 1, 0) < 0) {
wprint("%s: Write error at row %d.\n",
tiff_file, ls->nr);
}
}
#endif
g3_encode_line(&lo);
if (ls->len == lo.len) {
if (memcmp(ls->line, lo.line, ls->len))
wprint("SFF encoded line %d do not match\n", ls->nr);
} else
wprint("SFF encoded line %d len %d do not match %d\n", ls->nr, lo.len, ls->len);
free(lo.line);
return len + add_eol(p + len);
}
#endif
static int add_raw_line(struct sff_page *pg, unsigned char *s, int len, int nr)
{
struct g3_mh_line_s ls;
ls.nr = nr;
ls.rawline = pg->sp;
ls.linelen = pg->head.linelen;
ls.line = s;
ls.len = len;
g3_decode_line(&ls);
if (pg->tiff) {
if (TIFFWriteScanline(pg->tiff, ls.rawline, ls.nr, 0) < 0) {
wprint("Write error at row %d.\n", ls.nr);
}
}
pg->sp += pg->line_size;
return 0;
}
static int add_raw_empty_line(struct sff_page *pg, int nr)
{
unsigned char buf[8];
unsigned char *p = buf;
int len;
*p++ = 0xB2;
*p++ = 0x59;
*p++ = 0x01;
*p++ = 0x80;
len = (uint16_t)(p - buf);
return add_raw_line(pg, buf, len, nr);
}
static int add_raw_empty_lines(struct sff_page *pg, int cnt, int start)
{
int i;
for (i = 0; i < cnt; i++) {
add_raw_empty_line(pg, start + i);
}
return 0;
}
int sff_decode_page_data(struct sff_page *pg)
{
unsigned char rt;
int l, nr;
pg->RStrip = calloc(pg->lines, pg->line_size);
pg->sp = pg->RStrip;
pg->dp = pg->start;
rt = *pg->dp;
pg->dp++;
nr = 0;
while (pg->dp < pg->ep) {
l = rt;
if (rt == 0) {
/* escape 2 byte len */
l = CAPIMSG_U16(pg->dp, 0);
pg->dp += 2;
#ifdef SFF_VERBOSE_DEBUG
dprint(MIDEBUG_NCCI_DATA, "Line %d with %d bytes found in page %d\n", nr, l, pg->nr);
#endif
add_raw_line(pg, pg->dp, l, nr);
nr++;
} else if (rt < 217) {
l = rt;
#ifdef SFF_VERBOSE_DEBUG
dprint(MIDEBUG_NCCI_DATA, "Line %d with %d bytes found in page %d\n", nr, l, pg->nr);
#endif
add_raw_line(pg, pg->dp, l, nr);
nr++;
} else if (rt < 254) {
l = 0;
#ifdef SFF_VERBOSE_DEBUG
dprint(MIDEBUG_NCCI_DATA, "Skip %d empty lines (line %d) in page %d\n", rt - 216, nr, pg->nr);
#endif
add_raw_empty_lines(pg, rt - 216, nr);
nr += (rt - 216);
} else if (rt == 254) {
/* Page header should be never occur */
wprint("Pageheader inside page %d \n", pg->nr);
} else { /* 255 */
l = *pg->dp;
pg->dp++;
if (!l) {
add_raw_empty_line(pg, nr);
nr++;
dprint(MIDEBUG_NCCI_DATA, "Illegal Line %d in page %d found\n", nr, pg->nr);
} else
dprint(MIDEBUG_NCCI_DATA, "%d bytes userdata found in page %d\n", l, pg->nr);
}
pg->dp += l;
rt = *pg->dp;
pg->dp++;
}
return 0;
}
static int sff_read_data(struct sff_state *sff)
{
struct sff_page *pg;
uint8_t rt;
uint16_t l;
int ret;
if (sff->state < SFF_Header) {
ret = sff_read_file_header(sff);
if (ret < 0)
return ret;
if (sff->dp == sff->ep)
return 1;
}
pg = sff->lastpage;
while ((sff->dp + 1) < sff->ep) {
rt = *sff->dp;
if (rt == 0) {
/* escape 2 byte len */
if ((sff->dp + 3) < sff->ep) {
l = 3 + CAPIMSG_U16(sff->dp, 1);
if ((sff->dp + l) >= sff->ep)
break;
pg->lines++;
} else
break;;
} else if (rt < 217) {
l = 1 + rt;
if ((sff->dp + l) >= sff->ep)
break;
pg->lines++;
} else if (rt < 254) {
l = 1;
pg->lines += rt - 216;
} else if (rt == 254) {
/* New Page header */
if (pg)
pg->ep = sff->dp;
if (sff->dp[1] == 0) {
/* EOF reached */
return 0;
}
l = 2 + sff->dp[1];
if ((sff->dp + l) >= sff->ep)
break;
ret = sff_read_page_header(sff);
if (ret)
return ret;
pg = sff->lastpage;
l = 0; /* read read_page_header did change sff->dp */
} else { /* 255 */
l = 1 + sff->dp[1];
if (l == 1) {
pg->lines++;
} else {
if ((sff->dp + l) >= sff->ep)
break;
}
}
sff->dp += l;
}
return 1;
}
static void adjust_memory(struct sff_state *sff, unsigned char *np)
{
size_t offset;
struct sff_page *pg;
offset = np - sff->data;
dprint(MIDEBUG_NCCI_DATA, "Adjust data offset old=%p new=%p offset=%zu data_size=%zu\n",
sff->data, np, offset, sff->data_size);
if (sff->dp)
sff->dp += offset;
pg = sff->firstpage;
while (pg) {
if (pg->headp)
pg->headp += offset;
if (pg->start)
pg->start += offset;
if (pg->dp)
pg->dp += offset;
if (pg->ep)
pg->ep += offset;
pg = pg->next;
}
}
int SFF_Put_Data(struct sff_state *sff, unsigned char *data, int len)
{
unsigned char *dp;
size_t inc;
if ((sff->size + len) >= sff->data_size) {
inc = SFF_DATA_BLOCK_SIZE;
while (len > inc)
inc += SFF_DATA_BLOCK_SIZE;
dp = realloc(sff->data, sff->data_size + inc);
if (!dp) {
eprint("No memory for sff data block (%zd)\n", sff->data_size + inc);
return -ENOMEM;
}
sff->data_size += inc;
if (sff->data && sff->data != dp) {
adjust_memory(sff, dp);
} else
dprint(MIDEBUG_NCCI_DATA, "Adjust data_size=%zu data=%p dp=%p\n", sff->data_size, sff->data, dp);
sff->data = dp;
if (!sff->dp)
sff->dp = dp;
}
memcpy(sff->data + sff->size, data, len);
sff->size += len;
sff->ep = sff->data + sff->size;
return sff_read_data(sff);
}
static int sff_copy_data(struct sff_state *sff, unsigned char *data, int len)
{
unsigned char *dp;
size_t inc;
if ((sff->size + len) >= sff->data_size) {
inc = SFF_DATA_BLOCK_SIZE;
while (len > inc)
inc += SFF_DATA_BLOCK_SIZE;
dp = realloc(sff->data, sff->data_size + inc);
if (!dp) {
eprint("No memory for sff data block (%zd)\n", sff->data_size + inc);
return -ENOMEM;
}
sff->data_size += inc;
if (sff->data && sff->data != dp) {
adjust_memory(sff, dp);
} else
dprint(MIDEBUG_NCCI_DATA, "Adjust data_size=%zu data=%p dp=%p\n", sff->data_size, sff->data, dp);
sff->data = dp;
if (!sff->dp)
sff->dp = dp;
}
/* if data is NULL reserve len bytes */
if (data)
memcpy(sff->dp, data, len);
sff->size += len;
sff->dp += len;
return len;
}
static int sff_put_encoded_line(struct sff_state *sff, struct sff_page *pg, struct g3_mh_line_s *ls)
{
int ret = 0;
unsigned char tmp[4];
if (ls->len < 217) {
tmp[0] = ls->len;
ret = sff_copy_data(sff, tmp, 1);
if (ret < 0)
return ret;
ret = sff_copy_data(sff, ls->line, ls->len);
} else {
tmp[0] = 0;
capimsg_setu16(tmp, 1, ls->len);
ret = sff_copy_data(sff, tmp, 3);
if (ret < 0)
return ret;
ret = sff_copy_data(sff, ls->line, ls->len);
}
if (ret >= 0) {
pg->dp = sff->dp;
pg->ep = pg->dp;
}
return ret;
}
static int sff_put_page(struct sff_state *sff, struct sff_page *pg)
{
int ret = 0;
capimsg_setu8(pg->headp, 0, SFF_RT_PAGEHEAD);
capimsg_setu8(pg->headp, 1, 0x10);
capimsg_setu8(pg->headp, 2, pg->head.res_vertical);
capimsg_setu8(pg->headp, 3, pg->head.res_horizontal);
capimsg_setu8(pg->headp, 4, pg->head.coding);
capimsg_setu8(pg->headp, 5, pg->head.reserved);
capimsg_setu16(pg->headp, 6, pg->head.linelen);
capimsg_setu16(pg->headp, 8, pg->head.pagelen);
capimsg_setu32(pg->headp, 10, pg->head.o_previous_page);
capimsg_setu32(pg->headp, 14, pg->head.o_next_page);
return ret;
}
static int sff_put_eof(struct sff_state *sff)
{
unsigned char eof[2] = {SFF_RT_PAGEHEAD, 0};
return sff_copy_data(sff, eof, 2);
}
static int sff_put_header(struct sff_state *sff)
{
int ret = 0;
if (sff->size < SFF_FILE_HEADER_SIZE) {
ret = sff_copy_data(sff, NULL, SFF_FILE_HEADER_SIZE);
if (ret < 0)
return ret;
}
sff->fh.o_docend = sff->size;
sff->fh.o_firstpageheader = 0x14;
sff->fh.pagecount = sff->page_cnt;
if (sff->lastpage)
sff->fh.o_lastpageheader = sff->lastpage->headp - sff->data;
capimsg_setu32(sff->data, 0, sff->fh.magic);
capimsg_setu8(sff->data, 4, sff->fh.version);
capimsg_setu8(sff->data, 5, sff->fh.reserved);
capimsg_setu16(sff->data, 6, sff->fh.userinfo);
capimsg_setu16(sff->data, 8, sff->fh.pagecount);
capimsg_setu16(sff->data, 10, sff->fh.o_firstpageheader);
capimsg_setu32(sff->data, 12, sff->fh.o_lastpageheader);
capimsg_setu32(sff->data, 16, sff->fh.o_docend);
return 0;
}
int SFF_WriteTiff(struct sff_state *sff, char *name)
{
struct sff_page *next, *pg = sff->firstpage;
TIFF *tf;
int compression_out = COMPRESSION_CCITTFAX3;
int fillorder_out = FILLORDER_MSB2LSB;
uint32_t group3options_out = GROUP3OPT_FILLBITS|GROUP3OPT_2DENCODING;
uint32_t group4options_out = 0; /* compressed */
uint32_t defrowsperstrip = (uint32_t) 0;
uint32_t rowsperstrip;
int photometric_out = PHOTOMETRIC_MINISWHITE;
float resY;
tf = TIFFOpen(name, "w");
if (tf == NULL) {
wprint("Can not create Tiff file %s\n", name);
return -1;
}
while(pg) {
if (pg->lines) {
if (pg->head.pagelen == 0) {
pg->head.pagelen = pg->lines;
} else if (pg->head.pagelen < pg->lines) {
wprint("found more lines %d as in header %d\n", pg->lines, pg->head.pagelen);
pg->head.pagelen = pg->lines;
} else if (pg->head.pagelen > pg->lines) {
wprint("found less lines %d as in header %d\n", pg->lines, pg->head.pagelen);
pg->head.pagelen = pg->lines;
}
} else {
wprint("SFF page %d no lines detected\n", pg->nr);
}
if (pg->head.res_vertical)
resY = 196.0;
else
resY = 98.0;
TIFFSetField(tf, TIFFTAG_FILLORDER, FILLORDER_LSB2MSB);
TIFFSetField(tf, TIFFTAG_IMAGEWIDTH, pg->head.linelen);
TIFFSetField(tf, TIFFTAG_BITSPERSAMPLE, 1);
TIFFSetField(tf, TIFFTAG_COMPRESSION, compression_out);
TIFFSetField(tf, TIFFTAG_PHOTOMETRIC, photometric_out);
TIFFSetField(tf, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
TIFFSetField(tf, TIFFTAG_SAMPLESPERPIXEL, 1);
switch (compression_out) {
/* g3 */
case COMPRESSION_CCITTFAX3:
TIFFSetField(tf, TIFFTAG_GROUP3OPTIONS, group3options_out);
TIFFSetField(tf, TIFFTAG_FAXMODE, FAXMODE_CLASSIC);
rowsperstrip = (defrowsperstrip) ? defrowsperstrip : (uint32_t)-1;
break;
/* g4 */
case COMPRESSION_CCITTFAX4:
TIFFSetField(tf, TIFFTAG_GROUP4OPTIONS, group4options_out);
TIFFSetField(tf, TIFFTAG_FAXMODE, FAXMODE_CLASSIC);
rowsperstrip = (defrowsperstrip) ? defrowsperstrip : (uint32_t)-1;
break;
default:
rowsperstrip = (defrowsperstrip) ? defrowsperstrip : TIFFDefaultStripSize(tf, 0);
break;
}
TIFFSetField(tf, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
TIFFSetField(tf, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
TIFFSetField(tf, TIFFTAG_FILLORDER, fillorder_out);
TIFFSetField(tf, TIFFTAG_SOFTWARE, "mISDNcapid");
TIFFSetField(tf, TIFFTAG_XRESOLUTION, 203.0);
TIFFSetField(tf, TIFFTAG_YRESOLUTION, resY);
TIFFSetField(tf, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
TIFFSetField(tf, TIFFTAG_PAGENUMBER, sff->page_cnt, pg->nr);
pg->tiff = tf;
sff_decode_page_data(pg);
dprint(MIDEBUG_NCCI, "SFF wrote page %d with %d lines\n", pg->nr, pg->lines);
TIFFSetField(tf, TIFFTAG_IMAGELENGTH, pg->lines);
TIFFWriteDirectory(tf);
pg = pg->next;
}
TIFFClose(tf);
pg = sff->firstpage;
while (pg) {
if (pg->RStrip)
free(pg->RStrip);
next = pg->next;
free(pg);
pg = next;
}
return 0;
}
int SFF_ReadTiff(struct sff_state *sff, char *name)
{
TIFF *tf;
int linelen = 0, retval = 0, newpg = 1, lines;
int i, ret;
unsigned char *rawbuf = NULL;
unsigned char *cbuf = NULL;
struct sff_page *pg, *prevpg;
struct g3_mh_line_s ls;
float resV;
tf = TIFFOpen(name, "r");
if (tf == NULL) {
wprint("Can not open Tiff file %s\n", name);
return -1;
}
rawbuf = calloc(1, 4096);
if (!rawbuf) {
eprint("Cannot allocate SFF rawbuf\n");
goto end;
}
cbuf = calloc(1, 4096);
if (!cbuf) {
eprint("Cannot allocate SFF cbuf\n");
goto end;
}
sff->fh.magic = SFF_MAGIC_HEAD;
sff->fh.version = SFF_VERSION;
sff->fh.reserved = 0;
sff->fh.userinfo = 0;
sff->fh.pagecount = 0;
sff->fh.o_firstpageheader = 0x14;
sff->fh.o_lastpageheader = 0;
sff->fh.o_docend = 0;
sff->state = SFF_Header;
ret = sff_copy_data(sff, NULL, SFF_FILE_HEADER_SIZE);
sff->page_cnt = 0;
if (ret < 0) {
eprint("Cannot reserve the file header\n");
retval = -ENOMEM;
goto end;
}
while (newpg) {
pg = calloc(1, sizeof(*pg));
if (!pg) {
eprint("Cannot allocate SFF page header\n");
retval = -ENOMEM;
break;
}
if (!sff->firstpage)
sff->firstpage = pg;
prevpg = sff->lastpage;
if (sff->lastpage)
sff->lastpage->next = pg;
sff->lastpage = pg;
sff->page_cnt++;
if (!TIFFGetField(tf, TIFFTAG_IMAGEWIDTH, &linelen))
wprint("TIFFTAG_IMAGEWIDTH not set\n");
if (!linelen) {
wprint("Using default linelength 1728\n");
linelen = 1728;
}
pg->head.linelen = linelen;
if (!TIFFGetField(tf, TIFFTAG_IMAGELENGTH, &lines)) {
wprint("TIFFTAG_IMAGELENGTH not set\n");
retval = -EINVAL;
break;
}
pg->headp = sff->dp;
/* reserve the page header */
ret = sff_copy_data(sff, NULL, SFF_PAGE_HEADER_SIZE);
if (ret < 0) {
eprint("Cannot reserve the page header\n");
retval = -ENOMEM;
break;
}
pg->start = sff->dp;
pg->dp = sff->dp;
pg->head.pagelen = lines;
ls.rawline = rawbuf;
ls.line = cbuf;
ls.linelen = linelen;
if (!TIFFGetField(tf, TIFFTAG_YRESOLUTION, &resV)) {
wprint("TIFFTAG_YRESOLUTION not set\n");
resV = 98.0;
}
dprint(MIDEBUG_NCCI_DATA, "V-resolution: %f\n", resV);
if (resV > 100.0)
pg->head.res_vertical = 1;
else
pg->head.res_vertical = 0;
pg->head.res_horizontal = 0;
for (i = 0; i < lines; i++) {
ret = TIFFReadScanline(tf, rawbuf, i, 0);
if (ret < 1) {
wprint("TIFFReadScanline %d returned %d\n", i, ret);
retval = -EINVAL;
goto end;
}
ls.nr = i + 1;
ret = g3_encode_line(&ls);
if (ret < 0) {
wprint("encoding line %d gaves error %d\n", i + 1, ret);
retval = -EINVAL;
goto end;
} else {
ret = sff_put_encoded_line(sff, pg, &ls);
if (ret < 0) {
wprint("putting encoded_line %d gaves error %d\n", i + 1, ret);
retval = ret;
goto end;
}
}
#ifdef SFF_VERBOSE_DEBUG
dprint(MIDEBUG_NCCI_DATA, "Line %d encode %d bytes %x %x %x %x %x %x %x %x\n", i, ret,
cbuf[0], cbuf[1], cbuf[2], cbuf[3], cbuf[4], cbuf[5], cbuf[6], cbuf[7]);
#endif
}
if (prevpg) {
prevpg->head.o_next_page = pg->headp - sff->data;
pg->head.o_previous_page = prevpg->headp - sff->data;
sff_put_page(sff, prevpg);
} else
pg->head.o_previous_page = 1;
pg->head.o_next_page = 1;
sff_put_page(sff, pg);
newpg = TIFFReadDirectory(tf);
if (!newpg) {
/* write EOF tag */
ret = sff_put_eof(sff);
if (ret < 0) {
eprint("Cannot put EOF\n");
retval = -ENOMEM;
break;
}
/* write header */
sff_put_header(sff);
}
}
end:
if (rawbuf)
free(rawbuf);
if (cbuf)
free(cbuf);
while (sff->firstpage) {
pg = sff->firstpage->next;
free(sff->firstpage);
sff->firstpage = pg;
}
TIFFClose(tf);
dprint(MIDEBUG_NCCI, "Recoded %d pages as SFF size %zu (allocated %zu)\n", sff->page_cnt, sff->size, sff->data_size);
return retval;
}
/* USE_SOFTFAX */
#endif

View File

@ -1,91 +0,0 @@
/*
* sff.h
*
* Author Karsten Keil <kkeil@linux-pingi.de>
*
* Copyright 2011 by Karsten Keil <kkeil@linux-pingi.de>
*
* This code is free software; you can redistribute it and/or modify
* it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE
* version 2.1 as published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU LESSER GENERAL PUBLIC LICENSE for more details.
*
*/
#ifndef _SFF_H
#define _SFF_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include "mc_buffer.h"
#define SFF_MAGIC_HEAD 0x66666653
#define SFF_VERSION 1
#define SFF_RT_PAGEHEAD 0xfe
#define SFF_FILE_HEADER_SIZE 20
struct sff_file_head {
uint32_t magic;
uint8_t version;
uint8_t reserved;
uint16_t userinfo;
uint16_t pagecount;
uint16_t o_firstpageheader;
uint32_t o_lastpageheader;
uint32_t o_docend;
};
#define SFF_PAGE_HEADER_SIZE 18
struct sff_page_head {
uint8_t rectype;
uint8_t pageheaderlen;
uint8_t res_vertical;
uint8_t res_horizontal;
uint8_t coding;
uint8_t reserved;
uint16_t linelen;
uint16_t pagelen;
uint32_t o_previous_page;
uint32_t o_next_page;
};
enum SFFState {
SFF_Begin = 0,
SFF_Header,
SFF_PageHeader,
SFF_PageData,
SFF_PageDone,
SFF_DocEnd,
};
struct sff_page;
struct sff_state {
enum SFFState state;
struct sff_file_head fh;
int page_cnt;
struct sff_page *firstpage;
struct sff_page *lastpage;
size_t data_size;
size_t size;
unsigned char *data;
unsigned char *dp; /* current byte */
unsigned char *ep; /* last byte */
};
int SFF_Put_Data(struct sff_state *, unsigned char *, int);
int SFF_WriteTiff(struct sff_state *, char *);
int SFF_ReadTiff(struct sff_state *, char *);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,13 +0,0 @@
#!/bin/bash
#checks out the given branch
if [ "$1" = "" ] ; then
echo "please provide one of the branch names:"
git branch -a
exit
fi
git-checkout -b $1 origin/$1
git-config branch.$1.remote origin
git-config branch.$1.merge refs/heads/$1

View File

@ -1,192 +0,0 @@
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.63])
AC_INIT([mISDNuser],[2.0.22],[i4ldeveloper@isdn4linux.de],[mISDNuser])
AC_CONFIG_SRCDIR([tools/])
AC_CONFIG_HEADERS([include/config.h])
AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE([-Wall foreign subdir-objects])
# Checks for programs.
AC_PROG_CC
AC_PROG_CXX
AC_PROG_INSTALL
AM_PROG_AR
AC_PROG_LIBTOOL
AM_PROG_LEX
AC_CHECK_LIB([pthread], [pthread_create])
# Checks for header files.
AC_CHECK_HEADERS([arpa/inet.h fcntl.h malloc.h netdb.h netinet/in.h stdlib.h string.h sys/ioctl.h sys/socket.h sys/time.h unistd.h])
# Checks for typedefs, structures, and compiler characteristics.
AC_HEADER_STDBOOL
AC_C_INLINE
AC_TYPE_INT16_T
AC_TYPE_INT32_T
AC_TYPE_INT64_T
AC_TYPE_PID_T
AC_TYPE_SIZE_T
LT_INIT
AC_ARG_ENABLE([example],
[ --enable-example Include example programs],
[case "${enableval}" in
yes) example=true ;;
no) example=false ;;
*) AC_MSG_ERROR([bad value ${enableval} for --enable-example]) ;;
esac],
[example=false])
AM_CONDITIONAL([OPT_EXAMPLE], [test "x$example" = xtrue])
AC_ARG_ENABLE([gui],
[ --enable-gui Include GUI programs],
[case "${enableval}" in
yes) gui=true ;;
no) gui=false ;;
*) AC_MSG_ERROR([bad value ${enableval} for --enable-example]) ;;
esac],
[gui=false])
AM_CONDITIONAL([OPT_GUI], [test "x$gui" = xtrue])
if $gui
then
AC_CHECK_LIB(QtCore, [qt_addObject],
AC_MSG_RESULT(found),
AC_MSG_ERROR([Qt library not found])
)
AC_ARG_VAR(QMAKE, [QT make helper])
AC_CHECK_TOOL(QMAKE, qmake,[NotFound],)
if test x$QMAKE = xNotFound
then
AC_MSG_ERROR([qmake not found])
fi
fi
AC_ARG_ENABLE([memleak_debug],
[ --enable-memleak_debug Turn on debugging of memleaks],
[case "${enableval}" in
yes) memleak_debug=true ;;
no) memleak_debug=false ;;
*) AC_MSG_ERROR([bad value ${enableval} for --enable-memleak_debug]) ;;
esac],
[debug=false])
AM_CONDITIONAL([MEMLEAKDEBUG], [test x$memleak_debug = xtrue])
if test x$memleak_debug = xtrue ; then
MEMLEAKDEBUG_COMPILE=1
else
MEMLEAKDEBUG_COMPILE=0
fi
AC_SUBST(MEMLEAKDEBUG_COMPILE)
AC_ARG_ENABLE([capi],
[ --enable-capi Include CAPI2.0 support],
[case "${enableval}" in
yes) capi=true ;;
no) capi=false ;;
*) AC_MSG_ERROR([bad value ${enableval} for --enable-capi]) ;;
esac],
[capi=false])
AM_CONDITIONAL([OPT_CAPI], [test "x$capi" = xtrue])
AC_ARG_ENABLE([softdsp],
[ --enable-softdsp Include CAPI2.0 softdsp support for analog FAX],
[case "${enableval}" in
yes) softdsp=true ;;
no) softdsp=false ;;
*) AC_MSG_ERROR([bad value ${enableval} for --enable-softdsp]) ;;
esac],
[softdsp=false])
AM_CONDITIONAL([OPT_SOFTDSP], [test "x$softdsp" = xtrue])
if $capi
then
AC_CHECK_LIB(capi20, [capi20_isinstalled],,
AC_MSG_ERROR([capi library not found])
)
AC_CHECK_HEADER([capi20.h],,
AC_MSG_ERROR([capi20.h do not exist - install capi4linux development files]),
)
AC_CHECK_HEADER([capi_mod.h],,
AC_MSG_ERROR([capi_mod.h do not exist - update capi4linux]),
)
AC_EGREP_HEADER([unsigned\ \(\ \*IsInstalled], capi_mod.h,
[
AC_MSG_RESULT([Old capi_mod.h *IsInstalled detected])
HAVE_OLDCAPIMOD=1
],[
AC_MSG_RESULT([New capi_mod.h *IsInstalled detected])
HAVE_OLDCAPIMOD=0
]
)
AC_SUBST(HAVE_OLDCAPIMOD)
AC_COMPUTE_INT([CAPI_MODULE_LOADER_VERSION], [[MODULE_LOADER_VERSION]],
[
#include <sys/types.h>
#include <capi_mod.h>
],
[AC_MSG_ERROR([capi library MODULE_LOADER_VERSION cannot calculated - update capi4linux])]
)
AC_MSG_RESULT([Capi library module loader version ${CAPI_MODULE_LOADER_VERSION} detected])
AC_SUBST(CAPI_MODULE_LOADER_VERSION)
if $softdsp
then
AC_CHECK_HEADER([spandsp.h],,
AC_MSG_ERROR([spandsp header file not found - install spandsp development files])
)
fi
AC_SUBST( [MISDN_CAPI_SOCKET_NAME], "sock" )
AC_SUBST( [MISDN_CAPI_SOCKET_DIR], "$(localstatedir)/run/mISDNcapid" )
fi
# Checks for library functions.
AC_FUNC_FORK
AC_FUNC_MALLOC
AC_CHECK_FUNCS([gethostbyname gettimeofday inet_ntoa memset select socket strcasecmp strchr strdup strerror strstr strtol])
# special checks
MISDN_CHECK_AF_ISDN
AC_MSG_CHECKING([whether building from git])
if test -d ${srcdir}/.git/objects; then
AC_MSG_RESULT([yes])
git_repo=true
else
AC_MSG_RESULT([no])
git_repo=false
fi
AC_MISDN_GROUP
AC_SUBST(MISDN_GROUP)
AM_CONDITIONAL([GIT_REPO], [test "x$git_repo" = xtrue])
AC_CONFIG_FILES([Makefile
45-misdn.rules
include/Makefile
include/mISDN/mISDNcompat.h
lib/Makefile
bridge/Makefile
l1oip/Makefile
tools/Makefile
example/Makefile
guitools/Makefile
guitools/qmisdnwatch/Makefile
capi20/Makefile
capi20/m_capi_sock.h
capi20/module/Makefile
])
AC_OUTPUT

6
example/.gitignore vendored
View File

@ -1,6 +0,0 @@
/cleanl2
/loghex
/misdnportinfo
/misdntestcon
/misdntestlayer1
/misdntestlayer3

52
example/Makefile Normal file
View File

@ -0,0 +1,52 @@
LIBINCL := $(INCLUDEDIR)/mISDNlib.h
PROGS := testcon testcon_l2 testlayer3 loadfirm sendhwctrl testlayer1 misdnportinfo
# PROGS := testcon testnet loadfirm logger
all: $(PROGS)
install:
for i in $(PROGS) ; do \
install -m 755 $$i $(INSTALL_PREFIX)/usr/bin ;\
done
misdnportinfo: misdnportinfo.o $(mISDNLIB)
testcon: testcon.o $(mISDNLIB)
testlayer3: testlayer3.o $(mISDNLIB)
testnet: testnet.o $(mISDNLIB)
testcon_l2: testcon_l2.o $(mISDNLIB)
loadfirm: loadfirm.o $(mISDNLIB)
sendhwctrl: sendhwctrl.o $(mISDNLIB)
testlayer1: testlayer1.o $(mISDNLIB)
logger: logger.o $(mISDNLIB)
misdnportinfo.o : misdnportinfo.c $(LIBINCL)
testcon.o : testcon.c ../include/l3dss1.h $(LIBINCL)
testlayer3.o : testlayer3.c ../include/l3dss1.h $(LIBINCL)
testnet.o : testnet.c ../include/l3dss1.h $(LIBINCL)
testcon_l2.o : testcon_l2.c ../include/l3dss1.h $(LIBINCL)
loadfirm.o: loadfirm.c $(LIBINCL)
sendhwctrl.o: sendhwctrl.c $(LIBINCL)
logger.o: logger.c $(LIBINCL)
clean:
rm -f *.o *~ DEADJOE
distclean: clean
rm -f *.a $(PROGS)

View File

@ -1,11 +0,0 @@
bin_PROGRAMS = misdntestcon misdntestlayer1 misdntestlayer3 misdnportinfo
misdntestcon_SOURCES = testcon.c
misdntestcon_LDADD = ../lib/libmisdn.la
misdntestlayer1_SOURCES = testlayer1.c
misdntestlayer3_SOURCES = testlayer3.c
misdnportinfo_SOURCES = misdnportinfo.c
misdntestlayer3_LDADD = ../lib/libmisdn.la
AM_CPPFLAGS = -Wall -Werror -I$(top_srcdir)/include $(_MEMLEAKDEBUG)
CLEANFILES = *~

301
example/loadfirm.c Normal file
View File

@ -0,0 +1,301 @@
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include "mISDNlib.h"
void usage(pname)
char *pname;
{
fprintf(stderr,"Call with %s [options] [firmware filename]\n",pname);
fprintf(stderr,"\n Valid options are:\n");
fprintf(stderr,"\n");
fprintf(stderr," -? Usage ; printout this information\n");
fprintf(stderr," -c<n> use card number n (default 1)\n");
fprintf(stderr," -v<n> Printing debug info level n\n");
fprintf(stderr," 0 only received messages are printed\n");
fprintf(stderr," 1 send count\n");
fprintf(stderr," 2 send status\n");
fprintf(stderr," 3 send contens\n");
fprintf(stderr," 4 device read count\n");
fprintf(stderr," 5 stdin line parsing\n");
fprintf(stderr," 6 stdin line raw contens\n");
fprintf(stderr," 7 filenumber/select status\n");
fprintf(stderr,"\n");
}
typedef struct _devinfo {
int device;
int mode;
int d_stid;
int d_adress;
int b_stid[2];
int b_adress[2];
int used_bchannel;
} devinfo_t;
#define MAX_SIZE 0x10000
static int VerifyOn=0;
unsigned char *firmware;
int download_firmware(devinfo_t *di, int size) {
unsigned char *p, buf[2048], rbuf[128];
iframe_t *frm = (iframe_t *)buf;
//iframe_t *rfrm = (iframe_t *)rbuf;
int cnt, ret = 0;
int *adr, l;
frm->prim = PH_CONTROL | REQUEST;
frm->dinfo = HW_FIRM_START;
frm->addr = di->b_adress[di->used_bchannel] | FLG_MSG_TARGET | FLG_MSG_DOWN;
frm->len = 4;
adr = (int *)&frm->data.i;
// *adr++ = HW_FIRM_START;
*adr++ = size;
ret = mISDN_write(di->device, buf, frm->len+mISDN_HEADER_LEN, 100000);
if (ret < 0)
fprintf(stdout,"send_data write error %d %s\n", errno,
strerror(errno));
else if (VerifyOn>3)
fprintf(stdout,"send_data write ret=%d\n", ret);
ret = mISDN_read(di->device, rbuf, 128, TIMEOUT_10SEC);
if (VerifyOn>3)
fprintf(stdout,"read ret=%d\n", ret);
cnt = 0;
p = firmware;
while (cnt<size) {
l = 1024;
if (l+cnt >=size)
l = size - cnt;
frm->prim = PH_CONTROL | REQUEST;
frm->dinfo = HW_FIRM_DATA;
frm->addr = di->b_adress[di->used_bchannel] | FLG_MSG_TARGET | FLG_MSG_DOWN;
frm->len = l + 4;
adr = (int *)&frm->data.i;
// *adr++ = HW_FIRM_DATA;
*adr++ = l;
memcpy(adr, firmware + cnt, l);
ret = mISDN_write(di->device, buf, frm->len+mISDN_HEADER_LEN, 100000);
if (ret < 0)
fprintf(stdout,"send_data write error %d %s\n", errno,
strerror(errno));
else if (VerifyOn>3)
fprintf(stdout,"send_data write ret=%d\n", ret);
ret = mISDN_read(di->device, rbuf, 128, TIMEOUT_10SEC);
if (VerifyOn>3)
fprintf(stdout,"read ret=%d\n", ret);
cnt += l;
}
frm->prim = PH_CONTROL | REQUEST;
frm->dinfo = HW_FIRM_END;
frm->addr = di->b_adress[di->used_bchannel] | FLG_MSG_TARGET | FLG_MSG_DOWN;
frm->len = 0;
// adr = (int *)&frm->data.i;
// *adr++ = HW_FIRM_END;
ret = mISDN_write(di->device, buf, frm->len+mISDN_HEADER_LEN, 100000);
if (ret < 0)
fprintf(stdout,"send_data write error %d %s\n", errno,
strerror(errno));
else if (VerifyOn>3)
fprintf(stdout,"send_data write ret=%d\n", ret);
ret = mISDN_read(di->device, rbuf, 128, TIMEOUT_10SEC);
if (VerifyOn>3)
fprintf(stdout,"read ret=%d\n", ret);
ret = mISDN_clear_stack(di->device, di->b_stid[di->used_bchannel]);
if (VerifyOn>3)
fprintf(stdout,"clear_stack ret=%d\n", ret);
return(0);
}
int do_setup(devinfo_t *di, int cardnr) {
unsigned char buf[2048];
iframe_t *frm = (iframe_t *)buf;
int ret = 0;
int i;
stack_info_t *stinf;
mISDN_pid_t pid;
layer_info_t li;
ret = mISDN_get_stack_count(di->device);
if (VerifyOn>1)
fprintf(stdout,"%d stacks found(%d)\n", ret, cardnr);
if (ret < cardnr) {
fprintf(stdout,"cannot config card nr %d only %d cards\n",
cardnr, ret);
return(2);
}
ret = mISDN_get_stack_info(di->device, cardnr, buf, 1024);
if (ret<=0) {
fprintf(stdout,"cannot get stackinfo err: %d\n", ret);
return(3);
}
stinf = (stack_info_t *)&frm->data.p;
if (VerifyOn>1)
mISDNprint_stack_info(stdout, stinf);
di->d_stid = stinf->id;
fprintf(stdout,"stid(%08x) childcnt(%d)\n", stinf->id, stinf->childcnt);
for (i=0;i<2;i++) {
if (stinf->childcnt>i)
di->b_stid[i] = stinf->child[i];
else
di->b_stid[i] = 0;
}
di->used_bchannel = 0;
memset(&li, 0, sizeof(layer_info_t));
strcpy(&li.name[0], "B L3");
li.object_id = -1;
li.extentions = 0;
li.pid.protocol[3] = ISDN_PID_L3_B_TRANS;
li.pid.layermask = ISDN_LAYER(3);
li.st = di->b_stid[di->used_bchannel];
ret = mISDN_new_layer(di->device, &li);
if (ret) {
fprintf(stdout, "new_layer ret(%d)\n", ret);
return(4);
}
di->b_adress[di->used_bchannel] = li.id;
if (VerifyOn>2)
fprintf(stdout,"b_adress%d %08x\n",
di->used_bchannel+1, ret);
#if 0
ret = mISDN_preregister_layer(di->device, di->b_stid[di->used_bchannel], di->b_adress[di->used_bchannel]);
if (ret < 0) {
fprintf(stdout, "preregister_layer ret(%d)\n", ret);
return(5);
}
#endif
memset(&pid, 0, sizeof(mISDN_pid_t));
pid.protocol[1] = ISDN_PID_L1_B_64TRANS;
pid.protocol[2] = ISDN_PID_L2_B_TRANS;
pid.protocol[3] = ISDN_PID_L3_B_TRANS;
pid.layermask = ISDN_LAYER(1) | ISDN_LAYER(2)| ISDN_LAYER(3);
ret = mISDN_set_stack(di->device,
di->b_stid[di->used_bchannel], &pid);
if (ret) {
fprintf(stdout, "set_stack ret(%d)\n", ret);
return(6);
}
ret = mISDN_get_setstack_ind(di->device, di->b_adress[di->used_bchannel]);
if (ret) {
fprintf(stdout, "get_setstack_ind ret(%d)\n", ret);
return(7);
}
return(0);
}
int
read_firmware(unsigned char *fname)
{
FILE *infile;
int cnt;
if (!(infile = fopen(fname, "rb"))) {
fprintf(stderr, "cannot open file %s\n", fname);
exit(-1);
}
firmware = (unsigned char *) malloc(MAX_SIZE);
if (!firmware) {
fprintf(stderr, "cannot get %d byte memory\n", MAX_SIZE+4);
exit(-1);
}
cnt = fread(firmware, 1, MAX_SIZE, infile);
fclose(infile);
if (cnt==MAX_SIZE) {
fprintf(stderr, "wrong filesize\n");
exit(-1);
}
return(cnt);
}
int main(argc,argv)
int argc;
char *argv[];
{
char FileName[200];
int aidx=1,para=1;
char sw;
int len,err;
devinfo_t mISDN;
int cardnr =1;
fprintf(stderr,"loadfirm 1.0\n");
strcpy(FileName,"ISAR.BIN");
if (argc<1) {
fprintf(stderr,"Error: Not enough arguments please check\n");
usage(argv[0]);
exit(1);
} else {
do {
if (argv[aidx] && argv[aidx][0]=='-') {
sw=argv[aidx][1];
switch (sw) {
case 'v':
case 'V':
VerifyOn=1;
if (argv[aidx][2]) {
VerifyOn=atol(&argv[aidx][2]);
}
break;
case 'c':
if (argv[aidx][2]) {
cardnr=atol(&argv[aidx][2]);
}
break;
case '?' :
usage(argv[0]);
exit(1);
break;
default : fprintf(stderr,"Unknown Switch %c\n",sw);
usage(argv[0]);
exit(1);
break;
}
} else {
if (para==1) {
if (argc > 1)
strcpy(FileName,argv[aidx]);
para++;
} else {
fprintf(stderr,"Undefined argument %s\n",argv[aidx]);
usage(argv[0]);
exit(1);
}
}
aidx++;
} while (aidx<argc);
}
memset(&mISDN, 0, sizeof(mISDN));
if (0>(mISDN.device = mISDN_open())) {
printf("TestmISDN cannot open mISDN due to %s\n",
strerror(errno));
return(1);
}
len = read_firmware(FileName);
if (VerifyOn)
fprintf(stdout,"read firmware from %s %d bytes\n", FileName, len);
err = do_setup(&mISDN, cardnr);
if (err)
fprintf(stdout,"do_setup error %d\n", err);
else
download_firmware(&mISDN, len);
free(firmware);
err=mISDN_close(mISDN.device);
if (err)
fprintf(stdout,"mISDN_close: error(%d): %s\n", err,
strerror(err));
return(0);
}

475
example/logger.c Normal file
View File

@ -0,0 +1,475 @@
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include "mISDNlib.h"
#include "l3dss1.h"
void usage(pname)
char *pname;
{
fprintf(stderr,"Call with %s [options] [filename]\n",pname);
fprintf(stderr,"\n");
fprintf(stderr,"\n Valid options are:\n");
fprintf(stderr,"\n");
fprintf(stderr," -? Usage ; printout this information\n");
fprintf(stderr," -c<n> use card number n (default 1)\n");
fprintf(stderr," -F<n> use function n (default 0)\n");
fprintf(stderr," 0 normal logging\n");
fprintf(stderr,"\n");
}
typedef struct _devinfo {
int device;
int cardnr;
int func;
char phonenr[32];
int d_stid;
int layer1;
int layer2;
int layer3;
int b_stid[2];
int b_adress[2];
int used_bchannel;
int save;
int flag;
int val;
int cr;
int si;
int bl1_prot;
int bl2_prot;
int bl3_prot;
} devinfo_t;
#define FLG_SEND_TONE 0x0001
#define FLG_SEND_DATA 0x0002
#define FLG_BCHANNEL_SETUP 0x0010
#define FLG_BCHANNEL_DOACTIVE 0x0020
#define FLG_BCHANNEL_ACTIVE 0x0040
#define FLG_BCHANNEL_ACTDELAYED 0x0080
#define FLG_CALL_ORGINATE 0x0100
#define FLG_BCHANNEL_EARLY 0x0200
#define MAX_REC_BUF 4000
#define MAX_DATA_BUF 1024
static int VerifyOn=0;
static devinfo_t *init_di = NULL;
#define MsgHead(ptr, cref, mty) \
*ptr++ = 0x8; \
if (cref == -1) { \
*ptr++ = 0x0; \
} else { \
*ptr++ = 0x1; \
*ptr++ = cref^0x80; \
} \
*ptr++ = mty
int printhexdata(FILE *f, int len, u_char *p)
{
while(len--) {
fprintf(f, "%02x", *p++);
if (len)
fprintf(f, " ");
}
fprintf(f, "\n");
return(0);
}
int process_dchannel(devinfo_t *di, int len, iframe_t *frm)
{
write(di->save, frm, len);
if (frm->prim == (PH_DATA | INDICATION) && (frm->len >0)) {
if (VerifyOn>5)
printhexdata(stdout, frm->len, (void *)&frm->data.i);
}
return(0);
}
int setup_bchannel(devinfo_t *di) {
mISDN_pid_t pid;
int ret;
layer_info_t li;
if ((di->used_bchannel<0) || (di->used_bchannel>1)) {
fprintf(stdout, "wrong channel %d\n", di->used_bchannel);
return(0);
}
memset(&li, 0, sizeof(layer_info_t));
strcpy(&li.name[0], "B L3");
li.object_id = -1;
li.extentions = 0;
li.pid.protocol[3] = di->bl3_prot;
li.pid.layermask = ISDN_LAYER(3);
li.st = di->b_stid[di->used_bchannel];
ret = mISDN_new_layer(di->device, &li);
if (ret<0) {
fprintf(stdout, "new_layer ret(%d)\n", ret);
return(0);
}
if (ret) {
di->b_adress[di->used_bchannel] = ret;
if (VerifyOn>2)
fprintf(stdout,"b_adress%d %08x\n",
di->used_bchannel+1, ret);
memset(&pid, 0, sizeof(mISDN_pid_t));
pid.protocol[1] = di->bl1_prot;
pid.protocol[2] = di->bl2_prot;
pid.protocol[3] = di->bl3_prot;
pid.layermask = ISDN_LAYER(1) | ISDN_LAYER(2)| ISDN_LAYER(3);
if (di->flag & FLG_CALL_ORGINATE)
pid.global = 1;
ret = mISDN_set_stack(di->device,
di->b_stid[di->used_bchannel], &pid);
if (ret) {
fprintf(stdout, "set_stack ret(%d)\n", ret);
return(0);
}
ret = di->b_adress[di->used_bchannel];
}
return(ret);
}
int activate_bchan(devinfo_t *di) {
unsigned char buf[128];
iframe_t *rfrm;
int ret;
ret = mISDN_write_frame(di->device, buf,
di->b_adress[di->used_bchannel] | IF_DOWN,
DL_ESTABLISH | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
if (VerifyOn>3)
fprintf(stdout,"DL_ESTABLISH write ret=%d\n", ret);
ret = mISDN_read(di->device, buf, 128, TIMEOUT_10SEC);
if (VerifyOn>3)
fprintf(stdout,"DL_ESTABLISH read ret=%d\n", ret);
rfrm = (iframe_t *)buf;
if (ret>0) {
if (rfrm->prim == (DL_ESTABLISH | CONFIRM)) {
di->flag |= FLG_BCHANNEL_ACTIVE;
}
}
return(ret);
}
int deactivate_bchan(devinfo_t *di) {
unsigned char buf[128];
int ret;
ret = mISDN_write_frame(di->device, buf,
di->b_adress[di->used_bchannel] | IF_DOWN,
DL_RELEASE | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
if (VerifyOn>3)
fprintf(stdout,"DL_RELEASE write ret=%d\n", ret);
ret = mISDN_read(di->device, buf, 128, TIMEOUT_10SEC);
if (VerifyOn>3)
fprintf(stdout,"DL_RELEASE read ret=%d\n", ret);
di->flag &= ~FLG_BCHANNEL_ACTIVE;
di->flag &= ~FLG_BCHANNEL_SETUP;
ret = mISDN_clear_stack(di->device, di->b_stid[di->used_bchannel]);
if (VerifyOn>3)
fprintf(stdout,"clear_stack ret=%d\n", ret);
return(ret);
}
int read_mutiplexer(devinfo_t *di) {
unsigned char buf[MAX_REC_BUF];
iframe_t *rfrm;
int timeout = TIMEOUT_10SEC;
int ret = 0;
rfrm = (iframe_t *)buf;
/* Main loop */
while (1){
ret = mISDN_read(di->device, buf, MAX_REC_BUF, timeout);
if (VerifyOn>3)
fprintf(stdout,"readloop ret=%d\n", ret);
if (ret == -1) {
fprintf(stdout,"readloop read error\n");
break;
}
if (ret >= 16) {
if (VerifyOn>4)
fprintf(stdout,"readloop addr(%x) prim(%x) len(%d)\n",
rfrm->addr, rfrm->prim, rfrm->len);
if (rfrm->addr == (di->b_adress[di->used_bchannel] | IF_DOWN)) {
/* B-Channel related messages */
if (rfrm->prim == (DL_DATA | INDICATION)) {
/* received data, save it */
write(di->save, &rfrm->data.i, rfrm->len);
}
/* D-Channel related messages */
} else if (rfrm->addr == (di->layer2 | IF_DOWN)) {
if (VerifyOn>4)
fprintf(stdout,"readloop addr(%x) prim(%x)len(%d)\n",
rfrm->addr, rfrm->prim, rfrm->len);
process_dchannel(di, ret, rfrm);
} else {
if (VerifyOn)
fprintf(stdout,"readloop unknown addr(%x) prim((%x)len(%d)\n",
rfrm->addr, rfrm->prim, rfrm->len);
}
}
}
return(0);
}
int
add_dlayer2(devinfo_t *di, int prot)
{
layer_info_t li;
interface_info_t ii;
int lid, ret;
memset(&li, 0, sizeof(layer_info_t));
strcpy(&li.name[0], "user L2");
li.object_id = -1;
li.extentions = 0;
li.pid.protocol[2] = prot;
li.pid.layermask = ISDN_LAYER(2);
li.st = di->d_stid;
lid = mISDN_new_layer(di->device, &li);
if (lid<0)
return(12);
di->layer2 = lid;
if (!di->layer2)
return(13);
/*
* EXT_IF_CREATE | EXT_IF_EXCLUSIV sorgen dafuer, das wenn die L3
* Schnittstelle schon benutzt ist, eine neue L2 Instanz erzeugt
* wird
*/
ii.extentions = EXT_IF_CREATE | EXT_IF_EXCLUSIV;
ii.owner = di->layer2;
ii.peer = di->layer1;
ii.stat = IF_DOWN;
ret = mISDN_connect(di->device, &ii);
if (ret)
return(13);
ii.owner = di->layer2;
ii.stat = IF_DOWN;
ret = mISDN_get_interface_info(di->device, &ii);
if (ret != 0)
return(14);
if (ii.peer == di->layer1)
fprintf(stdout, "Layer 1 not cloned\n");
else
fprintf(stdout, "Layer 1 %08x cloned from %08x\n",
ii.peer, di->layer1);
return(0);
}
int do_setup(devinfo_t *di) {
unsigned char buf[1024];
iframe_t *frm = (iframe_t *)buf;
int i, ret = 0;
stack_info_t *stinf;
status_info_t *si;
di->bl2_prot = ISDN_PID_L2_B_TRANS;
di->bl3_prot = ISDN_PID_L3_B_TRANS;
switch (di->func) {
case 0:
di->bl1_prot = ISDN_PID_L1_B_64TRANS;
di->si = 1;
break;
default:
fprintf(stdout,"unknown program function %d\n",
di->func);
return(1);
}
ret = mISDN_get_stack_count(di->device);
if (VerifyOn>1)
fprintf(stdout,"%d stacks found\n", ret);
if (ret < di->cardnr) {
fprintf(stdout,"cannot config card nr %d only %d cards\n",
di->cardnr, ret);
return(2);
}
ret = mISDN_get_stack_info(di->device, di->cardnr, buf, 1024);
if (ret<=0) {
fprintf(stdout,"cannot get stackinfo err: %d\n", ret);
return(3);
}
stinf = (stack_info_t *)&frm->data.p;
if (VerifyOn>1)
mISDNprint_stack_info(stdout, stinf);
di->d_stid = stinf->id;
for (i=0;i<2;i++) {
if (stinf->childcnt>i)
di->b_stid[i] = stinf->child[i];
else
di->b_stid[i] = 0;
}
di->layer1 = mISDN_get_layerid(di->device, di->d_stid, 1);
if (di->layer1<0) {
fprintf(stdout,"cannot get layer1\n");
return(4);
}
if (VerifyOn>1)
fprintf(stdout,"layer1 id %08x\n", di->layer1);
di->layer2 = mISDN_get_layerid(di->device, di->d_stid, 2);
if (VerifyOn>1)
fprintf(stdout,"layer2 id %08x\n", di->layer2);
if (di->layer2) {
fprintf(stdout,"layer 2 allready present\n");
return(5);
}
ret = add_dlayer2(di, ISDN_PID_L2_LAPD);
if (ret)
return(ret);
ret = mISDN_get_status_info(di->device, di->layer1, buf, 1024);
if (ret > mISDN_HEADER_LEN) {
si = (status_info_t *)&frm->data.p;
mISDNprint_status(stdout, si);
} else
fprintf(stdout,"mISDN_get_status_info ret(%d)\n", ret);
ret = mISDN_get_status_info(di->device, di->layer2, buf, 1024);
if (ret > mISDN_HEADER_LEN) {
si = (status_info_t *)&frm->data.p;
mISDNprint_status(stdout, si);
} else
fprintf(stdout,"mISDN_get_status_info ret(%d)\n", ret);
sleep(1);
init_di = di;
return(0);
}
void
close_di(devinfo_t *di) {
unsigned char buf[1024];
int ret = 0;
init_di = NULL;
ret = mISDN_write_frame(di->device, buf, di->layer3 | IF_DOWN,
MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
if (VerifyOn>3)
fprintf(stdout,"ret=%d\n", ret);
ret = mISDN_read(di->device, buf, 1024, TIMEOUT_10SEC);
if (VerifyOn>3)
fprintf(stdout,"read ret=%d\n", ret);
}
static void
term_handler(int sig)
{
if (init_di)
close_di(init_di);
}
int main(argc,argv)
int argc;
char *argv[];
{
char FileName[200],FileNameOut[200];
int aidx=1,para=1;
char sw;
devinfo_t mISDN;
int err;
fprintf(stderr,"TestmISDN 1.0\n");
strcpy(FileName, "test_file");
memset(&mISDN, 0, sizeof(mISDN));
mISDN.cardnr = 1;
mISDN.func = 0;
mISDN.phonenr[0] = 0;
signal(SIGTERM, term_handler);
signal(SIGINT, term_handler);
signal(SIGPIPE, term_handler);
if (argc<1) {
fprintf(stderr,"Error: Not enough arguments please check\n");
usage(argv[0]);
exit(1);
} else {
do {
if (argv[aidx] && argv[aidx][0]=='-') {
sw=argv[aidx][1];
switch (sw) {
case 'v':
case 'V':
VerifyOn=1;
if (argv[aidx][2]) {
VerifyOn=atol(&argv[aidx][2]);
}
break;
case 'c':
if (argv[aidx][2]) {
mISDN.cardnr=atol(&argv[aidx][2]);
}
break;
case 'F':
if (argv[aidx][2]) {
mISDN.func=atol(&argv[aidx][2]);
}
break;
case '?' :
usage(argv[0]);
exit(1);
break;
default : fprintf(stderr,"Unknown Switch %c\n",sw);
usage(argv[0]);
exit(1);
break;
}
} else {
if (para==1) {
if (argc > 1)
strcpy(FileName,argv[aidx]);
para++;
} else {
fprintf(stderr,"Undefined argument %s\n",argv[aidx]);
usage(argv[0]);
exit(1);
}
}
aidx++;
} while (aidx<argc);
}
if (0>(mISDN.device = mISDN_open())) {
printf("TestmISDN cannot open mISDN due to %s\n",
strerror(errno));
return(1);
}
sprintf(FileNameOut,"%s",FileName);
if (0>(mISDN.save = open(FileName, O_WRONLY|O_CREAT|O_TRUNC,S_IRWXU))) {
printf("TestmISDN cannot open %s due to %s\n",FileName,
strerror(errno));
close(mISDN.device);
return(1);
}
if (VerifyOn>8)
fprintf(stdout,"fileno %d/%d\n",mISDN.save, mISDN.device);
err = do_setup(&mISDN);
if (err)
fprintf(stdout,"do_setup error %d\n", err);
else
read_mutiplexer(&mISDN);
close(mISDN.save);
err=mISDN_close(mISDN.device);
if (err)
fprintf(stdout,"mISDN_close: error(%d): %s\n", err,
strerror(err));
return(0);
}

View File

@ -1,81 +1,199 @@
/*
*
* Copyright 2008 Karsten Keil <kkeil@suse.de>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59
* Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
*/
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <netinet/udp.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/socket.h>
#include "mISDNlib.h"
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/ioctl.h>
#include <mISDN/mISDNif.h>
#include <mISDN/q931.h>
#include <mISDN/af_isdn.h>
#include <errno.h>
int main(int argc, char *argv[])
/*
* global function to show all available isdn ports
*/
void isdn_port_info(void)
{
int cnt, ret = 0, i = 0;
int sk;
struct mISDN_devinfo devinfo;
int err;
int i, ii, p;
int useable, nt, pri;
unsigned char buff[1025];
iframe_t *frm = (iframe_t *)buff;
stack_info_t *stinf;
int device;
sk = socket(PF_ISDN, SOCK_RAW, ISDN_P_BASE);
if (sk < 1) {
fprintf(stdout, "could not open socket %s\n", strerror(errno));
return 2;
}
ret = ioctl(sk, IMGETCOUNT, &cnt);
if (ret) {
fprintf(stdout, "error getting interface count: %s\n", strerror(errno));
close(sk);
return 3;
/* open mISDN */
if ((device = mISDN_open()) < 0)
{
fprintf(stderr, "mISDN_open() failed: ret=%d errno=%d (%s) Check for mISDN modules and device.\n", device, errno, strerror(errno));
exit(-1);
}
printf("Found %d device%s\n",cnt,(cnt==1)?"":"s");
/* get number of stacks */
i = 1;
ii = mISDN_get_stack_count(device);
printf("\n");
if (ii <= 0)
{
printf("Found no card. Please be sure to load card drivers.\n");
}
while(cnt && i <= MAX_DEVICE_ID) {
devinfo.id = i;
ret = ioctl(sk, IMGETDEVINFO, &devinfo);
if (ret < 0) {
fprintf(stdout, "error getting info for device %d: %s\n", i, strerror(errno));
} else {
fprintf(stdout, " id: %d\n", devinfo.id);
fprintf(stdout, " Dprotocols: %08x\n", devinfo.Dprotocols);
fprintf(stdout, " Bprotocols: %08x\n", devinfo.Bprotocols);
fprintf(stdout, " protocol: %d\n", devinfo.protocol);
fprintf(stdout, " nrbchan: %d\n", devinfo.nrbchan);
fprintf(stdout, " name: %s\n", devinfo.name);
cnt--;
/* loop the number of cards and get their info */
while(i <= ii)
{
err = mISDN_get_stack_info(device, i, buff, sizeof(buff));
if (err <= 0)
{
fprintf(stderr, "mISDN_get_stack_info() failed: port=%d err=%d\n", i, err);
break;
}
stinf = (stack_info_t *)&frm->data.p;
nt = pri = 0;
useable = 1;
/* output the port info */
printf("Port %2d: ", i);
switch(stinf->pid.protocol[0] & ~ISDN_PID_FEATURE_MASK)
{
case ISDN_PID_L0_TE_S0:
printf("TE-mode BRI S/T interface line (for phone lines)");
#if 0
if (stinf->pid.protocol[0] & ISDN_PID_L0_TE_S0_HFC & ISDN_PID_FEATURE_MASK)
printf(" HFC multiport card");
#endif
break;
case ISDN_PID_L0_NT_S0:
nt = 1;
printf("NT-mode BRI S/T interface port (for phones)");
#if 0
if (stinf->pid.protocol[0] & ISDN_PID_L0_NT_S0_HFC & ISDN_PID_FEATURE_MASK)
printf(" HFC multiport card");
#endif
break;
case ISDN_PID_L0_TE_U:
printf("TE-mode BRI U interface line");
break;
case ISDN_PID_L0_NT_U:
nt = 1;
printf("NT-mode BRI U interface port");
break;
case ISDN_PID_L0_TE_UP2:
printf("TE-mode BRI Up2 interface line");
break;
case ISDN_PID_L0_NT_UP2:
nt = 1;
printf("NT-mode BRI Up2 interface port");
break;
case ISDN_PID_L0_TE_E1:
pri = 1;
printf("TE-mode PRI E1 interface line (for phone lines)");
#if 0
if (stinf->pid.protocol[0] & ISDN_PID_L0_TE_E1_HFC & ISDN_PID_FEATURE_MASK)
printf(" HFC-E1 card");
#endif
break;
case ISDN_PID_L0_NT_E1:
nt = 1;
pri = 1;
printf("NT-mode PRI E1 interface port (for phones)");
#if 0
if (stinf->pid.protocol[0] & ISDN_PID_L0_NT_E1_HFC & ISDN_PID_FEATURE_MASK)
printf(" HFC-E1 card");
#endif
break;
default:
useable = 0;
printf("unknown type 0x%08x",stinf->pid.protocol[0]);
}
printf("\n");
if (nt)
{
if (stinf->pid.protocol[1] == 0)
{
useable = 0;
printf(" -> Missing layer 1 NT-mode protocol.\n");
}
p = 2;
while(p <= MAX_LAYER_NR) {
if (stinf->pid.protocol[p])
{
useable = 0;
printf(" -> Layer %d protocol 0x%08x is detected, but not allowed for NT lib.\n", p, stinf->pid.protocol[p]);
}
p++;
}
if (useable)
{
if (pri)
printf(" -> Interface is Point-To-Point (PRI).\n");
else
printf(" -> Interface can be Poin-To-Point/Multipoint.\n");
}
} else
{
if (stinf->pid.protocol[1] == 0)
{
useable = 0;
printf(" -> Missing layer 1 protocol.\n");
}
if (stinf->pid.protocol[2] == 0)
{
useable = 0;
printf(" -> Missing layer 2 protocol.\n");
}
if (stinf->pid.protocol[2] & ISDN_PID_L2_DF_PTP)
{
printf(" -> Interface is Poin-To-Point.\n");
}
if (stinf->pid.protocol[3] == 0)
{
useable = 0;
printf(" -> Missing layer 3 protocol.\n");
} else
{
printf(" -> Protocol: ");
switch(stinf->pid.protocol[3] & ~ISDN_PID_FEATURE_MASK)
{
case ISDN_PID_L3_DSS1USER:
printf("DSS1 (Euro ISDN)");
break;
default:
useable = 0;
printf("unknown protocol 0x%08x",stinf->pid.protocol[3]);
}
printf("\n");
}
p = 4;
while(p <= MAX_LAYER_NR) {
if (stinf->pid.protocol[p])
{
useable = 0;
printf(" -> Layer %d protocol 0x%08x is detected, but not allowed for TE lib.\n", p, stinf->pid.protocol[p]);
}
p++;
}
printf(" -> childcnt: %d\n",stinf->childcnt);
}
if (!useable)
printf(" * Port NOT useable for PBX (maybe there is already a PBX running?)\n");
printf("--------\n");
i++;
}
printf("\n");
close(sk);
return 0;
/* close mISDN */
if ((err = mISDN_close(device)))
{
fprintf(stderr, "mISDN_close() failed: err=%d '%s'\n", err, strerror(err));
exit(-1);
}
}
int main()
{
isdn_port_info();
return 0;
}

199
example/sendhwctrl.c Normal file
View File

@ -0,0 +1,199 @@
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include "mISDNlib.h"
void usage(pname)
char *pname;
{
fprintf(stderr,"Call with %s [options] <prim> <dinfo>\n",pname);
fprintf(stderr,"\n Valid options are:\n");
fprintf(stderr,"\n");
fprintf(stderr," -? Usage ; printout this information\n");
fprintf(stderr," -c<n> use card number n (default 1)\n");
fprintf(stderr," -v<n> Printing debug info level n\n");
fprintf(stderr," 0 only received messages are printed\n");
fprintf(stderr," 1 send count\n");
fprintf(stderr," 2 send status\n");
fprintf(stderr," 3 send contens\n");
fprintf(stderr," 4 device read count\n");
fprintf(stderr," 5 stdin line parsing\n");
fprintf(stderr," 6 stdin line raw contens\n");
fprintf(stderr," 7 filenumber/select status\n");
fprintf(stderr,"\n");
fprintf(stderr,"<prim> primitiv code e.g. 0x000280 PH_CONTROL REQUEST\n");
fprintf(stderr,"<dinfo> dinfo code e.g. 0xFF01 to loop B1\n");
fprintf(stderr,"\n");
}
typedef struct _devinfo {
int device;
unsigned int d_stid;
unsigned int d_adress;
} devinfo_t;
static int VerifyOn=0;
int send_primitiv(devinfo_t *di, unsigned int prim, unsigned int dinfo) {
unsigned char *p, buf[2048], rbuf[128];
iframe_t *frm = (iframe_t *)buf;
int ret = 0;
frm->prim = prim;
frm->dinfo = dinfo;
frm->addr = di->d_adress | FLG_MSG_TARGET | FLG_MSG_DOWN;
frm->len = 0;
ret = mISDN_write(di->device, buf, frm->len+mISDN_HEADER_LEN, 100000);
if (ret < 0)
fprintf(stdout,"send_data write error %d %s\n", errno,
strerror(errno));
else if (VerifyOn>3)
fprintf(stdout,"send_data write ret=%d\n", ret);
ret = mISDN_read(di->device, rbuf, 128, TIMEOUT_1SEC);
if (VerifyOn>3)
fprintf(stdout,"read ret=%d\n", ret);
return(0);
}
int do_setup(devinfo_t *di, int cardnr) {
unsigned char buf[2048];
iframe_t *frm = (iframe_t *)buf;
int ret = 0;
stack_info_t *stinf;
ret = mISDN_get_stack_count(di->device);
if (VerifyOn>1)
fprintf(stdout,"%d stacks found(%d)\n", ret, cardnr);
if (ret < cardnr) {
fprintf(stdout,"cannot config card nr %d only %d cards\n",
cardnr, ret);
return(2);
}
ret = mISDN_get_stack_info(di->device, cardnr, buf, 1024);
if (ret<=0) {
fprintf(stdout,"cannot get stackinfo err: %d\n", ret);
return(3);
}
stinf = (stack_info_t *)&frm->data.p;
if (VerifyOn>1)
mISDNprint_stack_info(stdout, stinf);
di->d_stid = stinf->id;
if (!stinf->inst[0]) {
fprintf(stdout,"cannot get hw d-channel address\n");
return(4);
}
di->d_adress = stinf->inst[0];
return(0);
}
unsigned int
get_value(char *s)
{
unsigned int v;
if (strlen(s) >2) {
if (s[0] == '0') {
if ((s[1] == 'x') || (s[1] == 'X')) {
sscanf(s, "%x", &v);
return(v);
}
}
}
v = atol(s);
return(v);
}
int main(argc,argv)
int argc;
char *argv[];
{
int aidx=1,para=1;
char sw;
int err;
devinfo_t mISDN;
int cardnr =1;
unsigned int prim = 0;
unsigned int dinfo = 0;
fprintf(stderr,"sendhwctrl 1.0\n");
if (argc<1) {
fprintf(stderr,"Error: Not enough arguments please check\n");
usage(argv[0]);
exit(1);
} else {
do {
if (argv[aidx] && argv[aidx][0]=='-') {
sw=argv[aidx][1];
switch (sw) {
case 'v':
case 'V':
VerifyOn=1;
if (argv[aidx][2]) {
VerifyOn=atol(&argv[aidx][2]);
}
break;
case 'c':
if (argv[aidx][2]) {
cardnr=atol(&argv[aidx][2]);
}
break;
case '?' :
usage(argv[0]);
exit(1);
break;
default : fprintf(stderr,"Unknown Switch %c\n",sw);
usage(argv[0]);
exit(1);
break;
}
} else {
if (para==1) {
if (argc > 1)
prim = get_value(argv[aidx]);
para++;
} else if (para==2) {
if (argc > 1)
dinfo = get_value(argv[aidx]);
para++;
} else {
fprintf(stderr,"Undefined argument %s\n",argv[aidx]);
usage(argv[0]);
exit(1);
}
}
aidx++;
} while (aidx<argc);
}
if (para < 3) {
fprintf(stderr,"Error: Not enough arguments please check\n");
usage(argv[0]);
exit(1);
}
memset(&mISDN, 0, sizeof(mISDN));
if (0>(mISDN.device = mISDN_open())) {
printf("TestmISDN cannot open mISDN due to %s\n",
strerror(errno));
return(1);
}
err = do_setup(&mISDN, cardnr);
if (err)
fprintf(stdout,"do_setup error %d\n", err);
else
send_primitiv(&mISDN, prim, dinfo);
if (err)
fprintf(stdout,"mISDN_close: error(%d): %s\n", err,
strerror(err));
return(0);
}

BIN
example/test_file Executable file

Binary file not shown.

0
example/test_file.in Executable file
View File

File diff suppressed because one or more lines are too long

11
example/test_x75.in Executable file
View File

@ -0,0 +1,11 @@
Welcome to SuSE Linux 7.1 (i386) - Kernel (l).
pingi!login: test
Password:
Last login: Fri May 18 20:48:26 on ttyI1
Have a lot of fun...
test@pingi:~ > ls -l
insgesamt 0
test@pingi:~ > logout

4
example/test_x75.out Normal file
View File

@ -0,0 +1,4 @@
test
test
ls -l
logout

File diff suppressed because it is too large Load Diff

0
example/testcon.in Executable file
View File

873
example/testcon_l2.c Normal file
View File

@ -0,0 +1,873 @@
/* Beispiel fuer ein L2 B-channel modul statt dem L3 */
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include "mISDNlib.h"
#include "l3dss1.h"
void usage(pname)
char *pname;
{
fprintf(stderr,"Call with %s [options] [filename]\n",pname);
fprintf(stderr,"\n");
fprintf(stderr," filename filename.in incoming data\n");
fprintf(stderr," filename.out outgoing data\n");
fprintf(stderr," data is alaw for voice\n");
fprintf(stderr,"\n");
fprintf(stderr,"\n Valid options are:\n");
fprintf(stderr,"\n");
fprintf(stderr," -? Usage ; printout this information\n");
fprintf(stderr," -c<n> use card number n (default 1)\n");
fprintf(stderr," -F<n> use function n (default 0)\n");
fprintf(stderr," 0 send and recive voice\n");
fprintf(stderr," 1 send touchtones\n");
fprintf(stderr," 2 recive touchtones\n");
fprintf(stderr," 3 send and recive hdlc data\n");
fprintf(stderr," 4 send and recive X75 data\n");
fprintf(stderr," 5 send and recive voice early B connect\n");
fprintf(stderr," -n <phone nr> Phonenumber to dial\n");
fprintf(stderr," -vn Printing debug info level n\n");
fprintf(stderr,"\n");
}
typedef struct _devinfo {
int device;
int cardnr;
int func;
char phonenr[32];
int d_stid;
int layer1;
int layer2;
int layer3;
int b_stid[2];
int b_adress[2];
int used_bchannel;
int save;
int play;
FILE *fplay;
int flag;
int val;
int cr;
int si;
int bl1_prot;
int bl2_prot;
int bl3_prot;
} devinfo_t;
#define FLG_SEND_TONE 0x0001
#define FLG_SEND_DATA 0x0002
#define FLG_BCHANNEL_SETUP 0x0010
#define FLG_BCHANNEL_DOACTIVE 0x0020
#define FLG_BCHANNEL_ACTIVE 0x0040
#define FLG_BCHANNEL_ACTDELAYED 0x0080
#define FLG_CALL_ORGINATE 0x0100
#define FLG_BCHANNEL_EARLY 0x0200
#define MAX_REC_BUF 4000
#define MAX_DATA_BUF 1024
#define ISDN_PID_L2_B_USER 0x420000ff
static int VerifyOn=0;
char tt_char[]="0123456789ABCD*#";
#define PLAY_SIZE 64
#define MsgHead(ptr, cref, mty) \
*ptr++ = 0x8; \
if (cref == -1) { \
*ptr++ = 0x0; \
} else { \
*ptr++ = 0x1; \
*ptr++ = cref^0x80; \
} \
*ptr++ = mty
int play_msg(devinfo_t *di) {
unsigned char buf[PLAY_SIZE+mISDN_HEADER_LEN];
iframe_t *frm = (iframe_t *)buf;
int len, ret;
if (di->play<0)
return(0);
len = read(di->play, buf + mISDN_HEADER_LEN, PLAY_SIZE);
if (len<0) {
printf("play_msg err %d: \"%s\"\n", errno, strerror(errno));
close(di->play);
di->play = -1;
}
frm->addr = di->b_adress[di->used_bchannel] | FLG_MSG_TARGET | FLG_MSG_DOWN;
frm->prim = PH_DATA | REQUEST;
frm->dinfo = 0;
frm->len = len;
ret = mISDN_write(di->device, buf, len+mISDN_HEADER_LEN, 8000);
if (ret < 0)
fprintf(stdout,"play write error %d %s\n", errno, strerror(errno));
else if (VerifyOn>3)
fprintf(stdout,"play write ret=%d\n", ret);
return(ret);
}
int send_data(devinfo_t *di) {
unsigned char buf[MAX_DATA_BUF+mISDN_HEADER_LEN];
iframe_t *frm = (iframe_t *)buf;
unsigned char *data;
int len, ret;
if (di->play<0 || !di->fplay)
return(0);
if (!(data = fgets(buf + mISDN_HEADER_LEN, MAX_DATA_BUF, di->fplay))) {
close(di->play);
di->play = -1;
data = buf + mISDN_HEADER_LEN;
data[0] = 4; /* ctrl-D */
data[1] = 0;
}
len = strlen(data);
if (len==0) {
close(di->play);
di->play = -1;
data[0] = 4; /* ctrl-D */
len = 1;
}
frm->addr = di->b_adress[di->used_bchannel] | FLG_MSG_TARGET | FLG_MSG_DOWN;
frm->prim = PH_DATA | REQUEST;
frm->dinfo = 0;
frm->len = len;
ret = mISDN_write(di->device, buf, len+mISDN_HEADER_LEN, 100000);
if (ret < 0)
fprintf(stdout,"send_data write error %d %s\n", errno, strerror(errno));
else if (VerifyOn>3)
fprintf(stdout,"send_data write ret=%d\n", ret);
return(ret);
}
int setup_bchannel(devinfo_t *di) {
mISDN_pid_t pid;
int ret;
layer_info_t li;
if ((di->used_bchannel<0) || (di->used_bchannel>1)) {
fprintf(stdout, "wrong channel %d\n", di->used_bchannel);
return(0);
}
memset(&li, 0, sizeof(layer_info_t));
strcpy(&li.name[0], "B L2");
li.object_id = -1;
li.extentions = 0;
li.pid.protocol[2] = di->bl2_prot;
li.pid.layermask = ISDN_LAYER(2);
li.st = di->b_stid[di->used_bchannel];
ret = mISDN_new_layer(di->device, &li);
if (ret<0) {
fprintf(stdout, "new_layer ret(%d)\n", ret);
return(0);
}
if (ret) {
di->b_adress[di->used_bchannel] = ret;
if (VerifyOn>2)
fprintf(stdout,"b_adress%d %08x\n",
di->used_bchannel+1, ret);
memset(&pid, 0, sizeof(mISDN_pid_t));
pid.protocol[1] = di->bl1_prot;
pid.protocol[2] = di->bl2_prot;
// pid.protocol[3] = di->bl3_prot;
pid.layermask = ISDN_LAYER(1) | ISDN_LAYER(2); // | ISDN_LAYER(3);
if (di->flag & FLG_CALL_ORGINATE)
pid.global = 1;
ret = mISDN_set_stack(di->device,
di->b_stid[di->used_bchannel], &pid);
if (ret) {
fprintf(stdout, "set_stack ret(%d)\n", ret);
return(0);
}
ret = di->b_adress[di->used_bchannel];
}
return(ret);
}
int send_SETUP(devinfo_t *di, int SI, char *PNr) {
unsigned char *np, *p, *msg, buf[1024];
int len, ret;
p = msg = buf + mISDN_HEADER_LEN;
MsgHead(p, di->cr, MT_SETUP);
*p++ = 0xa1; /* complete indicator */
*p++ = IE_BEARER;
if (SI == 1) { /* Audio */
*p++ = 0x3; /* Length */
*p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */
*p++ = 0x90; /* Circuit-Mode 64kbps */
*p++ = 0xa3; /* A-Law Audio */
} else { /* default Datatransmission 64k */
*p++ = 0x2; /* Length */
*p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inf */
*p++ = 0x90; /* Circuit-Mode 64kbps */
}
*p++ = IE_CALLED_PN;
np = PNr;
*p++ = strlen(np) + 1;
/* Classify as AnyPref. */
*p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
while (*np)
*p++ = *np++ & 0x7f;
len = p - msg;
ret = mISDN_write_frame(di->device, buf, di->layer3 | FLG_MSG_TARGET | FLG_MSG_DOWN,
DL_DATA | REQUEST, 0, len, msg, TIMEOUT_1SEC);
return(ret);
}
int activate_bchan(devinfo_t *di) {
unsigned char buf[128];
iframe_t *rfrm;
int ret;
ret = mISDN_write_frame(di->device, buf,
di->b_adress[di->used_bchannel] | FLG_MSG_TARGET | FLG_MSG_DOWN,
PH_ACTIVATE | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
if (VerifyOn>3)
fprintf(stdout,"PH_ACTIVATE write ret=%d\n", ret);
ret = mISDN_read(di->device, buf, 128, TIMEOUT_10SEC);
if (VerifyOn>3)
fprintf(stdout,"PH_ACTIVATE read ret=%d\n", ret);
rfrm = (iframe_t *)buf;
if (ret>0) {
if (rfrm->prim == (PH_ACTIVATE | CONFIRM)) {
di->flag |= FLG_BCHANNEL_ACTIVE;
}
}
return(ret);
}
int deactivate_bchan(devinfo_t *di) {
unsigned char buf[128];
int ret;
ret = mISDN_write_frame(di->device, buf,
di->b_adress[di->used_bchannel] | FLG_MSG_TARGET | FLG_MSG_DOWN,
DL_RELEASE | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
if (VerifyOn>3)
fprintf(stdout,"DL_RELEASE write ret=%d\n", ret);
ret = mISDN_read(di->device, buf, 128, TIMEOUT_10SEC);
if (VerifyOn>3)
fprintf(stdout,"DL_RELEASE read ret=%d\n", ret);
di->flag &= ~FLG_BCHANNEL_ACTIVE;
di->flag &= ~FLG_BCHANNEL_SETUP;
ret = mISDN_clear_stack(di->device, di->b_stid[di->used_bchannel]);
if (VerifyOn>3)
fprintf(stdout,"clear_stack ret=%d\n", ret);
return(ret);
}
int send_touchtone(devinfo_t *di, int tone) {
iframe_t frm;
int tval, ret;
if (VerifyOn>1)
fprintf(stdout,"send_touchtone %c\n", DTMF_TONE_MASK & tone);
tval = DTMF_TONE_VAL | tone;
ret = mISDN_write_frame(di->device, &frm,
di->b_adress[di->used_bchannel] | FLG_MSG_TARGET | FLG_MSG_DOWN,
PH_CONTROL | REQUEST, 0, 4, &tval, TIMEOUT_1SEC);
if (VerifyOn>3)
fprintf(stdout,"tt send ret=%d\n", ret);
return(ret);
}
int read_mutiplexer(devinfo_t *di) {
unsigned char *p, *msg, buf[MAX_REC_BUF];
iframe_t *rfrm;
int timeout = TIMEOUT_10SEC;
int ret = 0;
int len;
rfrm = (iframe_t *)buf;
/* Main loop */
start_again:
while ((ret = mISDN_read(di->device, buf, MAX_REC_BUF, timeout))) {
if (VerifyOn>3)
fprintf(stdout,"readloop ret=%d\n", ret);
if (ret >= 16) {
if (VerifyOn>4)
fprintf(stdout,"readloop addr(%x) prim(%x) len(%d)\n",
rfrm->addr, rfrm->prim, rfrm->len);
if (rfrm->addr == (di->b_adress[di->used_bchannel] | FLG_MSG_TARGET | FLG_MSG_DOWN)) {
/* B-Channel related messages */
if (rfrm->prim == (PH_DATA | INDICATION)) {
/* received data, save it */
write(di->save, &rfrm->data.i, rfrm->len);
} else if (rfrm->prim == (PH_DATA | CONFIRM)) {
/* get ACK of send data, so we can
* send more
*/
if (VerifyOn>5)
fprintf(stdout,"PH_DATA_CNF\n");
switch (di->func) {
case 0:
case 2:
if (di->play > -1)
play_msg(di);
break;
}
} else if (rfrm->prim == (PH_CONTROL | INDICATION)) {
if ((rfrm->len == 4) &&
((rfrm->data.i & ~DTMF_TONE_MASK)
== DTMF_TONE_VAL)) {
fprintf(stdout,"GOT TT %c\n",
DTMF_TONE_MASK & rfrm->data.i);
} else
fprintf(stdout,"unknown PH_CONTROL len %d/val %x\n",
rfrm->len, rfrm->data.i);
}
/* D-Channel related messages */
} else if ((ret > 19) && (buf[19] == MT_CONNECT) &&
(di->flag & FLG_CALL_ORGINATE)) {
/* We got connect, so bring B-channel up */
if (!(di->flag & FLG_BCHANNEL_EARLY)) {
if (!(di->flag & FLG_BCHANNEL_ACTDELAYED))
activate_bchan(di);
else
di->flag |= FLG_BCHANNEL_DOACTIVE;
}
/* send a CONNECT_ACKNOWLEDGE */
p = msg = buf + mISDN_HEADER_LEN;
MsgHead(p, di->cr, MT_CONNECT_ACKNOWLEDGE);
len = p - msg;
ret = mISDN_write_frame(di->device, buf,
di->layer3 | FLG_MSG_TARGET | FLG_MSG_DOWN, DL_DATA | REQUEST,
0, len, msg, TIMEOUT_1SEC);
/* if here is outgoing data, send first part */
switch (di->func) {
case 0:
case 2:
case 5:
if (di->play > -1)
play_msg(di);
break;
case 1:
/* send next after 2 sec */
timeout = 2*TIMEOUT_1SEC;
di->flag |= FLG_SEND_TONE;
break;
case 3:
case 4:
/* setup B after 1 sec */
timeout = 1*TIMEOUT_1SEC;
break;
}
} else if ((ret > 19) && (buf[19] == MT_CONNECT_ACKNOWLEDGE) &&
(!(di->flag & FLG_CALL_ORGINATE))) {
/* We got connect ack, so bring B-channel up */
if (!(di->flag & FLG_BCHANNEL_EARLY)) {
if (!(di->flag & FLG_BCHANNEL_ACTDELAYED))
activate_bchan(di);
else
di->flag |= FLG_BCHANNEL_DOACTIVE;
}
/* if here is outgoing data, send first part */
switch (di->func) {
case 0:
case 2:
case 5:
if (di->play > -1)
play_msg(di);
break;
case 1:
/* send next after 2 sec */
timeout = 2*TIMEOUT_1SEC;
di->flag |= FLG_SEND_TONE;
break;
case 3:
case 4:
/* setup B after 1 sec */
timeout = 1*TIMEOUT_1SEC;
break;
}
} else if ((ret > 19) && (buf[19] == MT_DISCONNECT)) {
/* send a RELEASE */
p = msg = buf + mISDN_HEADER_LEN;
MsgHead(p, di->cr, MT_RELEASE);
len = p - msg;
ret = mISDN_write_frame(di->device, buf,
di->layer3 | FLG_MSG_TARGET | FLG_MSG_DOWN, DL_DATA | REQUEST,
0, len, msg, TIMEOUT_1SEC);
} else if ((ret > 19) && (buf[19] == MT_RELEASE)) {
/* on a disconnecting msg leave loop */
/* send a RELEASE_COMPLETE */
p = msg = buf + mISDN_HEADER_LEN;
MsgHead(p, di->cr, MT_RELEASE_COMPLETE);
len = p - msg;
ret = mISDN_write_frame(di->device, buf,
di->layer3 | FLG_MSG_TARGET | FLG_MSG_DOWN, DL_DATA | REQUEST,
0, len, msg, TIMEOUT_1SEC);
return(2);
} else if ((ret > 19) && (buf[19] == MT_RELEASE_COMPLETE)) {
/* on a disconnecting msg leave loop */
return(1);
}
}
}
if (di->flag & FLG_SEND_TONE) {
if (di->val) {
di->val--;
send_touchtone(di, tt_char[di->val]);
} else {
/* After last tone disconnect */
p = msg = buf + mISDN_HEADER_LEN;
MsgHead(p, di->cr, MT_DISCONNECT);
len = p - msg;
ret = mISDN_write_frame(di->device, buf,
di->layer3 | FLG_MSG_TARGET | FLG_MSG_DOWN, DL_DATA | REQUEST,
0, len, msg, TIMEOUT_1SEC);
di->flag &= ~FLG_SEND_TONE;
}
goto start_again;
} else if (di->flag & FLG_SEND_DATA) {
if (di->play > -1)
send_data(di);
else
di->flag &= ~FLG_SEND_DATA;
goto start_again;
} else if (di->flag & FLG_BCHANNEL_DOACTIVE) {
ret = activate_bchan(di);
if (!ret) {
fprintf(stdout,"error on activate_bchan\n");
return(0);
}
di->flag &= ~FLG_BCHANNEL_DOACTIVE;
/* send next after 1 sec */
timeout = 1*TIMEOUT_1SEC;
di->flag |= FLG_SEND_DATA;
goto start_again;
}
return(0);
}
int do_connection(devinfo_t *di) {
unsigned char *p, *msg, buf[1024];
iframe_t *rfrm;
int len, idx, ret = 0;
int bchannel;
rfrm = (iframe_t *)buf;
if (strlen(di->phonenr)) {
di->flag |= FLG_CALL_ORGINATE;
di->cr = 0x81;
send_SETUP(di, di->si, di->phonenr);
}
bchannel= -1;
/* Wait for a SETUP message or a CALL_PROCEEDING */
while ((ret = mISDN_read(di->device, buf, 1024, 3*TIMEOUT_10SEC))) {
if (VerifyOn>3)
fprintf(stdout,"readloop ret=%d\n", ret);
if (ret >= 20) {
if (((!(di->flag & FLG_CALL_ORGINATE)) &&
(buf[19] == MT_SETUP)) ||
((di->flag & FLG_CALL_ORGINATE) &&
(buf[19] == MT_CALL_PROCEEDING))) {
if (!(di->flag & FLG_CALL_ORGINATE))
di->cr = buf[18];
idx = 20;
while (idx<ret) {
if (buf[idx] == IE_CHANNEL_ID) {
bchannel=buf[idx+2] & 0x3;
break;
} else if (!(buf[idx] & 0x80)) {
/* variable len IE */
idx++;
idx += buf[idx];
}
idx++;
}
break;
}
}
}
fprintf(stdout,"bchannel %d\n", bchannel);
if (bchannel > 0) {
/* setup a B-channel stack */
di->used_bchannel = bchannel -1;
switch (di->func) {
case 5:
di->flag |= FLG_BCHANNEL_EARLY;
case 0:
case 1:
case 2:
case 3:
case 4:
ret = setup_bchannel(di);
if (ret)
di->flag |= FLG_BCHANNEL_SETUP;
else {
fprintf(stdout,"error on setup_bchannel\n");
goto clean_up;
}
if (di->flag & FLG_BCHANNEL_EARLY) {
ret = activate_bchan(di);
if (!ret) {
fprintf(stdout,"error on activate_bchan\n");
goto clean_up;
}
}
break;
}
if (!(di->flag & FLG_CALL_ORGINATE)) {
p = msg = buf + mISDN_HEADER_LEN;
MsgHead(p, di->cr, MT_CONNECT);
len = p - msg;
ret = mISDN_write_frame(di->device, buf,
di->layer3 | FLG_MSG_TARGET | FLG_MSG_DOWN, DL_DATA | REQUEST,
0, len, msg, TIMEOUT_1SEC);
}
if (!read_mutiplexer(di)) { /* timed out */
/* send a RELEASE_COMPLETE */
fprintf(stdout,"read_mutiplexer timed out sending RELEASE_COMPLETE\n");
p = msg = buf + mISDN_HEADER_LEN;;
MsgHead(p, di->cr, MT_RELEASE_COMPLETE);
len = p - msg;
ret = mISDN_write_frame(di->device, buf,
di->layer3 | FLG_MSG_TARGET | FLG_MSG_DOWN, DL_DATA | REQUEST,
0, len, msg, TIMEOUT_1SEC);
}
deactivate_bchan(di);
} else {
fprintf(stdout,"no channel or no connection\n");
}
clean_up:
sleep(1);
ret = mISDN_write_frame(di->device, buf, di->layer3 | FLG_MSG_TARGET | FLG_MSG_DOWN,
DL_RELEASE | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
if (VerifyOn>3)
fprintf(stdout,"ret=%d\n", ret);
ret = mISDN_read(di->device, buf, 1024, TIMEOUT_10SEC);
if (VerifyOn>3)
fprintf(stdout,"read ret=%d\n", ret);
sleep(1);
ret = mISDN_write_frame(di->device, buf, di->layer3 | FLG_MSG_TARGET | FLG_MSG_DOWN,
MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
if (VerifyOn>3)
fprintf(stdout,"ret=%d\n", ret);
ret = mISDN_read(di->device, buf, 1024, TIMEOUT_10SEC);
if (VerifyOn>3)
fprintf(stdout,"read ret=%d\n", ret);
return(0);
}
int
add_dlayer3(devinfo_t *di, int prot)
{
layer_info_t li;
stack_info_t si;
#ifdef OBSOLETE
interface_info_t ii;
#endif
int ret;
if (di->layer3) {
memset(&si, 0, sizeof(stack_info_t));
si.extentions = EXT_STACK_CLONE;
si.mgr = -1;
si.id = di->d_stid;
ret = mISDN_new_stack(di->device, &si);
if (ret <= 0) {
fprintf(stdout, "clone stack failed ret(%d)\n", ret);
return(11);
}
di->d_stid = ret;
}
memset(&li, 0, sizeof(layer_info_t));
strcpy(&li.name[0], "user L3");
li.object_id = -1;
li.extentions = 0;
li.pid.protocol[3] = prot;
li.pid.layermask = ISDN_LAYER(3);
li.st = di->d_stid;
ret = mISDN_new_layer(di->device, &li);
if (ret<0)
return(12);
di->layer3 = li.id;
if (!di->layer3)
return(13);
#ifdef OBSOLETE
/*
* EXT_IF_CREATE | EXT_IF_EXCLUSIV sorgen dafuer, das wenn die L3
* Schnittstelle schon benutzt ist, eine neue L2 Instanz erzeugt
* wird
*/
ii.extentions = EXT_IF_CREATE | EXT_IF_EXCLUSIV;
ii.owner = di->layer3;
ii.peer = di->layer2;
ii.stat = FLG_MSG_TARGET | FLG_MSG_DOWN;
ret = mISDN_connect(di->device, &ii);
if (ret)
return(13);
ii.owner = di->layer3;
ii.stat = FLG_MSG_TARGET | FLG_MSG_DOWN;
ret = mISDN_get_interface_info(di->device, &ii);
if (ret != 0)
return(14);
if (ii.peer == di->layer2)
fprintf(stdout, "Layer 2 not cloned\n");
else
fprintf(stdout, "Layer 2 %08x cloned from %08x\n",
ii.peer, di->layer2);
di->layer2 = ii.peer;
#endif
return(0);
}
int do_setup(devinfo_t *di) {
unsigned char buf[1024];
iframe_t *frm = (iframe_t *)buf;
int i, ret = 0;
stack_info_t *stinf;
status_info_t *si;
di->bl2_prot = ISDN_PID_L2_B_USER;
di->bl3_prot = ISDN_PID_L3_B_TRANS;
switch (di->func) {
case 0:
case 5:
di->bl1_prot = ISDN_PID_L1_B_64TRANS;
di->si = 1;
break;
case 1:
di->bl1_prot = ISDN_PID_L1_B_64TRANS;
di->bl2_prot = ISDN_PID_L2_B_TRANSDTMF;
di->si = 1;
di->val= 8; /* send 8 touch tons (7 ... 0) */
break;
case 2:
di->bl1_prot = ISDN_PID_L1_B_64TRANS;
di->bl2_prot = ISDN_PID_L2_B_TRANSDTMF;
di->si = 1;
break;
case 3:
di->bl1_prot = ISDN_PID_L1_B_64HDLC;
di->si = 7;
break;
case 4:
fprintf(stdout,"X.75 not supported with L2 user\n");
return(1);
default:
fprintf(stdout,"unknown program function %d\n",
di->func);
return(1);
}
ret = mISDN_get_stack_count(di->device);
if (VerifyOn>1)
fprintf(stdout,"%d stacks found\n", ret);
if (ret < di->cardnr) {
fprintf(stdout,"cannot config card nr %d only %d cards\n",
di->cardnr, ret);
return(2);
}
ret = mISDN_get_stack_info(di->device, di->cardnr, buf, 1024);
if (ret<=0) {
fprintf(stdout,"cannot get stackinfo err: %d\n", ret);
return(3);
}
stinf = (stack_info_t *)&frm->data.p;
if (VerifyOn>1)
mISDNprint_stack_info(stdout, stinf);
di->d_stid = stinf->id;
for (i=0;i<2;i++) {
if (stinf->childcnt>i)
di->b_stid[i] = stinf->child[i];
else
di->b_stid[i] = 0;
}
di->layer1 = mISDN_get_layerid(di->device, di->d_stid, 1);
if (di->layer1<0) {
fprintf(stdout,"cannot get layer1\n");
return(4);
}
if (VerifyOn>1)
fprintf(stdout,"layer1 id %08x\n", di->layer1);
di->layer2 = mISDN_get_layerid(di->device, di->d_stid, 2);
if (di->layer2<0) {
fprintf(stdout,"cannot get layer2\n");
return(5);
}
if (VerifyOn>1)
fprintf(stdout,"layer2 id %08x\n", di->layer2);
di->layer3 = mISDN_get_layerid(di->device, di->d_stid, 3);
if (di->layer3<0) {
fprintf(stdout,"cannot get layer3\n");
di->layer3 = 0;
}
if (VerifyOn>1)
fprintf(stdout,"layer3 id %08x\n", di->layer3);
ret = add_dlayer3(di, ISDN_PID_L3_DSS1USER);
if (ret)
return(ret);
ret = mISDN_write_frame(di->device, buf, di->layer3 | FLG_MSG_TARGET | FLG_MSG_DOWN,
DL_ESTABLISH | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
if (VerifyOn>3)
fprintf(stdout,"dl_etablish write ret=%d\n", ret);
ret = mISDN_read(di->device, buf, 1024, TIMEOUT_10SEC);
if (VerifyOn>3)
fprintf(stdout,"dl_etablish read ret=%d\n", ret);
if (ret>0) {
if (frm->prim != (DL_ESTABLISH | CONFIRM))
return(6);
} else {
fprintf(stdout,"DL_ESTABLISH | REQUEST return(%d)\n", ret);
return(7);
}
ret = mISDN_get_status_info(di->device, di->layer1, buf, 1024);
if (ret > mISDN_HEADER_LEN) {
si = (status_info_t *)&frm->data.p;
mISDNprint_status(stdout, si);
} else
fprintf(stdout,"mISDN_get_status_info ret(%d)\n", ret);
ret = mISDN_get_status_info(di->device, di->layer2, buf, 1024);
if (ret > mISDN_HEADER_LEN) {
si = (status_info_t *)&frm->data.p;
mISDNprint_status(stdout, si);
} else
fprintf(stdout,"mISDN_get_status_info ret(%d)\n", ret);
sleep(1);
return(0);
}
int main(argc,argv)
int argc;
char *argv[];
{
char FileName[200],FileNameOut[200];
int aidx=1,para=1, idx;
char sw;
devinfo_t mISDN;
int err;
fprintf(stderr,"TestmISDN 1.0\n");
strcpy(FileName, "test_file");
memset(&mISDN, 0, sizeof(mISDN));
mISDN.cardnr = 1;
mISDN.func = 0;
mISDN.phonenr[0] = 0;
if (argc<1) {
fprintf(stderr,"Error: Not enough arguments please check\n");
usage(argv[0]);
exit(1);
} else {
do {
if (argv[aidx] && argv[aidx][0]=='-') {
sw=argv[aidx][1];
switch (sw) {
case 'v':
case 'V':
VerifyOn=1;
if (argv[aidx][2]) {
VerifyOn=atol(&argv[aidx][2]);
}
break;
case 'c':
if (argv[aidx][2]) {
mISDN.cardnr=atol(&argv[aidx][2]);
}
break;
case 'F':
if (argv[aidx][2]) {
mISDN.func=atol(&argv[aidx][2]);
}
break;
case 'n':
if (!argv[aidx][2]) {
idx = 0;
aidx++;
} else {
idx=2;
}
if (aidx<=argc) {
strcpy(mISDN.phonenr, &argv[aidx][idx]);
} else {
fprintf(stderr," Switch %c without value\n",sw);
exit(1);
}
break;
case '?' :
usage(argv[0]);
exit(1);
break;
default : fprintf(stderr,"Unknown Switch %c\n",sw);
usage(argv[0]);
exit(1);
break;
}
} else {
if (para==1) {
if (argc > 1)
strcpy(FileName,argv[aidx]);
para++;
} else {
fprintf(stderr,"Undefined argument %s\n",argv[aidx]);
usage(argv[0]);
exit(1);
}
}
aidx++;
} while (aidx<argc);
}
if (0>(mISDN.device = mISDN_open())) {
printf("TestmISDN cannot open mISDN due to %s\n",
strerror(errno));
return(1);
}
sprintf(FileNameOut,"%s.out",FileName);
sprintf(FileName,"%s.in",FileName);
if (0>(mISDN.save = open(FileName, O_WRONLY|O_CREAT|O_TRUNC,S_IRWXU))) {
printf("TestmISDN cannot open %s due to %s\n",FileName,
strerror(errno));
close(mISDN.device);
return(1);
}
if (0>(mISDN.play = open(FileNameOut, O_RDONLY))) {
printf("TestmISDN cannot open %s due to %s\n",FileNameOut,
strerror(errno));
mISDN.play = -1;
} else
mISDN.fplay = fdopen(mISDN.play, "r");
if (VerifyOn>8)
fprintf(stdout,"fileno %d/%d/%d\n",mISDN.save, mISDN.play,
mISDN.device);
err = do_setup(&mISDN);
if (err)
fprintf(stdout,"do_setup error %d\n", err);
else
do_connection(&mISDN);
close(mISDN.save);
if (mISDN.play>=0)
close(mISDN.play);
err=mISDN_close(mISDN.device);
if (err)
fprintf(stdout,"mISDN_close: error(%d): %s\n", err,
strerror(err));
return(0);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

967
example/testnet.c Normal file
View File

@ -0,0 +1,967 @@
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include "mISDNlib.h"
#include "l3dss1.h"
unsigned char ulaw_to_Alaw[256] = {
0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d,
0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25,
0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d,
0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35,
0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d, 0x02,
0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x1a,
0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x12,
0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x6b,
0x68, 0x69, 0x6e, 0x6f, 0x6c, 0x6d, 0x62, 0x63,
0x60, 0x61, 0x66, 0x67, 0x64, 0x65, 0x7b, 0x79,
0x7e, 0x7f, 0x7c, 0x7d, 0x72, 0x73, 0x70, 0x71,
0x76, 0x77, 0x74, 0x75, 0x4b, 0x49, 0x4f, 0x4d,
0x42, 0x43, 0x40, 0x41, 0x46, 0x47, 0x44, 0x45,
0x5a, 0x5b, 0x58, 0x59, 0x5e, 0x5f, 0x5c, 0x5d,
0x52, 0x52, 0x53, 0x53, 0x50, 0x50, 0x51, 0x51,
0x56, 0x56, 0x57, 0x57, 0x54, 0x54, 0x55, 0xd5,
0xaa, 0xab, 0xa8, 0xa9, 0xae, 0xaf, 0xac, 0xad,
0xa2, 0xa3, 0xa0, 0xa1, 0xa6, 0xa7, 0xa4, 0xa5,
0xba, 0xbb, 0xb8, 0xb9, 0xbe, 0xbf, 0xbc, 0xbd,
0xb2, 0xb3, 0xb0, 0xb1, 0xb6, 0xb7, 0xb4, 0xb5,
0x8b, 0x88, 0x89, 0x8e, 0x8f, 0x8c, 0x8d, 0x82,
0x83, 0x80, 0x81, 0x86, 0x87, 0x84, 0x85, 0x9a,
0x9b, 0x98, 0x99, 0x9e, 0x9f, 0x9c, 0x9d, 0x92,
0x93, 0x90, 0x91, 0x96, 0x97, 0x94, 0x95, 0xeb,
0xe8, 0xe9, 0xee, 0xef, 0xec, 0xed, 0xe2, 0xe3,
0xe0, 0xe1, 0xe6, 0xe7, 0xe4, 0xe5, 0xfb, 0xf9,
0xfe, 0xff, 0xfc, 0xfd, 0xf2, 0xf3, 0xf0, 0xf1,
0xf6, 0xf7, 0xf4, 0xf5, 0xcb, 0xc9, 0xcf, 0xcd,
0xc2, 0xc3, 0xc0, 0xc1, 0xc6, 0xc7, 0xc4, 0xc5,
0xda, 0xdb, 0xd8, 0xd9, 0xde, 0xdf, 0xdc, 0xdd,
0xd2, 0xd2, 0xd3, 0xd3, 0xd0, 0xd0, 0xd1, 0xd1,
0xd6, 0xd6, 0xd7, 0xd7, 0xd4, 0xd4, 0xd5, 0xd5,
};
unsigned char Alaw_to_ulaw[256] = {
0x29, 0x2a, 0x27, 0x28, 0x2d, 0x2e, 0x2b, 0x2c,
0x21, 0x22, 0x1f, 0x20, 0x25, 0x26, 0x23, 0x24,
0x39, 0x3a, 0x37, 0x38, 0x3d, 0x3e, 0x3b, 0x3c,
0x31, 0x32, 0x2f, 0x30, 0x35, 0x36, 0x33, 0x34,
0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d,
0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05,
0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d,
0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15,
0x62, 0x63, 0x60, 0x61, 0x66, 0x67, 0x64, 0x65,
0x5d, 0x5d, 0x5c, 0x5c, 0x5f, 0x5f, 0x5e, 0x5e,
0x74, 0x76, 0x70, 0x72, 0x7c, 0x7e, 0x78, 0x7a,
0x6a, 0x6b, 0x68, 0x69, 0x6e, 0x6f, 0x6c, 0x6d,
0x48, 0x49, 0x46, 0x47, 0x4c, 0x4d, 0x4a, 0x4b,
0x40, 0x41, 0x3f, 0x3f, 0x44, 0x45, 0x42, 0x43,
0x56, 0x57, 0x54, 0x55, 0x5a, 0x5b, 0x58, 0x59,
0x4f, 0x4f, 0x4e, 0x4e, 0x52, 0x53, 0x50, 0x51,
0xa9, 0xaa, 0xa7, 0xa8, 0xad, 0xae, 0xab, 0xac,
0xa1, 0xa2, 0x9f, 0xa0, 0xa5, 0xa6, 0xa3, 0xa4,
0xb9, 0xba, 0xb7, 0xb8, 0xbd, 0xbe, 0xbb, 0xbc,
0xb1, 0xb2, 0xaf, 0xb0, 0xb5, 0xb6, 0xb3, 0xb4,
0x8a, 0x8b, 0x88, 0x89, 0x8e, 0x8f, 0x8c, 0x8d,
0x82, 0x83, 0x80, 0x81, 0x86, 0x87, 0x84, 0x85,
0x9a, 0x9b, 0x98, 0x99, 0x9e, 0x9f, 0x9c, 0x9d,
0x92, 0x93, 0x90, 0x91, 0x96, 0x97, 0x94, 0x95,
0xe2, 0xe3, 0xe0, 0xe1, 0xe6, 0xe7, 0xe4, 0xe5,
0xdd, 0xdd, 0xdc, 0xdc, 0xdf, 0xdf, 0xde, 0xde,
0xf4, 0xf6, 0xf0, 0xf2, 0xfc, 0xfe, 0xf8, 0xfa,
0xea, 0xeb, 0xe8, 0xe9, 0xee, 0xef, 0xec, 0xed,
0xc8, 0xc9, 0xc6, 0xc7, 0xcc, 0xcd, 0xca, 0xcb,
0xc0, 0xc1, 0xbf, 0xbf, 0xc4, 0xc5, 0xc2, 0xc3,
0xd6, 0xd7, 0xd4, 0xd5, 0xda, 0xdb, 0xd8, 0xd9,
0xcf, 0xcf, 0xce, 0xce, 0xd2, 0xd3, 0xd0, 0xd1,
};
void usage(pname)
char *pname;
{
fprintf(stderr,"Call with %s [options] [filename]\n",pname);
fprintf(stderr,"\n");
fprintf(stderr," filename filename.in incoming data\n");
fprintf(stderr," filename.out outgoing data\n");
fprintf(stderr," data is sun audio 8khz 8bi for voice\n");
fprintf(stderr,"\n");
fprintf(stderr,"\n Valid options are:\n");
fprintf(stderr,"\n");
fprintf(stderr," -? Usage ; printout this information\n");
fprintf(stderr," -c<n> use card number n (default 1)\n");
fprintf(stderr," -d <text> Display text (default \"Test Display\")\n");
fprintf(stderr," -m <number> Called PN (default 789)\n");
fprintf(stderr," -n <number> Calling PN (default keine)\n");
fprintf(stderr," -F<n> use function n (default 0)\n");
fprintf(stderr," 0 outgoing call\n");
fprintf(stderr," 1 incomming call\n");
fprintf(stderr," -vn Printing debug info level n\n");
fprintf(stderr,"\n");
}
typedef struct _devinfo {
int device;
int cardnr;
int func;
char phonenr[32];
char display[32];
char msn[32];
int d_stid;
int layer1;
int layer2;
int layer3;
int b_stid[2];
int b_adress[2];
int used_bchannel;
int save;
int play;
FILE *fplay;
int flag;
int val;
int cr;
int si;
int bl1_prot;
int bl2_prot;
int bl3_prot;
} devinfo_t;
#define FLG_SEND_TONE 0x0001
#define FLG_SEND_DATA 0x0002
#define FLG_BCHANNEL_SETUP 0x0010
#define FLG_BCHANNEL_DOACTIVE 0x0020
#define FLG_BCHANNEL_ACTIVE 0x0040
#define FLG_BCHANNEL_ACTDELAYED 0x0080
#define FLG_CALL_ORGINATE 0x0100
#define MAX_REC_BUF 4000
#define MAX_DATA_BUF 1024
static int VerifyOn=0;
char tt_char[]="0123456789ABCD*#";
#define PLAY_SIZE 64
#define MsgHead(ptr, cref, mty) \
*ptr++ = 0x8; \
if (cref == -1) { \
*ptr++ = 0x0; \
} else { \
*ptr++ = 0x1; \
*ptr++ = cref^0x80; \
} \
*ptr++ = mty
int save_alaw(devinfo_t *di, unsigned char *buf, int len) {
int i;
unsigned char *p = buf;
for (i=0; i<len; i++) {
*p = ulaw_to_Alaw[*p];
p++;
}
write(di->save, buf, len);
return(len);
}
int play_msg(devinfo_t *di) {
unsigned char buf[PLAY_SIZE+mISDN_HEADER_LEN], *p;
iframe_t *frm = (iframe_t *)buf;
int len, ret, i;
if (di->play<0)
return(0);
len = read(di->play, buf + mISDN_HEADER_LEN, PLAY_SIZE);
if (len<0) {
printf("play_msg err %d: \"%s\"\n", errno, strerror(errno));
close(di->play);
di->play = -1;
}
p = buf + mISDN_HEADER_LEN;
for (i=0; i<len; i++) {
*p = Alaw_to_ulaw[*p];
p++;
}
frm->addr = di->b_adress[di->used_bchannel] | FLG_MSG_TARGET | FLG_MSG_DOWN;
frm->prim = DL_DATA | REQUEST;
frm->dinfo = 0;
frm->len = len;
ret = mISDN_write(di->device, buf, len+mISDN_HEADER_LEN, 8000);
if (ret < 0)
fprintf(stdout,"play write error %d %s\n", errno, strerror(errno));
else if (VerifyOn>3)
fprintf(stdout,"play write ret=%d\n", ret);
return(ret);
}
int send_data(devinfo_t *di) {
unsigned char buf[MAX_DATA_BUF+mISDN_HEADER_LEN];
iframe_t *frm = (iframe_t *)buf;
unsigned char *data;
int len, ret;
if (di->play<0 || !di->fplay)
return(0);
if (!(data = fgets(buf + mISDN_HEADER_LEN, MAX_DATA_BUF, di->fplay))) {
close(di->play);
di->play = -1;
data = buf + mISDN_HEADER_LEN;
data[0] = 4; /* ctrl-D */
data[1] = 0;
}
len = strlen(data);
if (len==0) {
close(di->play);
di->play = -1;
data[0] = 4; /* ctrl-D */
len = 1;
}
frm->addr = di->b_adress[di->used_bchannel] | FLG_MSG_TARGET | FLG_MSG_DOWN;
frm->prim = DL_DATA | REQUEST;
frm->dinfo = 0;
frm->len = len;
ret = mISDN_write(di->device, buf, len+mISDN_HEADER_LEN, 100000);
if (ret < 0)
fprintf(stdout,"send_data write error %d %s\n", errno, strerror(errno));
else if (VerifyOn>3)
fprintf(stdout,"send_data write ret=%d\n", ret);
return(ret);
}
int setup_bchannel(devinfo_t *di) {
mISDN_pid_t pid;
int ret;
layer_info_t li;
if ((di->used_bchannel<0) || (di->used_bchannel>1)) {
fprintf(stdout, "wrong channel %d\n", di->used_bchannel);
return(0);
}
memset(&li, 0, sizeof(layer_info_t));
strcpy(&li.name[0], "B L3");
li.object_id = -1;
li.extentions = 0;
li.pid.protocol[3] = di->bl3_prot;
li.pid.layermask = ISDN_LAYER(3);
li.st = di->b_stid[di->used_bchannel];
ret = mISDN_new_layer(di->device, &li);
if (ret<0) {
fprintf(stdout, "new_layer ret(%d)\n", ret);
return(0);
}
if (ret) {
di->b_adress[di->used_bchannel] = ret;
if (VerifyOn>2)
fprintf(stdout,"b_adress%d %08x\n",
di->used_bchannel+1, ret);
memset(&pid, 0, sizeof(mISDN_pid_t));
pid.protocol[1] = di->bl1_prot;
pid.protocol[2] = di->bl2_prot;
pid.protocol[3] = di->bl3_prot;
pid.layermask = ISDN_LAYER(1) | ISDN_LAYER(2)| ISDN_LAYER(3);
if (di->flag & FLG_CALL_ORGINATE)
pid.global = 1;
ret = mISDN_set_stack(di->device,
di->b_stid[di->used_bchannel], &pid);
if (ret) {
fprintf(stdout, "set_stack ret(%d)\n", ret);
return(0);
}
ret = di->b_adress[di->used_bchannel];
}
return(ret);
}
int send_SETUP(devinfo_t *di, int SI, char *PNr) {
unsigned char *np, *p, *msg, buf[1024];
int len, ret;
p = msg = buf + mISDN_HEADER_LEN;
MsgHead(p, di->cr, MT_SETUP);
*p++ = 0xa1; /* complete indicator */
*p++ = IE_BEARER;
if (SI == 1) { /* Audio */
*p++ = 0x3; /* Length */
*p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */
*p++ = 0x90; /* Circuit-Mode 64kbps */
*p++ = 0xa3; /* A-Law Audio */
} else { /* default Datatransmission 64k */
*p++ = 0x2; /* Length */
*p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inf */
*p++ = 0x90; /* Circuit-Mode 64kbps */
}
*p++ = IE_CHANNEL_ID;
*p++ = 0x1; /* Length */
*p++ = 0x80 | (1 + di->used_bchannel);
if (strlen(di->display)) {
*p++ = IE_DISPLAY;
*p++ = strlen(di->display);
np = di->display;
while(*np)
*p++ = *np++ & 0x7f;
}
if (strlen(di->msn)) {
*p++ = IE_CALLING_PN;
*p++ = strlen(PNr) +2;
*p++ = 0x01;
*p++ = 0x80;
np = PNr;
while(*np)
*p++ = *np++ & 0x7f;
}
if (PNr && strlen(PNr)) {
*p++ = IE_CALLED_PN;
np = di->msn;
*p++ = strlen(np) + 1;
/* Classify as AnyPref. */
*p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
while (*np)
*p++ = *np++ & 0x7f;
}
len = p - msg;
ret = mISDN_write_frame(di->device, buf, di->layer3 | FLG_MSG_TARGET | FLG_MSG_DOWN,
DL_UNITDATA | REQUEST, 0, len, msg, TIMEOUT_1SEC);
return(ret);
}
int activate_bchan(devinfo_t *di) {
unsigned char buf[128];
iframe_t *rfrm;
int ret;
ret = mISDN_write_frame(di->device, buf,
di->b_adress[di->used_bchannel] | FLG_MSG_TARGET | FLG_MSG_DOWN,
DL_ESTABLISH | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
if (VerifyOn>3)
fprintf(stdout,"DL_ESTABLISH write ret=%d\n", ret);
ret = mISDN_read(di->device, buf, 128, TIMEOUT_10SEC);
if (VerifyOn>3)
fprintf(stdout,"DL_ESTABLISH read ret=%d\n", ret);
rfrm = (iframe_t *)buf;
if (ret>0) {
if (rfrm->prim == (DL_ESTABLISH | CONFIRM)) {
di->flag |= FLG_BCHANNEL_ACTIVE;
}
}
return(ret);
}
int deactivate_bchan(devinfo_t *di) {
unsigned char buf[128];
int ret;
ret = mISDN_write_frame(di->device, buf,
di->b_adress[di->used_bchannel] | FLG_MSG_TARGET | FLG_MSG_DOWN,
DL_RELEASE | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
if (VerifyOn>3)
fprintf(stdout,"DL_RELEASE write ret=%d\n", ret);
ret = mISDN_read(di->device, buf, 128, TIMEOUT_10SEC);
if (VerifyOn>3)
fprintf(stdout,"DL_RELEASE read ret=%d\n", ret);
di->flag &= ~FLG_BCHANNEL_ACTIVE;
di->flag &= ~FLG_BCHANNEL_SETUP;
ret = mISDN_clear_stack(di->device, di->b_stid[di->used_bchannel]);
if (VerifyOn>3)
fprintf(stdout,"clear_stack ret=%d\n", ret);
return(ret);
}
int send_touchtone(devinfo_t *di, int tone) {
iframe_t frm;
int tval, ret;
if (VerifyOn>1)
fprintf(stdout,"send_touchtone %c\n", DTMF_TONE_MASK & tone);
tval = DTMF_TONE_VAL | tone;
ret = mISDN_write_frame(di->device, &frm,
di->b_adress[di->used_bchannel] | FLG_MSG_TARGET | FLG_MSG_DOWN,
PH_CONTROL | REQUEST, 0, 4, &tval, TIMEOUT_1SEC);
if (VerifyOn>3)
fprintf(stdout,"tt send ret=%d\n", ret);
return(ret);
}
int read_mutiplexer(devinfo_t *di) {
unsigned char *p, *msg, buf[MAX_REC_BUF];
iframe_t *rfrm;
int timeout = TIMEOUT_10SEC;
int ret = 0;
int len;
rfrm = (iframe_t *)buf;
/* Main loop */
start_again:
while ((ret = mISDN_read(di->device, buf, MAX_REC_BUF, timeout))) {
if (VerifyOn>3)
fprintf(stdout,"readloop ret=%d\n", ret);
if (ret >= 16) {
if (VerifyOn>4)
fprintf(stdout,"readloop addr(%x) prim(%x) len(%d)\n",
rfrm->addr, rfrm->prim, rfrm->len);
if (rfrm->addr == (di->b_adress[di->used_bchannel] | FLG_MSG_TARGET | FLG_MSG_DOWN)) {
/* B-Channel related messages */
if (rfrm->prim == (DL_DATA | INDICATION)) {
/* received data, save it */
save_alaw(di, (unsigned char *)&rfrm->data.i,
rfrm->len);
} else if (rfrm->prim == (DL_DATA | CONFIRM)) {
/* get ACK of send data, so we can
* send more
*/
if (VerifyOn>5)
fprintf(stdout,"DL_DATA_CNF\n");
switch (di->func) {
case 0:
case 1:
if (di->play > -1)
play_msg(di);
break;
}
} else if (rfrm->prim == (PH_CONTROL | INDICATION)) {
if ((rfrm->len == 4) &&
((rfrm->data.i & ~DTMF_TONE_MASK)
== DTMF_TONE_VAL)) {
fprintf(stdout,"GOT TT %c\n",
DTMF_TONE_MASK & rfrm->data.i);
} else
fprintf(stdout,"unknown PH_CONTROL len %d/val %x\n",
rfrm->len, rfrm->data.i);
}
/* D-Channel related messages */
} else if ((ret > 19) && (buf[19] == MT_CONNECT) &&
(di->flag & FLG_CALL_ORGINATE)) {
/* We got connect, so bring B-channel up */
if (!(di->flag & FLG_BCHANNEL_ACTDELAYED))
activate_bchan(di);
else
di->flag |= FLG_BCHANNEL_DOACTIVE;
/* send a CONNECT_ACKNOWLEDGE */
p = msg = buf + mISDN_HEADER_LEN;
MsgHead(p, di->cr, MT_CONNECT_ACKNOWLEDGE);
len = p - msg;
ret = mISDN_write_frame(di->device, buf,
di->layer3 | FLG_MSG_TARGET | FLG_MSG_DOWN, DL_DATA | REQUEST,
0, len, msg, TIMEOUT_1SEC);
/* if here is outgoing data, send first part */
switch (di->func) {
case 0:
case 1:
if (di->play > -1)
play_msg(di);
break;
}
} else if ((ret > 19) && (buf[19] == MT_CONNECT_ACKNOWLEDGE) &&
(!(di->flag & FLG_CALL_ORGINATE))) {
/* We got connect ack, so bring B-channel up */
if (!(di->flag & FLG_BCHANNEL_ACTDELAYED))
activate_bchan(di);
else
di->flag |= FLG_BCHANNEL_DOACTIVE;
/* if here is outgoing data, send first part */
switch (di->func) {
case 0:
case 1:
if (di->play > -1)
play_msg(di);
break;
}
} else if ((ret > 19) && (buf[19] == MT_DISCONNECT)) {
/* send a RELEASE */
p = msg = buf + mISDN_HEADER_LEN;
MsgHead(p, di->cr, MT_RELEASE);
len = p - msg;
ret = mISDN_write_frame(di->device, buf,
di->layer3 | FLG_MSG_TARGET | FLG_MSG_DOWN, DL_DATA | REQUEST,
0, len, msg, TIMEOUT_1SEC);
} else if ((ret > 19) && (buf[19] == MT_RELEASE)) {
/* on a disconnecting msg leave loop */
/* send a RELEASE_COMPLETE */
p = msg = buf + mISDN_HEADER_LEN;
MsgHead(p, di->cr, MT_RELEASE_COMPLETE);
len = p - msg;
ret = mISDN_write_frame(di->device, buf,
di->layer3 | FLG_MSG_TARGET | FLG_MSG_DOWN, DL_DATA | REQUEST,
0, len, msg, TIMEOUT_1SEC);
return(2);
} else if ((ret > 19) && (buf[19] == MT_RELEASE_COMPLETE)) {
/* on a disconnecting msg leave loop */
return(1);
}
}
}
if (di->flag & FLG_SEND_TONE) {
if (di->val) {
di->val--;
send_touchtone(di, tt_char[di->val]);
} else {
/* After last tone disconnect */
p = msg = buf + mISDN_HEADER_LEN;
MsgHead(p, di->cr, MT_DISCONNECT);
len = p - msg;
ret = mISDN_write_frame(di->device, buf,
di->layer3 | FLG_MSG_TARGET | FLG_MSG_DOWN, DL_DATA | REQUEST,
0, len, msg, TIMEOUT_1SEC);
di->flag &= ~FLG_SEND_TONE;
}
goto start_again;
} else if (di->flag & FLG_SEND_DATA) {
if (di->play > -1)
send_data(di);
else
di->flag &= ~FLG_SEND_DATA;
goto start_again;
} else if (di->flag & FLG_BCHANNEL_DOACTIVE) {
ret = activate_bchan(di);
if (!ret) {
fprintf(stdout,"error on activate_bchan\n");
return(0);
}
di->flag &= ~FLG_BCHANNEL_DOACTIVE;
/* send next after 1 sec */
timeout = 1*TIMEOUT_1SEC;
di->flag |= FLG_SEND_DATA;
goto start_again;
}
return(0);
}
int do_connection(devinfo_t *di) {
unsigned char *p, *msg, buf[1024];
iframe_t *rfrm;
int len, idx, ret = 0;
int bchannel;
time_t tim;
struct tm *ts;
rfrm = (iframe_t *)buf;
if (di->func == 0) {
di->flag |= FLG_CALL_ORGINATE;
di->cr = 0x81;
send_SETUP(di, di->si, di->phonenr);
}
bchannel= di->used_bchannel + 1;
/* Wait for a SETUP message or a CALL_PROCEEDING */
while ((ret = mISDN_read(di->device, buf, 1024, 3*TIMEOUT_10SEC))) {
if (VerifyOn>3)
fprintf(stdout,"readloop ret=%d\n", ret);
if (ret >= 20) {
if (((!(di->flag & FLG_CALL_ORGINATE)) &&
(buf[19] == MT_SETUP)) ||
((di->flag & FLG_CALL_ORGINATE) &&
(buf[19] == MT_ALERTING))) {
if (!(di->flag & FLG_CALL_ORGINATE))
di->cr = buf[18];
idx = 20;
break;
}
}
}
fprintf(stdout,"bchannel %d\n", bchannel);
if (bchannel > 0) {
/* setup a B-channel stack */
switch (di->func) {
case 0:
case 1:
case 2:
case 3:
case 4:
ret = setup_bchannel(di);
if (ret)
di->flag |= FLG_BCHANNEL_SETUP;
else {
fprintf(stdout,"error on setup_bchannel\n");
goto clean_up;
}
break;
}
if (!(di->flag & FLG_CALL_ORGINATE)) {
p = msg = buf + mISDN_HEADER_LEN;
MsgHead(p, di->cr, MT_CONNECT);
time(&tim);
ts = localtime(&tim);
if (ts->tm_year > 99)
ts->tm_year -=100;
printf("Time %d:%d %d/%d/%d\n",
ts->tm_hour, ts->tm_min,
ts->tm_mday, ts->tm_mon+1, ts->tm_year);
*p++ = IE_CHANNEL_ID;
*p++ = 0x1; /* Length */
*p++ = 0x80 | (1 + di->used_bchannel);
*p++ = IE_DISPLAY;
*p++ = strlen(di->display);
for (idx=0; idx < strlen(di->display); idx++)
*p++ = di->display[idx];
*p++ = IE_DATE;
*p++ = 5;
*p++ = ts->tm_year;
*p++ = ts->tm_mon+1;
*p++ = ts->tm_mday;
*p++ = ts->tm_hour;
*p++ = ts->tm_min;
len = p - msg;
ret = mISDN_write_frame(di->device, buf,
di->layer3 | FLG_MSG_TARGET | FLG_MSG_DOWN, DL_DATA | REQUEST,
0, len, msg, TIMEOUT_1SEC);
}
if (!read_mutiplexer(di)) { /* timed out */
/* send a RELEASE_COMPLETE */
fprintf(stdout,"read_mutiplexer timed out sending RELEASE_COMPLETE\n");
p = msg = buf + mISDN_HEADER_LEN;;
MsgHead(p, di->cr, MT_RELEASE_COMPLETE);
len = p - msg;
ret = mISDN_write_frame(di->device, buf,
di->layer3 | FLG_MSG_TARGET | FLG_MSG_DOWN, DL_DATA | REQUEST,
0, len, msg, TIMEOUT_1SEC);
}
deactivate_bchan(di);
} else {
fprintf(stdout,"no channel or no connection\n");
}
clean_up:
sleep(1);
ret = mISDN_write_frame(di->device, buf, di->layer3 | FLG_MSG_TARGET | FLG_MSG_DOWN,
DL_RELEASE | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
if (VerifyOn>3)
fprintf(stdout,"ret=%d\n", ret);
ret = mISDN_read(di->device, buf, 1024, TIMEOUT_10SEC);
if (VerifyOn>3)
fprintf(stdout,"read ret=%d\n", ret);
sleep(1);
ret = mISDN_write_frame(di->device, buf, di->layer3 | FLG_MSG_TARGET | FLG_MSG_DOWN,
MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
if (VerifyOn>3)
fprintf(stdout,"ret=%d\n", ret);
ret = mISDN_read(di->device, buf, 1024, TIMEOUT_10SEC);
if (VerifyOn>3)
fprintf(stdout,"read ret=%d\n", ret);
return(0);
}
int
add_dlayer3(devinfo_t *di, int prot)
{
layer_info_t li;
stack_info_t si;
#ifdef OBSOLETE
interface_info_t ii;
#endif
int lid, ret;
if (di->layer3) {
memset(&si, 0, sizeof(stack_info_t));
si.extentions = EXT_STACK_CLONE;
si.mgr = -1;
si.id = di->d_stid;
ret = mISDN_new_stack(di->device, &si);
if (ret <= 0) {
fprintf(stdout, "clone stack failed ret(%d)\n", ret);
return(11);
}
di->d_stid = ret;
}
memset(&li, 0, sizeof(layer_info_t));
strcpy(&li.name[0], "user L3");
li.object_id = -1;
li.extentions = 0;
li.pid.protocol[3] = prot;
li.pid.layermask = ISDN_LAYER(3);
li.st = di->d_stid;
lid = mISDN_new_layer(di->device, &li);
if (lid<0)
return(12);
di->layer3 = lid;
if (!di->layer3)
return(13);
#ifdef OBSOLETE
/*
* EXT_IF_CREATE | EXT_IF_EXCLUSIV sorgen dafuer, das wenn die L3
* Schnittstelle schon benutzt ist, eine neue L2 Instanz erzeugt
* wird
*/
ii.extentions = EXT_IF_CREATE | EXT_IF_EXCLUSIV;
ii.owner = di->layer3;
ii.peer = di->layer2;
ii.stat = FLG_MSG_TARGET | FLG_MSG_DOWN;
ret = mISDN_connect(di->device, &ii);
if (ret)
return(13);
ii.owner = di->layer3;
ii.stat = FLG_MSG_TARGET | FLG_MSG_DOWN;
ret = mISDN_get_interface_info(di->device, &ii);
if (ret != 0)
return(14);
if (ii.peer == di->layer2)
fprintf(stdout, "Layer 2 not cloned\n");
else
fprintf(stdout, "Layer 2 %08x cloned from %08x\n",
ii.peer, di->layer2);
di->layer2 = ii.peer;
#endif
return(0);
}
int do_setup(devinfo_t *di) {
unsigned char buf[1024];
iframe_t *frm = (iframe_t *)buf;
int i, ret = 0;
stack_info_t *stinf;
status_info_t *si;
di->bl2_prot = ISDN_PID_L2_B_TRANS;
di->bl3_prot = ISDN_PID_L3_B_TRANS;
di->bl1_prot = ISDN_PID_L1_B_64TRANS;
di->si = 1;
ret = mISDN_get_stack_count(di->device);
if (VerifyOn>1)
fprintf(stdout,"%d stacks found\n", ret);
if (ret < di->cardnr) {
fprintf(stdout,"cannot config card nr %d only %d cards\n",
di->cardnr, ret);
return(2);
}
ret = mISDN_get_stack_info(di->device, di->cardnr, buf, 1024);
if (ret<=0) {
fprintf(stdout,"cannot get stackinfo err: %d\n", ret);
return(3);
}
stinf = (stack_info_t *)&frm->data.p;
if (VerifyOn>1)
mISDNprint_stack_info(stdout, stinf);
di->d_stid = stinf->id;
for (i=0;i<2;i++) {
if (stinf->childcnt>i)
di->b_stid[i] = stinf->child[i];
else
di->b_stid[i] = 0;
}
di->layer1 = mISDN_get_layerid(di->device, di->d_stid, 1);
if (di->layer1<0) {
fprintf(stdout,"cannot get layer1\n");
return(4);
}
if (VerifyOn>1)
fprintf(stdout,"layer1 id %08x\n", di->layer1);
di->layer2 = mISDN_get_layerid(di->device, di->d_stid, 2);
if (di->layer2<0) {
fprintf(stdout,"cannot get layer2\n");
return(5);
}
if (VerifyOn>1)
fprintf(stdout,"layer2 id %08x\n", di->layer2);
di->layer3 = mISDN_get_layerid(di->device, di->d_stid, 3);
if (di->layer3<0) {
fprintf(stdout,"cannot get layer3\n");
di->layer3 = 0;
}
if (VerifyOn>1)
fprintf(stdout,"layer3 id %08x\n", di->layer3);
ret = add_dlayer3(di, ISDN_PID_L3_DSS1NET);
if (ret)
return(ret);
ret = mISDN_write_frame(di->device, buf, di->layer3 | FLG_MSG_TARGET | FLG_MSG_DOWN,
DL_ESTABLISH | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
if (VerifyOn>3)
fprintf(stdout,"dl_etablish write ret=%d\n", ret);
ret = mISDN_read(di->device, buf, 1024, TIMEOUT_1SEC);
if (VerifyOn>3)
fprintf(stdout,"dl_etablish read ret=%d\n", ret);
if (ret>0) {
if (frm->prim != (DL_ESTABLISH | CONFIRM)) {
fprintf(stdout,"DL_ESTABLISH | REQUEST return prim:%x\n",
frm->prim);
// return(6);
}
} else {
fprintf(stdout,"DL_ESTABLISH | REQUEST return(%d)\n", ret);
// return(7);
}
ret = mISDN_get_status_info(di->device, di->layer1, buf, 1024);
if (ret > mISDN_HEADER_LEN) {
si = (status_info_t *)&frm->data.p;
mISDNprint_status(stdout, si);
} else
fprintf(stdout,"mISDN_get_status_info ret(%d)\n", ret);
ret = mISDN_get_status_info(di->device, di->layer2, buf, 1024);
if (ret > mISDN_HEADER_LEN) {
si = (status_info_t *)&frm->data.p;
mISDNprint_status(stdout, si);
} else
fprintf(stdout,"mISDN_get_status_info ret(%d)\n", ret);
sleep(1);
return(0);
}
int main(argc,argv)
int argc;
char *argv[];
{
char FileName[200],FileNameOut[200];
int aidx=1,para=1, idx;
char sw;
devinfo_t mISDN;
int err;
fprintf(stderr,"Test HFCNet 1.0\n");
strcpy(FileName, "test_file");
memset(&mISDN, 0, sizeof(mISDN));
mISDN.cardnr = 1;
mISDN.func = 0;
strcpy(mISDN.display, "Test Display");
strcpy(mISDN.msn, "789");
mISDN.phonenr[0] = 0;
if (argc<1) {
fprintf(stderr,"Error: Not enough arguments please check\n");
usage(argv[0]);
exit(1);
} else {
do {
if (argv[aidx] && argv[aidx][0]=='-') {
sw=argv[aidx][1];
switch (sw) {
case 'v':
case 'V':
VerifyOn=1;
if (argv[aidx][2]) {
VerifyOn=atol(&argv[aidx][2]);
}
break;
case 'c':
if (argv[aidx][2]) {
mISDN.cardnr=atol(&argv[aidx][2]);
}
break;
case 'F':
if (argv[aidx][2]) {
mISDN.func=atol(&argv[aidx][2]);
}
break;
case 'd':
if (!argv[aidx][2]) {
idx = 0;
aidx++;
} else {
idx=2;
}
if (aidx<=argc) {
strcpy(mISDN.display, &argv[aidx][idx]);
} else {
fprintf(stderr," Switch %c without value\n",sw);
exit(1);
}
break;
case 'm':
if (!argv[aidx][2]) {
idx = 0;
aidx++;
} else {
idx=2;
}
if (aidx<=argc) {
strcpy(mISDN.msn, &argv[aidx][idx]);
} else {
fprintf(stderr," Switch %c without value\n",sw);
exit(1);
}
break;
case 'n':
if (!argv[aidx][2]) {
idx = 0;
aidx++;
} else {
idx=2;
}
if (aidx<=argc) {
strcpy(mISDN.phonenr, &argv[aidx][idx]);
} else {
fprintf(stderr," Switch %c without value\n",sw);
exit(1);
}
break;
case '?' :
usage(argv[0]);
exit(1);
break;
default : fprintf(stderr,"Unknown Switch %c\n",sw);
usage(argv[0]);
exit(1);
break;
}
} else {
if (para==1) {
if (argc > 1)
strcpy(FileName,argv[aidx]);
para++;
} else {
fprintf(stderr,"Undefined argument %s\n",argv[aidx]);
usage(argv[0]);
exit(1);
}
}
aidx++;
} while (aidx<argc);
}
if (0>(mISDN.device = mISDN_open())) {
printf("TestmISDN cannot open mISDN due to %s\n",
strerror(errno));
return(1);
}
sprintf(FileNameOut,"%s.out",FileName);
sprintf(FileName,"%s.in",FileName);
printf("TestmISDN open in %s\n",FileName);
if (0>(mISDN.save = open(FileName, O_WRONLY|O_CREAT|O_TRUNC,S_IRWXU))) {
printf("TestmISDN cannot open %s due to %s\n",FileName,
strerror(errno));
close(mISDN.device);
return(1);
}
printf("TestmISDN open out %s\n",FileNameOut);
if (0>(mISDN.play = open(FileNameOut, O_RDONLY))) {
printf("TestmISDN cannot open %s due to %s\n",FileNameOut,
strerror(errno));
mISDN.play = -1;
} else
mISDN.fplay = fdopen(mISDN.play, "r");
printf("TestmISDN files open\n");
if (VerifyOn>8)
fprintf(stdout,"fileno %d/%d/%d\n",mISDN.save, mISDN.play,
mISDN.device);
err = do_setup(&mISDN);
if (err)
fprintf(stdout,"do_setup error %d\n", err);
else
do_connection(&mISDN);
close(mISDN.save);
if (mISDN.play>=0)
close(mISDN.play);
err=mISDN_close(mISDN.device);
if (err)
fprintf(stdout,"mISDN_close: error(%d): %s\n", err,
strerror(err));
return(0);
}

View File

@ -1,5 +0,0 @@
export _MEMLEAKDEBUG
SUBDIRS = qmisdnwatch
CLEANFILES = *~

View File

@ -1,20 +0,0 @@
bin_SCRIPTS = qmisdnwatch$(EXEEXT)
QMISDNWATCH_S = res/16x16-bullet-gray.png res/16x16-bullet-green.png \
res/16x16-bullet-red.png res/16x16-bullet-yellow.png res/icons.qrc \
src/extraWidgets.cpp src/extraWidgets.h src/main.cpp \
src/mainWindow.cpp src/mainWindow.h src/misdn.cpp \
src/misdn.h src/Ql1logThread.cpp src/Ql1logThread.h
AM_CPPFLAGS = -I$(top_srcdir)/include $(_MEMLEAKDEBUG)
CLEANFILES = *~ src/*~ res/*~ Makefile.qt moc_*.cpp qrc_icons.cpp
Makefile.qt: $(srcdir)/qmisdnwatch.pro
$(QMAKE) -o $@ $(srcdir)/qmisdnwatch.pro
qmisdnwatch$(EXEEXT): Makefile.qt $(QMISDNWATCH_S)
$(MAKE) -f Makefile.qt
EXTRA_DIST = $(QMISDNWATCH_S) $(srcdir)/qmisdnwatch.pro

View File

@ -1,40 +0,0 @@
qmisdnwatch
AUTHOR
-------
Martin Bachem
m.bachem@gmx.de
LICENSE
--------
qmisdnwatch is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation version 2
qmisdnwatch is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with qmisdnwatch. If not, see <http://www.gnu.org/licenses/>.
REQUIREMENTS
-------------
mISDN v2
Qt4
COMPILE / RUN
---------------
qmake
make
./qmisdnwatch
DOCs
-----
http://www.misdn.org/index.php/Qmisdnwatch
<end of file>

View File

@ -1,12 +0,0 @@
TEMPLATE = app
TARGET =
DEPENDPATH += . src
INCLUDEPATH += . src ../../include
# not yet ;) LIBS += -lmisdn
# Input
HEADERS += src/mainWindow.h src/misdn.h src/extraWidgets.h src/Ql1logThread.h
SOURCES += src/main.cpp src/mainWindow.cpp src/misdn.cpp src/extraWidgets.cpp src/Ql1logThread.cpp
RESOURCES = res/icons.qrc

Binary file not shown.

Before

Width:  |  Height:  |  Size: 844 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 799 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 798 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 853 B

View File

@ -1,8 +0,0 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file alias="gray.png">16x16-bullet-gray.png</file>
<file alias="green.png">16x16-bullet-green.png</file>
<file alias="red.png">16x16-bullet-red.png</file>
<file alias="yellow.png">16x16-bullet-yellow.png</file>
</qresource>
</RCC>

View File

@ -1,189 +0,0 @@
/* $Id: Ql1logThread.cpp 10 2008-10-31 12:58:01Z daxtar $
* (c) 2008 Martin Bachem, m.bachem@gmx.de
*
* This file is part of qmisdnwatch
*
* Project's Home
* http://www.misdn.org/index.php/Qmisdnwatch
*
* qmisdnwatch is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2
*
* qmisdnwatch is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with qmisdnwatch. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <QByteArray>
#include <QInputDialog>
#include <sys/ioctl.h>
#include "misdn.h"
#include "Ql1logThread.h"
void Ql1logThread::run(void)
{
qDebug("Ql1logThread::run socket(%i) devId(%d) proto(%d)",
socket, devId, protocol);
if (isConnected())
{
struct msghdr mh;
struct iovec iov[1];
struct ctstamp cts;
int ret;
int buflen = 512;
unsigned char buffer[buflen];
while (1) {
mh.msg_name = NULL;
mh.msg_namelen = 0;
mh.msg_iov = iov;
mh.msg_iovlen = 1;
mh.msg_control = &cts;
mh.msg_controllen = sizeof(cts);
mh.msg_flags = 0;
iov[0].iov_base = buffer;
iov[0].iov_len = buflen;
ret = recvmsg(socket, &mh, 0);
if (ret >= 0) {
if (cts.cmsg_type != MISDN_TIME_STAMP) {
cts.tv.tv_sec = 0;
cts.tv.tv_usec = 0;
}
QByteArray * data = new QByteArray((const char *)buffer, ret);
emit rcvData(devId, *data, cts.tv);
}
}
} else
qDebug("ERROR socket not connected...");
}
bool Ql1logThread::connectLayer1(struct mISDN_devinfo *devInfo) {
if (isConnected())
return true;
protocol = devInfo->protocol;
if (!protocol) {
QStringList items;
bool Ok;
if (devInfo->Dprotocols & (1 << ISDN_P_TE_S0))
items << "TE mode S0 layer1";
if (devInfo->Dprotocols & (1 << ISDN_P_NT_S0))
items << "NT mode S0 layer1";
if (devInfo->Dprotocols & (1 << ISDN_P_TE_E1))
items << "TE mode E1 layer1";
if (devInfo->Dprotocols & (1 << ISDN_P_NT_E1))
items << "NT mode E1 layer1";
if (devInfo->Dprotocols & (1 << ISDN_P_TE_UP0))
items << "TE mode UP0 layer1";
if (devInfo->Dprotocols & (1 << ISDN_P_NT_UP0))
items << "NT mode UP0 layer1";
QString value = QInputDialog::getItem(NULL,
QString(devInfo->name),
tr("port still unused, please select layer1 mode:"),
items, 0, false, &Ok);
if (Ok && !value.isEmpty()) {
if (value == "TE mode S0 layer1")
setProtocol(ISDN_P_TE_S0);
if (value == "NT mode S0 layer1")
setProtocol(ISDN_P_NT_S0);
if (value == "TE mode E1 layer1")
setProtocol(ISDN_P_TE_E1);
if (value == "NT mode E1 layer1")
setProtocol(ISDN_P_NT_E1);
if (value == "TE mode UP0 layer1")
setProtocol(ISDN_P_TE_UP0);
if (value == "NT mode UP0 layer1")
setProtocol(ISDN_P_NT_UP0);
}
}
if (protocol) {
devInfo->protocol = protocol;
dch_echo = misdn.openl1Log(devId, protocol, &socket, &addr);
qDebug("Ql1logThread::connectLayer1 socket(%i) devId(%d) proto(%d)",
socket, devId, protocol);
if (socket >= 0)
start();
}
if (isConnected()) {
emit l1Connected(devId);
return true;
}
return false;
}
bool Ql1logThread::sendActivateReq(void) {
if (isConnected()) {
int ret;
unsigned char buffer[MISDN_HEADER_LEN];
struct mISDNhead * hh = (struct mISDNhead *)buffer;
hh->prim = PH_ACTIVATE_REQ;
hh->id = MISDN_ID_ANY;
ret = sendto(socket, buffer, MISDN_HEADER_LEN, 0, NULL, 0);
return (ret >= 0);
}
return false;
}
bool Ql1logThread::sendInformationReq(void) {
if (isConnected()) {
int ret;
unsigned char buffer[MISDN_HEADER_LEN];
struct mISDNhead * hh = (struct mISDNhead *)buffer;
hh->prim = MPH_INFORMATION_REQ;
hh->id = MISDN_ID_ANY;
ret = sendto(socket, buffer, MISDN_HEADER_LEN, 0, NULL, 0);
return (ret >= 0);
}
return false;
}
bool Ql1logThread::isConnected(void) {
return ((socket >= 0) && isRunning());
}
void Ql1logThread::disconnectLayer1(void) {
close(socket);
terminate();
wait(1000);
socket = -1;
emit l1Disonnected(devId);
qDebug("dev %i layer1 disconnected", devId);
}
void Ql1logThread::setProtocol(int p) {
protocol = p;
qDebug("Ql1logThread protocol %d (%d)", protocol, p);
}
int Ql1logThread::getProtocol(void) {
return protocol;
}
int Ql1logThread::hasEcho(void) {
return (dch_echo);
}
Ql1logThread::Ql1logThread(int id, mISDN & m) : devId(id), misdn(m) {
dch_echo = -1;
socket = -1;
protocol = 0;
connect(this, SIGNAL(finished()), this, SLOT(finish()));
}
Ql1logThread::~Ql1logThread() {
disconnectLayer1();
}
void Ql1logThread::finish() {
emit finished(devId);
}

View File

@ -1,69 +0,0 @@
/* $Id: Ql1logThread.h 10 2008-10-31 12:58:01Z daxtar $
* (c) 2008 Martin Bachem, m.bachem@gmx.de
*
* This file is part of qmisdnwatch
*
* Project's Home
* http://www.misdn.org/index.php/Qmisdnwatch
*
* qmisdnwatch is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2
*
* qmisdnwatch is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with qmisdnwatch. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef _QL1LOGTHREAD_H_
#define _QL1LOGTHREAD_H_
#include <QObject>
#include <QThread>
#include <QByteArray>
#include "misdn.h"
class Ql1logThread : public QThread
{
Q_OBJECT
private:
int devId;
int socket;
struct sockaddr_mISDN addr;
mISDN & misdn;
int protocol;
int dch_echo;
public:
Ql1logThread(int id, mISDN & m);
~Ql1logThread();
bool connectLayer1(struct mISDN_devinfo *devInfo);
void disconnectLayer1(void);
bool isConnected(void);
bool sendActivateReq(void);
bool sendInformationReq(void);
void setProtocol(int p);
int getProtocol(void);
int hasEcho(void);
protected:
void run();
public slots:
void finish();
signals:
void finished(unsigned int id);
void l1Connected(unsigned int id);
void l1Disonnected(unsigned int id);
void rcvData(unsigned int id, QByteArray data, struct timeval);
};
#endif // _QL1LOGTHREAD_H_

View File

@ -1,66 +0,0 @@
/* $Id: extraWidgets.cpp 9 2008-10-30 20:44:26Z daxtar $
* (c) 2008 Martin Bachem, m.bachem@gmx.de
*
* This file is part of qmisdnwatch
*
* Project's Home
* http://www.misdn.org/index.php/Qmisdnwatch
*
* qmisdnwatch is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2
*
* qmisdnwatch is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with qmisdnwatch. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <QObject>
#include <QWidget>
#include <QPushButton>
#include "extraWidgets.h"
/*
* the Widgets below are childs of commmon Qt Widgets, but signal the mISDN
* device ID along with their main action trigger.
*
*/
/* idButton (QPushButton) */
idButton::idButton( const QString& text, QWidget* parent,
unsigned int id)
: QPushButton(text, parent), devId(id) {
connect(this, SIGNAL(clicked()), this, SLOT(click()));
}
void idButton::click() {
emit clicked(devId);
}
/******************************************************************************/
/* idAction (QAction) */
idAction::idAction(const QString & text, QObject * parent,
unsigned int id)
: QAction(text, parent), devId(id) {
connect(this, SIGNAL(triggered()), this, SLOT(trigger()));
}
idAction::idAction(const QIcon & icon, const QString & text, QObject * parent,
unsigned int id)
: QAction(icon, text, parent), devId(id) {
connect(this, SIGNAL(triggered()), this, SLOT(trigger()));
}
void idAction::trigger() {
emit triggered(devId);
}

View File

@ -1,60 +0,0 @@
/* $Id: extraWidgets.h 9 2008-10-30 20:44:26Z daxtar $
* (c) 2008 Martin Bachem, m.bachem@gmx.de
*
* This file is part of qmisdnwatch
*
* Project's Home
* http://www.misdn.org/index.php/Qmisdnwatch
*
* qmisdnwatch is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2
*
* qmisdnwatch is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with qmisdnwatch. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef _EXTRA_WIDGETS_H_
#define _EXTRA_WIDGETS_H_
#include <QPushButton>
#include <QAction>
/* QBushbutton sending mISDN device ID at clicked() signal */
class idButton : public QPushButton {
Q_OBJECT
public:
idButton(const QString& text, QWidget* parent = NULL,
unsigned int id=0);
private:
unsigned int devId;
public slots:
void click();
signals:
void clicked(unsigned int id);
};
/* QAction sending mISDN device ID at clicked() signal */
class idAction : public QAction {
Q_OBJECT
public:
idAction(const QString & text, QObject * parent,
unsigned int id);
idAction(const QIcon & icon, const QString & text,
QObject * parent, unsigned int id);
private:
unsigned int devId;
public slots:
void trigger();
signals:
void triggered(unsigned int id);
};
#endif // _EXTRA_WIDGETS_H_

View File

@ -1,43 +0,0 @@
/* $Id: main.cpp 10 2008-10-31 12:58:01Z daxtar $
* (c) 2008 Martin Bachem, m.bachem@gmx.de
*
* This file is part of qmisdnwatch
*
* Project's Home
* http://www.misdn.org/index.php/Qmisdnwatch
*
* qmisdnwatch is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2
*
* qmisdnwatch is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with qmisdnwatch. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <QApplication>
#include "mainWindow.h"
#include "misdn.h"
Q_DECLARE_METATYPE(timeval);
QDataStream &operator<<( QDataStream &out, const timeval& ) { return out; }
QDataStream &operator>>( QDataStream &in, timeval& ) { return in; }
int main(int argc, char *argv[]) {
qRegisterMetaType<timeval>("timeval");
qRegisterMetaTypeStreamOperators<timeval>("timeval");
QCoreApplication::setOrganizationName("mISDN");
QCoreApplication::setOrganizationDomain("misdn.org");
QCoreApplication::setApplicationName("qmisdnwatch");
QApplication app(argc, argv);
mainWindow* window = new mainWindow;
window->show();
return app.exec();
}

View File

@ -1,907 +0,0 @@
/* $Id: mainWindow.cpp 11 2008-10-31 18:35:50Z daxtar $
* (c) 2008 Martin Bachem, m.bachem@gmx.de
*
* This file is part of qmisdnwatch
*
* Project's Home
* http://www.misdn.org/index.php/Qmisdnwatch
*
* qmisdnwatch is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2
*
* qmisdnwatch is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with qmisdnwatch. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <QApplication>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QGridLayout>
#include <QTreeWidget>
#include <QTreeWidgetItem>
#include <QTimer>
#include <QLabel>
#include <QInputDialog>
#include <QByteArray>
#include <QFile>
#include <QFileDialog>
#include <QDataStream>
#include <QMessageBox>
#include <QMenuBar>
#include <QMenu>
#include <QSettings>
#include <QPixmap>
#include <QCloseEvent>
#include "misdn.h"
#include "mainWindow.h"
void mainWindow::about() {
QMessageBox::information(this, tr("About qmisdnwatch"),
tr("<b>qmisdnwatch</b> <b>v0.0.4</b><br>m.bachem@gmx.de<br>http://www.misdn.org/index.php/Qmisdnwatch"),
QMessageBox::Ok);
}
struct isdnDeviceStuff * mainWindow::getStuffbyId(unsigned int id) {
int i;
for (i=0; i<devStack.count(); i++)
if (devStack[i].id == id)
return &devStack[i];
return NULL;
}
struct mISDN_devinfo * mainWindow::getDevInfoById(unsigned int id) {
int i;
for (i=0; i<deviceList.count(); i++)
if (deviceList[i].id == id)
return &deviceList[i];
return NULL;
}
int mainWindow::getDevIdByTabId(int tabId) {
int i;
for (i=0; i<devStack.count(); i++)
if (devStack[i].tabId == tabId)
return i;
return -1;
}
int mainWindow::renameDevice(unsigned int id) {
struct isdnDeviceStuff * thisDevStuff = getStuffbyId(id);
struct mISDN_devinfo * devInfo = getDevInfoById(id);
if (!thisDevStuff || !devInfo)
return -1;
bool inputOk;
QString newName = QInputDialog::getText(this, tr("rename Layer1"), "new device name:",
QLineEdit::Normal, QString(devInfo->name), &inputOk);
if (inputOk && !newName.isEmpty()) {
if (strcmp(newName.toAscii().data(), devInfo->name) != 0) {
deviceListTimer->stop();
if (!misdn.renameLayer1(id, newName.toAscii().data())) {
strncpy(devInfo->name, newName.toAscii().data(), MISDN_MAX_IDLEN);
tabsheet->setTabText(thisDevStuff->tabId, newName);
thisDevStuff->treeHead->setText(0, newName);
debugOut(thisDevStuff->log, tr("renamed device to '%1'\n")
.arg(newName));
} else {
debugOut(thisDevStuff->log, tr("ERROR: renaming to '%1' failed\n")
.arg(newName));
}
deviceListTimer->start(1000);
}
}
return 0;
}
int mainWindow::actionRenameL1(void) {
int i = getDevIdByTabId(tabsheet->currentIndex());
if (i >= 0)
return renameDevice(i);
else
return -1;
}
void mainWindow::actionConnectL1(void) {
int id = getDevIdByTabId(tabsheet->currentIndex());
if (id >= 0) {
struct isdnDeviceStuff * thisDevStuff = getStuffbyId(id);
struct mISDN_devinfo * devInfo = getDevInfoById(id);
if (!thisDevStuff || !devInfo)
return;
thisDevStuff->l1Thread->connectLayer1(devInfo);
}
}
void mainWindow::actionDisconnectL1(void) {
int id = getDevIdByTabId(tabsheet->currentIndex());
if (id >= 0) {
struct isdnDeviceStuff * thisDevStuff = getStuffbyId(id);
if (!thisDevStuff)
return;
thisDevStuff->l1Thread->disconnectLayer1();
}
}
bool mainWindow::sendActivateReq(unsigned int id) {
struct isdnDeviceStuff * thisDevStuff = getStuffbyId(id);
struct mISDN_devinfo * devInfo = getDevInfoById(id);
if (!thisDevStuff || !devInfo)
return false;
if (thisDevStuff->l1Thread->connectLayer1(devInfo)) {
if (!thisDevStuff->activationPending) {
thisDevStuff->activationPending = true;
thisDevStuff->labelDchIcon->setPixmap(*thisDevStuff->bulletYellow);
debugOut(thisDevStuff->log, tr("<== LAYER1 ACTIVATE REQUEST\n"));
return thisDevStuff->l1Thread->sendActivateReq();
}
}
return false;
}
bool mainWindow::actionActivateReq(void) {
int id = getDevIdByTabId(tabsheet->currentIndex());
if (id >= 0)
sendActivateReq(id);
return false;
}
bool mainWindow::actionInformationReq(void) {
int id = getDevIdByTabId(tabsheet->currentIndex());
if (id >= 0) {
struct isdnDeviceStuff * thisDevStuff = getStuffbyId(id);
struct mISDN_devinfo * devInfo = getDevInfoById(id);
if (!thisDevStuff || !devInfo)
return false;
if ((thisDevStuff) && (thisDevStuff->l1Thread->connectLayer1(devInfo))) {
debugOut(thisDevStuff->log, tr("<== LAYER1 INFORMATION REQUEST\n"));
return thisDevStuff->l1Thread->sendInformationReq();
}
}
return false;
}
int mainWindow::cleanL2(unsigned int id) {
struct isdnDeviceStuff * thisDevStuff = getStuffbyId(id);
if (!thisDevStuff)
return -1;
int ret = misdn.cleanl2(id);
if (ret >= 0)
debugOut(thisDevStuff->log, tr("cleansed Layer2\n"));
else {
debugOut(thisDevStuff->log, tr("ERROR: cleaning L2 failed: "));
if (ret == -4)
debugOut(thisDevStuff->log, tr("no L2 protocol set\n"));
else if (ret == -1)
debugOut(thisDevStuff->log, tr("ioctrl invalid argument\n"));
else
debugOut(thisDevStuff->log, QString("%1\n").arg(ret));
}
return 0;
}
int mainWindow::actionCleanL2(void) {
int i = getDevIdByTabId(tabsheet->currentIndex());
if (i >= 0)
return cleanL2(i);
else
return -1;
}
void mainWindow::l1Connected(unsigned int id) {
struct isdnDeviceStuff * thisDevStuff = getStuffbyId(id);
struct mISDN_devinfo * devInfo = getDevInfoById(id);
if (!thisDevStuff || !devInfo)
return;
tabsheet->setTabText(thisDevStuff->tabId, QString("* %1").arg(devInfo->name));
thisDevStuff->menuDisconnectL1->setEnabled(true);
thisDevStuff->menuConnectL1->setEnabled(false);
debugOut(thisDevStuff->log, tr("Layer1 socket connected (dev %1)\n").arg(id));
}
void mainWindow::l1Disonnected(unsigned int id) {
struct isdnDeviceStuff * thisDevStuff = getStuffbyId(id);
struct mISDN_devinfo * devInfo = getDevInfoById(id);
if (!thisDevStuff || !devInfo)
return;
tabsheet->setTabText(thisDevStuff->tabId, QString(devInfo->name));
thisDevStuff->menuDisconnectL1->setEnabled(false);
thisDevStuff->menuConnectL1->setEnabled(true);
debugOut(thisDevStuff->log, tr("Layer1 socket disconnected (dev %1)\n").arg(id));
}
void mainWindow::eyeSDNappend(QByteArray & target, QByteArray & data, int offset) {
for (int i=offset; i<data.count(); i++) {
unsigned char byte = data[i];
if ((byte == 0xFF) || (byte == 0xFE)) {
target.append(0xFE);
byte -= 2;
}
target.append(byte);
}
}
void mainWindow::logRcvData(unsigned int id, QByteArray data, struct timeval tv) {
struct isdnDeviceStuff * thisDevStuff = getStuffbyId(id);
struct mISDN_devinfo * devInfo = getDevInfoById(id);
struct tm *mt;
unsigned char origin;
int len;
if ((!thisDevStuff) || (!devInfo))
return;
unsigned char buffer[data.count()];
for (int i=0; i<data.count(); i++)
buffer[i] = data[i];
struct mISDNhead * hh = (struct mISDNhead *)buffer;
switch (hh->prim) {
case PH_ACTIVATE_CNF:
debugOut(thisDevStuff->log, tr("==> LAYER1 ACTIVE\n"));
thisDevStuff->labelDchIcon->setPixmap(*thisDevStuff->bulletGreen);
thisDevStuff->activated = true;
thisDevStuff->activationPending = false;
break;
case PH_ACTIVATE_IND:
debugOut(thisDevStuff->log, tr("==> LAYER1 ACTIVATED\n"));
thisDevStuff->labelDchIcon->setPixmap(*thisDevStuff->bulletGreen);
thisDevStuff->activated = true;
thisDevStuff->activationPending = false;
break;
case PH_DEACTIVATE_CNF:
debugOut(thisDevStuff->log, tr("==> LAYER1 DEACTIVE\n"));
thisDevStuff->labelDchIcon->setPixmap(*thisDevStuff->bulletGray);
thisDevStuff->activated = false;
thisDevStuff->activationPending = false;
break;
case PH_DEACTIVATE_IND:
debugOut(thisDevStuff->log, tr("==> LAYER1 DEACTIVATED\n"));
thisDevStuff->labelDchIcon->setPixmap(*thisDevStuff->bulletGray);
thisDevStuff->activated = false;
thisDevStuff->activationPending = false;
break;
case MPH_INFORMATION_IND:
debugOut(thisDevStuff->log, tr("==> LAYER1 INFORMATION IND:"));
binaryOut(thisDevStuff->log, data, sizeof(struct mISDNhead));
break;
}
if (!thisDevStuff->captureL1)
return;
QString timeStr("");
mt = localtime((time_t *)&tv.tv_sec);
timeStr.sprintf("%02d.%02d.%04d %02d:%02d:%02d.%06ld:\t", mt->tm_mday, mt->tm_mon + 1, mt->tm_year + 1900,
mt->tm_hour, mt->tm_min, mt->tm_sec, tv.tv_usec);
debugOut(thisDevStuff->log, timeStr);
debugOut(thisDevStuff->log, QString("prim(0x%1)\tid(%2)")
.arg(QString::number(hh->prim, 16))
.arg(QString::number(hh->id, 16)));
binaryOut(thisDevStuff->log, data, sizeof(struct mISDNhead));
// collect data as eyeSDN stream to SaveAs wireshark readable
if (thisDevStuff->l1Thread->hasEcho() && (hh->prim == PH_DATA_REQ))
return;
if ((hh->prim != PH_DATA_REQ) && (hh->prim != PH_DATA_IND) &&
(hh->prim != PH_DATA_E_IND))
return;
if (devInfo->protocol == ISDN_P_NT_S0 || devInfo->protocol == ISDN_P_NT_E1)
origin = hh->prim == PH_DATA_REQ ? 0 : 1;
else
origin = ((hh->prim == PH_DATA_REQ) ||
(hh->prim == PH_DATA_E_IND)) ? 1 : 0;
len = data.count() - MISDN_HEADER_LEN;
QByteArray eyeHeader;
eyeHeader.append((unsigned char)(0xff & (tv.tv_usec >> 16)));
eyeHeader.append((unsigned char)(0xff & (tv.tv_usec >> 8)));
eyeHeader.append((unsigned char)(0xff & tv.tv_usec));
eyeHeader.append((char)0);
eyeHeader.append((unsigned char)(0xff & (tv.tv_sec >> 24)));
eyeHeader.append((unsigned char)(0xff & (tv.tv_sec >> 16)));
eyeHeader.append((unsigned char)(0xff & (tv.tv_sec >> 8)));
eyeHeader.append((unsigned char)(0xff & tv.tv_sec));
eyeHeader.append((char)0);
eyeHeader.append((unsigned char) origin);
eyeHeader.append((unsigned char)(0xff & (len >> 8)));
eyeHeader.append((unsigned char)(0xff & len));
/* add Frame escaped */
thisDevStuff->eyeSDN.append(0xFF);
eyeSDNappend(thisDevStuff->eyeSDN, eyeHeader, 0);
eyeSDNappend(thisDevStuff->eyeSDN, data, sizeof(struct mISDNhead));
thisDevStuff->captureFrameCnt++;
}
int mainWindow::switchL1Logging(unsigned int id) {
struct isdnDeviceStuff * thisDevStuff = getStuffbyId(id);
struct mISDN_devinfo * devInfo = getDevInfoById(id);
if ((!thisDevStuff) || (!devInfo))
return -1;
thisDevStuff->captureL1 = !thisDevStuff->captureL1;
if (!thisDevStuff->captureL1) {
if (thisDevStuff->l1Thread->hasEcho()) {
debugOut(thisDevStuff->log,
tr("D/E channel logging stopped\n"));
thisDevStuff->buttonLogL1->setText(
tr("start D-/E-Channel logging"));
}
else {
debugOut(thisDevStuff->log,
tr("D channel logging stopped\n"));
thisDevStuff->buttonLogL1->setText(
tr("start D-Channel logging"));
}
} else {
thisDevStuff->eyeSDN.clear();
thisDevStuff->captureFrameCnt = 0;
if (thisDevStuff->l1Thread->connectLayer1(devInfo)) {
QByteArray eyeHeader("EyeSDN");
thisDevStuff->eyeSDN.append(eyeHeader);
if (thisDevStuff->l1Thread->hasEcho()) {
debugOut(thisDevStuff->log,
tr("D/E channel logging started\n"));
thisDevStuff->buttonLogL1->setText(
tr("stop D-/E-Channel logging"));
}
else {
debugOut(thisDevStuff->log,
tr("D channel logging started\n"));
thisDevStuff->buttonLogL1->setText(
tr("stop D-Channel logging"));
}
} else {
debugOut(thisDevStuff->log,
tr("no connetion Layer1 established\n"));
thisDevStuff->captureL1 = false;
}
}
return 0;
}
int mainWindow::saveL1Log(unsigned int id) {
struct isdnDeviceStuff * thisDevStuff = getStuffbyId(id);
struct mISDN_devinfo * devInfo = getDevInfoById(id);
if ((!thisDevStuff) || (!devInfo))
return -1;
QString filename;
filename = QFileDialog::getSaveFileName(
this, tr("Save Log As WireShark readable"));
if (filename.isEmpty())
return -1;
/* save complete file */
QFile file(filename);
file.open(QIODevice::WriteOnly);
QDataStream out(&file);
for (int i = 0; i < thisDevStuff->eyeSDN.count(); ++i) {
unsigned char byte = thisDevStuff->eyeSDN[i];
out.writeRawData((const char*)&byte, 1);
}
file.close();
return 0;
}
int mainWindow::showActionMenu(unsigned int id) {
struct isdnDeviceStuff * thisDevStuff = getStuffbyId(id);
struct mISDN_devinfo * devInfo = getDevInfoById(id);
if ((!thisDevStuff) || (!devInfo))
return -1;
thisDevStuff->actionPopup->exec(QCursor::pos()); // popup();
return 0;
}
void mainWindow::createNewDeviceTab(struct mISDN_devinfo *devInfo) {
struct isdnDeviceStuff newDevStuff;
unsigned int i;
qDebug("device %d arised (%s) nrbchan(%d)", devInfo->id, devInfo->name,
devInfo->nrbchan);
/* misc control vars */
newDevStuff.id = devInfo->id;
newDevStuff.captureL1 = false;
newDevStuff.activated = false;
newDevStuff.activationPending = false;
newDevStuff.tab = new QWidget;
newDevStuff.tabId = tabsheet->addTab(newDevStuff.tab,
QString(devInfo->name));
/* Button 'L1 logging' */
newDevStuff.buttonLogL1 = new idButton(tr("start D-/E-Channel logging"),
newDevStuff.tab, newDevStuff.id);
connect(newDevStuff.buttonLogL1, SIGNAL(clicked(unsigned int)),
this, SLOT(switchL1Logging(unsigned int)));
/* Button 'saveLog' */
newDevStuff.buttonSaveLog = new idButton(tr("Save Log As"),
newDevStuff.tab, newDevStuff.id);
connect(newDevStuff.buttonSaveLog, SIGNAL(clicked(unsigned int)),
this, SLOT(saveL1Log(unsigned int)));
/* Button 'ISDN Actions' */
newDevStuff.buttonActionMenu = new idButton(tr("Device Actions"),
newDevStuff.tab, newDevStuff.id);
connect(newDevStuff.buttonActionMenu, SIGNAL(clicked(unsigned int)),
this, SLOT(showActionMenu(unsigned int)));
/* color bullets */
newDevStuff.bulletRed = new QPixmap(":red.png");
newDevStuff.bulletGreen = new QPixmap(":green.png");
newDevStuff.bulletGray = new QPixmap(":gray.png");
newDevStuff.bulletYellow = new QPixmap(":yellow.png");
/* D-Channel icon */
newDevStuff.labelDchText = new QLabel(newDevStuff.tab);
newDevStuff.labelDchIcon = new QLabel(newDevStuff.tab);
newDevStuff.labelDchIcon->setPixmap(*newDevStuff.bulletRed);
/* B-Channel icon */
newDevStuff.labelBchText = new QLabel(tr("B-Channels: "), newDevStuff.tab);
for (i=0; i<devInfo->nrbchan; i++) {
newDevStuff.labelBchIcon[i] = new QLabel(newDevStuff.tab);
newDevStuff.labelBchIcon[i]->setPixmap(*newDevStuff.bulletRed);
}
/* Text Widget */
newDevStuff.log = new QTextEdit();
/* l1 Thread */
newDevStuff.l1Thread = new Ql1logThread(devInfo->id, misdn);
newDevStuff.l1Thread->setParent(newDevStuff.tab);
connect(newDevStuff.l1Thread, SIGNAL(l1Connected(unsigned int)),
this, SLOT(l1Connected(unsigned int)));
connect(newDevStuff.l1Thread, SIGNAL(l1Disonnected(unsigned int)),
this, SLOT(l1Disonnected(unsigned int)));
connect(newDevStuff.l1Thread, SIGNAL(rcvData(unsigned int, QByteArray, struct timeval)),
this, SLOT(logRcvData(unsigned int, QByteArray, struct timeval)));
/* action PopupMenu */
newDevStuff.actionPopup = new QMenu(newDevStuff.tab);
newDevStuff.menuConnectL1 = newDevStuff.actionPopup->
addAction(tr("connect Layer1"), this, SLOT(actionConnectL1()));
newDevStuff.menuDisconnectL1 = newDevStuff.actionPopup->
addAction(tr("disconnect Layer1"), this, SLOT(actionDisconnectL1()));
newDevStuff.menuDisconnectL1->setEnabled(false);
newDevStuff.actionPopup->addSeparator();
newDevStuff.actionPopup->addAction(tr("send ACTIVATE REQUEST"), this, SLOT(actionActivateReq()));
newDevStuff.actionPopup->addAction(tr("send INFORMATION REQUEST"), this, SLOT(actionInformationReq()));
newDevStuff.actionPopup->addSeparator();
newDevStuff.actionPopup->addAction(tr("rename Layer1"), this, SLOT(actionRenameL1()));
newDevStuff.actionPopup->addAction(tr("clean Layer2"), this, SLOT(actionCleanL2()));
QHBoxLayout *hbox;
QVBoxLayout *vbox;
QGridLayout *grid;
/* Layout */
vbox = new QVBoxLayout(newDevStuff.tab);
hbox = new QHBoxLayout();
hbox->addWidget(newDevStuff.buttonActionMenu);
hbox->addSpacing(5);
hbox->addWidget(newDevStuff.buttonLogL1);
hbox->insertStretch(3, 0);
vbox->addItem(hbox);
hbox = new QHBoxLayout();
grid = new QGridLayout();
grid->addWidget(newDevStuff.labelDchText, 0, 0);
grid->addWidget(newDevStuff.labelDchIcon, 0, 1);
grid->addWidget(newDevStuff.labelBchText, 1, 0);
for (i=0; i<devInfo->nrbchan; i++)
grid->addWidget(newDevStuff.labelBchIcon[i], 1, i+1);
hbox->addItem(grid);
hbox->insertStretch(2,0);
vbox->addItem(hbox);
vbox->addWidget(newDevStuff.log);
hbox = new QHBoxLayout();
hbox->addWidget(newDevStuff.buttonSaveLog);
hbox->insertStretch(1, 0);
vbox->addItem(hbox);
devStack << newDevStuff;
struct isdnDeviceStuff * thisDevStuff = getStuffbyId(devInfo->id);
if (!thisDevStuff)
return;
if ((optionAutoConnectTE->isChecked()) && IS_ISDN_P_TE(devInfo->protocol))
thisDevStuff->l1Thread->connectLayer1(devInfo);
if ((optionAutoConnectNT->isChecked()) && IS_ISDN_P_NT(devInfo->protocol))
thisDevStuff->l1Thread->connectLayer1(devInfo);
if ((optionAutoConnectUnused->isChecked()) && !devInfo->protocol)
thisDevStuff->l1Thread->connectLayer1(devInfo);
}
void mainWindow::removeVanishedDevices(void) {
int i, j;
int vanishedDev=1;
while (vanishedDev && devStack.count()) {
for (i=(devStack.count()-1); i>=0; i--) {
vanishedDev = 1;
for (j=0; j<deviceList.count(); j++)
if (devStack[i].id == deviceList[j].id)
vanishedDev = 0;
if (vanishedDev) {
qDebug("device %d vansihed", devStack[i].id);
tabsheet->removeTab(devStack[i].tabId);
for(j=i+1; j<devStack.count(); j++)
devStack[j].tabId--;
devStack.removeAt(i);
break;
}
}
}
}
void mainWindow::renewDeviceWidgets(void) {
int i, j, n = deviceList.count();
struct mISDN_devinfo devInfo;
int newdev;
/* clear old widgets */
devtree->clear();
removeVanishedDevices();
QTreeWidgetItem* devitem;
for (i=0; i<n; i++) {
devInfo = deviceList[i];
newdev = 1;
for (j=0; j<devStack.count(); j++)
if (devInfo.id == devStack[j].id)
newdev = 0;
/* create new Device Tab and stuff */
if (newdev)
createNewDeviceTab(&devInfo);
struct isdnDeviceStuff * thisDevStuff = getStuffbyId(devInfo.id);
if (!thisDevStuff)
return;
/* Update main Device Tree */
devitem = new QTreeWidgetItem(devtree);
devitem->setText(0, QString(devInfo.name));
thisDevStuff->treeHead = devitem;
QTreeWidgetItem* optitem;
optitem = new QTreeWidgetItem(devitem);
optitem->setText(0, tr("Id: %1")
.arg(devInfo.id));
optitem = new QTreeWidgetItem(devitem);
optitem->setText(0, tr("D protocols: %1")
.arg(devInfo.Dprotocols));
if (devInfo.Dprotocols) {
QTreeWidgetItem* l1item = new QTreeWidgetItem(optitem);
l1item->setText(0, tr("Layer 1"));
QTreeWidgetItem* doptitem;
if (devInfo.Dprotocols & (1 << ISDN_P_TE_S0)) {
doptitem = new QTreeWidgetItem(l1item);
doptitem->setText(0, tr("S0 TE"));
}
if (devInfo.Dprotocols & (1 << ISDN_P_NT_S0)) {
doptitem = new QTreeWidgetItem(l1item);
doptitem->setText(0, tr("S0 NT"));
}
if (devInfo.Dprotocols & (1 << ISDN_P_TE_E1)) {
doptitem = new QTreeWidgetItem(l1item);
doptitem->setText(0, tr("E1 TE"));
}
if (devInfo.Dprotocols & (1 << ISDN_P_NT_E1)) {
doptitem = new QTreeWidgetItem(l1item);
doptitem->setText(0, tr("E1 NT"));
}
if (devInfo.Dprotocols & (1 << ISDN_P_TE_UP0)) {
doptitem = new QTreeWidgetItem(l1item);
doptitem->setText(0, tr("UP0 TE"));
}
if (devInfo.Dprotocols & (1 << ISDN_P_NT_UP0)) {
doptitem = new QTreeWidgetItem(l1item);
doptitem->setText(0, tr("UP0 NT"));
}
}
optitem = new QTreeWidgetItem(devitem);
optitem->setText(0, tr("B protocols: %1")
.arg(devInfo.Bprotocols));
if (devInfo.Bprotocols) {
QTreeWidgetItem* l1item = new QTreeWidgetItem(optitem);
l1item->setText(0, QString("Layer 1"));
QTreeWidgetItem* boptitem;
if (devInfo.Bprotocols & (1 <<
(ISDN_P_B_RAW
- ISDN_P_B_START))) {
boptitem = new QTreeWidgetItem(l1item);
boptitem->setText(0,
tr("RAW (transparent)"));
}
if (devInfo.Bprotocols & (1 <<
(ISDN_P_B_HDLC
- ISDN_P_B_START))) {
boptitem = new QTreeWidgetItem(l1item);
boptitem->setText(0, tr("HDLC"));
}
if (devInfo.Bprotocols & (1 <<
(ISDN_P_B_X75SLP
- ISDN_P_B_START))) {
boptitem = new QTreeWidgetItem(l1item);
boptitem->setText(0, tr("X.75"));
}
QTreeWidgetItem* l2item = new QTreeWidgetItem(optitem);
l2item->setText(0, tr("Layer 2"));
if (devInfo.Bprotocols & (1 <<
(ISDN_P_B_L2DTMF
- ISDN_P_B_START))) {
boptitem = new QTreeWidgetItem(l2item);
boptitem->setText(0, tr("DTMF"));
}
}
optitem = new QTreeWidgetItem(devitem);
optitem->setText(0, QString(tr("protocol: %1"))
.arg(devInfo.protocol));
QTreeWidgetItem* l1item = new QTreeWidgetItem(optitem);
thisDevStuff->labelDchText->setText("D-Channel: ");
switch (devInfo.protocol) {
case 0:
l1item->setText(0, tr("unused"));
break;
case ISDN_P_TE_S0:
l1item->setText(0, tr("S0 TE"));
thisDevStuff->labelDchText->setText("D-Channel S0 TE: ");
break;
case ISDN_P_NT_S0:
l1item->setText(0, tr("S0 NT"));
thisDevStuff->labelDchText->setText("D-Channel S0 NT: ");
break;
case ISDN_P_TE_E1:
l1item->setText(0, tr("E1 TE"));
thisDevStuff->labelDchText->setText("D-Channel E1 TE: ");
break;
case ISDN_P_NT_E1:
l1item->setText(0, tr("E1 NT"));
thisDevStuff->labelDchText->setText("D-Channel E1 NT: ");
break;
case ISDN_P_TE_UP0:
l1item->setText(0, tr("UP0 TE"));
thisDevStuff->labelDchText->setText("D-Channel UP0 TE: ");
break;
case ISDN_P_NT_UP0:
l1item->setText(0, tr("UP0 NT"));
thisDevStuff->labelDchText->setText("D-Channel UP0 NT: ");
break;
default:
l1item->setText(0, tr("unkown protocol"));
break;
}
optitem = new QTreeWidgetItem(devitem);
optitem->setText(0, tr("B-Channels: %1")
.arg(devInfo.nrbchan));
}
}
void mainWindow::showMISDNversion(void) {
struct mISDNversion v;
v = misdn.getVersion();
debugOut(logText, tr("mISDN kernel driver v%1.%2.%4\n")
.arg(v.major)
.arg(v.minor)
.arg(v.release));
}
void mainWindow::updateDeviceList(void) {
int i, j;
QList <struct mISDN_devinfo> tmpDevList;
int newdev = 0, oldnumdevs = misdn.getLastNumDevs();
if (!misdn.isCoreConnected()) {
misdn.connectCore();
if (!misdn.isCoreConnected())
return;
else
showMISDNversion();
}
i = misdn.getNumDevices();
if (i < 0) {
debugOut(logText, tr("unable to connect mISDN socket\n"));
devtree->clear();
return;
}
if (i != oldnumdevs)
debugOut(logText, tr("found %1 device%2\n")
.arg(i)
.arg((i==1)?"":"s"));
if (i >= 0) {
struct mISDN_devinfo devInfo;
for (j=0; ((j<MAX_DEVICE_ID) && (tmpDevList.count() < i)); j++)
if (misdn.getDeviceInfo(&devInfo, j) >= 0)
tmpDevList << devInfo;
if (tmpDevList.count() == deviceList.count()) {
for (j=0; j<deviceList.count(); j++)
newdev |= memcmp(&tmpDevList[j],
&deviceList[j],
sizeof(struct mISDN_devinfo)-8);
} else
newdev = 1;
/* numDevices of devinfos had changed */
if (newdev) {
deviceList.clear();
for (j=0; j<i; j++) {
debugOut(logText, tr("id %1: '%2'\n")
.arg(tmpDevList[j].id)
.arg(QString(
tmpDevList[j].name)));
deviceList << tmpDevList[j];
}
renewDeviceWidgets();
}
}
/* auto Activate? */
if (optionAutoActivateTE->isChecked() || optionAutoActivateNT->isChecked()) {
for (i=0; i<devStack.count(); i++) {
struct mISDN_devinfo * devInfo = getDevInfoById(devStack[i].id);
if (devInfo) {
if (IS_ISDN_P_TE(devInfo->protocol) && optionAutoActivateTE->isChecked()
&& !devStack[i].activated) {
sendActivateReq(devStack[i].id);
}
if (IS_ISDN_P_NT(devInfo->protocol) && optionAutoActivateNT->isChecked()
&& !devStack[i].activated) {
sendActivateReq(devStack[i].id);
}
}
}
}
}
void mainWindow::debugOut(QTextEdit * textEdit, QString text) {
textEdit->moveCursor(QTextCursor::End);
textEdit->insertPlainText(text);
textEdit->ensureCursorVisible();
}
void mainWindow::binaryOut(QTextEdit * textEdit, QByteArray & data, int offset) {
int i, j=0;
QString lz;
if (offset < data.size())
debugOut(textEdit, ": ");
for (i=offset; i<data.size(); i++) {
lz = (((unsigned char)data[i]) < 0x10)?"0":"";
if (!(j++ % 8))
debugOut(textEdit, "\n\t");
debugOut(textEdit, QString("0x%1%2 ")
.arg(lz)
.arg(QString::number((unsigned char)data[i], 16))
);
}
debugOut(textEdit, "\n\n");
}
void mainWindow::aboutQt() {
QMessageBox::aboutQt(this);
}
void mainWindow::closeEvent( QCloseEvent* ce ) {
QSettings settings;
qDebug("closing...");
settings.setValue(tr("layer1/autoConnectTE"), optionAutoConnectTE->isChecked()?1:0);
settings.setValue(tr("layer1/autoConnectNT"), optionAutoConnectNT->isChecked()?1:0);
settings.setValue(tr("layer1/autoConnectUnused"), optionAutoConnectUnused->isChecked()?1:0);
settings.setValue(tr("layer1/autoActivateTE"), optionAutoActivateTE->isChecked()?1:0);
settings.setValue(tr("layer1/autoActivateNT"), optionAutoActivateNT->isChecked()?1:0);
// settings.setValue(tr("layer1/pollInformation"), optionPollInformation->isChecked()?1:0);
ce->accept();
}
mainWindow::mainWindow( QMainWindow *parent,
Qt::WindowFlags flags ) :
QMainWindow(parent, flags)
{
QSettings settings;
resize(520, 400);
QWidget * centralwidget = new QWidget(this);
tabsheet = new QTabWidget(centralwidget);
maintab = new QWidget;
tabsheet->addTab(maintab, "mISDN");
QVBoxLayout *vbox01 = new QVBoxLayout(centralwidget);
QVBoxLayout *vbox02 = new QVBoxLayout(maintab);
logText = new QTextEdit(maintab);
logText->setMaximumHeight(120);
devtree = new QTreeWidget(maintab);
devtree->setHeaderLabel(tr("mISDN v2 devices"));
deviceListTimer = new(QTimer);
connect(deviceListTimer, SIGNAL(timeout()),
this, SLOT(updateDeviceList()));
vbox01->addWidget(tabsheet);
vbox02->addWidget(devtree);
vbox02->addWidget(logText);
QMenu * optionsMenu = new QMenu(tr("Options"), this);
QMenu * autoConnect = new QMenu(tr("auto-Connect"), optionsMenu);
optionsMenu->addMenu(autoConnect);
optionAutoConnectTE = autoConnect->addAction(tr("TE ports"));
optionAutoConnectTE->setCheckable(true);
optionAutoConnectTE->setChecked(settings.value(tr("layer1/autoConnectTE"), 1).toInt() == 1);
optionAutoConnectNT = autoConnect->addAction(tr("NT ports"));
optionAutoConnectNT->setCheckable(true);
optionAutoConnectNT->setChecked(settings.value(tr("layer1/autoConnectNT"), 1).toInt() == 1);
optionAutoConnectUnused = autoConnect->addAction(tr("unused Ports"));
optionAutoConnectUnused->setCheckable(true);
optionAutoConnectUnused->setChecked(settings.value(tr("layer1/autoConnectUnused"), 0).toInt() == 1);
QMenu * autoActivate = new QMenu(tr("auto-Activate"), optionsMenu);
optionsMenu->addMenu(autoActivate);
optionAutoActivateTE = autoActivate->addAction(tr("TE ports"));
optionAutoActivateTE->setCheckable(true);
optionAutoActivateTE->setChecked(settings.value(tr("layer1/autoActivateTE"), 1).toInt() == 1);
optionAutoActivateNT = autoActivate->addAction(tr("NT ports"));
optionAutoActivateNT->setCheckable(true);
optionAutoActivateNT->setChecked(settings.value(tr("layer1/autoActivateNT"), 0).toInt() == 1);
/*
optionPollInformation = optionsMenu->addAction(tr("poll Layer1 Information"));
optionPollInformation->setCheckable(true);
optionPollInformation->setChecked(settings.value(tr("layer1/pollInformation"), 0).toInt() == 1);
*/
QMenu * helpMenu = new QMenu(tr("?"), this);
helpMenu->addAction(tr("about qmisdnwatch"), this, SLOT(about()));
helpMenu->addAction(tr("about Qt"), this, SLOT(aboutQt()));
menuBar()->addMenu(optionsMenu);
menuBar()->addMenu(helpMenu);
setCentralWidget(centralwidget);
setWindowTitle(QString ("qmisdnwatch"));
if (misdn.isCoreConnected())
showMISDNversion();
else
debugOut(logText, "connecting mISDN core socket failed\n");
updateDeviceList();
deviceListTimer->start(1000);
}

View File

@ -1,130 +0,0 @@
/* $Id: mainWindow.h 11 2008-10-31 18:35:50Z daxtar $
* (c) 2008 Martin Bachem, m.bachem@gmx.de
*
* This file is part of qmisdnwatch
*
* Project's Home
* http://www.misdn.org/index.php/Qmisdnwatch
*
* qmisdnwatch is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2
*
* qmisdnwatch is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with qmisdnwatch. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef mainWindow_H
#define mainWindow_H
#include <QWidget>
#include <QMainWindow>
#include <QTextEdit>
#include <QTabWidget>
#include <QTreeWidget>
#include <QTimer>
#include <QLabel>
#include <QPushButton>
#include <QThread>
#include <QCloseEvent>
#include "Ql1logThread.h"
#include "extraWidgets.h"
#include "misdn.h"
struct isdnDeviceStuff {
unsigned int id;
QWidget * tab; /* tab in TabWidget */
int tabId; /* tabID in TabWidget */
QPixmap * bulletRed;
QPixmap * bulletGreen;
QPixmap * bulletGray;
QPixmap * bulletYellow;
QLabel * labelDchText;
QLabel * labelDchIcon;
QLabel * labelBchText;
QLabel * labelBchIcon[32]; /* TODO : malloc! */
QTreeWidgetItem * treeHead;
QTextEdit * log;
idButton * buttonLogL1;
idButton * buttonSaveLog;
idButton * buttonActionMenu;
QAction * actionRename;
Ql1logThread * l1Thread;
QMenu * actionPopup;
QAction * menuConnectL1;
QAction * menuDisconnectL1;
QByteArray eyeSDN;
bool captureL1;
bool activated;
bool activationPending;
int captureFrameCnt;
};
class mainWindow : public QMainWindow {
Q_OBJECT
public:
mainWindow( QMainWindow *parent = 0,
Qt::WindowFlags flags = 0 );
private:
QList <struct mISDN_devinfo> deviceList;
QList <struct isdnDeviceStuff> devStack;
QTabWidget * tabsheet;
QWidget * maintab;
QTreeWidget * devtree;
QTimer * deviceListTimer;
QTextEdit * logText;
QAction * optionAutoConnectTE;
QAction * optionAutoConnectNT;
QAction * optionAutoConnectUnused;
QAction * optionAutoActivateTE;
QAction * optionAutoActivateNT;
QAction * optionPollInformation;
mISDN misdn;
void showMISDNversion(void);
void renewDeviceWidgets(void);
void removeVanishedDevices(void);
void createNewDeviceTab(struct mISDN_devinfo *devinfo);
void debugOut(QTextEdit * textEdit, QString text);
void binaryOut(QTextEdit * textEdit, QByteArray & data, int offset);
void eyeSDNappend(QByteArray & target, QByteArray & data, int offset);
struct isdnDeviceStuff * getStuffbyId(unsigned int id);
struct mISDN_devinfo * getDevInfoById(unsigned int id);
int getDevIdByTabId(int tabId);
private slots:
void updateDeviceList(void);
int renameDevice(unsigned int id);
int cleanL2(unsigned int id);
int actionCleanL2(void);
int actionRenameL1(void);
void actionConnectL1(void);
bool actionActivateReq(void);
bool sendActivateReq(unsigned int id);
bool actionInformationReq(void);
void actionDisconnectL1(void);
int switchL1Logging(unsigned int id);
int saveL1Log(unsigned int id);
int showActionMenu(unsigned int id);
void logRcvData(unsigned int id, QByteArray data, struct timeval tv);
void l1Connected(unsigned int id);
void l1Disonnected(unsigned int id);
void about();
void aboutQt();
protected:
void closeEvent( QCloseEvent* );
};
#endif

View File

@ -1,185 +0,0 @@
/* $Id: misdn.cpp 11 2008-10-31 18:35:50Z daxtar $
* (c) 2008 Martin Bachem, m.bachem@gmx.de
*
* This file is part of qmisdnwatch
*
* Project's Home
* http://www.misdn.org/index.php/Qmisdnwatch
*
* qmisdnwatch is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2
*
* qmisdnwatch is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with qmisdnwatch. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "misdn.h"
#include <QApplication>
#include <mISDN/af_isdn.h>
mISDN::mISDN(void) {
numdevices = -1;
memset(&kver, 0, sizeof(struct mISDNversion));
connectCore();
}
mISDN::~mISDN(void) {
if (isCoreConnected())
close(sock);
}
int mISDN::connectCore(void) {
sock = socket(PF_ISDN, SOCK_RAW, ISDN_P_BASE);
qDebug("mISDN::connectCore %d", sock);
if (isCoreConnected())
queryVersion();
return sock;
}
bool mISDN::isCoreConnected(void) {
return(sock >= 0);
}
struct mISDNversion mISDN::getVersion(void) {
return(kver);
}
void mISDN::queryVersion(void) {
struct mISDNversion v;
int ret;
if (isCoreConnected()) {
ret = ioctl(sock, IMGETVERSION, &v);
if (ret >= 0)
memcpy(&kver, &v, sizeof(struct mISDNversion));
}
}
int mISDN::getNumDevices(void) {
int cnt, ret = 0;
if (isCoreConnected()) {
ret = ioctl(sock, IMGETCOUNT, &cnt);
if (!ret) {
numdevices = cnt;
return(cnt);
}
}
return(-1);
}
int mISDN::getDeviceInfo(struct mISDN_devinfo *devinfo, int id) {
int ret;
if (isCoreConnected()) {
devinfo->id = id;
try {
ret = ioctl(sock, IMGETDEVINFO, devinfo);
if (!ret)
return 0;
}
catch (...) {
return -1;
}
}
return -2;
}
/*
* returns
* <0 on error
* =0 socket open with no E-Channel logging available
* =1 socket open with E-Channel logging enabled
*/
int mISDN::openl1Log(int id, int protocol, int * log_socket,
struct sockaddr_mISDN * log_addr)
{
int ret, channel;
if (!(isCoreConnected()))
return -2;
if ((*log_socket = socket(PF_ISDN, SOCK_DGRAM, protocol)) >= 0)
{
log_addr->family = AF_ISDN;
log_addr->dev = id;
ret = -1;
channel = 1;
while ((ret < 0) && (channel >= 0)) {
log_addr->channel = (unsigned char)channel;
ret = bind(*log_socket, (struct sockaddr *)log_addr,
sizeof(struct sockaddr_mISDN));
if (ret < 0)
channel--;
}
int opt=1;
setsockopt(*log_socket, SOL_MISDN, MISDN_TIME_STAMP,
&opt, sizeof(opt));
return (log_addr->channel == 1);
}
return -1;
}
int mISDN::getLastNumDevs(void) {
return(numdevices);
}
int mISDN::renameLayer1(unsigned int id, char * name) {
struct mISDN_devrename devrename;
int ret;
if (isCoreConnected()) {
devrename.id = id;
strncpy(devrename.name, name, MISDN_MAX_IDLEN);
ret = ioctl(sock, IMSETDEVNAME, &devrename);
return ret;
}
return -1;
}
int mISDN::cleanl2(unsigned int id) {
int ret;
if (isCoreConnected()) {
struct mISDN_devinfo devinfo;
if (getDeviceInfo(&devinfo, id) >= 0) {
if (!devinfo.protocol)
return -4;
int l2sock;
if (IS_ISDN_P_TE(devinfo.protocol))
l2sock = socket(PF_ISDN, SOCK_DGRAM,
ISDN_P_LAPD_TE);
else
l2sock = socket(PF_ISDN, SOCK_DGRAM,
ISDN_P_LAPD_NT);
if (l2sock >= 0) {
struct sockaddr_mISDN addr;
addr.family = AF_ISDN;
addr.dev = id;
addr.channel = 0;
addr.sapi = 0;
addr.tei = 127;
ret = bind(l2sock, (struct sockaddr *) &addr,
sizeof(addr));
if (ret >= 0) {
int clean = 1;
ret = ioctl(l2sock, IMCLEAR_L2, &clean);
if (ret < 0)
return -1;
return 0;
} else
return -2;
} else
return -3;
} else
return -6;
}
return -7;
}

View File

@ -1,104 +0,0 @@
/* $Id: misdn.h 11 2008-10-31 18:35:50Z daxtar $
* (c) 2008 Martin Bachem, m.bachem@gmx.de
*
* This file is part of qmisdnwatch
*
* Project's Home
* http://www.misdn.org/index.php/Qmisdnwatch
*
* qmisdnwatch is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2
*
* qmisdnwatch is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with qmisdnwatch. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef _MISDN_H_
#define _MISDN_H_
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <netinet/udp.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/ioctl.h>
#include <mISDN/mISDNif.h>
#include <mISDN/q931.h>
#ifndef ISDN_P_TE_UP0
#define ISDN_P_TE_UP0 0x05
#endif
#ifndef ISDN_P_NT_UP0
#define ISDN_P_NT_UP0 0x06
#endif
#ifndef IS_ISDN_P_TE
#define IS_ISDN_P_TE(p) ((p == ISDN_P_TE_S0) || (p == ISDN_P_TE_E1) || \
(p == ISDN_P_TE_UP0) || (p == ISDN_P_LAPD_TE))
#endif
#ifndef IS_ISDN_P_NT
#define IS_ISDN_P_NT(p) ((p == ISDN_P_NT_S0) || (p == ISDN_P_NT_E1) || \
(p == ISDN_P_NT_UP0) || (p == ISDN_P_LAPD_NT))
#endif
#ifndef IS_ISDN_P_S0
#define IS_ISDN_P_S0(p) ((p == ISDN_P_TE_S0) || (p == ISDN_P_NT_S0))
#endif
#ifndef IS_ISDN_P_E1
#define IS_ISDN_P_E1(p) ((p == ISDN_P_TE_E1) || (p == ISDN_P_NT_E1))
#endif
#ifndef IS_ISDN_P_UP0
#define IS_ISDN_P_UP0(p) ((p == ISDN_P_TE_UP0) || (p == ISDN_P_NT_UP0))
#endif
class mISDN {
public:
mISDN(void);
~mISDN(void);
int connectCore(void);
bool isCoreConnected(void);
int getNumDevices(void);
int getDeviceInfo(struct mISDN_devinfo *devinfo, int id);
int getLastNumDevs(void);
struct mISDNversion getVersion(void);
/* socket helper */
int openl1Log(int id, int protocol, int * log_socket,
struct sockaddr_mISDN * log_addr);
/* tools / examples */
int renameLayer1(unsigned int id, char * name);
int cleanl2(unsigned int id);
private:
void queryVersion(void);
int numdevices; // devicesNumber
int sock; // base socket handles
struct mISDNversion kver; // mISDN kernel version
};
struct ctstamp {
size_t cmsg_len;
int cmsg_level;
int cmsg_type;
struct timeval tv;
};
#endif // _MISDN_H_

70
i4lnet/Makefile Normal file
View File

@ -0,0 +1,70 @@
CC = gcc
AR = ar
RANLIB = ranlib
all: libisdnnet.a libisdnnet_pic.a libisdnnet.so
install:
install -m 644 libisdnnet.a $(INSTALL_PREFIX)/usr/lib
install -m 644 libisdnnet_pic.a $(INSTALL_PREFIX)/usr/lib
install -m 644 libisdnnet.so $(INSTALL_PREFIX)/usr/lib
cp *.h $(INSTALL_PREFIX)/usr/include/mISDNuser/
ISDNNET_OBJ = net_if.o isdn_debug.o isdn_msg.o fsm.o net_l2.o tei.o net_l3.o \
manager.o tone.o bchannel.o g711.o
ISDNNET_PICOBJ = $(ISDNNET_OBJ:%.o=%.lo)
ifeq ($(shell uname -m),x86_64)
CFLAGS += -fPIC
endif
libisdnnet_pic.a: $(ISDNNET_PICOBJ)
$(AR) cru $@ $^
$(RANLIB) $@
libisdnnet.a: $(ISDNNET_OBJ)
$(AR) cru $@ $^
$(RANLIB) $@
libisdnnet.so: $(ISDNNET_OBJ)
$(CC) $(CFLAGS) -shared -Xlinker -x -o $@ $^
.c.o:
$(CC) $(CFLAGS) -o $@ -c $<
.c.lo:
$(CC) $(CFLAGS) -fPIC -o $@ -c $<
isdn_msg.o isdn_msg.lo: isdn_msg.c $(INCLUDEDIR)/isdn_msg.h $(INCLUDEDIR)/isdn_net.h
isdn_debug.o isdn_debug.lo: isdn_debug.c $(INCLUDEDIR)/isdn_debug.h
net_l2.o net_l2.lo: net_l2.c net_l2.h $(INCLUDEDIR)/isdn_net.h fsm.h
fsm.o fsm.lo: fsm.c fsm.h $(INCLUDEDIR)/isdn_net.h
tei.o tei.lo: tei.c net_l2.h $(INCLUDEDIR)/isdn_net.h
net_l3.o net_l3.lo: net_l3.c $(INCLUDEDIR)/isdn_net.h net_l3.h
manager.o manager.lo: manager.c $(INCLUDEDIR)/isdn_net.h $(INCLUDEDIR)/bchannel.h
net_if.o net_if.lo: net_if.c $(INCLUDEDIR)/isdn_net.h
tone.o tone.lo: tone.c $(INCLUDEDIR)/tone.h $(INCLUDEDIR)/bchannel.h \
$(INCLUDEDIR)/isdn_net.h $(INCLUDEDIR)/ibuffer.h
bchannel.o bchannel.lo: bchannel.c $(INCLUDEDIR)/isdn_net.h $(INCLUDEDIR)/tone.h \
$(INCLUDEDIR)/bchannel.h net_l3.h $(INCLUDEDIR)/ibuffer.h
g711.o g711.lo: g711.c $(INCLUDEDIR)/g711.h
clean:
rm -f *.o *.lo *~ DEADJOE
rm -f libisdnnet.a libisdnnet_pic.a libisdnnet.so
distclean: clean
rm -f *.a
.SUFFIXES: .lo

1380
i4lnet/bchannel.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,25 +1,17 @@
/* $Id: fsm.c,v 2.0 2004/06/29 14:35:31 kkeil Exp $
/* $Id$
*
* Author Karsten Keil (keil@isdn4linux.de)
*
* Author Karsten Keil <kkeil@novell.com>
* Thanks to Jan den Ouden
* Fritz Elfert
*
* Copyright 2007 by Karsten Keil <kkeil@novell.com>
*
* This code is free software; you can redistribute it and/or modify
* it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE
* version 2.1 as published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU LESSER GENERAL PUBLIC LICENSE for more details.
* This file is (c) under GNU PUBLIC LICENSE
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "fsm.h"
#include "debug.h"
#define FSM_TIMER_DEBUG 0
@ -34,12 +26,12 @@ FsmNew(struct Fsm *fsm,
if (!fsm->jumpmatrix)
return;
memset(fsm->jumpmatrix, 0, sizeof (FSMFNPTR) * fsm->state_count * fsm->event_count);
for (i = 0; i < fncount; i++)
for (i = 0; i < fncount; i++)
if ((fnlist[i].state>=fsm->state_count) || (fnlist[i].event>=fsm->event_count)) {
eprint("FsmNew Error line %d st(%ld/%ld) ev(%ld/%ld)\n",
i,(long)fnlist[i].state,(long)fsm->state_count,
(long)fnlist[i].event,(long)fsm->event_count);
} else
} else
fsm->jumpmatrix[fsm->state_count * fnlist[i].event +
fnlist[i].state] = (FSMFNPTR) fnlist[i].routine;
}
@ -80,32 +72,34 @@ FsmEvent(struct FsmInst *fi, int event, void *arg)
void
FsmChangeState(struct FsmInst *fi, int newstate)
{
if (fi->debug)
fi->printdebug(fi, "ChangeState %s -> %s",
fi->fsm->strState[fi->state], fi->fsm->strState[newstate]);
fi->state = newstate;
if (fi->debug)
fi->printdebug(fi, "ChangeState %s",
fi->fsm->strState[newstate]);
}
static void
FsmExpireTimer(void *arg)
static int
FsmExpireTimer(struct FsmTimer *ft)
{
struct FsmTimer *ft = arg;
#if FSM_TIMER_DEBUG
if (ft->fi->debug)
ft->fi->printdebug(ft->fi, "FsmExpireTimer %lx", (long) ft);
#endif
FsmEvent(ft->fi, ft->event, ft->arg);
return(0);
}
void
FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft)
{
ft->fi = fi;
ft->tl.function = (void *)FsmExpireTimer;
ft->tl.data = (long) ft;
#if FSM_TIMER_DEBUG
if (ft->fi->debug)
ft->fi->printdebug(ft->fi, "FsmInitTimer %lx", (long) ft);
#endif
init_timer(&ft->tl, ft->fi->tb, ft, FsmExpireTimer);
init_timer(&ft->tl, ft->fi->nst);
}
void
@ -118,6 +112,12 @@ FsmDelTimer(struct FsmTimer *ft, int where)
del_timer(&ft->tl);
}
void
FsmRemoveTimer(struct FsmTimer *ft)
{
remove_timer(&ft->tl);
}
int
FsmAddTimer(struct FsmTimer *ft,
int millisec, int event, void *arg, int where)
@ -130,13 +130,15 @@ FsmAddTimer(struct FsmTimer *ft,
#endif
if (timer_pending(&ft->tl)) {
eprint("FsmAddTimer: timer already active!\n");
wprint("FsmAddTimer: timer already active!\n");
ft->fi->printdebug(ft->fi, "FsmAddTimer already active!");
return -1;
}
init_timer(&ft->tl, ft->fi->nst);
ft->event = event;
ft->arg = arg;
add_timer(&ft->tl, millisec);
ft->tl.expires = millisec;
add_timer(&ft->tl);
return 0;
}
@ -153,7 +155,9 @@ FsmRestartTimer(struct FsmTimer *ft,
if (timer_pending(&ft->tl))
del_timer(&ft->tl);
init_timer(&ft->tl, ft->fi->nst);
ft->event = event;
ft->arg = arg;
add_timer(&ft->tl, millisec);
ft->tl.expires = millisec;
add_timer(&ft->tl);
}

53
i4lnet/fsm.h Normal file
View File

@ -0,0 +1,53 @@
/* $Id$
*
* This file is (c) under GNU PUBLIC LICENSE
*
*/
/* Statemachine */
#include "isdn_net.h"
struct FsmInst;
typedef void (* FSMFNPTR)(struct FsmInst *, int, void *);
struct Fsm {
FSMFNPTR *jumpmatrix;
int state_count, event_count;
char **strEvent, **strState;
};
struct FsmInst {
struct Fsm *fsm;
net_stack_t *nst;
int state;
int debug;
void *userdata;
int userint;
void (*printdebug) (struct FsmInst *, char *, ...);
};
struct FsmNode {
int state, event;
void (*routine) (struct FsmInst *, int, void *);
};
struct FsmTimer {
struct FsmInst *fi;
itimer_t tl;
int event;
void *arg;
};
extern void FsmNew(struct Fsm *, struct FsmNode *, int);
extern void FsmFree(struct Fsm *);
extern int FsmEvent(struct FsmInst *, int , void *);
extern void FsmChangeState(struct FsmInst *, int);
extern void FsmInitTimer(struct FsmInst *, struct FsmTimer *);
extern int FsmAddTimer(struct FsmTimer *, int, int, void *, int);
extern void FsmRestartTimer(struct FsmTimer *, int, int, void *, int);
extern void FsmDelTimer(struct FsmTimer *, int);
extern void FsmRemoveTimer(struct FsmTimer *);

928
i4lnet/g711.c Normal file
View File

@ -0,0 +1,928 @@
/*
* This source code is quick table lookup implementation of
* convert 16 bit linear PCM and A-law u-law (ITU G.711) codings
* Tables are generated using ITU G.711 example code from
* Sun Microsystems, Inc.
*
* (C)2001 Karsten Keil kkeil@suse.de
*
*
*
*/
#include "g711.h"
unsigned char _l2u[4096] = {
0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7,
0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0, 0xef,
0xef, 0xee, 0xee, 0xed, 0xed, 0xec, 0xec, 0xeb,
0xeb, 0xea, 0xea, 0xe9, 0xe9, 0xe8, 0xe8, 0xe7,
0xe7, 0xe6, 0xe6, 0xe5, 0xe5, 0xe4, 0xe4, 0xe3,
0xe3, 0xe2, 0xe2, 0xe1, 0xe1, 0xe0, 0xe0, 0xdf,
0xdf, 0xdf, 0xdf, 0xde, 0xde, 0xde, 0xde, 0xdd,
0xdd, 0xdd, 0xdd, 0xdc, 0xdc, 0xdc, 0xdc, 0xdb,
0xdb, 0xdb, 0xdb, 0xda, 0xda, 0xda, 0xda, 0xd9,
0xd9, 0xd9, 0xd9, 0xd8, 0xd8, 0xd8, 0xd8, 0xd7,
0xd7, 0xd7, 0xd7, 0xd6, 0xd6, 0xd6, 0xd6, 0xd5,
0xd5, 0xd5, 0xd5, 0xd4, 0xd4, 0xd4, 0xd4, 0xd3,
0xd3, 0xd3, 0xd3, 0xd2, 0xd2, 0xd2, 0xd2, 0xd1,
0xd1, 0xd1, 0xd1, 0xd0, 0xd0, 0xd0, 0xd0, 0xcf,
0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xce,
0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xcd,
0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcc,
0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcb,
0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xca,
0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xc9,
0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc8,
0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc7,
0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc6,
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc5,
0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc4,
0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc3,
0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc2,
0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc1,
0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc0,
0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xbf,
0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbe,
0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,
0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbd,
0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd,
0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbc,
0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc,
0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbb,
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb,
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba,
0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba,
0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xb9,
0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9,
0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb8,
0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8,
0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb7,
0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7,
0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb6,
0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6,
0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb5,
0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5,
0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb3,
0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3,
0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb2,
0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2,
0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb1,
0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1,
0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb0,
0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0,
0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xaf,
0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xae,
0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae,
0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae,
0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae,
0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xad,
0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xac,
0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xab,
0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa9,
0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9,
0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9,
0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9,
0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa8,
0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8,
0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8,
0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8,
0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa7,
0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7,
0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7,
0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7,
0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa6,
0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa5,
0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa4,
0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa3,
0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa2,
0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2,
0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2,
0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2,
0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa1,
0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa0,
0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0,
0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0,
0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0,
0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0x9f,
0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f,
0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f,
0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f,
0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f,
0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f,
0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f,
0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f,
0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9e,
0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,
0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,
0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,
0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,
0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,
0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,
0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,
0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9d,
0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d,
0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d,
0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d,
0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d,
0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d,
0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d,
0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d,
0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9c,
0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c,
0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c,
0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c,
0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c,
0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c,
0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c,
0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c,
0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9b,
0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9a,
0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a,
0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a,
0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a,
0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a,
0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a,
0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a,
0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a,
0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x99,
0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x98,
0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x97,
0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97,
0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97,
0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97,
0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97,
0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97,
0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97,
0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97,
0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x96,
0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96,
0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96,
0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96,
0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96,
0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96,
0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96,
0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96,
0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x95,
0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x94,
0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x93,
0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x92,
0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x91,
0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x8f,
0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8e,
0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8d,
0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8c,
0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8b,
0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8a,
0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x89,
0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x87,
0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x86,
0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x85,
0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x84,
0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x83,
0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x82,
0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
};
unsigned char _l2A[2048] = {
0xd5, 0xd4, 0xd7, 0xd6, 0xd1, 0xd0, 0xd3, 0xd2,
0xdd, 0xdc, 0xdf, 0xde, 0xd9, 0xd8, 0xdb, 0xda,
0xc5, 0xc4, 0xc7, 0xc6, 0xc1, 0xc0, 0xc3, 0xc2,
0xcd, 0xcc, 0xcf, 0xce, 0xc9, 0xc8, 0xcb, 0xca,
0xf5, 0xf5, 0xf4, 0xf4, 0xf7, 0xf7, 0xf6, 0xf6,
0xf1, 0xf1, 0xf0, 0xf0, 0xf3, 0xf3, 0xf2, 0xf2,
0xfd, 0xfd, 0xfc, 0xfc, 0xff, 0xff, 0xfe, 0xfe,
0xf9, 0xf9, 0xf8, 0xf8, 0xfb, 0xfb, 0xfa, 0xfa,
0xe5, 0xe5, 0xe5, 0xe5, 0xe4, 0xe4, 0xe4, 0xe4,
0xe7, 0xe7, 0xe7, 0xe7, 0xe6, 0xe6, 0xe6, 0xe6,
0xe1, 0xe1, 0xe1, 0xe1, 0xe0, 0xe0, 0xe0, 0xe0,
0xe3, 0xe3, 0xe3, 0xe3, 0xe2, 0xe2, 0xe2, 0xe2,
0xed, 0xed, 0xed, 0xed, 0xec, 0xec, 0xec, 0xec,
0xef, 0xef, 0xef, 0xef, 0xee, 0xee, 0xee, 0xee,
0xe9, 0xe9, 0xe9, 0xe9, 0xe8, 0xe8, 0xe8, 0xe8,
0xeb, 0xeb, 0xeb, 0xeb, 0xea, 0xea, 0xea, 0xea,
0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97,
0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96,
0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d,
0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c,
0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f,
0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,
0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a,
0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5,
0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5,
0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5,
0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7,
0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7,
0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7,
0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7,
0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6,
0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6,
0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6,
0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6,
0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1,
0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1,
0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1,
0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1,
0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0,
0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0,
0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0,
0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0,
0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3,
0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3,
0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3,
0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3,
0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2,
0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2,
0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2,
0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2,
0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd,
0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd,
0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd,
0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd,
0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc,
0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc,
0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc,
0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc,
0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,
0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,
0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,
0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,
0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9,
0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9,
0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9,
0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9,
0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8,
0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8,
0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8,
0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8,
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb,
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb,
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb,
0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb,
0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba,
0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba,
0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba,
0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba,
0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7,
0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7,
0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7,
0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7,
0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7,
0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7,
0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7,
0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7,
0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0,
0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0,
0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0,
0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0,
0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0,
0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0,
0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0,
0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0,
0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2,
0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2,
0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2,
0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2,
0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2,
0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2,
0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2,
0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2,
0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae,
0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae,
0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae,
0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae,
0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae,
0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae,
0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae,
0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae,
0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9,
0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9,
0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9,
0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9,
0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9,
0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9,
0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9,
0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9,
0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8,
0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8,
0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8,
0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8,
0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8,
0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8,
0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8,
0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8,
0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
};
signed short _u2l[256] = {
-32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956,
-23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764,
-15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412,
-11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316,
-7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
-5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
-3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
-2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
-1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
-1372, -1308, -1244, -1180, -1116, -1052, -988, -924,
-876, -844, -812, -780, -748, -716, -684, -652,
-620, -588, -556, -524, -492, -460, -428, -396,
-372, -356, -340, -324, -308, -292, -276, -260,
-244, -228, -212, -196, -180, -164, -148, -132,
-120, -112, -104, -96, -88, -80, -72, -64,
-56, -48, -40, -32, -24, -16, -8, -2,
32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316,
7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140,
5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092,
3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004,
2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980,
1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436,
1372, 1308, 1244, 1180, 1116, 1052, 988, 924,
876, 844, 812, 780, 748, 716, 684, 652,
620, 588, 556, 524, 492, 460, 428, 396,
372, 356, 340, 324, 308, 292, 276, 260,
244, 228, 212, 196, 180, 164, 148, 132,
120, 112, 104, 96, 88, 80, 72, 64,
56, 48, 40, 32, 24, 16, 8, 2,
};
signed short _A2l[256] = {
-5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
-7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
-2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
-3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
-22016,-20992,-24064,-23040,-17920,-16896,-19968,-18944,
-30208,-29184,-32256,-31232,-26112,-25088,-28160,-27136,
-11008,-10496,-12032,-11520, -8960, -8448, -9984, -9472,
-15104,-14592,-16128,-15616,-13056,-12544,-14080,-13568,
-344, -328, -376, -360, -280, -264, -312, -296,
-472, -456, -504, -488, -408, -392, -440, -424,
-88, -72, -120, -104, -24, -8, -56, -40,
-216, -200, -248, -232, -152, -136, -184, -168,
-1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
-1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
-688, -656, -752, -720, -560, -528, -624, -592,
-944, -912, -1008, -976, -816, -784, -880, -848,
5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736,
7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784,
2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368,
3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392,
22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472,
15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
344, 328, 376, 360, 280, 264, 312, 296,
472, 456, 504, 488, 408, 392, 440, 424,
88, 72, 120, 104, 24, 8, 56, 40,
216, 200, 248, 232, 152, 136, 184, 168,
1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184,
1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696,
688, 656, 752, 720, 560, 528, 624, 592,
944, 912, 1008, 976, 816, 784, 880, 848,
};
unsigned char _u2A[256] = {
0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d,
0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25,
0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d,
0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35,
0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d,
0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05,
0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x12,
0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x6a,
0x68, 0x69, 0x6e, 0x6f, 0x6c, 0x6d, 0x62, 0x63,
0x60, 0x61, 0x66, 0x67, 0x64, 0x65, 0x7a, 0x78,
0x7e, 0x7f, 0x7c, 0x7d, 0x72, 0x73, 0x70, 0x71,
0x76, 0x77, 0x74, 0x75, 0x4b, 0x49, 0x4f, 0x4d,
0x42, 0x43, 0x40, 0x41, 0x46, 0x47, 0x44, 0x45,
0x5a, 0x5b, 0x58, 0x59, 0x5e, 0x5f, 0x5c, 0x5d,
0x52, 0x52, 0x53, 0x53, 0x50, 0x50, 0x51, 0x51,
0x56, 0x56, 0x57, 0x57, 0x54, 0x54, 0x55, 0x55,
0xaa, 0xab, 0xa8, 0xa9, 0xae, 0xaf, 0xac, 0xad,
0xa2, 0xa3, 0xa0, 0xa1, 0xa6, 0xa7, 0xa4, 0xa5,
0xba, 0xbb, 0xb8, 0xb9, 0xbe, 0xbf, 0xbc, 0xbd,
0xb2, 0xb3, 0xb0, 0xb1, 0xb6, 0xb7, 0xb4, 0xb5,
0x8a, 0x8b, 0x88, 0x89, 0x8e, 0x8f, 0x8c, 0x8d,
0x82, 0x83, 0x80, 0x81, 0x86, 0x87, 0x84, 0x85,
0x9b, 0x98, 0x99, 0x9e, 0x9f, 0x9c, 0x9d, 0x92,
0x93, 0x90, 0x91, 0x96, 0x97, 0x94, 0x95, 0xea,
0xe8, 0xe9, 0xee, 0xef, 0xec, 0xed, 0xe2, 0xe3,
0xe0, 0xe1, 0xe6, 0xe7, 0xe4, 0xe5, 0xfa, 0xf8,
0xfe, 0xff, 0xfc, 0xfd, 0xf2, 0xf3, 0xf0, 0xf1,
0xf6, 0xf7, 0xf4, 0xf5, 0xcb, 0xc9, 0xcf, 0xcd,
0xc2, 0xc3, 0xc0, 0xc1, 0xc6, 0xc7, 0xc4, 0xc5,
0xda, 0xdb, 0xd8, 0xd9, 0xde, 0xdf, 0xdc, 0xdd,
0xd2, 0xd2, 0xd3, 0xd3, 0xd0, 0xd0, 0xd1, 0xd1,
0xd6, 0xd6, 0xd7, 0xd7, 0xd4, 0xd4, 0xd5, 0xd5,
};
unsigned char _A2u[256] = {
0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d,
0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25,
0x39, 0x3a, 0x37, 0x38, 0x3d, 0x3e, 0x3b, 0x3c,
0x31, 0x32, 0x30, 0x30, 0x35, 0x36, 0x33, 0x34,
0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d,
0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05,
0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d,
0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15,
0x62, 0x63, 0x60, 0x61, 0x66, 0x67, 0x64, 0x65,
0x5d, 0x5d, 0x5c, 0x5c, 0x5f, 0x5f, 0x5e, 0x5e,
0x74, 0x76, 0x70, 0x72, 0x7c, 0x7e, 0x78, 0x7a,
0x6a, 0x6b, 0x68, 0x69, 0x6e, 0x6f, 0x6c, 0x6d,
0x48, 0x49, 0x46, 0x47, 0x4c, 0x4d, 0x4a, 0x4b,
0x40, 0x41, 0x3f, 0x3f, 0x44, 0x45, 0x42, 0x43,
0x56, 0x57, 0x54, 0x55, 0x5a, 0x5b, 0x58, 0x59,
0x4f, 0x4f, 0x4e, 0x4e, 0x52, 0x53, 0x50, 0x51,
0xaa, 0xab, 0xa8, 0xa9, 0xae, 0xaf, 0xac, 0xad,
0xa2, 0xa3, 0xa0, 0xa1, 0xa6, 0xa7, 0xa4, 0xa5,
0xb9, 0xba, 0xb7, 0xb8, 0xbd, 0xbe, 0xbb, 0xbc,
0xb1, 0xb2, 0xb0, 0xb0, 0xb5, 0xb6, 0xb3, 0xb4,
0x8a, 0x8b, 0x88, 0x89, 0x8e, 0x8f, 0x8c, 0x8d,
0x82, 0x83, 0x80, 0x81, 0x86, 0x87, 0x84, 0x85,
0x9a, 0x9b, 0x98, 0x99, 0x9e, 0x9f, 0x9c, 0x9d,
0x92, 0x93, 0x90, 0x91, 0x96, 0x97, 0x94, 0x95,
0xe2, 0xe3, 0xe0, 0xe1, 0xe6, 0xe7, 0xe4, 0xe5,
0xdd, 0xdd, 0xdc, 0xdc, 0xdf, 0xdf, 0xde, 0xde,
0xf4, 0xf6, 0xf0, 0xf2, 0xfc, 0xfe, 0xf8, 0xfa,
0xea, 0xeb, 0xe8, 0xe9, 0xee, 0xef, 0xec, 0xed,
0xc8, 0xc9, 0xc6, 0xc7, 0xcc, 0xcd, 0xca, 0xcb,
0xc0, 0xc1, 0xbf, 0xbf, 0xc4, 0xc5, 0xc2, 0xc3,
0xd6, 0xd7, 0xd4, 0xd5, 0xda, 0xdb, 0xd8, 0xd9,
0xcf, 0xcf, 0xce, 0xce, 0xd2, 0xd3, 0xd0, 0xd1,
};

160
i4lnet/isdn_debug.c Normal file
View File

@ -0,0 +1,160 @@
#include <stdarg.h>
#include <time.h>
#include <string.h>
#include "isdn_debug.h"
static unsigned int debug_mask = 0;
static FILE *debug_file = NULL;
static FILE *warn_file = NULL;
static FILE *error_file = NULL;
int
debug_init(unsigned int mask, char *dfile, char *wfile, char *efile)
{
if (dfile) {
if (debug_file && (debug_file != stdout))
debug_file = freopen(dfile, "a", debug_file);
else
debug_file = fopen(dfile, "a");
if (!debug_file) {
debug_file = stdout;
fprintf(debug_file,
"%s: cannot open %s for debug log, using stdout\n",
__FUNCTION__, dfile);
}
} else {
if (!debug_file) {
debug_file = stdout;
// fprintf(debug_file,
// "%s: using stdout for debug log\n", __FUNCTION__);
}
}
if (wfile) {
if (warn_file && (warn_file != stderr))
warn_file = freopen(wfile, "a", warn_file);
else
warn_file = fopen(wfile, "a");
if (!warn_file) {
warn_file = stderr;
fprintf(warn_file,
"%s: cannot open %s for warning log, using stderr\n",
__FUNCTION__, wfile);
}
} else {
if (!warn_file) {
warn_file = stderr;
// fprintf(warn_file,
// "%s: using stderr for warning log\n", __FUNCTION__);
}
}
if (efile) {
if (error_file && (error_file != stderr))
error_file = freopen(efile, "a", error_file);
else
error_file = fopen(efile, "a");
if (!error_file) {
error_file = stderr;
fprintf(error_file,
"%s: cannot open %s for error log, using stderr\n",
__FUNCTION__, efile);
}
} else {
if (!error_file) {
error_file = stderr;
// fprintf(error_file,
// "%s: using stderr for error log\n", __FUNCTION__);
}
}
debug_mask = mask;
// fprintf(debug_file, "%s: debug_mask = %x\n", __FUNCTION__, debug_mask);
return(0);
}
void
debug_close(void)
{
// fprintf(debug_file, "%s: debug channel now closed\n", __FUNCTION__);
if (debug_file && (debug_file != stdout))
fclose(debug_file);
// fprintf(warn_file, "%s: warn channel now closed\n", __FUNCTION__);
if (warn_file && (warn_file != stderr))
fclose(warn_file);
// fprintf(error_file, "%s: error channel now closed\n", __FUNCTION__);
if (error_file && (error_file != stderr))
fclose(error_file);
}
int
dprint(unsigned int mask, int port, const char *fmt, ...)
{
int ret = 0;
va_list args;
time_t tm = time(NULL);
char *tmp=ctime(&tm),*p;
p=strchr(tmp,'\n');
if (p) *p=':';
va_start(args, fmt);
if (debug_mask & mask) {
if (debug_file != stdout)
fprintf(debug_file, "%s P(%02d): L(0x%02x):",tmp, port,mask);
ret = vfprintf(debug_file, fmt, args);
if (debug_file != stdout)
fflush(debug_file);
}
va_end(args);
return(ret);
}
int
wprint(const char *fmt, ...)
{
int ret = 0;
va_list args;
va_start(args, fmt);
ret = vfprintf(warn_file, fmt, args);
fflush(warn_file);
va_end(args);
return(ret);
}
int
eprint(const char *fmt, ...)
{
int ret = 0;
va_list args;
va_start(args, fmt);
ret = vfprintf(error_file, fmt, args);
fflush(error_file);
va_end(args);
return(ret);
}
int
dhexprint(unsigned int mask, char *head, unsigned char *buf, int len)
{
int ret = 0;
char *p,*obuf;
if (debug_mask & mask) {
obuf = malloc(3*(len+1));
if (!obuf)
return(-ENOMEM);
p = obuf;
while (len) {
p += sprintf(p,"%02x ", *buf);
buf++;
len--;
}
p--;
*p=0;
ret = fprintf(debug_file, "%s %s\n", head, obuf);
free(obuf);
}
return(ret);
}

112
i4lnet/isdn_msg.c Normal file
View File

@ -0,0 +1,112 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "isdn_msg.h"
#include "isdn_debug.h"
static msg_queue_t _free_queue;
msg_queue_t *free_queue;
void
msg_init(void)
{
free_queue = & _free_queue;
msg_queue_init(free_queue);
free_queue->maxlen = 40;
}
static int alloc_msg_cnt = 0;
msg_t *
_new_msg(int size)
{
msg_t *m;
if (size <= MAX_MSG_SIZE)
size = MAX_MSG_SIZE;
else
goto err;
m = malloc(sizeof(msg_t));
if (!m)
goto err;
m->size = size;
alloc_msg_cnt++;
return(m);
err:
eprint("%s: no mem for size %d msg\n", __FUNCTION__,
size);
return(NULL);
}
msg_t *
alloc_msg(int size)
{
msg_t *m;
if (size > MAX_MSG_SIZE)
return(NULL);
if (msg_queue_len(free_queue))
m = msg_dequeue(free_queue);
else
m = _new_msg(size);
if (!m) {
eprint("%s: no mem for msg len (%d)\n", __FUNCTION__,
size);
return(NULL);
}
m->list = NULL;
m->prev = NULL;
m->next = NULL;
m->head = &m->__data[0];
m->data = m->head + DEFAULT_HEADROOM;
m->tail = m->data;
m->end = m->head + m->size;
m->len = 0;
dprint(DBGM_MSG, -1,"%s: %d msg(%p)\n", __FUNCTION__,
alloc_msg_cnt, m);
return(m);
}
void
free_msg(msg_t *msg) {
if (!msg) {
wprint("free NULL msg\n");
return;
}
dprint(DBGM_MSG, -1,"%s: %d/%d msg(%p) \n", __FUNCTION__,
alloc_msg_cnt, free_queue->len, msg);
if (msg->list) {
if (msg->list == free_queue)
wprint("%s: free twice msg(%p)\n", __FUNCTION__,
msg);
else
wprint("%s: msg(%p) in queue(%p)\n", __FUNCTION__,
msg, msg->list);
return;
}
if (free_queue->len>=free_queue->maxlen) {
alloc_msg_cnt--;
dprint(DBGM_MSG, -1, "free msg no free_queue %d/%d\n",
free_queue->len, free_queue->maxlen);
free(msg);
return;
}
msg_queue_head(free_queue, msg);
}
msg_t *
msg_copy(msg_t *msg) {
msg_t *nmsg;
dprint(DBGM_MSG, -1,"%s: old(%p)\n", __FUNCTION__, msg);
nmsg = alloc_msg(msg->size);
if (!nmsg)
return(NULL);
dprint(DBGM_MSG, -1,"%s: new(%p) size(%d)\n", __FUNCTION__,
nmsg, msg->size);
memcpy(nmsg, msg, sizeof(msg_t));
return(nmsg);
}

286
i4lnet/manager.c Normal file
View File

@ -0,0 +1,286 @@
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "isdn_net.h"
#include "l3dss1.h"
#include "net_l2.h"
#include "net_l3.h"
#include "bchannel.h"
#include "helper.h"
int
match_nr(manager_t *mgr, unsigned char *nx, nr_list_t **nrx)
{
int l,i,ret = 2;
unsigned char *p;
nr_list_t *nr = mgr->nrlist;
if (!nrx)
return(3);
l = nx[0] - 1;
if (l<=0)
return(3);
while(nr) {
p = nx + 2;
dprint(DBGM_MAN, -1,"%s: cpn(%s) nr(%s)\n", __FUNCTION__,
p, nr->nr);
for(i=0;i<nr->len;i++) {
if (*p != nr->nr[i])
break;
if ((i+1) == nr->len) {
*nrx = nr;
return(0);
}
if (l == (i+1)) {
ret = 1;
break;
}
p++;
}
nr = nr->next;
}
return(ret);
}
static int
manager2stack(void *dat, void *arg)
{
net_stack_t *nst = dat;
msg_t *msg = arg;
mISDNuser_head_t *hh;
dprint(DBGM_MAN, -1, "%s:dat(%p) arg(%p)\n", __FUNCTION__,
dat, arg);
if (!nst | !arg)
return(-EINVAL);
hh = (mISDNuser_head_t *)msg->data;
dprint(DBGM_MAN, -1, "%s: prim(%x) dinfo(%x) msg->len(%d)\n", __FUNCTION__,
hh->prim, hh->dinfo, msg->len);
if (hh->prim == (CC_NEW_CR | INDICATION)) /* high prio */
msg_queue_head(&nst->wqueue, arg);
else
msg_queue_tail(&nst->wqueue, arg);
sem_post(&nst->work);
return(0);
}
static int
stack2manager(void *dat, void *arg) {
manager_t *mgr = dat;
msg_t *msg = arg;
mISDNuser_head_t *hh;
if (!msg || !mgr)
return(-EINVAL);
hh = (mISDNuser_head_t *)msg->data;
dprint(DBGM_MAN, -1, "%s: prim(%x) dinfo(%x) msg->len(%d) bid(%x/%x)\n", __FUNCTION__,
hh->prim, hh->dinfo, msg->len, mgr->bc[0].l3id, mgr->bc[1].l3id);
if (hh->prim == (CC_SETUP | INDICATION)) {
SETUP_t *setup;
RELEASE_COMPLETE_t *rc;
unsigned char cause[4];
setup = (SETUP_t*)(msg->data + mISDNUSER_HEAD_SIZE);
pthread_mutex_lock(&mgr->bc[0].lock);
if (mgr->bc[0].cstate == BC_CSTATE_NULL) {
mgr->bc[0].cstate = BC_CSTATE_ICALL;
msg_queue_tail(&mgr->bc[0].workq, msg);
pthread_mutex_unlock(&mgr->bc[0].lock);
sem_post(&mgr->bc[0].work);
return(0);
}
pthread_mutex_unlock(&mgr->bc[0].lock);
pthread_mutex_lock(&mgr->bc[1].lock);
if (mgr->bc[1].cstate == BC_CSTATE_NULL) {
mgr->bc[1].cstate = BC_CSTATE_ICALL;
msg_queue_tail(&mgr->bc[1].workq, msg);
pthread_mutex_unlock(&mgr->bc[1].lock);
sem_post(&mgr->bc[1].work);
return(0);
}
pthread_mutex_unlock(&mgr->bc[1].lock);
/* No channel available */
cause[0] = 2;
cause[1] = 0x80 | CAUSE_LOC_PNET_LOCUSER;
if (setup->CHANNEL_ID)
cause[2] = 0x80 | CAUSE_CHANNEL_UNACCEPT;
else
cause[2] = 0x80 | CAUSE_NO_CHANNEL;
prep_l3data_msg(CC_RELEASE_COMPLETE | REQUEST, hh->dinfo,
sizeof(RELEASE_COMPLETE_t), 3, msg);
rc = (RELEASE_COMPLETE_t *)(msg->data + mISDNUSER_HEAD_SIZE);
rc->CAUSE = msg_put(msg, 3);
memcpy(rc->CAUSE, &cause, 3);
if (manager2stack(mgr->nst, msg))
free_msg(msg);
} else if (hh->dinfo == mgr->bc[0].l3id) {
msg_queue_tail(&mgr->bc[0].workq, msg);
sem_post(&mgr->bc[0].work);
} else if (hh->dinfo == mgr->bc[1].l3id) {
msg_queue_tail(&mgr->bc[1].workq, msg);
sem_post(&mgr->bc[1].work);
} else {
wprint("%s: prim(%x) dinfo(%x) msg->len(%d) not handled\n", __FUNCTION__,
hh->prim, hh->dinfo, msg->len);
return(-ESRCH);
}
return(0);
}
static int
appl2bc(manager_t *mgr, int prim, void *arg)
{
bchannel_t *bc = arg;
msg_t *msg;
dprint(DBGM_MAN, -1, "%s(%p,%x,%p)\n", __FUNCTION__,
mgr, prim, arg);
if (!mgr || !bc)
return(-EINVAL);
if (prim == PR_APP_OCHANNEL) {
bchannel_t **bcp = arg;
pthread_mutex_lock(&mgr->bc[0].lock);
if (mgr->bc[0].cstate == BC_CSTATE_NULL) {
mgr->bc[0].cstate = BC_CSTATE_OCALL;
pthread_mutex_unlock(&mgr->bc[0].lock);
*bcp = &mgr->bc[0];
return(1);
}
pthread_mutex_unlock(&mgr->bc[0].lock);
pthread_mutex_lock(&mgr->bc[1].lock);
if (mgr->bc[1].cstate == BC_CSTATE_NULL) {
mgr->bc[1].cstate = BC_CSTATE_OCALL;
pthread_mutex_unlock(&mgr->bc[1].lock);
*bcp = &mgr->bc[1];
return(2);
}
pthread_mutex_unlock(&mgr->bc[1].lock);
/* No channel available */
return(-EBUSY);
} else if (prim == PR_APP_OCALL) {
pthread_mutex_lock(&bc->lock);
msg = create_link_msg(CC_SETUP | REQUEST, bc->l3id, 0,
NULL, 0);
if (!msg)
return(-ENOMEM);
msg_queue_tail(&bc->workq, msg);
sem_post(&bc->work);
pthread_mutex_unlock(&bc->lock);
} else if (prim == PR_APP_ALERT) {
pthread_mutex_lock(&bc->lock);
msg = create_link_msg(CC_ALERTING | REQUEST, bc->l3id, 0,
NULL, 0);
if (!msg)
return(-ENOMEM);
msg_queue_tail(&bc->workq, msg);
sem_post(&bc->work);
pthread_mutex_unlock(&bc->lock);
} else if (prim == PR_APP_CONNECT) {
pthread_mutex_lock(&bc->lock);
msg = create_link_msg(CC_CONNECT | REQUEST, bc->l3id, 0,
NULL, 0);
if (!msg)
return(-ENOMEM);
msg_queue_tail(&bc->workq, msg);
sem_post(&bc->work);
pthread_mutex_unlock(&bc->lock);
} else if (prim == PR_APP_HANGUP) {
pthread_mutex_lock(&bc->lock);
msg = create_link_msg(CC_DISCONNECT | REQUEST, bc->l3id, 0,
NULL, 0);
if (!msg)
return(-ENOMEM);
msg_queue_tail(&bc->workq, msg);
sem_post(&bc->work);
pthread_mutex_unlock(&bc->lock);
} else if (prim == PR_APP_FACILITY) {
pthread_mutex_lock(&bc->lock);
msg = create_link_msg(CC_FACILITY | REQUEST, bc->l3id,
0, NULL, 0);
if (!msg)
return(-ENOMEM);
msg_queue_tail(&bc->workq, msg);
sem_post(&bc->work);
pthread_mutex_unlock(&bc->lock);
} else if (prim == PR_APP_USERUSER) {
pthread_mutex_lock(&bc->lock);
msg = create_link_msg(CC_USER_INFORMATION | REQUEST, bc->l3id,
0, NULL, 0);
if (!msg)
return(-ENOMEM);
msg_queue_tail(&bc->workq, msg);
sem_post(&bc->work);
pthread_mutex_unlock(&bc->lock);
} else {
wprint("%s(%p,%x,%p) unhandled\n", __FUNCTION__,
mgr, prim, arg);
}
return(0);
}
int
init_manager(manager_t **mlist, afunc_t application)
{
manager_t *mgr;
int ret;
*mlist = NULL;
mgr = malloc(sizeof(manager_t));
if (!mgr)
return(-ENOMEM);
memset(mgr, 0, sizeof(manager_t));
mgr->nst = malloc(sizeof(net_stack_t));
if (!mgr->nst) {
free(mgr);
return(-ENOMEM);
}
memset(mgr->nst, 0, sizeof(net_stack_t));
ret = do_net_stack_setup(mgr->nst);
if (ret) {
free(mgr->nst);
free(mgr);
return(ret);
}
mgr->application = application;
mgr->app_bc = appl2bc;
mgr->man2stack = manager2stack;
mgr->nst->l3_manager = stack2manager;
mgr->nst->manager = mgr;
Isdnl2Init(mgr->nst);
Isdnl3Init(mgr->nst);
mgr->bc[0].manager = mgr;
mgr->bc[1].manager = mgr;
init_bchannel(&mgr->bc[0], 1);
init_bchannel(&mgr->bc[1], 2);
*mlist = mgr;
return(0);
}
int
cleanup_manager(manager_t *mgr)
{
int ret, *retv;
dprint(DBGM_MAN, -1,"%s\n", __FUNCTION__);
term_bchannel(&mgr->bc[0]);
term_bchannel(&mgr->bc[1]);
cleanup_Isdnl3(mgr->nst);
cleanup_Isdnl2(mgr->nst);
do_net_stack_cleanup(mgr->nst);
ret = pthread_join(mgr->bc[0].tid, (void *)&retv);
dprint(DBGM_MAN, -1,"%s: join ret(%d) bc1 retv(%p)\n", __FUNCTION__,
ret, retv);
ret = pthread_join(mgr->bc[1].tid, (void *)&retv);
dprint(DBGM_MAN, -1,"%s: join ret(%d) bc2 retv(%p)\n", __FUNCTION__,
ret, retv);
while(mgr->nrlist) {
nr_list_t *nr = mgr->nrlist;
REMOVE_FROM_LISTBASE(nr, mgr->nrlist);
free(nr);
}
free(mgr->nst);
free(mgr);
return(0);
}

712
i4lnet/net_if.c Normal file
View File

@ -0,0 +1,712 @@
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "net_l2.h"
#include "isdn_net.h"
#include "bchannel.h"
#include "helper.h"
int
do_net_stack_setup(net_stack_t *nst)
{
int ret;
unsigned char buf[1024];
int i,cnt;
iframe_t *frm = (iframe_t *)buf;
stack_info_t *stinf;
layer_info_t li;
#ifdef OBSOLETE
interface_info_t ii;
#endif
if (!nst)
return(-EINVAL);
if (nst->device)
return(-EBUSY);
ret = mISDN_open();
if (0 > ret) {
wprint("cannot open mISDN due to %s\n",
strerror(errno));
return(ret);
}
nst->device = ret;
cnt = mISDN_get_stack_count(nst->device);
if (cnt < 1) {
mISDN_close(nst->device);
wprint("no cards found ret(%d)\n", cnt);
return(-ENODEV);
}
for (i=1; i<=cnt; i++) {
ret = mISDN_get_stack_info(nst->device, i, buf, 1024);
if (ret<=0)
dprint(DBGM_NET, nst->cardnr, "cannot get stackinfo err: %d\n", ret);
stinf = (stack_info_t *)&frm->data.p;
// mISDNprint_stack_info(stdout, stinf);
if ((stinf->pid.protocol[0] == ISDN_PID_L0_NT_S0) &&
(stinf->pid.protocol[1] == ISDN_PID_L1_NT_S0)) {
if (stinf->instcnt == 1) {
nst->cardnr = i;
nst->d_stid = stinf->id;
nst->b_stid[0] = stinf->child[0];
nst->b_stid[1] = stinf->child[1];
dprint(DBGM_NET, nst->cardnr, "bst1 %x bst2 %x\n",
nst->b_stid[0], nst->b_stid[1]);
break;
} else
dprint(DBGM_NET, nst->cardnr, "stack %d instcnt is %d\n",
i, stinf->instcnt);
} else
dprint(DBGM_NET, nst->cardnr, "stack %d protocol %x\n",
i, stinf->pid.protocol[0]);
}
if (i>cnt) {
mISDN_close(nst->device);
wprint("no NT cards found\n");
return(-ENODEV);
}
nst->l1_id = mISDN_get_layerid(nst->device, nst->d_stid, 1);
if (nst->l1_id < 0) {
mISDN_close(nst->device);
eprint("no layer1 id found\n");
return(-EINVAL);
}
dprint(DBGM_NET, nst->cardnr, "found NT card stack card%d dst(%x) l1(%x)\n",
nst->cardnr, nst->d_stid, nst->l1_id);
memset(&li, 0, sizeof(layer_info_t));
strcpy(&li.name[0], "net l2");
li.object_id = -1;
li.extentions = 0;
li.pid.protocol[2] = ISDN_PID_L2_LAPD_NET;
li.pid.layermask = ISDN_LAYER(2);
li.st = nst->d_stid;
nst->l2_id = mISDN_new_layer(nst->device, &li);
if (nst->l2_id<=0) {
eprint("cannot add layer2 error %d %s\n",
nst->l2_id, strerror(-nst->l2_id));
mISDN_close(nst->device);
return(nst->l2_id);
}
#ifdef OBSOLETE
ii.extentions = EXT_IF_EXCLUSIV;
ii.owner = nst->l2_id;
ii.peer = nst->l1_id;
ii.stat = IF_DOWN;
ret = mISDN_connect(nst->device, &ii);
if (ret) {
eprint("cannot connect layer1 error %d %s\n",
ret, strerror(-ret));
mISDN_close(nst->device);
return(ret);
}
#endif
dprint(DBGM_NET, nst->cardnr, "add nt net layer2 %x\n",
nst->l2_id);
msg_queue_init(&nst->down_queue);
msg_queue_init(&nst->rqueue);
msg_queue_init(&nst->wqueue);
pthread_mutex_init(&nst->lock, NULL);
ret = sem_init (&nst->work, 0, 0);
if (ret) {
eprint("cannot init semaphore ret(%d) %d %s\n",
ret, errno, strerror(errno));
return(ret);
}
return(0);
}
int
do_net_stack_cleanup(net_stack_t *nst)
{
int ret;
msg_queue_purge(&nst->down_queue);
msg_queue_purge(&nst->rqueue);
msg_queue_purge(&nst->wqueue);
if (nst->phd_down_msg)
free_msg(nst->phd_down_msg);
nst->phd_down_msg = NULL;
mISDN_close(nst->device);
ret = sem_destroy(&nst->work);
if (ret) {
eprint("cannot destroy semaphore ret(%d) %d %s\n",
ret, errno, strerror(errno));
return(ret);
}
ret = pthread_mutex_destroy(&nst->lock);
if (ret) {
eprint("cannot destroy mutex ret(%d) %s\n",
ret, strerror(ret));
return(ret);
}
return(0);
}
static itimer_t
*get_timer(net_stack_t *nst, int id)
{
itimer_t *it = nst->tlist;
while(it) {
if (it->id == id)
break;
it = it->next;
}
return(it);
}
int
init_timer(itimer_t *it, net_stack_t *nst)
{
iframe_t frm;
int ret;
if (!nst)
return(-ENODEV);
if (!get_timer(nst, it->id)) {
it->id = (int)it;
it->Flags = 0;
it->nst = nst;
it->prev = NULL;
if (nst->tlist) {
nst->tlist->prev = it;
it->next = nst->tlist;
}
nst->tlist = it;
}
dprint(DBGM_NET, nst->cardnr, "init timer(%x)\n", it->id);
if (test_bit(FLG_TIMER_RUNING, &it->Flags))
dprint(DBGM_NET, nst->cardnr, "init timer(%x) while running\n", it->id);
ret = mISDN_write_frame(it->nst->device, &frm, it->id,
MGR_INITTIMER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
if (ret)
wprint("cannot init timer %p err(%d) %s\n",
it, errno, strerror(errno));
return(ret);
}
int
remove_timer(itimer_t *it)
{
iframe_t frm;
int ret;
if (!it->nst)
return(-ENODEV);
if (!get_timer(it->nst, it->id))
return(-ENODEV);
ret = mISDN_write_frame(it->nst->device, &frm, it->id,
MGR_REMOVETIMER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
if (ret)
wprint("cannot remove timer %p err(%d) %s\n",
it, errno, strerror(errno));
REMOVE_FROM_LISTBASE(it, it->nst->tlist);
return(ret);
}
int
add_timer(itimer_t *it)
{
iframe_t frm;
int ret;
if (!it->nst)
return(-ENODEV);
if (!get_timer(it->nst, it->id))
return(-ENODEV);
if (timer_pending(it))
return(-EBUSY);
dprint(DBGM_NET, it->nst->cardnr, "add timer(%x)\n", it->id);
test_and_set_bit(FLG_TIMER_RUNING, &it->Flags);
ret = mISDN_write_frame(it->nst->device, &frm, it->id,
MGR_ADDTIMER | REQUEST, it->expires, 0, NULL, TIMEOUT_1SEC);
if (ret)
wprint("cannot add timer %p (%d ms) err(%d) %s\n",
it, it->expires, errno, strerror(errno));
return(ret);
}
int
del_timer(itimer_t *it)
{
iframe_t frm;
int ret;
if (!it->nst)
return(-ENODEV);
if (!get_timer(it->nst, it->id))
return(-ENODEV);
dprint(DBGM_NET, it->nst->cardnr, "del timer(%x)\n", it->id);
test_and_clear_bit(FLG_TIMER_RUNING, &it->Flags);
ret = mISDN_write_frame(it->nst->device, &frm, it->id,
MGR_DELTIMER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
if (ret)
wprint("cannot del timer %p (%d ms) err(%d) %s\n",
it, it->expires, errno, strerror(errno));
return(ret);
}
int
timer_pending(itimer_t *it)
{
return(test_bit(FLG_TIMER_RUNING, &it->Flags));
}
static int
handle_timer(net_stack_t *nst, int id)
{
itimer_t *it;
int ret = 0;
it = get_timer(nst, id);
if (!it)
return(-ENODEV);
// dprint(DBGM_NET, nst->cardnr, "handle timer(%x)\n", it->id);
test_and_clear_bit(FLG_TIMER_RUNING, &it->Flags);
if (it->function)
ret = it->function(it->data);
return(ret);
}
int
write_dmsg(net_stack_t *nst, msg_t *msg)
{
iframe_t *frm;
mISDNuser_head_t *hh;
hh = (mISDNuser_head_t *)msg->data;
dprint(DBGM_NET, nst->cardnr, "%s: msg(%p) len(%d) pr(%x) di(%x) q(%d)\n", __FUNCTION__,
msg, msg->len, hh->prim, hh->dinfo, nst->phd_down_msg?1:0);
msg_pull(msg, mISDNUSER_HEAD_SIZE);
frm = (iframe_t *)msg_push(msg, mISDN_HEADER_LEN);
frm->prim = hh->prim;
frm->dinfo = hh->dinfo;
frm->addr = nst->l2_id | FLG_MSG_DOWN;
frm->len = msg->len - mISDN_HEADER_LEN;
if (frm->prim == PH_DATA_REQ) {
frm->dinfo = (int)msg;
if (nst->phd_down_msg) {
msg_queue_tail(&nst->down_queue, msg);
return(0);
}
nst->phd_down_msg = msg;
}
mISDN_write(nst->device, msg->data, msg->len, -1);
free_msg(msg);
return(0);
}
int
phd_conf(net_stack_t *nst, iframe_t *frm, msg_t *msg)
{
dprint(DBGM_NET, nst->cardnr, "%s: di(%x)\n", __FUNCTION__, frm->dinfo);
if (frm->dinfo == (int)nst->phd_down_msg) {
free_msg(msg);
nst->phd_down_msg = msg_dequeue(&nst->down_queue);
if (nst->phd_down_msg) {
mISDN_write(nst->device, nst->phd_down_msg->data,
nst->phd_down_msg->len, -1);
free_msg(nst->phd_down_msg);
}
return(0);
} else {
wprint("%s: not matching %p/%#x\n", __FUNCTION__,
nst->phd_down_msg, frm->dinfo);
return(-EINVAL);
}
}
static int
do_net_read(net_stack_t *nst)
{
msg_t *msg;
iframe_t *frm;
int ret;
msg = alloc_msg(MAX_MSG_SIZE);
if (!msg)
return(-ENOMEM);
ret = mISDN_read(nst->device, msg->data, MAX_MSG_SIZE, -1);
if (ret<0) {
free_msg(msg);
if (errno == EAGAIN)
return(0);
else
return(-errno);
}
if (!ret) {
wprint("do_net_read read nothing\n");
free_msg(msg);
return(-EINVAL);
}
__msg_trim(msg, ret);
frm = (iframe_t *)msg->data;
dprint(DBGM_NET, nst->cardnr,"%s: prim(%x) addr(%x)\n", __FUNCTION__,
frm->prim, frm->addr);
switch (frm->prim) {
case MGR_INITTIMER | CONFIRM:
case MGR_ADDTIMER | CONFIRM:
case MGR_DELTIMER | CONFIRM:
case MGR_REMOVETIMER | CONFIRM:
// dprint(DBGM_NET, nst->cardnr, "timer(%x) cnf(%x)\n",
// frm->addr, frm->prim);
free_msg(msg);
return(0);
}
msg_queue_tail(&nst->rqueue, msg);
sem_post(&nst->work);
return(0);
}
static int
b_message(net_stack_t *nst, int ch, iframe_t *frm, msg_t *msg)
{
mISDNuser_head_t *hh;
msg_pull(msg, mISDN_HEADER_LEN);
hh = (mISDNuser_head_t *)msg_push(msg, mISDNUSER_HEAD_SIZE);
hh->prim = frm->prim;
hh->dinfo = nst->bcid[ch];
if (nst->l3_manager)
return(nst->l3_manager(nst->manager, msg));
return(-EINVAL);
}
static int
do_readmsg(net_stack_t *nst, msg_t *msg)
{
iframe_t *frm;
int ret = -EINVAL;
if (!nst || !msg)
return(-EINVAL);
frm = (iframe_t *)msg->data;
dprint(DBGM_NET, nst->cardnr,"%s: prim(%x) addr(%x)\n", __FUNCTION__,
frm->prim, frm->addr);
if (frm->prim == (MGR_TIMER | INDICATION)) {
mISDN_write_frame(nst->device, msg->data, frm->addr,
MGR_TIMER | RESPONSE, 0, 0, NULL, TIMEOUT_1SEC);
ret = handle_timer(nst, frm->addr);
free_msg(msg);
return(0);
}
if ((frm->addr & INST_ID_MASK) == nst->l2_id) {
if (nst->l1_l2) {
ret = nst->l1_l2(nst, msg);
}
} else if (nst->b_addr[0] &&
((frm->addr & INST_ID_MASK) == nst->b_addr[0])) {
ret = b_message(nst, 0, frm, msg);
} else if (nst->b_addr[1] &&
((frm->addr & INST_ID_MASK) == nst->b_addr[1])) {
ret = b_message(nst, 1, frm, msg);
} else if (nst->b_stid[0] == frm->addr) {
ret = b_message(nst, 0, frm, msg);
} else if (nst->b_stid[1] == frm->addr) {
ret = b_message(nst, 1, frm, msg);
} else if (frm->prim == (MGR_DELLAYER | CONFIRM)) {
dprint(DBGM_NET, nst->cardnr,"%s: MGR_DELLAYER CONFIRM addr(%x)\n", __FUNCTION__,
frm->addr);
free_msg(msg);
return(0);
} else {
wprint("%s: unhandled msg(%d) prim(%x) addr(%x) dinfo(%x)\n", __FUNCTION__,
frm->len, frm->prim, frm->addr, frm->dinfo);
}
return(ret);
}
static int
setup_bchannel(net_stack_t *nst, mISDNuser_head_t *hh, msg_t *msg) {
mISDN_pid_t *pid;
int ret, ch, *id;
layer_info_t li;
unsigned char buf[32];
if ((hh->dinfo < 1) || (hh->dinfo > 2)) {
eprint("wrong channel %d\n", hh->dinfo);
return(-EINVAL);
}
ch = hh->dinfo -1;
dprint(DBGM_NET, nst->cardnr,"%s:ch%d\n", __FUNCTION__, hh->dinfo);
msg_pull(msg, mISDNUSER_HEAD_SIZE);
id = (int *)msg->data;
nst->bcid[ch] = *id;
msg_pull(msg, sizeof(int));
pid = (mISDN_pid_t *)msg->data;
memset(&li, 0, sizeof(layer_info_t));
li.object_id = -1;
li.extentions = 0;
li.st = nst->b_stid[ch];
if (pid->protocol[2] == ISDN_PID_L2_B_USER) {
strcpy(&li.name[0], "B L2");
li.pid.protocol[2] = ISDN_PID_L2_B_USER;
li.pid.layermask = ISDN_LAYER(2);
} else {
strcpy(&li.name[0], "B L3");
li.pid.protocol[3] = pid->protocol[3];
li.pid.layermask = ISDN_LAYER(3);
}
if (nst->b_addr[ch])
wprint("%s: b_addr[%d] %x in use\n", __FUNCTION__,
ch, nst->b_addr[ch]);
ret = mISDN_new_layer(nst->device, &li);
if (ret<=0) {
wprint("%s: new_layer ret(%d)\n", __FUNCTION__, ret);
goto error;
}
if (ret) {
nst->b_addr[ch] = ret;
dprint(DBGM_NET, nst->cardnr,"%s: b_address%d %08x\n", __FUNCTION__,
hh->dinfo, ret);
ret = mISDN_set_stack(nst->device, nst->b_stid[ch],
pid);
if (ret) {
wprint("set_stack ret(%d)\n", ret);
mISDN_write_frame(nst->device, buf,
nst->b_addr[ch], MGR_DELLAYER | REQUEST,
0, 0, NULL, TIMEOUT_1SEC);
nst->b_addr[ch] = 0;
goto error;
}
if_link(nst->manager, (ifunc_t)nst->l3_manager,
BC_SETUP | CONFIRM, nst->bcid[ch], sizeof(int),
&nst->b_addr[ch], 0);
free_msg(msg);
return(0);
}
error:
if_link(nst->manager, (ifunc_t)nst->l3_manager, BC_SETUP | SUB_ERROR,
nst->bcid[ch], sizeof(int), &ret, 0);
free_msg(msg);
return(0);
}
static int
cleanup_bc(net_stack_t *nst, mISDNuser_head_t *hh, msg_t *msg)
{
unsigned char buf[32];
int ch;
if (hh->dinfo == nst->bcid[0])
ch = 0;
else if (hh->dinfo == nst->bcid[1])
ch = 1;
else {
wprint("%s:not channel match %x %x/%x\n", __FUNCTION__,
hh->dinfo, nst->bcid[0], nst->bcid[1]);
if_link(nst->manager, (ifunc_t)nst->l3_manager,
BC_CLEANUP | SUB_ERROR, hh->dinfo, 0, NULL, 0);
free_msg(msg);
return(0);
}
dprint(DBGM_NET, nst->cardnr,"%s:ch%d\n", __FUNCTION__, ch + 1);
mISDN_clear_stack(nst->device, nst->b_stid[ch]);
if (nst->b_addr[ch])
mISDN_write_frame(nst->device, buf, nst->b_addr[ch],
MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
if_link(nst->manager, (ifunc_t)nst->l3_manager,
BC_CLEANUP | CONFIRM, hh->dinfo, 0, NULL, 0);
nst->b_addr[ch] = 0;
free_msg(msg);
return(0);
}
static int
l1_request(net_stack_t *nst, mISDNuser_head_t *hh, msg_t *msg)
{
iframe_t *frm;
hh = (mISDNuser_head_t *)msg->data;
dprint(DBGM_NET, nst->cardnr, "%s: msg(%p) len(%d) pr(%x) di(%x)\n", __FUNCTION__,
msg, msg->len, hh->prim, hh->dinfo);
msg_pull(msg, mISDNUSER_HEAD_SIZE);
frm = (iframe_t *)msg_push(msg, mISDN_HEADER_LEN);
frm->prim = hh->prim;
frm->addr = hh->dinfo;
if (frm->prim == PH_DATA_REQ)
frm->dinfo = (int)msg;
else
frm->dinfo = 0;
frm->len = msg->len - mISDN_HEADER_LEN;
mISDN_write(nst->device, msg->data, msg->len, -1);
free_msg(msg);
return(0);
}
static int
do_writemsg(net_stack_t *nst, msg_t *msg)
{
mISDNuser_head_t *hh;
int ret = -EINVAL;
if (!nst || !msg)
return(-EINVAL);
hh = (mISDNuser_head_t *)msg->data;
dprint(DBGM_NET, nst->cardnr,"%s: prim(%x) dinfo(%x)\n", __FUNCTION__,
hh->prim, hh->dinfo);
if ((hh->prim & LAYER_MASK) == MSG_L1_PRIM) {
ret = l1_request(nst, hh, msg);
} else if (hh->prim == (BC_SETUP | REQUEST)) {
ret = setup_bchannel(nst, hh, msg);
} else if (hh->prim == (BC_CLEANUP | REQUEST)) {
ret = cleanup_bc(nst, hh, msg);
} else if (hh->prim == (CC_NEW_CR | INDICATION)) {
msg_pull(msg, mISDNUSER_HEAD_SIZE);
if (hh->dinfo == nst->bcid[0]) {
nst->bcid[0] = *((int *)msg->data);
free_msg(msg);
ret = 0;
} else if (hh->dinfo == nst->bcid[1]) {
nst->bcid[1] = *((int *)msg->data);
free_msg(msg);
ret = 0;
} else
ret = -ENXIO;
} else if ((hh->prim & LAYER_MASK) == MSG_L3_PRIM) {
if (nst->manager_l3)
ret = nst->manager_l3(nst, msg);
} else {
wprint("%s: prim(%x) dinfo(%x) unhandled msg(%d)\n", __FUNCTION__,
hh->prim, hh->dinfo, msg->len);
}
return(ret);
}
static void *
main_readloop(void *arg)
{
net_stack_t *nst = arg;
int lp = 1;
int sel, ret;
int maxfd;
fd_set rfd;
fd_set efd;
pthread_t tid;
tid = pthread_self();
dprint(DBGM_NET, nst->cardnr, "%s: tid %ld\n", __FUNCTION__, tid);
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
while(lp) {
// dprint(DBGM_NET, nst->cardnr, "%s: begin dev %d\n", __FUNCTION__, nst->device);
maxfd = nst->device;
FD_ZERO(&rfd);
FD_SET(nst->device, &rfd);
FD_ZERO(&efd);
FD_SET(nst->device, &efd);
maxfd++;
restart:
sel = mISDN_select(maxfd, &rfd, NULL, &efd, NULL);
if (sel < 0) {
if (errno == EINTR) {
if (test_bit(FLG_NST_TERMINATION, &nst->flag))
break;
dprint(DBGM_NET, nst->cardnr, "%s: select restart\n", __FUNCTION__);
goto restart;
}
wprint("%s: error(%d) in select %s\n", __FUNCTION__,
errno, strerror(errno));
break;
}
if (sel) {
if (FD_ISSET(nst->device, &rfd)) {
ret = do_net_read(nst);
if (ret) {
dprint(DBGM_NET, nst->cardnr, "%s: rdfunc ret(%d)\n", __FUNCTION__, ret);
}
}
if (FD_ISSET(nst->device, &efd)) {
dprint(DBGM_NET, nst->cardnr, "%s: exception\n", __FUNCTION__);
}
}
}
dprint(DBGM_NET, nst->cardnr,"%s: fall trough, abort\n", __FUNCTION__);
pthread_mutex_lock(&nst->lock);
test_and_set_bit(FLG_NST_READER_ABORT, &nst->flag);
pthread_mutex_unlock(&nst->lock);
sem_post(&nst->work);
return(NULL);
}
void *
do_netthread(void *arg) {
net_stack_t *nst = arg;
int ret;
pthread_t tid;
void *retval = NULL;
/* create reader thread */
tid = pthread_self();
dprint(DBGM_NET, nst->cardnr, "%s: tid %ld\n", __FUNCTION__, tid);
ret = pthread_create(&nst->reader, NULL, main_readloop, (void *)nst);
tid = pthread_self();
dprint(DBGM_NET, nst->cardnr, "%s: tid %ld crated %ld\n", __FUNCTION__, tid, nst->reader);
if (ret) {
eprint("%s: cannot create reader %d\n", __FUNCTION__,
ret);
return(NULL);
}
while(1) {
msg_t *msg;
sem_wait(&nst->work);
msg = msg_dequeue(&nst->wqueue);
if (msg) {
ret = do_writemsg(nst, msg);
if (ret) {
wprint("%s: do_writemsg return %d\n", __FUNCTION__,
ret);
free_msg(msg);
}
}
msg = msg_dequeue(&nst->rqueue);
if (msg) {
ret = do_readmsg(nst, msg);
if (ret) {
wprint("%s: do_readmsg return %d\n", __FUNCTION__,
ret);
free_msg(msg);
}
}
pthread_mutex_lock(&nst->lock);
if (test_and_clear_bit(FLG_NST_READER_ABORT, &nst->flag)) {
pthread_mutex_unlock(&nst->lock);
dprint(DBGM_NET, nst->cardnr,"%s: reader aborted\n", __FUNCTION__);
ret = pthread_join(nst->reader, &retval);
dprint(DBGM_NET, nst->cardnr,"%s: join ret(%d) reader retval %p\n", __FUNCTION__,
ret, retval);
break;
}
if (test_bit(FLG_NST_TERMINATION, &nst->flag)) {
pthread_mutex_unlock(&nst->lock);
dprint(DBGM_NET, nst->cardnr,"%s: reader cancel\n", __FUNCTION__);
ret = pthread_cancel(nst->reader);
dprint(DBGM_NET, nst->cardnr,"%s: cancel reader ret(%d)\n", __FUNCTION__,
ret);
ret = pthread_join(nst->reader, &retval);
dprint(DBGM_NET, nst->cardnr,"%s: join ret(%d) reader retval %p\n", __FUNCTION__,
ret, retval);
break;
}
pthread_mutex_unlock(&nst->lock);
}
return(retval);
}
int
term_netstack(net_stack_t *nst)
{
test_and_set_bit(FLG_NST_TERMINATION, &nst->flag);
sem_post(&nst->work);
return(0);
}

2098
i4lnet/net_l2.c Normal file

File diff suppressed because it is too large Load Diff

147
i4lnet/net_l2.h Normal file
View File

@ -0,0 +1,147 @@
/* $Id$
*
* Layer 2 defines
*
* This file is (c) under GNU PUBLIC LICENSE
*
*/
#ifndef NET_L2_H
#define NET_L2_H
#include "mISDNlib.h"
#include "isdn_net.h"
#include "fsm.h"
#ifdef MEMDBG
#include "memdbg.h"
#endif
#define DINFO_SKB -1
#define MAX_WINDOW 8
typedef struct _teimgr {
int ri;
struct FsmInst tei_m;
struct FsmTimer t201;
int T201;
int debug;
int val;
struct _layer2 *l2;
} teimgr_t;
struct _layer2 {
struct _layer2 *prev;
struct _layer2 *next;
int sapi;
int tei;
laddr_t addr;
int maxlen;
teimgr_t *tm;
u_long flag;
u_int vs, va, vr;
int rc;
u_int window;
u_int sow;
struct FsmInst l2m;
struct FsmTimer t200, t203;
int T200, N200, T203;
int debug;
msg_t *windowar[MAX_WINDOW];
net_stack_t *nst;
msg_queue_t i_queue;
msg_queue_t ui_queue;
};
#define SAPITEI(ces) (ces>>8)&0xff, ces&0xff
static inline int CES(layer2_t *l2) {
return(l2->tei | (l2->sapi << 8));
}
/* from mISDN_l2.c */
extern int tei0_active(layer2_t *l2);
extern layer2_t *new_dl2(net_stack_t *nst, int tei);
extern int tei_l2(layer2_t *l2, msg_t *msg);
extern int Isdnl2Init(net_stack_t *nst);
extern void cleanup_Isdnl2(net_stack_t *nst);
/* from tei.c */
extern int tei_mux(net_stack_t *nst, msg_t *msg);
extern int l2_tei(teimgr_t *tm, msg_t *msg);
extern int create_teimgr(layer2_t *l2);
extern void release_tei(teimgr_t *tm);
extern int TEIInit(net_stack_t *nst);
extern void TEIFree(net_stack_t *nst);
#define GROUP_TEI 127
#define TEI_SAPI 63
#define CTRL_SAPI 0
#define RR 0x01
#define RNR 0x05
#define REJ 0x09
#define SABME 0x6f
#define SABM 0x2f
#define DM 0x0f
#define UI 0x03
#define DISC 0x43
#define UA 0x63
#define FRMR 0x87
#define XID 0xaf
#define CMD 0
#define RSP 1
#define LC_FLUSH_WAIT 1
#define FLG_LAPB 0
#define FLG_LAPD 1
#define FLG_ORIG 2
#define FLG_MOD128 3
#define FLG_PEND_REL 4
#define FLG_L3_INIT 5
#define FLG_T200_RUN 6
#define FLG_ACK_PEND 7
#define FLG_REJEXC 8
#define FLG_OWN_BUSY 9
#define FLG_PEER_BUSY 10
#define FLG_DCHAN_BUSY 11
#define FLG_L1_ACTIV 12
#define FLG_ESTAB_PEND 13
#define FLG_PTP 14
#define FLG_FIXED_TEI 15
#define FLG_L2BLOCK 16
#define FLG_L1_BUSY 17
#define FLG_LAPD_NET 18
#define FLG_TEI_T201_1 19
/* Simple replacement for the NON-ATOMIC routines which asm/bitops.h
was providing. */
static inline int test_bit(int bit, unsigned long *word)
{
return !!((*word) & (1<<bit));
}
static inline int test_and_clear_bit(int bit, unsigned long *word)
{
int ret = !!((*word) & (1<<bit));
*word &= ~(1<<bit);
return ret;
}
static inline int test_and_set_bit(int bit, unsigned long *word)
{
int ret = !!((*word) & (1<<bit));
*word |= 1<<bit;
return ret;
}
static inline void clear_bit(int bit, unsigned long *word)
{
*word &= ~(1<<bit);
}
static inline void set_bit(int bit, unsigned long *word)
{
*word |= 1<<bit;
}
#endif

3017
i4lnet/net_l3.c Normal file

File diff suppressed because it is too large Load Diff

290
i4lnet/net_l3.h Normal file
View File

@ -0,0 +1,290 @@
/* $Id$
*
* Layer 3 defines
*
* This file is (c) under GNU PUBLIC LICENSE
*
*/
#ifndef NET_L3_H
#define NET_L3_H
#include "isdn_net.h"
typedef struct _layer3_proc layer3_proc_t;
typedef struct _L3Timer L3Timer_t;
struct _L3Timer {
layer3_proc_t *pc;
itimer_t tl;
int nr;
};
struct _layer3_proc {
layer3_proc_t *prev;
layer3_proc_t *next;
layer3_proc_t *child;
layer3_proc_t *master;
layer3_t *l3;
int callref;
int ces;
int selces;
int state;
u_long Flags;
L3Timer_t timer1;
L3Timer_t timer2;
int bc;
int err;
int cause;
int hold_state;
u_char obuf[MAX_DFRAME_LEN];
u_char *op;
};
#define FLG_L3P_TIMER312 1
#define FLG_L3P_TIMER303_1 2
#define FLG_L3P_TIMER308_1 3
#define FLG_L3P_GOTRELCOMP 4
struct _layer3 {
layer3_t *prev;
layer3_t *next;
msg_queue_t squeue0;
int l2_state0;
int next_cr;
int debug;
net_stack_t *nst;
layer3_proc_t *proc;
};
static inline msg_t *l3_alloc_msg(int size)
{
msg_t *msg;
msg = alloc_msg(size+MAX_HEADER_LEN);
if (msg)
msg_reserve(msg, MAX_HEADER_LEN);
return(msg);
}
extern int Isdnl3Init(net_stack_t *);
extern void cleanup_Isdnl3(net_stack_t *);
extern void display_NR_IE(u_char *, char *, char *);
/* l3 pointer arrays */
typedef struct _ALERTING {
u_char *BEARER;
u_char *CHANNEL_ID;
u_char *FACILITY;
u_char *PROGRESS;
u_char *DISPLAY;
u_char *SIGNAL;
u_char *HLC;
u_char *USER_USER;
u_char *REDIR_DN;
} ALERTING_t;
typedef struct _CALL_PROCEEDING {
u_char *BEARER;
u_char *CHANNEL_ID;
u_char *FACILITY;
u_char *PROGRESS;
u_char *DISPLAY;
u_char *REDIR_DN;
u_char *HLC;
} CALL_PROCEEDING_t;
typedef struct _CONNECT {
u_char *BEARER;
u_char *CHANNEL_ID;
u_char *FACILITY;
u_char *PROGRESS;
u_char *DISPLAY;
u_char *DATE;
u_char *SIGNAL;
u_char *CONNECT_PN;
u_char *CONNECT_SUB;
u_char *LLC;
u_char *HLC;
u_char *USER_USER;
int ces;
} CONNECT_t;
typedef struct _CONNECT_ACKNOWLEDGE {
u_char *CHANNEL_ID;
u_char *DISPLAY;
u_char *SIGNAL;
} CONNECT_ACKNOWLEDGE_t;
typedef struct _DISCONNECT {
u_char *CAUSE;
u_char *FACILITY;
u_char *PROGRESS;
u_char *DISPLAY;
u_char *SIGNAL;
u_char *USER_USER;
} DISCONNECT_t;
typedef struct _INFORMATION {
u_char *COMPLETE;
u_char *DISPLAY;
u_char *KEYPAD;
u_char *SIGNAL;
u_char *CALLED_PN;
} INFORMATION_t;
typedef struct _NOTIFY {
u_char *BEARER;
u_char *NOTIFY;
u_char *DISPLAY;
u_char *REDIR_DN;
} NOTIFY_t;
typedef struct _PROGRESS {
u_char *BEARER;
u_char *CAUSE;
u_char *FACILITY;
u_char *PROGRESS;
u_char *DISPLAY;
u_char *HLC;
} PROGRESS_t;
typedef struct _RELEASE {
u_char *CAUSE;
u_char *FACILITY;
u_char *DISPLAY;
u_char *SIGNAL;
u_char *USER_USER;
} RELEASE_t;
typedef struct _RELEASE_COMPLETE {
u_char *CAUSE;
u_char *FACILITY;
u_char *DISPLAY;
u_char *SIGNAL;
u_char *USER_USER;
} RELEASE_COMPLETE_t;
typedef struct _RESUME {
u_char *CALL_ID;
u_char *FACILITY;
int ces;
} RESUME_t;
typedef struct _RESUME_ACKNOWLEDGE {
u_char *CHANNEL_ID;
u_char *FACILITY;
u_char *DISPLAY;
} RESUME_ACKNOWLEDGE_t;
typedef struct _RESUME_REJECT {
u_char *CAUSE;
u_char *DISPLAY;
} RESUME_REJECT_t;
typedef struct _SETUP {
u_char *COMPLETE;
u_char *BEARER;
u_char *CHANNEL_ID;
u_char *FACILITY;
u_char *PROGRESS;
u_char *NET_FAC;
u_char *DISPLAY;
u_char *KEYPAD;
u_char *SIGNAL;
u_char *CALLING_PN;
u_char *CALLING_SUB;
u_char *CALLED_PN;
u_char *CALLED_SUB;
u_char *REDIR_NR;
u_char *LLC;
u_char *HLC;
u_char *USER_USER;
int ces;
} SETUP_t;
typedef struct _SETUP_ACKNOWLEDGE {
u_char *CHANNEL_ID;
u_char *FACILITY;
u_char *PROGRESS;
u_char *DISPLAY;
u_char *SIGNAL;
} SETUP_ACKNOWLEDGE_t;
typedef struct _STATUS {
u_char *CAUSE;
u_char *CALL_STATE;
u_char *DISPLAY;
} STATUS_t;
typedef struct _STATUS_ENQUIRY {
u_char *DISPLAY;
} STATUS_ENQUIRY_t;
typedef struct _SUSPEND {
u_char *CALL_ID;
u_char *FACILITY;
} SUSPEND_t;
typedef struct _SUSPEND_ACKNOWLEDGE {
u_char *FACILITY;
u_char *DISPLAY;
} SUSPEND_ACKNOWLEDGE_t;
typedef struct _SUSPEND_REJECT {
u_char *CAUSE;
u_char *DISPLAY;
} SUSPEND_REJECT_t;
typedef struct _CONGESTION_CONTROL {
u_char *CONGESTION;
u_char *CAUSE;
u_char *DISPLAY;
} CONGESTION_CONTROL_t;
typedef struct _USER_INFORMATION {
u_char *MORE_DATA;
u_char *USER_USER;
} USER_INFORMATION_t;
typedef struct _RESTART {
u_char *CHANNEL_ID;
u_char *DISPLAY;
u_char *RESTART_IND;
} RESTART_t;
typedef struct _FACILITY {
u_char *FACILITY;
u_char *DISPLAY;
} FACILITY_t;
typedef struct _HOLD {
u_char *DISPLAY;
} HOLD_t;
typedef struct _HOLD_ACKNOWLEDGE {
u_char *CHANNEL_ID;
u_char *DISPLAY;
} HOLD_ACKNOWLEDGE_t;
typedef struct _HOLD_REJECT {
u_char *CAUSE;
u_char *DISPLAY;
} HOLD_REJECT_t;
typedef struct _RETRIEVE {
u_char *CHANNEL_ID;
} RETRIEVE_t;
typedef struct _RETRIEVE_ACKNOWLEDGE {
u_char *CHANNEL_ID;
u_char *DISPLAY;
} RETRIEVE_ACKNOWLEDGE_t;
typedef struct _RETRIEVE_REJECT {
u_char *CAUSE;
u_char *DISPLAY;
} RETRIEVE_REJECT_t;
#endif

320
i4lnet/nettst.c Normal file
View File

@ -0,0 +1,320 @@
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <time.h>
#include "isdn_net.h"
#include "net_l2.h"
#include "net_l3.h"
#include "net_l4.h"
#include "l3dss1.h"
#include "helper.h"
#include "bchannel.h"
#include "tone.h"
net_stack_t kern_if;
itimer_t timer1;
static void
do_cleanup(net_stack_t *nst)
{
fprintf(stderr, "%s\n", __FUNCTION__);
cleanup_Isdnl4(nst);
cleanup_Isdnl3(nst);
cleanup_Isdnl2(nst);
do_net_stack_cleanup(nst);
}
static void
term_handler(int sig)
{
pthread_t tid;
tid = pthread_self();
fprintf(stderr,"signal %d received from thread %ld\n", sig, tid);
test_and_set_bit(FLG_KIF_TERMINATION, &kern_if.flag);
sem_post(&kern_if.network);
}
static int
man_down(net_stack_t *nst, msg_t *msg)
{
msg_queue_tail(&nst->wqueue, msg);
sem_post(&nst->network);
return(0);
}
static int
do_disconnect(layer4_t *l4)
{
l4->cause_loc = CAUSE_LOC_PNET_LOCUSER;
l4->cause_val = CAUSE_NORMAL_CLEARING;
l4->progress = PROGRESS_TONE;
if_link(l4->nst, man_down, MAN_CLEAR_CALL | REQUEST,
l4->channel, 0, NULL, 0);
return(0);
}
static int
do_connect(layer4_t *l4)
{
if_link(l4->nst, man_down, MAN_CONNECT | REQUEST,
l4->channel, 0, NULL, 0);
return(0);
}
static int
do_alert(layer4_t *l4)
{
if_link(l4->nst, man_down, MAN_ALERT | REQUEST,
l4->channel, 0, NULL, 0);
return(0);
}
static int
clear_call(layer4_t *l4)
{
if (l4->sdata) {
layer4_t *peer = l4->sdata;
if (l4->cause_val) {
peer->cause_loc = l4->cause_loc;
peer->cause_val = l4->cause_val;
} else {
peer->cause_loc = CAUSE_LOC_PNET_LOCUSER;
peer->cause_val = CAUSE_NORMALUNSPECIFIED;
}
peer->progress = PROGRESS_TONE;
peer->sbuf = NULL;
peer->sdata = NULL;
peer->rdata = NULL;
if (peer->nst)
if_link(peer->nst, man_down, MAN_CLEAR_CALL |
REQUEST, peer->channel, 0, NULL, 0);
}
l4->sdata = NULL;
l4->rdata = NULL;
l4->sbuf = NULL;
return(0);
}
static int
alert_call(layer4_t *l4)
{
if (l4->sdata)
do_alert(l4->sdata);
return(0);
}
static int
connect_call(layer4_t *l4)
{
strcpy(l4->display,"connect ack");
if_link(l4->nst, man_down, MAN_CONNECT | RESPONSE,
l4->channel, 0, NULL, 0);
del_timer(&timer1);
if (l4->sdata)
do_connect(l4->sdata);
return(0);
}
static int
route_call(layer4_t *l4)
{
layer4_t *newl4;
fprintf(stderr, "%s: msn ", __FUNCTION__);
display_NR_IE(l4->msn);
fprintf(stderr, "%s: nr ", __FUNCTION__);
display_NR_IE(l4->nr);
if (l4->usednr->typ == NR_TYPE_INTERN) {
newl4 = get_free_channel(&kern_if, -1, NULL);
if (!newl4) {
l4->cause_loc = CAUSE_LOC_PNET_LOCUSER;
l4->cause_val = CAUSE_USER_BUSY;
l4->progress = PROGRESS_TONE;
if_link(l4->nst, man_down, MAN_CLEAR_CALL | REQUEST,
l4->channel, 0, NULL, 0);
return(0);
}
l4->sdata = newl4;
l4->rdata = newl4;
newl4->sdata = l4;
newl4->rdata = l4;
l4->sbuf = &newl4->rbuf;
newl4->sbuf = &l4->rbuf;
newl4->msn[0] = l4->usednr->len +1;
newl4->msn[1] = 0x81;
memcpy(&newl4->msn[2], l4->usednr->nr, l4->usednr->len);
if (l4->msn[0])
memcpy(newl4->nr, l4->msn, l4->msn[0] + 1);
newl4->l1_prot = ISDN_PID_L1_B_64TRANS;
if_link(newl4->nst, man_down, MAN_SETUP | REQUEST,
newl4->channel, 0, NULL, 0);
} else if (l4->usednr->typ == NR_TYPE_AUDIO) {
l4->sdata = NULL;
l4->rdata = NULL;
strcpy(l4->display,"connect to AUDIO");
do_connect(l4);
l4->display[0] = 0;
deactivate_bchannel(l4);
setup_bchannel_rawdev(l4);
activate_bchannel(l4);
} else if (l4->usednr->typ == NR_TYPE_VOIP) {
l4->sdata = NULL;
l4->rdata = NULL;
sprintf(l4->display,"calling %s", l4->usednr->name);
do_alert(l4);
sprintf(l4->display,"connect to %s", l4->usednr->name);
do_connect(l4);
l4->display[0] = 0;
deactivate_bchannel(l4);
setup_bchannel_rawdev(l4);
activate_bchannel(l4);
}
return(0);
}
static int
manager(net_stack_t *nst, msg_t *msg) {
mISDNuser_head_t *hh;
layer4_t *l4;
if (!msg)
return(-EINVAL);
hh = (mISDNuser_head_t *)msg->data;
msg_pull(msg, mISDN_HEAD_SIZE);
fprintf(stderr, "%s: prim(%x) msg->len(%d)\n", __FUNCTION__,
hh->prim, msg->len);
if (hh->dinfo == 1) {
l4 = &nst->layer4[0];
} else if (hh->dinfo == 2) {
l4 = &nst->layer4[1];
} else {
return(-EINVAL);
}
switch(hh->prim) {
case MAN_SETUP | INDICATION:
fprintf(stderr, "%s: setup id(%x)\n", __FUNCTION__,
hh->dinfo);
route_call(l4);
break;
case MAN_ALERT | INDICATION:
fprintf(stderr, "%s: connect id(%x)\n", __FUNCTION__,
hh->dinfo);
alert_call(l4);
break;
case MAN_CONNECT | INDICATION:
fprintf(stderr, "%s: connect id(%x)\n", __FUNCTION__,
hh->dinfo);
connect_call(l4);
break;
case MAN_CLEAR_CALL | INDICATION:
fprintf(stderr, "%s: clear call id(%x)\n", __FUNCTION__,
hh->dinfo);
clear_call(l4);
break;
default:
fprintf(stderr, "%s: unhandled prim(%x) msg->len(%d)\n", __FUNCTION__,
hh->prim, msg->len);
break;
}
free_msg(msg);
return(0);
}
int main(argc,argv)
int argc;
char *argv[];
{
int ret, *retp;
nr_list_t *nr1,*nr2,*nr3,*nr4,*nr5;
layer4_t *l4;
if_action_t mISDNrd,*hrd;
nr1 = malloc(sizeof(nr_list_t));
nr2 = malloc(sizeof(nr_list_t));
nr3 = malloc(sizeof(nr_list_t));
nr4 = malloc(sizeof(nr_list_t));
nr5 = malloc(sizeof(nr_list_t));
memset(nr1, 0, sizeof(nr_list_t));
memset(nr2, 0, sizeof(nr_list_t));
memset(nr3, 0, sizeof(nr_list_t));
memset(nr4, 0, sizeof(nr_list_t));
memset(nr5, 0, sizeof(nr_list_t));
nr1->len = 5;
strcpy(nr1->nr,"12345");
nr1->typ = NR_TYPE_INTERN;
nr2->len = 4;
strcpy(nr2->nr,"4566");
nr2->typ = NR_TYPE_INTERN;
nr3->len = 3;
strcpy(nr3->nr,"789");
nr3->typ = NR_TYPE_AUDIO;
nr4->len = 3;
strcpy(nr4->nr,"147");
strcpy(nr4->name, "pingi2");
nr4->typ = NR_TYPE_VOIP;
nr5->len = 3;
strcpy(nr5->nr,"258");
strcpy(nr5->name, "pingi2");
nr5->typ = NR_TYPE_VOIP;
msg_init();
ret = do_net_stack_setup(&kern_if);
if (ret) {
fprintf(stderr, "error in do_net_stack_setup %d\n", ret);
return(0);
}
APPEND_TO_LIST(nr1, kern_if.nrlist);
APPEND_TO_LIST(nr2, kern_if.nrlist);
APPEND_TO_LIST(nr3, kern_if.nrlist);
APPEND_TO_LIST(nr4, kern_if.nrlist);
APPEND_TO_LIST(nr5, kern_if.nrlist);
Isdnl2Init(&kern_if);
Isdnl3Init(&kern_if);
Isdnl4Init(&kern_if);
kern_if.l4_mgr = manager;
init_bhandler(&kern_if);
memset(&timer1, 0, sizeof(itimer_t));
signal(SIGTERM, term_handler);
signal(SIGINT, term_handler);
signal(SIGPIPE, term_handler);
if (argc>1) {
l4 = get_free_channel(&kern_if, -1, NULL);
if (l4) {
l4->msn[0] = 4;
l4->msn[1] = 0x81;
l4->msn[2] = '8';
l4->msn[3] = '8';
l4->msn[4] = '8';
l4->nr[0] = 4;
l4->nr[1] = 0x81;
l4->nr[2] = '1';
l4->nr[3] = '2';
l4->nr[4] = '3';
l4->l1_prot = ISDN_PID_L1_B_64TRANS;
if_link(l4->nst, man_down, MAN_SETUP | REQUEST,
l4->channel, 0, NULL, 0);
del_timer(&timer1);
timer1.function = (void *)do_disconnect;
timer1.data = (long)l4;
init_timer(&timer1, &kern_if);
timer1.expires = 8000;
add_timer(&timer1);
}
}
hrd = &mISDNrd;
memset(hrd, 0, sizeof(if_action_t));
hrd->nst = &kern_if;
hrd->fd = kern_if.device;
hrd->function = do_net_read;
APPEND_TO_LIST(hrd, kern_if.rd);
retp = do_netthread(&kern_if);
fprintf(stderr, "do_main_loop returns(%p)\n", retp);
do_cleanup(&kern_if);
return(0);
}

145
i4lnet/sndloop.c Normal file
View File

@ -0,0 +1,145 @@
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/soundcard.h>
unsigned char ulaw_to_Alaw[256] = {
0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d,
0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25,
0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d,
0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35,
0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d, 0x02,
0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x1a,
0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x12,
0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x6b,
0x68, 0x69, 0x6e, 0x6f, 0x6c, 0x6d, 0x62, 0x63,
0x60, 0x61, 0x66, 0x67, 0x64, 0x65, 0x7b, 0x79,
0x7e, 0x7f, 0x7c, 0x7d, 0x72, 0x73, 0x70, 0x71,
0x76, 0x77, 0x74, 0x75, 0x4b, 0x49, 0x4f, 0x4d,
0x42, 0x43, 0x40, 0x41, 0x46, 0x47, 0x44, 0x45,
0x5a, 0x5b, 0x58, 0x59, 0x5e, 0x5f, 0x5c, 0x5d,
0x52, 0x52, 0x53, 0x53, 0x50, 0x50, 0x51, 0x51,
0x56, 0x56, 0x57, 0x57, 0x54, 0x54, 0x55, 0xd5,
0xaa, 0xab, 0xa8, 0xa9, 0xae, 0xaf, 0xac, 0xad,
0xa2, 0xa3, 0xa0, 0xa1, 0xa6, 0xa7, 0xa4, 0xa5,
0xba, 0xbb, 0xb8, 0xb9, 0xbe, 0xbf, 0xbc, 0xbd,
0xb2, 0xb3, 0xb0, 0xb1, 0xb6, 0xb7, 0xb4, 0xb5,
0x8b, 0x88, 0x89, 0x8e, 0x8f, 0x8c, 0x8d, 0x82,
0x83, 0x80, 0x81, 0x86, 0x87, 0x84, 0x85, 0x9a,
0x9b, 0x98, 0x99, 0x9e, 0x9f, 0x9c, 0x9d, 0x92,
0x93, 0x90, 0x91, 0x96, 0x97, 0x94, 0x95, 0xeb,
0xe8, 0xe9, 0xee, 0xef, 0xec, 0xed, 0xe2, 0xe3,
0xe0, 0xe1, 0xe6, 0xe7, 0xe4, 0xe5, 0xfb, 0xf9,
0xfe, 0xff, 0xfc, 0xfd, 0xf2, 0xf3, 0xf0, 0xf1,
0xf6, 0xf7, 0xf4, 0xf5, 0xcb, 0xc9, 0xcf, 0xcd,
0xc2, 0xc3, 0xc0, 0xc1, 0xc6, 0xc7, 0xc4, 0xc5,
0xda, 0xdb, 0xd8, 0xd9, 0xde, 0xdf, 0xdc, 0xdd,
0xd2, 0xd2, 0xd3, 0xd3, 0xd0, 0xd0, 0xd1, 0xd1,
0xd6, 0xd6, 0xd7, 0xd7, 0xd4, 0xd4, 0xd5, 0xd5,
};
unsigned char Alaw_to_ulaw[256] = {
0x29, 0x2a, 0x27, 0x28, 0x2d, 0x2e, 0x2b, 0x2c,
0x21, 0x22, 0x1f, 0x20, 0x25, 0x26, 0x23, 0x24,
0x39, 0x3a, 0x37, 0x38, 0x3d, 0x3e, 0x3b, 0x3c,
0x31, 0x32, 0x2f, 0x30, 0x35, 0x36, 0x33, 0x34,
0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d,
0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05,
0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d,
0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15,
0x62, 0x63, 0x60, 0x61, 0x66, 0x67, 0x64, 0x65,
0x5d, 0x5d, 0x5c, 0x5c, 0x5f, 0x5f, 0x5e, 0x5e,
0x74, 0x76, 0x70, 0x72, 0x7c, 0x7e, 0x78, 0x7a,
0x6a, 0x6b, 0x68, 0x69, 0x6e, 0x6f, 0x6c, 0x6d,
0x48, 0x49, 0x46, 0x47, 0x4c, 0x4d, 0x4a, 0x4b,
0x40, 0x41, 0x3f, 0x3f, 0x44, 0x45, 0x42, 0x43,
0x56, 0x57, 0x54, 0x55, 0x5a, 0x5b, 0x58, 0x59,
0x4f, 0x4f, 0x4e, 0x4e, 0x52, 0x53, 0x50, 0x51,
0xa9, 0xaa, 0xa7, 0xa8, 0xad, 0xae, 0xab, 0xac,
0xa1, 0xa2, 0x9f, 0xa0, 0xa5, 0xa6, 0xa3, 0xa4,
0xb9, 0xba, 0xb7, 0xb8, 0xbd, 0xbe, 0xbb, 0xbc,
0xb1, 0xb2, 0xaf, 0xb0, 0xb5, 0xb6, 0xb3, 0xb4,
0x8a, 0x8b, 0x88, 0x89, 0x8e, 0x8f, 0x8c, 0x8d,
0x82, 0x83, 0x80, 0x81, 0x86, 0x87, 0x84, 0x85,
0x9a, 0x9b, 0x98, 0x99, 0x9e, 0x9f, 0x9c, 0x9d,
0x92, 0x93, 0x90, 0x91, 0x96, 0x97, 0x94, 0x95,
0xe2, 0xe3, 0xe0, 0xe1, 0xe6, 0xe7, 0xe4, 0xe5,
0xdd, 0xdd, 0xdc, 0xdc, 0xdf, 0xdf, 0xde, 0xde,
0xf4, 0xf6, 0xf0, 0xf2, 0xfc, 0xfe, 0xf8, 0xfa,
0xea, 0xeb, 0xe8, 0xe9, 0xee, 0xef, 0xec, 0xed,
0xc8, 0xc9, 0xc6, 0xc7, 0xcc, 0xcd, 0xca, 0xcb,
0xc0, 0xc1, 0xbf, 0xbf, 0xc4, 0xc5, 0xc2, 0xc3,
0xd6, 0xd7, 0xd4, 0xd5, 0xda, 0xdb, 0xd8, 0xd9,
0xcf, 0xcf, 0xce, 0xce, 0xd2, 0xd3, 0xd0, 0xd1,
};
int main(argc,argv)
int argc;
char *argv[];
{
int audio_out;
int mISDN_in;
int format;
int cnt, wcnt, i;
int n,sel;
fd_set fdr;
unsigned char buf[128];
if (argc<=1)
exit(1);
audio_out = open("/dev/audio", O_WRONLY | O_NONBLOCK);
if (0 > audio_out) {
fprintf(stderr, "cannot open /dev/audio for write:%s\n",
strerror(errno));
exit(1);
}
mISDN_in = open(argv[1], O_RDONLY | O_NONBLOCK);
if (0 > mISDN_in) {
close(audio_out);
fprintf(stderr, "cannot open %s for read:%s\n",
argv[1], strerror(errno));
exit(1);
}
format = AFMT_MU_LAW;
fprintf(stdout, "audio format %x\n", format);
if (ioctl(audio_out, SNDCTL_DSP_SETFMT, &format) == -1) {
fprintf(stderr, "ioctl SNDCTL_DSP_SETFMT %s\n",
strerror(errno));
} else
fprintf(stdout, "audio format %x\n", format);
while(1) {
cnt = read(mISDN_in, buf, 128);
fprintf(stdout, "mISDN_in %d bytes\n", cnt);
if (cnt>0) {
for (i=0;i<cnt;i++)
buf[i] = Alaw_to_ulaw[buf[i]];
wcnt = write(audio_out, buf, cnt);
fprintf(stdout, "audio_out%d bytes\n", wcnt);
} else if (errno == EAGAIN) {
FD_ZERO(&fdr);
FD_SET(mISDN_in, &fdr);
n = mISDN_in;
n++;
sel = select(n, &fdr, NULL, NULL, NULL);
if (sel<1) {
fprintf(stdout, "sel %d : %s\n",
sel, strerror(errno));
break;
}
} else {
fprintf(stdout, "mISDN_in: %s\n",
strerror(errno));
break;
}
}
close(audio_out);
close(mISDN_in);
}

145
i4lnet/sndloop2.c Normal file
View File

@ -0,0 +1,145 @@
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/soundcard.h>
unsigned char ulaw_to_Alaw[256] = {
0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d,
0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25,
0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d,
0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35,
0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d, 0x02,
0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x1a,
0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x12,
0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x6b,
0x68, 0x69, 0x6e, 0x6f, 0x6c, 0x6d, 0x62, 0x63,
0x60, 0x61, 0x66, 0x67, 0x64, 0x65, 0x7b, 0x79,
0x7e, 0x7f, 0x7c, 0x7d, 0x72, 0x73, 0x70, 0x71,
0x76, 0x77, 0x74, 0x75, 0x4b, 0x49, 0x4f, 0x4d,
0x42, 0x43, 0x40, 0x41, 0x46, 0x47, 0x44, 0x45,
0x5a, 0x5b, 0x58, 0x59, 0x5e, 0x5f, 0x5c, 0x5d,
0x52, 0x52, 0x53, 0x53, 0x50, 0x50, 0x51, 0x51,
0x56, 0x56, 0x57, 0x57, 0x54, 0x54, 0x55, 0xd5,
0xaa, 0xab, 0xa8, 0xa9, 0xae, 0xaf, 0xac, 0xad,
0xa2, 0xa3, 0xa0, 0xa1, 0xa6, 0xa7, 0xa4, 0xa5,
0xba, 0xbb, 0xb8, 0xb9, 0xbe, 0xbf, 0xbc, 0xbd,
0xb2, 0xb3, 0xb0, 0xb1, 0xb6, 0xb7, 0xb4, 0xb5,
0x8b, 0x88, 0x89, 0x8e, 0x8f, 0x8c, 0x8d, 0x82,
0x83, 0x80, 0x81, 0x86, 0x87, 0x84, 0x85, 0x9a,
0x9b, 0x98, 0x99, 0x9e, 0x9f, 0x9c, 0x9d, 0x92,
0x93, 0x90, 0x91, 0x96, 0x97, 0x94, 0x95, 0xeb,
0xe8, 0xe9, 0xee, 0xef, 0xec, 0xed, 0xe2, 0xe3,
0xe0, 0xe1, 0xe6, 0xe7, 0xe4, 0xe5, 0xfb, 0xf9,
0xfe, 0xff, 0xfc, 0xfd, 0xf2, 0xf3, 0xf0, 0xf1,
0xf6, 0xf7, 0xf4, 0xf5, 0xcb, 0xc9, 0xcf, 0xcd,
0xc2, 0xc3, 0xc0, 0xc1, 0xc6, 0xc7, 0xc4, 0xc5,
0xda, 0xdb, 0xd8, 0xd9, 0xde, 0xdf, 0xdc, 0xdd,
0xd2, 0xd2, 0xd3, 0xd3, 0xd0, 0xd0, 0xd1, 0xd1,
0xd6, 0xd6, 0xd7, 0xd7, 0xd4, 0xd4, 0xd5, 0xd5,
};
unsigned char Alaw_to_ulaw[256] = {
0x29, 0x2a, 0x27, 0x28, 0x2d, 0x2e, 0x2b, 0x2c,
0x21, 0x22, 0x1f, 0x20, 0x25, 0x26, 0x23, 0x24,
0x39, 0x3a, 0x37, 0x38, 0x3d, 0x3e, 0x3b, 0x3c,
0x31, 0x32, 0x2f, 0x30, 0x35, 0x36, 0x33, 0x34,
0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d,
0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05,
0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d,
0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15,
0x62, 0x63, 0x60, 0x61, 0x66, 0x67, 0x64, 0x65,
0x5d, 0x5d, 0x5c, 0x5c, 0x5f, 0x5f, 0x5e, 0x5e,
0x74, 0x76, 0x70, 0x72, 0x7c, 0x7e, 0x78, 0x7a,
0x6a, 0x6b, 0x68, 0x69, 0x6e, 0x6f, 0x6c, 0x6d,
0x48, 0x49, 0x46, 0x47, 0x4c, 0x4d, 0x4a, 0x4b,
0x40, 0x41, 0x3f, 0x3f, 0x44, 0x45, 0x42, 0x43,
0x56, 0x57, 0x54, 0x55, 0x5a, 0x5b, 0x58, 0x59,
0x4f, 0x4f, 0x4e, 0x4e, 0x52, 0x53, 0x50, 0x51,
0xa9, 0xaa, 0xa7, 0xa8, 0xad, 0xae, 0xab, 0xac,
0xa1, 0xa2, 0x9f, 0xa0, 0xa5, 0xa6, 0xa3, 0xa4,
0xb9, 0xba, 0xb7, 0xb8, 0xbd, 0xbe, 0xbb, 0xbc,
0xb1, 0xb2, 0xaf, 0xb0, 0xb5, 0xb6, 0xb3, 0xb4,
0x8a, 0x8b, 0x88, 0x89, 0x8e, 0x8f, 0x8c, 0x8d,
0x82, 0x83, 0x80, 0x81, 0x86, 0x87, 0x84, 0x85,
0x9a, 0x9b, 0x98, 0x99, 0x9e, 0x9f, 0x9c, 0x9d,
0x92, 0x93, 0x90, 0x91, 0x96, 0x97, 0x94, 0x95,
0xe2, 0xe3, 0xe0, 0xe1, 0xe6, 0xe7, 0xe4, 0xe5,
0xdd, 0xdd, 0xdc, 0xdc, 0xdf, 0xdf, 0xde, 0xde,
0xf4, 0xf6, 0xf0, 0xf2, 0xfc, 0xfe, 0xf8, 0xfa,
0xea, 0xeb, 0xe8, 0xe9, 0xee, 0xef, 0xec, 0xed,
0xc8, 0xc9, 0xc6, 0xc7, 0xcc, 0xcd, 0xca, 0xcb,
0xc0, 0xc1, 0xbf, 0xbf, 0xc4, 0xc5, 0xc2, 0xc3,
0xd6, 0xd7, 0xd4, 0xd5, 0xda, 0xdb, 0xd8, 0xd9,
0xcf, 0xcf, 0xce, 0xce, 0xd2, 0xd3, 0xd0, 0xd1,
};
//#define AUDIOF "/usr/share/sounds/au/linus-english.au"
#define AUDIOF "/dev/audio"
int main(argc,argv)
int argc;
char *argv[];
{
int audio_in;
int mISDN_out;
int format;
int cnt, wcnt, i;
int n,sel;
fd_set fdw;
unsigned char buf[128];
if (argc<=1)
exit(1);
audio_in = open(AUDIOF, O_RDONLY);
if (0 > audio_in) {
fprintf(stderr, "cannot open " AUDIOF " for read:%s\n",
strerror(errno));
exit(1);
}
mISDN_out = open(argv[1], O_WRONLY | O_NONBLOCK);
if (0 > mISDN_out) {
close(audio_in);
fprintf(stderr, "cannot open %s for write:%s\n",
argv[1], strerror(errno));
exit(1);
}
while(1) {
cnt = read(audio_in, buf, 128);
fprintf(stdout, "audio_in %d bytes\n", cnt);
if (cnt>0) {
for (i=0;i<cnt;i++)
buf[i] = ulaw_to_Alaw[buf[i]];
wcnt = write(mISDN_out, buf, cnt);
fprintf(stdout, "mISDN_out%d bytes\n", wcnt);
if (wcnt>0) {
fprintf(stdout, "mISDN_out%d bytes\n", wcnt);
} else if (errno == EAGAIN) {
FD_ZERO(&fdw);
FD_SET(mISDN_out, &fdw);
n = mISDN_out;
n++;
sel = select(n, NULL, &fdw, NULL, NULL);
if (sel<1) {
fprintf(stdout, "sel %d : %s\n",
sel, strerror(errno));
break;
}
} else {
fprintf(stdout, "mISDN_out: %s\n",
strerror(errno));
}
} else {
fprintf(stdout, "audio_in: %s\n",
strerror(errno));
break;
}
}
close(audio_in);
close(mISDN_out);
}

443
i4lnet/tei.c Normal file
View File

@ -0,0 +1,443 @@
/* $Id$
*
* Author Karsten Keil (keil@isdn4linux.de)
*
* This file is (c) under GNU PUBLIC LICENSE
* For changes and modifications please read
* ../../../Documentation/isdn/mISDN.cert
*
*/
#define __NO_VERSION__
#include <stdlib.h>
#include "net_l2.h"
// #include "helper.h"
// #include "debug.h"
// #include <linux/random.h>
const char *tei_revision = "$Revision$";
#define ID_REQUEST 1
#define ID_ASSIGNED 2
#define ID_DENIED 3
#define ID_CHK_REQ 4
#define ID_CHK_RES 5
#define ID_REMOVE 6
#define ID_VERIFY 7
#define TEI_ENTITY_ID 0xf
enum {
ST_TEI_NOP,
ST_TEI_REMOVE,
ST_TEI_IDVERIFY,
};
#define TEI_STATE_COUNT (ST_TEI_IDVERIFY+1)
static char *strTeiState[] =
{
"ST_TEI_NOP",
"ST_TEI_REMOVE",
"ST_TEI_IDVERIFY",
};
enum {
EV_IDREQ,
EV_ASSIGN,
EV_ASSIGN_REQ,
EV_CHECK_RES,
EV_CHECK_REQ,
EV_REMOVE,
EV_VERIFY,
EV_T201,
};
#define TEI_EVENT_COUNT (EV_T201+1)
static char *strTeiEvent[] =
{
"EV_IDREQ",
"EV_ASSIGN",
"EV_ASSIGN_REQ",
"EV_CHECK_RES",
"EV_CHECK_REQ",
"EV_REMOVE",
"EV_VERIFY",
"EV_T201",
};
static layer2_t
*new_tei_req(net_stack_t *nst)
{
layer2_t *l2;
int tei;
for (tei=64;tei<127;tei++) {
l2 = nst->layer2;
while(l2) {
if (l2->tei == tei)
break;
l2 = l2->next;
}
if (!l2)
break;
}
if (tei==127) /* all tei in use */
return(NULL);
l2 = new_dl2(nst, tei);
return(l2);
}
unsigned int
random_ri(void)
{
long int x;
x = random();
return (x & 0xffff);
}
static layer2_t *
find_tei(net_stack_t *nst, int tei)
{
layer2_t *l2;
l2 = nst->layer2;
while(l2) {
if (l2->tei == tei)
break;
l2 = l2->next;
}
return(l2);
}
static void
put_tei_msg(teimgr_t *tm, u_char m_id, unsigned int ri, u_char tei)
{
msg_t *msg;
u_char bp[8];
bp[0] = (TEI_SAPI << 2);
if (test_bit(FLG_LAPD_NET, &tm->l2->flag))
bp[0] |= 2; /* CR:=1 for net command */
bp[1] = (GROUP_TEI << 1) | 0x1;
bp[2] = UI;
bp[3] = TEI_ENTITY_ID;
bp[4] = ri >> 8;
bp[5] = ri & 0xff;
bp[6] = m_id;
bp[7] = (tei << 1) | 1;
msg = create_link_msg(MDL_UNITDATA | REQUEST, DINFO_SKB, 8, bp, 0);
if (!msg) {
dprint(DBGM_TEI, -1, "mISDN: No msg for TEI manager\n");
return;
}
if (tei_l2(tm->l2, msg))
free_msg(msg);
}
static void
tei_assign_req(struct FsmInst *fi, int event, void *arg)
{
teimgr_t *tm = fi->userdata;
u_char *dp = arg;
if (tm->l2->tei == -1) {
tm->tei_m.printdebug(&tm->tei_m,
"net tei assign request without tei");
return;
}
tm->ri = ((unsigned int) *dp++ << 8);
tm->ri += *dp++;
if (tm->debug)
tm->tei_m.printdebug(&tm->tei_m,
"net assign request ri %d teim %d", tm->ri, *dp);
put_tei_msg(tm, ID_ASSIGNED, tm->ri, tm->l2->tei);
FsmChangeState(fi, ST_TEI_NOP);
}
static void
tei_id_chk_res(struct FsmInst *fi, int event, void *arg)
{
teimgr_t *tm = fi->userdata;
int *ri = arg;
if (tm->debug)
tm->tei_m.printdebug(fi, "identity %d check response ri %x/%x",
tm->l2->tei, *ri, tm->ri);
if (tm->ri != -1) {
FsmDelTimer(&tm->t201, 4);
tm->tei_m.printdebug(fi, "duplicat %d response", tm->l2->tei);
tm->val = tm->l2->tei;
put_tei_msg(tm, ID_REMOVE, 0, tm->val);
FsmAddTimer(&tm->t201, tm->T201, EV_T201, NULL, 2);
FsmChangeState(&tm->tei_m, ST_TEI_REMOVE);
} else
tm->ri = *ri;
}
static void
tei_id_remove(struct FsmInst *fi, int event, void *arg)
{
teimgr_t *tm = fi->userdata;
int *tei = arg;
if (tm->debug)
tm->tei_m.printdebug(fi, "identity remove tei %d/%d", *tei, tm->l2->tei);
tm->val = *tei;
put_tei_msg(tm, ID_REMOVE, 0, tm->val);
FsmAddTimer(&tm->t201, tm->T201, EV_T201, NULL, 2);
FsmChangeState(&tm->tei_m, ST_TEI_REMOVE);
}
static void
tei_id_verify(struct FsmInst *fi, int event, void *arg)
{
teimgr_t *tm = fi->userdata;
if (tm->debug)
tm->tei_m.printdebug(fi, "id verify request for tei %d",
tm->l2->tei);
tm->ri = -1;
put_tei_msg(tm, ID_CHK_REQ, 0, tm->l2->tei);
FsmChangeState(&tm->tei_m, ST_TEI_IDVERIFY);
test_and_set_bit(FLG_TEI_T201_1, &tm->l2->flag);
FsmAddTimer(&tm->t201, tm->T201, EV_T201, NULL, 2);
}
static void
tei_id_remove_tout(struct FsmInst *fi, int event, void *arg)
{
teimgr_t *tm = fi->userdata;
if (tm->debug)
tm->tei_m.printdebug(fi, "remove req(2) tei %d",
tm->l2->tei);
put_tei_msg(tm, ID_REMOVE, 0, tm->val);
FsmChangeState(fi, ST_TEI_NOP);
}
static void
tei_id_ver_tout(struct FsmInst *fi, int event, void *arg)
{
teimgr_t *tm = fi->userdata;
if (tm->debug)
tm->tei_m.printdebug(fi, "verify tout tei %d",
tm->l2->tei);
if (test_and_clear_bit(FLG_TEI_T201_1, &tm->l2->flag)) {
put_tei_msg(tm, ID_CHK_REQ, 0, tm->l2->tei);
tm->ri = -1;
FsmAddTimer(&tm->t201, tm->T201, EV_T201, NULL, 3);
} else {
FsmChangeState(fi, ST_TEI_NOP);
if (tm->ri == -1) {
tm->tei_m.printdebug(fi, "tei %d check no response",
tm->l2->tei);
// remove tei
} else
tm->tei_m.printdebug(fi, "tei %d check ok",
tm->l2->tei);
}
}
int
l2_tei(teimgr_t *tm, msg_t *msg)
{
mISDNuser_head_t *hh;
int ret = -EINVAL;
if (!tm || !msg)
return(ret);
hh = (mISDNuser_head_t *)msg->data;
dprint(DBGM_TEI, -1, "%s: prim(%x)\n", __FUNCTION__, hh->prim);
if (msg->len < mISDN_FRAME_MIN)
return(ret);
switch(hh->prim) {
case (MDL_REMOVE | INDICATION):
FsmEvent(&tm->tei_m, EV_REMOVE, &hh->dinfo);
break;
case (MDL_ERROR | REQUEST):
if (!test_bit(FLG_FIXED_TEI, &tm->l2->flag))
FsmEvent(&tm->tei_m, EV_VERIFY, NULL);
break;
}
free_msg(msg);
return(0);
}
static void
tei_debug(struct FsmInst *fi, char *fmt, ...)
{
teimgr_t *tm = fi->userdata;
char tbuf[128];
va_list args;
va_start(args, fmt);
vsprintf(tbuf, fmt, args);
dprint(DBGM_L2, -1, "tei%d %s\n", tm->l2->tei, tbuf);
va_end(args);
}
static struct FsmNode TeiFnList[] =
{
{ST_TEI_NOP, EV_ASSIGN_REQ, tei_assign_req},
{ST_TEI_NOP, EV_VERIFY, tei_id_verify},
{ST_TEI_NOP, EV_REMOVE, tei_id_remove},
{ST_TEI_REMOVE, EV_T201, tei_id_remove_tout},
{ST_TEI_IDVERIFY, EV_T201, tei_id_ver_tout},
{ST_TEI_IDVERIFY, EV_REMOVE, tei_id_remove},
{ST_TEI_IDVERIFY, EV_CHECK_RES, tei_id_chk_res},
};
#define TEI_FN_COUNT (sizeof(TeiFnList)/sizeof(struct FsmNode))
void
release_tei(teimgr_t *tm)
{
FsmDelTimer(&tm->t201, 1);
free(tm);
}
int
create_teimgr(layer2_t *l2) {
teimgr_t *ntei;
if (!l2) {
eprint("create_tei no layer2\n");
return(-EINVAL);
}
if (!(ntei = malloc(sizeof(teimgr_t)))) {
eprint("kmalloc teimgr failed\n");
return(-ENOMEM);
}
memset(ntei, 0, sizeof(teimgr_t));
ntei->l2 = l2;
ntei->T201 = 1000; /* T201 1000 milliseconds */
ntei->debug = l2->debug;
ntei->tei_m.nst = l2->nst;
ntei->tei_m.debug = l2->debug;
ntei->tei_m.userdata = ntei;
ntei->tei_m.printdebug = tei_debug;
ntei->tei_m.fsm = l2->nst->teifsm;
ntei->tei_m.state = ST_TEI_NOP;
FsmInitTimer(&ntei->tei_m, &ntei->t201);
l2->tm = ntei;
return(0);
}
int
tei_mux(net_stack_t *nst, msg_t *msg)
{
mISDNuser_head_t *hh;
u_char *dp;
int mt;
layer2_t *l2;
unsigned int ri, ai;
hh = (mISDNuser_head_t *)msg->data;
dprint(DBGM_TEI, -1, "%s: prim(%x) len(%d)\n", __FUNCTION__,
hh->prim, msg->len);
if (msg->len < mISDN_FRAME_MIN)
return(-EINVAL);
if (hh->prim != (MDL_UNITDATA | INDICATION)) {
wprint("%s: prim(%x) unhandled\n", __FUNCTION__,
hh->prim);
return(-EINVAL);
}
msg_pull(msg, mISDNUSER_HEAD_SIZE);
if (msg->len < 8) {
wprint("short tei mgr frame %d/8\n", msg->len);
return(-EINVAL);
}
dp = msg->data + 2;
if ((*dp & 0xef) != UI) {
wprint("tei mgr frame is not ui %x\n", *dp);
return(-EINVAL);
}
dp++;
if (*dp++ != TEI_ENTITY_ID) {
/* wrong management entity identifier, ignore */
dp--;
wprint("tei handler wrong entity id %x\n", *dp);
return(-EINVAL);
} else {
mt = *(dp+2);
ri = ((unsigned int) *dp++ << 8);
ri += *dp++;
dp++;
ai = (unsigned int) *dp++;
ai >>= 1;
dprint(DBGM_TEI, -1, "tei handler mt %x ri(%x) ai(%d)\n",
mt, ri, ai);
if (mt == ID_REQUEST) {
if (ai != 127) {
wprint("%s: ID_REQUEST ai(%d) not 127\n", __FUNCTION__,
ai);
return(-EINVAL);
}
l2 = new_tei_req(nst);
if (!l2) {
wprint("%s: no free tei\n", __FUNCTION__);
return(-EBUSY);
}
l2->tm->ri = ri;
put_tei_msg(l2->tm, ID_ASSIGNED, ri, l2->tei);
free_msg(msg);
return(0);
}
l2 = find_tei(nst, ai);
if (mt == ID_VERIFY) {
if (l2) {
FsmEvent(&l2->tm->tei_m, EV_VERIFY, &ai);
} else {
l2 = find_tei(nst, 127);
if (!l2) {
wprint("%s: no 127 manager\n", __FUNCTION__);
return(-EINVAL);
}
FsmEvent(&l2->tm->tei_m, EV_REMOVE, &ai);
}
} else if (mt == ID_CHK_RES) {
if (l2) {
FsmEvent(&l2->tm->tei_m, EV_CHECK_RES, &ri);
} else {
l2 = find_tei(nst, 127);
if (!l2) {
wprint("%s: no 127 manager\n", __FUNCTION__);
return(-EINVAL);
}
FsmEvent(&l2->tm->tei_m, EV_REMOVE, &ai);
}
} else {
wprint("%s: wrong mt %x", __FUNCTION__, mt);
return(-EINVAL);
}
}
free_msg(msg);
return(0);
}
int TEIInit(net_stack_t *nst)
{
struct Fsm *teif;
if (!(teif = malloc(sizeof(struct Fsm))))
return(1);
nst->teifsm = teif;
memset(teif, 0, sizeof(struct Fsm));
teif->state_count = TEI_STATE_COUNT;
teif->event_count = TEI_EVENT_COUNT;
teif->strEvent = strTeiEvent;
teif->strState = strTeiState;
FsmNew(teif, TeiFnList, TEI_FN_COUNT);
return(0);
}
void TEIFree(net_stack_t *nst)
{
FsmFree(nst->teifsm);
}

147
i4lnet/tone.c Normal file
View File

@ -0,0 +1,147 @@
#include <stdio.h>
#include "isdn_net.h"
#include "tone.h"
#include "bchannel.h"
/*
* These are 10 periods (24 ms) of the 425 Hz tone used by most inband
* signals.
* Its quiet not exacly 425 Hz, but 416,66667, which fit very well
* the 15% tolerance
*/
const unsigned char tone_425[TONE_425_SIZE] = {
0xd5, 0x81, 0xb6, 0xbf, 0xbb, 0xba, 0xb8, 0xb2,
0x8a, 0x9d, 0x15, 0x0e, 0x33, 0x39, 0x3a, 0x3b,
0x3e, 0x31, 0x0d, 0x65, 0x85, 0xb4, 0xbd, 0xb8,
0xba, 0xb8, 0xbd, 0xb4, 0x85, 0x65, 0x0d, 0x31,
0x3e, 0x3b, 0x3a, 0x39, 0x33, 0x0e, 0x15, 0x9d,
0x8a, 0xb2, 0xb8, 0xba, 0xbb, 0xbf, 0xb6, 0x81,
0xd5, 0x01, 0x36, 0x3f, 0x3b, 0x3a, 0x38, 0x32,
0x0a, 0x1d, 0x95, 0x8e, 0xb3, 0xb9, 0xba, 0xbb,
0xbe, 0xb1, 0x8d, 0xe5, 0x05, 0x34, 0x3d, 0x38,
0x3a, 0x38, 0x3d, 0x34, 0x05, 0xe5, 0x8d, 0xb1,
0xbe, 0xbb, 0xba, 0xb9, 0xb3, 0x8e, 0x95, 0x1d,
0x0a, 0x32, 0x38, 0x3a, 0x3b, 0x3f, 0x36, 0x01,
0xd5, 0x81, 0xb6, 0xbf, 0xbb, 0xba, 0xb8, 0xb2,
0x8a, 0x9d, 0x15, 0x0e, 0x33, 0x39, 0x3a, 0x3b,
0x3e, 0x31, 0x0d, 0x65, 0x85, 0xb4, 0xbd, 0xb8,
0xba, 0xb8, 0xbd, 0xb4, 0x85, 0x65, 0x0d, 0x31,
0x3e, 0x3b, 0x3a, 0x39, 0x33, 0x0e, 0x15, 0x9d,
0x8a, 0xb2, 0xb8, 0xba, 0xbb, 0xbf, 0xb6, 0x81,
0xd5, 0x01, 0x36, 0x3f, 0x3b, 0x3a, 0x38, 0x32,
0x0a, 0x1d, 0x95, 0x8e, 0xb3, 0xb9, 0xba, 0xbb,
0xbe, 0xb1, 0x8d, 0xe5, 0x05, 0x34, 0x3d, 0x38,
0x3a, 0x38, 0x3d, 0x34, 0x05, 0xe5, 0x8d, 0xb1,
0xbe, 0xbb, 0xba, 0xb9, 0xb3, 0x8e, 0x95, 0x1d,
0x0a, 0x32, 0x38, 0x3a, 0x3b, 0x3f, 0x36, 0x01
};
/*
* These are 10 ms of silence
*/
const unsigned char tone_SILENCE[TONE_SILENCE_SIZE] = {
0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5,
0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5,
0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5,
0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5,
0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5,
0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5,
0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5,
0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5,
0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5,
0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5
};
int tone_handler(bchannel_t *bc) {
const unsigned char *tp;
int len;
dprint(DBGM_TONE, -1, "%s:ch%d Flags %x\n", __FUNCTION__,
bc->channel, bc->Flags);
if (bc->bstate != BC_BSTATE_ACTIV)
return(1);
if (bc->smsg)
return(2);
if (!(bc->Flags & FLG_BC_TONE))
return(3);
if (bc->Flags & FLG_BC_TONE_DIAL) {
tp = tone_425;
len = TONE_425_SIZE;
} else if (bc->Flags & FLG_BC_TONE_ALERT) {
if (bc->Flags & FLG_BC_TONE_SILENCE) {
if (bc->ttime > TONE_ALERT_SILENCE_TIME) {
bc->ttime = 0;
tp = tone_425;
len = TONE_425_SIZE;
bc->Flags &= ~FLG_BC_TONE_SILENCE;
} else {
tp = tone_SILENCE;
len = TONE_SILENCE_SIZE;
}
} else {
if (bc->ttime > TONE_ALERT_TIME) {
bc->ttime = 0;
tp = tone_SILENCE;
len = TONE_SILENCE_SIZE;
bc->Flags |= FLG_BC_TONE_SILENCE;
} else {
tp = tone_425;
len = TONE_425_SIZE;
}
}
} else if (bc->Flags & FLG_BC_TONE_BUSY) {
if (bc->Flags & FLG_BC_TONE_SILENCE) {
if (bc->ttime > TONE_BUSY_SILENCE_TIME) {
bc->ttime = 0;
tp = tone_425;
len = TONE_425_SIZE;
bc->Flags &= ~FLG_BC_TONE_SILENCE;
} else {
tp = tone_SILENCE;
len = TONE_SILENCE_SIZE;
}
} else {
if (bc->ttime > TONE_BUSY_TIME) {
bc->ttime = 0;
tp = tone_SILENCE;
len = TONE_SILENCE_SIZE;
bc->Flags |= FLG_BC_TONE_SILENCE;
} else {
tp = tone_425;
len = TONE_425_SIZE;
}
}
} else if (bc->Flags & FLG_BC_TONE_SILENCE) {
tp = tone_SILENCE;
len = TONE_SILENCE_SIZE;
} else
return(4);
if (len > ibuf_freecount(bc->sbuf)) {
dprint(DBGM_TONE, -1, "%s:ch%d not sbuf %d/%d\n", __FUNCTION__,
bc->channel, len, ibuf_freecount(bc->sbuf));
return(5);
}
if (bc->sbuf) {
bc->ttime += len*125;
ibuf_memcpy_w(bc->sbuf, (unsigned char *)tp, len);
sem_post(bc->sbuf->rsem);
}
return(0);
}
int
set_tone(bchannel_t *bc, int tone)
{
bc->Flags &= ~FLG_BC_TONE;
bc->Flags |= tone;
bc->ttime = 0;
if (tone) {
if (bc->sbuf) {
bc->sbuf->rsem = &bc->work;
bc->sbuf->wsem = &bc->work;
}
}
return(bc->Flags & FLG_BC_TONE);
}

2
include/.gitignore vendored
View File

@ -1,2 +0,0 @@
/stamp-h1
/config.h

View File

@ -1,7 +0,0 @@
nobase_include_HEADERS = mISDN/l3dss1.h mISDN/mbuffer.h mISDN/mISDNif.h mISDN/mlayer3.h mISDN/q931.h mISDN/suppserv.h
nobase_nodist_include_HEADERS = mISDN/mISDNcompat.h
# private mISDNuser code fragment
noinst_HEADERS = mISDN/af_isdn.h
CLEANFILES = *~ mISDN/*~

Some files were not shown because too many files have changed in this diff Show More