Jolly:
now the bridig util is ready. to bridge, just say: isdnbridge <port1> <port2> and they will be bridged. very usefull for L1oIP. modified: Makefile new file: bridge/Makefile new file: bridge/bridge.c
This commit is contained in:
parent
920d67e950
commit
65a34a749f
1
Makefile
1
Makefile
|
@ -49,6 +49,7 @@ SUBDIRS += $(shell if test -d i4lnet ; then echo i4lnet; fi)
|
|||
SUBDIRS += $(shell if test -d tenovis ; then echo tenovis; fi)
|
||||
SUBDIRS += $(shell if test -d voip ; then echo voip; fi)
|
||||
SUBDIRS += $(shell if test -d suppserv ; then echo suppserv; fi)
|
||||
SUBDIRS += $(shell if test -d bridge ; then echo bridge; fi)
|
||||
|
||||
LIBS := lib/libmISDN.a
|
||||
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
# ifndef SF_DIR
|
||||
# SF_DIR = /home/kkeil/speak_freely-7.2
|
||||
# endif
|
||||
|
||||
mISDNLIB = $(mISDN_DIR)/lib/libmISDN.a
|
||||
|
||||
HLIBINCL = $(mISDN_DIR)/include/mISDNlib.h
|
||||
|
||||
EXTRA_CFLAGS :=
|
||||
EXTRA_INCLUDE :=
|
||||
EXTRA_LIB :=
|
||||
|
||||
PROGRAMMS = isdnbridge
|
||||
|
||||
all: $(PROGRAMMS)
|
||||
|
||||
install:
|
||||
for i in $(PROGRAMMS) ; do \
|
||||
install -m 755 $$i $(INSTALL_PREFIX)/usr/bin ;\
|
||||
done
|
||||
|
||||
CARGS =
|
||||
|
||||
CCFLAGS = -Wall -DLINUX -DM_LITTLE_ENDIAN
|
||||
|
||||
LFLAGS =
|
||||
|
||||
DEBUG =
|
||||
|
||||
CFLAGS := $(CFLAGS) $(DEBUG) $(EXTRA_INCLUDE) \
|
||||
$(CARGS) $(DUPLEX) $(CCFLAGS) $(DOMAIN) $(EXTRA_CFLAGS)
|
||||
|
||||
BRIDGEOBJ = bridge.o
|
||||
|
||||
isdnbridge: $(BRIDGEOBJ) $(mISDNLIB) \
|
||||
$(HLIBINCL)
|
||||
$(CC) $(BRIDGEOBJ) $(mISDNLIB) \
|
||||
$(LFLAGS) -o $@
|
||||
|
||||
bridge.o: bridge.c
|
||||
|
||||
clean:
|
||||
rm -f *.o DEADJOE
|
||||
find ./ -name '*~' -exec rm {} \;
|
||||
rm -f $(PROGRAMMS)
|
||||
|
||||
distclean: clean
|
||||
rm -f *.a $(PROGRAMMS)
|
|
@ -0,0 +1,962 @@
|
|||
/*****************************************************************************\
|
||||
** **
|
||||
** isdnbridge **
|
||||
** **
|
||||
**---------------------------------------------------------------------------**
|
||||
** Copyright: Andreas Eversberg (GPL) **
|
||||
** **
|
||||
** user space utility to bridge two mISDN ports. **
|
||||
** **
|
||||
\*****************************************************************************/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
//#include <poll.h>
|
||||
#include <errno.h>
|
||||
//#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <mISDNlib.h>
|
||||
|
||||
#define ISDN_PID_L4_B_USER 0x440000ff
|
||||
|
||||
//#define DEBUG
|
||||
|
||||
/* used for udevice */
|
||||
int entity = 0;
|
||||
|
||||
/* the device handler and port list */
|
||||
int mISDNdevice = -1;
|
||||
int portcount = 0; /* counts all open ports for finding pair */
|
||||
|
||||
/* quit flag */
|
||||
int quit = 0;
|
||||
|
||||
/* option stuff */
|
||||
int nooutput = 0;
|
||||
int traffic = 0;
|
||||
|
||||
/* mISDN port structure list */
|
||||
struct mISDNport {
|
||||
struct mISDNport *next, *prev;
|
||||
int count; /* port count */
|
||||
int portnum; /* port number */
|
||||
int l1link; /* if l1 is available (only works with nt-mode) */
|
||||
time_t l1establish; /* time until establishing after link failure */
|
||||
int ntmode; /* is TRUE if port is nt mode */
|
||||
int pri; /* is TRUE if port is a primary rate interface */
|
||||
int upper_id; /* id to transfer data down */
|
||||
int lower_id; /* id to transfer data up */
|
||||
int d_stid;
|
||||
int b_num; /* number of ports */
|
||||
int b_stid[256];
|
||||
int b_addr[256];
|
||||
int b_state[256]; /* state 0 = IDLE */
|
||||
unsigned char que_frm[2048]; /* queue while layer 1 is down */
|
||||
int que_len;
|
||||
};
|
||||
|
||||
struct mISDNport *mISDNport_first = NULL;
|
||||
|
||||
enum { B_STATE_IDLE, B_STATE_ACTIVATING, B_STATE_ACTIVE, B_STATE_DEACTIVATING };
|
||||
|
||||
/*
|
||||
* show state
|
||||
*/
|
||||
static void show_state(struct mISDNport *m1)
|
||||
{
|
||||
struct mISDNport *m2 = m1;
|
||||
|
||||
if (nooutput)
|
||||
return;
|
||||
|
||||
if (m1->count & 1)
|
||||
m1 = m1->prev;
|
||||
else
|
||||
m2 = m2->next;
|
||||
|
||||
printf("Port %2d %s <-> Port %2d %s\n", m1->portnum, (m1->l1link)?"ACTIVE":"inactive", m2->portnum, (m2->l1link)?"ACTIVE":"inactive");
|
||||
}
|
||||
/*
|
||||
* show traffic
|
||||
*/
|
||||
static void show_traffic(struct mISDNport *m1, unsigned char *data, int len)
|
||||
{
|
||||
struct mISDNport *m2 = m1;
|
||||
int right, i;
|
||||
|
||||
if (nooutput)
|
||||
return;
|
||||
|
||||
if (m1->count & 1)
|
||||
{
|
||||
m1 = m1->prev;
|
||||
right = 0;
|
||||
} else
|
||||
{
|
||||
m2 = m2->next;
|
||||
right = 1;
|
||||
}
|
||||
|
||||
printf("Port %2d %s Port %2d :", m1->portnum, right?"-->":"<--", m2->portnum);
|
||||
i = 0;
|
||||
while(i < len)
|
||||
{
|
||||
printf(" %02x", data[i]);
|
||||
i++;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* debug output
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
#define PDEBUG(fmt, arg...) _printdebug(__FUNCTION__, __LINE__, fmt, ## arg)
|
||||
static void _printdebug(const char *function, int line, const char *fmt, ...)
|
||||
{
|
||||
char buffer[4096];
|
||||
va_list args;
|
||||
|
||||
va_start(args,fmt);
|
||||
vsnprintf(buffer, sizeof(buffer)-1, fmt, args);
|
||||
buffer[sizeof(buffer)-1]=0;
|
||||
va_end(args);
|
||||
|
||||
printf("%s, line %d: %s", function, line, buffer);
|
||||
}
|
||||
#else
|
||||
#define PDEBUG(fmt, arg...) if(1)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* signal handler to interrupt main loop
|
||||
*/
|
||||
static void sighandler(int sigset)
|
||||
{
|
||||
if (sigset == SIGHUP)
|
||||
return;
|
||||
if (sigset == SIGPIPE)
|
||||
return;
|
||||
fprintf(stderr, "Signal received: %d\n", sigset);
|
||||
if (!quit)
|
||||
quit = 1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* send control information to the channel (dsp-module)
|
||||
*/
|
||||
static void ph_control(unsigned long b_addr, int c1, int c2)
|
||||
{
|
||||
unsigned char buffer[mISDN_HEADER_LEN+sizeof(int)+sizeof(int)];
|
||||
iframe_t *ctrl = (iframe_t *)buffer;
|
||||
unsigned long *d = (unsigned long *)&ctrl->data.p;
|
||||
|
||||
ctrl->prim = PH_CONTROL | REQUEST;
|
||||
ctrl->addr = b_addr | FLG_MSG_DOWN;
|
||||
ctrl->dinfo = 0;
|
||||
ctrl->len = sizeof(unsigned long)*2;
|
||||
*d++ = c1;
|
||||
*d++ = c2;
|
||||
mISDN_write(mISDNdevice, ctrl, mISDN_HEADER_LEN+ctrl->len, TIMEOUT_1SEC);
|
||||
}
|
||||
|
||||
void ph_control_block(unsigned long b_addr, int c1, void *c2, int c2_len)
|
||||
{
|
||||
unsigned char buffer[mISDN_HEADER_LEN+sizeof(int)+c2_len];
|
||||
iframe_t *ctrl = (iframe_t *)buffer;
|
||||
unsigned long *d = (unsigned long *)&ctrl->data.p;
|
||||
|
||||
ctrl->prim = PH_CONTROL | REQUEST;
|
||||
ctrl->addr = b_addr | FLG_MSG_DOWN;
|
||||
ctrl->dinfo = 0;
|
||||
ctrl->len = sizeof(unsigned long)*2;
|
||||
*d++ = c1;
|
||||
memcpy(d, c2, c2_len);
|
||||
mISDN_write(mISDNdevice, ctrl, mISDN_HEADER_LEN+ctrl->len, TIMEOUT_1SEC);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* activate / deactivate bchannel
|
||||
*/
|
||||
static void bchannel_activate(struct mISDNport *mISDNport, int i)
|
||||
{
|
||||
iframe_t act;
|
||||
|
||||
/* we must activate if we are deactivated */
|
||||
if (mISDNport->b_state[i] == B_STATE_IDLE)
|
||||
{
|
||||
/* activate bchannel */
|
||||
PDEBUG("activating bchannel (index %d), because currently idle (address 0x%x).\n", i, mISDNport->b_addr[i]);
|
||||
act.prim = DL_ESTABLISH | REQUEST;
|
||||
act.addr = mISDNport->b_addr[i] | FLG_MSG_DOWN;
|
||||
act.dinfo = 0;
|
||||
act.len = 0;
|
||||
mISDN_write(mISDNdevice, &act, mISDN_HEADER_LEN+act.len, TIMEOUT_1SEC);
|
||||
mISDNport->b_state[i] = B_STATE_ACTIVATING;
|
||||
return;
|
||||
}
|
||||
|
||||
/* if we are active, we configure our channel */
|
||||
if (mISDNport->b_state[i] == B_STATE_ACTIVE)
|
||||
{
|
||||
/* it is an error if this channel is not associated with a port object */
|
||||
PDEBUG("during activation, we add conference to %d.\n", ((mISDNport->count&(~1)) << 8) + (i<<1) + 1);
|
||||
ph_control(mISDNport->b_addr[i], CMX_CONF_JOIN, ((mISDNport->count&(~1)) << 8) + (i<<1) + 1);
|
||||
PDEBUG("during activation, we set rxoff.\n");
|
||||
ph_control(mISDNport->b_addr[i], CMX_RECEIVE_OFF, 0);
|
||||
#if 0
|
||||
if (sadks->crypt)
|
||||
{
|
||||
PDEBUG("during activation, we set crypt to crypt=%d.\n", mISDNport->b_port[i]->p_m_crypt);
|
||||
ph_control_block(mISDNport->b_addr[i], BF_ENABLE_KEY, mISDNport->b_port[i]->p_m_crypt_key, mISDNport->b_port[i]->p_m_crypt_key_len);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void bchannel_deactivate(struct mISDNport *mISDNport, int i)
|
||||
{
|
||||
iframe_t dact;
|
||||
|
||||
if (mISDNport->b_state[i] == B_STATE_ACTIVE)
|
||||
{
|
||||
ph_control(mISDNport->b_addr[i], CMX_CONF_SPLIT, 0);
|
||||
ph_control(mISDNport->b_addr[i], CMX_RECEIVE_ON, 0);
|
||||
/* deactivate bchannel */
|
||||
PDEBUG("deactivating bchannel (index %d), because currently active.\n", i);
|
||||
dact.prim = DL_RELEASE | REQUEST;
|
||||
dact.addr = mISDNport->b_addr[i] | FLG_MSG_DOWN;
|
||||
dact.dinfo = 0;
|
||||
dact.len = 0;
|
||||
mISDN_write(mISDNdevice, &dact, mISDN_HEADER_LEN+dact.len, TIMEOUT_1SEC);
|
||||
mISDNport->b_state[i] = B_STATE_DEACTIVATING;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* main loop for processing messages from mISDN device
|
||||
*/
|
||||
int mISDN_handler(void)
|
||||
{
|
||||
iframe_t *frm;
|
||||
struct mISDNport *mISDNport;
|
||||
int i;
|
||||
unsigned char data[2048];
|
||||
int len;
|
||||
|
||||
/* get message from kernel */
|
||||
len = mISDN_read(mISDNdevice, data, sizeof(data), 0);
|
||||
if (len < 0)
|
||||
{
|
||||
if (errno == EAGAIN)
|
||||
return(0);
|
||||
fprintf(stderr, "FATAL ERROR: failed to do mISDN_read()\n");
|
||||
exit(-1);
|
||||
}
|
||||
if (!len)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
frm = (iframe_t *)data;
|
||||
|
||||
/* global prim */
|
||||
switch(frm->prim)
|
||||
{
|
||||
case MGR_INITTIMER | CONFIRM:
|
||||
case MGR_ADDTIMER | CONFIRM:
|
||||
case MGR_DELTIMER | CONFIRM:
|
||||
case MGR_REMOVETIMER | CONFIRM:
|
||||
return(1);
|
||||
}
|
||||
|
||||
/* find the port */
|
||||
mISDNport = mISDNport_first;
|
||||
while(mISDNport)
|
||||
{
|
||||
if ((frm->addr&STACK_ID_MASK) == (unsigned int)(mISDNport->upper_id&STACK_ID_MASK))
|
||||
{
|
||||
/* d-message */
|
||||
switch(frm->prim)
|
||||
{
|
||||
case MGR_SHORTSTATUS | INDICATION:
|
||||
case MGR_SHORTSTATUS | CONFIRM:
|
||||
switch(frm->dinfo) {
|
||||
case SSTATUS_L1_ACTIVATED:
|
||||
PDEBUG("Received SSTATUS_L1_ACTIVATED for port %d.\n", mISDNport->portnum);
|
||||
goto ss_act;
|
||||
case SSTATUS_L1_DEACTIVATED:
|
||||
PDEBUG("Received SSTATUS_L1_DEACTIVATED for port %d.\n", mISDNport->portnum);
|
||||
goto ss_deact;
|
||||
}
|
||||
break;
|
||||
|
||||
case PH_ACTIVATE | CONFIRM:
|
||||
case PH_ACTIVATE | INDICATION:
|
||||
PDEBUG("Received PH_ACTIVATE for port %d.\n", mISDNport->portnum);
|
||||
ss_act:
|
||||
if (!mISDNport->l1link)
|
||||
{
|
||||
mISDNport->l1link = 1;
|
||||
show_state(mISDNport);
|
||||
}
|
||||
if (mISDNport->que_len)
|
||||
{
|
||||
mISDN_write(mISDNdevice, mISDNport->que_frm, mISDNport->que_len, TIMEOUT_1SEC);
|
||||
mISDNport->que_len = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case PH_DEACTIVATE | CONFIRM:
|
||||
case PH_DEACTIVATE | INDICATION:
|
||||
PDEBUG("Received PH_DEACTIVATE for port %d.\n", mISDNport->portnum);
|
||||
ss_deact:
|
||||
if (mISDNport->l1link)
|
||||
{
|
||||
mISDNport->l1link = 0;
|
||||
show_state(mISDNport);
|
||||
}
|
||||
mISDNport->que_len = 0;
|
||||
break;
|
||||
|
||||
case PH_CONTROL | CONFIRM:
|
||||
case PH_CONTROL | INDICATION:
|
||||
PDEBUG("Received PH_CONTROL for port %d.\n", mISDNport->portnum);
|
||||
break;
|
||||
|
||||
case PH_DATA | INDICATION:
|
||||
if (traffic)
|
||||
show_traffic(mISDNport, data + mISDN_HEADER_LEN, frm->len);
|
||||
PDEBUG("GOT data from %s port %d prim 0x%x dinfo 0x%x addr 0x%x\n", (mISDNport->ntmode)?"NT":"TE", mISDNport->portnum, frm->prim, frm->dinfo, frm->addr);
|
||||
if (mISDNport->count & 1)
|
||||
{
|
||||
if (mISDNport->prev == NULL)
|
||||
{
|
||||
printf("soft error, no prev where expected.\n");
|
||||
exit (0);
|
||||
}
|
||||
/* sending to previous port */
|
||||
frm->prim = PH_DATA | REQUEST;
|
||||
frm->addr = mISDNport->prev->upper_id | FLG_MSG_DOWN;
|
||||
PDEBUG("sending to %s port %d prim 0x%x dinfo 0x%x addr 0x%x\n", (mISDNport->prev->ntmode)?"NT":"TE", mISDNport->prev->portnum, frm->prim, frm->dinfo, frm->addr);
|
||||
if (mISDNport->prev->l1link)
|
||||
mISDN_write(mISDNdevice, frm, mISDN_HEADER_LEN+frm->len, TIMEOUT_1SEC);
|
||||
else {
|
||||
PDEBUG("layer 1 is down, so we queue and activate link.\n");
|
||||
memcpy(mISDNport->prev->que_frm, frm, len);
|
||||
mISDNport->prev->que_len = len;
|
||||
frm->prim = PH_ACTIVATE | REQUEST;
|
||||
frm->dinfo = 0;
|
||||
frm->len = 0;
|
||||
mISDN_write(mISDNdevice, frm, mISDN_HEADER_LEN+frm->len, TIMEOUT_1SEC);
|
||||
}
|
||||
} else {
|
||||
|
||||
if (mISDNport->next == NULL)
|
||||
{
|
||||
printf("soft error, no next where expected.\n");
|
||||
exit (0);
|
||||
}
|
||||
/* sending to next port */
|
||||
frm->prim = PH_DATA | REQUEST;
|
||||
frm->addr = mISDNport->next->upper_id | FLG_MSG_DOWN;
|
||||
PDEBUG("sending to %s port %d prim 0x%x dinfo 0x%x addr 0x%x\n", (mISDNport->next->ntmode)?"NT":"TE", mISDNport->next->portnum, frm->prim, frm->dinfo, frm->addr);
|
||||
if (mISDNport->next->l1link)
|
||||
mISDN_write(mISDNdevice, frm, mISDN_HEADER_LEN+frm->len, TIMEOUT_1SEC);
|
||||
else {
|
||||
PDEBUG("layer 1 is down, so we queue and activate link.\n");
|
||||
memcpy(mISDNport->next->que_frm, frm, len);
|
||||
mISDNport->next->que_len = len;
|
||||
frm->prim = PH_ACTIVATE | REQUEST;
|
||||
frm->dinfo = 0;
|
||||
frm->len = 0;
|
||||
mISDN_write(mISDNdevice, frm, mISDN_HEADER_LEN+frm->len, TIMEOUT_1SEC);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PH_DATA | CONFIRM:
|
||||
//PDEBUG("GOT confirm from %s port %d prim 0x%x dinfo 0x%x addr 0x%x\n", (mISDNport->ntmode)?"NT":"TE", mISDNport->portnum, frm->prim, frm->dinfo, frm->addr);
|
||||
break;
|
||||
|
||||
case PH_DATA | REQUEST:
|
||||
PDEBUG("GOT strange PH_DATA REQUEST from %s port %d prim 0x%x dinfo 0x%x addr 0x%x\n", (mISDNport->ntmode)?"NT":"TE", mISDNport->portnum, frm->prim, frm->dinfo, frm->addr);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
//PDEBUG("flg:%d upper_id=%x addr=%x\n", (frm->addr&FLG_CHILD_STACK), (mISDNport->b_addr[0])&(~IF_CHILDMASK), (frm->addr)&(~IF_CHILDMASK));
|
||||
/* check if child, and if parent stack match */
|
||||
if ((frm->addr&FLG_CHILD_STACK) && (((unsigned int)(mISDNport->b_addr[0])&(~CHILD_ID_MASK)&STACK_ID_MASK) == ((frm->addr)&(~CHILD_ID_MASK)&STACK_ID_MASK)))
|
||||
{
|
||||
/* b-message */
|
||||
switch(frm->prim)
|
||||
{
|
||||
/* we don't care about confirms, we use rx data to sync tx */
|
||||
case PH_DATA | CONFIRM:
|
||||
case DL_DATA | CONFIRM:
|
||||
break;
|
||||
|
||||
/* we receive audio data, we respond to it AND we send tones */
|
||||
case PH_DATA | INDICATION:
|
||||
case DL_DATA | INDICATION:
|
||||
case PH_CONTROL | INDICATION:
|
||||
i = 0;
|
||||
while(i < mISDNport->b_num)
|
||||
{
|
||||
if ((unsigned int)(mISDNport->b_addr[i]&STACK_ID_MASK) == (frm->addr&STACK_ID_MASK))
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
if (i == mISDNport->b_num)
|
||||
{
|
||||
fprintf(stderr, "unhandled b-message (address 0x%x).\n", frm->addr);
|
||||
break;
|
||||
}
|
||||
PDEBUG("got B-channel data, this should not happen all the time. (just a few until cmx release tx-data are ok)\n");
|
||||
break;
|
||||
|
||||
case PH_ACTIVATE | INDICATION:
|
||||
case DL_ESTABLISH | INDICATION:
|
||||
case PH_ACTIVATE | CONFIRM:
|
||||
case DL_ESTABLISH | CONFIRM:
|
||||
PDEBUG("DL_ESTABLISH confirm: bchannel is now activated (address 0x%x).\n", frm->addr);
|
||||
i = 0;
|
||||
while(i < mISDNport->b_num)
|
||||
{
|
||||
if ((unsigned int)(mISDNport->b_addr[i]&STACK_ID_MASK) == (frm->addr&STACK_ID_MASK))
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
if (i == mISDNport->b_num)
|
||||
{
|
||||
fprintf(stderr, "unhandled b-establish (address 0x%x).\n", frm->addr);
|
||||
break;
|
||||
}
|
||||
mISDNport->b_state[i] = B_STATE_ACTIVE;
|
||||
bchannel_activate(mISDNport, i);
|
||||
break;
|
||||
|
||||
case PH_DEACTIVATE | INDICATION:
|
||||
case DL_RELEASE | INDICATION:
|
||||
case PH_DEACTIVATE | CONFIRM:
|
||||
case DL_RELEASE | CONFIRM:
|
||||
PDEBUG("DL_RELEASE confirm: bchannel is now de-activated (address 0x%x).\n", frm->addr);
|
||||
i = 0;
|
||||
while(i < mISDNport->b_num)
|
||||
{
|
||||
if ((unsigned int)(mISDNport->b_addr[i]&STACK_ID_MASK) == (frm->addr&STACK_ID_MASK))
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
if (i == mISDNport->b_num)
|
||||
{
|
||||
fprintf(stderr, "unhandled b-release (address 0x%x).\n", frm->addr);
|
||||
break;
|
||||
}
|
||||
mISDNport->b_state[i] = B_STATE_IDLE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
mISDNport = mISDNport->next;
|
||||
}
|
||||
if (!mISDNport)
|
||||
{
|
||||
if (frm->prim == (MGR_TIMER | INDICATION))
|
||||
fprintf(stderr, "unhandled timer indication message: prim(0x%x) addr(0x%x) len(%d)\n", frm->prim, frm->addr, len);
|
||||
else
|
||||
fprintf(stderr, "unhandled message: prim(0x%x) addr(0x%x) len(%d)\n", frm->prim, frm->addr, len);
|
||||
}
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* global function to add a new card (port)
|
||||
*/
|
||||
struct mISDNport *mISDN_port_open(int port)
|
||||
{
|
||||
int ret;
|
||||
unsigned char buff[1025];
|
||||
iframe_t *frm = (iframe_t *)buff;
|
||||
stack_info_t *stinf;
|
||||
struct mISDNport *mISDNport, **mISDNportp, *mISDNport_prev;
|
||||
int i, cnt;
|
||||
layer_info_t li;
|
||||
// interface_info_t ii;
|
||||
mISDN_pid_t pid;
|
||||
int pri = 0;
|
||||
int nt = 0;
|
||||
iframe_t dact;
|
||||
|
||||
/* open mISDNdevice if not already open */
|
||||
if (mISDNdevice < 0)
|
||||
{
|
||||
ret = mISDN_open();
|
||||
if (ret < 0)
|
||||
{
|
||||
fprintf(stderr, "cannot open mISDN device ret=%d errno=%d (%s) Check for mISDN modules!\nAlso did you create \"/dev/mISDN\"? Do: \"mknod /dev/mISDN c 46 0\"\n", ret, errno, strerror(errno));
|
||||
return(0);
|
||||
}
|
||||
mISDNdevice = ret;
|
||||
PDEBUG("mISDN device opened.\n");
|
||||
|
||||
/* create entity for layer 3 TE-mode */
|
||||
mISDN_write_frame(mISDNdevice, buff, 0, MGR_NEWENTITY | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
|
||||
ret = mISDN_read_frame(mISDNdevice, frm, sizeof(iframe_t), 0, MGR_NEWENTITY | CONFIRM, TIMEOUT_1SEC);
|
||||
if (ret < (int)mISDN_HEADER_LEN)
|
||||
{
|
||||
noentity:
|
||||
fprintf(stderr, "cannot request MGR_NEWENTITY from mISDN. Exitting due to software bug.");
|
||||
exit(-1);
|
||||
}
|
||||
entity = frm->dinfo & 0xffff;
|
||||
if (!entity)
|
||||
goto noentity;
|
||||
PDEBUG("our entity for l3-processes is %d.\n", entity);
|
||||
}
|
||||
|
||||
/* query port's requirements */
|
||||
cnt = mISDN_get_stack_count(mISDNdevice);
|
||||
if (cnt <= 0)
|
||||
{
|
||||
fprintf(stderr, "Found no card. Please be sure to load card drivers.\n");
|
||||
return(0);
|
||||
}
|
||||
if (port>cnt || port<1)
|
||||
{
|
||||
fprintf(stderr, "Port (%d) given is out of existing port range (%d-%d)\n", port, 1, cnt);
|
||||
return(0);
|
||||
}
|
||||
ret = mISDN_get_stack_info(mISDNdevice, port, buff, sizeof(buff));
|
||||
if (ret < 0)
|
||||
{
|
||||
fprintf(stderr, "Cannot get stack info for port %d (ret=%d)\n", port, ret);
|
||||
return(0);
|
||||
}
|
||||
stinf = (stack_info_t *)&frm->data.p;
|
||||
switch(stinf->pid.protocol[0] & ~ISDN_PID_FEATURE_MASK)
|
||||
{
|
||||
case ISDN_PID_L0_TE_S0:
|
||||
PDEBUG("TE-mode BRI S/T interface line\n");
|
||||
break;
|
||||
case ISDN_PID_L0_NT_S0:
|
||||
PDEBUG("NT-mode BRI S/T interface port\n");
|
||||
nt = 1;
|
||||
break;
|
||||
case ISDN_PID_L0_TE_U:
|
||||
PDEBUG("TE-mode BRI U interface line\n");
|
||||
break;
|
||||
case ISDN_PID_L0_NT_U:
|
||||
PDEBUG("NT-mode BRI U interface port\n");
|
||||
nt = 1;
|
||||
break;
|
||||
case ISDN_PID_L0_TE_UP2:
|
||||
PDEBUG("TE-mode BRI Up2 interface line\n");
|
||||
break;
|
||||
case ISDN_PID_L0_NT_UP2:
|
||||
PDEBUG("NT-mode BRI Up2 interface port\n");
|
||||
nt = 1;
|
||||
break;
|
||||
case ISDN_PID_L0_TE_E1:
|
||||
PDEBUG("TE-mode PRI E1 interface line\n");
|
||||
pri = 1;
|
||||
break;
|
||||
case ISDN_PID_L0_NT_E1:
|
||||
PDEBUG("LT-mode PRI E1 interface port\n");
|
||||
pri = 1;
|
||||
nt = 1;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "unknown port(%d) type 0x%08x\n", port, stinf->pid.protocol[0]);
|
||||
return(0);
|
||||
}
|
||||
if (stinf->pid.protocol[1] == 0)
|
||||
{
|
||||
fprintf(stderr, "Given port %d: Missing layer 1 protocol.\n", port);
|
||||
return(0);
|
||||
}
|
||||
if (stinf->pid.protocol[2])
|
||||
{
|
||||
fprintf(stderr, "Given port %d: Layer 2 protocol 0x%08x is detected, but not allowed for bridging layer 1.\n", port, stinf->pid.protocol[2]);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* add mISDNport structure */
|
||||
mISDNport = mISDNport_first;
|
||||
mISDNportp = &mISDNport_first;
|
||||
mISDNport_prev = NULL;
|
||||
while(mISDNport)
|
||||
{
|
||||
mISDNport_prev=mISDNport;
|
||||
mISDNportp = &mISDNport->next;
|
||||
mISDNport = mISDNport->next;
|
||||
}
|
||||
mISDNport = (struct mISDNport *)calloc(1, sizeof(struct mISDNport));
|
||||
if (!mISDNport)
|
||||
{
|
||||
fprintf(stderr, "Cannot alloc mISDNport structure\n");
|
||||
return(0);
|
||||
}
|
||||
memset(mISDNport, 0, sizeof(mISDNport));
|
||||
*mISDNportp = mISDNport;
|
||||
mISDNport->prev = mISDNport_prev;
|
||||
|
||||
/* allocate ressources of port */
|
||||
mISDNport->count = portcount++;
|
||||
mISDNport->portnum = port;
|
||||
mISDNport->ntmode = nt;
|
||||
mISDNport->pri = pri;
|
||||
mISDNport->d_stid = stinf->id;
|
||||
PDEBUG("d_stid = 0x%x.\n", mISDNport->d_stid);
|
||||
mISDNport->b_num = stinf->childcnt;
|
||||
PDEBUG("Port has %d b-channels.\n", mISDNport->b_num);
|
||||
i = 0;
|
||||
while(i < stinf->childcnt)
|
||||
{
|
||||
mISDNport->b_stid[i] = stinf->child[i];
|
||||
PDEBUG("b_stid[%d] = 0x%x.\n", i, mISDNport->b_stid[i]);
|
||||
i++;
|
||||
}
|
||||
memset(&li, 0, sizeof(li));
|
||||
strcpy(&li.name[0], "bridge l2");
|
||||
li.object_id = -1;
|
||||
li.extentions = 0;
|
||||
li.pid.protocol[2] = (nt)?ISDN_PID_L2_LAPD_NET:ISDN_PID_L2_LAPD;
|
||||
li.pid.layermask = ISDN_LAYER(2);
|
||||
li.st = mISDNport->d_stid;
|
||||
ret = mISDN_new_layer(mISDNdevice, &li);
|
||||
if (ret)
|
||||
{
|
||||
fprintf(stderr, "Cannot add layer 2 of port %d (ret %d)\n", port, ret);
|
||||
return(0);
|
||||
}
|
||||
mISDNport->upper_id = li.id;
|
||||
ret = mISDN_register_layer(mISDNdevice, mISDNport->d_stid, mISDNport->upper_id);
|
||||
if (ret)
|
||||
{
|
||||
fprintf(stderr, "Cannot register layer 2 of port %d\n", port);
|
||||
return(0);
|
||||
}
|
||||
mISDNport->lower_id = mISDN_get_layerid(mISDNdevice, mISDNport->d_stid, 1);
|
||||
if (mISDNport->lower_id < 0)
|
||||
{
|
||||
fprintf(stderr, "Cannot get layer(1) id of port %d\n", port);
|
||||
return(0);
|
||||
}
|
||||
mISDNport->upper_id = mISDN_get_layerid(mISDNdevice, mISDNport->d_stid, 2);
|
||||
if (mISDNport->upper_id < 0)
|
||||
{
|
||||
fprintf(stderr, "Cannot get layer(2) id of port %d\n", port);
|
||||
return(0);
|
||||
}
|
||||
PDEBUG("Layer 2 of port %d added.\n", port);
|
||||
|
||||
/* try to activate link layer 1 */
|
||||
{
|
||||
iframe_t act;
|
||||
/* L1 */
|
||||
PDEBUG("sending PH_ACTIVATE to port %d.\n", port);
|
||||
act.prim = PH_ACTIVATE | REQUEST;
|
||||
act.addr = mISDNport->upper_id | FLG_MSG_DOWN;
|
||||
act.dinfo = 0;
|
||||
act.len = 0;
|
||||
mISDN_write(mISDNdevice, &act, mISDN_HEADER_LEN+act.len, TIMEOUT_1SEC);
|
||||
}
|
||||
/* initially, we assume that the link is down */
|
||||
mISDNport->l1link = 0;
|
||||
|
||||
PDEBUG("using 'mISDN_dsp.o' module\n");
|
||||
|
||||
/* add all bchannel layers */
|
||||
i = 0;
|
||||
while(i < mISDNport->b_num)
|
||||
{
|
||||
mISDNport->b_state[i] = B_STATE_IDLE;
|
||||
/* create new layer */
|
||||
PDEBUG("creating bchannel %d (index %d).\n" , i+1+(i>=15), i);
|
||||
memset(&li, 0, sizeof(li));
|
||||
memset(&pid, 0, sizeof(pid));
|
||||
li.object_id = -1;
|
||||
li.extentions = 0;
|
||||
li.st = mISDNport->b_stid[i];
|
||||
strcpy(li.name, "B L4");
|
||||
li.pid.layermask = ISDN_LAYER((4));
|
||||
li.pid.protocol[4] = ISDN_PID_L4_B_USER;
|
||||
ret = mISDN_new_layer(mISDNdevice, &li);
|
||||
if (ret)
|
||||
{
|
||||
failed_new_layer:
|
||||
fprintf(stderr, "mISDN_new_layer() failed to add bchannel %d (index %d)\n", i+1+(i>=15), i);
|
||||
return(0);
|
||||
}
|
||||
mISDNport->b_addr[i] = li.id;
|
||||
if (!li.id)
|
||||
{
|
||||
goto failed_new_layer;
|
||||
}
|
||||
PDEBUG("new layer (b_addr=0x%x)\n", mISDNport->b_addr[i]);
|
||||
|
||||
/* create new stack */
|
||||
pid.protocol[1] = ISDN_PID_L1_B_64TRANS;
|
||||
pid.protocol[2] = ISDN_PID_L2_B_TRANS;
|
||||
pid.protocol[3] = ISDN_PID_L3_B_DSP;
|
||||
pid.protocol[4] = ISDN_PID_L4_B_USER;
|
||||
pid.layermask = ISDN_LAYER((1)) | ISDN_LAYER((2)) | ISDN_LAYER((3)) | ISDN_LAYER((4));
|
||||
ret = mISDN_set_stack(mISDNdevice, mISDNport->b_stid[i], &pid);
|
||||
if (ret)
|
||||
{
|
||||
stack_error:
|
||||
fprintf(stderr, "mISDN_set_stack() failed (ret=%d) to add bchannel (index %d) stid=0x%x\n", ret, i, mISDNport->b_stid[i]);
|
||||
mISDN_write_frame(mISDNdevice, buff, mISDNport->b_addr[i], MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
|
||||
mISDNport->b_addr[i] = 0;
|
||||
return(0);
|
||||
}
|
||||
ret = mISDN_get_setstack_ind(mISDNdevice, mISDNport->b_addr[i]);
|
||||
if (ret)
|
||||
goto stack_error;
|
||||
|
||||
/* get layer id */
|
||||
mISDNport->b_addr[i] = mISDN_get_layerid(mISDNdevice, mISDNport->b_stid[i], 4);
|
||||
if (!mISDNport->b_addr[i])
|
||||
goto stack_error;
|
||||
/* deactivate bchannel if already enabled due to crash */
|
||||
PDEBUG("deactivating bchannel (index %d) as a precaution.\n", i);
|
||||
dact.prim = DL_RELEASE | REQUEST;
|
||||
dact.addr = mISDNport->b_addr[i] | FLG_MSG_DOWN;
|
||||
dact.dinfo = 0;
|
||||
dact.len = 0;
|
||||
mISDN_write(mISDNdevice, &dact, mISDN_HEADER_LEN+dact.len, TIMEOUT_1SEC);
|
||||
|
||||
i++;
|
||||
}
|
||||
PDEBUG("using port %d %s %d b-channels\n", mISDNport->portnum, (mISDNport->ntmode)?"NT-mode":"TE-mode", mISDNport->b_num);
|
||||
return(mISDNport);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* global function to free ALL cards (ports)
|
||||
*/
|
||||
void mISDN_port_close(void)
|
||||
{
|
||||
struct mISDNport *mISDNport, *mISDNporttemp;
|
||||
unsigned char buf[32];
|
||||
int i;
|
||||
|
||||
/* free all ports */
|
||||
mISDNport = mISDNport_first;
|
||||
while(mISDNport)
|
||||
{
|
||||
i = 0;
|
||||
while(i < mISDNport->b_num)
|
||||
{
|
||||
bchannel_deactivate(mISDNport, i);
|
||||
PDEBUG("freeing %s port %d bchannel (index %d).\n", (mISDNport->ntmode)?"NT":"TE", mISDNport->portnum, i);
|
||||
if (mISDNport->b_stid[i])
|
||||
{
|
||||
mISDN_clear_stack(mISDNdevice, mISDNport->b_stid[i]);
|
||||
if (mISDNport->b_addr[i])
|
||||
mISDN_write_frame(mISDNdevice, buf, mISDNport->b_addr[i] | FLG_MSG_DOWN, MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
PDEBUG("freeing d-stack.\n");
|
||||
if (mISDNport->d_stid)
|
||||
{
|
||||
// mISDN_clear_stack(mISDNdevice, mISDNport->d_stid);
|
||||
if (mISDNport->lower_id)
|
||||
mISDN_write_frame(mISDNdevice, buf, mISDNport->lower_id, MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
|
||||
}
|
||||
|
||||
mISDNporttemp = mISDNport;
|
||||
mISDNport = mISDNport->next;
|
||||
memset(mISDNporttemp, 0, sizeof(struct mISDNport));
|
||||
free(mISDNporttemp);
|
||||
}
|
||||
mISDNport_first = NULL;
|
||||
|
||||
/* close mISDNdevice */
|
||||
if (mISDNdevice >= 0)
|
||||
{
|
||||
/* free entity */
|
||||
mISDN_write_frame(mISDNdevice, buf, 0, MGR_DELENTITY | REQUEST, entity, 0, NULL, TIMEOUT_1SEC);
|
||||
/* close device */
|
||||
mISDN_close(mISDNdevice);
|
||||
mISDNdevice = -1;
|
||||
PDEBUG("mISDN device closed.\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* main routine and loop
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct mISDNport *mISDNport_a, *mISDNport_b;
|
||||
int i, j;
|
||||
int forking = 0;
|
||||
|
||||
if (argc <= 1)
|
||||
{
|
||||
usage:
|
||||
printf("Usage: %s [--traffic] [--fork] <port a> <port b> [<port a> <port b> [...]]\n\n", argv[0]);
|
||||
printf("Bridges given pairs of ports. The number of given ports must be even.\n");
|
||||
printf("Each pair of ports must be the same interface size (equal channel number).\n");
|
||||
printf("Both ports may have same mode, e.g. TE-mode, to bridge ISDN to leased line.\n");
|
||||
printf("Also bridging a card to ISDN over IP tunnel is possible. (L1oIP)\n");
|
||||
printf("Note: Ports must have layer 1 only, so layermask must be 0x3 to make it work.\n");
|
||||
printf("--fork will make a daemon fork.\n");
|
||||
printf("--traffic will show D-channel traffic.\n");
|
||||
return(0);
|
||||
}
|
||||
if (strstr("help", argv[1]))
|
||||
goto usage;
|
||||
|
||||
/* open mISDN */
|
||||
i = 1;
|
||||
while (i < argc)
|
||||
{
|
||||
usleep(200000);
|
||||
if (!strcmp(argv[i], "--traffic"))
|
||||
{
|
||||
traffic = 1;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(argv[i], "--fork"))
|
||||
{
|
||||
forking = 1;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* open port a */
|
||||
mISDNport_a = mISDN_port_open(strtol(argv[i], NULL, 0));
|
||||
if (!mISDNport_a)
|
||||
goto error;
|
||||
printf("port A: #%d %s, %d b-channels\n", mISDNport_a->portnum, (mISDNport_a->ntmode)?"NT-mode":"TE-mode", mISDNport_a->b_num);
|
||||
i++; // two ports at the same time
|
||||
if (i == argc)
|
||||
{
|
||||
fprintf(stderr, "The number of ports given are not even.\nYou may only bridge two or more pairs of ports.\n\n");
|
||||
goto error;
|
||||
}
|
||||
mISDNport_b = mISDN_port_open(strtol(argv[i], NULL, 0));
|
||||
if (!mISDNport_b)
|
||||
goto error;
|
||||
/* open port b */
|
||||
printf("port B: #%d %s, %d b-channels\n", mISDNport_b->portnum, (mISDNport_b->ntmode)?"NT-mode":"TE-mode", mISDNport_b->b_num);
|
||||
i++; // two ports at the same time
|
||||
|
||||
if (mISDNport_a->b_num != mISDNport_b->b_num)
|
||||
{
|
||||
fprintf(stderr, "The pair of ports are not compatible for bridging.\n");
|
||||
fprintf(stderr, "The number ob B-channels are different: port(%d)=%d, port(%d)=%d\n", mISDNport_a->portnum, mISDNport_a->b_num, mISDNport_b->portnum, mISDNport_b->b_num);
|
||||
|
||||
mISDN_port_close();
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* opening and bridge each pair of bchannels */
|
||||
j = 0;
|
||||
while(j < mISDNport_a->b_num)
|
||||
{
|
||||
bchannel_activate(mISDNport_a, j);
|
||||
while(mISDN_handler())
|
||||
;
|
||||
j++;
|
||||
}
|
||||
j = 0;
|
||||
while(j < mISDNport_b->b_num)
|
||||
{
|
||||
bchannel_activate(mISDNport_b, j);
|
||||
while(mISDN_handler())
|
||||
;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
printf("%s now started\n",argv[0]);
|
||||
|
||||
/* forking */
|
||||
if (forking) {
|
||||
pid_t pid;
|
||||
|
||||
/* do daemon fork */
|
||||
pid = fork();
|
||||
|
||||
if (pid < 0)
|
||||
{
|
||||
fprintf(stderr, "Cannot fork!\n");
|
||||
goto free;
|
||||
}
|
||||
if (pid != 0)
|
||||
{
|
||||
exit(0);
|
||||
}
|
||||
usleep(200000);
|
||||
printf("\n");
|
||||
|
||||
/* do second fork */
|
||||
pid = fork();
|
||||
|
||||
if (pid < 0)
|
||||
{
|
||||
fprintf(stderr, "Cannot fork!\n");
|
||||
goto free;
|
||||
}
|
||||
if (pid != 0)
|
||||
{
|
||||
printf("PBX: Starting daemon.\n");
|
||||
exit(0);
|
||||
}
|
||||
nooutput = 1;
|
||||
}
|
||||
|
||||
/* signal handlers */
|
||||
signal(SIGINT,sighandler);
|
||||
signal(SIGHUP,sighandler);
|
||||
signal(SIGTERM,sighandler);
|
||||
signal(SIGPIPE,sighandler);
|
||||
|
||||
while(!quit)
|
||||
{
|
||||
//mISDNport_a->l1link = 1;
|
||||
if (!mISDN_handler())
|
||||
usleep(30000);
|
||||
}
|
||||
|
||||
/* remove signal handler */
|
||||
signal(SIGINT,SIG_DFL);
|
||||
signal(SIGHUP,SIG_DFL);
|
||||
signal(SIGTERM,SIG_DFL);
|
||||
signal(SIGPIPE,SIG_DFL);
|
||||
|
||||
free:
|
||||
mISDN_port_close();
|
||||
return(0);
|
||||
|
||||
error:
|
||||
return(-1);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue