154 lines
4.4 KiB
C
154 lines
4.4 KiB
C
/*****************************************************************************\
|
|
** **
|
|
** LCR **
|
|
** **
|
|
**---------------------------------------------------------------------------**
|
|
** Copyright: Andreas Eversberg **
|
|
** **
|
|
** loopback interface functions **
|
|
** **
|
|
\*****************************************************************************/
|
|
|
|
#include "main.h"
|
|
|
|
struct mISDNloop mISDNloop = { -1, 0 };
|
|
|
|
void mISDNloop_close(void)
|
|
{
|
|
if (mISDNloop.sock > -1)
|
|
close(mISDNloop.sock);
|
|
mISDNloop.sock = -1;
|
|
}
|
|
|
|
int mISDNloop_open()
|
|
{
|
|
int ret;
|
|
int cnt;
|
|
unsigned long on = 1;
|
|
struct sockaddr_mISDN addr;
|
|
struct mISDN_devinfo devinfo;
|
|
int pri, bri;
|
|
|
|
/* already open */
|
|
if (mISDNloop.sock > -1)
|
|
return 0;
|
|
|
|
PDEBUG(DEBUG_PORT, "Open external interface of loopback.\n");
|
|
|
|
/* check port counts */
|
|
ret = ioctl(mISDNsocket, IMGETCOUNT, &cnt);
|
|
if (ret < 0) {
|
|
fprintf(stderr, "Cannot get number of mISDN devices. (ioctl IMGETCOUNT failed ret=%d)\n", ret);
|
|
return(ret);
|
|
}
|
|
|
|
if (cnt <= 0) {
|
|
PERROR_RUNTIME("Found no card. Please be sure to load card drivers.\n");
|
|
return -EIO;
|
|
}
|
|
mISDNloop.port = mISDN_getportbyname(mISDNsocket, cnt, options.loopback_ext);
|
|
if (mISDNloop.port < 0) {
|
|
PERROR_RUNTIME("Port name '%s' not found, did you load loopback interface?.\n", options.loopback_ext);
|
|
return mISDNloop.port;
|
|
}
|
|
/* get protocol */
|
|
bri = pri = 0;
|
|
devinfo.id = mISDNloop.port;
|
|
ret = ioctl(mISDNsocket, IMGETDEVINFO, &devinfo);
|
|
if (ret < 0) {
|
|
PERROR_RUNTIME("Cannot get device information for port %d. (ioctl IMGETDEVINFO failed ret=%d)\n", mISDNloop.port, ret);
|
|
return ret;
|
|
}
|
|
if (devinfo.Dprotocols & (1 << ISDN_P_TE_S0)) {
|
|
bri = 1;
|
|
}
|
|
if (devinfo.Dprotocols & (1 << ISDN_P_TE_E1)) {
|
|
pri = 1;
|
|
}
|
|
if (!bri && !pri) {
|
|
PERROR_RUNTIME("loop port %d does not support TE PRI or TE BRI.\n", mISDNloop.port);
|
|
}
|
|
/* open socket */
|
|
if ((mISDNloop.sock = socket(PF_ISDN, SOCK_DGRAM, (pri)?ISDN_P_TE_E1:ISDN_P_TE_S0)) < 0) {
|
|
PERROR_RUNTIME("loop port %d failed to open socket.\n", mISDNloop.port);
|
|
mISDNloop_close();
|
|
return mISDNloop.sock;
|
|
}
|
|
/* set nonblocking io */
|
|
if ((ret = ioctl(mISDNloop.sock, FIONBIO, &on)) < 0) {
|
|
PERROR_RUNTIME("loop port %d failed to set socket into nonblocking io.\n", mISDNloop.port);
|
|
mISDNloop_close();
|
|
return ret;
|
|
}
|
|
/* bind socket to dchannel */
|
|
memset(&addr, 0, sizeof(addr));
|
|
addr.family = AF_ISDN;
|
|
addr.dev = mISDNloop.port;
|
|
addr.channel = 0;
|
|
if ((ret = bind(mISDNloop.sock, (struct sockaddr *)&addr, sizeof(addr))) < 0) {
|
|
PERROR_RUNTIME("loop port %d failed to bind socket. (name = %s errno=%d)\n", mISDNloop.port, options.loopback_ext, errno);
|
|
mISDNloop_close();
|
|
return (ret);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int loop_hunt_bchannel(class PmISDN *port, struct mISDNport *mISDNport)
|
|
{
|
|
int channel;
|
|
int i;
|
|
char map[mISDNport->b_num];
|
|
struct interface *interface;
|
|
struct interface_port *ifport;
|
|
|
|
chan_trace_header(mISDNport, port, "CHANNEL SELECTION (setup)", DIRECTION_NONE);
|
|
add_trace("channel", "reserved", "%d", mISDNport->b_reserved);
|
|
if (mISDNport->b_reserved >= mISDNport->b_num) { // of out chan..
|
|
add_trace("conclusion", NULL, "all channels are reserved");
|
|
end_trace();
|
|
return(-34); // no channel
|
|
}
|
|
|
|
/* map all used ports of shared loopback interface */
|
|
memset(map, 0, sizeof(map));
|
|
interface = interface_first;
|
|
while(interface) {
|
|
ifport = interface->ifport;
|
|
while(ifport) {
|
|
if (!strcmp(ifport->portname, options.loopback_lcr)) {
|
|
i = 0;
|
|
while(i < mISDNport->b_num) {
|
|
if (mISDNport->b_port[i])
|
|
map[i] = 1;
|
|
i++;
|
|
}
|
|
}
|
|
ifport = ifport->next;
|
|
}
|
|
interface = interface->next;
|
|
}
|
|
|
|
/* find channel */
|
|
i = 0;
|
|
channel = 0;
|
|
while(i < mISDNport->b_num) {
|
|
if (!map[i]) {
|
|
channel = i+1+(i>=15);
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
if (!channel) {
|
|
add_trace("conclusion", NULL, "no channel available");
|
|
end_trace();
|
|
return(-6); // channel unacceptable
|
|
}
|
|
add_trace("conclusion", NULL, "channel available");
|
|
add_trace("connect", "channel", "%d", channel);
|
|
end_trace();
|
|
return(channel);
|
|
}
|
|
|
|
|