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