Initial revision
This commit is contained in:
commit
0c3b232b6a
|
@ -0,0 +1,3 @@
|
||||||
|
*.o
|
||||||
|
*.a
|
||||||
|
*~
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
Binary file not shown.
File diff suppressed because one or more lines are too long
|
@ -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
|
||||||
|
[00minsgesamt 0
|
||||||
|
[mtest@pingi:~ > logout
|
|
@ -0,0 +1,4 @@
|
||||||
|
test
|
||||||
|
test
|
||||||
|
ls -l
|
||||||
|
logout
|
|
@ -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,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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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);
|
||||||
|
}
|
|
@ -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 *);
|
||||||
|
|
|
@ -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,
|
||||||
|
};
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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 */
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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]);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
#
|
||||||
|
# for each channel one line with a value:
|
||||||
|
# 0 don't record channel
|
||||||
|
# 1 record channel
|
||||||
|
#
|
||||||
|
1
|
||||||
|
0
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
|
@ -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
|
|
@ -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);
|
||||||
|
}
|
|
@ -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;
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
|
@ -0,0 +1,3 @@
|
||||||
|
debug_init: debug_mask = 0
|
||||||
|
debug_init: debug_mask = 0
|
||||||
|
debug_close: debug channel now closed
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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/*
|
||||||
|
|
Loading…
Reference in New Issue