Make this application capable of using kernel or user space mISDN
This commit is contained in:
parent
4150cc3e67
commit
3672a4c99e
|
@ -1,4 +1,4 @@
|
|||
AM_CPPFLAGS = -Wall -Wextra -g $(all_includes)
|
||||
AM_CPPFLAGS = -Wall -Wextra -g $(all_includes) -I$(srcdir)/../libmisdnuser/include
|
||||
|
||||
bin_PROGRAMS = \
|
||||
osmo-cc-misdn-endpoint
|
||||
|
@ -7,6 +7,8 @@ osmo_cc_misdn_endpoint_SOURCES = \
|
|||
ie.c \
|
||||
dss1.c \
|
||||
isdn.c \
|
||||
ph_socket.c \
|
||||
ph_driver.c \
|
||||
main.c
|
||||
|
||||
osmo_cc_misdn_endpoint_LDADD = \
|
||||
|
@ -18,5 +20,8 @@ osmo_cc_misdn_endpoint_LDADD = \
|
|||
../libjitter/libjitter.a \
|
||||
../libosmocc/libosmocc.a \
|
||||
../libg711/libg711.a \
|
||||
-lmisdn
|
||||
../libmisdn/libmisdn.a \
|
||||
../libmisdnuser/libmisdnuser.a
|
||||
|
||||
# -lmisdn
|
||||
|
||||
|
|
220
src/isdn/isdn.c
220
src/isdn/isdn.c
|
@ -37,6 +37,7 @@
|
|||
#endif
|
||||
#include <mISDN/mlayer3.h>
|
||||
#include <mISDN/q931.h>
|
||||
#include "../libmisdn/socket.h"
|
||||
|
||||
#ifndef container_of
|
||||
#define container_of(ptr, type, member) ({ \
|
||||
|
@ -655,16 +656,18 @@ void isdn_destroy(isdn_t *isdn_ep)
|
|||
{
|
||||
struct msn_list *msn;
|
||||
|
||||
/* destroy all calls */
|
||||
while (isdn_ep->call_list)
|
||||
call_destroy(isdn_ep->call_list);
|
||||
|
||||
/* remove stack instance */
|
||||
isdn_close(isdn_ep);
|
||||
|
||||
/* close mISDN socket */
|
||||
if (isdn_ep->socket > 0)
|
||||
close(isdn_ep->socket);
|
||||
|
||||
/* destroy all calls */
|
||||
while (isdn_ep->call_list)
|
||||
call_destroy(isdn_ep->call_list);
|
||||
if (isdn_ep->l2sock)
|
||||
close(isdn_ep->l2sock);
|
||||
if (isdn_ep->l2inst)
|
||||
mISDN_base_release(isdn_ep->l2inst);
|
||||
|
||||
/* free msn list */
|
||||
while (isdn_ep->msn_list) {
|
||||
|
@ -683,17 +686,30 @@ void isdn_destroy(isdn_t *isdn_ep)
|
|||
}
|
||||
|
||||
/* initialization and configuration to isdn interface instance */
|
||||
int isdn_initialize(isdn_t *isdn_ep, char law, const char *portname, int ntmode, int ptp, int layer1hold, int layer2hold, const char *channel_out, const char *channel_in, const char *timeouts, int tx_delay, int tx_gain, int rx_gain, const char *pipeline, int dtmf, int local_tones, int serving_location)
|
||||
int isdn_initialize(isdn_t *isdn_ep, ph_socket_t *ph_socket, char law, const char *portname, int ntmode, int ptp, int layer1hold, int layer2hold, const char *channel_out, const char *channel_in, const char *timeouts, int tx_delay, int tx_gain, int rx_gain, const char *pipeline, int dtmf, int local_tones, int serving_location)
|
||||
{
|
||||
int rc;
|
||||
void *mui;
|
||||
|
||||
/* open mISDN socket */
|
||||
rc = socket(PF_ISDN, SOCK_RAW, ISDN_P_BASE);
|
||||
if (rc < 0) {
|
||||
PDEBUG(DISDN, DEBUG_ERROR, "Cannot open mISDN due to errno=%d:%s. (Does your Kernel support socket based mISDN? Protocol family is %d.)\n", errno, strerror(errno), PF_ISDN);
|
||||
return -errno;
|
||||
if (!ph_socket) {
|
||||
/* open mISDN socket */
|
||||
rc = socket(PF_ISDN, SOCK_RAW, ISDN_P_BASE);
|
||||
if (rc < 0) {
|
||||
PDEBUG(DISDN, DEBUG_ERROR, "Cannot open mISDN due to errno=%d:%s. (Does your Kernel support socket based mISDN? Protocol family is %d.)\n", errno, strerror(errno), PF_ISDN);
|
||||
return -errno;
|
||||
}
|
||||
isdn_ep->l2sock = rc;
|
||||
} else {
|
||||
isdn_ep->ph_socket = ph_socket;
|
||||
/* open mISDN user space */
|
||||
rc = mISDN_base_create(&mui, ISDN_P_BASE);
|
||||
if (rc < 0) {
|
||||
PDEBUG(DISDN, DEBUG_ERROR, "Cannot open mISDN due to errno=%d:%s. (Please fix!)\n", errno, strerror(errno));
|
||||
return -errno;
|
||||
}
|
||||
isdn_ep->l2inst = mui;
|
||||
portname = "0";
|
||||
}
|
||||
isdn_ep->socket = rc;
|
||||
|
||||
/* store settings */
|
||||
isdn_ep->law = law;
|
||||
|
@ -907,38 +923,40 @@ static int bchannel_create(isdn_t *isdn_ep, int index)
|
|||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
|
||||
if (isdn_ep->b_sock[index] > 0) {
|
||||
PDEBUG(DISDN, DEBUG_ERROR, "Socket already created for index %d\n", index);
|
||||
return -EIO;
|
||||
if (isdn_ep->l2sock) {
|
||||
if (isdn_ep->b_sock[index] > 0) {
|
||||
PDEBUG(DISDN, DEBUG_ERROR, "Socket already created for index %d\n", index);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* open socket */
|
||||
if (isdn_ep->b_mode[index] == B_MODE_HDLC) {
|
||||
PDEBUG(DISDN, DEBUG_NOTICE, "Use B-Channel with HDLC l!!!\n");
|
||||
}
|
||||
rc = socket(PF_ISDN, SOCK_DGRAM, (isdn_ep->b_mode[index] == B_MODE_HDLC) ? ISDN_P_B_L2DSPHDLC : ISDN_P_B_L2DSP);
|
||||
if (rc < 0) {
|
||||
PDEBUG(DISDN, DEBUG_ERROR, "Failed to open bchannel-socket for index %d with mISDN-DSP layer. Did you load mISDN_dsp.ko?\n", index);
|
||||
return(0);
|
||||
}
|
||||
isdn_ep->b_sock[index] = rc;
|
||||
|
||||
/* set nonblocking io */
|
||||
flags = fcntl(isdn_ep->b_sock[index], F_GETFL);
|
||||
flags |= O_NONBLOCK;
|
||||
fcntl(isdn_ep->b_sock[index], F_SETFL, flags);
|
||||
|
||||
/* bind socket to bchannel */
|
||||
addr.family = AF_ISDN;
|
||||
addr.dev = isdn_ep->portnum;
|
||||
addr.channel = channel;
|
||||
rc = bind(isdn_ep->b_sock[index], (struct sockaddr *)&addr, sizeof(addr));
|
||||
if (rc < 0) {
|
||||
PDEBUG(DISDN, DEBUG_ERROR, "Failed to bind bchannel-socket for index %d with mISDN-DSP layer (errno=%d). Did you load mISDN_dsp.ko?\n", index, errno);
|
||||
close(isdn_ep->b_sock[index]);
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
|
||||
/* open socket */
|
||||
if (isdn_ep->b_mode[index] == B_MODE_HDLC) {
|
||||
PDEBUG(DISDN, DEBUG_NOTICE, "Use B-Channel with HDLC l!!!\n");
|
||||
}
|
||||
rc = socket(PF_ISDN, SOCK_DGRAM, (isdn_ep->b_mode[index] == B_MODE_HDLC) ? ISDN_P_B_L2DSPHDLC : ISDN_P_B_L2DSP);
|
||||
if (rc < 0) {
|
||||
PDEBUG(DISDN, DEBUG_ERROR, "Failed to open bchannel-socket for index %d with mISDN-DSP layer. Did you load mISDN_dsp.ko?\n", index);
|
||||
return(0);
|
||||
}
|
||||
isdn_ep->b_sock[index] = rc;
|
||||
|
||||
/* set nonblocking io */
|
||||
flags = fcntl(isdn_ep->b_sock[index], F_GETFL);
|
||||
flags |= O_NONBLOCK;
|
||||
fcntl(isdn_ep->b_sock[index], F_SETFL, flags);
|
||||
|
||||
/* bind socket to bchannel */
|
||||
addr.family = AF_ISDN;
|
||||
addr.dev = isdn_ep->portnum;
|
||||
addr.channel = channel;
|
||||
rc = bind(isdn_ep->b_sock[index], (struct sockaddr *)&addr, sizeof(addr));
|
||||
if (rc < 0) {
|
||||
PDEBUG(DISDN, DEBUG_ERROR, "Failed to bind bchannel-socket for index %d with mISDN-DSP layer (errno=%d). Did you load mISDN_dsp.ko?\n", index, errno);
|
||||
close(isdn_ep->b_sock[index]);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
PDEBUG(DISDN, DEBUG_DEBUG, "created socket #%d for B-channel %d\n", isdn_ep->b_sock[index], channel);
|
||||
|
||||
return 0;
|
||||
|
@ -951,15 +969,25 @@ static void bchannel_activate(isdn_t *isdn_ep, int index, int activate, int time
|
|||
int channel = index + 1 + (index >= 15);
|
||||
int rc;
|
||||
|
||||
if (isdn_ep->l2sock) {
|
||||
if (isdn_ep->b_sock[index] <= 0)
|
||||
return;
|
||||
|
||||
if (isdn_ep->b_sock[index] <= 0)
|
||||
return;
|
||||
act.prim = (activate) ? PH_ACTIVATE_REQ : PH_DEACTIVATE_REQ;
|
||||
act.id = 0;
|
||||
rc = sendto(isdn_ep->b_sock[index], &act, MISDN_HEADER_LEN, 0, NULL, 0);
|
||||
if (rc < 0)
|
||||
PDEBUG(DISDN, DEBUG_ERROR, "Failed to send to socket #%d, of B-channel %d\n", isdn_ep->b_sock[index], channel);
|
||||
}
|
||||
|
||||
act.prim = (activate) ? PH_ACTIVATE_REQ : PH_DEACTIVATE_REQ;
|
||||
act.id = 0;
|
||||
rc = sendto(isdn_ep->b_sock[index], &act, MISDN_HEADER_LEN, 0, NULL, 0);
|
||||
if (rc < 0)
|
||||
PDEBUG(DISDN, DEBUG_ERROR, "Failed to send to socket #%d, of B-channel %d\n", isdn_ep->b_sock[index], channel);
|
||||
if (isdn_ep->l2inst) {
|
||||
uint8_t mode = PH_MODE_TRANS;
|
||||
if (isdn_ep->b_mode[index] == B_MODE_HDLC) {
|
||||
PDEBUG(DISDN, DEBUG_NOTICE, "Use B-Channel with HDLC!!!\n");
|
||||
mode = PH_MODE_HDLC;
|
||||
}
|
||||
ph_socket_tx_msg(isdn_ep->ph_socket, channel, (activate) ? PH_PRIM_ACT_REQ : PH_PRIM_DACT_REQ, &mode, 1);
|
||||
}
|
||||
|
||||
PDEBUG(DISDN, DEBUG_DEBUG, "%s B-channel %d%s\n", (activate) ? "activating" : "deactivating", channel, (timeout) ? " after timeout recovery" : "");
|
||||
|
||||
|
@ -1077,13 +1105,19 @@ static void bchannel_destroy(isdn_t *isdn_ep, int index)
|
|||
{
|
||||
int channel = index + 1 + (index >= 15);
|
||||
|
||||
if (isdn_ep->b_sock[index] <= 0)
|
||||
return;
|
||||
if (isdn_ep->l2sock) {
|
||||
if (isdn_ep->b_sock[index] <= 0)
|
||||
return;
|
||||
|
||||
PDEBUG(DISDN, DEBUG_DEBUG, "destroyed socket #%d for B-channel %d\n", isdn_ep->b_sock[index], channel);
|
||||
PDEBUG(DISDN, DEBUG_DEBUG, "destroyed socket #%d for B-channel %d\n", isdn_ep->b_sock[index], channel);
|
||||
|
||||
close(isdn_ep->b_sock[index]);
|
||||
isdn_ep->b_sock[index] = 0;
|
||||
close(isdn_ep->b_sock[index]);
|
||||
isdn_ep->b_sock[index] = 0;
|
||||
}
|
||||
|
||||
if (isdn_ep->l2inst) {
|
||||
PDEBUG(DISDN, DEBUG_DEBUG, "destroyed B-channel %d\n", channel);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1287,8 +1321,8 @@ void bchannel_event(isdn_t *isdn_ep, int index, int event)
|
|||
|
||||
static void bchannel_receive(isdn_t *isdn_ep, int index, struct mISDNhead *hh, unsigned char *data, int len);
|
||||
|
||||
/* handle frames from B-channel */
|
||||
static int bchannel_work(isdn_t *isdn_ep, int index)
|
||||
/* handle frames from B-channel (kernel socket) */
|
||||
static int bchannel_kernel_sock_work(isdn_t *isdn_ep, int index)
|
||||
{
|
||||
int channel = index + 1 + (index >= 15);
|
||||
unsigned char buffer[2048+MISDN_HEADER_LEN];
|
||||
|
@ -1320,7 +1354,7 @@ static int bchannel_work(isdn_t *isdn_ep, int index)
|
|||
if (isdn_ep->b_call[index])
|
||||
bchannel_receive(isdn_ep, index, hh, buffer + MISDN_HEADER_LEN, rc - MISDN_HEADER_LEN);
|
||||
else
|
||||
PDEBUG(DISDN, DEBUG_DEBUG, "b-channel is not associated to an ISDNPort (channel %d), ignoring.\n", channel);
|
||||
PDEBUG(DISDN, DEBUG_DEBUG, "b-channel is not associated to a call (channel %d), ignoring.\n", channel);
|
||||
break;
|
||||
|
||||
case PH_ACTIVATE_IND:
|
||||
|
@ -1346,6 +1380,34 @@ static int bchannel_work(isdn_t *isdn_ep, int index)
|
|||
return 1;
|
||||
}
|
||||
|
||||
/* handle data frames from B-channel (ph_socket) */
|
||||
void bchannel_ph_sock_receive(void *priv, int channel, uint8_t prim, uint8_t *data, int length)
|
||||
{
|
||||
isdn_t *isdn_ep = (isdn_t *)priv;
|
||||
int index = channel - 1 - (channel > 16);
|
||||
|
||||
if (index < 0 || index > 127)
|
||||
return;
|
||||
|
||||
switch (prim) {
|
||||
case PH_PRIM_DATA_IND:
|
||||
if (isdn_ep->b_call[index]) {
|
||||
struct mISDNhead hh = { .prim = PH_DATA_IND };
|
||||
bchannel_receive(isdn_ep, index, &hh, data, length);
|
||||
} else
|
||||
PDEBUG(DISDN, DEBUG_DEBUG, "b-channel is not associated to a call (channel %d), ignoring.\n", channel);
|
||||
break;
|
||||
case PH_PRIM_ACT_IND:
|
||||
PDEBUG(DISDN, DEBUG_DEBUG, "PH_PRIM_ACT_IND: bchannel is now activated (channel %d).\n", channel);
|
||||
bchannel_event(isdn_ep, index, B_EVENT_ACTIVATED);
|
||||
break;
|
||||
case PH_PRIM_DACT_IND:
|
||||
PDEBUG(DISDN, DEBUG_DEBUG, "PH_PRIM_DACT_IND: bchannel is now deactivated (channel %d).\n", channel);
|
||||
bchannel_event(isdn_ep, index, B_EVENT_DEACTIVATED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void b_timer_timeout(struct timer *timer)
|
||||
{
|
||||
struct b_timer_inst *ti = timer->priv;
|
||||
|
@ -1516,11 +1578,14 @@ static void send_to_rtp(call_t *call, unsigned char *data, int len)
|
|||
if (call->b_index >= 0) {
|
||||
unsigned char buf[MISDN_HEADER_LEN + len];
|
||||
struct mISDNhead *frm = (struct mISDNhead *)buf;
|
||||
int rc;
|
||||
int rc = 0;
|
||||
memcpy(buf + MISDN_HEADER_LEN, data, len);
|
||||
frm->prim = PH_DATA_REQ;
|
||||
frm->id = 0;
|
||||
rc = send(call->isdn_ep->b_sock[call->b_index], buf, MISDN_HEADER_LEN + len, 0);
|
||||
if (call->isdn_ep->ph_socket)
|
||||
ph_socket_tx_msg(call->isdn_ep->ph_socket, call->b_channel, PH_PRIM_DATA_REQ, buf + MISDN_HEADER_LEN, len);
|
||||
else
|
||||
rc = send(call->isdn_ep->b_sock[call->b_index], buf, MISDN_HEADER_LEN + len, 0);
|
||||
if (rc < 0)
|
||||
PDEBUG(DISDN, DEBUG_ERROR, "write error B-channel data (socket #%d errno=%d:%s)\n", call->isdn_ep->b_sock[call->b_index], errno, strerror(errno));
|
||||
}
|
||||
|
@ -1629,11 +1694,14 @@ void bchannel_send(struct osmo_cc_session_codec *codec, uint16_t __attribute__((
|
|||
if (call->b_index >= 0) {
|
||||
unsigned char buf[MISDN_HEADER_LEN + len];
|
||||
struct mISDNhead *frm = (struct mISDNhead *)buf;
|
||||
int rc;
|
||||
int rc = 0;
|
||||
memcpy(buf + MISDN_HEADER_LEN, data, len);
|
||||
frm->prim = PH_DATA_REQ;
|
||||
frm->id = 0;
|
||||
rc = send(call->isdn_ep->b_sock[call->b_index], buf, MISDN_HEADER_LEN + len, 0);
|
||||
if (call->isdn_ep->ph_socket)
|
||||
ph_socket_tx_msg(call->isdn_ep->ph_socket, call->b_channel, PH_PRIM_DATA_REQ, buf + MISDN_HEADER_LEN, len);
|
||||
else
|
||||
rc = send(call->isdn_ep->b_sock[call->b_index], buf, MISDN_HEADER_LEN + len, 0);
|
||||
if (rc < 0)
|
||||
PDEBUG(DISDN, DEBUG_ERROR, "write error B-channel data (socket #%d errno=%d:%s)\n", call->isdn_ep->b_sock[call->b_index], errno, strerror(errno));
|
||||
}
|
||||
|
@ -1667,7 +1735,7 @@ int do_layer3(struct mlayer3 *ml3, unsigned int cmd, unsigned int pid, struct l3
|
|||
return 0;
|
||||
}
|
||||
|
||||
int mISDN_getportbyname(int sock, int cnt, const char *portname)
|
||||
int mISDN_getportbyname(isdn_t *isdn_ep, int cnt, const char *portname)
|
||||
{
|
||||
struct mISDN_devinfo devinfo;
|
||||
int port = 0, rc;
|
||||
|
@ -1677,7 +1745,10 @@ int mISDN_getportbyname(int sock, int cnt, const char *portname)
|
|||
/* resolve name */
|
||||
while (port < cnt) {
|
||||
devinfo.id = port;
|
||||
rc = ioctl(sock, IMGETDEVINFO, &devinfo);
|
||||
if (isdn_ep->l2sock)
|
||||
rc = ioctl(isdn_ep->l2sock, IMGETDEVINFO, &devinfo);
|
||||
if (isdn_ep->l2inst)
|
||||
rc = mISDN_base_ioctl(isdn_ep->l2inst, IMGETDEVINFO, &devinfo);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
if (!strcasecmp(devinfo.name, portname))
|
||||
|
@ -1706,7 +1777,7 @@ int isdn_open(isdn_t *isdn_ep)
|
|||
int nt, te;
|
||||
struct mISDN_devinfo devinfo;
|
||||
unsigned int protocol, prop;
|
||||
int rc;
|
||||
int rc = 0;
|
||||
|
||||
/* queue must be initializes, because l3-thread may send messages during open_layer3() */
|
||||
mqueue_init(&isdn_ep->upqueue);
|
||||
|
@ -1725,7 +1796,10 @@ int isdn_open(isdn_t *isdn_ep)
|
|||
memset(&devinfo, 0, sizeof(devinfo));
|
||||
|
||||
/* check port counts */
|
||||
rc = ioctl(isdn_ep->socket, IMGETCOUNT, &cnt);
|
||||
if (isdn_ep->l2sock)
|
||||
rc = ioctl(isdn_ep->l2sock, IMGETCOUNT, &cnt);
|
||||
if (isdn_ep->l2inst)
|
||||
rc = mISDN_base_ioctl(isdn_ep->l2inst, IMGETCOUNT, &cnt);
|
||||
if (rc < 0) {
|
||||
PDEBUG(DISDN, DEBUG_ERROR, "Cannot get number of mISDN devices. (ioctl IMGETCOUNT failed errno = %d)\n", errno);
|
||||
goto error;
|
||||
|
@ -1736,7 +1810,7 @@ int isdn_open(isdn_t *isdn_ep)
|
|||
goto error;
|
||||
}
|
||||
if (portnum < 0) {
|
||||
portnum = mISDN_getportbyname(isdn_ep->socket, cnt, portname);
|
||||
portnum = mISDN_getportbyname(isdn_ep, cnt, portname);
|
||||
if (portnum < 0) {
|
||||
PDEBUG(DISDN, DEBUG_ERROR, "Port name '%s' not found, use 'misdn_info' tool to list all existing ports.\n", portname);
|
||||
goto error;
|
||||
|
@ -1751,7 +1825,10 @@ int isdn_open(isdn_t *isdn_ep)
|
|||
/* get port attributes */
|
||||
pri = bri = nt = te = 0;
|
||||
devinfo.id = portnum;
|
||||
rc = ioctl(isdn_ep->socket, IMGETDEVINFO, &devinfo);
|
||||
if (isdn_ep->l2sock)
|
||||
rc = ioctl(isdn_ep->l2sock, IMGETDEVINFO, &devinfo);
|
||||
if (isdn_ep->l2inst)
|
||||
rc = mISDN_base_ioctl(isdn_ep->l2inst, IMGETDEVINFO, &devinfo);
|
||||
if (rc < 0) {
|
||||
PDEBUG(DISDN, DEBUG_ERROR, "Cannot get device information for port %d. (ioctl IMGETDEVINFO failed errno=%d)\n", portnum, errno);
|
||||
goto error;
|
||||
|
@ -1861,6 +1938,8 @@ int isdn_open(isdn_t *isdn_ep)
|
|||
}
|
||||
|
||||
isdn_ep->b_num = devinfo.nrbchan;
|
||||
if (!isdn_ep->b_num)
|
||||
isdn_ep->b_num = (pri) ? 30 : 2;
|
||||
isdn_ep->portnum = portnum;
|
||||
if (isdn_ep->portname)
|
||||
free(isdn_ep->portname);
|
||||
|
@ -1888,7 +1967,8 @@ int isdn_open(isdn_t *isdn_ep)
|
|||
if (isdn_ep->ntmode && !isdn_ep->ptp)
|
||||
isdn_ep->l2link = 1;
|
||||
|
||||
PDEBUG(DISDN, DEBUG_DEBUG, "using 'mISDN_dsp.o' module\n");
|
||||
if (isdn_ep->l2sock)
|
||||
PDEBUG(DISDN, DEBUG_DEBUG, "using 'mISDN_dsp.o' module\n");
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -2064,7 +2144,7 @@ void isdn_bchannel_work(isdn_t *isdn_ep)
|
|||
for (i = 0; i < isdn_ep->b_num; i++) {
|
||||
do {
|
||||
if (isdn_ep->b_sock[i] > 0)
|
||||
w = bchannel_work(isdn_ep, i);
|
||||
w = bchannel_kernel_sock_work(isdn_ep, i);
|
||||
else
|
||||
w = 0;
|
||||
} while (w);
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "../libosmocc/helper.h"
|
||||
#include "../libsample/sample.h"
|
||||
#include "../libjitter/jitter.h"
|
||||
#include "ph_socket.h"
|
||||
|
||||
#define B_MODE_TRANSPARENT 0
|
||||
#define B_MODE_HDLC 1
|
||||
|
@ -91,7 +92,9 @@ typedef struct isdn {
|
|||
int pri;
|
||||
int l1hold;
|
||||
int l2hold;
|
||||
int socket;
|
||||
int l2sock;
|
||||
void *l2inst;
|
||||
ph_socket_t *ph_socket;
|
||||
pthread_mutex_t upqueue_lock;
|
||||
struct mqueue upqueue;
|
||||
int upqueue_initialized;
|
||||
|
@ -180,7 +183,7 @@ int open_bchannel_out(call_t *call, unsigned int cmd, int channel, int exclusive
|
|||
/* isdn instance */
|
||||
isdn_t *isdn_create(void);
|
||||
void isdn_destroy(isdn_t *isdn_ep);
|
||||
int isdn_initialize(isdn_t *isdn_ep, char law, const char *portname, int ntmode, int ptp, int layer1hold, int layer2hold, const char *channel_out, const char *channel_in, const char *timeouts, int tx_delay, int tx_gain, int rx_gain, const char *pipeline, int dtmf, int local_tones, int serving_location);
|
||||
int isdn_initialize(isdn_t *isdn_ep, ph_socket_t *ph_socket, char law, const char *portname, int ntmode, int ptp, int layer1hold, int layer2hold, const char *channel_out, const char *channel_in, const char *timeouts, int tx_delay, int tx_gain, int rx_gain, const char *pipeline, int dtmf, int local_tones, int serving_location);
|
||||
int isdn_open(isdn_t *isdn_ep);
|
||||
void isdn_close(isdn_t *isdn_ep);
|
||||
void isdn_add_msn(isdn_t *isdn_ep, const char *msn);
|
||||
|
|
|
@ -30,12 +30,15 @@
|
|||
#include <mISDN/mbuffer.h>
|
||||
#include "isdn.h"
|
||||
#include "dss1.h"
|
||||
#include "../libmisdn/core.h"
|
||||
#include "ph_driver.h"
|
||||
|
||||
isdn_t *isdn_ep = NULL;
|
||||
int num_kanal = 1;
|
||||
|
||||
static char law = 'a';
|
||||
static const char *portname = "0";
|
||||
static const char *portname = NULL;
|
||||
static int misdn_kernel = 0, misdn_user = 0;
|
||||
static int ntmode = 0;
|
||||
static int ptp = 0;
|
||||
static int layer1hold = 0;
|
||||
|
@ -72,7 +75,10 @@ static void print_help()
|
|||
printf(" --ulaw\n");
|
||||
printf(" Use U-LAW for b-channel coding instead of alaw.\n");
|
||||
printf(" -p --port <portnr> | <portname>\n");
|
||||
printf(" Number or name of misdn port (see misdn_info). (Default = %s)\n", portname);
|
||||
printf(" Number or name of misdn port (see misdn_info).\n");
|
||||
printf(" -s --socket <path>\n");
|
||||
printf(" Path to UNIX socket that provides layer 1 connection to an ISDN\n");
|
||||
printf(" interface.\n");
|
||||
printf(" -n --nt\n");
|
||||
printf(" The given port is configured as NT-mode, instead of TE-mode.\n");
|
||||
printf(" -0 --ptp\n");
|
||||
|
@ -149,6 +155,7 @@ static void add_options(void)
|
|||
option_add('v', "verbose", 1);
|
||||
option_add(OPT_ULAW, "ulaw", 0);
|
||||
option_add('p', "port", 1);
|
||||
option_add('s', "socket", 1);
|
||||
option_add('n', "nt", 0);
|
||||
option_add('0', "ptp", 0);
|
||||
option_add('M', "msn", 1);
|
||||
|
@ -193,6 +200,11 @@ static int handle_options(int short_option, int argi, char **argv)
|
|||
break;
|
||||
case 'p':
|
||||
portname = options_strdup(argv[argi]);
|
||||
misdn_kernel = 1;
|
||||
break;
|
||||
case 's':
|
||||
portname = options_strdup(argv[argi]);
|
||||
misdn_user = 1;
|
||||
break;
|
||||
case 'n':
|
||||
ntmode = 1;
|
||||
|
@ -295,7 +307,10 @@ static int mISDNlib_debug(const char *file, int line, const char *func, int __at
|
|||
int main(int argc, char *argv[])
|
||||
{
|
||||
int argi, rc;
|
||||
int misdn_initialized = 0;
|
||||
int ph_drv_initialized = 0;
|
||||
int layer3_initialized = 0;
|
||||
struct ph_socket_driver ph_drv;
|
||||
|
||||
g711_init();
|
||||
|
||||
|
@ -314,16 +329,42 @@ int main(int argc, char *argv[])
|
|||
if (argi <= 0)
|
||||
return argi;
|
||||
|
||||
/* misdn init and debug */
|
||||
rc = check_mISDN_dsp();
|
||||
if (rc)
|
||||
if (!misdn_kernel && !misdn_user) {
|
||||
fprintf(stderr, "You defined no mISDN port or layer 1 socket. You must define either one of them! Use '-h' for help.\n");
|
||||
goto error;
|
||||
}
|
||||
if (misdn_kernel && misdn_user) {
|
||||
fprintf(stderr, "You defined mISDN port and layer 1 socket. You must define either one of them!\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* check for DSP (kernel only) */
|
||||
if (misdn_kernel) {
|
||||
rc = check_mISDN_dsp();
|
||||
if (rc)
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* init user space mISDN */
|
||||
if (misdn_user) {
|
||||
rc = mISDNInit((debug_mISDN) ? 0xffffffff : 0);
|
||||
if (rc)
|
||||
goto error;
|
||||
misdn_initialized = 1;
|
||||
rc = init_ph_socket_driver(&ph_drv, isdn_ep, portname, 0, ntmode, (debug_mISDN) ? 0xffffffff : 0);
|
||||
if (rc)
|
||||
goto error;
|
||||
ph_drv_initialized = 1;
|
||||
}
|
||||
|
||||
/* mISDNuser init and debug */
|
||||
mi_fn.prt_debug = mISDNlib_debug;
|
||||
init_layer3(4, &mi_fn);
|
||||
init_layer3(4, &mi_fn, (misdn_user) ? 1 : 0);
|
||||
layer3_initialized = 1;
|
||||
mISDN_set_debug_level((debug_mISDN) ? 0xfffffeff : 0);
|
||||
|
||||
rc = isdn_initialize(isdn_ep, law, portname, ntmode, ptp, layer1hold, layer2hold, channel_out, channel_in, timeouts, tx_delay, tx_gain, rx_gain, pipeline, dtmf, local_tones, serving_location);
|
||||
/* init instance */
|
||||
rc = isdn_initialize(isdn_ep, (misdn_user) ? &ph_drv.ph_socket : NULL, law, portname, ntmode, ptp, layer1hold, layer2hold, channel_out, channel_in, timeouts, tx_delay, tx_gain, rx_gain, pipeline, dtmf, local_tones, serving_location);
|
||||
if (rc) {
|
||||
PDEBUG(DISDN, DEBUG_ERROR, "mISDN initializing failed!\n");
|
||||
goto error;
|
||||
|
@ -349,10 +390,19 @@ int main(int argc, char *argv[])
|
|||
process_timer();
|
||||
isdn_bchannel_work(isdn_ep);
|
||||
isdn_rtp_work(isdn_ep);
|
||||
if (misdn_user) {
|
||||
/* run workers of mISDN stacks in user space */
|
||||
mISDN_work();
|
||||
}
|
||||
do {
|
||||
w = 0;
|
||||
w |= osmo_cc_handle();
|
||||
w |= isdn_dchannel_work(isdn_ep);
|
||||
if (misdn_user) {
|
||||
/* run workers of mISDN stacks in user space */
|
||||
w |= ph_socket_work(&ph_drv.ph_socket);
|
||||
w |= work_layer3(isdn_ep->ml3);
|
||||
}
|
||||
} while (w);
|
||||
usleep(1000);
|
||||
}
|
||||
|
@ -372,6 +422,12 @@ error:
|
|||
if (layer3_initialized)
|
||||
cleanup_layer3();
|
||||
|
||||
if (ph_drv_initialized)
|
||||
exit_ph_socket_driver(&ph_drv);
|
||||
|
||||
if (misdn_initialized)
|
||||
mISDN_cleanup();
|
||||
|
||||
options_free();
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -0,0 +1,309 @@
|
|||
/* ph-socket driver for user space mISDN
|
||||
*
|
||||
* (C) 2020 by Andreas Eversberg <jolly@eversberg.eu>
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include "ph_socket.h"
|
||||
#include "ph_driver.h"
|
||||
#define __MISDNL1L2__
|
||||
#include "../libmisdn/mISDNhw.h"
|
||||
|
||||
static inline u_int
|
||||
get_sapi_tei(u_char *p)
|
||||
{
|
||||
u_int sapi, tei;
|
||||
|
||||
sapi = *p >> 2;
|
||||
tei = p[1] >> 1;
|
||||
return sapi | (tei << 8);
|
||||
}
|
||||
|
||||
/* message from mISDN stack to PH-socket */
|
||||
static int d_msg_down(struct mISDNchannel *ch, struct sk_buff *skb)
|
||||
{
|
||||
struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);
|
||||
struct dchannel *dch = container_of(dev, struct dchannel, dev);
|
||||
struct ph_socket_driver *drv = dch->hw;
|
||||
struct mISDNhead *hh = mISDN_HEAD_P(skb);
|
||||
|
||||
switch (hh->prim) {
|
||||
case PH_DATA_REQ:
|
||||
printk(KERN_DEBUG "PH-DATA-REQ to interface (channel=%d, len=%d)\n", drv->dch->slot, skb->len);
|
||||
ph_socket_tx_msg(&drv->ph_socket, drv->dch->slot, PH_PRIM_DATA_REQ, skb->data, skb->len);
|
||||
skb_trim(skb, 0);
|
||||
printk(KERN_DEBUG "PH-DATA-CNF from interface\n");
|
||||
queue_ch_frame(ch, PH_DATA_CNF, hh->id, skb);
|
||||
skb = NULL;
|
||||
break;
|
||||
case PH_ACTIVATE_REQ:
|
||||
printk(KERN_DEBUG "PH-ACTOVATE_REQ from interface\n");
|
||||
ph_socket_tx_msg(&drv->ph_socket, drv->dch->slot, PH_PRIM_ACT_REQ, NULL, 0);
|
||||
break;
|
||||
case PH_DEACTIVATE_REQ:
|
||||
printk(KERN_DEBUG "PH-DEACTOVATE_REQ from interface\n");
|
||||
ph_socket_tx_msg(&drv->ph_socket, drv->dch->slot, PH_PRIM_DACT_REQ, NULL, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
if (skb)
|
||||
dev_kfree_skb(skb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* open sub function of d_ctrl */
|
||||
static int open_dchannel(struct ph_socket_driver __attribute__((unused)) *drv, struct dchannel *dch, struct channel_req *rq)
|
||||
{
|
||||
if (dch->debug & DEBUG_HW_OPEN)
|
||||
printk(KERN_DEBUG "%s: dev(%d) open from %p\n", __func__,
|
||||
dch->dev.id, __builtin_return_address(0));
|
||||
if (rq->protocol == ISDN_P_NONE)
|
||||
return -EINVAL;
|
||||
if ((dch->dev.D.protocol != ISDN_P_NONE) &&
|
||||
(dch->dev.D.protocol != rq->protocol)) {
|
||||
if (dch->debug & DEBUG_HW_OPEN)
|
||||
printk(KERN_WARNING "%s: change protocol %x to %x\n",
|
||||
__func__, dch->dev.D.protocol, rq->protocol);
|
||||
}
|
||||
if (dch->dev.D.protocol != rq->protocol)
|
||||
dch->dev.D.protocol = rq->protocol;
|
||||
|
||||
if (test_bit(FLG_ACTIVE, &dch->Flags)) {
|
||||
_queue_data(&dch->dev.D, PH_ACTIVATE_IND, MISDN_ID_ANY,
|
||||
0, NULL, GFP_KERNEL);
|
||||
}
|
||||
rq->ch = &dch->dev.D;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* channel sub function of d_ctrl */
|
||||
static int channel_dctrl(struct dchannel __attribute__((unused)) *dch, struct mISDN_ctrl_req *cq)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
switch (cq->op) {
|
||||
default:
|
||||
printk(KERN_WARNING "%s: unknown Op %x\n",
|
||||
__func__, cq->op);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* control from mISDN stack to this driver */
|
||||
static int d_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
|
||||
{
|
||||
struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);
|
||||
struct dchannel *dch = container_of(dev, struct dchannel, dev);
|
||||
struct ph_socket_driver *drv = dch->hw;
|
||||
struct channel_req *rq;
|
||||
int err = 0;
|
||||
|
||||
if (dch->debug & DEBUG_HW)
|
||||
printk(KERN_DEBUG "%s: cmd:%x %p\n",
|
||||
__func__, cmd, arg);
|
||||
switch (cmd) {
|
||||
case OPEN_CHANNEL:
|
||||
rq = arg;
|
||||
switch (rq->protocol) {
|
||||
case ISDN_P_TE_S0:
|
||||
case ISDN_P_NT_S0:
|
||||
if (drv->pri) {
|
||||
err = -EINVAL;
|
||||
break;
|
||||
}
|
||||
err = open_dchannel(drv, dch, rq);
|
||||
break;
|
||||
case ISDN_P_TE_E1:
|
||||
case ISDN_P_NT_E1:
|
||||
if (!drv->pri) {
|
||||
err = -EINVAL;
|
||||
break;
|
||||
}
|
||||
err = open_dchannel(drv, dch, rq);
|
||||
break;
|
||||
default:
|
||||
;
|
||||
//err = open_bchannel(hc, dch, rq);
|
||||
}
|
||||
break;
|
||||
case CLOSE_CHANNEL:
|
||||
if (dch->debug & DEBUG_HW_OPEN)
|
||||
printk(KERN_DEBUG "%s: dev(%d) close from %p\n",
|
||||
__func__, dch->dev.id,
|
||||
__builtin_return_address(0));
|
||||
break;
|
||||
case CONTROL_CHANNEL:
|
||||
err = channel_dctrl(dch, arg);
|
||||
break;
|
||||
default:
|
||||
if (dch->debug & DEBUG_HW)
|
||||
printk(KERN_DEBUG "%s: unknown command %x\n",
|
||||
__func__, cmd);
|
||||
err = -EINVAL;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
/* init instance of PH-socket driver */
|
||||
int init_ph_socket_driver(struct ph_socket_driver *drv, void *priv, const char *socket_name, int pri, int nt, uint32_t debug)
|
||||
{
|
||||
int ret = 0;
|
||||
struct dchannel *dch;
|
||||
|
||||
|
||||
memset(drv, 0, sizeof(*drv));
|
||||
drv->priv = priv;
|
||||
drv->pri = pri;
|
||||
drv->nt = nt;
|
||||
|
||||
/* socket client */
|
||||
ph_socket_init(&drv->ph_socket, drv, socket_name, 0);
|
||||
|
||||
/* allocate dchannel structure */
|
||||
dch = kzalloc(sizeof(*dch), GFP_KERNEL);
|
||||
if (!dch) {
|
||||
ret = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* populate dchannel structure */
|
||||
dch->debug = debug;
|
||||
mISDN_initdchannel(dch, MAX_DFRAME_LEN_L1, NULL);
|
||||
dch->hw = drv;
|
||||
if (pri) {
|
||||
if (nt)
|
||||
dch->dev.Dprotocols = (1 << ISDN_P_NT_E1);
|
||||
else
|
||||
dch->dev.Dprotocols = (1 << ISDN_P_TE_E1);
|
||||
dch->dev.nrbchan = 30;
|
||||
} else {
|
||||
if (nt)
|
||||
dch->dev.Dprotocols = (1 << ISDN_P_NT_S0);
|
||||
else
|
||||
dch->dev.Dprotocols = (1 << ISDN_P_TE_S0);
|
||||
dch->dev.nrbchan = 2;
|
||||
}
|
||||
dch->dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) |
|
||||
(1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK));
|
||||
dch->dev.D.send = d_msg_down;
|
||||
dch->dev.D.ctrl = d_ctrl;
|
||||
dch->slot = (pri) ? 16 : 3;
|
||||
dch->dev.nrbchan = 0;
|
||||
|
||||
/* register dchannel to mISDN */
|
||||
ret = mISDN_register_device(&dch->dev, NULL, "ph-socket");
|
||||
if (ret) {
|
||||
kfree(dch);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* link */
|
||||
drv->dch = dch;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
exit_ph_socket_driver(drv);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* destroy instance of PH-socket driver */
|
||||
void exit_ph_socket_driver(struct ph_socket_driver *drv)
|
||||
{
|
||||
/* unregister dchannel structure and free */
|
||||
if (drv->dch) {
|
||||
mISDN_unregister_device(&drv->dch->dev);
|
||||
mISDN_freedchannel(drv->dch);
|
||||
kfree(drv->dch);
|
||||
drv->dch = NULL;
|
||||
}
|
||||
|
||||
/* close socket */
|
||||
ph_socket_exit(&drv->ph_socket);
|
||||
}
|
||||
|
||||
/* message from PH-socket to mISDN */
|
||||
void ph_socket_rx_msg(ph_socket_t *s, int channel, uint8_t prim, uint8_t *data, int length)
|
||||
{
|
||||
struct ph_socket_driver *drv = (struct ph_socket_driver *)s->priv;
|
||||
|
||||
/* stack not complete */
|
||||
if (!drv || !drv->dch)
|
||||
return;
|
||||
|
||||
switch (prim) {
|
||||
case PH_PRIM_DATA_IND:
|
||||
if (drv->dch->slot == channel) {
|
||||
printk(KERN_DEBUG "PH-DATA-IND from interface (channel %d, len=%d)\n", channel, length);
|
||||
if (length < 2) {
|
||||
printk(KERN_ERR "%s: Message too short!\n", __func__);
|
||||
break;
|
||||
}
|
||||
_queue_data(&drv->dch->dev.D, PH_DATA_IND, get_sapi_tei(data), length, data, GFP_ATOMIC);
|
||||
break;
|
||||
}
|
||||
bchannel_ph_sock_receive(drv->priv, channel, prim, data, length);
|
||||
break;
|
||||
case PH_PRIM_ACT_IND:
|
||||
if (drv->dch->slot == channel) {
|
||||
printk(KERN_DEBUG "PH-ACTIVATE-IND from interface (dchannel)\n");
|
||||
drv->activated = 1;
|
||||
_queue_data(&drv->dch->dev.D, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, NULL, GFP_ATOMIC);
|
||||
break;
|
||||
}
|
||||
printk(KERN_DEBUG "PH-ACTIVATE-IND from interface (bchannel)\n");
|
||||
bchannel_ph_sock_receive(drv->priv, channel, prim, data, length);
|
||||
break;
|
||||
case PH_PRIM_DACT_IND:
|
||||
if (drv->dch->slot == channel) {
|
||||
printk(KERN_DEBUG "PH-DEACTIVATE-IND from interface (dchannel)\n");
|
||||
drv->activated = 0;
|
||||
_queue_data(&drv->dch->dev.D, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, NULL, GFP_ATOMIC);
|
||||
break;
|
||||
}
|
||||
printk(KERN_DEBUG "PH-DEACTIVATE-IND from interface (bchannel)\n");
|
||||
bchannel_ph_sock_receive(drv->priv, channel, prim, data, length);
|
||||
break;
|
||||
case PH_PRIM_CTRL_IND:
|
||||
if (length >= 1) {
|
||||
switch (data[0]) {
|
||||
case PH_CTRL_ENABLE:
|
||||
printk(KERN_DEBUG "PH-SOCKET Interface available\n");
|
||||
drv->enabled = 1;
|
||||
break;
|
||||
case PH_CTRL_DISABLE:
|
||||
printk(KERN_DEBUG "PH-SOCKET Interface unavailable\n");
|
||||
drv->enabled = 0;
|
||||
if (drv->activated) {
|
||||
drv->activated = 0;
|
||||
_queue_data(&drv->dch->dev.D, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, NULL, GFP_ATOMIC);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR "%s: Rejecting unknown message 0x%02x from PH-socket!\n", __func__, prim);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
struct ph_socket_driver {
|
||||
void *priv;
|
||||
int pri, nt;
|
||||
ph_socket_t ph_socket;
|
||||
struct dchannel *dch;
|
||||
int enabled, activated;
|
||||
};
|
||||
|
||||
int init_ph_socket_driver(struct ph_socket_driver *drv, void *priv, const char *socket_name, int pri, int nt, uint32_t debug);
|
||||
void exit_ph_socket_driver(struct ph_socket_driver *drv);
|
||||
|
||||
void bchannel_ph_sock_receive(void *priv, int channel, uint8_t prim, uint8_t *data, int length);
|
||||
|
|
@ -0,0 +1 @@
|
|||
/files/projects/uk0/src/uk0/ph_socket.c
|
|
@ -0,0 +1 @@
|
|||
/files/projects/uk0/src/uk0/ph_socket.h
|
Loading…
Reference in New Issue