Make this application capable of using kernel or user space mISDN

This commit is contained in:
Andreas Eversberg 2022-03-27 16:30:19 +02:00
parent 4150cc3e67
commit 3672a4c99e
8 changed files with 550 additions and 81 deletions

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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;

309
src/isdn/ph_driver.c Normal file
View File

@ -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);
}
}

14
src/isdn/ph_driver.h Normal file
View File

@ -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);

1
src/isdn/ph_socket.c Symbolic link
View File

@ -0,0 +1 @@
/files/projects/uk0/src/uk0/ph_socket.c

1
src/isdn/ph_socket.h Symbolic link
View File

@ -0,0 +1 @@
/files/projects/uk0/src/uk0/ph_socket.h