Initial revision

This commit is contained in:
kkeil 2003-08-27 07:33:02 +00:00
commit 0c3b232b6a
78 changed files with 21629 additions and 0 deletions

3
.cvsignore Normal file
View File

@ -0,0 +1,3 @@
*.o
*.a
*~

63
Makefile Normal file
View File

@ -0,0 +1,63 @@
mISDN_DIR := $(PWD)
export mISDN_DIR
INCLUDEDIR := $(mISDN_DIR)/include
export INCLUDEDIR
CFLAGS:= -g -Wall -O2 -I $(INCLUDEDIR)
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)
LIBS := lib/libmISDN.a
all:
make TARGET=$@ subdirs
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

32
example/Makefile Normal file
View File

@ -0,0 +1,32 @@
LIBINCL := $(INCLUDEDIR)/mISDNlib.h
PROGS := testcon testnet testcon_l2 loadfirm logger
all: $(PROGS)
testcon: testcon.o $(mISDNLIB)
testnet: testnet.o $(mISDNLIB)
testcon_l2: testcon_l2.o $(mISDNLIB)
loadfirm: loadfirm.o $(mISDNLIB)
logger: logger.o $(mISDNLIB)
testcon.o : testcon.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)
logger.o: logger.c $(LIBINCL)
clean:
rm -f *.o *~ DEADJOE
distclean: clean
rm -f *.a $(PROGS)

288
example/loadfirm.c Normal file
View File

@ -0,0 +1,288 @@
#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 recived 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 = 0;
frm->addr = di->b_adress[di->used_bchannel] | IF_DOWN;
frm->len = 8;
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 = 0;
frm->addr = di->b_adress[di->used_bchannel] | IF_DOWN;
frm->len = l + 8;
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 = 0;
frm->addr = di->b_adress[di->used_bchannel] | IF_DOWN;
frm->len = 4;
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;
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<=0) {
fprintf(stdout, "new_layer ret(%d)\n", ret);
return(4);
}
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] = 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(5);
}
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);
}

477
example/logger.c Normal file
View File

@ -0,0 +1,477 @@
#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, &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 *p, *msg, buf[MAX_REC_BUF];
iframe_t *rfrm;
int timeout = TIMEOUT_10SEC;
int ret = 0;
int len;
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;
stack_info_t si;
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, 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;
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);
}

BIN
example/test_file Executable file

Binary file not shown.

0
example/test_file.in Executable file
View File

1
example/test_file.out Executable 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

868
example/testcon.c Normal file
View File

@ -0,0 +1,868 @@
#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
static int VerifyOn=0;
static 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] | IF_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] | IF_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_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 | IF_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] | 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 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] | IF_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] | IF_DOWN)) {
/* B-Channel related messages */
if (rfrm->prim == (DL_DATA | INDICATION)) {
/* received data, save it */
write(di->save, &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 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 | IF_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 | IF_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 | IF_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 | IF_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 | IF_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 | IF_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 | IF_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 | 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);
return(0);
}
int
add_dlayer3(devinfo_t *di, int prot)
{
layer_info_t li;
stack_info_t si;
interface_info_t ii;
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);
/*
* 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 = IF_DOWN;
ret = mISDN_connect(di->device, &ii);
if (ret)
return(13);
ii.owner = di->layer3;
ii.stat = IF_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;
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:
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:
di->bl1_prot = ISDN_PID_L1_B_64HDLC;
di->bl2_prot = ISDN_PID_L2_B_X75SLP;
di->si = 7;
di->flag |= FLG_BCHANNEL_ACTDELAYED;
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 (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 | IF_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);
}

0
example/testcon.in Executable file
View File

869
example/testcon_l2.c Normal file
View File

@ -0,0 +1,869 @@
/* 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] | IF_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] | IF_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 | IF_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] | IF_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] | 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 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] | IF_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] | IF_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 | IF_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 | IF_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 | IF_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 | IF_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 | IF_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 | IF_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 | IF_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 | 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);
return(0);
}
int
add_dlayer3(devinfo_t *di, int prot)
{
layer_info_t li;
stack_info_t si;
interface_info_t ii;
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);
/*
* 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 = IF_DOWN;
ret = mISDN_connect(di->device, &ii);
if (ret)
return(13);
ii.owner = di->layer3;
ii.stat = IF_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;
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 | IF_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);
}

963
example/testnet.c Normal file
View File

@ -0,0 +1,963 @@
#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] | IF_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] | IF_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 | IF_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] | 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 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] | IF_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] | IF_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 | IF_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 | IF_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 | IF_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 | IF_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 | IF_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 | IF_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 | IF_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 | 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);
return(0);
}
int
add_dlayer3(devinfo_t *di, int prot)
{
layer_info_t li;
stack_info_t si;
interface_info_t ii;
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);
/*
* 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 = IF_DOWN;
ret = mISDN_connect(di->device, &ii);
if (ret)
return(13);
ii.owner = di->layer3;
ii.stat = IF_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;
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 | IF_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);
}

39
i4lnet/Makefile Normal file
View File

@ -0,0 +1,39 @@
all: libisdnnet.a
ISDNNETOBJ = 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
libisdnnet.a: $(ISDNNETOBJ)
rm -f $@
ar cr $@ $(ISDNNETOBJ)
isdn_msg.o : isdn_msg.c $(INCLUDEDIR)/isdn_msg.h $(INCLUDEDIR)/isdn_net.h
isdn_debug.o : isdn_debug.c $(INCLUDEDIR)/isdn_debug.h
net_l2.o : net_l2.c net_l2.h $(INCLUDEDIR)/isdn_net.h fsm.h
fsm.o : fsm.c fsm.h $(INCLUDEDIR)/isdn_net.h
tei.o : tei.c net_l2.h $(INCLUDEDIR)/isdn_net.h
net_l3.o : net_l3.c $(INCLUDEDIR)/isdn_net.h net_l3.h
manager.o : manager.c $(INCLUDEDIR)/isdn_net.h $(INCLUDEDIR)/bchannel.h
net_if.o : net_if.c $(INCLUDEDIR)/isdn_net.h
tone.o: tone.c $(INCLUDEDIR)/tone.h $(INCLUDEDIR)/bchannel.h \
$(INCLUDEDIR)/isdn_net.h $(INCLUDEDIR)/ibuffer.h
bchannel.o: bchannel.c $(INCLUDEDIR)/isdn_net.h $(INCLUDEDIR)/tone.h \
$(INCLUDEDIR)/bchannel.h net_l3.h $(INCLUDEDIR)/ibuffer.h
g711.o: g711.c $(INCLUDEDIR)/g711.h
clean:
rm -f *.o *~ DEADJOE
distclean: clean
rm -f *.a

1379
i4lnet/bchannel.c Normal file

File diff suppressed because it is too large Load Diff

163
i4lnet/fsm.c Normal file
View File

@ -0,0 +1,163 @@
/* $Id: fsm.c,v 0.9 2003/08/27 07:33:03 kkeil Exp $
*
* Author Karsten Keil (keil@isdn4linux.de)
*
* Thanks to Jan den Ouden
* Fritz Elfert
*
* This file is (c) under GNU PUBLIC LICENSE
*
*/
#include <stdio.h>
#include <stdlib.h>
#include "fsm.h"
#define FSM_TIMER_DEBUG 0
void
FsmNew(struct Fsm *fsm,
struct FsmNode *fnlist, int fncount)
{
int i;
fsm->jumpmatrix = (FSMFNPTR *)
malloc(sizeof (FSMFNPTR) * fsm->state_count * fsm->event_count);
if (!fsm->jumpmatrix)
return;
memset(fsm->jumpmatrix, 0, sizeof (FSMFNPTR) * fsm->state_count * fsm->event_count);
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
fsm->jumpmatrix[fsm->state_count * fnlist[i].event +
fnlist[i].state] = (FSMFNPTR) fnlist[i].routine;
}
void
FsmFree(struct Fsm *fsm)
{
free(fsm->jumpmatrix);
}
int
FsmEvent(struct FsmInst *fi, int event, void *arg)
{
FSMFNPTR r;
if ((fi->state>=fi->fsm->state_count) || (event >= fi->fsm->event_count)) {
eprint("FsmEvent Error st(%ld/%ld) ev(%d/%ld)\n",
(long)fi->state,(long)fi->fsm->state_count,event,(long)fi->fsm->event_count);
return(1);
}
r = fi->fsm->jumpmatrix[fi->fsm->state_count * event + fi->state];
if (r) {
if (fi->debug)
fi->printdebug(fi, "State %s Event %s",
fi->fsm->strState[fi->state],
fi->fsm->strEvent[event]);
r(fi, event, arg);
return (0);
} else {
if (fi->debug)
fi->printdebug(fi, "State %s Event %s no action",
fi->fsm->strState[fi->state],
fi->fsm->strEvent[event]);
return (!0);
}
}
void
FsmChangeState(struct FsmInst *fi, int newstate)
{
fi->state = newstate;
if (fi->debug)
fi->printdebug(fi, "ChangeState %s",
fi->fsm->strState[newstate]);
}
static int
FsmExpireTimer(struct FsmTimer *ft)
{
#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->nst);
}
void
FsmDelTimer(struct FsmTimer *ft, int where)
{
#if FSM_TIMER_DEBUG
if (ft->fi->debug)
ft->fi->printdebug(ft->fi, "FsmDelTimer %lx %d", (long) ft, where);
#endif
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)
{
#if FSM_TIMER_DEBUG
if (ft->fi->debug)
ft->fi->printdebug(ft->fi, "FsmAddTimer %lx %d %d",
(long) ft, millisec, where);
#endif
if (timer_pending(&ft->tl)) {
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;
ft->tl.expires = millisec;
add_timer(&ft->tl);
return 0;
}
void
FsmRestartTimer(struct FsmTimer *ft,
int millisec, int event, void *arg, int where)
{
#if FSM_TIMER_DEBUG
if (ft->fi->debug)
ft->fi->printdebug(ft->fi, "FsmRestartTimer %lx %d %d",
(long) ft, millisec, where);
#endif
if (timer_pending(&ft->tl))
del_timer(&ft->tl);
init_timer(&ft->tl, ft->fi->nst);
ft->event = event;
ft->arg = arg;
ft->tl.expires = millisec;
add_timer(&ft->tl);
}

53
i4lnet/fsm.h Normal file
View File

@ -0,0 +1,53 @@
/* $Id: fsm.h,v 0.9 2003/08/27 07:33:03 kkeil Exp $
*
* 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,
};

151
i4lnet/isdn_debug.c Normal file
View File

@ -0,0 +1,151 @@
#include <stdarg.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, const char *fmt, ...)
{
int ret = 0;
va_list args;
va_start(args, fmt);
if (debug_mask & 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);
}

113
i4lnet/isdn_msg.c Normal file
View File

@ -0,0 +1,113 @@
#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,"%s: %d msg(%p) at %p %p\n", __FUNCTION__,
alloc_msg_cnt, m, __builtin_return_address(0),
__builtin_return_address(1));
return(m);
}
void
free_msg(msg_t *msg) {
if (!msg) {
wprint("free NULL msg\n");
return;
}
dprint(DBGM_MSG,"%s: %d/%d msg(%p) at %p %p\n", __FUNCTION__,
alloc_msg_cnt, free_queue->len, msg,
__builtin_return_address(0), __builtin_return_address(1));
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, "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,"%s: old(%p)\n", __FUNCTION__, msg);
nmsg = alloc_msg(msg->size);
if (!nmsg)
return(NULL);
dprint(DBGM_MSG,"%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,"%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;
mISDN_head_t *hh;
dprint(DBGM_MAN, "%s:dat(%p) arg(%p)\n", __FUNCTION__,
dat, arg);
if (!nst | !arg)
return(-EINVAL);
hh = (mISDN_head_t *)msg->data;
dprint(DBGM_MAN, "%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;
mISDN_head_t *hh;
if (!msg || !mgr)
return(-EINVAL);
hh = (mISDN_head_t *)msg->data;
dprint(DBGM_MAN, "%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 + mISDN_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 + mISDN_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, "%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,"%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,"%s: join ret(%d) bc1 retv(%p)\n", __FUNCTION__,
ret, retv);
ret = pthread_join(mgr->bc[1].tid, (void *)&retv);
dprint(DBGM_MAN,"%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);
}

708
i4lnet/net_if.c Normal file
View File

@ -0,0 +1,708 @@
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <asm/bitops.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;
interface_info_t ii;
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, "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, "bst1 %x bst2 %x\n",
nst->b_stid[0], nst->b_stid[1]);
break;
} else
dprint(DBGM_NET, "stack %d instcnt is %d\n",
i, stinf->instcnt);
} else
dprint(DBGM_NET, "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, "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);
}
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);
}
dprint(DBGM_NET, "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, "init timer(%x)\n", it->id);
if (test_bit(FLG_TIMER_RUNING, &it->Flags))
dprint(DBGM_NET, "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, "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, "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, "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;
mISDN_head_t *hh;
hh = (mISDN_head_t *)msg->data;
dprint(DBGM_NET, "%s: msg(%p) len(%d) pr(%x) di(%x)\n", __FUNCTION__,
msg, msg->len, hh->prim, hh->dinfo);
msg_pull(msg, mISDN_HEAD_SIZE);
frm = (iframe_t *)msg_push(msg, IFRAME_HEAD_SIZE);
frm->prim = hh->prim;
frm->dinfo = hh->dinfo;
frm->addr = nst->l2_id | IF_DOWN;
frm->len = msg->len - IFRAME_HEAD_SIZE;
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, "%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,"%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, "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)
{
mISDN_head_t *hh;
msg_pull(msg, IFRAME_HEAD_SIZE);
hh = (mISDN_head_t *)msg_push(msg, mISDN_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,"%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 & IF_ADDRMASK) == nst->l2_id) {
if (nst->l1_l2) {
ret = nst->l1_l2(nst, msg);
}
} else if (nst->b_addr[0] &&
((frm->addr & IF_ADDRMASK) == nst->b_addr[0])) {
ret = b_message(nst, 0, frm, msg);
} else if (nst->b_addr[1] &&
((frm->addr & IF_ADDRMASK) == 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,"%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, mISDN_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,"%s:ch%d\n", __FUNCTION__, hh->dinfo);
msg_pull(msg, mISDN_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,"%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, mISDN_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,"%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, mISDN_head_t *hh, msg_t *msg)
{
iframe_t *frm;
hh = (mISDN_head_t *)msg->data;
dprint(DBGM_NET, "%s: msg(%p) len(%d) pr(%x) di(%x)\n", __FUNCTION__,
msg, msg->len, hh->prim, hh->dinfo);
msg_pull(msg, mISDN_HEAD_SIZE);
frm = (iframe_t *)msg_push(msg, IFRAME_HEAD_SIZE);
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 - IFRAME_HEAD_SIZE;
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)
{
mISDN_head_t *hh;
int ret = -EINVAL;
if (!nst || !msg)
return(-EINVAL);
hh = (mISDN_head_t *)msg->data;
dprint(DBGM_NET,"%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, mISDN_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, "%s: tid %ld\n", __FUNCTION__, tid);
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
while(lp) {
// dprint(DBGM_NET, "%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, "%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, "%s: rdfunc ret(%d)\n", __FUNCTION__, ret);
}
}
if (FD_ISSET(nst->device, &efd)) {
dprint(DBGM_NET, "%s: exception\n", __FUNCTION__);
}
}
}
dprint(DBGM_NET,"%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, "%s: tid %ld\n", __FUNCTION__, tid);
ret = pthread_create(&nst->reader, NULL, main_readloop, (void *)nst);
tid = pthread_self();
dprint(DBGM_NET, "%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,"%s: reader aborted\n", __FUNCTION__);
ret = pthread_join(nst->reader, &retval);
dprint(DBGM_NET,"%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,"%s: reader cancel\n", __FUNCTION__);
ret = pthread_cancel(nst->reader);
dprint(DBGM_NET,"%s: cancel reader ret(%d)\n", __FUNCTION__,
ret);
ret = pthread_join(nst->reader, &retval);
dprint(DBGM_NET,"%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);
}

2072
i4lnet/net_l2.c Normal file

File diff suppressed because it is too large Load Diff

118
i4lnet/net_l2.h Normal file
View File

@ -0,0 +1,118 @@
/* $Id: net_l2.h,v 0.9 2003/08/27 07:33:03 kkeil Exp $
*
* Layer 2 defines
*
* This file is (c) under GNU PUBLIC LICENSE
*
*/
#ifndef NET_L2_H
#define NET_L2_H
#include <asm/bitops.h>
#include "mISDNlib.h"
#include "isdn_net.h"
#include "fsm.h"
#ifdef MEMDBG
#include "memdbg.h"
#endif
#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_int 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 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(void);
extern void TEIFree(void);
#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
#endif

2213
i4lnet/net_l3.c Normal file

File diff suppressed because it is too large Load Diff

257
i4lnet/net_l3.h Normal file
View File

@ -0,0 +1,257 @@
/* $Id: net_l3.h,v 0.9 2003/08/27 07:33:03 kkeil Exp $
*
* 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;
int Flags;
L3Timer_t timer1;
L3Timer_t timer2;
int bc;
int err;
int cause;
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 squeue;
int l2_state;
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 *);
/* 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;
} ALERTING_t;
typedef struct _CALL_PROCEEDING {
u_char *BEARER;
u_char *CHANNEL_ID;
u_char *FACILITY;
u_char *PROGRESS;
u_char *DISPLAY;
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;
} 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;
} NOTIFY_t;
typedef struct _PROGRESS {
u_char *BEARER;
u_char *CAUSE;
u_char *FACILITY;
u_char *PROGRESS;
u_char *DISPLAY;
u_char *HLC;
u_char *USER_USER;
} 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;
} 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;
} 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;
#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) {
mISDN_head_t *hh;
layer4_t *l4;
if (!msg)
return(-EINVAL);
hh = (mISDN_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);
}

441
i4lnet/tei.c Normal file
View File

@ -0,0 +1,441 @@
/* $Id: tei.c,v 0.9 2003/08/27 07:33:03 kkeil Exp $
*
* 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: 0.9 $";
#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
static
struct Fsm teifsm =
{NULL, 0, 0, NULL, NULL};
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, "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)
{
mISDN_head_t *hh;
int ret = -EINVAL;
if (!tm || !msg)
return(ret);
hh = (mISDN_head_t *)msg->data;
dprint(DBGM_TEI, "%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, "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 = &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)
{
mISDN_head_t *hh;
u_char *dp;
int mt;
layer2_t *l2;
unsigned int ri, ai;
hh = (mISDN_head_t *)msg->data;
dprint(DBGM_TEI, "%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, mISDN_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, "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(void)
{
teifsm.state_count = TEI_STATE_COUNT;
teifsm.event_count = TEI_EVENT_COUNT;
teifsm.strEvent = strTeiEvent;
teifsm.strState = strTeiState;
FsmNew(&teifsm, TeiFnList, TEI_FN_COUNT);
return(0);
}
void TEIFree(void)
{
FsmFree(&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, "%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, "%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);
}

37
include/bchannel.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef BCHANNEL_H
#define BCHANNEL_H
enum {
BC_CSTATE_NULL,
BC_CSTATE_ICALL,
BC_CSTATE_OCALL,
BC_CSTATE_OVERLAP_REC,
BC_CSTATE_PROCEED,
BC_CSTATE_ALERTING,
BC_CSTATE_ACTIV,
BC_CSTATE_DISCONNECT,
BC_CSTATE_DISCONNECTED,
BC_CSTATE_RELEASE,
};
enum {
BC_BSTATE_NULL,
BC_BSTATE_SETUP,
BC_BSTATE_ACTIVATE,
BC_BSTATE_ACTIV,
BC_BSTATE_DEACTIVATE,
BC_BSTATE_CLEANUP,
};
#define BC_SETUP 0x0e0100
#define BC_CLEANUP 0x0e0200
#define ISDN_PID_L2_B_USER 0x420000ff
#define ISDN_PID_L3_B_USER 0x430000ff
extern int init_bchannel(bchannel_t *bc, int channel);
extern int term_bchannel(bchannel_t *bc);
#endif

68
include/g711.h Normal file
View File

@ -0,0 +1,68 @@
/*
* 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
*
*
*
*/
#ifndef G711_H
#define G711_H
extern unsigned char _l2u[4096];
extern unsigned char _l2A[2048];
extern unsigned char _u2A[256];
extern unsigned char _A2u[256];
extern signed short _u2l[256];
extern signed short _A2l[256];
static __inline__ unsigned char linear2ulaw(signed short l)
{
unsigned char mask;
mask = (l<0) ? 0x7f : 0xff;
if (l<0)
l = -l;
if (l<4)
return(0xff & mask);
l -= 4;
l >>= 3;
return(_l2u[l] & mask);
}
static __inline__ unsigned char linear2alaw(signed short l)
{
unsigned char mask;
mask = (l<0) ? 0x7f : 0xff;
if (l<0)
l = -l;
l >>= 4;
return(_l2A[l] & mask);
}
static __inline__ signed short ulaw2linear(unsigned char u)
{
return(_u2l[u]);
}
static __inline__ signed short alaw2linear(unsigned char a)
{
return(_A2l[a]);
}
static __inline__ unsigned char ulaw2alaw(unsigned char u)
{
return(_u2A[u]);
}
static __inline__ unsigned char alaw2ulaw(unsigned char a)
{
return(_A2u[a]);
}
#endif

58
include/helper.h Normal file
View File

@ -0,0 +1,58 @@
/* $Id: helper.h,v 0.9 2003/08/27 07:33:02 kkeil Exp $
*
* Basic declarations, defines and prototypes
*
* This file is (c) under GNU PUBLIC LICENSE
*
*/
#ifndef _mISDN_HELPER_H
#define _mISDN_HELPER_H
#ifdef MEMDBG
#include "memdbg.h"
#endif
#define int_error() \
fprintf(stderr, "mISDN: INTERNAL ERROR in %s:%d\n", \
__FILE__, __LINE__)
#define int_errtxt(fmt, arg...) \
fprintf(stderr, "mISDN: INTERNAL ERROR in %s:%d " fmt "\n", \
__FILE__, __LINE__, ## arg)
#define APPEND_TO_LIST(item,base) \
if (item->prev || item->next) \
int_errtxt("APPEND not clean %p<-%p->%p", \
item->prev, item, item->next); \
item->next = NULL; \
item->prev = base; \
while (item->prev && item->prev->next) \
item->prev = item->prev->next; \
if (item->prev == item) { \
int_errtxt("APPEND DUP %p", item); \
} else \
if (base) { \
item->prev->next = item; \
} else \
base = item
#define INSERT_INTO_LIST(newi,nexti,base) \
newi->next = nexti; \
newi->prev = nexti->prev; \
if (newi->prev) \
newi->prev->next = newi; \
nexti->prev = newi; \
if (base == nexti) \
base = newi
#define REMOVE_FROM_LIST(item) \
if (item->prev) \
item->prev->next = item->next; \
if (item->next) \
item->next->prev = item->prev
#define REMOVE_FROM_LISTBASE(item,base) \
REMOVE_FROM_LIST(item); \
if (item == base) \
base = item->next
#endif

119
include/ibuffer.h Normal file
View File

@ -0,0 +1,119 @@
#ifndef IBUFFER_H
#define IBUFFER_H
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <string.h>
/* ibuffer stuff */
typedef struct _ibuffer ibuffer_t;
struct _ibuffer {
int size;
unsigned char *buffer;
int ridx;
int widx;
sem_t *rsem;
sem_t *wsem;
};
static inline void
clear_ibuffer(ibuffer_t *ib)
{
if (!ib)
return;
ib->ridx = 0;
ib->widx = 0;
}
static inline ibuffer_t *
init_ibuffer(int size)
{
ibuffer_t *ib;
ib = malloc(sizeof(ibuffer_t));
if (!ib)
return(NULL);
memset(ib, 0, sizeof(ibuffer_t));
ib->buffer = malloc(size);
if (!ib->buffer) {
free(ib);
return(NULL);
}
ib->size = size;
return(ib);
}
static inline void
free_ibuffer(ibuffer_t *ib)
{
if (!ib)
return;
if (ib->buffer)
free(ib->buffer);
free(ib);
}
static inline int
ibuf_usedcount(ibuffer_t *ib)
{
int l;
if (!ib)
return(0);
l = ib->widx - ib->ridx;
if (l<0)
l += ib->size;
return(l);
}
static inline int
ibuf_freecount(ibuffer_t *ib)
{
if (!ib)
return(0);
return(ib->size - ibuf_usedcount(ib));
}
static inline void
ibuf_memcpy_w(ibuffer_t *ib, void *data, int len)
{
unsigned char *p = data;
int frag;
frag = ib->size - ib->widx;
if (frag < len) {
memcpy(&ib->buffer[ib->widx], p, frag);
p += frag;
frag = len - frag;
ib->widx = 0;
} else
frag = len;
memcpy(&ib->buffer[ib->widx], p, frag);
ib->widx += frag;
ib->widx %= ib->size;
}
static inline void
ibuf_memcpy_r(void *data, ibuffer_t *ib, int len)
{
unsigned char *p = data;
int frag;
frag = ib->size - ib->ridx;
if (frag < len) {
memcpy(p, &ib->buffer[ib->ridx], frag);
p += frag;
frag = len - frag;
ib->ridx = 0;
} else
frag = len;
memcpy(p, &ib->buffer[ib->ridx], frag);
ib->ridx += frag;
ib->ridx %= ib->size;
}
#endif

36
include/isdn_debug.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef ISDN_DEBUG_H
#define ISDN_DEBUG_H
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#define DBGM_NET 0x00000001
#define DBGM_MSG 0x00000002
#define DBGM_FSM 0x00000004
#define DBGM_TEI 0x00000010
#define DBGM_L2 0x00000020
#define DBGM_L3 0x00000040
#define DBGM_L3DATA 0x00000080
#define DBGM_BC 0x00000100
#define DBGM_TONE 0x00000200
#define DBGM_BCDATA 0x00000400
#define DBGM_MAN 0x00001000
#define DBGM_APPL 0x00002000
#define DBGM_ISDN 0x00004000
#define DBGM_SOCK 0x00010000
#define DBGM_CONN 0x00020000
#define DBGM_CDATA 0x00040000
#define DBGM_DDATA 0x00080000
#define DBGM_SOUND 0x00100000
#define DBGM_SDATA 0x00200000
#define DBGM_TOPLEVEL 0x40000000
#define DBGM_ALL 0xffffffff
extern int dprint(unsigned int mask, const char *fmt, ...);
extern int eprint(const char *fmt, ...);
extern int wprint(const char *fmt, ...);
extern int debug_init(unsigned int, char *, char *, char *);
extern void debug_close(void);
extern int dhexprint(unsigned int, char *, unsigned char *, int);
#endif

187
include/isdn_msg.h Normal file
View File

@ -0,0 +1,187 @@
#ifndef ISDN_MSG_H
#define ISDN_MSG_H
#include <pthread.h>
#include <semaphore.h>
#define MAX_MSG_SIZE 2080
#define DEFAULT_HEADROOM 16
typedef struct _msg {
struct _msg *prev;
struct _msg *next;
struct _msg_queue *list;
int len;
int size;
unsigned char *head;
unsigned char *data;
unsigned char *tail;
unsigned char *end;
unsigned char __data[MAX_MSG_SIZE];
} msg_t;
typedef struct _msg_queue {
struct _msg *prev;
struct _msg *next;
pthread_mutex_t lock;
int len;
int maxlen;
} msg_queue_t;
extern void msg_init(void);
extern msg_t *alloc_msg(int);
extern void free_msg(msg_t *);
extern msg_queue_t *free_queue;
extern msg_t *msg_copy(msg_t *msg);
#define msg_clone(m) msg_copy(m)
static inline void
msg_queue_init(msg_queue_t *q)
{
pthread_mutex_init(&q->lock, NULL);
q->len = 0;
q->prev = (msg_t *)q;
q->next = (msg_t *)q;
}
static inline int msg_queue_len(msg_queue_t *list_)
{
return(list_->len);
}
static inline void msg_queue_head(msg_queue_t *list, msg_t *newm)
{
msg_t *prev, *next;
pthread_mutex_lock(&list->lock);
newm->list = list;
list->len++;
prev = (msg_t *)list;
next = prev->next;
newm->next = next;
newm->prev = prev;
next->prev = newm;
prev->next = newm;
pthread_mutex_unlock(&list->lock);
}
static inline void msg_queue_tail(msg_queue_t *list, msg_t *newm)
{
msg_t *prev, *next;
pthread_mutex_lock(&list->lock);
newm->list = list;
list->len++;
next = (msg_t *)list;
prev = next->prev;
newm->next = next;
newm->prev = prev;
next->prev = newm;
prev->next = newm;
pthread_mutex_unlock(&list->lock);
}
static inline msg_t *msg_dequeue(msg_queue_t *list)
{
msg_t *next, *prev, *result;
pthread_mutex_lock(&list->lock);
prev = (msg_t *) list;
next = prev->next;
result = NULL;
if (next != prev) {
result = next;
next = next->next;
list->len--;
next->prev = prev;
prev->next = next;
result->next = NULL;
result->prev = NULL;
result->list = NULL;
}
pthread_mutex_unlock(&list->lock);
return result;
}
static __inline__ void msg_queue_purge(msg_queue_t *list)
{
msg_t *msg;
while ((msg = msg_dequeue(list))!=NULL)
free_msg(msg);
}
static __inline__ unsigned char *msg_put(msg_t *msg, unsigned int len)
{
unsigned char *tmp=msg->tail;
msg->tail+=len;
msg->len+=len;
if(msg->tail>msg->end)
{
fprintf(stderr, "msg_over_panic msg(%p) data(%p) head(%p)\n",
msg, msg->data, msg->head);
return(NULL);
}
return tmp;
}
static __inline__ unsigned char *msg_push(msg_t *msg, unsigned int len)
{
msg->data-=len;
msg->len+=len;
if(msg->data < msg->head)
{
fprintf(stderr, "msg_under_panic msg(%p) data(%p) head(%p)\n",
msg, msg->data, msg->head);
return(NULL);
}
return msg->data;
}
static __inline__ char *__msg_pull(msg_t *msg, unsigned int len)
{
msg->len-=len;
return msg->data+=len;
}
static __inline__ unsigned char * msg_pull(msg_t *msg, unsigned int len)
{
if (len > msg->len)
return NULL;
return __msg_pull(msg,len);
}
static __inline__ int msg_headroom(msg_t *msg)
{
return msg->data-msg->head;
}
static __inline__ int msg_tailroom(msg_t *msg)
{
return msg->end-msg->tail;
}
static __inline__ void msg_reserve(msg_t *msg, unsigned int len)
{
msg->data+=len;
msg->tail+=len;
}
static __inline__ void __msg_trim(msg_t *msg, unsigned int len)
{
msg->len = len;
msg->tail = msg->data+len;
}
static __inline__ void msg_trim(msg_t *msg, unsigned int len)
{
if (msg->len > len) {
__msg_trim(msg, len);
}
}
#endif

296
include/isdn_net.h Normal file
View File

@ -0,0 +1,296 @@
#ifndef ISDN_NET_H
#define ISDN_NET_H
#include <stdlib.h>
#include <errno.h>
#include <pthread.h>
#include <semaphore.h>
#include "mISDNlib.h"
#include "isdn_msg.h"
#include "isdn_debug.h"
#include "ibuffer.h"
#define MSN_LEN 32
#define SUBADR_LEN 24
#define UUS_LEN 256
#define FAC_LEN 132
#ifndef mISDN_FRAME_MIN
#define mISDN_FRAME_MIN 8
#endif
typedef struct _layer2 layer2_t;
typedef struct _layer3 layer3_t;
typedef struct _layer4 layer4_t;
typedef struct _bchannel bchannel_t;
typedef struct _mISDNif mISDNif_t;
typedef struct _mISDNinstance mISDNinstance_t;
typedef struct _net_stack net_stack_t;
typedef struct _manager manager_t;
typedef struct _nr_list nr_list_t;
typedef int (*ifunc_t)(net_stack_t *, msg_t *);
typedef int (*bfunc_t)(void *, void *);
typedef int (*afunc_t)(manager_t *, int, void *);
#define MAX_BDATA_SIZE 2048
struct _bchannel {
sem_t work;
msg_queue_t workq;
pthread_t tid;
manager_t *manager;
void *app;
int channel;
pthread_mutex_t lock;
int cstate;
int bstate;
int l3id;
int b_addr;
int Flags;
int ttime;
nr_list_t *usednr;
int l1_prot;
unsigned char bc[8];
unsigned char uu[UUS_LEN];
unsigned char fac[FAC_LEN];
unsigned char nr[MSN_LEN];
unsigned char msn[MSN_LEN];
unsigned char clisub[SUBADR_LEN];
unsigned char cldsub[SUBADR_LEN];
int cause_loc;
int cause_val;
unsigned char display[84];
msg_t *smsg;
ibuffer_t *rbuf;
ibuffer_t *sbuf;
int rrid;
int rsid;
};
struct _manager {
manager_t *prev;
manager_t *next;
bchannel_t bc[2];
nr_list_t *nrlist;
net_stack_t *nst;
bfunc_t man2stack;
afunc_t application;
afunc_t app_bc;
pthread_t tid;
sem_t work;
msg_queue_t workq;
};
#define PR_APP_CHECK_NR 1
#define PR_APP_ICALL 2
#define PR_APP_OCHANNEL 3
#define PR_APP_OCALL 4
#define PR_APP_ALERT 5
#define PR_APP_CONNECT 6
#define PR_APP_HANGUP 7
#define PR_APP_CLEAR 8
#define PR_APP_USERUSER 9
#define PR_APP_FACILITY 10
#define PR_APP_OPEN_RECFILES 11
#define PR_APP_CLOSE_RECFILES 12
#define FLG_NST_READER_ABORT 1
#define FLG_NST_TERMINATION 2
struct _net_stack {
int device;
int cardnr;
int d_stid;
int l0_id;
int l1_id;
int l2_id;
msg_t *phd_down_msg;
layer2_t *layer2;
layer3_t *layer3;
ifunc_t l1_l2;
ifunc_t l2_l3;
ifunc_t l3_l2;
ifunc_t manager_l3;
bfunc_t l3_manager;
manager_t *manager;
msg_queue_t down_queue;
msg_queue_t rqueue;
msg_queue_t wqueue;
sem_t work;
pthread_mutex_t lock;
pthread_t reader;
int b_stid[2];
int b_addr[2];
int bcid[2];
int flag;
struct _itimer *tlist;
};
struct _nr_list {
nr_list_t *prev;
nr_list_t *next;
unsigned char len;
unsigned char nr[MSN_LEN];
unsigned char name[64];
int typ;
int flags;
};
#define NR_TYPE_INTERN 1
#define NR_TYPE_AUDIO 2
#define NR_TYPE_VOIP 3
typedef struct _itimer {
struct _itimer *prev;
struct _itimer *next;
net_stack_t *nst;
int id;
int expires;
int Flags;
unsigned long data;
int (*function)(unsigned long);
} itimer_t;
#define FLG_TIMER_RUNING 1
#define FLG_BC_USE 0x00000001
#define FLG_BC_SENT_CID 0x00000002
#define FLG_BC_CALL_ORGINATE 0x00000004
#define FLG_BC_PROGRESS 0x00000008
#define FLG_BC_APPLICATION 0x00000010
#define FLG_BC_TONE_DIAL 0x00000100
#define FLG_BC_TONE_BUSY 0x00000200
#define FLG_BC_TONE_ALERT 0x00000400
#define FLG_BC_TONE_SILENCE 0x00000800
#define FLG_BC_TONE_NONE 0x00000000
#define FLG_BC_TONE 0x00000F00
#define FLG_BC_RECORD 0x00010000
#define FLG_BC_RECORDING 0x00020000
#define FLG_BC_RAWDEVICE 0x01000000
#define FLG_BC_KEEP_SEND 0x02000000
#define FLG_BC_TERMINATE 0x08000000
#define MSG_L1_PRIM 0x010000
#define MSG_L2_PRIM 0x020000
#define MSG_L3_PRIM 0x030000
extern int do_net_stack_setup(net_stack_t *);
extern int do_net_stack_cleanup(net_stack_t *nst);
extern void *do_netthread(void *);
extern int term_netstack(net_stack_t *nst);
extern int init_manager(manager_t **mlist, afunc_t application);
extern int cleanup_manager(manager_t *mgr);
extern int write_dmsg(net_stack_t *, msg_t *);
extern int phd_conf(net_stack_t *, iframe_t *, msg_t *);
extern int init_timer(itimer_t *, net_stack_t *);
extern int add_timer(itimer_t *);
extern int del_timer(itimer_t *);
extern int remove_timer(itimer_t *it);
extern int timer_pending(itimer_t *);
extern u_char *findie(u_char *, int, u_char, int);
extern u_char *find_and_copy_ie(u_char *, int, u_char, int, msg_t *);
extern void display_NR_IE(u_char *, char *);
extern int match_nr(manager_t *mgr, unsigned char *nx, nr_list_t **nrx);
typedef struct _mISDN_head {
u_int prim;
int dinfo;
} mISDN_head_t;
#define mISDN_HEAD_SIZE sizeof(mISDN_head_t)
/* interface msg help routines */
static inline void mISDN_newhead(u_int prim, int dinfo, msg_t *msg)
{
mISDN_head_t *hh = (mISDN_head_t *)msg->data;
hh->prim = prim;
hh->dinfo = dinfo;
}
static inline int if_newhead(void *arg, ifunc_t func, u_int prim, int dinfo,
msg_t *msg)
{
if (!msg)
return(-ENXIO);
mISDN_newhead(prim, dinfo, msg);
return(func(arg, msg));
}
static inline void mISDN_addhead(u_int prim, int dinfo, msg_t *msg)
{
mISDN_head_t *hh = (mISDN_head_t *)msg_push(msg, mISDN_HEAD_SIZE);
hh->prim = prim;
hh->dinfo = dinfo;
}
static inline int if_addhead(void *arg, ifunc_t func, u_int prim, int dinfo,
msg_t *msg)
{
if (!msg)
return(-ENXIO);
mISDN_addhead(prim, dinfo, msg);
return(func(arg, msg));
}
static inline msg_t *create_link_msg(u_int prim, int dinfo,
int len, void *arg, int reserve)
{
msg_t *msg;
if (!(msg = alloc_msg(len + mISDN_HEAD_SIZE + reserve))) {
wprint("%s: no msg size %d+%d+%d\n", __FUNCTION__,
len, mISDN_HEAD_SIZE, reserve);
return(NULL);
} else
msg_reserve(msg, reserve + mISDN_HEAD_SIZE);
if (len)
memcpy(msg_put(msg, len), arg, len);
mISDN_addhead(prim, dinfo, msg);
return(msg);
}
static inline int if_link(void *farg, ifunc_t func, u_int prim, int dinfo, int len,
void *arg, int reserve)
{
msg_t *msg;
int err;
if (!(msg = create_link_msg(prim, dinfo, len, arg, reserve)))
return(-ENOMEM);
err = func(farg, msg);
if (err)
free_msg(msg);
return(err);
}
static inline msg_t *prep_l3data_msg(u_int prim, int dinfo, int ssize, int dsize, msg_t *old)
{
if (!old) {
old = alloc_msg(ssize + dsize + mISDN_HEAD_SIZE + DEFAULT_HEADROOM);
if (!old) {
wprint("%s: no msg size %d+%d+%d\n", __FUNCTION__,
ssize, dsize, mISDN_HEAD_SIZE + DEFAULT_HEADROOM);
return(NULL);
}
} else {
old->data = old->head + DEFAULT_HEADROOM;
old->tail = old->data;
old->len = 0;
}
memset(msg_put(old, ssize + mISDN_HEAD_SIZE), 0,
ssize + mISDN_HEAD_SIZE);
mISDN_newhead(prim, dinfo, old);
return(old);
}
#endif

24
include/isound.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef ISOUND_H
#define ISOUND_H
#include "ibuffer.h"
typedef struct _isound isound_t;
#define MAX_AUDIO_READ 2048
struct _isound {
ibuffer_t *sbuf;
ibuffer_t *rbuf;
int Flag;
int data;
unsigned char rtmp[MAX_AUDIO_READ];
unsigned char wtmp[MAX_AUDIO_READ];
int wlen;
int widx;
sem_t work;
pthread_t rd_t;
pthread_t wr_t;
};
#endif

173
include/l3dss1.h Normal file
View File

@ -0,0 +1,173 @@
/* $Id: l3dss1.h,v 0.9 2003/08/27 07:33:02 kkeil Exp $
*
* DSS1 (Euro) D-channel protocol defines
*
* This file is (c) under GNU PUBLIC LICENSE
*
*/
#ifndef l3dss1_process
#define T301 180000
#define T302 15000
#define T303 4000
#define T304 30000
#define T305 30000
#define T308 4000
/* for layer 1 certification T309 < layer1 T3 (e.g. 4000) */
/* This makes some tests easier and quicker */
#define T309 40000
#define T310 30000
#define T312 6000
#define T313 4000
#define T318 4000
#define T319 4000
#define N303 1
#define T_CTRL 180000
/* private TIMER events */
#define CC_TIMER 0x000001
#define CC_T301 0x030101
#define CC_T302 0x030201
#define CC_T303 0x030301
#define CC_T304 0x030401
#define CC_T305 0x030501
#define CC_T308 0x030801
#define CC_T309 0x030901
#define CC_T310 0x031001
#define CC_T312 0x031201
#define CC_T313 0x031301
#define CC_T318 0x031801
#define CC_T319 0x031901
#define CC_TCTRL 0x031f01
/*
* Message-Types
*/
#define MT_ALERTING 0x01
#define MT_CALL_PROCEEDING 0x02
#define MT_CONNECT 0x07
#define MT_CONNECT_ACKNOWLEDGE 0x0f
#define MT_PROGRESS 0x03
#define MT_SETUP 0x05
#define MT_SETUP_ACKNOWLEDGE 0x0d
#define MT_RESUME 0x26
#define MT_RESUME_ACKNOWLEDGE 0x2e
#define MT_RESUME_REJECT 0x22
#define MT_SUSPEND 0x25
#define MT_SUSPEND_ACKNOWLEDGE 0x2d
#define MT_SUSPEND_REJECT 0x21
#define MT_USER_INFORMATION 0x20
#define MT_DISCONNECT 0x45
#define MT_RELEASE 0x4d
#define MT_RELEASE_COMPLETE 0x5a
#define MT_RESTART 0x46
#define MT_RESTART_ACKNOWLEDGE 0x4e
#define MT_SEGMENT 0x60
#define MT_CONGESTION_CONTROL 0x79
#define MT_INFORMATION 0x7b
#define MT_FACILITY 0x62
#define MT_NOTIFY 0x6e
#define MT_STATUS 0x7d
#define MT_STATUS_ENQUIRY 0x75
#define IE_SEGMENT 0x00
#define IE_BEARER 0x04
#define IE_CAUSE 0x08
#define IE_CALL_ID 0x10
#define IE_CALL_STATE 0x14
#define IE_CHANNEL_ID 0x18
#define IE_FACILITY 0x1c
#define IE_PROGRESS 0x1e
#define IE_NET_FAC 0x20
#define IE_NOTIFY 0x27
#define IE_DISPLAY 0x28
#define IE_DATE 0x29
#define IE_KEYPAD 0x2c
#define IE_SIGNAL 0x34
#define IE_INFORATE 0x40
#define IE_E2E_TDELAY 0x42
#define IE_TDELAY_SEL 0x43
#define IE_PACK_BINPARA 0x44
#define IE_PACK_WINSIZE 0x45
#define IE_PACK_SIZE 0x46
#define IE_CUG 0x47
#define IE_REV_CHARGE 0x4a
#define IE_CONNECT_PN 0x4c
#define IE_CONNECT_SUB 0x4d
#define IE_CALLING_PN 0x6c
#define IE_CALLING_SUB 0x6d
#define IE_CALLED_PN 0x70
#define IE_CALLED_SUB 0x71
#define IE_REDIR_NR 0x74
#define IE_TRANS_SEL 0x78
#define IE_RESTART_IND 0x79
#define IE_LLC 0x7c
#define IE_HLC 0x7d
#define IE_USER_USER 0x7e
#define IE_ESCAPE 0x7f
#define IE_SHIFT 0x90
#define IE_MORE_DATA 0xa0
#define IE_COMPLETE 0xa1
#define IE_CONGESTION 0xb0
#define IE_REPEAT 0xd0
#define IE_MANDATORY 0x0100
/* mandatory not in every case */
#define IE_MANDATORY_1 0x0200
#define ERR_IE_COMPREHENSION 1
#define ERR_IE_UNRECOGNIZED -1
#define ERR_IE_LENGTH -2
#define ERR_IE_SEQUENCE -3
#define CAUSE_LOC_USER 0
#define CAUSE_LOC_PNET_LOCUSER 1
#define CAUSE_UNASSIGNED_NUMBER 1
#define CAUSE_NO_TRANSIT_ROUTE 2
#define CAUSE_NO_ROUTE 3
#define CAUSE_CHANNEL_UNACCEPT 6
#define CAUSE_NORMAL_CLEARING 16
#define CAUSE_USER_BUSY 17
#define CAUSE_NOUSER_RESPONDING 18
#define CAUSE_CALL_REJECTED 21
#define CAUSE_NONSELECTED_USER 26
#define CAUSE_INVALID_NUMBER 28
#define CAUSE_STATUS_RESPONSE 30
#define CAUSE_NORMALUNSPECIFIED 31
#define CAUSE_NO_CHANNEL 34
#define CAUSE_TEMPORARY_FAILURE 41
#define CAUSE_INVALID_CALLREF 81
#define CAUSE_INCOMPATIBLE_DEST 88
#define CAUSE_MANDATORY_IE_MISS 96
#define CAUSE_MT_NOTIMPLEMENTED 97
#define CAUSE_IE_NOTIMPLEMENTED 99
#define CAUSE_INVALID_CONTENTS 100
#define CAUSE_NOTCOMPAT_STATE 101
#define CAUSE_TIMER_EXPIRED 102
#define CAUSE_PROTOCOL_ERROR 111
#define NO_CAUSE 254
#define PROGRESS_TONE 8
#else /* only l3dss1_process */
/* l3dss1 specific data in l3 process */
typedef struct
{ unsigned char invoke_id; /* used invoke id in remote ops, 0 = not active */
ulong ll_id; /* remebered ll id */
u_char remote_operation; /* handled remote operation, 0 = not active */
int proc; /* rememered procedure */
ulong remote_result; /* result of remote operation for statcallb */
char uus1_data[35]; /* data send during alerting or disconnect */
} dss1_proc_priv;
/* l3dss1 specific data in protocol stack */
typedef struct
{ unsigned char last_invoke_id; /* last used value for invoking */
unsigned char invoke_used[32]; /* 256 bits for 256 values */
} dss1_stk_priv;
#endif /* only l3dss1_process */

402
include/mISDNlib.h Normal file
View File

@ -0,0 +1,402 @@
#ifndef _mISDN_LIB_H
#define _mISDN_LIB_H
/* API library to use with /dev/mISDN */
/* we need somme extentions */
#define _GNU_SOURCE
typedef unsigned short u16;
#include <sys/types.h>
#include <stdio.h>
#include <linux/mISDNif.h>
#define mISDN_INBUFFER_SIZE 0x20000
#define mISDN_HEADER_LEN 16
#define TIMEOUT_1SEC 1000000
#define TIMEOUT_10SEC 10000000
#define TIMEOUT_INFINIT -1
// extern void xxxxxxxxxx(void);
/* Prototypes from device.c */
/* mISDN_open(void)
*
* opens a mISDN device and allocate buffers for it
*
* parameter:
* none
*
* return:
* the file descriptor or -1 on error and the error cause in errno
*/
extern int mISDN_open(void);
/* mISDN_close(int fid)
*
* close the mISDN device and frees related memory.
*
* parameter:
* fid - file descriptor returned by mISDN_open
*
* return:
* 0 on success or -1 on error and the error cause in errno
*
*/
extern int mISDN_close(int fid);
/* mISDN_read(int fid, void *buf, size_t count, int utimeout)
*
* read one message from device or buffer
*
* parameter:
* fid - FILE descriptor returned by mISDN_open
* buf - pointer to readbuffer
* count - maximum length of read data
* utimeout - maximum time in microseconds to wait for data, if -1
* wait until some data is ready
*
* return:
* length of read data or -1 on error and the error cause in errno
*
*/
extern int mISDN_read(int fid, void *buf, size_t count, int utimeout);
/* mISDN_read_frame(int fid, void *buf, size_t count, u_int addr,
* u_int msgtype, int utimeout)
*
* read one message for address (addr) and message type (msgtype)
* from device or buffer
*
* parameter:
* fid - FILE descriptor returned by mISDN_open
* buf - pointer to readbuffer
* count - maximum length of read data
* addr - address of frame
* msgtype - message type of frame
* utimeout - maximum time in microseconds to wait for data, if -1
* wait until some data is ready
*
* return:
* length of read data or -1 on error and the error cause in errno
*
*/
extern int mISDN_read_frame(int fid, void *buf, size_t count, u_int addr,
u_int msgtype, int utimeout);
/* mISDN_write(int fid, void *buf, size_t count, int utimeout)
*
* write a message to device
*
* parameter:
* fid - FILE descriptor returned by mISDN_open
* buf - pointer to data to write
* count - length of data
* utimeout - maximum time in microseconds to wait for device ready to
* accept new data, if -1 wait until device is ready
*
* return:
* length of written data or -1 on error and the error cause in errno
*
*/
extern int mISDN_write(int fid, void *buf, size_t count, int utimeout);
/* mISDN_write_frame(int fid, void *fbuf, u_int addr, u_int msgtype,
* int dinfo, int dlen, void *dbuf, int utimeout)
*
* write a frame to device
*
* parameter:
* fid - FILE descriptor returned by mISDN_open
* fbuf - buffer for frame, caller has to provide a big enougth buffer
* count - length of data
* addr - address for frame
* msgtype - message type of frame
* dinfo - data info parameter
* dlen - len of dbuf data, if negativ it is an error code (dbuf len=0)
* dbuf - pointer to frame payload data
* utimeout - maximum time in microseconds to wait for device ready to
* accept new data, if -1 wait until device is ready
*
* return:
* 0 if successfull or -1 on error and the error cause in errno
*
*/
extern int mISDN_write_frame(int fid, void *fbuf, u_int addr, u_int msgtype,
int dinfo, int dlen, void *dbuf, int utimeout);
/* int mISDN_select(int n, fd_set *readfds, fd_set *writefds,
* fd_set *exceptfds, struct timeval *timeout)
*
* select call which handles mISDN readbuffer
*
* parameters and use see man select
*
*/
extern int mISDN_select(int n, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
/* Prototypes from stack.c */
/* mISDN_get_stack_count(int fid)
*
* get number of ISDN stacks
*
* parameter:
* fid - FILE descriptor returned by mISDN_open
*
* return:
* count of ISDN stacks, negativ values for error
*
*/
extern int mISDN_get_stack_count(int fid);
/* mISDN_get_stack_info(int fid, int stack, void *info, size_t max_len)
*
* get the info about ISDN stack
*
* parameter:
* fid - FILE descriptor returned by mISDN_open
* stack - ID of the stack
* info - buffer to store info
* max_len - size of above buffer
*
* return:
* length of stored info, negativ values are errors
*
*/
extern int mISDN_get_stack_info(int fid, int stack, void *info, size_t max_len);
/* mISDN_new_stack(int fid, stack_info_t *s_info)
*
* create a new stack
*
* parameter:
* fid - FILE descriptor returned by mISDN_open
* s_info - info for the new stack
*
* return:
* stack id or negativ error code
*
*/
extern int mISDN_new_stack(int fid, stack_info_t *s_info);
/* mISDN_set_stack(int fid, int stack, mISDN_pid_t *pid)
*
* setup a stack for the given protocol
*
* parameter:
* fid - FILE descriptor returned by mISDN_open
* stack - stack id
* pid - description of the stack protocol
*
* return:
* 0 on sucess other values are errors
*
*/
extern int mISDN_set_stack(int fid, int stack, mISDN_pid_t *pid);
/* mISDN_clear_stack(int fid, int stack)
*
* clear the protocol stack
*
* parameter:
* fid - FILE descriptor returned by mISDN_open
* stack - stack id
*
* return:
* 0 on sucess other values are errors
*
*/
extern int mISDN_clear_stack(int fid, int stack);
/* mISDNprint_stack_info(FILE *file, stack_info_t *s_info)
*
* print out the stack_info in readable output
*
* parameter:
* file - stream to print to
* s_info - stack_info
*
* return:
* nothing
*
*/
extern void mISDNprint_stack_info(FILE *file, stack_info_t *s_info);
/* Prototypes from layer.c */
/* mISDN_get_layerid(int fid, int stack, int layer)
*
* get the id of the layer given by stack and layer number
*
* parameter:
* fid - FILE descriptor returned by mISDN_open
* stack - ID of the stack
* layer - layer number
*
* return:
* layer id or negativ error code
*
*/
extern int mISDN_get_layerid(int fid, int stack, int layer);
/* mISDN_new_layer(int fid, layer_info_t *l_info)
*
* create a new layer
*
* parameter:
* fid - FILE descriptor returned by mISDN_open
* l_info - info for the layer
*
* return:
* layer id or negativ error code
*
*/
extern int mISDN_new_layer(int fid, layer_info_t *l_info);
/* mISDN_connect(int fid, interface_info_t *i_info)
*
* create a new connection
*
* parameter:
* fid - FILE descriptor returned by mISDN_open
* i_info - info for the connection
*
* return:
* 0 on success or error code
*
*/
extern int mISDN_connect(int fid, interface_info_t *i_info);
/* mISDN_get_layer_info(int fid, int lid, void *info, size_t max_len)
*
* get the info about ISDN layer
*
* parameter:
* fid - FILE descriptor returned by mISDN_open
* lid - ID of the layer
* info - buffer to store info
* max_len - size of above buffer
*
* return:
* length of stored info, negativ values are errors
*
*/
extern int mISDN_get_layer_info(int fid, int lid, void *info, size_t max_len);
/* mISDN_get_interface_info(int fid, interface_info_t *i_info)
*
* get the info about ISDN layer interface
*
* parameter:
* fid - FILE descriptor returned by mISDN_open
* i_info - contains the info about layer (i_info->owner) and
* which interface (i_info->stat) and gives requested info back
*
* return:
* 0 on sucess other values are errors
*
*/
extern int mISDN_get_interface_info(int fid, interface_info_t *i_info);
/* Prototypes and defines for status.c */
/* l1 status_info */
typedef struct _status_info_l1 {
int len;
int typ;
int protocol;
int status;
int state;
int Flags;
int T3;
int delay;
int debug;
} status_info_l1_t;
/* State values for l1 state machine (status_info_l1_t state field) */
extern char *strL1SState[];
/* l2 status_info */
typedef struct _laddr {
u_char A;
u_char B;
} laddr_t;
typedef struct _status_info_l2 {
int len;
int typ;
int protocol;
int state;
int sapi;
int tei;
laddr_t addr;
int maxlen;
u_int flag;
u_int vs;
u_int va;
u_int vr;
int rc;
u_int window;
u_int sow;
int T200;
int N200;
int T203;
int len_i_queue;
int len_ui_queue;
int len_d_queue;
int debug;
int tei_state;
int tei_ri;
int T202;
int N202;
int tei_debug;
} status_info_l2_t;
/* State values for l2 state machine (status_info_l2_t state field) */
extern char *strL2State[];
/* mISDN_get_status_info(int fid, int id, void *info, size_t max_len)
*
* get status infos about layer instances in the ISDN stack
*
* parameter:
* fid - FILE descriptor returned by mISDN_open
* id - ID of the instance
* info - buffer to store info
* max_len - size of above buffer
*
* return:
* length of stored info, negativ values are errors
*
*/
extern int mISDN_get_status_info(int fid, int id, void *info, size_t max_len);
/* mISDNprint_status(FILE *file, status_info_t *si)
*
* print out the status in readable output
*
* parameter:
* file - stream to print to
* s_info - status_info
*
* return:
* 0 on success or -1 if no known status_info
*
*/
extern int mISDNprint_status(FILE *file, status_info_t *si);
/* private functions */
extern int set_wrrd_atomic(int fid);
extern int clear_wrrd_atomic(int fid);
#endif

29
include/tone.h Normal file
View File

@ -0,0 +1,29 @@
#ifndef TONE_H
#define TONE_H
/*
* These are 10 periods of the 425 Hz tone used by most inband signals
* Its actually not exacly 425 Hz, but 416,66667, which fit very well
* the 15% tolerance
*/
#define TONE_425_SIZE 192
extern const unsigned char tone_425[TONE_425_SIZE];
/*
* These are 10 ms of silence
*/
#define TONE_SILENCE_SIZE 80
extern const unsigned char tone_SILENCE[TONE_SILENCE_SIZE];
/* Values for tone pattern */
#define TONE_ALERT_SILENCE_TIME 4000000
#define TONE_ALERT_TIME 1000000
#define TONE_BUSY_SILENCE_TIME 500000
#define TONE_BUSY_TIME 500000
extern int tone_handler(bchannel_t *bc);
extern int set_tone(bchannel_t *bc, int tone);
#endif

19
lib/Makefile Normal file
View File

@ -0,0 +1,19 @@
all: libmISDN.a
libmISDN.a: device.o layer.o stack.o status.o
rm -f $@
ar -r $@ $^
ar -s $@
device.o : device.c ../include/mISDNlib.h
layer.o : layer.c ../include/mISDNlib.h
stack.o : stack.c ../include/mISDNlib.h
status.o : status.c ../include/mISDNlib.h
clean:
rm -f *.o *~ DEADJOE
distclean: clean
rm -f *.a

684
lib/device.c Normal file
View File

@ -0,0 +1,684 @@
#include "mISDNlib.h"
#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 <pthread.h>
/* API library to use with /dev/mISDN */
typedef struct _mISDNdev {
struct _mISDNdev *prev;
struct _mISDNdev *next;
pthread_mutex_t rmutex;
pthread_mutex_t wmutex;
int Flags;
int fid;
int isize;
unsigned char *inbuf;
unsigned char *irp;
unsigned char *iend;
} mISDNdev_t;
#define FLG_mISDN_WRRD_ATOMIC 1
mISDNdev_t *devlist = NULL;
static pthread_mutex_t devlist_lock = PTHREAD_MUTEX_INITIALIZER;
#define mISDN_DEVICE "/dev/mISDN"
#if 0
void
xxxxxxxxxx(void) {
if (devlist)
fprintf(stderr, "xxxxxxxxxx dev %p prev %p next %p\n", devlist, devlist->prev, devlist->next);
else
fprintf(stderr, "xxxxxxxxxx devlist %p\n", devlist);
}
#endif
int
mISDN_open(void)
{
int fid;
mISDNdev_t *dev;
if (0>(fid = open(mISDN_DEVICE, O_RDWR | O_NONBLOCK)))
return(fid);
pthread_mutex_lock(&devlist_lock);
dev = devlist;
while(dev) {
if (dev->fid==fid)
break;
dev = dev->next;
}
pthread_mutex_unlock(&devlist_lock);
if (dev) {
fprintf(stderr, "%s: device %d (%p) has allready fid(%d)\n",
__FUNCTION__, dev->fid, dev, fid);
close(fid);
errno = EBUSY;
return(-1);
}
dev = malloc(sizeof(mISDNdev_t));
if (!dev) {
close(fid);
errno = ENOMEM;
return(-1);
}
memset(dev, 0, sizeof(mISDNdev_t));
dev->fid = fid;
dev->isize = mISDN_INBUFFER_SIZE;
dev->inbuf = malloc(dev->isize);
if (!dev->inbuf) {
free(dev);
close(fid);
errno = ENOMEM;
return(-1);
}
dev->irp = dev->inbuf;
dev->iend = dev->inbuf;
pthread_mutex_init(&dev->rmutex, NULL);
pthread_mutex_init(&dev->wmutex, NULL);
pthread_mutex_lock(&devlist_lock);
dev->prev = devlist;
while(dev->prev && dev->prev->next)
dev->prev = dev->prev->next;
if (devlist)
dev->prev->next = dev;
else
devlist = dev;
pthread_mutex_unlock(&devlist_lock);
return(fid);
}
int
mISDN_close(int fid)
{
mISDNdev_t *dev = devlist;
int ret;
pthread_mutex_lock(&devlist_lock);
while(dev) {
if (dev->fid==fid)
break;
dev = dev->next;
}
if (!dev) {
pthread_mutex_unlock(&devlist_lock);
errno = ENODEV;
return(-1);
}
if (dev->prev)
dev->prev->next = dev->next;
if (dev->next)
dev->next->prev = dev->prev;
if (devlist==dev)
devlist=dev->next;
pthread_mutex_lock(&dev->rmutex);
if (dev->inbuf)
free(dev->inbuf);
dev->inbuf = NULL;
pthread_mutex_unlock(&dev->rmutex);
ret = pthread_mutex_destroy(&dev->rmutex);
if (ret)
fprintf(stderr, "%s: rmutex destroy returns %d\n",
__FUNCTION__, ret);
pthread_mutex_lock(&dev->wmutex);
pthread_mutex_unlock(&dev->wmutex);
ret = pthread_mutex_destroy(&dev->wmutex);
if (ret)
fprintf(stderr, "%s: wmutex destroy returns %d\n",
__FUNCTION__, ret);
pthread_mutex_unlock(&devlist_lock);
free(dev);
return(close(fid));
}
static int
mISDN_remove_iframe(mISDNdev_t *dev, iframe_t *frm)
{
u_char *ep;
int len;
if (frm->len > 0)
len = mISDN_HEADER_LEN + frm->len;
else
len = mISDN_HEADER_LEN;
ep = (u_char *)frm;
ep += len;
if (ep >= dev->iend)
dev->iend = (u_char *)frm;
else {
memcpy(frm, ep, dev->iend - ep);
dev->iend -= len;
}
return(dev->iend - dev->irp);
}
int
mISDN_read(int fid, void *buf, size_t count, int utimeout) {
mISDNdev_t *dev;
int ret = 0, len, sel;
fd_set in;
iframe_t *ifr;
struct timeval tout;
#ifdef MUTEX_TIMELOCK
struct timespec ts;
#endif
pthread_mutex_lock(&devlist_lock);
dev = devlist;
while(dev) {
if (dev->fid==fid)
break;
dev = dev->next;
}
pthread_mutex_unlock(&devlist_lock);
if (!dev) {
errno = ENODEV;
return(-1);
}
if (utimeout != -1) {
tout.tv_sec = utimeout/1000000;
tout.tv_usec = utimeout%1000000;
#ifdef MUTEX_TIMELOCK
if (utimeout == 0) {
ret = pthread_mutex_trylock(&dev->rmutex);
if (ret) {
fprintf(stderr, "%s: mutex_trylock (%d)\n",
__FUNCTION__, ret);
errno = ret;
return(-1);
}
} else {
#ifdef CLOCK_REALTIME
clock_gettime(CLOCK_REALTIME, &ts);
#else
{
struct timeval tv;
struct timezone tz;
gettimeofday(&tv,&tz);
TIMEVAL_TO_TIMESPEC(&tv,&ts);
}
#endif
ts.tv_sec += tout.tv_sec;
ts.tv_nsec += 1000*tout.tv_usec;
if (ts.tv_nsec > 1000000000L) {
ts.tv_sec++;
ts.tv_nsec -= 1000000000L;
}
ret = pthread_mutex_timedlock(&dev->rmutex, &ts);
if (ret) {
fprintf(stderr, "%s: mutex_timedlock (%d)\n",
__FUNCTION__, ret);
errno = ret;
return(-1);
}
}
#else
pthread_mutex_lock(&dev->rmutex);
#endif
} else
pthread_mutex_lock(&dev->rmutex);
if (dev->Flags & FLG_mISDN_WRRD_ATOMIC) {
// fprintf(stderr, "%s: WRRD_ATOMIC try again\n", __FUNCTION__);
errno = EAGAIN;
ret = -1;
goto out;
}
len = dev->iend - dev->irp;
if (!len) {
dev->irp = dev->iend = dev->inbuf;
pthread_mutex_unlock(&dev->rmutex);
FD_ZERO(&in);
FD_SET(fid, &in);
if (utimeout != -1) {
sel = select(fid + 1, &in, NULL, NULL, &tout);
} else
sel = select(fid + 1, &in, NULL, NULL, NULL);
if (sel<0) {
// fprintf(stderr, "%s: select err(%d)\n", __FUNCTION__, errno);
return(sel);
} else if (sel==0) {
// fprintf(stderr, "%s: select timed out\n", __FUNCTION__);
return(0);
}
if (FD_ISSET(fid, &in)) {
#ifdef MUTEX_TIMELOCK
if (!utimeout) {
ret = pthread_mutex_trylock(&dev->rmutex);
if (ret) {
fprintf(stderr, "%s: mutex_trylock (%d)\n",
__FUNCTION__, ret);
errno = ret;
return(-1);
}
} else
#endif
pthread_mutex_lock(&dev->rmutex);
len = dev->isize - (dev->iend - dev->irp);
if (len<=0) {
errno = ENOSPC;
ret = -1;
goto out;
}
if (dev->Flags & FLG_mISDN_WRRD_ATOMIC) {
// fprintf(stderr, "%s: WRRD_ATOMIC try again\n", __FUNCTION__);
errno = EAGAIN;
ret = -1;
goto out;
}
len = read(fid, dev->iend, len);
// fprintf(stderr, "%s: read %d\n", __FUNCTION__, len);
if (len <= 0) {
ret = len;
goto out;
}
dev->iend += len;
len = dev->iend - dev->irp;
} else {
return(0);
}
}
if (len < mISDN_HEADER_LEN) {
dev->iend = dev->irp;
fprintf(stderr, "%s: frame too short:%d\n",
__FUNCTION__, len);
errno = EINVAL;
ret = -1;
goto out;
}
ifr = (iframe_t *)dev->irp;
if (ifr->len > 0) {
if ((ifr->len + mISDN_HEADER_LEN) > len) {
dev->iend = dev->irp;
errno = EINVAL;
ret = -1;
goto out;
}
len = ifr->len + mISDN_HEADER_LEN;
} else
len = mISDN_HEADER_LEN;
if (len>count) {
errno = ENOSPC;
ret = -1;
goto out;
}
memcpy(buf, dev->irp, len);
dev->irp += len;
ret = len;
out:
pthread_mutex_unlock(&dev->rmutex);
return(ret);
}
static iframe_t *
mISDN_find_iframe(mISDNdev_t *dev, u_int addr, u_int prim) {
iframe_t *frm;
u_char *rp;
rp = dev->irp;
while(rp<dev->iend) {
if ((dev->iend - rp) < mISDN_HEADER_LEN) {
return(NULL);
}
frm = (iframe_t *)rp;
if ((frm->addr == addr) && (frm->prim == prim))
return(frm);
if (frm->len > 0)
rp += mISDN_HEADER_LEN + frm->len;
else
rp += mISDN_HEADER_LEN;
}
return(NULL);
}
int
mISDN_read_frame(int fid, void *buf, size_t count, u_int addr, u_int msgtype,
int utimeout)
{
mISDNdev_t *dev;
int len, sel, first, ret = 0;
fd_set in;
iframe_t *ifr;
struct timeval tout;
#ifdef MUTEX_TIMELOCK
struct timespec ts;
#endif
pthread_mutex_lock(&devlist_lock);
dev = devlist;
while(dev) {
if (dev->fid==fid)
break;
dev = dev->next;
}
pthread_mutex_unlock(&devlist_lock);
if (!dev) {
errno = ENODEV;
return(-1);
}
if (utimeout != -1) {
tout.tv_sec = utimeout/1000000;
tout.tv_usec = utimeout%1000000;
#ifdef MUTEX_TIMELOCK
if (utimeout == 0) {
ret = pthread_mutex_trylock(&dev->rmutex);
if (ret) {
fprintf(stderr, "%s: mutex_trylock (%d)\n",
__FUNCTION__, ret);
errno = ret;
return(-1);
}
} else {
#ifdef CLOCK_REALTIME
clock_gettime(CLOCK_REALTIME, &ts);
#else
{
struct timeval tv;
struct timezone tz;
gettimeofday(&tv,&tz);
TIMEVAL_TO_TIMESPEC(&tv,&ts);
}
#endif
ts.tv_sec += tout.tv_sec;
ts.tv_nsec += 1000*tout.tv_usec;
if (ts.tv_nsec > 1000000000L) {
ts.tv_sec++;
ts.tv_nsec -= 1000000000L;
}
ret = pthread_mutex_timedlock(&dev->rmutex, &ts);
if (ret) {
fprintf(stderr, "%s: mutex_timedlock (%d)\n",
__FUNCTION__, ret);
errno = ret;
return(-1);
}
}
#else
pthread_mutex_lock(&dev->rmutex);
#endif
} else
pthread_mutex_lock(&dev->rmutex);
first = 1;
while((utimeout == -1) || tout.tv_sec || tout.tv_usec || first) {
if (!first || !(dev->iend - dev->irp)) {
FD_ZERO(&in);
FD_SET(fid, &in);
if (utimeout != -1)
sel = select(fid + 1, &in, NULL, NULL, &tout);
else
sel = select(fid + 1, &in, NULL, NULL, NULL);
if (sel<0) {
// fprintf(stderr, "%s: select err(%d)\n", __FUNCTION__, errno);
ret = sel;
goto out;
} else if (sel==0) {
// fprintf(stderr, "%s: select timed out\n", __FUNCTION__);
ret = 0;
goto out;
}
if (FD_ISSET(fid, &in)) {
len = dev->isize - (dev->iend - dev->irp);
if (len<=0) {
errno = ENOSPC;
ret = -1;
goto out;
}
len = read(fid, dev->iend, len);
// fprintf(stderr, "%s: read %d\n", __FUNCTION__, len);
if (len <= 0) {
ret = len;
goto out;
}
dev->iend += len;
} else
continue;
}
if (dev->iend - dev->irp) {
ifr = mISDN_find_iframe(dev, addr, msgtype);
if (ifr) {
if (ifr->len > 0) {
#if 0
if ((ifr->len + mISDN_HEADER_LEN) > len) {
dev->irp = dev->iend;
errno = EINVAL;
ret = -1;
goto out;
}
#endif
len = ifr->len + mISDN_HEADER_LEN;
} else
len = mISDN_HEADER_LEN;
if (len > count) {
errno = ENOSPC;
ret = -1;
goto out;
}
memcpy(buf, ifr, len);
mISDN_remove_iframe(dev, ifr);
ret = len;
goto out;
}
}
first = 0;
}
out:
pthread_mutex_unlock(&dev->rmutex);
return(ret);
}
int
mISDN_write(int fid, void *buf, size_t count, int utimeout) {
mISDNdev_t *dev;
int len, sel;
fd_set out;
struct timeval tout;
#ifdef MUTEX_TIMELOCK
struct timespec ts;
int ret;
#endif
pthread_mutex_lock(&devlist_lock);
dev = devlist;
while(dev) {
if (dev->fid==fid)
break;
dev = dev->next;
}
pthread_mutex_unlock(&devlist_lock);
if (!dev) {
errno = ENODEV;
return(-1);
}
FD_ZERO(&out);
FD_SET(fid, &out);
if (utimeout != -1) {
tout.tv_sec = utimeout/1000000;
tout.tv_usec = utimeout%1000000;
sel = select(fid + 1, NULL, &out, NULL, &tout);
} else
sel = select(fid + 1, NULL, &out, NULL, NULL);
if (sel<=0)
return(sel);
if (!FD_ISSET(fid, &out))
return(0);
if (utimeout != -1) {
#ifdef MUTEX_TIMELOCK
if (utimeout == 0) {
ret = pthread_mutex_trylock(&dev->wmutex);
if (ret) {
fprintf(stderr, "%s: mutex_trylock (%d)\n",
__FUNCTION__, ret);
errno = ret;
return(-1);
}
} else {
#ifdef CLOCK_REALTIME
clock_gettime(CLOCK_REALTIME, &ts);
#else
{
struct timeval tv;
struct timezone tz;
gettimeofday(&tv,&tz);
TIMEVAL_TO_TIMESPEC(&tv,&ts);
}
#endif
ts.tv_sec += tout.tv_sec;
ts.tv_nsec += 1000*tout.tv_usec;
if (ts.tv_nsec > 1000000000L) {
ts.tv_sec++;
ts.tv_nsec -= 1000000000L;
}
ret = pthread_mutex_timedlock(&dev->wmutex, &ts);
if (ret) {
fprintf(stderr, "%s: mutex_timedlock (%d)\n",
__FUNCTION__, ret);
errno = ret;
return(-1);
}
}
#else
pthread_mutex_lock(&dev->wmutex);
#endif
} else
pthread_mutex_lock(&dev->wmutex);
len = write(fid, buf, count);
pthread_mutex_unlock(&dev->wmutex);
return(len);
}
int
mISDN_write_frame(int fid, void *fbuf, u_int addr, u_int msgtype,
int dinfo, int dlen, void *dbuf, int utimeout)
{
iframe_t *ifr = fbuf;
int len = mISDN_HEADER_LEN;
int ret;
if (!fbuf) {
errno = EINVAL;
return(-1);
}
if ((dlen > 0) && !dbuf) {
errno = EINVAL;
return(-1);
}
ifr->addr = addr;
ifr->prim = msgtype;
ifr->dinfo= dinfo;
ifr->len = dlen;
if (dlen>0) {
len += dlen;
memcpy(&ifr->data.i, dbuf, dlen);
}
ret = mISDN_write(fid, ifr, len, utimeout);
if (ret == len)
ret = 0;
else if (ret>=0) {
errno = ENOSPC;
ret = -1;
}
return(ret);
}
int
mISDN_select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
struct timeval *timeout)
{
mISDNdev_t *dev = devlist;
if (readfds) {
pthread_mutex_lock(&devlist_lock);
while(dev) {
if (FD_ISSET(dev->fid, readfds)) {
if (dev->iend - dev->irp) {
pthread_mutex_unlock(&devlist_lock);
FD_ZERO(readfds);
FD_SET(dev->fid, readfds);
if (writefds)
FD_ZERO(writefds);
if (exceptfds)
FD_ZERO(exceptfds);
return(1);
}
}
dev = dev->next;
}
pthread_mutex_unlock(&devlist_lock);
}
return(select(n, readfds, writefds, exceptfds, timeout));
}
int
set_wrrd_atomic(int fid)
{
mISDNdev_t *dev;
int ret;
pthread_mutex_lock(&devlist_lock);
dev = devlist;
while(dev) {
if (dev->fid==fid)
break;
dev = dev->next;
}
pthread_mutex_unlock(&devlist_lock);
if (!dev) {
return(-1);
}
pthread_mutex_lock(&dev->rmutex);
if (dev->Flags & FLG_mISDN_WRRD_ATOMIC)
ret = 1;
else {
ret = 0;
dev->Flags |= FLG_mISDN_WRRD_ATOMIC;
}
pthread_mutex_unlock(&dev->rmutex);
return(ret);
}
int
clear_wrrd_atomic(int fid)
{
mISDNdev_t *dev;
int ret;
pthread_mutex_lock(&devlist_lock);
dev = devlist;
while(dev) {
if (dev->fid==fid)
break;
dev = dev->next;
}
pthread_mutex_unlock(&devlist_lock);
if (!dev) {
return(-1);
}
if (dev->Flags & FLG_mISDN_WRRD_ATOMIC) {
dev->Flags &= ~FLG_mISDN_WRRD_ATOMIC;
ret = 0;
} else {
ret = 1;
}
return(ret);
}

138
lib/layer.c Normal file
View File

@ -0,0 +1,138 @@
#include <errno.h>
#include <string.h>
#include "mISDNlib.h"
int
mISDN_get_layerid(int fid, int stack, int layer)
{
iframe_t ifr;
int ret;
set_wrrd_atomic(fid);
ret = mISDN_write_frame(fid, &ifr, stack, MGR_GETLAYERID | REQUEST,
layer, 0, NULL, TIMEOUT_1SEC);
if (ret) {
clear_wrrd_atomic(fid);
return(ret);
}
ret = mISDN_read_frame(fid, &ifr, sizeof(iframe_t),
stack, MGR_GETLAYERID | CONFIRM, TIMEOUT_1SEC);
clear_wrrd_atomic(fid);
if (ret != mISDN_HEADER_LEN) {
if (ret>0)
ret = -EINVAL;
} else {
if (ifr.len)
ret = ifr.len;
else
ret = ifr.dinfo;
}
return(ret);
}
int
mISDN_new_layer(int fid, layer_info_t *l_info)
{
unsigned char buf[sizeof(layer_info_t) + mISDN_HEADER_LEN];
iframe_t *ifr = (iframe_t *)buf;
int ret;
set_wrrd_atomic(fid);
ret = mISDN_write_frame(fid, buf, 0, MGR_NEWLAYER | REQUEST,
0, sizeof(layer_info_t), l_info, TIMEOUT_1SEC);
// fprintf(stderr, "%s: wret %d\n", __FUNCTION__, ret);
if (ret) {
clear_wrrd_atomic(fid);
return(ret);
}
ret = mISDN_read_frame(fid, ifr, sizeof(layer_info_t) + mISDN_HEADER_LEN,
0, MGR_NEWLAYER | CONFIRM, TIMEOUT_1SEC);
clear_wrrd_atomic(fid);
// fprintf(stderr, "%s: rret %d\n", __FUNCTION__, ret);
if (ret<0)
return(ret);
if (ret < (mISDN_HEADER_LEN + sizeof(int))) {
if (ret == mISDN_HEADER_LEN)
ret = ifr->len;
else if (ret>0)
ret = -EINVAL;
} else
ret = ifr->data.i;
// fprintf(stderr, "%s: ret %x\n", __FUNCTION__, ret);
return(ret);
}
int
mISDN_connect(int fid, interface_info_t *i_info)
{
unsigned char buf[sizeof(interface_info_t) + mISDN_HEADER_LEN];
iframe_t ifr;
int ret;
set_wrrd_atomic(fid);
ret = mISDN_write_frame(fid, buf, 0, MGR_CONNECT | REQUEST,
0, sizeof(interface_info_t), i_info, TIMEOUT_1SEC);
if (ret) {
clear_wrrd_atomic(fid);
return(ret);
}
ret = mISDN_read_frame(fid, &ifr, sizeof(iframe_t),
0, MGR_CONNECT | CONFIRM, TIMEOUT_1SEC);
clear_wrrd_atomic(fid);
if (ret != mISDN_HEADER_LEN) {
if (ret > 0)
ret = -1;
} else {
if (ifr.len)
ret = ifr.len;
else
ret = ifr.data.i;
}
return(ret);
}
int
mISDN_get_layer_info(int fid, int lid, void *info, size_t max_len)
{
iframe_t ifr;
int ret;
set_wrrd_atomic(fid);
ret = mISDN_write_frame(fid, &ifr, lid, MGR_GETLAYER | REQUEST,
0, 0, NULL, TIMEOUT_1SEC);
if (ret) {
clear_wrrd_atomic(fid);
return(ret);
}
ret = mISDN_read_frame(fid, info, max_len,
lid, MGR_GETLAYER | CONFIRM, TIMEOUT_1SEC);
clear_wrrd_atomic(fid);
return(ret);
}
int
mISDN_get_interface_info(int fid, interface_info_t *i_info)
{
unsigned char buf[sizeof(interface_info_t) + mISDN_HEADER_LEN];
iframe_t *ifr = (iframe_t *)buf;
int ret;
set_wrrd_atomic(fid);
ret = mISDN_write_frame(fid, ifr, i_info->owner, MGR_GETIF | REQUEST,
i_info->stat, 0, NULL, TIMEOUT_1SEC);
if (ret) {
clear_wrrd_atomic(fid);
return(ret);
}
ret = mISDN_read_frame(fid, ifr, sizeof(interface_info_t) + mISDN_HEADER_LEN,
i_info->owner, MGR_GETIF | CONFIRM, TIMEOUT_1SEC);
clear_wrrd_atomic(fid);
if (ret==mISDN_HEADER_LEN) {
ret = ifr->data.i;
} else if (ret == (sizeof(interface_info_t) + mISDN_HEADER_LEN)) {
ret = 0;
memcpy(i_info, &ifr->data.p, sizeof(interface_info_t));
}
return(ret);
}

141
lib/stack.c Normal file
View File

@ -0,0 +1,141 @@
#include <errno.h>
#include <string.h>
#include "mISDNlib.h"
// #include <stdio.h>
int
mISDN_get_stack_count(int fid)
{
iframe_t ifr;
int ret;
set_wrrd_atomic(fid);
ret = mISDN_write_frame(fid, &ifr, 0, MGR_GETSTACK | REQUEST,
0, 0, NULL, TIMEOUT_1SEC);
if (ret) {
clear_wrrd_atomic(fid);
return(ret);
}
ret = mISDN_read_frame(fid, &ifr, sizeof(iframe_t), 0,
MGR_GETSTACK | CONFIRM, TIMEOUT_1SEC);
clear_wrrd_atomic(fid);
if (ret != mISDN_HEADER_LEN) {
if (ret > 0)
ret = -EINVAL;
} else {
if (ifr.len)
ret = ifr.len;
else
ret = ifr.dinfo;
}
return(ret);
}
int
mISDN_new_stack(int fid, stack_info_t *s_info)
{
u_char buf[sizeof(stack_info_t) + mISDN_HEADER_LEN];
iframe_t ifr;
int ret;
set_wrrd_atomic(fid);
ret = mISDN_write_frame(fid, buf, 0, MGR_NEWSTACK | REQUEST,
0, sizeof(stack_info_t), s_info, TIMEOUT_1SEC);
if (ret) {
clear_wrrd_atomic(fid);
return(ret);
}
ret = mISDN_read_frame(fid, &ifr, sizeof(iframe_t), 0,
MGR_NEWSTACK | CONFIRM, TIMEOUT_1SEC);
clear_wrrd_atomic(fid);
if (ret == mISDN_HEADER_LEN) {
if (ifr.len)
ret = ifr.len;
else
ret = ifr.dinfo;
}
return(ret);
}
int
mISDN_set_stack(int fid, int stack, mISDN_pid_t *pid)
{
u_char buf[sizeof(mISDN_pid_t) + mISDN_HEADER_LEN];
iframe_t ifr;
int ret;
set_wrrd_atomic(fid);
ret = mISDN_write_frame(fid, buf, stack, MGR_SETSTACK | REQUEST,
0, sizeof(mISDN_pid_t), pid, TIMEOUT_1SEC);
if (ret) {
clear_wrrd_atomic(fid);
return(ret);
}
ret = mISDN_read_frame(fid, &ifr, sizeof(iframe_t),
stack, MGR_SETSTACK | CONFIRM, TIMEOUT_1SEC);
clear_wrrd_atomic(fid);
if (ret == mISDN_HEADER_LEN)
ret = ifr.len;
else if (ret>0)
ret = -EINVAL;
return(ret);
}
int
mISDN_clear_stack(int fid, int stack)
{
iframe_t ifr;
int ret;
set_wrrd_atomic(fid);
ret = mISDN_write_frame(fid, &ifr, stack, MGR_CLEARSTACK | REQUEST,
0, 0, NULL, TIMEOUT_1SEC);
if (ret) {
clear_wrrd_atomic(fid);
return(ret);
}
ret = mISDN_read_frame(fid, &ifr, sizeof(iframe_t),
stack, MGR_CLEARSTACK | CONFIRM, TIMEOUT_1SEC);
clear_wrrd_atomic(fid);
if (ret == mISDN_HEADER_LEN)
ret = ifr.len;
else if (ret>0)
ret = -EINVAL;
return(ret);
}
int
mISDN_get_stack_info(int fid, int stack, void *info, size_t max_len)
{
iframe_t ifr;
int ret;
set_wrrd_atomic(fid);
ret = mISDN_write_frame(fid, &ifr, stack, MGR_GETSTACK | REQUEST,
0, 0, NULL, TIMEOUT_1SEC);
if (ret) {
clear_wrrd_atomic(fid);
return(ret);
}
ret = mISDN_read_frame(fid, info, max_len,
stack, MGR_GETSTACK | CONFIRM, TIMEOUT_1SEC);
clear_wrrd_atomic(fid);
return(ret);
}
void
mISDNprint_stack_info(FILE *file, stack_info_t *s_info)
{
int i;
fprintf(file, "stack id %08x\n", s_info->id);
fprintf(file, " ext %08x\n", s_info->extentions);
for(i=0;i<=MAX_LAYER_NR;i++)
fprintf(file, " prot%d %08x\n", i, s_info->pid.protocol[i]);
for(i=0;i<s_info->instcnt;i++)
fprintf(file, " inst%d %08x\n", i, s_info->inst[i]);
fprintf(file, " mgr %08x\n", s_info->mgr);
for(i=0;i<s_info->childcnt;i++)
fprintf(file, " child%d %08x\n", i, s_info->child[i]);
}

79
lib/status.c Normal file
View File

@ -0,0 +1,79 @@
#include <errno.h>
#include <string.h>
#include "mISDNlib.h"
/* State values for l1 state machine (status_info_l1_t state field) */
char *strL1SState[] =
{
"ST_L1_F2",
"ST_L1_F3",
"ST_L1_F4",
"ST_L1_F5",
"ST_L1_F6",
"ST_L1_F7",
"ST_L1_F8",
};
/* State values for l2 state machine (status_info_l2_t state field) */
char *strL2State[] =
{
"ST_L2_1",
"ST_L2_2",
"ST_L2_3",
"ST_L2_4",
"ST_L2_5",
"ST_L2_6",
"ST_L2_7",
"ST_L2_8",
};
int
mISDN_get_status_info(int fid, int id, void *info, size_t max_len)
{
iframe_t ifr;
int ret;
set_wrrd_atomic(fid);
ret = mISDN_write_frame(fid, &ifr, id, MGR_STATUS | REQUEST,
0, 0, NULL, TIMEOUT_1SEC);
if (ret) {
clear_wrrd_atomic(fid);
return(ret);
}
ret = mISDN_read_frame(fid, info, max_len,
id, MGR_STATUS | CONFIRM, TIMEOUT_1SEC);
clear_wrrd_atomic(fid);
return(ret);
}
/* not complete now */
int
mISDNprint_status(FILE *file, status_info_t *si)
{
int ret=0;
status_info_l1_t *si1;
status_info_l2_t *si2;
switch(si->typ) {
case STATUS_INFO_L1:
si1 = (status_info_l1_t *)si;
fprintf(file," prot:%x status:%d state:%s Flags:%x\n",
si1->protocol, si1->status,
strL1SState[si1->state], si1->Flags);
break;
case STATUS_INFO_L2:
si2 = (status_info_l2_t *)si;
fprintf(file," prot:%x tei:%d state:%s flag:%x\n",
si2->protocol, si2->tei,
strL2State[si2->state], si2->flag);
break;
default:
fprintf(file, "unknown status type %d\n", si->typ);
break;
}
return(ret);
}

34
tenovis/Makefile Normal file
View File

@ -0,0 +1,34 @@
LIBINCL := $(INCLUDEDIR)/mISDNlib.h
TENOVISLIB := lib/libtenovis.a
TENOVISINC := lib/tenovis.h
SUBDIRS := lib
PROGS := testlib tstlib
all: sublib $(PROGS)
testlib: testlib.o $(TENOVISLIB) $(mISDNLIB)
tstlib: tstlib.o $(TENOVISLIB) $(mISDNLIB)
testlib.o : testlib.c ../include/l3dss1.h $(LIBINCL) $(TENOVISINC)
tstlib.o : tstlib.c $(LIBINCL) $(TENOVISINC)
sublib:
$(MAKE) -C lib lib
subdirs:
set -e; for i in $(SUBDIRS) ; do $(MAKE) -C $$i $(TARGET); done
clean:
make TARGET=$@ subdirs
rm -f *.o *~ DEADJOE
distclean: clean
make TARGET=$@ subdirs
rm -f *.a $(PROGS)

20
tenovis/lib/Makefile Normal file
View File

@ -0,0 +1,20 @@
lib: libtenovis.a
libtenovis.a: tenovis_device.o tenovis_intern.o
rm -f $@
ar -r $@ $^
ar -s $@
tenovis_device.o : tenovis_device.c tenovis.h tenovis_int.h \
../../include/mISDNlib.h
tenovis_intern.o : tenovis_intern.c tenovis.h tenovis_int.h \
../../include/mISDNlib.h
clean:
rm -f *.o *~ DEADJOE
distclean: clean
rm -f *.a

68
tenovis/lib/tenovis.h Normal file
View File

@ -0,0 +1,68 @@
/* Interface for Tenovis */
/*
* int DL3open(void);
*
* DL3open() opens a device through which the D channel can be accessed.
*
* Returns a file descriptor on success or -1 in case of an error.
* The file descriptor is used in all other DL3* calls and for select().
*
*/
extern int DL3open(void);
/*
*
* int DL3close(int DL3fd)
*
* DL3close(int DL3fd) closes the DL3fd previously opened DL3open().
*
* The file descriptor DL3fd must not be used after DL3close() was called !
*
* Parameter:
* DL3fd : file descriptor assigned by DL3open
*
* Returnvalue:
* 0 on success or -1 if the file descriptor was already closed or
* is not valid.
*
*/
extern int DL3close(int DL3fd);
/*
* int DL3write(int DL3fd, const void *buf, size_t count);
*
* Sends a message to the layer 3 of the D channel stack.
*
* Parameter:
* DL3fd : file descriptor assigned by DL3open
* buf : pointer to the message buffer
* count : the length of the message in bytes
*
* Returnvalue:
* 0 on success or -1 on error in which case errno is set.
*
*
*/
extern int DL3write(int DL3fd, const void *buf, size_t count);
/*
* size_t DL3read(int DL3fd, void *buf, size_t count);
*
* Reads a message from the Layer 3 of the D channel stack.
*
* Parameter:
* DL3fd : file descriptor assigned by DL3open
* buf : pointer to the message buffer
* count : the maximum message size which can read
*
* Returnvalue:
* the length of the message in bytes or -1 in case of an error
* -2 if it was an internal (not L3) message
*/
extern size_t DL3read(int DL3fd, void *buf, size_t count);

View File

@ -0,0 +1,171 @@
/*
* Interface for Tenovis
* device functions
*
*/
#include "tenovis_int.h"
#include "tenovis.h"
/*
* int DL3open(void);
*
* DL3open() opens a device through which the D channel can be accessed.
*
* Returns a file descriptor on success or -1 in case of an error.
* The file descriptor is used in all other DL3* calls and for select().
*
*/
int
DL3open(void)
{
int fid, ret;
tenovisdev_t *dev;
if (0>(fid = mISDN_open()))
return(fid);
dev = get_tdevice(fid);
if (dev) {
fprintf(stderr, __FUNCTION__ " device %d (%p) has allready fid(%d)\n",
dev->fid, dev, fid);
close(fid);
errno = EBUSY;
return(-1);
}
dev = alloc_tdevice(fid);
if (!dev) {
return(-1);
}
ret = setup_tdevice(dev);
if (ret)
ret = -1;
else
ret = fid;
return(ret);
}
/*
*
* int DL3close(int DL3fd)
*
* DL3close(int DL3fd) closes the DL3fd previously opened DL3open().
*
* The file descriptor DL3fd must not be used after DL3close() was called !
*
* Parameter:
* DL3fd : file descriptor assigned by DL3open
*
* Returnvalue:
* 0 on success or -1 if the file descriptor was already closed or
* is not valid.
*
*/
int
DL3close(int DL3fd)
{
tenovisdev_t *dev;
int ret;
dev = get_tdevice(DL3fd);
if (!dev) {
errno = ENODEV;
return(-1);
}
shutdown_tdevice(dev);
ret = free_tdevice(dev);
return(ret);
}
/*
* int DL3write(int DL3fd, const void *buf, size_t count);
*
* Sends a message to the layer 3 of the D channel stack.
*
* Parameter:
* DL3fd : file descriptor assigned by DL3open
* buf : pointer to the message buffer
* count : the length of the message in bytes
*
* Returnvalue:
* 0 on success or -1 on error in which case errno is set.
*
*
*/
extern int DL3write(int DL3fd, const void *buf, size_t count)
{
tenovisdev_t *dev;
int ret;
dev = get_tdevice(DL3fd);
if (!dev) {
errno = ENODEV;
return(-1);
}
if (!count)
return(0);
ret = mISDN_write_frame(dev->fid, dev->buf.p, dev->tlid | IF_UP,
DL_DATA | INDICATION, 0, count, (void *)buf, TIMEOUT_1SEC);
return(ret);
}
/*
* size_t DL3read(int DL3fd, void *buf, size_t count);
*
* Reads a message from the Layer 3 of the D channel stack.
*
* Parameter:
* DL3fd : file descriptor assigned by DL3open
* buf : pointer to the message buffer
* count : the maximum message size which can read
*
* Returnvalue:
* the length of the message in bytes or -1 in case of an error
* -2 if it was an internal (not L3) message
*/
extern size_t DL3read(int DL3fd, void *buf, size_t count)
{
tenovisdev_t *dev;
int ret;
dev = get_tdevice(DL3fd);
if (!dev) {
errno = ENODEV;
return(-1);
}
if (!buf) {
errno = EINVAL;
return(-1);
}
if (!count)
return(0);
if (count > dev->size - IFRAME_HEAD_SIZE)
count = dev->size - IFRAME_HEAD_SIZE;
ret = mISDN_read(dev->fid, dev->buf.p, count + IFRAME_HEAD_SIZE,
TIMEOUT_10SEC);
#ifdef PRINTDEBUG
fprintf(stdout, __FUNCTION__": mISDN_read ret(%d) adr(%x) pr(%x) di(%x) l(%d)\n",
ret, dev->buf.f->addr, dev->buf.f->prim,
dev->buf.f->dinfo, dev->buf.f->len);
#endif
if (ret <= 0)
return(ret);
if (dev->buf.f->addr == (dev->tlid | IF_UP)) {
if (dev->buf.f->prim == (DL_DATA | REQUEST)) {
if (dev->buf.f->len > count) {
errno = ENOSPC;
return(-1);
}
ret = dev->buf.f->len;
memcpy(buf, &dev->buf.f->data.p, ret);
return(ret);
}
}
ret = intern_read(dev);
return(ret);
}

47
tenovis/lib/tenovis_int.h Normal file
View File

@ -0,0 +1,47 @@
#include "mISDNlib.h"
#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 <pthread.h>
//#define PRINTDEBUG
#undef PRINTDEBUG
#define TN_INBUFFER_SIZE 4000
typedef struct _tenovisdev {
struct _tenovisdev *prev;
struct _tenovisdev *next;
int fid;
unsigned int dstid;
unsigned int dl0id;
unsigned int dl1id;
unsigned int dl2id;
unsigned int dl3id;
unsigned int dl4id;
unsigned int tlid;
unsigned int hwid;
unsigned int Flags;
pthread_mutex_t mutex;
int size;
union {
unsigned char *p;
iframe_t *f;
} buf;
} tenovisdev_t;
#define TN_FLG_L2_ACTIV 0x0001
extern tenovisdev_t *get_tdevice(int fid);
extern tenovisdev_t *alloc_tdevice(int fid);
extern int free_tdevice(tenovisdev_t *dev);
extern int setup_tdevice(tenovisdev_t *dev);
extern int shutdown_tdevice(tenovisdev_t *dev);
extern int intern_read(tenovisdev_t *dev);

View File

@ -0,0 +1,293 @@
/*
* Internal functions for Tenovis lib
*
*/
#include "tenovis_int.h"
#include "tenovis.h"
static tenovisdev_t *tdevlist = NULL;
static pthread_mutex_t tdevlist_lock = PTHREAD_MUTEX_INITIALIZER;
tenovisdev_t *
alloc_tdevice(int fid)
{
tenovisdev_t *dev;
dev = malloc(sizeof(tenovisdev_t));
if (!dev) {
close(fid);
errno = ENODEV;
return(NULL);
}
memset(dev, 0, sizeof(tenovisdev_t));
dev->fid = fid;
dev->size = TN_INBUFFER_SIZE;
dev->buf.p = malloc(dev->size);
if (!dev->buf.p) {
close(fid);
free(dev);
errno = ENODEV;
return(NULL);
}
pthread_mutex_init(&dev->mutex, NULL);
pthread_mutex_lock(&tdevlist_lock);
dev->prev = tdevlist;
while(dev->prev && dev->prev->next)
dev->prev = dev->prev->next;
if (tdevlist)
dev->prev->next = dev;
else
tdevlist = dev;
pthread_mutex_unlock(&tdevlist_lock);
return(dev);
}
tenovisdev_t *
get_tdevice(int fid)
{
tenovisdev_t *dev;
pthread_mutex_lock(&tdevlist_lock);
dev = tdevlist;
while(dev) {
if (dev->fid==fid)
break;
dev = dev->next;
}
pthread_mutex_unlock(&tdevlist_lock);
return(dev);
}
int
free_tdevice(tenovisdev_t *dev)
{
int ret;
if (dev->prev)
dev->prev->next = dev->next;
if (dev->next)
dev->next->prev = dev->prev;
if (tdevlist==dev)
tdevlist=dev->next;
pthread_mutex_lock(&dev->mutex);
if (dev->buf.p)
free(dev->buf.p);
dev->buf.p = NULL;
pthread_mutex_unlock(&dev->mutex);
ret = pthread_mutex_destroy(&dev->mutex);
if (ret)
fprintf(stderr, __FUNCTION__ "mutex destroy returns %d\n",
ret);
ret = mISDN_close(dev->fid);
free(dev);
return(ret);
}
int
setup_tdevice(tenovisdev_t *dev)
{
int ret;
stack_info_t *stinf;
layer_info_t linf;
interface_info_t iinf;
ret = mISDN_write_frame(dev->fid, dev->buf.p, 0,
MGR_SETDEVOPT | REQUEST, FLG_mISDNPORT_ONEFRAME,
0, NULL, TIMEOUT_1SEC);
#ifdef PRINTDEBUG
fprintf(stdout, "MGR_SETDEVOPT ret(%d)\n", ret);
#endif
ret = mISDN_read(dev->fid, dev->buf.p, 1024, TIMEOUT_10SEC);
#ifdef PRINTDEBUG
fprintf(stdout, "mISDN_read ret(%d) pr(%x) di(%x) l(%d)\n",
ret, dev->buf.f->prim, dev->buf.f->dinfo, dev->buf.f->len);
#endif
ret = mISDN_get_stack_count(dev->fid);
#ifdef PRINTDEBUG
fprintf(stdout, "stackcnt %d\n", ret);
#endif
if (ret <= 0) {
free_tdevice(dev);
errno = ENODEV;
return(-1);
}
ret = mISDN_get_stack_info(dev->fid, 1, dev->buf.p, dev->size);
stinf = (stack_info_t *)&dev->buf.f->data.p;
#ifdef PRINTDEBUG
mISDNprint_stack_info(stdout, stinf);
fprintf(stdout, "ext(%x) instcnt(%d) childcnt(%d)\n",
stinf->extentions, stinf->instcnt, stinf->childcnt);
#endif
dev->dstid = stinf->id;
dev->dl0id = mISDN_get_layerid(dev->fid, dev->dstid, 0);
dev->dl1id = mISDN_get_layerid(dev->fid, dev->dstid, 1);
dev->dl2id = mISDN_get_layerid(dev->fid, dev->dstid, 2);
dev->dl3id = mISDN_get_layerid(dev->fid, dev->dstid, 3);
dev->dl4id = mISDN_get_layerid(dev->fid, dev->dstid, 4);
#ifdef PRINTDEBUG
fprintf(stdout, " dl0id = %08x\n", dev->dl0id);
fprintf(stdout, " dl1id = %08x\n", dev->dl1id);
fprintf(stdout, " dl2id = %08x\n", dev->dl2id);
fprintf(stdout, " dl3id = %08x\n", dev->dl3id);
fprintf(stdout, " dl4id = %08x\n", dev->dl4id);
memset(&iinf, 0, sizeof(interface_info_t));
iinf.owner = dev->dl2id;
iinf.stat = IF_UP;
ret = mISDN_get_interface_info(dev->fid, &iinf);
fprintf(stdout, "l2 up own(%x) -> peer(%x)\n",
iinf.owner, iinf.peer);
memset(&iinf, 0, sizeof(interface_info_t));
iinf.owner = dev->dl2id;
iinf.stat = IF_DOWN;
ret = mISDN_get_interface_info(dev->fid, &iinf);
fprintf(stdout, "l2 down own(%x) -> peer(%x)\n",
iinf.owner, iinf.peer);
memset(&iinf, 0, sizeof(interface_info_t));
iinf.owner = dev->dl3id;
iinf.stat = IF_UP;
ret = mISDN_get_interface_info(dev->fid, &iinf);
fprintf(stdout, "l3 up own(%x) -> peer(%x)\n",
iinf.owner, iinf.peer);
memset(&iinf, 0, sizeof(interface_info_t));
iinf.owner = dev->dl3id;
iinf.stat = IF_DOWN;
ret = mISDN_get_interface_info(dev->fid, &iinf);
fprintf(stdout, "l3 down own(%x) -> peer(%x)\n",
iinf.owner, iinf.peer);
#endif
memset(&linf, 0, sizeof(layer_info_t));
strcpy(&linf.name[0], "tenovis L2");
linf.object_id = -1;
linf.extentions = EXT_INST_MIDDLE;
linf.pid.protocol[stinf->instcnt] = ISDN_PID_ANY;
linf.pid.layermask = ISDN_LAYER(stinf->instcnt);
linf.st = dev->dstid;
dev->tlid = mISDN_new_layer(dev->fid, &linf);
#ifdef PRINTDEBUG
fprintf(stdout, "mISDN_new_layer ret(%x)\n", dev->tlid);
ret = mISDN_get_stack_info(dev->fid, 1, dev->buf.p, dev->size);
stinf = (stack_info_t *)&dev->buf.f->data.p;
mISDNprint_stack_info(stdout, stinf);
#endif
memset(&iinf, 0, sizeof(interface_info_t));
iinf.extentions = EXT_INST_MIDDLE;
iinf.owner = dev->tlid;
iinf.peer = dev->dl3id;
iinf.stat = IF_UP;
ret = mISDN_write_frame(dev->fid, dev->buf.p, dev->tlid,
MGR_SETIF | REQUEST, 0, sizeof(interface_info_t),
&iinf, TIMEOUT_1SEC);
#ifdef PRINTDEBUG
fprintf(stdout, "mISDN_write_frame ret(%d)\n", ret);
#endif
ret = mISDN_read(dev->fid, dev->buf.p, 1024, TIMEOUT_10SEC);
#ifdef PRINTDEBUG
fprintf(stdout, "mISDN_read ret(%d) pr(%x) di(%x) l(%d)\n",
ret, dev->buf.f->prim, dev->buf.f->dinfo,
dev->buf.f->len);
#endif
memset(&iinf, 0, sizeof(interface_info_t));
iinf.extentions = EXT_INST_MIDDLE;
iinf.owner = dev->tlid;
iinf.peer = dev->dl2id;
iinf.stat = IF_DOWN;
ret = mISDN_write_frame(dev->fid, dev->buf.p, dev->tlid,
MGR_SETIF | REQUEST, 0, sizeof(interface_info_t),
&iinf, TIMEOUT_1SEC);
#ifdef PRINTDEBUG
fprintf(stdout, "mISDN_write_frame ret(%d)\n", ret);
#endif
ret = mISDN_read(dev->fid, dev->buf.p, 1024, TIMEOUT_10SEC);
#ifdef PRINTDEBUG
fprintf(stdout, "mISDN_read ret(%d) pr(%x) di(%x) l(%d)\n",
ret, dev->buf.f->prim, dev->buf.f->dinfo,
dev->buf.f->len);
memset(&iinf, 0, sizeof(interface_info_t));
iinf.owner = dev->dl2id;
iinf.stat = IF_UP;
ret = mISDN_get_interface_info(dev->fid, &iinf);
fprintf(stdout, "l2 up own(%x) -> peer(%x)\n",
iinf.owner, iinf.peer);
memset(&iinf, 0, sizeof(interface_info_t));
iinf.owner = dev->dl2id;
iinf.stat = IF_DOWN;
ret = mISDN_get_interface_info(dev->fid, &iinf);
fprintf(stdout, "l2 down own(%x) -> peer(%x)\n",
iinf.owner, iinf.peer);
memset(&iinf, 0, sizeof(interface_info_t));
iinf.owner = dev->dl3id;
iinf.stat = IF_UP;
ret = mISDN_get_interface_info(dev->fid, &iinf);
fprintf(stdout, "l3 up own(%x) -> peer(%x)\n",
iinf.owner, iinf.peer);
memset(&iinf, 0, sizeof(interface_info_t));
iinf.owner = dev->dl3id;
iinf.stat = IF_DOWN;
ret = mISDN_get_interface_info(dev->fid, &iinf);
fprintf(stdout, "l3 down own(%x) -> peer(%x)\n",
iinf.owner, iinf.peer);
#endif
return(0);
}
int
shutdown_tdevice(tenovisdev_t *dev)
{
int ret;
pthread_mutex_lock(&dev->mutex);
if (dev->buf.p) {
if (dev->tlid) {
ret = mISDN_write_frame(dev->fid, dev->buf.p,
dev->tlid, MGR_DELLAYER | REQUEST,
0, 0, NULL, TIMEOUT_1SEC);
#ifdef PRINTDEBUG
fprintf(stdout, "MGR_DELLAYER ret(%d)\n", ret);
#endif
ret = mISDN_read(dev->fid, dev->buf.p, 1024,
TIMEOUT_10SEC);
#ifdef PRINTDEBUG
fprintf(stdout, "mISDN_read ret(%d) pr(%x) di(%x) l(%d)\n",
ret, dev->buf.f->prim, dev->buf.f->dinfo,
dev->buf.f->len);
#endif
}
}
pthread_mutex_unlock(&dev->mutex);
return(0);
}
int
intern_read(tenovisdev_t *dev)
{
int ret;
#ifdef PRINTDEBUG
fprintf(stdout, __FUNCTION__" addr(%x) prim(%x)\n",
dev->buf.f->addr, dev->buf.f->prim);
#endif
if (dev->buf.f->addr == (dev->tlid | IF_UP)) {
if (dev->buf.f->prim == (DL_ESTABLISH | REQUEST)) {
dev->Flags |= TN_FLG_L2_ACTIV;
ret = mISDN_write_frame(dev->fid, dev->buf.p,
dev->tlid | IF_UP, DL_ESTABLISH | CONFIRM,
0, 0, NULL, TIMEOUT_1SEC);
#ifdef PRINTDEBUG
fprintf(stdout, __FUNCTION__": estab cnf ret(%d)\n",
ret);
#endif
} else if (dev->buf.f->prim == (DL_RELEASE | REQUEST)) {
dev->Flags &= ~TN_FLG_L2_ACTIV;
ret = mISDN_write_frame(dev->fid, dev->buf.p,
dev->tlid | IF_UP, DL_RELEASE | CONFIRM,
0, 0, NULL, TIMEOUT_1SEC);
#ifdef PRINTDEBUG
fprintf(stdout, __FUNCTION__": rel cnf ret(%d)\n",
ret);
#endif
}
}
return(-2);
}

277
tenovis/testlib.c Normal file
View File

@ -0,0 +1,277 @@
#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 <signal.h>
#include "mISDNlib.h"
#include "lib/tenovis.h"
#include "l3dss1.h"
int tid;
int hid;
int dl3id;
int l2activ = 0;
#define BUFFER_SIZE 2048
u_char buffer[BUFFER_SIZE];
u_char msg[BUFFER_SIZE];
iframe_t *frame;
int
init_lowdchannel(void)
{
int ret;
stack_info_t *stinf;
layer_info_t linf;
interface_info_t iinf;
int dstid, dl2id;
frame = (iframe_t *)buffer;
hid = mISDN_open();
if (hid < 0)
return(-1);
ret = mISDN_write_frame(hid, buffer, 0,
MGR_SETDEVOPT | REQUEST, FLG_mISDNPORT_ONEFRAME,
0, NULL, TIMEOUT_1SEC);
fprintf(stdout, "MGR_SETDEVOPT ret(%d)\n", ret);
ret = mISDN_read(hid, buffer, BUFFER_SIZE, TIMEOUT_10SEC);
fprintf(stdout, "mISDN_read ret(%d) pr(%x) di(%x) l(%d)\n",
ret, frame->prim, frame->dinfo, frame->len);
ret = mISDN_get_stack_count(hid);
fprintf(stdout, "stackcnt %d\n", ret);
if (ret <= 0) {
mISDN_close(hid);
return(-1);
}
ret = mISDN_get_stack_info(hid, 1, buffer, BUFFER_SIZE);
stinf = (stack_info_t *)&frame->data.p;
mISDNprint_stack_info(stdout, stinf);
fprintf(stdout, "ext(%x) instcnt(%d) childcnt(%d)\n",
stinf->extentions, stinf->instcnt, stinf->childcnt);
dstid = stinf->id;
dl2id = mISDN_get_layerid(hid, dstid, 2);
fprintf(stdout, " dl2id = %08x\n", dl2id);
memset(&iinf, 0, sizeof(interface_info_t));
iinf.owner = dl2id;
iinf.stat = IF_UP;
ret = mISDN_get_interface_info(hid, &iinf);
fprintf(stdout, "l2 up own(%x) -> peer(%x)\n",
iinf.owner, iinf.peer);
memset(&iinf, 0, sizeof(interface_info_t));
iinf.owner = dl2id;
iinf.stat = IF_DOWN;
ret = mISDN_get_interface_info(hid, &iinf);
fprintf(stdout, "l2 down own(%x) -> peer(%x)\n",
iinf.owner, iinf.peer);
memset(&linf, 0, sizeof(layer_info_t));
strcpy(&linf.name[0], "tst L3");
linf.object_id = -1;
linf.extentions = EXT_INST_MIDDLE;
linf.pid.protocol[stinf->instcnt] = ISDN_PID_ANY;
linf.pid.layermask = ISDN_LAYER(stinf->instcnt);
linf.st = dstid;
dl3id = mISDN_new_layer(hid, &linf);
fprintf(stdout, "mISDN_new_layer ret(%x)\n", dl3id);
ret = mISDN_get_stack_info(hid, 1, buffer, BUFFER_SIZE);
stinf = (stack_info_t *)&frame->data.p;
mISDNprint_stack_info(stdout, stinf);
memset(&iinf, 0, sizeof(interface_info_t));
iinf.extentions = EXT_INST_MIDDLE;
iinf.owner = dl3id;
iinf.peer = dl2id;
iinf.stat = IF_DOWN;
ret = mISDN_write_frame(hid, buffer, dl3id,
MGR_SETIF | REQUEST, 0, sizeof(interface_info_t),
&iinf, TIMEOUT_1SEC);
fprintf(stdout, "mISDN_write_frame ret(%d)\n", ret);
ret = mISDN_read(hid, buffer, 1024, TIMEOUT_10SEC);
fprintf(stdout, "mISDN_read ret(%d) pr(%x) di(%x) l(%d)\n",
ret, frame->prim, frame->dinfo,
frame->len);
memset(&iinf, 0, sizeof(interface_info_t));
iinf.owner = dl2id;
iinf.stat = IF_UP;
ret = mISDN_get_interface_info(hid, &iinf);
fprintf(stdout, "l2 up own(%x) -> peer(%x)\n",
iinf.owner, iinf.peer);
memset(&iinf, 0, sizeof(interface_info_t));
iinf.owner = dl2id;
iinf.stat = IF_DOWN;
ret = mISDN_get_interface_info(hid, &iinf);
fprintf(stdout, "l2 down own(%x) -> peer(%x)\n",
iinf.owner, iinf.peer);
return(0);
}
int
close_lowdchannel(void)
{
int ret;
ret = mISDN_write_frame(hid, buffer, dl3id, MGR_DELLAYER | REQUEST,
0, 0, NULL, TIMEOUT_1SEC);
fprintf(stdout, "MGR_DELLAYER ret(%d)\n", ret);
ret = mISDN_read(hid, buffer, 1024, TIMEOUT_10SEC);
fprintf(stdout, "mISDN_read ret(%d) pr(%x) di(%x) l(%d)\n",
ret, frame->prim, frame->dinfo, frame->len);
return(0);
}
int
process_lowdchannel(int len)
{
int ret;
fprintf(stderr, "mISDN_read pr(%x) di(%x) l(%d)\n",
frame->prim, frame->dinfo, frame->len);
if (frame->prim == (DL_DATA | INDICATION)) {
ret = DL3write(tid, &frame->data.p, frame->len);
fprintf(stderr, "DL3write ret(%d)\n", ret);
} else if (frame->prim == (DL_UNITDATA | INDICATION)) {
ret = DL3write(tid, &frame->data.p, frame->len);
fprintf(stderr, "DL3write ret(%d)\n", ret);
} else if (frame->prim == (DL_ESTABLISH | CONFIRM)) {
fprintf(stderr, "estab cnf\n");
l2activ = 1;
} else if (frame->prim == (DL_ESTABLISH | INDICATION)) {
fprintf(stderr, "estab ind\n");
l2activ = 1;
} else if (frame->prim == (DL_RELEASE | CONFIRM)) {
fprintf(stderr, "release cnf\n");
l2activ = 0;
} else if (frame->prim == (DL_RELEASE | INDICATION)) {
fprintf(stderr, "release ind\n");
l2activ = 0;
}
return(0);
}
int
send_lowdchannel(int len)
{
int ret;
if (!l2activ) {
ret = mISDN_write_frame(hid, buffer, dl3id | IF_DOWN,
DL_ESTABLISH | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
fprintf(stderr, "estab req ret(%d)\n", ret);
ret = mISDN_read(hid, buffer, 1024, TIMEOUT_10SEC);
fprintf(stderr, "estab read ret(%d)\n", ret);
if (ret >= 16) {
if (frame->prim == (DL_ESTABLISH | CONFIRM)) {
fprintf(stderr, "estab cnf\n");
l2activ = 1;
}
if (frame->prim == (DL_ESTABLISH | INDICATION)) {
fprintf(stderr, "estab ind\n");
l2activ = 1;
}
}
}
ret = mISDN_write_frame(hid, buffer, dl3id | IF_DOWN,
DL_DATA | REQUEST, 0, len, msg, TIMEOUT_1SEC);
return(ret);
}
static void
term_handler(int sig)
{
int err;
fprintf(stderr,"signal %d received\n", sig);
close_lowdchannel();
err = DL3close(tid);
fprintf(stderr,"DL3close returns %d\n", err);
exit(0);
}
int main(argc,argv)
int argc;
char *argv[];
{
int ret, n;
int err;
fd_set in;
fprintf(stderr,"%s\n", argv[0]);
tid = DL3open();
fprintf(stderr,"DL3open returns %d\n", tid);
if (tid<0) {
fprintf(stderr,"DL3open error %s\n", strerror(errno));
exit(1);
}
if (init_lowdchannel()) {
DL3close(tid);
exit(1);
}
signal(SIGTERM, term_handler);
signal(SIGINT, term_handler);
signal(SIGPIPE, term_handler);
while(1) {
FD_ZERO(&in);
n = fileno(stdin);
FD_SET(n, &in);
if (n<tid)
n = tid;
FD_SET(tid, &in);
if (n<hid)
n = hid;
FD_SET(hid, &in);
n++;
ret = select(n, &in, NULL, NULL, NULL);
if (ret<0)
continue;
if (FD_ISSET(fileno(stdin), &in))
break;
if (FD_ISSET(tid, &in)) {
ret = DL3read(tid, msg, 2048);
if (ret == -2) {
fprintf(stderr,"DL3read internal processing\n");
} else if (ret == -1) {
fprintf(stderr,"DL3read errno %d: %s\n",
errno, strerror(errno));
} else if (ret == 0) {
fprintf(stderr,"DL3read empty frame ?\n");
} else {
fprintf(stderr,"DL3read %d bytes\n", ret);
send_lowdchannel(ret);
}
}
if (FD_ISSET(hid, &in)) {
ret = mISDN_read(hid, buffer, 1024, TIMEOUT_1SEC);
if (ret < 0) {
fprintf(stderr,"mISDN_read errno %d: %s\n",
errno, strerror(errno));
} else if (ret == 0) {
fprintf(stderr,"mISDN_read empty frame ?\n");
} else {
fprintf(stderr,"mISDN_read %d bytes\n", ret);
if (ret < 16) {
fprintf(stderr,"mISDN_read incomplete frame\n");
continue;
}
process_lowdchannel(ret);
}
}
}
err = close_lowdchannel();
fprintf(stderr,"close_lowdchannel returns %d\n", err);
err = DL3close(tid);
fprintf(stderr,"DL3close returns %d\n", err);
return(0);
}

156
tenovis/tstlib.c Normal file
View File

@ -0,0 +1,156 @@
#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 <signal.h>
#include "mISDNlib.h"
#include "lib/tenovis.h"
#include "l3dss1.h"
#define make_dss1_head(f, cr, mt) \
*f++ = 8;\
*f++ = 1;\
*f++ = cr;\
*f++ = mt
int tid;
u_char callref;
static void
term_handler(int sig)
{
int err;
fprintf(stderr,"signal %d received\n", sig);
err = DL3close(tid);
fprintf(stderr,"DL3close returns %d\n", err);
exit(0);
}
int
handle_msg(u_char *imsg, int len)
{
u_char mt,cr;
u_char omsg[2048], *p;
int ret;
cr = imsg[2];
callref = cr;
mt = imsg[3];
p = omsg;
switch(mt) {
case MT_SETUP:
make_dss1_head(p, (cr ^ 0x80), MT_CALL_PROCEEDING);
*p++ = IE_CHANNEL_ID;
*p++ = 3;
*p++ = 0xa1;
*p++ = 0x83;
*p++ = 0x05;
ret = DL3write(tid, omsg, p - omsg);
fprintf(stderr,"CALLP write ret %d\n", ret);
p = omsg;
make_dss1_head(p, (cr ^ 0x80), MT_ALERTING);
ret = DL3write(tid, omsg, p - omsg);
fprintf(stderr,"ALERT write ret %d\n", ret);
p = omsg;
make_dss1_head(p, (cr ^ 0x80), MT_CONNECT);
ret = DL3write(tid, omsg, p - omsg);
fprintf(stderr,"CONN write ret %d\n", ret);
break;
case MT_DISCONNECT:
make_dss1_head(p, (cr ^= 0x80), MT_RELEASE);
ret = DL3write(tid, omsg, p - omsg);
fprintf(stderr,"REL write ret %d\n", ret);
break;
case MT_RELEASE:
make_dss1_head(p, (cr ^= 0x80), MT_RELEASE_COMPLETE);
ret = DL3write(tid, omsg, p - omsg);
fprintf(stderr,"RELC write ret %d\n", ret);
break;
case MT_RELEASE_COMPLETE:
fprintf(stderr,"got RELC len(%d)\n", len);
break;
case MT_STATUS:
fprintf(stderr,"got STATUS cr(%x) len(%d)\n",
cr, len);
break;
default:
fprintf(stderr,"got mt(%x) cr(%x) len(%d)\n",
mt, cr, len);
break;
}
return(0);
}
int main(argc,argv)
int argc;
char *argv[];
{
u_char imsg[2048];
u_char omsg[2048], *p;
int ret, n, loop = 1;
int err;
fd_set in;
fprintf(stderr,"%s\n", argv[0]);
tid = DL3open();
fprintf(stderr,"DL3open returns %d\n", tid);
if (tid<0) {
fprintf(stderr,"DL3open error %s\n", strerror(errno));
exit(1);
}
signal(SIGTERM, term_handler);
signal(SIGINT, term_handler);
signal(SIGPIPE, term_handler);
while(loop) {
FD_ZERO(&in);
n = fileno(stdin);
FD_SET(n, &in);
if (n<tid)
n = tid;
FD_SET(tid, &in);
n++;
ret = select(n, &in, NULL, NULL, NULL);
if (ret<0)
continue;
if (FD_ISSET(fileno(stdin), &in)) {
fgets(imsg, 2048, stdin);
switch(imsg[0]) {
case 'q':
case 'Q':
loop = 0;
break;
case 'h':
case 'H':
p = omsg;
make_dss1_head(p, (callref ^ 0x80),
MT_DISCONNECT);
*p++ = IE_CAUSE;
*p++ = 2;
*p++ = 0x80;
*p++ = 0x90;
ret = DL3write(tid, omsg, p - omsg);
fprintf(stderr,"DISC write ret %d\n", ret);
break;
default:
fprintf(stderr,"commands are (h)angup and (q)uit\n");
break;
}
}
if (FD_ISSET(tid, &in)) {
ret = DL3read(tid, imsg, 2048);
if (ret>0)
handle_msg(imsg, ret);
}
}
err = DL3close(tid);
fprintf(stderr,"DL3close returns %d\n", err);
return(0);
}

83
voip/Makefile Normal file
View File

@ -0,0 +1,83 @@
# ifndef SF_DIR
# SF_DIR = /home/kkeil/speak_freely-7.2
# endif
mISDNLIB = $(mISDN_DIR)/lib/libmISDN.a
ISDNNETLIB = $(mISDN_DIR)/i4lnet/libisdnnet.a
HLIBINCL = $(mISDN_DIR)/include/mISDNlib.h
INETINCL = $(mISDN_DIR)/include/isdn_net.h
EXTRA_CFLAGS :=
EXTRA_INCLUDE :=
EXTRA_LIB :=
GSM_DIR := ../../gsm-1.0-pl6
ifdef GSM_DIR
EXTRA_CFLAGS += -DGSM_COMPRESSION
EXTRA_INCLUDE += -I$(GSM_DIR)/inc
EXTRA_LIB += $(GSM_DIR)/lib/libgsm.a
endif
PROGRAMMS = voipisdn
all: $(PROGRAMMS)
INTERNET_PORT = 2074
CARGS = -DInternet_Port=$(INTERNET_PORT)
CCFLAGS = -O3 -DLINUX -DM_LITTLE_ENDIAN
LFLAGS = -lncurses -lm -lrt -lpthread
DEBUG = -g -DHEXDUMP
CFLAGS := $(CFLAGS) $(DEBUG) $(EXTRA_INCLUDE) \
$(CARGS) $(DUPLEX) $(CCFLAGS) $(DOMAIN) $(EXTRA_CFLAGS)
LEX = flex -8
VOIPISDNOBJ = voip_isdn.o rtpacket.o voip_timer.o \
read_cfg.o voip_appl.o voip_isdn_app.o
voipisdn: $(VOIPISDNOBJ) $(ISDNNETLIB) $(mISDNLIB) $(EXTRA_LIB) \
$(HLIBINCL) $(INETINCL) \
globals.h iapplication.h
$(CC) $(VOIPISDNOBJ) $(ISDNNETLIB) $(mISDNLIB) $(EXTRA_LIB) \
$(LFLAGS) -o $@
rtpacket.o: rtpacket.c rtpacket.h \
$(mISDN_DIR)/include/g711.h
voip_timer.o: voip_timer.c vitimer.h
voip_appl.o: voip_appl.c $(mISDN_DIR)/include/g711.h \
globals.h rtpacket.h iapplication.h \
$(HLIBINCL) $(INETINCL)
voip_isdn_app.o: voip_isdn_app.c \
globals.h rtpacket.h iapplication.h \
$(HLIBINCL) $(INETINCL)
voip_isdn.o: voip_isdn.c $(mISDN_DIR)/include/g711.h \
globals.h rtpacket.h iapplication.h \
$(HLIBINCL) $(INETINCL)
cfg_lex.c: cfg.lex
$(LEX) cfg.lex
mv lex.yy.c cfg_lex.c
read_cfg.o: read_cfg.c cfg_lex.c cfg.lex iapplication.h
tstparse.o: tstparse.c
tstparse: tstparse.o read_cfg.o
clean:
rm -f *.o cfg_lex.c DEADJOE
find ./ -name '*~' -exec rm {} \;
distclean: clean
rm -f *.a $(PROGRAMMS) tstparse

83
voip/Makefile.org Normal file
View File

@ -0,0 +1,83 @@
# ifndef SF_DIR
# SF_DIR = /home/kkeil/speak_freely-7.2
# endif
HISAXLIB = $(HISAX_DIR)/lib/libhisax.a
ISDNNETLIB = $(HISAX_DIR)/i4lnet/libisdnnet.a
HLIBINCL = $(HISAX_DIR)/include/hisaxlib.h
INETINCL = $(HISAX_DIR)/include/isdn_net.h
EXTRA_CFLAGS :=
EXTRA_INCLUDE :=
EXTRA_LIB :=
GSM_DIR := ../../gsm-1.0-pl6
ifdef GSM_DIR
EXTRA_CFLAGS += -DGSM_COMPRESSION
EXTRA_INCLUDE += -I$(GSM_DIR)/inc
EXTRA_LIB += $(GSM_DIR)/lib/libgsm.a
endif
PROGRAMMS = voipisdn
all: $(PROGRAMMS)
INTERNET_PORT = 2074
CARGS = -DInternet_Port=$(INTERNET_PORT)
CCFLAGS = -O3 -DLINUX -DM_LITTLE_ENDIAN
LFLAGS = -lncurses -lm -lrt -lpthread
DEBUG = -g -DHEXDUMP
CFLAGS := $(CFLAGS) $(DEBUG) $(EXTRA_INCLUDE) \
$(CARGS) $(DUPLEX) $(CCFLAGS) $(DOMAIN) $(EXTRA_CFLAGS)
LEX = flex -8
VOIPISDNOBJ = voip_isdn.o rtpacket.o voip_timer.o \
read_cfg.o voip_appl.o voip_isdn_app.o
voipisdn: $(VOIPISDNOBJ) $(ISDNNETLIB) $(HISAXLIB) $(EXTRA_LIB) \
$(HLIBINCL) $(INETINCL) \
globals.h iapplication.h
$(CC) $(VOIPISDNOBJ) $(ISDNNETLIB) $(HISAXLIB) $(EXTRA_LIB) \
$(LFLAGS) -o $@
rtpacket.o: rtpacket.c rtpacket.h \
$(HISAX_DIR)/include/g711.h
voip_timer.o: voip_timer.c vitimer.h
voip_appl.o: voip_appl.c $(HISAX_DIR)/include/g711.h \
globals.h rtpacket.h iapplication.h \
$(HLIBINCL) $(INETINCL)
voip_isdn_app.o: voip_isdn_app.c \
globals.h rtpacket.h iapplication.h \
$(HLIBINCL) $(INETINCL)
voip_isdn.o: voip_isdn.c $(HISAX_DIR)/include/g711.h \
globals.h rtpacket.h iapplication.h \
$(HLIBINCL) $(INETINCL)
cfg_lex.c: cfg.lex
$(LEX) cfg.lex
mv lex.yy.c cfg_lex.c
read_cfg.o: read_cfg.c cfg_lex.c cfg.lex iapplication.h
tstparse.o: tstparse.c
tstparse: tstparse.o read_cfg.o
clean:
rm -f *.o cfg_lex.c DEADJOE
find ./ -name '*~' -exec rm {} \;
distclean: clean
rm -f *.a $(PROGRAMMS) tstparse

115
voip/cfg.lex Normal file
View File

@ -0,0 +1,115 @@
WSP [ \t]
NWSP [^ \t\n]
VCHR [A-Za-z_]
VCHRZ [A-Za-z_0-9]
VCHRX [A-Za-z\-\._0-9]
VCHRP [A-Za-z\-\.\/_0-9]
MSN [Mm][Ss][Nn]
AUDIONR [Aa][Uu][Dd][Ii][Oo][Nn][Rr]
VOIPNR [Vv][Oo][Ii][Pp][Nn][Rr]
DEBUG [Dd][Ee][Bb][Uu][Gg]
PORT [Pp][Oo][Rr][Tt]
GSM [Gg][Ss][Mm]
RECORD [Rr][Ee][Cc][Oo][Rr][Dd]
FILE [Ff][Ii][Ll][Ee]
PATH [Pp][Aa][Tt][Hh]
CTRL [Cc][Tt][Rr][Ll]
ZIF [0-9]
HZIF [0-9a-fA-F]
HEX 0[Xx]{HZIF}+
NR {ZIF}+
NAME {VCHRX}+
PATHSTR {VCHRP}+
%START Normal Comment Number Name NumValue PathValue
%%
int AktState=0;
ulong val=0;
nr_list_t *new_nr = NULL;
<Normal>{
^#.* ;
{DEBUG}{WSP}+ {
BEGIN NumValue;
AktState = ST_DEB;
}
{RECORD}{CTRL}{FILE}{WSP}+ {
BEGIN PathValue;
AktState = ST_RCF;
}
{RECORD}{FILE}{PATH}{WSP}+ {
BEGIN PathValue;
AktState = ST_RFP;
}
{PORT}{WSP}+ {
BEGIN NumValue;
AktState = ST_PORT;
}
{MSN}{WSP}+ {
BEGIN Number;
AktState = ST_MSN;
new_nr = getnewnr(NR_TYPE_INTERN);
}
{AUDIONR}{WSP}+ {
BEGIN Number;
AktState = ST_AUDIO;
new_nr = getnewnr(NR_TYPE_AUDIO);
}
{VOIPNR}{WSP}+ {
BEGIN Number;
AktState = ST_VNR;
new_nr = getnewnr(NR_TYPE_VOIP);
}
{GSM}{WSP}* {
add_cfgflag(AktState, new_nr, FLAG_GSM);
}
{WSP}+ ;
[^ \t\n] {
yyless(0);
BEGIN Name;
}
\n {
new_nr = NULL;
}
}
<Number>{
{WSP}* ;
{NR} {
add_cfgnr(AktState, new_nr, yytext, yyleng);
BEGIN Normal;
}
}
<Name>{
{WSP}* ;
{NAME} {
add_cfgname(AktState, new_nr, yytext, yyleng);
BEGIN Normal;
}
}
<NumValue>{
{WSP}* ;
{HEX} {
val = strtol(yytext, NULL, 16);
add_cfgval(AktState, new_nr, val);
AktState = ST_NORM;
BEGIN Normal;
}
{NR} {
val = strtol(yytext, NULL, 0);
add_cfgval(AktState, new_nr, val);
AktState = ST_NORM;
BEGIN Normal;
}
}
<PathValue>{
{WSP}* ;
{PATHSTR} {
add_path(AktState, yytext, yyleng);
AktState = ST_NORM;
BEGIN Normal;
}
}

View File

@ -0,0 +1,36 @@
#
# tstsetup voipisdn
#
#
# File to control recording of channels
# see rec_ctrl.sample
#
RecordCtrlFile /var/tmp/rec_ctrl
#
# Path to diretory where record files are saved
# Record filenames are <timestamp>_<channel>.r (from phone)
# <timestamp>_<channel>.s (to phone)
#
RecordFilePath /var/tmp/
#
# MSN <number>
# local number
#
MSN 12345
MSN 888
#
# VOIPNR <number> <hostname|addresse> [GSM]
# foreign numbers on hostname or address
# option: using of GSM
#
VOIPNR 4566 pictra_client GSM
VOIPNR 4568 pictra_client
VOIPNR 4567 10.23.200.1
#
# AUDIONR <number>
# number for calling the local soundcard
#
AUDIONR 789

View File

@ -0,0 +1,7 @@
#
# for each channel one line with a value:
# 0 don't record channel
# 1 record channel
#
1
0

19
voip/globals.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef FLAG_GSM
#define FLAG_GSM 0x0020
#endif
extern int parse_cfg(char *, manager_t *);
#ifdef INIT_GLOBALS
int global_debug = 0;
int rtp_port = Internet_Port;
int default_flags = 0;
char RecordCtrlFile[1024] = {0,};
char RecordFilePath[1024] = {0,};
#else
extern int global_debug;
extern int rtp_port;
extern int default_flags;
extern char RecordCtrlFile[1024];
extern char RecordFilePath[1024];
#endif

137
voip/iapplication.h Normal file
View File

@ -0,0 +1,137 @@
#ifndef IAPPLICATION_H
#define IAPPLICATION_H
#include "vitimer.h"
#ifdef GSM_COMPRESSION
#include <gsm.h>
#endif
#define AP_MODE_IDLE 0
#define AP_MODE_INTERN_CALL 1
#define AP_MODE_AUDIO_CALL 2
#define AP_MODE_VOIP_OCALL 3
#define AP_MODE_VOIP_ICALL 4
#define AP_FLG_AUDIO_ACTIV 1
#define AP_FLG_VOIP_ALERTING 2
#define AP_FLG_VOIP_ACTIV 4
#define AP_FLG_VOIP_NEW_CONN 0x01000000
#define AP_FLG_VOIP_PEER_VALID 0x02000000
#define AP_FLG_VOIP_SENT_BYE 0x04000000
#define AP_FLG_VOIP_PEER_BYE 0x08000000
#define AP_FLG_VOIP_PEER_SF 0x10000000
#define AP_FLG_AUDIO_USED 0x00000100
#define AP_FLG_VOIP_ABORT 0x80000000
#define AP_PR_VOIP_ISDN 1
#define AP_PR_VOIP_NEW 2
#define AP_PR_VOIP_SPEAKFREE 3
#define AP_PR_VOIP_BYE 4
#define MAX_HOST_SIZE 64
#define MAX_NETBUFFER_SIZE 8040
#define SLOW_TIMEOUT_s 10
#define SLOW_TIMEOUT_us 0
#define NORMAL_TIMEOUT_s 0
#define NORMAL_TIMEOUT_us (320*125)
#define SNDFLG_ULAW 0x00000001
#define SNDFLG_ALAW 0x00000002
#define SNDFLG_LINEAR16 0x00000004
#define SNDFLG_COMPR_GSM 0x00000100
typedef struct _iapplication iapplication_t;
typedef struct _vapplication vapplication_t;
typedef struct _vconnection vconnection_t;
struct _iapplication {
iapplication_t *prev;
iapplication_t *next;
manager_t *mgr;
vapplication_t *vapp;
void *data1;
void *data2;
vconnection_t *con;
void *para;
vi_timer_t timer;
pthread_t tid;
int Flags;
int mode;
};
struct _vapplication {
manager_t *mgr_lst;
char hostname[MAX_HOST_SIZE];
unsigned int flags;
struct timeval tout;
int debug;
int port;
int dsock;
int csock;
struct sockaddr_in daddr;
struct sockaddr_in caddr;
struct sockaddr_in from;
int fromlen;
iapplication_t *iapp_lst;
int rlen;
union {
unsigned char d[MAX_NETBUFFER_SIZE];
} buf;
};
struct _vconnection {
int sock;
struct sockaddr_in cpeer;
struct sockaddr_in dpeer;
char rmtname[256];
char con_hostname[32];
unsigned int own_ssrc;
unsigned int peer_ssrc;
unsigned int timestamp;
unsigned short seq;
unsigned short lastseq;
unsigned char oc;
unsigned char pc;
msg_queue_t aqueue;
msg_t *amsg;
int rlen;
unsigned char *rbuf;
unsigned int sndflags;
int pkt_size;
int slen;
#ifdef GSM_COMPRESSION
gsm r_gsm;
gsm s_gsm;
#endif
unsigned char sbuf[1024];
unsigned char dbuf[1152];
unsigned char cbuf[1024];
};
extern pthread_t run_voip(vapplication_t *v);
extern void *voip_sender(void *arg);
extern void clear_connection(iapplication_t *);
extern void free_application(iapplication_t *);
extern unsigned long getnew_ssrc(vapplication_t *);
extern iapplication_t *new_application(vapplication_t *);
extern vconnection_t *new_connection(iapplication_t *, struct in_addr *);
extern int SendCtrl(iapplication_t *);
extern int voip_application_handler(iapplication_t *, int,
unsigned char *);
extern int setup_voip(iapplication_t *, bchannel_t *);
extern int close_voip(iapplication_t *, bchannel_t *);
extern int setup_voip_ocall(iapplication_t *, bchannel_t *);
extern int alert_voip(iapplication_t *, bchannel_t *);
extern int facility_voip(iapplication_t *, bchannel_t *);
extern int useruser_voip(iapplication_t *, bchannel_t *);
extern int connect_voip(iapplication_t *, bchannel_t *);
extern int disconnect_voip(iapplication_t *, bchannel_t *);
extern int release_voip(iapplication_t *, bchannel_t *);
#endif

13
voip/options.h Normal file
View File

@ -0,0 +1,13 @@
int debugforce;
int whichport;
int jitter;
int jitteridlet;
int record;
int hexdump;
int blowfish_spec;
BF_KEY blowfishkey;
char ideakey[17];
char deskey[9];
char *curotp;
char *pgppass;

9
voip/prep.conf Normal file
View File

@ -0,0 +1,9 @@
#undef PUSH_TO_TALK
#undef USE_CURSES
#undef AUDIO_DEVICE_FILE
#undef HALF_DUPLEX
#undef HEWLETT_PACKARD
#define UNIX5
#undef UNIX420
#undef Solaris
#undef sgi

143
voip/read_cfg.c Normal file
View File

@ -0,0 +1,143 @@
#include <stdio.h>
#include <stdlib.h>
#include "isdn_net.h"
#include "helper.h"
#define INIT_GLOBALS
#include "globals.h"
static manager_t *akt_mgr;
int add_cfgnr(int state, nr_list_t *nr, char *t, int l);
int add_cfgname(int state, nr_list_t *nr, char *t, int l);
int add_cfgval(int state, nr_list_t *nr, ulong val);
nr_list_t *getnewnr(int typ);
int add_cfgflag(int state, nr_list_t *nr, int flag);
int add_path(int state, char *t, int l);
enum {
ST_NORM,
ST_MSN,
ST_VNR,
ST_AUDIO,
ST_DEB,
ST_PORT,
ST_RFP,
ST_RCF,
};
#include "cfg_lex.c"
int yywrap(void)
{
return(1);
}
int parse_cfg(char *FName, manager_t *mgr) {
int ret;
yyin = fopen(FName, "r");
if (!yyin) {
fprintf(stderr,"cannot open cfg file %s\n", FName);
return(1);
} else
fprintf(stderr,"parsing cfg file %s\n", FName);
akt_mgr = mgr;
BEGIN Normal;
ret = yylex();
fclose(yyin);
return(ret);
}
nr_list_t *
getnewnr(int typ)
{
nr_list_t *nr;
nr = malloc(sizeof(nr_list_t));
memset(nr, 0, sizeof(nr_list_t));
nr->typ = typ;
return(nr);
}
int
add_cfgnr(int state, nr_list_t *nr, char *t, int l)
{
// printf("%s(%d,%p,%s)\n", __FUNCTION__, state, nr, t);
if (nr) {
switch(state) {
default:
strcpy(nr->nr, t);
nr->len = l;
APPEND_TO_LIST(nr, akt_mgr->nrlist);
break;
}
}
return(0);
}
int
add_cfgname(int state, nr_list_t *nr, char *t, int l)
{
// printf("%s(%d,%p,%s)\n", __FUNCTION__, state, nr, t);
if (nr) {
switch(state) {
default:
strcpy(nr->name, t);
break;
}
}
return(0);
}
int
add_cfgval(int state, nr_list_t *nr, ulong val)
{
if (nr) {
} else {
switch(state) {
case ST_DEB:
global_debug = val;
break;
case ST_PORT:
rtp_port = val;
break;
}
}
return(0);
}
int
add_cfgflag(int state, nr_list_t *nr, int flag)
{
if (nr) {
nr->flags ^= flag;
} else {
default_flags ^= flag;
}
return(0);
}
int
add_path(int state, char *t, int l)
{
// printf("%s(%d,%s)\n", __FUNCTION__, state, t);
if (l<1)
return(0);
switch(state) {
default:
fprintf(stderr, "%s: Unknown state(%d) text(%s)\n", __FUNCTION__,
state, t);
case ST_RCF:
strcpy(RecordCtrlFile, t);
break;
case ST_RFP:
strcpy(RecordFilePath, t);
if (RecordFilePath[l-1] != '/') {
RecordFilePath[l] = '/';
RecordFilePath[l+1] = 0;
}
break;
}
return(0);
}

133
voip/rtp.h Normal file
View File

@ -0,0 +1,133 @@
/*
* rtp.h -- RTP header file
* RTP draft: November 1994 version
*
* $Id: rtp.h,v 0.9 2003/08/27 07:33:03 kkeil Exp $
*/
#define RTP_SEQ_MOD (1<<16)
#define RTP_TS_MOD (0xffffffff)
/*
* Current type value.
*/
#define RTP_VERSION 2
#define RTP_MAX_SDES 256 /* maximum text length for SDES */
typedef enum {
RTCP_SR = 200,
RTCP_RR = 201,
RTCP_SDES = 202,
RTCP_BYE = 203,
RTCP_APP = 204
} rtcp_type_t;
typedef enum {
RTCP_SDES_END = 0,
RTCP_SDES_CNAME = 1,
RTCP_SDES_NAME = 2,
RTCP_SDES_EMAIL = 3,
RTCP_SDES_PHONE = 4,
RTCP_SDES_LOC = 5,
RTCP_SDES_TOOL = 6,
RTCP_SDES_NOTE = 7,
RTCP_SDES_PRIV = 8,
RTCP_SDES_IMG = 9,
RTCP_SDES_DOOR = 10,
RTCP_SDES_SOURCE = 11
} rtcp_sdes_type_t;
typedef enum {
AE_PCMU,
AE_1016,
AE_G721,
AE_GSM,
AE_G723,
AE_IDVI,
AE_LPC,
AE_PCMA,
AE_L16,
AE_G728,
AE_MAX
} audio_encoding_t;
typedef struct {
audio_encoding_t encoding; /* type of encoding (differs) */
unsigned sample_rate; /* sample frames per second */
unsigned channels; /* number of interleaved channels */
} audio_descr_t;
typedef struct {
unsigned int version:2; /* protocol version */
unsigned int p:1; /* padding flag */
unsigned int x:1; /* header extension flag */
unsigned int cc:4; /* CSRC count */
unsigned int m:1; /* marker bit */
unsigned int pt:7; /* payload type */
u_int16_t seq; /* sequence number */
u_int32_t ts; /* timestamp */
u_int32_t ssrc; /* synchronization source */
u_int32_t csrc[1]; /* optional CSRC list */
} rtp_hdr_t;
typedef struct {
unsigned int version:2; /* protocol version */
unsigned int p:1; /* padding flag */
unsigned int count:5; /* varies by payload type */
unsigned int pt:8; /* payload type */
u_int16_t length; /* packet length in words, without this word */
} rtcp_common_t;
/* reception report */
typedef struct {
u_int32_t ssrc; /* data source being reported */
unsigned int fraction:8; /* fraction lost since last SR/RR */
int lost:24; /* cumulative number of packets lost (signed!) */
u_int32_t last_seq; /* extended last sequence number received */
u_int32_t jitter; /* interarrival jitter */
u_int32_t lsr; /* last SR packet from this source */
u_int32_t dlsr; /* delay since last SR packet */
} rtcp_rr_t;
typedef struct {
u_int8_t type; /* type of SDES item (rtcp_sdes_type_t) */
u_int8_t length; /* length of SDES item (in octets) */
char data[1]; /* text, not zero-terminated */
} rtcp_sdes_item_t;
/* one RTCP packet */
typedef struct {
rtcp_common_t common; /* common header */
union {
/* sender report (SR) */
struct {
u_int32_t ssrc; /* source this RTCP packet refers to */
u_int32_t ntp_sec; /* NTP timestamp */
u_int32_t ntp_frac;
u_int32_t rtp_ts; /* RTP timestamp */
u_int32_t psent; /* packets sent */
u_int32_t osent; /* octets sent */
/* variable-length list */
rtcp_rr_t rr[1];
} sr;
/* reception report (RR) */
struct {
u_int32_t ssrc; /* source this generating this report */
/* variable-length list */
rtcp_rr_t rr[1];
} rr;
/* BYE */
struct {
u_int32_t src[1]; /* list of sources */
/* can't express trailing text */
} bye;
/* source description (SDES) */
struct rtcp_sdes_t {
u_int32_t src; /* first SSRC/CSRC */
rtcp_sdes_item_t item[1]; /* list of SDES items */
} sdes;
} r;
} rtcp_t;

858
voip/rtpacket.c Normal file
View File

@ -0,0 +1,858 @@
/*
RTP input packet construction and parsing
*/
#include <pwd.h>
#include <sys/param.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include "g711.h"
#include "rtpacket.h"
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
audio_descr_t adt[] = {
/* enc sample ch */
{AE_PCMU, 8000, 1}, /* 0 PCMU */
{AE_MAX, 8000, 1}, /* 1 1016 */
{AE_G721, 8000, 1}, /* 2 G721 */
{AE_GSM, 8000, 1}, /* 3 GSM */
{AE_G723, 8000, 1}, /* 4 Unassigned */
{AE_IDVI, 8000, 1}, /* 5 DVI4 */
{AE_IDVI, 16000, 1}, /* 6 DVI4 */
{AE_LPC, 8000, 1}, /* 7 LPC */
{AE_PCMA, 8000, 1}, /* 8 PCMA */
{AE_MAX, 0, 1}, /* 9 G722 */
{AE_L16, 44100, 2}, /* 10 L16 */
{AE_L16, 44100, 1}, /* 11 L16 */
{AE_MAX, 0, 1}, /* 12 */
};
#define MAX_MISORDER 100
#define MAX_DROPOUT 3000
/* ISRTP -- Determine if a packet is RTP or not. If so, convert
in place into a sound buffer. */
int isrtp(pkt, len)
unsigned char *pkt;
int len;
{
#ifdef RationalWorld
rtp_hdr_t *rh = (rtp_hdr_t *) pkt;
#endif
unsigned int r_version, r_p, r_x, r_cc, r_m, r_pt,
r_seq, r_ts;
/* Tear apart the header in a byte- and bit field-order
independent fashion. */
r_version = (pkt[0] >> 6) & 3;
r_p = !!(pkt[0] & 0x20);
r_x = !!(pkt[0] & 0x10);
r_cc = pkt[0] & 0xF;
r_m = !!(pkt[1] & 0x80);
r_pt = pkt[1] & 0x1F;
r_seq = ntohs(*((short *) (pkt + 2)));
r_ts = ntohl(*((long *) (pkt + 4)));
if (
#ifdef RationalWorld
rh->version == RTP_VERSION && /* Version ID correct */
rh->pt < ELEMENTS(adt) && /* Payload type credible */
adt[rh->pt].sample_rate != 0 && /* Defined payload type */
/* Padding, if present, is plausible */
(!rh->p || (pkt[len - 1] < (len - (12 + 4 * rh->cc))))
#else
r_version == RTP_VERSION && /* Version ID correct */
r_pt < ELEMENTS(adt) && /* Payload type credible */
adt[r_pt].sample_rate != 0 && /* Defined payload type */
/* Padding, if present, is plausible */
(!r_p || (pkt[len - 1] < (len - (12 + 4 * r_cc))))
#endif
) {
unsigned char *payload;
int lex, paylen;
/* Length of fixed header extension, if any */
lex = r_x ? (ntohs(*((short *) (pkt + 2 + 12 + 4 * r_cc))) + 1) * 4 : 0;
payload = pkt + (12 + 4 * r_cc) + lex; /* Start of payload */
paylen = len - ((12 + 4 * r_cc) + /* Length of payload */
lex + (r_p ? pkt[len - 1] : 0));
return TRUE;
}
return FALSE;
}
/* ISVALIDRTCPPACKET -- Consistency check a packet to see if
is a compliant RTCP packet. Note that
since this must also accept Speak Freely
SDES packets, the test on the protocol is
not as tight as were it exclusively for
RTP. */
int isValidRTCPpacket(p, len)
unsigned char *p;
int len;
{
unsigned char *end;
if (((((p[0] >> 6) & 3) != RTP_VERSION) && /* Version incorrect ? */
((((p[0] >> 6) & 3) != 1))) || /* Allow Speak Freely too */
((p[0] & 0x20) != 0) || /* Padding in first packet ? */
((p[1] != RTCP_SR) && (p[1] != RTCP_RR))) { /* First item not SR or RR ? */
return FALSE;
}
end = p + len;
do {
/* Advance to next subpacket */
p += (ntohs(*((short *) (p + 2))) + 1) * 4;
} while (p < end && (((p[0] >> 6) & 3) == RTP_VERSION));
return p == end;
}
/* ISRTCPBYEPACKET -- Test if this RTCP packet contains a BYE. */
int isRTCPByepacket(p, len)
unsigned char *p;
int len;
{
unsigned char *end;
int sawbye = FALSE;
/* Version incorrect ? */
if ((((p[0] >> 6) & 3) != RTP_VERSION && ((p[0] >> 6) & 3) != 1) ||
((p[0] & 0x20) != 0) || /* Padding in first packet ? */
((p[1] != RTCP_SR) && (p[1] != RTCP_RR))) { /* First item not SR or RR ? */
return FALSE;
}
end = p + len;
do {
if (p[1] == RTCP_BYE) {
sawbye = TRUE;
}
/* Advance to next subpacket */
p += (ntohs(*((short *) (p + 2))) + 1) * 4;
} while (p < end && (((p[0] >> 6) & 3) == RTP_VERSION));
return (p == end) && sawbye;
}
/* ISRTCPAPPPACKET -- Test if this RTCP packet contains a APP item
with a given name. If so, returns a pointer
to the APP sub-packet in app_ptr. */
int isRTCPAPPpacket(p, len, name, app_ptr)
unsigned char *p;
int len;
char *name;
unsigned char **app_ptr;
{
unsigned char *end;
*app_ptr = NULL;
/* Version incorrect ? */
if ((((p[0] >> 6) & 3) != RTP_VERSION && ((p[0] >> 6) & 3) != 1) ||
((p[0] & 0x20) != 0) || /* Padding in first packet ? */
((p[1] != RTCP_SR) && (p[1] != RTCP_RR))) { /* First item not SR or RR ? */
return FALSE;
}
end = p + len;
do {
if ((p[1] == RTCP_APP) && (memcmp(p + 8, name, 4) == 0)) {
*app_ptr = p;
return TRUE;
}
/* Advance to next subpacket */
p += (ntohs(*((short *) (p + 2))) + 1) * 4;
} while (p < end && (((p[0] >> 6) & 3) == RTP_VERSION));
return FALSE;
}
#if 0
/* RTP_MAKE_SDES -- Generate a source description for this
user, based either on information obtained
from the password file or supplied by
environment variables. Strict construction
of the RTP specification requires every
SDES packet to be a composite which begins
with a sender or receiver report. If the
"strict" argument is true, we'll comply with
this. Unfortunately, Look Who's Listening
Server code was not aware of this little
twist when originally implemented, so it will
take some time to transition all the running
servers to composite packet aware code. */
int rtp_make_sdes(pkt, ssrc_i, port, strict)
char **pkt;
unsigned long ssrc_i;
int port, strict;
{
unsigned char zp[1500];
unsigned char *p = zp;
rtcp_t *rp;
unsigned char *ap;
char *sp, *ep;
int l, hl;
struct passwd *pw;
char s[256], ev[1024];
#define addSDES(item, text) *ap++ = item; *ap++ = l = strlen(text); \
bcopy(text, ap, l); ap += l
hl = 0;
if (strict) {
*p++ = RTP_VERSION << 6;
*p++ = RTCP_RR;
*p++ = 0;
*p++ = 1;
*((long *) p) = htonl(ssrc_i);
p += 4;
hl = 8;
}
rp = (rtcp_t *) p;
#ifdef RationalWorld
rp->common.version = RTP_VERSION;
rp->common.p = 0;
rp->common.count = 1;
rp->common.pt = RTCP_SDES;
#else
*((short *) p) = htons((RTP_VERSION << 14) | RTCP_SDES | (1 << 8));
#endif
rp->r.sdes.src = htonl(ssrc_i);
ap = (unsigned char *) rp->r.sdes.item;
ep = getenv("SPEAKFREE_ID");
if (ep != NULL) {
if (strlen(ep) == 0) {
ep = NULL;
} else {
strcpy(ev, ep);
ep = ev;
}
}
/* Build canonical name for this user. This is generally
a name which can be used for "talk" and "finger", and
is not necessarily the user's E-mail address. */
if ((sp = getenv("SPEAKFREE_CNAME")) != NULL && strlen(sp) > 0) {
/* If strict, drop leading asterisk that's used to request an
unlisted entry on an LWL server. */
if (strict && sp[0] == '*') {
sp++;
}
addSDES(RTCP_SDES_CNAME, sp);
} else {
pw = getpwuid(getuid());
if (pw != NULL) {
char dn[64];
char hn[MAXHOSTNAMELEN];
dn[0] = hn[0] = 0;
getdomainname(dn, sizeof dn);
gethostname(hn, sizeof hn);
if (dn[0] != 0) {
sprintf(s, "%s@%s", pw->pw_name, dn);
} else {
struct hostent *h;
struct in_addr naddr;
h = gethostbyname(hn);
if (strchr(h->h_name, '.') != NULL) {
sprintf(s, "%s@%s", pw->pw_name, h->h_name);
} else {
bcopy(h->h_addr, &naddr, sizeof naddr);
sprintf(s, "%s@%s", pw->pw_name, inet_ntoa(naddr));
}
}
addSDES(RTCP_SDES_CNAME, s);
if (ep == NULL && pw->pw_gecos != NULL) {
char *gc = strchr(pw->pw_gecos, ',');
if (gc != NULL) {
*gc = 0;
}
addSDES(RTCP_SDES_NAME, pw->pw_gecos);
}
} else {
#ifdef Solaris
{ char s[12];
sysinfo(SI_HW_SERIAL, s, 12);
sprintf(s, "Unknown@%s.hostid.net", s);
}
#else
sprintf(s, "Unknown@%lu.hostid.net", gethostid());
#endif
addSDES(RTCP_SDES_CNAME, s);
}
}
/* If a SPEAKFREE_ID environment variable is present,
parse the items it contains. Format:
SPEAKFREE_ID=<full name>:<E-mail address>:<phone number>:<location>
*/
if (ep != NULL) {
int i;
static int items[] = { RTCP_SDES_NAME, RTCP_SDES_EMAIL,
RTCP_SDES_PHONE, RTCP_SDES_LOC };
char *np;
for (i = 0; i < ELEMENTS(items); i++) {
while (*ep && isspace(*ep)) {
ep++;
}
if (*ep == 0) {
break;
}
if ((np = strchr(ep, ':')) != NULL) {
*np++ = 0;
} else {
np = NULL;
}
if (strlen(ep) > 0) {
/* If strict, drop leading asterisk that's used to request an
unlisted entry on an LWL server. */
if (strict && items[i] == RTCP_SDES_EMAIL && ep[0] == '*') {
ep++;
}
addSDES(items[i], ep);
}
if (np == NULL) {
break;
}
ep = np;
}
}
addSDES(RTCP_SDES_TOOL, "Speak Freely for Unix");
if (!strict) {
/* If a port number is specified, add a PRIV item indicating
the port we're communicating on. */
if (port >= 0) {
char s[20];
sprintf(s, "\001P%d", port);
addSDES(RTCP_SDES_PRIV, s);
}
}
*ap++ = RTCP_SDES_END;
*ap++ = 0;
l = ap - p;
rp->common.length = htons(((l + 3) / 4) - 1);
l = hl + ((ntohs(rp->common.length) + 1) * 4);
/* Okay, if the total length of this packet is not an odd
multiple of 4 bytes, we're going to put a pad at the
end of it. Why? Because we may encrypt the packet
later and that requires it be a multiple of 8 bytes,
and we don't want the encryption code to have to
know all about our weird composite packet structure.
Oh yes, there's no reason to do this if strict isn't
set, since we never encrypt packets sent to a Look
Who's Listening server.
Why an odd multiple of 4 bytes, I head you ask?
Because when we encrypt an RTCP packet, we're required
to prefix it with four random bytes to deter a known
plaintext attack, and since the total buffer we
encrypt, including the random bytes, has to be a
multiple of 8 bytes, the message needs to be an odd
multiple of 4. */
if (strict) {
int pl = (l & 4) ? l : l + 4;
if (pl > l) {
int pad = pl - l;
bzero(zp + l, pad); /* Clear pad area to zero */
zp[pl - 1] = pad; /* Put pad byte count at end of packet */
p[0] |= 0x20; /* Set the "P" bit in the header of the
SDES (last in message) packet */
/* If we've added an additional word to
the packet, adjust the length in the
SDES message, which must include the
pad */
rp->common.length = htons(ntohs(rp->common.length) + ((pad) / 4));
l = pl; /* Include pad in length of packet */
}
}
*pkt = (char *) malloc(l);
if (*pkt != NULL) {
bcopy(zp, *pkt, l);
return l;
}
return 0;
}
/* RTP_MAKE_SDES_S-- Generate a source description for this
servers to composite packet aware code. */
int rtp_make_sdes_s(pkt, strict, r)
char **pkt;
struct rtcp_sdes_request *r;
int strict;
{
unsigned char zp[1500];
unsigned char *p = zp;
unsigned long *ssrc;
rtcp_t *rp;
unsigned char *ap;
int l, hl, i;
#define addSDES(item, text) *ap++ = item; *ap++ = l = strlen(text); \
bcopy(text, ap, l); ap += l
ssrc = (unsigned long *)r->ssrc;
hl = 0;
if (strict) {
*p++ = RTP_VERSION << 6;
*p++ = RTCP_RR;
*p++ = 0;
*p++ = 1;
*((long *) p) = htonl(*ssrc);
p += 4;
hl = 8;
}
rp = (rtcp_t *) p;
#ifdef RationalWorld
rp->common.version = RTP_VERSION;
rp->common.p = 0;
rp->common.count = 1;
rp->common.pt = RTCP_SDES;
#else
*((short *) p) = htons((RTP_VERSION << 14) | RTCP_SDES | (1 << 8));
#endif
rp->r.sdes.src = htonl(*ssrc);
ap = (unsigned char *) rp->r.sdes.item;
for (i = 0; i < r->nitems; i++) {
addSDES(r->item[i].r_item, r->item[i].r_text);
}
*ap++ = RTCP_SDES_END;
*ap++ = 0;
l = ap - p;
rp->common.length = htons(((l + 3) / 4) - 1);
l = hl + ((ntohs(rp->common.length) + 1) * 4);
/* Okay, if the total length of this packet is not an odd
multiple of 4 bytes, we're going to put a pad at the
end of it. Why? Because we may encrypt the packet
later and that requires it be a multiple of 8 bytes,
and we don't want the encryption code to have to
know all about our weird composite packet structure.
Oh yes, there's no reason to do this if strict isn't
set, since we never encrypt packets sent to a Look
Who's Listening server.
Why an odd multiple of 4 bytes, I head you ask?
Because when we encrypt an RTCP packet, we're required
to prefix it with four random bytes to deter a known
plaintext attack, and since the total buffer we
encrypt, including the random bytes, has to be a
multiple of 8 bytes, the message needs to be an odd
multiple of 4. */
if (strict) {
int pl = (l & 4) ? l : l + 4;
if (pl > l) {
int pad = pl - l;
bzero(zp + l, pad); /* Clear pad area to zero */
zp[pl - 1] = pad; /* Put pad byte count at end of packet */
p[0] |= 0x20; /* Set the "P" bit in the header of the
SDES (last in message) packet */
/* If we've added an additional word to
the packet, adjust the length in the
SDES message, which must include the
pad */
rp->common.length = htons(ntohs(rp->common.length) + ((pad) / 4));
l = pl; /* Include pad in length of packet */
}
}
if (*pkt == NULL)
*pkt = (char *) malloc(l);
if (*pkt != NULL) {
bcopy(zp, *pkt, l);
return l;
}
return 0;
}
#endif
/* RTP_MAKE_BYE -- Create a "BYE" RTCP packet for this connection. */
int rtp_make_bye(p, ssrc_i, raison, strict)
unsigned char *p;
unsigned long ssrc_i;
char *raison;
int strict;
{
rtcp_t *rp;
unsigned char *ap, *zp;
int l, hl;
/* If requested, prefix the packet with a null receiver
report. This is required by the RTP spec, but is not
required in packets sent only to the Look Who's Listening
server. */
zp = p;
hl = 0;
if (strict) {
*p++ = RTP_VERSION << 6;
*p++ = RTCP_RR;
*p++ = 0;
*p++ = 1;
*((long *) p) = htonl(ssrc_i);
p += 4;
hl = 8;
}
rp = (rtcp_t *) p;
#ifdef RationalWorld
rp->common.version = RTP_VERSION;
rp->common.p = 0;
rp->common.count = 1;
rp->common.pt = RTCP_BYE;
#else
*((short *) p) = htons((RTP_VERSION << 14) | RTCP_BYE | (1 << 8));
#endif
rp->r.bye.src[0] = htonl(ssrc_i);
ap = (unsigned char *) rp->r.sdes.item;
l = 0;
if (raison != NULL) {
l = strlen(raison);
if (l > 0) {
*ap++ = l;
bcopy(raison, ap, l);
ap += l;
}
}
while ((ap - p) & 3) {
*ap++ = 0;
}
l = ap - p;
rp->common.length = htons((l / 4) - 1);
l = hl + ((ntohs(rp->common.length) + 1) * 4);
/* If strict, pad the composite packet to an odd multiple of 4
bytes so that if we decide to encrypt it we don't have to worry
about padding at that point. */
if (strict) {
int pl = (l & 4) ? l : l + 4;
if (pl > l) {
int pad = pl - l;
bzero(zp + l, pad); /* Clear pad area to zero */
zp[pl - 1] = pad; /* Put pad byte count at end of packet */
p[0] |= 0x20; /* Set the "P" bit in the header of the
SDES (last in message) packet */
/* If we've added an additional word to
the packet, adjust the length in the
SDES message, which must include the
pad */
rp->common.length = htons(ntohs(rp->common.length) + ((pad) / 4));
l = pl; /* Include pad in length of packet */
}
}
return l;
}
/* RTP_MAKE_APP -- Create a "APP" (application-defined) RTCP packet
for this connection with the given type (name)
and content. */
int rtp_make_app(p, ssrc_i, strict, type, content, len)
unsigned char *p, *content;
unsigned long ssrc_i;
int strict, len;
char *type;
{
rtcp_t *rp;
unsigned char *ap, *zp;
int l, hl;
/* If requested, prefix the packet with a null receiver
report. This is required by the RTP spec, but is not
required in packets sent only to other copies of Speak
Freely. */
zp = p;
hl = 0;
if (strict) {
*p++ = RTP_VERSION << 6;
*p++ = RTCP_RR;
*p++ = 0;
*p++ = 1;
*((long *) p) = htonl(ssrc_i);
p += 4;
hl = 8;
}
rp = (rtcp_t *) p;
*((short *) p) = htons((RTP_VERSION << 14) | RTCP_APP | (1 << 8));
rp->r.bye.src[0] = htonl(ssrc_i);
ap = p + 8;
bcopy(type, ap, 4);
ap += 4;
bcopy(content, ap, len);
ap += len;
while ((ap - p) & 3) {
*ap++ = 0;
}
l = ap - p;
rp->common.length = htons((l / 4) - 1);
l = hl + ((ntohs(rp->common.length) + 1) * 4);
/* If strict, pad the composite packet to an odd multiple of 4
bytes so that if we decide to encrypt it we don't have to worry
about padding at that point. */
if (strict) {
int pl = (l & 4) ? l : l + 4;
if (pl > l) {
int pad = pl - l;
bzero(zp + l, pad); /* Clear pad area to zero */
zp[pl - 1] = pad; /* Put pad byte count at end of packet */
p[0] |= 0x20; /* Set the "P" bit in the header of the
SDES (last in message) packet */
/* If we've added an additional word to
the packet, adjust the length in the
SDES message, which must include the
pad */
rp->common.length = htons(ntohs(rp->common.length) + ((pad) / 4));
l = pl; /* Include pad in length of packet */
}
}
return l;
}
#if 0
/* RTPOUT -- Convert a sound buffer into an RTP packet, given the
SSRC, timestamp, and sequence number appropriate for the
next packet sent to this connection. */
int rtpout(sb, ssrc_i, timestamp_i, seq_i, spurt)
soundbuf *sb;
unsigned long ssrc_i, timestamp_i;
unsigned short seq_i;
int spurt;
{
soundbuf rp;
rtp_hdr_t *rh = (rtp_hdr_t *) &rp;
int pl = 0;
#ifdef RationalWorld
rh->version = RTP_VERSION;
rh->p = 0;
rh->x = 0;
rh->cc = 0;
rh->m = !!spurt;
#else
*((short *) rh) = htons((RTP_VERSION << 14) | (spurt ? 0x80 : 0));
#endif
rh->seq = htons(seq_i);
rh->ts = htonl(timestamp_i);
rh->ssrc = htonl(ssrc_i);
/* GSM */
if (sb->compression & fCompGSM) {
#ifdef RationalWorld
rh->pt = 3;
#else
((char *) rh)[1] = 3;
#endif
bcopy(sb->buffer.buffer_val + 2, ((char *) &rp) + 12,
(int) sb->buffer.buffer_len - 2);
pl = (sb->buffer.buffer_len - 2) + 12;
/* ADPCM */
} else if (sb->compression & fCompADPCM) {
#ifdef RationalWorld
rh->pt = 5;
#else
((char *) rh)[1] = 5;
#endif
bcopy(sb->buffer.buffer_val, ((char *) &rp) + 12 + 4,
(int) sb->buffer.buffer_len - 3);
bcopy(sb->buffer.buffer_val + ((int) sb->buffer.buffer_len - 3),
((char *) &rp) + 12, 3);
((char *) &rp)[15] = 0;
pl = (sb->buffer.buffer_len + 1) + 12;
/* LPC */
} else if (sb->compression & fCompLPC) {
int i, n = (sb->buffer.buffer_len - 2) / 14;
char *ip = (char *) (sb->buffer.buffer_val + 2),
*op = (char *) &rp + 12;
#ifdef RationalWorld
rh->pt = 7;
#else
((char *) rh)[1] = 7;
#endif
for (i = 0; i < n; i++) {
bcopy(ip, op, 3);
bcopy(ip + 4, op + 3, 10);
op[13] = 0;
ip += 14;
op += 14;
}
pl = 12 + 14 * n;
} else if (sb->compression & fEnculaw) {
#ifdef RationalWorld
rh->pt = 0;
#else
((char *) rh)[1] = 0;
#endif
bcopy(sb->buffer.buffer_val, ((char *) &rp) + 12,
(int) sb->buffer.buffer_len);
pl = (int) sb->buffer.buffer_len + 12;
} else { /* default Uncompressed PCMA samples fEncAlaw */
#ifdef RationalWorld
rh->pt = 8;
#else
((char *) rh)[1] = 8;
#endif
bcopy(sb->buffer.buffer_val, ((char *) &rp) + 12,
(int) sb->buffer.buffer_len);
pl = (int) sb->buffer.buffer_len + 12;
}
if (pl > 0) {
bcopy((char *) &rp, (char *) sb, pl);
}
return pl;
}
#endif
/* PARSESDES -- Look for an SDES message in a possibly composite
RTCP packet and extract pointers to selected items
into the caller's structure. */
int parseSDES(packet, r)
unsigned char *packet;
struct rtcp_sdes_request *r;
{
int i, success = FALSE;
unsigned char *p = packet;
/* Initialise all the results in the request packet to NULL. */
for (i = 0; i < r->nitems; i++) {
r->item[i].r_text = NULL;
}
/* Walk through the individual items in a possibly composite
packet until we locate an SDES. This allows us to accept
packets that comply with the RTP standard that all RTCP packets
begin with an SR or RR. */
while ((p[0] >> 6 & 3) == RTP_VERSION || (p[0] >> 6 & 3) == 1) {
if ((p[1] == RTCP_SDES) && ((p[0] & 0x1F) > 0)) {
unsigned char *cp = p + 8,
*lp = cp + (ntohs(*((short *) (p + 2))) + 1) * 4;
bcopy(p + 4, r->ssrc, 4);
while (cp < lp) {
unsigned char itype = *cp;
if (itype == RTCP_SDES_END) {
break;
}
/* Search for a match in the request and fill the
first unused matching item. We do it this way to
permit retrieval of multiple PRIV items in the same
packet. */
for (i = 0; i < r->nitems; i++) {
if (r->item[i].r_item == itype &&
r->item[i].r_text == NULL) {
r->item[i].r_text = (char *) cp;
success = TRUE;
break;
}
}
cp += cp[1] + 2;
}
break;
}
/* If not of interest to us, skip to next subpacket. */
p += (ntohs(*((short *) (p + 2))) + 1) * 4;
}
return success;
}
/* COPYSDESITEM -- Copy an SDES item to a zero-terminated user
string. */
void copySDESitem(s, d)
char *s, *d;
{
int len = s[1] & 0xFF;
bcopy(s + 2, d, len);
d[len] = 0;
}

32
voip/rtpacket.h Normal file
View File

@ -0,0 +1,32 @@
#ifndef H_RTPACKET_H
#define H_RTPACKET_H
#include "rtp.h"
#define ELEMENTS(array) (sizeof(array)/sizeof((array)[0]))
#define fEnculaw 0x100000
#define fEncAlaw 0x200000
struct rtcp_sdes_request_item {
unsigned char r_item;
char *r_text;
};
struct rtcp_sdes_request {
int nitems; /* Number of items requested */
unsigned char ssrc[4]; /* Source identifier */
struct rtcp_sdes_request_item item[10]; /* Request items */
};
extern int isrtp(unsigned char *, int);
extern int isValidRTCPpacket(unsigned char *, int);
extern int isRTCPByepacket(unsigned char *, int);
extern int isRTCPAPPpacket(unsigned char *, int, char *, unsigned char **);
extern int rtp_make_sdes(char **, unsigned long, int, int);
extern int rtp_make_sdes_s(char **, int, struct rtcp_sdes_request *);
extern int rtp_make_bye(unsigned char *, unsigned long, char *, int);
extern int rtp_make_app(unsigned char *, unsigned long, int, char *,
unsigned char *, int);
extern int parseSDES(unsigned char *, struct rtcp_sdes_request *);
extern void copySDESitem(char *, char *);
#endif

3
voip/testlog Normal file
View File

@ -0,0 +1,3 @@
debug_init: debug_mask = 0
debug_init: debug_mask = 0
debug_close: debug channel now closed

13
voip/tstcfg Normal file
View File

@ -0,0 +1,13 @@
#
# tstsetup voip
#
DEBUG 066
PORT 2074
GSM
MSN 12345
MSN 888
VOIPNR 4566 pictra_client GSM
VOIPNR 4567 10.23.200.1
AUDIONR 789

29
voip/tstparse.c Normal file
View File

@ -0,0 +1,29 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "isdn_net.h"
#include "globals.h"
extern int parse_cfg(char *, manager_t *);
int main(argc,argv)
int argc;
char *argv[];
{
manager_t mgr;
nr_list_t *nr;
memset(&mgr, 0, sizeof(manager_t));
printf("Start: Debug %x Port %d Flags %x\n",
global_debug, rtp_port, default_flags);
parse_cfg("tstcfg", &mgr);
printf("AfterParse: Debug %x Port %d Flags %x\n",
global_debug, rtp_port, default_flags);
nr = mgr.nrlist;
while(nr) {
printf("nr(%s) len(%d) flg(%x) typ(%d) name(%s)\n",
nr->nr, nr->len, nr->flags, nr->typ, nr->name);
nr = nr->next;
}
return(0);
}

32
voip/vitimer.h Normal file
View File

@ -0,0 +1,32 @@
#ifndef VITIMER_H
#define VITIMER_H
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
typedef struct _vi_timer vi_timer_t;
typedef int (*timef_t)(void *, unsigned long, struct timeval *);
struct _vi_timer {
vi_timer_t *prev;
vi_timer_t *next;
struct timeval tv;
void *data;
unsigned long val;
timef_t func;
};
extern int run_vitimer(void);
extern void remove_vitimer(vi_timer_t *);
extern int init_vitimer(vi_timer_t *, void *, unsigned long, timef_t);
extern int add_vitimer_abs(vi_timer_t *, struct timeval *);
extern int add_vitimer_rel(vi_timer_t *, struct timeval *);
extern void clean_vitimer(void);
extern struct timeval *get_next_vitimer_time(void);
extern int get_next_vitimer_dist(struct timeval *);
#endif

1539
voip/voip_appl.c Normal file

File diff suppressed because it is too large Load Diff

832
voip/voip_isdn.c Normal file
View File

@ -0,0 +1,832 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <string.h>
#include <fcntl.h>
#include "g711.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include "isdn_net.h"
#include "l3dss1.h"
#include "helper.h"
#include "bchannel.h"
#include "tone.h"
#include "isound.h"
#include "globals.h"
#include "iapplication.h"
vapplication_t voip;
static int
getnext_record(FILE *f)
{
int opt = 0;
char line[128];
while(!feof(f)) {
if (fgets(line, 128, f)) {
// fprintf(stderr, "%s: line:%s", __FUNCTION__, line);
if (line[0]=='\n')
continue;
if (line[0]==0)
continue;
if (line[0]=='#')
continue;
sscanf(line,"%d", &opt);
return(opt);
}
}
return(0);
}
int
read_rec_ctrlfile(void)
{
FILE *f;
int opt;
manager_t *mgr = voip.mgr_lst;
if (RecordCtrlFile[0] == 0) {
dprint(DBGM_TOPLEVEL, "%s: no RecordCtrlFile\n", __FUNCTION__);
return(-ENOENT);
}
f = fopen(RecordCtrlFile, "r");
if (!f) {
dprint(DBGM_TOPLEVEL, "%s: cannot open %s: %s\n", __FUNCTION__,
RecordCtrlFile, strerror(errno));
return(-errno);
}
while(mgr) {
opt = getnext_record(f);
dprint(DBGM_TOPLEVEL, "%s: mgr %p ch1: %d\n", __FUNCTION__,
mgr, opt);
if (opt) {
mgr->bc[0].Flags |= FLG_BC_RECORD;
} else {
mgr->bc[0].Flags &= ~FLG_BC_RECORD;
}
opt = getnext_record(f);
dprint(DBGM_TOPLEVEL, "%s: mgr %p ch2: %d\n", __FUNCTION__,
mgr, opt);
if (opt) {
mgr->bc[1].Flags |= FLG_BC_RECORD;
} else {
mgr->bc[1].Flags &= ~FLG_BC_RECORD;
}
mgr = mgr->next;
}
fclose(f);
return(0);
}
static void
sig_usr1_handler(int sig)
{
dprint(DBGM_TOPLEVEL, "%s: got sig(%d)\n", __FUNCTION__, sig);
read_rec_ctrlfile();
signal(SIGUSR1, sig_usr1_handler);
}
#if 0
static void
sig_segfault(int sig, siginfo_t *si, void *arg) {
int i,*ip = arg;
dprint(DBGM_TOPLEVEL, "segfault %d, %p, %p\n",
sig, si, arg);
if (si) {
dprint(DBGM_TOPLEVEL, "si: sig(%d) err(%d) code(%d) pid(%d)\n",
si->si_signo, si->si_errno, si->si_code, si->si_pid);
dprint(DBGM_TOPLEVEL, "si: status(%x) value(%x)\n",
si->si_status, si->si_value.sival_int);
dprint(DBGM_TOPLEVEL, "si: int(%x) ptr(%p) addr(%p)\n",
si->si_int, si->si_ptr, si->si_addr);
}
if (ip) {
ip -= 10;
for(i=0;i<20;i++)
dprint(DBGM_TOPLEVEL, "ip %3d: %x\n", i-10, ip[i]);
}
ip = (int *)si;
if (ip) {
ip -= 10;
for(i=0;i<20;i++)
dprint(DBGM_TOPLEVEL, "si %3d: %x\n", i-10, ip[i]);
}
}
#endif
static void
term_handler(int sig)
{
pthread_t tid;
manager_t *mgr = voip.mgr_lst;
tid = pthread_self();
dprint(DBGM_TOPLEVEL,"signal %d received from thread %ld\n", sig, tid);
voip.flags |= AP_FLG_VOIP_ABORT;
while(mgr) {
term_netstack(mgr->nst);
term_bchannel(&mgr->bc[0]);
term_bchannel(&mgr->bc[1]);
mgr = mgr->next;
}
}
#if 0
static void
child_handler(int sig)
{
manager_t *mgr = voip.mgr_lst;
pid_t pid;
int stat;
dprint(DBGM_TOPLEVEL,"signal %d received\n", sig);
while (mgr) {
if (mgr->bc[0].pid) {
pid = waitpid(mgr->bc[0].pid, &stat, WNOHANG);
dprint(DBGM_TOPLEVEL, "%s: waitpid(%d) stat(%x) ret(%d)\n", __FUNCTION__,
mgr->bc[0].pid, stat, pid);
if (mgr->bc[0].pid == pid) {
mgr->bc[0].pid = 0;
// if (mgr->bc[0].state == BC_STATE_ACTIV)
break;
}
}
if (mgr->bc[1].pid) {
pid = waitpid(mgr->bc[1].pid, &stat, WNOHANG);
dprint(DBGM_TOPLEVEL, "%s: waitpid(%d) stat(%x) ret(%d)\n", __FUNCTION__,
mgr->bc[1].pid, stat, pid);
if (mgr->bc[1].pid == pid) {
mgr->bc[1].pid = 0;
// if (mgr->bc[1].state == BC_STATE_ACTIV)
break;
}
}
mgr = mgr->next;
}
signal(SIGCHLD, child_handler);
}
#endif
static void *
read_audio(void *arg)
{
isound_t *ia = arg;
pthread_t tid;
fd_set rfd, efd;
int ret,i;
tid = pthread_self();
dprint(DBGM_TOPLEVEL, "%s: tid %ld\n", __FUNCTION__, tid);
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
while(1) {
FD_ZERO(&rfd);
FD_ZERO(&efd);
FD_SET(ia->data, &rfd);
FD_SET(ia->data, &efd);
ret = select(ia->data +1, &rfd, NULL, &efd, NULL);
if (ret < 0) {
dprint(DBGM_TOPLEVEL, "%s: select error %d %s\n", __FUNCTION__,
errno, strerror(errno));
if (errno == EAGAIN)
continue;
if (errno == EINTR)
continue;
}
if (FD_ISSET(ia->data, &rfd)) {
ret = read(ia->data, ia->rtmp, MAX_AUDIO_READ);
if (ret < 0) {
dprint(DBGM_TOPLEVEL, "%s: read error %d %s\n", __FUNCTION__,
errno, strerror(errno));
if (errno == EAGAIN)
continue;
continue;
}
if (!ret) {
dprint(DBGM_TOPLEVEL, "%s: zero read\n", __FUNCTION__);
continue;
}
if (ret > ibuf_freecount(ia->rbuf)) {
dprint(DBGM_TOPLEVEL, "%s: rbuf overflow %d/%d\n", __FUNCTION__,
ret, ibuf_freecount(ia->rbuf));
ret = ibuf_freecount(ia->rbuf);
}
for (i=0; i<ret; i++)
ia->rtmp[i] = ulaw2alaw(ia->rtmp[i]);
ibuf_memcpy_w(ia->rbuf, ia->rtmp, ret);
if (ia->rbuf->rsem)
sem_post(ia->rbuf->rsem);
}
if (FD_ISSET(ia->data, &efd)) {
dprint(DBGM_TOPLEVEL, "%s: exception\n", __FUNCTION__);
break;
}
}
return NULL;
}
static void *
work_audio(void *arg)
{
isound_t *ia = arg;
pthread_t tid;
int ret, i;
tid = pthread_self();
dprint(DBGM_TOPLEVEL, "%s: tid %ld\n", __FUNCTION__, tid);
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
while(1) {
sem_wait(&ia->work);
if (ia->wlen) {
ret = write(ia->data, &ia->wtmp[ia->widx], ia->wlen);
if (ret == -1)
continue;
if (ret < ia->wlen) {
ia->wlen -= ret;
ia->widx += ret;
continue;
}
ia->wlen = 0;
ia->widx = 0;
}
if ((ia->wlen = ibuf_usedcount(ia->sbuf))) {
ibuf_memcpy_r(ia->wtmp, ia->sbuf, ia->wlen);
for (i=0; i<ia->wlen; i++)
ia->wtmp[i] = alaw2ulaw(ia->wtmp[i]);
ret = write(ia->data, &ia->wtmp[0], ia->wlen);
if (ret == -1)
continue;
if (ret < ia->wlen) {
ia->wlen -= ret;
ia->widx = ret;
continue;
}
ia->wlen = 0;
}
}
return(NULL);
}
int
setup_voip(iapplication_t *ap, bchannel_t *bc)
{
isound_t *ia;
int ret;
dprint(DBGM_APPL, "%s(%p, %p)\n", __FUNCTION__, ap, bc);
if (!bc)
return(-EINVAL);
if (!ap)
return(-EINVAL);
if (!bc->sbuf)
return(-EINVAL);
if (bc->rbuf)
return(-EINVAL);
bc->rbuf = init_ibuffer(2048);
if (!bc->rbuf)
return(-ENOMEM);
bc->rbuf->wsem = &bc->work;
ia = malloc(sizeof(isound_t));
if (!ia)
return(-ENOMEM);
memset(ia, 0, sizeof(isound_t));
ap->data2 = ia;
sem_init(&ia->work, 0, 0);
ia->sbuf = bc->rbuf;
ia->rbuf = bc->sbuf;
bc->sbuf->wsem = &ia->work;
bc->rbuf->rsem = &ia->work;
ret = pthread_create(&ap->tid, NULL, voip_sender, (void *)ap);
dprint(DBGM_APPL, "%s: create voip_sender %ld ret %d\n", __FUNCTION__,
ap->tid, ret);
return(ret);
}
int
close_voip(iapplication_t *ap, bchannel_t *bc)
{
isound_t *ia;
int ret, *retval;
dprint(DBGM_APPL, "%s(%p, %p)\n", __FUNCTION__, ap, bc);
if (!bc)
return(-EINVAL);
if (!ap)
return(-EINVAL);
ia = ap->data2;
ap->data2 = NULL;
ap->Flags &= ~AP_FLG_VOIP_ACTIV;
if (!ia)
return(-EINVAL);
ret = pthread_cancel(ap->tid);
dprint(DBGM_APPL, "%s: cancel sender ret(%d)\n", __FUNCTION__,
ret);
ret = pthread_join(ap->tid, (void *)&retval);
dprint(DBGM_APPL, "%s: join sender ret(%d) rval(%p)\n", __FUNCTION__,
ret, retval);
ia->sbuf = NULL;
ia->rbuf = NULL;
if (bc->sbuf)
bc->sbuf->wsem = NULL;
if (bc->rbuf)
free_ibuffer(bc->rbuf);
bc->rbuf = NULL;
ret = sem_destroy(&ia->work);
dprint(DBGM_APPL, "%s: sem_destroy work %d\n", __FUNCTION__,
ret);
free(ia);
return(0);
}
static int
setup_audio(iapplication_t *ap, bchannel_t *bc)
{
isound_t *ia;
int ret;
if (!bc)
return(-EINVAL);
if (!ap)
return(-EINVAL);
if (!bc->sbuf)
return(-EINVAL);
if (bc->rbuf)
return(-EINVAL);
bc->rbuf = init_ibuffer(2048);
if (!bc->rbuf)
return(-ENOMEM);
bc->rbuf->wsem = &bc->work;
ia = malloc(sizeof(isound_t));
if (!ia)
return(-ENOMEM);
memset(ia, 0, sizeof(isound_t));
sem_init(&ia->work, 0, 0);
ia->data = open("/dev/audio", O_RDWR | O_NONBLOCK);
if (ia->data < 0) {
free(ia);
dprint(DBGM_TOPLEVEL, "%s: open rdwr %d %s\n", __FUNCTION__,
errno, strerror(errno));
return(-errno);
}
ap->data2 = ia;
ia->sbuf = bc->rbuf;
ia->rbuf = bc->sbuf;
bc->sbuf->wsem = &ia->work;
bc->rbuf->rsem = &ia->work;
ret = pthread_create(&ia->rd_t, NULL, read_audio, (void *)ia);
dprint(DBGM_TOPLEVEL, "%s: create rd_t %ld ret %d\n", __FUNCTION__,
ia->rd_t, ret);
ret = pthread_create(&ia->wr_t, NULL, work_audio, (void *)ia);
dprint(DBGM_TOPLEVEL, "%s: create wr_t %ld ret %d\n", __FUNCTION__,
ia->wr_t, ret);
return(0);
}
static int
close_audio(iapplication_t *ap, bchannel_t *bc)
{
isound_t *ia;
int ret, *retval;
if (!bc)
return(-EINVAL);
if (!ap)
return(-EINVAL);
ia = ap->data2;
ap->data2 = NULL;
if (!ia)
return(-EINVAL);
close(ia->data);
ret = pthread_cancel(ia->rd_t);
dprint(DBGM_TOPLEVEL, "%s: cancel rd_t ret(%d)\n", __FUNCTION__,
ret);
ret = pthread_cancel(ia->wr_t);
dprint(DBGM_TOPLEVEL, "%s: cancel wr_t ret(%d)\n", __FUNCTION__,
ret);
ret = pthread_join(ia->rd_t, (void *)&retval);
dprint(DBGM_TOPLEVEL, "%s: join rd_t ret(%d) rval(%p)\n", __FUNCTION__,
ret, retval);
ret = pthread_join(ia->wr_t, (void *)&retval);
dprint(DBGM_TOPLEVEL, "%s: join wr_t ret(%d) rval(%p)\n", __FUNCTION__,
ret, retval);
ia->sbuf = NULL;
ia->rbuf = NULL;
if (bc->sbuf)
bc->sbuf->wsem = NULL;
if (bc->rbuf)
free_ibuffer(bc->rbuf);
bc->rbuf = NULL;
ret = sem_destroy(&ia->work);
dprint(DBGM_TOPLEVEL, "%s: sem_destroy work %d\n", __FUNCTION__,
ret);
free(ia);
return(0);
}
static int
route_call(iapplication_t *ap, bchannel_t *bc)
{
bchannel_t *newbc = NULL;
int ret;
if (bc) {
display_NR_IE(bc->msn, __FUNCTION__": msn");
display_NR_IE(bc->nr, __FUNCTION__": nr");
}
ap->data1 = bc;
if (!bc)
return(-EINVAL);
read_rec_ctrlfile();
if (bc->usednr->typ == NR_TYPE_INTERN) {
ap->mode = AP_MODE_INTERN_CALL;
ret = ap->mgr->app_bc(ap->mgr, PR_APP_OCHANNEL, &newbc);
if (0 >= ret)
dprint(DBGM_TOPLEVEL, "%s: no free channel ret(%d)\n", __FUNCTION__,
ret);
if (!newbc) {
bc->cause_loc = CAUSE_LOC_PNET_LOCUSER;
bc->cause_val = CAUSE_USER_BUSY;
ap->mgr->app_bc(ap->mgr, PR_APP_HANGUP, bc);
return(0);
}
newbc->app = ap;
ap->data2 = newbc;
newbc->Flags |= FLG_BC_APPLICATION;
newbc->msn[0] = bc->usednr->len +1;
newbc->msn[1] = 0x81;
memcpy(&newbc->msn[2], bc->usednr->nr, bc->usednr->len);
if (bc->msn[0])
memcpy(newbc->nr, bc->msn, bc->msn[0] + 1);
newbc->l1_prot = ISDN_PID_L1_B_64TRANS;
ap->mgr->app_bc(ap->mgr, PR_APP_OCALL, newbc);
} else if (bc->usednr->typ == NR_TYPE_AUDIO) {
if (ap->vapp->flags & AP_FLG_AUDIO_USED) {
bc->cause_loc = CAUSE_LOC_PNET_LOCUSER;
bc->cause_val = CAUSE_USER_BUSY;
ap->mgr->app_bc(ap->mgr, PR_APP_HANGUP, bc);
return(0);
} else
ap->vapp->flags |= AP_FLG_AUDIO_USED;
ap->mode = AP_MODE_AUDIO_CALL;
bc->Flags |= FLG_BC_PROGRESS;
ap->mgr->app_bc(ap->mgr, PR_APP_ALERT, bc);
ret = setup_audio(ap, bc);
if (ret) {
ap->vapp->flags &= ~AP_FLG_AUDIO_USED;
bc->cause_loc = CAUSE_LOC_PNET_LOCUSER;
bc->cause_val = CAUSE_INCOMPATIBLE_DEST;
ap->mgr->app_bc(ap->mgr, PR_APP_HANGUP, bc);
return(0);
}
ap->Flags |= AP_FLG_AUDIO_ACTIV;
strcpy(bc->display,"connect to AUDIO");
ap->mgr->app_bc(ap->mgr, PR_APP_CONNECT, bc);
} else if (bc->usednr->typ == NR_TYPE_VOIP) {
ap->mode = AP_MODE_VOIP_OCALL;
ret = setup_voip_ocall(ap, bc);
}
return(0);
}
static int
connect_call(iapplication_t *ap, bchannel_t *bc)
{
bchannel_t *peer = NULL;
int ret;
read_rec_ctrlfile();
if (ap->mode == AP_MODE_INTERN_CALL) {
if (ap->data1 == bc) {
peer = ap->data2;
} else if (ap->data2 == bc) {
peer = ap->data1;
}
if (peer) {
ap->mgr->app_bc(ap->mgr, PR_APP_CONNECT, peer);
bc->rbuf = peer->sbuf;
peer->rbuf = bc->sbuf;
if (bc->sbuf)
bc->sbuf->rsem = &peer->work;
if (peer->sbuf)
peer->sbuf->rsem = &bc->work;
} else {
return(-EINVAL);
}
} else if (ap->mode == AP_MODE_VOIP_OCALL) {
bc = ap->data1;
ap->Flags &= ~AP_FLG_VOIP_ALERTING;
sprintf(bc->display,"connect to %s", bc->usednr->name);
ap->mgr->app_bc(ap->mgr, PR_APP_CONNECT, bc);
} else if (ap->mode == AP_MODE_VOIP_ICALL) {
ret = connect_voip(ap, bc);
if (!ret) {
ap->Flags |= AP_FLG_VOIP_ACTIV;
ap->mgr->app_bc(ap->mgr, PR_APP_CONNECT, bc);
}
return(ret);
}
return(0);
}
static int
hangup_call(iapplication_t *ap, bchannel_t *bc)
{
if ((ap->mode == AP_MODE_VOIP_OCALL) ||
(ap->mode == AP_MODE_VOIP_ICALL)) {
if (ap->Flags & AP_FLG_VOIP_ACTIV) {
close_voip(ap, bc);
}
return(disconnect_voip(ap, bc));
}
return(0);
}
static int
clear_call(iapplication_t *ap, bchannel_t *bc)
{
bchannel_t *peer = NULL;
if (ap->mode == AP_MODE_INTERN_CALL) {
if (ap->data1 == bc) {
peer = ap->data2;
ap->data1 = NULL;
} else if (ap->data2 == bc) {
peer = ap->data1;
ap->data2= NULL;
}
bc->rbuf = NULL;
if (bc->sbuf)
bc->sbuf->rsem = &bc->work;
if (peer) {
peer->Flags |= FLG_BC_PROGRESS;
peer->cause_loc = bc->cause_loc;
peer->cause_val = bc->cause_val;
peer->rbuf = NULL;
if (peer->sbuf)
peer->sbuf->rsem = &peer->work;
ap->mgr->app_bc(ap->mgr, PR_APP_HANGUP, peer);
} else {
free_application(ap);
}
if (bc)
bc->app = NULL;
} else if (ap->mode == AP_MODE_AUDIO_CALL) {
if (ap->Flags & AP_FLG_AUDIO_ACTIV) {
close_audio(ap, bc);
ap->Flags &= ~AP_FLG_AUDIO_ACTIV;
ap->vapp->flags &= ~AP_FLG_AUDIO_USED;
}
if (bc)
bc->app = NULL;
free_application(ap);
} else if (ap->mode == AP_MODE_VOIP_OCALL) {
if (ap->Flags & AP_FLG_VOIP_ACTIV) {
close_voip(ap, bc);
}
release_voip(ap, bc);
ap->mode = AP_MODE_IDLE;
free_application(ap);
} else if (ap->mode == AP_MODE_VOIP_ICALL) {
if (ap->Flags & AP_FLG_VOIP_ACTIV) {
close_voip(ap, bc);
}
release_voip(ap, bc);
ap->mode = AP_MODE_IDLE;
free_application(ap);
}
return(0);
}
static int
alert_call(iapplication_t *ap, bchannel_t *bc)
{
bchannel_t *peer = NULL;
if (ap->mode == AP_MODE_VOIP_ICALL) {
return(alert_voip(ap, bc));
} else if (ap->mode == AP_MODE_INTERN_CALL) {
if (bc != ap->data2)
return(0);
peer = ap->data1;
if (!peer)
return(0);
peer->Flags |= FLG_BC_PROGRESS;
ap->mgr->app_bc(ap->mgr, PR_APP_ALERT, peer);
}
return(0);
}
static int
facility_info(iapplication_t *ap, bchannel_t *bc)
{
if ((ap->mode == AP_MODE_VOIP_ICALL) ||
(ap->mode == AP_MODE_VOIP_OCALL)) {
return(facility_voip(ap, bc));
}
return(0);
}
static int
useruser_info(iapplication_t *ap, bchannel_t *bc)
{
if ((ap->mode == AP_MODE_VOIP_ICALL) ||
(ap->mode == AP_MODE_VOIP_OCALL)) {
return(useruser_voip(ap, bc));
}
return(0);
}
static int
open_recfiles(iapplication_t *ap, bchannel_t *bc)
{
char filename[2048];
struct timeval tv;
int ret;
if (!bc)
return(-EINVAL);
if (!RecordFilePath[0]) {
dprint(DBGM_TOPLEVEL, "%s: RecordFilePath not set\n", __FUNCTION__);
return(-EINVAL);
}
gettimeofday(&tv, NULL);
sprintf(filename, "%s%08lx_%02d.r",
RecordFilePath, tv.tv_sec, bc->channel);
dprint(DBGM_TOPLEVEL, "%s: rf.r:%s\n", __FUNCTION__,
filename);
if (bc->rrid > 0)
close(bc->rrid);
bc->rrid = open(filename, O_WRONLY|O_CREAT|O_TRUNC,S_IRWXU);
if (bc->rrid < 0) {
ret = -errno;
dprint(DBGM_TOPLEVEL, "%s: rf.r error %s\n", __FUNCTION__,
strerror(errno));
return(ret);
}
filename[strlen(filename)-1] = 's';
dprint(DBGM_TOPLEVEL, "%s: rf.s:%s\n", __FUNCTION__,
filename);
if (bc->rsid > 0)
close(bc->rsid);
bc->rsid = open(filename, O_WRONLY|O_CREAT|O_TRUNC,S_IRWXU);
if (bc->rsid < 0) {
ret = -errno;
dprint(DBGM_TOPLEVEL, "%s: rf.s error %s\n", __FUNCTION__,
strerror(errno));
close(bc->rrid);
bc->rrid = -1;
return(ret);
}
bc->Flags |= FLG_BC_RECORDING;
return(0);
}
static int
close_recfiles(iapplication_t *ap, bchannel_t *bc)
{
if (!bc)
return(-EINVAL);
if (bc->rrid > 0)
close(bc->rrid);
bc->rrid = -1;
if (bc->rsid > 0)
close(bc->rsid);
bc->rsid = -1;
bc->Flags &= ~FLG_BC_RECORDING;
return(0);
}
static int
application_handler(manager_t *mgr, int prim, void *arg)
{
bchannel_t *bc = arg;
iapplication_t *appl = NULL;
if (!bc)
return(-EINVAL);
if (prim == PR_APP_ICALL) {
appl = new_application(&voip);
if (!appl)
return(-EBUSY);
appl->mgr = mgr;
bc->app = appl;
return(route_call(appl, bc));
return(-EBUSY);
}
appl = bc->app;
if (!appl)
return(-EINVAL);
if (prim == PR_APP_CONNECT) {
return(connect_call(appl, bc));
} else if (prim == PR_APP_ALERT) {
return(alert_call(appl, bc));
} else if (prim == PR_APP_FACILITY) {
return(facility_info(appl, bc));
} else if (prim == PR_APP_USERUSER) {
return(useruser_info(appl, bc));
} else if (prim == PR_APP_HANGUP) {
return(hangup_call(appl, bc));
} else if (prim == PR_APP_CLEAR) {
return(clear_call(appl, bc));
} else if (prim == PR_APP_OPEN_RECFILES) {
return(open_recfiles(appl, bc));
} else if (prim == PR_APP_CLOSE_RECFILES) {
return(close_recfiles(appl, bc));
}
return(-EINVAL);
}
int main(argc,argv)
int argc;
char *argv[];
{
int ret, *retp;
char host_cfg[MAX_HOST_SIZE+16];
pthread_t voip_id;
nr_list_t *nr;
debug_init(global_debug, "testlog", NULL, NULL);
memset(&voip, 0, sizeof(vapplication_t));
voip.tout.tv_sec = NORMAL_TIMEOUT_s;
voip.tout.tv_usec = NORMAL_TIMEOUT_us;
msg_init();
ret = init_manager(&voip.mgr_lst, application_handler);
if (ret) {
fprintf(stderr, "error in init_manager %d\n", ret);
exit(1);
}
parse_cfg("voip.cfg", voip.mgr_lst);
if (gethostname(voip.hostname, MAX_HOST_SIZE)) {
fprintf(stderr, "error getting hostname: %s\n",
strerror(errno));
exit(1);
}
sprintf(host_cfg, "%s.voip.cfg", voip.hostname);
parse_cfg(host_cfg, voip.mgr_lst);
debug_init(global_debug, NULL, NULL, NULL);
voip.port = rtp_port;
voip.flags = default_flags;
voip.debug = global_debug;
fprintf(stderr, "%s: debug(%x) port(%d)\n", __FUNCTION__,
global_debug, rtp_port);
nr = voip.mgr_lst->nrlist;
while(nr) {
dprint(DBGM_TOPLEVEL, "nr(%s) len(%d) flg(%x) typ(%d) name(%s)\n",
nr->nr, nr->len, nr->flags, nr->typ, nr->name);
nr = nr->next;
}
signal(SIGTERM, term_handler);
signal(SIGINT, term_handler);
signal(SIGPIPE, term_handler);
signal(SIGUSR1, sig_usr1_handler);
signal(SIGALRM, SIG_IGN);
read_rec_ctrlfile();
#if 0
signal(SIGCHLD, child_handler);
#endif
#if 0
{
static struct sigaction sa;
sa.sa_handler = NULL;
sa.sa_restorer = NULL;
sa.sa_sigaction = sig_segfault;
sa.sa_flags = SA_ONESHOT | SA_SIGINFO;
sigemptyset(&sa.sa_mask);
ret = sigaction(SIGSEGV, &sa, NULL);
fprintf(stderr, "sigaction ret(%d)\n",
ret);
}
#endif
voip_id = run_voip(&voip);
retp = do_netthread(voip.mgr_lst->nst);
fprintf(stderr, "do_main_loop returns(%p)\n", retp);
while (voip.mgr_lst) {
manager_t *next = voip.mgr_lst->next;
cleanup_manager(voip.mgr_lst);
voip.mgr_lst = next;
}
voip.flags |= AP_FLG_VOIP_ABORT;
ret = pthread_join(voip_id, (void *)&retp);
fprintf(stderr, "%s: join voipscan ret(%d) rval(%p)\n", __FUNCTION__,
ret, retp);
debug_close();
return(0);
}

509
voip/voip_isdn_app.c Normal file
View File

@ -0,0 +1,509 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include "isdn_net.h"
#include "l3dss1.h"
#include "globals.h"
#include "iapplication.h"
static void MsgAddIE(msg_t *msg, u_char ie, u_char *iep, int reset) {
int l;
u_char *p;
if (ie & 0x80)
l = 1;
else {
if (iep && *iep)
l = 2 + *iep;
else
return;
}
p = msg_put(msg, l);
*p++ = ie;
l--;
if (l) {
memcpy(p, iep, l);
if (reset)
*iep = 0;
}
}
static msg_t *
make_msg_head(int size, u_char mt) {
u_char *p;
msg_t *msg;
msg = alloc_msg(size);
if (msg) {
p = msg_put(msg, 3);
p++;
p++;
*p++ = mt;
}
return(msg);
}
int
alert_voip(iapplication_t *ap, bchannel_t *bc)
{
msg_t *msg;
if (!ap->con)
return(-EBUSY);
msg = make_msg_head(1024, MT_ALERTING);
if (msg) {
MsgAddIE(msg, IE_FACILITY, bc->fac, 1);
MsgAddIE(msg, IE_DISPLAY, bc->display, 1);
MsgAddIE(msg, IE_USER_USER, bc->uu, 1);
msg_queue_tail(&ap->con->aqueue, msg);
return(SendCtrl(ap));
}
return(-ENOMEM);
}
int
facility_voip(iapplication_t *ap, bchannel_t *bc)
{
msg_t *msg;
if (!ap->con)
return(-EBUSY);
msg = make_msg_head(1024, MT_FACILITY);
if (msg) {
MsgAddIE(msg, IE_FACILITY, bc->fac, 1);
MsgAddIE(msg, IE_DISPLAY, bc->display, 1);
msg_queue_tail(&ap->con->aqueue, msg);
return(SendCtrl(ap));
}
return(-ENOMEM);
}
int
useruser_voip(iapplication_t *ap, bchannel_t *bc)
{
msg_t *msg;
if (!ap->con)
return(-EBUSY);
msg = make_msg_head(1024, MT_USER_INFORMATION);
if (msg) {
MsgAddIE(msg, IE_USER_USER, bc->uu, 1);
msg_queue_tail(&ap->con->aqueue, msg);
return(SendCtrl(ap));
}
return(-ENOMEM);
}
int
connect_voip(iapplication_t *ap, bchannel_t *bc)
{
int ret;
msg_t *msg;
if (!ap->con)
return(-EBUSY);
ret = setup_voip(ap, bc);
if (ret) {
bc->cause_loc = CAUSE_LOC_PNET_LOCUSER;
bc->cause_val = CAUSE_NO_ROUTE;
ap->mgr->app_bc(ap->mgr, PR_APP_HANGUP, bc);
return(-EBUSY);
}
msg = make_msg_head(1024, MT_CONNECT);
if (msg) {
MsgAddIE(msg, IE_FACILITY, bc->fac, 1);
MsgAddIE(msg, IE_DISPLAY, bc->display, 1);
MsgAddIE(msg, IE_USER_USER, bc->uu, 1);
msg_queue_tail(&ap->con->aqueue, msg);
return(SendCtrl(ap));
}
return(-ENOMEM);
}
int
disconnect_voip(iapplication_t *ap, bchannel_t *bc)
{
msg_t *msg;
u_char cause[8];
if (!ap->con)
return(-EBUSY);
msg = make_msg_head(1024, MT_DISCONNECT);
if (msg) {
cause[0] = 2;
cause[1] = 0x80 | bc->cause_loc;
cause[2] = 0x80 | bc->cause_val;
MsgAddIE(msg, IE_CAUSE, cause, 0);
MsgAddIE(msg, IE_FACILITY, bc->fac, 1);
MsgAddIE(msg, IE_DISPLAY, bc->display, 1);
MsgAddIE(msg, IE_USER_USER, bc->uu, 1);
msg_queue_tail(&ap->con->aqueue, msg);
return(SendCtrl(ap));
}
return(-ENOMEM);
}
int
release_voip(iapplication_t *ap, bchannel_t *bc)
{
msg_t *msg;
u_char cause[8];
if (!ap->con)
return(-EBUSY);
msg = make_msg_head(1024, MT_RELEASE);
if (msg) {
cause[0] = 2;
cause[1] = 0x80 | bc->cause_loc;
cause[2] = 0x80 | bc->cause_val;
MsgAddIE(msg, IE_CAUSE, cause, 0);
MsgAddIE(msg, IE_FACILITY, bc->fac, 1);
MsgAddIE(msg, IE_DISPLAY, bc->display, 1);
MsgAddIE(msg, IE_USER_USER, bc->uu, 1);
msg_queue_tail(&ap->con->aqueue, msg);
return(SendCtrl(ap));
}
return(-ENOMEM);
}
int
setup_voip_ocall(iapplication_t *ap, bchannel_t *bc) {
msg_t *msg;
struct in_addr addr;
struct hostent *h;
if (!ap->con) {
if ((addr.s_addr = inet_addr(bc->usednr->name)) == -1) {
h = gethostbyname(bc->usednr->name);
if (!h) {
return(-ENXIO);
}
memcpy(&addr.s_addr, h->h_addr, sizeof(addr.s_addr));
}
ap->con = new_connection(ap, &addr);
if (!ap->con) {
return(-ENOMEM);
}
if (bc->usednr->flags & FLAG_GSM) {
ap->con->pkt_size = 640;
ap->con->sndflags |= SNDFLG_COMPR_GSM;
}
ap->con->own_ssrc = getnew_ssrc(ap->vapp);
}
msg = make_msg_head(1024, MT_SETUP);
if (msg) {
MsgAddIE(msg, IE_FACILITY, bc->fac, 1);
MsgAddIE(msg, IE_BEARER, bc->bc, 0);
MsgAddIE(msg, IE_DISPLAY, bc->display, 1);
MsgAddIE(msg, IE_CALLING_PN, bc->msn, 0);
MsgAddIE(msg, IE_CALLING_SUB, bc->clisub, 1);
MsgAddIE(msg, IE_CALLED_PN, bc->nr, 0);
MsgAddIE(msg, IE_CALLED_SUB, bc->cldsub, 1);
MsgAddIE(msg, IE_USER_USER, bc->uu, 1);
msg_queue_tail(&ap->con->aqueue, msg);
return(SendCtrl(ap));
}
return(-ENOMEM);
}
static int
parse_isdn_extra(unsigned char *arg, int len, bchannel_t *bc)
{
unsigned char *p;
p = findie(arg, len, IE_DISPLAY, 0);
if (p) {
memcpy(bc->display, p + 1, *p);
bc->display[*p] = 0;
}
p = findie(arg, len, IE_USER_USER, 0);
if (p)
memcpy(bc->uu, p, *p + 1);
p = findie(arg, len, IE_FACILITY, 0);
if (p)
memcpy(bc->fac, p, *p + 1);
return(0);
}
static int
parse_isdn_setup(iapplication_t *appl, unsigned char *arg, int len)
{
manager_t *mgr = appl->vapp->mgr_lst;
unsigned char *own, *p;
nr_list_t *nrx;
bchannel_t *bc = NULL;
int ret;
if (appl->mgr) { /* allready setup */
SendCtrl(appl);
return(-EINVAL);
}
own = findie(arg, len, IE_CALLED_PN, 0);
if (!own) {
SendCtrl(appl);
return(-EINVAL);
}
while(mgr) {
nrx = NULL;
if (!match_nr(mgr, own, &nrx)) {
ret = mgr->app_bc(mgr, PR_APP_OCHANNEL, &bc);
if (0 >= ret)
eprint( "%s: no free channel ret(%d)\n", __FUNCTION__,
ret);
if (!bc) {
eprint( "%s: no free channel\n", __FUNCTION__);
} else {
appl->mgr = mgr;
appl->data1 = bc;
appl->mode = AP_MODE_VOIP_ICALL;
bc->app = appl;
bc->usednr = nrx;
break;
}
}
mgr = mgr->next;
}
if (!mgr) {
} else {
p = findie(arg, len, IE_CALLING_PN, 0);
if (p)
memcpy(bc->nr, p, *p + 1);
p = findie(arg, len, IE_CALLING_SUB, 0);
if (p)
memcpy(bc->clisub, p, *p + 1);
p = findie(arg, len, IE_CALLED_SUB, 0);
if (p)
memcpy(bc->cldsub, p, *p + 1);
parse_isdn_extra(arg, len, bc);
bc->Flags |= FLG_BC_APPLICATION;
memcpy(bc->msn, own, own[0] + 1);
bc->l1_prot = ISDN_PID_L1_B_64TRANS;
if (!bc->display[0] && appl->con) {
strcpy(bc->display, appl->con->con_hostname);
}
mgr->app_bc(mgr, PR_APP_OCALL, bc);
}
SendCtrl(appl);
return(0);
}
static int
parse_isdn_alert(iapplication_t *appl, unsigned char *arg, int len)
{
bchannel_t *bc = appl->data1;
if (!appl->mgr || !bc) {
SendCtrl(appl);
return(-EINVAL);
}
parse_isdn_extra(arg, len, bc);
if (!bc->display[0] && bc->usednr) {
strcpy(bc->display, bc->usednr->name);
}
bc->Flags |= FLG_BC_PROGRESS;
appl->mgr->app_bc(appl->mgr, PR_APP_ALERT, bc);
SendCtrl(appl);
return(0);
}
int
parse_isdn_connect(iapplication_t *appl, unsigned char *arg, int len)
{
bchannel_t *bc = appl->data1;
int ret;
if (!appl->mgr || !bc) {
SendCtrl(appl);
return(-EINVAL);
}
parse_isdn_extra(arg, len, bc);
ret = setup_voip(appl, bc);
if (ret) {
bc->cause_loc = CAUSE_LOC_PNET_LOCUSER;
bc->cause_val = CAUSE_NO_ROUTE;
appl->mgr->app_bc(appl->mgr, PR_APP_HANGUP, bc);
return(0);
}
appl->Flags |= AP_FLG_VOIP_ACTIV;
appl->mgr->app_bc(appl->mgr, PR_APP_CONNECT, bc);
SendCtrl(appl);
return(0);
}
static int
parse_isdn_disc(iapplication_t *appl, unsigned char *arg, int len)
{
bchannel_t *bc = appl->data1;
unsigned char *p;
if (!appl->mgr || !bc) {
SendCtrl(appl);
return(-EINVAL);
}
p = findie(arg, len, IE_CAUSE, 0);
if (p) {
if (*p++ > 1) {
bc->cause_loc = *p++ & 0xf;
bc->cause_val = *p++ & 0x7f;
} else {
bc->cause_loc = CAUSE_LOC_PNET_LOCUSER;
bc->cause_val = CAUSE_NORMAL_CLEARING;
}
} else {
bc->cause_loc = CAUSE_LOC_PNET_LOCUSER;
bc->cause_val = CAUSE_NORMAL_CLEARING;
}
parse_isdn_extra(arg, len, bc);
if (appl->Flags & AP_FLG_VOIP_ACTIV) {
close_voip(appl, bc);
}
bc->Flags |= FLG_BC_PROGRESS;
appl->mgr->app_bc(appl->mgr, PR_APP_HANGUP, bc);
SendCtrl(appl);
return(0);
}
static int
parse_isdn_release(iapplication_t *appl, unsigned char *arg, int len)
{
bchannel_t *bc = appl->data1;
unsigned char *p;
if (!appl->mgr || !bc) {
SendCtrl(appl);
return(-EINVAL);
}
p = findie(arg, len, IE_CAUSE, 0);
if (p) {
if (*p++ > 1) {
bc->cause_loc = *p++ & 0xf;
bc->cause_val = *p++ & 0x7f;
} else {
bc->cause_loc = CAUSE_LOC_PNET_LOCUSER;
bc->cause_val = CAUSE_NORMAL_CLEARING;
}
} else {
bc->cause_loc = CAUSE_LOC_PNET_LOCUSER;
bc->cause_val = CAUSE_NORMAL_CLEARING;
}
parse_isdn_extra(arg, len, bc);
if (appl->Flags & AP_FLG_VOIP_ACTIV) {
close_voip(appl, bc);
}
bc->Flags |= FLG_BC_PROGRESS;
appl->mgr->app_bc(appl->mgr, PR_APP_HANGUP, bc);
SendCtrl(appl);
return(0);
}
static int
parse_isdn_uinfo(iapplication_t *appl, unsigned char *arg, int len)
{
bchannel_t *bc = appl->data1;
if (!appl->mgr || !bc) {
SendCtrl(appl);
return(-EINVAL);
}
parse_isdn_extra(arg, len, bc);
appl->mgr->app_bc(appl->mgr, PR_APP_USERUSER, bc);
SendCtrl(appl);
return(0);
}
static int
parse_isdn_fac(iapplication_t *appl, unsigned char *arg, int len)
{
bchannel_t *bc = appl->data1;
if (!appl->mgr || !bc) {
SendCtrl(appl);
return(-EINVAL);
}
parse_isdn_extra(arg, len, bc);
appl->mgr->app_bc(appl->mgr, PR_APP_FACILITY, bc);
SendCtrl(appl);
return(0);
}
static int
parse_isdn_packet(iapplication_t *appl, unsigned char *arg) {
unsigned char *p, oc, pc, pr, a_pc;
int len;
vconnection_t *con;
con = appl->con;
if (!con)
return(-EINVAL);
p = arg + 2;
len = ntohs(*((unsigned short *)p));
len *= 4;
p = arg + 12;
len -= 8;
if (len<=0)
return(-EINVAL);
oc = *p++;
pc = *p;
*p++ = 0; /* to use L3 findie, fake a dummy CR L3 frame */
pr = *p++;
dprint(DBGM_ISDN, "%s: pr(%02x) own(%d/%d) peer(%d/%d)\n", __FUNCTION__,
pr, oc, con->oc, pc, con->pc);
a_pc = con->pc;
a_pc++;
if (con->oc == oc) {
if (con->amsg) {
free_msg(con->amsg);
con->amsg = NULL;
}
}
if (a_pc != pc) {
} else
con->pc = pc;
if (pr == 0) { /* escape to private MTs */
pr = *p++;
if (pr == 0x81) { /* RR */
return(0);
}
return(-EINVAL);
} else if (pr == MT_SETUP) {
return(parse_isdn_setup(appl, arg + 12, len));
} else if (pr == MT_ALERTING) {
return(parse_isdn_alert(appl, arg + 12, len));
} else if (pr == MT_CONNECT) {
return(parse_isdn_connect(appl, arg + 12, len));
} else if (pr == MT_DISCONNECT) {
return(parse_isdn_disc(appl, arg + 12, len));
} else if (pr == MT_RELEASE) {
return(parse_isdn_release(appl, arg + 12, len));
} else if (pr == MT_USER_INFORMATION) {
return(parse_isdn_uinfo(appl, arg + 12, len));
} else if (pr == MT_FACILITY) {
return(parse_isdn_fac(appl, arg + 12, len));
}
return(0);
}
int
voip_application_handler(iapplication_t *appl, int prim, unsigned char *arg) {
dprint(DBGM_APPL, "%s(%p, %x, %p)\n", __FUNCTION__,
appl, prim, arg);
if (prim == AP_PR_VOIP_NEW) {
} else if (prim == AP_PR_VOIP_ISDN) {
return(parse_isdn_packet(appl, arg));
}
return(-EINVAL);
}

138
voip/voip_timer.c Normal file
View File

@ -0,0 +1,138 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>
#include <sys/time.h>
#include "vitimer.h"
static vi_timer_t *timerlist = NULL;
static void
ins_vitimer(vi_timer_t *iti) {
iti->prev = timerlist;
iti->next = NULL;
if (timerlist) {
if (timercmp(&timerlist->tv, &iti->tv, >)) {
iti->prev = NULL;
iti->next = timerlist;
}
}
while(iti->prev && iti->prev->next) {
if (timercmp(&iti->prev->next->tv, &iti->tv, >))
break;
iti->prev = iti->prev->next;
}
if (iti->prev) {
iti->next = iti->prev->next;
iti->prev->next = iti;
} else {
timerlist = iti;
}
if (iti->next)
iti->next->prev = iti;
}
int
run_vitimer(void)
{
int cnt = 0;
struct timeval act, del;
gettimeofday(&act, NULL);
while(timerlist) {
if (timercmp(&timerlist->tv, &act, >))
break;
timersub(&act, &timerlist->tv, &del);
timerlist->func(timerlist->data, timerlist->val, &del);
remove_vitimer(timerlist);
}
return(cnt);
}
void
remove_vitimer(vi_timer_t *iti) {
if (iti->prev)
iti->prev->next = iti->next;
if (iti->next)
iti->next->prev = iti->prev;
if (timerlist == iti)
timerlist = iti->next;
iti->prev = NULL;
iti->next = NULL;
}
int
init_vitimer(vi_timer_t *iti, void *data, unsigned long val, timef_t f)
{
if (!iti) {
return(-EINVAL);
}
iti->data = data;
iti->val = val;
iti->func = f;
return(0);
}
int
add_vitimer_abs(vi_timer_t *iti, struct timeval *tv)
{
if (!iti) {
return(-EINVAL);
}
iti->tv = *tv;
ins_vitimer(iti);
run_vitimer();
return(0);
}
int
add_vitimer_rel(vi_timer_t *iti, struct timeval *tv)
{
struct timeval act;
gettimeofday(&act, NULL);
if (!iti) {
return(-EINVAL);
}
timeradd(&act, tv, &iti->tv);
ins_vitimer(iti);
run_vitimer();
return(0);
}
void
clean_vitimer(void) {
while(timerlist)
remove_vitimer(timerlist);
}
struct timeval
*get_next_vitimer_time(void)
{
if (timerlist)
return(&timerlist->tv);
else
return(NULL);
}
int
get_next_vitimer_dist(struct timeval *tv)
{
struct timeval act;
if (!tv)
return(-EINVAL);
if (!timerlist)
return(-EINVAL);
gettimeofday(&act, NULL);
if (timercmp(&timerlist->tv, &act, <)) {
tv->tv_sec = 0;
tv->tv_usec = 0;
} else
timersub(&timerlist->tv, &act, tv);
return(0);
}

53
voip/voipisdn.spec Normal file
View File

@ -0,0 +1,53 @@
Vendor: SuSE GmbH, Nuernberg, Germany
Distribution: SuSE Linux 7.3 (i386)
Name: voipisdn
Packager: feedback@suse.de
Copyright: GPL
Group: Applications/Communications
Provides: voipisdn
Autoreqprov: on
Version: 20030423
Release: 1
Summary: Voice Communication Over Data Networks
Source1: hisax_voip-%{version}.tar.bz2
Source2: gsm-1.0.7.tar.gz
BuildRoot: /var/tmp/%{name}-build
%description
Voice Communication Over Data TCP/IP Networks ISDN gateway
Authors:
--------
Karsten Keil <kkeil@suse.de>
SuSE series: net
%prep
%setup -T -c -n voipisdn
%setup -n voipisdn -D -T -a 1
%setup -n voipisdn -D -T -a 2
%build
cd gsm-1.0-pl6
make
cd ..
cd hisax
make all
%install
rm -rf RPM_BUILD_ROOT
mkdir -p $RPM_BUILD_ROOT/usr/bin
install -c -s -m 755 hisax/voip/voipisdn $RPM_BUILD_ROOT/usr/bin/
%{?suse_check}
%clean
rm -rf RPM_BUILD_ROOT
%files
%defattr(-,root,root)
/usr/bin/*