some fixes, check README
[lcr.git] / mISDN.cpp
index c53b758..3c4c23d 100644 (file)
--- a/mISDN.cpp
+++ b/mISDN.cpp
@@ -1,6 +1,6 @@
 /*****************************************************************************\
 **                                                                           **
 /*****************************************************************************\
 **                                                                           **
-** PBX4Linux                                                                 **
+** Linux Call Router                                                         **
 **                                                                           **
 **---------------------------------------------------------------------------**
 ** Copyright: Andreas Eversberg                                              **
 **                                                                           **
 **---------------------------------------------------------------------------**
 ** Copyright: Andreas Eversberg                                              **
 \*****************************************************************************/ 
 
 
 \*****************************************************************************/ 
 
 
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
 #include "main.h"
 #include "main.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 <poll.h>
 #include <errno.h>
 #include <sys/ioctl.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
+#ifdef SOCKET_MISDN
+#include <netinet/udp.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <pthread.h>
+#include <linux/mISDNif.h>
+#include <q931.h>
+#include <mlayer3.h>
+#else
 extern "C" {
 extern "C" {
-#include <net_l2.h>
+#include <mISDNuser/net_l2.h>
 }
 }
+#endif
 
 
-#define ISDN_PID_L2_B_USER 0x420000ff
-#define ISDN_PID_L3_B_USER 0x430000ff
+#ifndef ISDN_PID_L4_B_USER
 #define ISDN_PID_L4_B_USER 0x440000ff
 #define ISDN_PID_L4_B_USER 0x440000ff
+#endif
 
 
-/* used for udevice */
-int entity = 0;
+/* list of mISDN ports */
+struct mISDNport *mISDNport_first;
 
 /* noise randomizer */
 unsigned char mISDN_rand[256];
 int mISDN_rand_count = 0;
 
 
 /* noise randomizer */
 unsigned char mISDN_rand[256];
 int mISDN_rand_count = 0;
 
-/* the device handler and port list */
-int mISDNdevice = -1;
+#ifdef MISDN_SOCKET
+int mISDNsocket = -1;
 
 
-/* list of mISDN ports */
-struct mISDNport *mISDNport_first;
+int mISDN_initialize(void)
+{
+       /* try to open raw socket to check kernel */
+       mISDNsocket = socket(PF_ISDN, SOCK_RAW, ISDN_P_BASE);
+       if (mISDNsocket < 0)
+       {
+               fprintf(stderr, "Cannot open mISDN due to %s. (Does your Kernel support socket based mISDN?)\n", strerror(errno));
+               return(-1);
+       }
+
+       /* initialize stuff of the NT lib */
+       if (options.deb & DEBUG_STACK)
+       {
+               global_debug = 0xffffffff & ~DBGM_MSG;
+//             global_debug = DBGM_L3DATA;
+       } else
+               global_debug = DBGM_MAN;
+       SPRINT(debug_log, "%s/debug.log", INSTALL_DATA);
+       if (options.deb & DEBUG_LOG)
+               mISDN_debug_init(global_debug, debug_log, debug_log, debug_log);
+       else
+               mISDN_debug_init(global_debug, NULL, NULL, NULL);
+
+       /* init mlayer3 */
+       init_layer3(4); // buffer of 4
+
+       return(0);
+}
+
+void mISDN_deinitialize(void)
+{
+       cleanup_layer3();
+
+       mISDN_debug_close();
+
+       if (mISDNsocket > -1)
+               close(mISDNsocket);
+}
+#else
+int entity = 0; /* used for udevice */
+int mISDNdevice = -1; /* the device handler and port list */
+
+int mISDN_initialize(void)
+{
+       char debug_log[128];
+       unsigned char buff[1025];
+       iframe_t *frm = (iframe_t *)buff;
+       int ret;
+
+       /* initialize stuff of the NT lib */
+       if (options.deb & DEBUG_STACK)
+       {
+               global_debug = 0xffffffff & ~DBGM_MSG;
+//             global_debug = DBGM_L3DATA;
+       } else
+               global_debug = DBGM_MAN;
+       SPRINT(debug_log, "%s/debug.log", INSTALL_DATA);
+       if (options.deb & DEBUG_LOG)
+               debug_init(global_debug, debug_log, debug_log, debug_log);
+       else
+               debug_init(global_debug, NULL, NULL, NULL);
+       msg_init();
+
+       /* 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(-1);
+               }
+               mISDNdevice = ret;
+               PDEBUG(DEBUG_ISDN, "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:
+                       FATAL("Cannot request MGR_NEWENTITY from mISDN. Exitting due to software bug.");
+               }
+               entity = frm->dinfo & 0xffff;
+               if (!entity)
+                       goto noentity;
+               PDEBUG(DEBUG_ISDN, "our entity for l3-processes is %d.\n", entity);
+       }
+       return(0);
+}
+
+void mISDN_deinitialize(void)
+{
+       unsigned char buff[1025];
+
+       debug_close();
+
+       if (mISDNdevice >= 0)
+       {
+               /* free entity */
+               mISDN_write_frame(mISDNdevice, buff, 0, MGR_DELENTITY | REQUEST, entity, 0, NULL, TIMEOUT_1SEC);
+               /* close device */
+               mISDN_close(mISDNdevice);
+               mISDNdevice = -1;
+               PDEBUG(DEBUG_ISDN, "mISDN device closed.\n");
+       }
+}
+#endif
 
 /*
  * constructor
 
 /*
  * constructor
@@ -53,7 +166,6 @@ PmISDN::PmISDN(int type, mISDNport *mISDNport, char *portname, struct port_setti
        p_m_b_channel = 0;
        p_m_b_exclusive = 0;
        p_m_b_reserve = 0;
        p_m_b_channel = 0;
        p_m_b_exclusive = 0;
        p_m_b_reserve = 0;
-       p_m_jittercheck = 0;
        p_m_delete = 0;
        p_m_hold = 0;
        p_m_txvol = p_m_rxvol = 0;
        p_m_delete = 0;
        p_m_hold = 0;
        p_m_txvol = p_m_rxvol = 0;
@@ -63,14 +175,16 @@ PmISDN::PmISDN(int type, mISDNport *mISDNport, char *portname, struct port_setti
        p_m_echo = 0;
        p_m_tone = 0;
        p_m_rxoff = 0;
        p_m_echo = 0;
        p_m_tone = 0;
        p_m_rxoff = 0;
-       p_m_calldata = 0;
+       p_m_joindata = 0;
        p_m_dtmf = !mISDNport->ifport->nodtmf;
        p_m_timeout = 0;
        p_m_timer = 0;
        p_m_dtmf = !mISDNport->ifport->nodtmf;
        p_m_timeout = 0;
        p_m_timer = 0;
+       p_m_remote_ref = 0; /* channel shall be exported to given remote */
+       p_m_remote_id = 0; /* channel shall be exported to given remote */
 
 
-       /* audio from up */
-       p_m_fromup_buffer_readp = 0;
-       p_m_fromup_buffer_writep = 0;
+       /* audio */
+       p_m_load = 0;
+       p_m_last_tv_sec = 0;
 
        /* crypt */
        p_m_crypt = 0;
 
        /* crypt */
        p_m_crypt = 0;
@@ -256,37 +370,70 @@ void l1l2l3_trace_header(struct mISDNport *mISDNport, class PmISDN *port, unsign
 /*
  * send control information to the channel (dsp-module)
  */
 /*
  * send control information to the channel (dsp-module)
  */
-void ph_control(struct mISDNport *mISDNport, class PmISDN *isdnport, unsigned long b_addr, int c1, int c2, char *trace_name, int trace_value)
+void ph_control(struct mISDNport *mISDNport, class PmISDN *isdnport, unsigned long handle, unsigned long c1, unsigned long c2, char *trace_name, int trace_value)
 {
 {
+#ifdef SOCKET_MISDN
+       unsigned char buffer[MISDN_HEADER_LEN+sizeof(int)+sizeof(int)];
+       struct mISDNhead *ctrl = (struct mISDNhead *)buffer;
+       unsigned long *d = buffer+MISDN_HEADER_LEN;
+       int ret;
+
+       ctrl->prim = PH_CONTROL_REQ;
+       ctrl->id = 0;
+       *d++ = c1;
+       *d++ = c2;
+       ret = sendto(handle, buffer, MISDN_HEADER_LEN+sizeof(int)*2, 0, NULL, 0);
+       if (!ret)
+               PERROR("Failed to send to socket %d\n", handle);
+#else
        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;
        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->addr = handle | FLG_MSG_DOWN;
        ctrl->dinfo = 0;
        ctrl->len = sizeof(int)*2;
        *d++ = c1;
        *d++ = c2;
        mISDN_write(mISDNdevice, ctrl, mISDN_HEADER_LEN+ctrl->len, TIMEOUT_1SEC);
        ctrl->dinfo = 0;
        ctrl->len = sizeof(int)*2;
        *d++ = c1;
        *d++ = c2;
        mISDN_write(mISDNdevice, ctrl, mISDN_HEADER_LEN+ctrl->len, TIMEOUT_1SEC);
+#endif
        chan_trace_header(mISDNport, isdnport, "BCHANNEL control", DIRECTION_OUT);
        chan_trace_header(mISDNport, isdnport, "BCHANNEL control", DIRECTION_OUT);
-       add_trace(trace_name, NULL, "%d", trace_value);
+       if (c1 == CMX_CONF_JOIN)
+               add_trace(trace_name, NULL, "0x%08x", trace_value);
+       else
+               add_trace(trace_name, NULL, "%d", trace_value);
        end_trace();
 }
 
        end_trace();
 }
 
-void ph_control_block(struct mISDNport *mISDNport, class PmISDN *isdnport, unsigned long b_addr, int c1, void *c2, int c2_len, char *trace_name, int trace_value)
+void ph_control_block(struct mISDNport *mISDNport, class PmISDN *isdnport, unsigned long handle, unsigned long c1, void *c2, int c2_len, char *trace_name, int trace_value)
 {
 {
+#ifdef SOCKET_MISDN
+       unsigned char buffer[MISDN_HEADER_LEN+sizeof(int)+c2_len];
+       struct mISDNhead *ctrl = (struct mISDNhead *)buffer;
+       unsigned long *d = buffer+MISDN_HEADER_LEN;
+       int ret;
+
+       ctrl->prim = PH_CONTROL_REQ;
+       ctrl->id = 0;
+       *d++ = c1;
+       memcpy(d, c2, c2_len);
+       ret = sendto(handle, buffer, MISDN_HEADER_LEN+sizeof(int)+c2_len, 0, NULL, 0);
+       if (!ret)
+               PERROR("Failed to send to socket %d\n", handle);
+#else
        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;
        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->addr = handle | FLG_MSG_DOWN;
        ctrl->dinfo = 0;
        ctrl->len = sizeof(int)+c2_len;
        *d++ = c1;
        memcpy(d, c2, c2_len);
        mISDN_write(mISDNdevice, ctrl, mISDN_HEADER_LEN+ctrl->len, TIMEOUT_1SEC);
        ctrl->dinfo = 0;
        ctrl->len = sizeof(int)+c2_len;
        *d++ = c1;
        memcpy(d, c2, c2_len);
        mISDN_write(mISDNdevice, ctrl, mISDN_HEADER_LEN+ctrl->len, TIMEOUT_1SEC);
+#endif
        chan_trace_header(mISDNport, isdnport, "BCHANNEL control", DIRECTION_OUT);
        add_trace(trace_name, NULL, "%d", trace_value);
        end_trace();
        chan_trace_header(mISDNport, isdnport, "BCHANNEL control", DIRECTION_OUT);
        add_trace(trace_name, NULL, "%d", trace_value);
        end_trace();
@@ -300,9 +447,55 @@ void ph_control_block(struct mISDNport *mISDNport, class PmISDN *isdnport, unsig
 static int _bchannel_create(struct mISDNport *mISDNport, int i)
 {
        unsigned char buff[1024];
 static int _bchannel_create(struct mISDNport *mISDNport, int i)
 {
        unsigned char buff[1024];
+       int ret;
+#ifdef SOCKET_MISDN
+       unsigned long on = 1;
+       struct sockadd_mISDN addr;
+
+       if (mISDNport->b_socket[i])
+       {
+               PERROR("Error: Socket already created for index %d\n", i);
+               return(0);
+       }
+
+       /* open socket */
+       mISDNport->b_socket[i] = socket(PF_ISDN, SOCK_DGRAM, ISDN_P_B_L2DSP);
+       if (mISDNport->b_socket[i])
+       {
+               PERROR("Error: Failed to open bchannel-socket for index %d with mISDN-DSP layer. Did you load mISDNdsp.ko?\n", i);
+               return(0);
+       }
+       
+       /* set nonblocking io */
+       ret = ioctl(mISDNport->b_socket[i], FIONBIO, &on);
+       if (ret < 0)
+       {
+               PERROR("Error: Failed to set bchannel-socket index %d into nonblocking IO\n", i);
+               close(mISDNport->b_socket[i]);
+               mISDNport->b_socket[i] = -1;
+               return(0);
+       }
+
+       /* bind socket to bchannel */
+       addr.family = AF_ISDN;
+       addr.dev = mISDNport->port-1;
+       addr.channel = i+1+(i>=15);
+       ret = bind(di->bchan, (struct sockaddr *)&addr, sizeof(addr));
+       if (ret < 0)
+       {
+               PERROR("Error: Failed to bind bchannel-socket for index %d with mISDN-DSP layer. Did you load mISDNdsp.ko?\n", i);
+               close(mISDNport->b_socket[i]);
+               mISDNport->b_socket[i] = -1;
+               return(0);
+       }
+
+       chan_trace_header(mISDNport, mISDNport->b_port[i], "BCHANNEL create socket", DIRECTION_OUT);
+       add_trace("channel", NULL, "%d", i+1+(i>=15));
+       add_trace("socket", NULL, "%d", mISDNport->b_socket[i]);
+       end_trace();
+#else
        layer_info_t li;
        mISDN_pid_t pid;
        layer_info_t li;
        mISDN_pid_t pid;
-       int ret;
 
        if (!mISDNport->b_stid[i])
        {
 
        if (!mISDNport->b_stid[i])
        {
@@ -363,9 +556,10 @@ static int _bchannel_create(struct mISDNport *mISDNport, int i)
                goto stack_error;
        chan_trace_header(mISDNport, mISDNport->b_port[i], "BCHANNEL create stack", DIRECTION_OUT);
        add_trace("channel", NULL, "%d", i+1+(i>=15));
                goto stack_error;
        chan_trace_header(mISDNport, mISDNport->b_port[i], "BCHANNEL create stack", DIRECTION_OUT);
        add_trace("channel", NULL, "%d", i+1+(i>=15));
-       add_trace("stack", "id", "0x%8x", mISDNport->b_stid[i]);
-       add_trace("stack", "address", "0x%8x", mISDNport->b_addr[i]);
+       add_trace("stack", "id", "0x%08x", mISDNport->b_stid[i]);
+       add_trace("stack", "address", "0x%08x", mISDNport->b_addr[i]);
        end_trace();
        end_trace();
+#endif
 
        return(1);
 
 
        return(1);
 
@@ -377,21 +571,34 @@ failed:
 
 /*
  * subfunction for bchannel_event
 
 /*
  * subfunction for bchannel_event
- * activate request
+ * activate / deactivate request
  */
  */
-static void _bchannel_activate(struct mISDNport *mISDNport, int i)
+static void _bchannel_activate(struct mISDNport *mISDNport, int i, int activate)
 {
 {
+#ifdef SOCKET_MISDN
+       struct mISDNhead act;
+       int ret;
+
+       act.prim = (activate)?DL_ESTABLISH_REQ:DL_RELEASE_REQ; 
+       act.id = 0;
+       ret = sendto(mISDNport->b_socket[i], &act, MISDN_HEADER_LEN, 0, NULL, 0);
+       if (!ret)
+               PERROR("Failed to send to socket %d\n", mISDNport->b_socket[i]);
+#else
        iframe_t act;
 
        /* activate bchannel */
        iframe_t act;
 
        /* activate bchannel */
-       chan_trace_header(mISDNport, mISDNport->b_port[i], "BCHANNEL activate", DIRECTION_OUT);
-       add_trace("channel", NULL, "%d", i+1+(i>=15));
-       end_trace();
-       act.prim = DL_ESTABLISH | REQUEST; 
+       act.prim = (activate?DL_ESTABLISH:DL_RELEASE) | 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);
        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);
+#endif
+
+       /* trace */
+       chan_trace_header(mISDNport, mISDNport->b_port[i], activate?(char*)"BCHANNEL activate":(char*)"BCHANNEL deactivate", DIRECTION_OUT);
+       add_trace("channel", NULL, "%d", i+1+(i>=15));
+       end_trace();
 }
 
 
 }
 
 
@@ -402,10 +609,16 @@ static void _bchannel_activate(struct mISDNport *mISDNport, int i)
 static void _bchannel_configure(struct mISDNport *mISDNport, int i)
 {
        struct PmISDN *port;
 static void _bchannel_configure(struct mISDNport *mISDNport, int i)
 {
        struct PmISDN *port;
-       int addr;
+#ifdef SOCKET_MISDN
+       int handle;
+
+       handle = mISDNport->b_socket[i];
+#else
+       unsigned long handle;
 
 
+       handle = mISDNport->b_addr[i];
+#endif
        port = mISDNport->b_port[i];
        port = mISDNport->b_port[i];
-       addr = mISDNport->b_addr[i];
        if (!port)
        {
                PERROR("bchannel index i=%d not associated with a port object\n", i);
        if (!port)
        {
                PERROR("bchannel index i=%d not associated with a port object\n", i);
@@ -414,45 +627,27 @@ static void _bchannel_configure(struct mISDNport *mISDNport, int i)
 
        /* set dsp features */
        if (port->p_m_txdata)
 
        /* set dsp features */
        if (port->p_m_txdata)
-               ph_control(mISDNport, port, addr, (port->p_m_txdata)?CMX_TXDATA_ON:CMX_TXDATA_OFF, 0, "DSP-TXDATA", port->p_m_txdata);
+               ph_control(mISDNport, port, handle, (port->p_m_txdata)?CMX_TXDATA_ON:CMX_TXDATA_OFF, 0, "DSP-TXDATA", port->p_m_txdata);
        if (port->p_m_delay)
        if (port->p_m_delay)
-               ph_control(mISDNport, port, addr, CMX_DELAY, port->p_m_delay, "DSP-DELAY", port->p_m_delay);
+               ph_control(mISDNport, port, handle, CMX_DELAY, port->p_m_delay, "DSP-DELAY", port->p_m_delay);
        if (port->p_m_txvol)
        if (port->p_m_txvol)
-               ph_control(mISDNport, port, addr, VOL_CHANGE_TX, port->p_m_txvol, "DSP-TXVOL", port->p_m_txvol);
+               ph_control(mISDNport, port, handle, VOL_CHANGE_TX, port->p_m_txvol, "DSP-TXVOL", port->p_m_txvol);
        if (port->p_m_rxvol)
        if (port->p_m_rxvol)
-               ph_control(mISDNport, port, addr, VOL_CHANGE_RX, port->p_m_rxvol, "DSP-RXVOL", port->p_m_rxvol);
+               ph_control(mISDNport, port, handle, VOL_CHANGE_RX, port->p_m_rxvol, "DSP-RXVOL", port->p_m_rxvol);
        if (port->p_m_conf)
        if (port->p_m_conf)
-               ph_control(mISDNport, port, addr, CMX_CONF_JOIN, port->p_m_conf, "DSP-CONF", port->p_m_conf);
+               ph_control(mISDNport, port, handle, CMX_CONF_JOIN, port->p_m_conf, "DSP-CONF", port->p_m_conf);
        if (port->p_m_echo)
        if (port->p_m_echo)
-               ph_control(mISDNport, port, addr, CMX_ECHO_ON, 0, "DSP-ECHO", 1);
+               ph_control(mISDNport, port, handle, CMX_ECHO_ON, 0, "DSP-ECHO", 1);
        if (port->p_m_tone)
        if (port->p_m_tone)
-               ph_control(mISDNport, port, addr, TONE_PATT_ON, port->p_m_tone, "DSP-TONE", port->p_m_tone);
+               ph_control(mISDNport, port, handle, TONE_PATT_ON, port->p_m_tone, "DSP-TONE", port->p_m_tone);
        if (port->p_m_rxoff)
        if (port->p_m_rxoff)
-               ph_control(mISDNport, port, addr, CMX_RECEIVE_OFF, 0, "DSP-RXOFF", 1);
+               ph_control(mISDNport, port, handle, CMX_RECEIVE_OFF, 0, "DSP-RXOFF", 1);
 //     if (port->p_m_txmix)
 //     if (port->p_m_txmix)
-//             ph_control(mISDNport, port, addr, CMX_MIX_ON, 0, "DSP-MIX", 1);
+//             ph_control(mISDNport, port, handle, CMX_MIX_ON, 0, "DSP-MIX", 1);
        if (port->p_m_dtmf)
        if (port->p_m_dtmf)
-               ph_control(mISDNport, port, addr, DTMF_TONE_START, 0, "DSP-DTMF", 1);
+               ph_control(mISDNport, port, handle, DTMF_TONE_START, 0, "DSP-DTMF", 1);
        if (port->p_m_crypt)
        if (port->p_m_crypt)
-               ph_control_block(mISDNport, port, addr, BF_ENABLE_KEY, port->p_m_crypt_key, port->p_m_crypt_key_len, "DSP-CRYPT", port->p_m_crypt_key_len);
-}
-
-/*
- * subfunction for bchannel_event
- * deactivate 
- */
-static void _bchannel_deactivate(struct mISDNport *mISDNport, int i)
-{
-       iframe_t dact;
-       
-       chan_trace_header(mISDNport, mISDNport->b_port[i], "BCHANNEL deactivate", DIRECTION_OUT);
-       add_trace("channel", NULL, "%d", i+1+(i>=15));
-       end_trace();
-       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);
+               ph_control_block(mISDNport, port, handle, BF_ENABLE_KEY, port->p_m_crypt_key, port->p_m_crypt_key_len, "DSP-CRYPT", port->p_m_crypt_key_len);
 }
 
 /*
 }
 
 /*
@@ -461,19 +656,33 @@ static void _bchannel_deactivate(struct mISDNport *mISDNport, int i)
  */
 static void _bchannel_destroy(struct mISDNport *mISDNport, int i)
 {
  */
 static void _bchannel_destroy(struct mISDNport *mISDNport, int i)
 {
+#ifdef SOCKET_MISDN
+       chan_trace_header(mISDNport, mISDNport->b_port[i], "BCHANNEL remove socket", DIRECTION_OUT);
+       add_trace("channel", NULL, "%d", i+1+(i>=15));
+       add_trace("socket", NULL, "%d", mISDNport->b_socket[i]);
+       end_trace();
+       if (mISDNport->b_socket[i] > -1)
+       {
+               close(mISDNport->b_socket[i]);
+               mISDNport->b_socket[i] = -1;
+       }
+#else
        unsigned char buff[1024];
 
        chan_trace_header(mISDNport, mISDNport->b_port[i], "BCHANNEL remove stack", DIRECTION_OUT);
        add_trace("channel", NULL, "%d", i+1+(i>=15));
        unsigned char buff[1024];
 
        chan_trace_header(mISDNport, mISDNport->b_port[i], "BCHANNEL remove stack", DIRECTION_OUT);
        add_trace("channel", NULL, "%d", i+1+(i>=15));
-       add_trace("stack", "id", "0x%8x", mISDNport->b_stid[i]);
-       add_trace("stack", "address", "0x%8x", mISDNport->b_addr[i]);
+       add_trace("stack", "id", "0x%08x", mISDNport->b_stid[i]);
+       add_trace("stack", "address", "0x%08x", mISDNport->b_addr[i]);
        end_trace();
        /* remove our stack only if set */
        end_trace();
        /* remove our stack only if set */
-       PDEBUG(DEBUG_BCHANNEL, "free stack (b_addr=0x%x)\n", mISDNport->b_addr[i]);
-       mISDN_clear_stack(mISDNdevice, mISDNport->b_stid[i]);
        if (mISDNport->b_addr[i])
        if (mISDNport->b_addr[i])
+       {
+               PDEBUG(DEBUG_BCHANNEL, "free stack (b_addr=0x%x)\n", mISDNport->b_addr[i]);
+               mISDN_clear_stack(mISDNdevice, mISDNport->b_stid[i]);
                mISDN_write_frame(mISDNdevice, buff, mISDNport->b_addr[i] | FLG_MSG_DOWN, MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
                mISDN_write_frame(mISDNdevice, buff, mISDNport->b_addr[i] | FLG_MSG_DOWN, MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
-       mISDNport->b_addr[i] = 0;
+               mISDNport->b_addr[i] = 0;
+       }
+#endif
 }
 
 
 }
 
 
@@ -503,23 +712,58 @@ It may be linked to a Port class, that likes to reactivate it.
 See above.
 After deactivating bchannel, and if not used, the bchannel becomes idle again.
 
 See above.
 After deactivating bchannel, and if not used, the bchannel becomes idle again.
 
+Also the bchannel may be exported, but only if the state is or becomes idle:
+
+- B_STATE_EXPORTING
+The bchannel assignment has been sent to the remove application.
+
+- B_STATE_REMOTE
+The bchannel assignment is acknowledged by the remote application.
+
+- B_STATE_IMPORTING
+The bchannel is re-imported by mISDN port object.
+
+- B_STATE_IDLE
+See above.
+After re-importing bchannel, and if not used, the bchannel becomes idle again.
+
 
 A bchannel can have the following events:
 
 
 A bchannel can have the following events:
 
-- B_EVENT_ACTIVATE
+- B_EVENT_USE
 A bchannel is required by a Port class.
 A bchannel is required by a Port class.
+The bchannel shall be exported to the remote application.
 
 - B_EVENT_ACTIVATED
 The bchannel beomes active.
 
 
 - B_EVENT_ACTIVATED
 The bchannel beomes active.
 
-- B_EVENT_DEACTIVATE
+- B_EVENT_DROP
 The bchannel is not required by Port class anymore
 
 - B_EVENT_DEACTIVATED
 The bchannel becomes inactive.
 
 The bchannel is not required by Port class anymore
 
 - B_EVENT_DEACTIVATED
 The bchannel becomes inactive.
 
+- B_EVENT_EXPORTED
+The bchannel is now used by remote application.
+
+- B_EVENT_IMPORTED
+The bchannel is not used by remote application.
+
 All actions taken on these events depend on the current bchannel's state and if it is linked to a Port class.
 
 All actions taken on these events depend on the current bchannel's state and if it is linked to a Port class.
 
+if an export request is receive by remote application, p_m_remote_* is set.
+the b_remote_*[index] indicates if and where the channel is exported to. (set from the point on, where export is initiated, until imported is acknowledged.)
+- set on export request from remote application (if port is assigned)
+- set on channel use, if requested by remote application (p_m_remote_*)
+- cleared on drop request
+
+the bchannel will be exported with ref and stack given. remote application uses the ref to link bchannel to the call.
+the bchannel will be imported with stack given only. remote application must store stack id with the bchannel process.
+the bchannel import/export is acknowledged with stack given.
+
+if exporting, b_remote_*[index] is set to the remote socket id.
+if importing has been acknowledged. b_remote_*[index] is cleared.
+
 */
 
 /*
 */
 
 /*
@@ -531,37 +775,124 @@ All actions taken on these events depend on the current bchannel's state and if
  */
 void bchannel_event(struct mISDNport *mISDNport, int i, int event)
 {
  */
 void bchannel_event(struct mISDNport *mISDNport, int i, int event)
 {
+       class PmISDN *b_port = mISDNport->b_port[i];
        int state = mISDNport->b_state[i];
        int state = mISDNport->b_state[i];
+       unsigned long p_m_remote_ref = 0;
+       unsigned long p_m_remote_id = 0;
+#ifdef SOCKET_MISDN
+       unsigned long portid = (mISDNport->portnum<<8) + i+1+(i>=15);
+#else
+       unsigned long portid = mISDNport->b_addr[i];
+#endif
+
+       if (b_port)
+       {
+               p_m_remote_id = b_port->p_m_remote_id;
+               p_m_remote_ref = b_port->p_m_remote_ref;
+       }
 
        switch(event)
        {
 
        switch(event)
        {
-               case B_EVENT_ACTIVATE:
+               case B_EVENT_USE:
                /* port must be linked in order to allow activation */
                /* port must be linked in order to allow activation */
-               if (!mISDNport->b_port[i])
-               {
-                       PERROR("SOFTWARE ERROR: bchannel must be linked to a Port class\n");
-                       exit(-1);
-               }
+               if (!b_port)
+                       FATAL("bchannel must be linked to a Port class\n");
                switch(state)
                {
                        case B_STATE_IDLE:
                switch(state)
                {
                        case B_STATE_IDLE:
-                       /* create stack and send activation request */
-                       if (_bchannel_create(mISDNport, i))
+                       if (p_m_remote_ref)
+                       {
+                               /* export bchannel */
+                               message_bchannel_to_join(p_m_remote_id, p_m_remote_ref, BCHANNEL_ASSIGN, portid);
+                               chan_trace_header(mISDNport, b_port, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
+                               add_trace("type", NULL, "assign");
+#ifdef SOCKET_MISDN
+                               add_trace("channel", NULL, "%d.%d", portid>>8, portid&0xff);
+#else
+                               add_trace("socket", "id", "%d", portid);
+#endif
+                               end_trace();
+                               state = B_STATE_EXPORTING;
+                               mISDNport->b_remote_id[i] = p_m_remote_id;
+                               mISDNport->b_remote_ref[i] = p_m_remote_ref;
+                       } else
                        {
                        {
-                               _bchannel_activate(mISDNport, i);
-                               state = B_STATE_ACTIVATING;
+                               /* create stack and send activation request */
+                               if (_bchannel_create(mISDNport, i))
+                               {
+                                       _bchannel_activate(mISDNport, i, 1);
+                                       state = B_STATE_ACTIVATING;
+                               }
                        }
                        break;
 
                        case B_STATE_ACTIVATING:
                        }
                        break;
 
                        case B_STATE_ACTIVATING:
+                       case B_STATE_EXPORTING:
+                       /* do nothing, because it is already activating */
+                       break;
+
+                       case B_STATE_DEACTIVATING:
+                       case B_STATE_IMPORTING:
+                       /* do nothing, because we must wait until we can reactivate */
+                       break;
+
+                       default:
+                       /* problems that might ocurr:
+                        * B_EVENT_USE is received when channel already in use.
+                        * bchannel exported, but not freed by other port
+                        */
+                       PERROR("Illegal event %d at state %d, please correct.\n", event, state);
+               }
+               break;
+
+               case B_EVENT_EXPORTREQUEST:
+               /* special case where the bchannel is requested by remote */
+               if (!p_m_remote_ref)
+               {
+                       PERROR("export request without remote channel set, please correct.\n");
+                       break;
+               }
+               switch(state)
+               {
+                       case B_STATE_IDLE:
+                       /* in case, the bchannel is exported right after seize_bchannel */
+                       /* export bchannel */
+                       /* p_m_remote_id is set, when this event happens. */
+                       message_bchannel_to_join(p_m_remote_id, p_m_remote_ref, BCHANNEL_ASSIGN, portid);
+                       chan_trace_header(mISDNport, b_port, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
+                       add_trace("type", NULL, "assign");
+#ifdef SOCKET_MISDN
+                       add_trace("channel", NULL, "%d.%d", portid>>8, portid&0xff);
+#else
+                       add_trace("socket", "id", "%d", portid);
+#endif
+                       end_trace();
+                       state = B_STATE_EXPORTING;
+                       mISDNport->b_remote_id[i] = p_m_remote_id;
+                       mISDNport->b_remote_ref[i] = p_m_remote_ref;
+                       break;
+
+                       case B_STATE_ACTIVATING:
+                       case B_STATE_EXPORTING:
                        /* do nothing, because it is already activating */
                        break;
 
                        case B_STATE_DEACTIVATING:
                        /* do nothing, because it is already activating */
                        break;
 
                        case B_STATE_DEACTIVATING:
+                       case B_STATE_IMPORTING:
                        /* do nothing, because we must wait until we can reactivate */
                        break;
 
                        /* do nothing, because we must wait until we can reactivate */
                        break;
 
+                       case B_STATE_ACTIVE:
+                       /* bchannel is active, so we deactivate */
+                       _bchannel_activate(mISDNport, i, 0);
+                       state = B_STATE_DEACTIVATING;
+                       break;
+
                        default:
                        default:
+                       /* problems that might ocurr:
+                        * ... when channel already in use.
+                        * bchannel exported, but not freed by other port
+                        */
                        PERROR("Illegal event %d at state %d, please correct.\n", event, state);
                }
                break;
                        PERROR("Illegal event %d at state %d, please correct.\n", event, state);
                }
                break;
@@ -570,15 +901,15 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
                switch(state)
                {
                        case B_STATE_ACTIVATING:
                switch(state)
                {
                        case B_STATE_ACTIVATING:
-                       if (mISDNport->b_port[i])
+                       if (b_port && !p_m_remote_id)
                        {
                                /* bchannel is active and used by Port class, so we configure bchannel */
                                _bchannel_configure(mISDNport, i);
                                state = B_STATE_ACTIVE;
                        } else
                        {
                        {
                                /* bchannel is active and used by Port class, so we configure bchannel */
                                _bchannel_configure(mISDNport, i);
                                state = B_STATE_ACTIVE;
                        } else
                        {
-                               /* bchannel is active, but not used anymore (or has wrong stack config), so we deactivate */
-                               _bchannel_deactivate(mISDNport, i);
+                               /* bchannel is active, but exported OR not used anymore (or has wrong stack config), so we deactivate */
+                               _bchannel_activate(mISDNport, i, 0);
                                state = B_STATE_DEACTIVATING;
                        }
                        break;
                                state = B_STATE_DEACTIVATING;
                        }
                        break;
@@ -588,12 +919,41 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
                }
                break;
 
                }
                break;
 
-               case B_EVENT_DEACTIVATE:
-               if (!mISDNport->b_port[i])
+               case B_EVENT_EXPORTED:
+               switch(state)
                {
                {
-                       PERROR("SOFTWARE ERROR: bchannel must be linked to a Port class\n");
-                       exit(-1);
+                       case B_STATE_EXPORTING:
+                       if (b_port && p_m_remote_ref && p_m_remote_ref==mISDNport->b_remote_ref[i])
+                       {
+                               /* remote export done */
+                               state = B_STATE_REMOTE;
+                       } else
+                       {
+                               /* bchannel is now exported, but we need bchannel back
+                                * OR bchannel is not used anymore
+                                * OR bchannel has been exported to an obsolete ref,
+                                * so reimport, to later export to new remote */
+                               message_bchannel_to_join(mISDNport->b_remote_id[i], 0, BCHANNEL_REMOVE, portid);
+                               chan_trace_header(mISDNport, b_port, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
+                               add_trace("type", NULL, "remove");
+#ifdef SOCKET_MISDN
+                               add_trace("channel", NULL, "%d.%d", portid>>8, portid&0xff);
+#else
+                               add_trace("socket", "id", "%d", portid);
+#endif
+                               end_trace();
+                               state = B_STATE_IMPORTING;
+                       }
+                       break;
+
+                       default:
+                       PERROR("Illegal event %d at state %d, please correct.\n", event, state);
                }
                }
+               break;
+
+               case B_EVENT_DROP:
+               if (!b_port)
+                       FATAL("bchannel must be linked to a Port class\n");
                switch(state)
                {
                        case B_STATE_IDLE:
                switch(state)
                {
                        case B_STATE_IDLE:
@@ -601,16 +961,32 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
                        break;
 
                        case B_STATE_ACTIVATING:
                        break;
 
                        case B_STATE_ACTIVATING:
+                       case B_STATE_EXPORTING:
                        /* do nothing because we must wait until bchanenl is active before deactivating */
                        break;
 
                        case B_STATE_ACTIVE:
                        /* bchannel is active, so we deactivate */
                        /* do nothing because we must wait until bchanenl is active before deactivating */
                        break;
 
                        case B_STATE_ACTIVE:
                        /* bchannel is active, so we deactivate */
-                       _bchannel_deactivate(mISDNport, i);
+                       _bchannel_activate(mISDNport, i, 0);
                        state = B_STATE_DEACTIVATING;
                        break;
 
                        state = B_STATE_DEACTIVATING;
                        break;
 
+                       case B_STATE_REMOTE:
+                       /* bchannel is exported, so we re-import */
+                       message_bchannel_to_join(mISDNport->b_remote_id[i], 0, BCHANNEL_REMOVE, portid);
+                       chan_trace_header(mISDNport, b_port, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
+                       add_trace("type", NULL, "remove");
+#ifdef SOCKET_MISDN
+                       add_trace("channel", NULL, "%d.%d", portid>>8, portid&0xff);
+#else
+                       add_trace("socket", "id", "%d", portid);
+#endif
+                       end_trace();
+                       state = B_STATE_IMPORTING;
+                       break;
+
                        case B_STATE_DEACTIVATING:
                        case B_STATE_DEACTIVATING:
+                       case B_STATE_IMPORTING:
                        /* we may have taken an already deactivating bchannel, but do not require it anymore, so we do nothing */
                        break;
 
                        /* we may have taken an already deactivating bchannel, but do not require it anymore, so we do nothing */
                        break;
 
@@ -629,13 +1005,30 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
                        case B_STATE_DEACTIVATING:
                        _bchannel_destroy(mISDNport, i);
                        state = B_STATE_IDLE;
                        case B_STATE_DEACTIVATING:
                        _bchannel_destroy(mISDNport, i);
                        state = B_STATE_IDLE;
-                       if (mISDNport->b_port[i])
+                       if (b_port)
                        {
                        {
-                               /* bchannel is now deactivate, but is requied by Port class, so we reactivate */
-                               if (_bchannel_create(mISDNport, i))
+                               /* bchannel is now deactivate, but is requied by Port class, so we reactivate / export */
+                               if (p_m_remote_ref)
                                {
                                {
-                                       _bchannel_activate(mISDNport, i);
-                                       state = B_STATE_ACTIVATING;
+                                       message_bchannel_to_join(p_m_remote_id, p_m_remote_ref, BCHANNEL_ASSIGN, portid);
+                                       chan_trace_header(mISDNport, b_port, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
+                                       add_trace("type", NULL, "assign");
+#ifdef SOCKET_MISDN
+                                       add_trace("channel", NULL, "%d.%d", portid>>8, portid&0xff);
+#else
+                                       add_trace("socket", "id", "%d", portid);
+#endif
+                                       end_trace();
+                                       state = B_STATE_EXPORTING;
+                                       mISDNport->b_remote_id[i] = p_m_remote_id;
+                                       mISDNport->b_remote_ref[i] = p_m_remote_ref;
+                               } else
+                               {
+                                       if (_bchannel_create(mISDNport, i))
+                                       {
+                                               _bchannel_activate(mISDNport, i, 1);
+                                               state = B_STATE_ACTIVATING;
+                                       }
                                }
                        }
                        break;
                                }
                        }
                        break;
@@ -645,6 +1038,47 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
                }
                break;
 
                }
                break;
 
+               case B_EVENT_IMPORTED:
+               switch(state)
+               {
+                       case B_STATE_IMPORTING:
+                       state = B_STATE_IDLE;
+                       mISDNport->b_remote_id[i] = 0;
+                       mISDNport->b_remote_ref[i] = 0;
+                       if (b_port)
+                       {
+                               /* bchannel is now imported, but is requied by Port class, so we reactivate / export */
+                               if (p_m_remote_ref)
+                               {
+                                       message_bchannel_to_join(p_m_remote_id, p_m_remote_ref, BCHANNEL_ASSIGN, portid);
+                                       chan_trace_header(mISDNport, b_port, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
+                                       add_trace("type", NULL, "assign");
+#ifdef SOCKET_MISDN
+                                       add_trace("channel", NULL, "%d.%d", portid>>8, portid&0xff);
+#else
+                                       add_trace("socket", "id", "%d", portid);
+#endif
+                                       end_trace();
+                                       state = B_STATE_EXPORTING;
+                                       mISDNport->b_remote_id[i] = p_m_remote_id;
+                                       mISDNport->b_remote_ref[i] = p_m_remote_ref;
+                               } else
+                               {
+                                       if (_bchannel_create(mISDNport, i))
+                                       {
+                                               _bchannel_activate(mISDNport, i, 1);
+                                               state = B_STATE_ACTIVATING;
+                                       }
+                               }
+                       }
+                       break;
+
+                       default:
+                       /* ignore, because not assigned */
+                       ;
+               }
+               break;
+
                default:
                PERROR("Illegal event %d, please correct.\n", event);
        }
                default:
                PERROR("Illegal event %d, please correct.\n", event);
        }
@@ -722,7 +1156,6 @@ seize:
        p_m_b_index = i;
        p_m_b_channel = channel;
        p_m_b_exclusive = exclusive;
        p_m_b_index = i;
        p_m_b_channel = channel;
        p_m_b_exclusive = exclusive;
-       p_m_jittercheck = 0;
 
        /* reserve channel */
        if (!p_m_b_reserve)
 
        /* reserve channel */
        if (!p_m_b_reserve)
@@ -740,155 +1173,280 @@ seize:
  */
 void PmISDN::drop_bchannel(void)
 {
  */
 void PmISDN::drop_bchannel(void)
 {
-       if (p_m_b_index < 0)
-               return;
-
        /* unreserve channel */
        if (p_m_b_reserve)
                p_m_mISDNport->b_reserved--;
        p_m_b_reserve = 0;
 
        /* if not in use */
        /* unreserve channel */
        if (p_m_b_reserve)
                p_m_mISDNport->b_reserved--;
        p_m_b_reserve = 0;
 
        /* if not in use */
+       if (p_m_b_index < 0)
+               return;
        if (!p_m_b_channel)
                return;
 
        PDEBUG(DEBUG_BCHANNEL, "PmISDN(%s) dropping bchannel\n", p_name);
 
        if (p_m_mISDNport->b_state[p_m_b_index] != B_STATE_IDLE)
        if (!p_m_b_channel)
                return;
 
        PDEBUG(DEBUG_BCHANNEL, "PmISDN(%s) dropping bchannel\n", p_name);
 
        if (p_m_mISDNport->b_state[p_m_b_index] != B_STATE_IDLE)
-               bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_DEACTIVATE);
+               bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_DROP);
        p_m_mISDNport->b_port[p_m_b_index] = NULL;
        p_m_b_index = -1;
        p_m_b_channel = 0;
        p_m_b_exclusive = 0;
 }
 
        p_m_mISDNport->b_port[p_m_b_index] = NULL;
        p_m_b_index = -1;
        p_m_b_channel = 0;
        p_m_b_exclusive = 0;
 }
 
-
-/*
- * handler
- */
-int PmISDN::handler(void)
+/* process bchannel export/import message from join */
+void message_bchannel_from_join(class JoinRemote *joinremote, int type, unsigned long handle)
 {
 {
-       struct message *message;
-       int elapsed, length;
-       int ret;
-       int inbuffer;
-
-       if ((ret = Port::handler()))
-               return(ret);
+       class Endpoint *epoint;
+       class Port *port;
+       class PmISDN *isdnport;
+       struct mISDNport *mISDNport;
+       int i, ii;
 
 
-       inbuffer = (p_m_fromup_buffer_writep - p_m_fromup_buffer_readp) & FROMUP_BUFFER_MASK;
-       /* send tone data to isdn device only if we have data */
-       if (p_tone_name[0] || p_m_crypt_msg_loops || inbuffer)
+       switch(type)
        {
        {
-               /* calculate how much to transmit */
-               if (!p_last_tv_sec)
-               {
-                       elapsed = ISDN_PRELOAD; /* preload for the first time */
-               } else
+               case BCHANNEL_REQUEST:
+               /* find the port object for the join object ref */
+               if (!(epoint = find_epoint_id(joinremote->j_epoint_id)))
                {
                {
-                       elapsed = 8000 * (now_tv.tv_sec - p_last_tv_sec)
-                               + 8 * (now_tv.tv_usec/1000 - p_last_tv_msec);
-                       /* gap was greater preload, so only fill up to preload level */
-                       if (elapsed > ISDN_PRELOAD)
+                       PDEBUG(DEBUG_BCHANNEL, "join %d has no endpoint (anymore)\n", joinremote->j_serial);
+                       return;
+               }
+               if (!epoint->ep_portlist)
+               {
+                       PDEBUG(DEBUG_BCHANNEL, "join %d has no port (anymore in portlist)\n", joinremote->j_serial);
+                       return;
+               }
+               if (epoint->ep_portlist->next)
+               {
+                       PERROR("join %d has enpoint %d with more than one port. this shall not happen to remote joins.\n", joinremote->j_serial, epoint->ep_serial);
+               }
+               if (!(port = find_port_id(epoint->ep_portlist->port_id)))
+               {
+                       PDEBUG(DEBUG_BCHANNEL, "join %d has no port (anymore as object)\n", joinremote->j_serial);
+                       return;
+               }
+               if (!((port->p_type&PORT_CLASS_MASK) != PORT_CLASS_mISDN))
+               {
+                       PERROR("join %d has port %d not of mISDN type. This shall not happen.\n", joinremote->j_serial, port->p_serial);
+               }
+               isdnport = (class PmISDN *)port;
+
+               /* assign */
+               if (isdnport->p_m_remote_id)
+               {
+                       PERROR("join %d recevied bchannel request from remote, but channel is already assinged.\n", joinremote->j_serial);
+                       break;
+               }
+               mISDNport = isdnport->p_m_mISDNport;
+               i = isdnport->p_m_b_index;
+               chan_trace_header(mISDNport, isdnport, "MESSAGE_BCHANNEL (from remote application)", DIRECTION_NONE);
+               add_trace("type", NULL, "export request");
+               isdnport->p_m_remote_ref = joinremote->j_serial;
+               isdnport->p_m_remote_id = joinremote->j_remote_id;
+               if (mISDNport && i>=0)
+               {
+                       bchannel_event(mISDNport, i, B_EVENT_EXPORTREQUEST);
+               }
+               end_trace();
+               break;
+
+               case BCHANNEL_ASSIGN_ACK:
+               case BCHANNEL_REMOVE_ACK:
+               /* find mISDNport for stack ID */
+               mISDNport = mISDNport_first;
+               while(mISDNport)
+               {
+                       i = 0;
+                       ii = mISDNport->b_num;
+                       while(i < ii)
                        {
                        {
-                               elapsed = ISDN_PRELOAD;
+#ifdef SOCKET_MISDN
+                               if (mISDNport->b_socket[i] == handle)
+#else
+                               if ((unsigned long)(mISDNport->portnum<<8)+i+1+(i>=15) == handle)
+#endif
+                                       break;
+                               i++;
                        }
                        }
+                       if (i != ii)
+                               break;
+                       mISDNport = mISDNport->next;
                }
                }
-printf("p%d elapsed=%d\n", p_serial, elapsed);
-               if (elapsed >= ISDN_TRANSMIT)
+               if (!mISDNport)
                {
                {
-                       unsigned char buf[mISDN_HEADER_LEN+ISDN_PRELOAD];
-                       iframe_t *frm = (iframe_t *)buf;
-                       unsigned char *p = buf+mISDN_HEADER_LEN;
+                       PERROR("received assign/remove ack for handle=%x, but handle does not exist in any mISDNport structure.\n", handle);
+                       break;
+               }
+               /* mISDNport may now be set or NULL */
+               
+               /* set */
+               chan_trace_header(mISDNport, mISDNport->b_port[i], "MESSAGE_BCHANNEL (from remote application)", DIRECTION_NONE);
+               add_trace("type", NULL, (type==BCHANNEL_ASSIGN_ACK)?"assign_ack":"remove_ack");
+               if (mISDNport && i>=0)
+                       bchannel_event(mISDNport, i, (type==BCHANNEL_ASSIGN_ACK)?B_EVENT_EXPORTED:B_EVENT_IMPORTED);
+               end_trace();
+               break;
+               default:
+               PERROR("received wrong bchannel message type %d from remote\n", type);
+       }
+}
 
 
-                       p_last_tv_sec = now_tv.tv_sec;
-                       p_last_tv_msec = now_tv.tv_usec/1000;
 
 
-                       /* read tones or fill with silence */
-                       length = read_audio(p, elapsed);
+/*
+ * handler
 
 
-                       /*
-                        * get data from up
-                        * the fromup_buffer data is written to the beginning of the buffer
-                        * the part that is filles with tones (length) is skipped, so tones have priority
-                        * the length value is increased by the number of data copied from fromup_buffer
-                        */
-printf("p%d inbuffer=%d\n", p_serial, inbuffer);
-                       if (inbuffer)
-                       {
-                               /* inbuffer might be less than we skip due to audio */
-                               if (inbuffer <= length)
-                               {
-                                       /* clear buffer */
-                                       p_m_fromup_buffer_readp = p_m_fromup_buffer_writep;
-                                       inbuffer = 0;
-                               } else
-                               {
-                                       /* skip what we already have with tones */
-                                       p_m_fromup_buffer_readp = (p_m_fromup_buffer_readp + length) & FROMUP_BUFFER_MASK;
-                                       inbuffer -= length;
-                                       p += length;
-                               }
-                               /* if we have more in buffer, than we send this time */
-                               if (inbuffer > (elapsed-length))
-                                       inbuffer = elapsed - length;
-                               /* set length to what we actually have */
-                               length = length + inbuffer;
-printf("p%d inbuffer=%d\n", p_serial, inbuffer);
-                               /* now fill up with fromup_buffer */
-                               while (inbuffer)
-                               {
-                                       *p++ = p_m_fromup_buffer[p_m_fromup_buffer_readp];
-                                       p_m_fromup_buffer_readp = (p_m_fromup_buffer_readp + 1) & FROMUP_BUFFER_MASK;
-                                       inbuffer--;
-                               }
-                       }
-printf("p%d length=%d\n", p_serial, length);
+audio transmission procedure:
+-----------------------------
+
+* priority
+three sources of audio transmission:
+- crypto-data high priority
+- tones high priority (also high)
+- remote-data low priority
+
+* elapsed
+a variable that temporarily shows the number of samples elapsed since last transmission process.
+p_m_last_tv_* is used to store that last timestamp. this is used to calculate the time elapsed.
+
+* load
+a variable that is increased whenever data is transmitted.
+it is decreased while time elapses. it stores the number of samples that
+are currently loaded to dsp module.
+since clock in dsp module is the same clock for user space process, these 
+times have no skew.
+
+* levels
+there are two levels:
+ISDN_LOAD will give the load that have to be kept in dsp.
+ISDN_MAXLOAD will give the maximum load before dropping.
+
+* procedure for low priority data
+see txfromup() for procedure
+in short: remote data is ignored during high priority tones
+
+* procedure for high priority data
+whenever load is below ISDN_LOAD, load is filled up to ISDN_LOAD
+if no more data is available, load becomes empty again.
+
+'load' variable:
+0                    ISDN_LOAD           ISDN_MAXLOAD
++--------------------+----------------------+
+|                    |                      |
++--------------------+----------------------+
+
+on empty load or on load below ISDN_LOAD, the load is inceased to ISDN_LOAD:
+0                    ISDN_LOAD           ISDN_MAXLOAD
++--------------------+----------------------+
+|TTTTTTTTTTTTTTTTTTTT|                      |
++--------------------+----------------------+
+
+on empty load, remote-audio causes the load with the remote audio to be increased to ISDN_LOAD.
+0                    ISDN_LOAD           ISDN_MAXLOAD
++--------------------+----------------------+
+|TTTTTTTTTTTTTTTTTTTTRRRRR                  |
++--------------------+----------------------+
 
 
-                       /* overwrite buffer with crypto stuff */
-                       if (p_m_crypt_msg_loops)
-                       {
-                               /* send pending message */
-                               int tosend;
+ */
+int PmISDN::handler(void)
+{
+       struct message *message;
+       int elapsed = 0;
+       int ret;
+
+       if ((ret = Port::handler()))
+               return(ret);
+
+       /* get elapsed */
+       if (p_m_last_tv_sec)
+       {
+               elapsed = 8000 * (now_tv.tv_sec - p_m_last_tv_sec)
+                       + 8 * (now_tv.tv_usec/1000 - p_m_last_tv_msec);
+       } else
+       {
+               /* set clock of first process ever in this instance */
+               p_m_last_tv_sec = now_tv.tv_sec;
+               p_m_last_tv_msec = now_tv.tv_usec/1000;
+       }
+       /* process only if we have a minimum of samples, to make packets not too small */
+       if (elapsed >= ISDN_TRANSMIT)
+       {
+               /* set clock of last process! */
+               p_m_last_tv_sec = now_tv.tv_sec;
+               p_m_last_tv_msec = now_tv.tv_usec/1000;
+
+               /* update load */
+               if (elapsed < p_m_load)
+                       p_m_load -= elapsed;
+               else
+                       p_m_load = 0;
+
+               /* to send data, tone must be active OR crypt messages must be on */
+               if ((p_tone_name[0] || p_m_crypt_msg_loops)
+                && (p_m_load < ISDN_LOAD)
+                && (p_state==PORT_STATE_CONNECT || p_m_mISDNport->tones))
+               {
+                       int tosend = ISDN_LOAD - p_m_load, length; 
+#ifdef SOCKET_MISDN
+                       unsigned char buf[MISDN_HEADER_LEN+tosend];
+                       struct mISDNhead *frm = (struct mISDNhead *)buf;
+                       unsigned long *d = buf+MISDN_HEADER_LEN;
+#else
+                       unsigned char buf[mISDN_HEADER_LEN+tosend];
+                       iframe_t *frm = (iframe_t *)buf;
+                       unsigned char *p = buf+mISDN_HEADER_LEN;
+#endif
 
 
+                       /* copy crypto loops */
+                       while (p_m_crypt_msg_loops && tosend)
+                       {
                                /* how much do we have to send */
                                /* how much do we have to send */
-                               tosend = p_m_crypt_msg_len - p_m_crypt_msg_current;
-                               if (tosend > elapsed)
-                                       tosend = elapsed;
+                               length = p_m_crypt_msg_len - p_m_crypt_msg_current;
 
 
-                               /* our length increases, if less */
-                               if (length < tosend)
+                               /* clip tosend */
+                               if (length > tosend)
                                        length = tosend;
 
                                /* copy message (part) to buffer */
                                        length = tosend;
 
                                /* copy message (part) to buffer */
-                               memcpy(p, p_m_crypt_msg+p_m_crypt_msg_current, tosend);
-                               p_m_crypt_msg_current += tosend;
+                               memcpy(p, p_m_crypt_msg+p_m_crypt_msg_current, length);
+
+                               /* new position */
+                               p_m_crypt_msg_current += length;
                                if (p_m_crypt_msg_current == p_m_crypt_msg_len)
                                {
                                if (p_m_crypt_msg_current == p_m_crypt_msg_len)
                                {
+                                       /* next loop */
                                        p_m_crypt_msg_current = 0;
                                        p_m_crypt_msg_loops--;
                                        p_m_crypt_msg_current = 0;
                                        p_m_crypt_msg_loops--;
+//                                     puts("eine loop weniger");
                                }
                                }
+
+                               /* new length */
+                               tosend -= length;
+                       }
+
+                       /* copy tones */
+                       if (p_tone_name[0] && tosend)
+                       {
+                               tosend -= read_audio(p, tosend);
                        }
                        }
+
+                       /* send data */
+#ifdef SOCKET_MISDN
+                       frm->prim = DL_DATA_REQ;
+                       frm->id = 0;
+                       ret = sendto(handle, buffer, MISDN_HEADER_LEN+ISDN_LOAD-p_m_load-tosend, 0, NULL, 0);
+                       if (!ret)
+                               PERROR("Failed to send to socket %d\n", handle);
+#else
                        frm->prim = DL_DATA | REQUEST; 
                        frm->addr = p_m_mISDNport->b_addr[p_m_b_index] | FLG_MSG_DOWN;
                        frm->dinfo = 0;
                        frm->prim = DL_DATA | REQUEST; 
                        frm->addr = p_m_mISDNport->b_addr[p_m_b_index] | FLG_MSG_DOWN;
                        frm->dinfo = 0;
-                       frm->len = length;
-                       mISDN_write(mISDNdevice, frm, mISDN_HEADER_LEN+frm->len, TIMEOUT_1SEC);
-
-                       if (p_debug_nothingtosend)
-                       {
-                               p_debug_nothingtosend = 0;
-                               PDEBUG((DEBUG_PORT | DEBUG_BCHANNEL), "PmISDN(%s) start sending, because we have tones and/or remote audio.\n", p_name);
-                       } 
-                       return(1);
+                       frm->len = ISDN_LOAD - p_m_load - tosend;
+#endif
+                       if (frm->len)
+                               mISDN_write(mISDNdevice, frm, mISDN_HEADER_LEN+frm->len, TIMEOUT_1SEC);
+                       p_m_load += frm->len;
                }
                }
-       } else
-       {
-               if (!p_debug_nothingtosend)
-               {
-                       p_debug_nothingtosend = 1;
-                       PDEBUG((DEBUG_PORT | DEBUG_BCHANNEL), "PmISDN(%s) stop sending, because we have only silence.\n", p_name);
-               } 
        }
 
        // NOTE: deletion is done by the child class
        }
 
        // NOTE: deletion is done by the child class
@@ -904,8 +1462,8 @@ printf("p%d length=%d\n", p_serial, length);
                        message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_TIMEOUT);
                        message->param.state = p_state;
                        message_put(message);
                        message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_TIMEOUT);
                        message->param.state = p_state;
                        message_put(message);
+                       return(1);
                }
                }
-               return(1);
        }
        
        return(0); /* nothing done */
        }
        
        return(0); /* nothing done */
@@ -915,23 +1473,34 @@ printf("p%d length=%d\n", p_serial, length);
 /*
  * whenever we get audio data from bchannel, we process it here
  */
 /*
  * whenever we get audio data from bchannel, we process it here
  */
+#ifdef SOCKET_MISDN
+void PmISDN::bchannel_receive(mISDNhead *hh, unsigned char *data, int len)
+{
+       unsigned long cont = *((unsigned long *)data);
+#else
 void PmISDN::bchannel_receive(iframe_t *frm)
 {
 void PmISDN::bchannel_receive(iframe_t *frm)
 {
+       int len = frm->len;
+       unsigned long cont = *((unsigned long *)&frm->data.p);
+       unsigned char *data =(unsigned char *)&frm->data.p;
+#endif
        unsigned char *data_temp;
        unsigned long length_temp;
        struct message *message;
        unsigned char *p;
        int l;
        unsigned char *data_temp;
        unsigned long length_temp;
        struct message *message;
        unsigned char *p;
        int l;
-       unsigned long cont;
 
 
+#ifdef SOCKET_MISDN
+       if (hh->prim == PH_CONTROL_IND)
+#else
        if (frm->prim == (PH_CONTROL | INDICATION))
        if (frm->prim == (PH_CONTROL | INDICATION))
+#endif
        {
        {
-               if (frm->len < 4)
+               if (len < 4)
                {
                        PERROR("SHORT READ OF PH_CONTROL INDICATION\n");
                        return;
                }
                {
                        PERROR("SHORT READ OF PH_CONTROL INDICATION\n");
                        return;
                }
-               cont = *((unsigned long *)&frm->data.p);
                if ((cont&(~DTMF_TONE_MASK)) == DTMF_TONE_VAL)
                {
                        chan_trace_header(p_m_mISDNport, this, "BCHANNEL control", DIRECTION_IN);
                if ((cont&(~DTMF_TONE_MASK)) == DTMF_TONE_VAL)
                {
                        chan_trace_header(p_m_mISDNport, this, "BCHANNEL control", DIRECTION_IN);
@@ -965,38 +1534,62 @@ void PmISDN::bchannel_receive(iframe_t *frm)
                        message_put(message);
                        break;
 
                        message_put(message);
                        break;
 
+                       default:
+                       chan_trace_header(p_m_mISDNport, this, "BCHANNEL control", DIRECTION_IN);
+                       add_trace("unknown", NULL, "0x%x", cont);
+                       end_trace();
+               }
+               return;
+       }
+#ifdef SOCKET_MISDN
+       if (hh->prim == PH_SIGNAL_IND)
+#else
+       if (frm->prim == (PH_SIGNAL | INDICATION))
+#endif
+       {
+               switch(frm->dinfo)
+               {
                        case CMX_TX_DATA:
                        if (!p_m_txdata)
                        {
                        case CMX_TX_DATA:
                        if (!p_m_txdata)
                        {
-                               /* if rx is off, it may happen that fifos send us pending informations, we just ignore them */
-                               PDEBUG(DEBUG_BCHANNEL, "PmISDN(%s) ignoring rx data, because 'txdata' is turned off\n", p_name);
+                               /* if tx is off, it may happen that fifos send us pending informations, we just ignore them */
+                               PDEBUG(DEBUG_BCHANNEL, "PmISDN(%s) ignoring tx data, because 'txdata' is turned off\n", p_name);
                                return;
                        }
                                return;
                        }
+                       /* see below (same condition) */
+                       if (p_state!=PORT_STATE_CONNECT
+                                && !p_m_mISDNport->tones)
+                               break;
+//                     printf(".");fflush(stdout);return;
                        if (p_record)
                        if (p_record)
-                               record((unsigned char *)(cont+1), frm->len - 4, 1); // from up
+                               record(data, len, 1); // from up
                        break;
 
                        default:
                        break;
 
                        default:
-                       chan_trace_header(p_m_mISDNport, this, "BCHANNEL control", DIRECTION_IN);
-                       add_trace("unknown", NULL, "0x%x", cont);
+                       chan_trace_header(p_m_mISDNport, this, "BCHANNEL signal", DIRECTION_IN);
+                       add_trace("unknown", NULL, "0x%x", frm->dinfo);
                        end_trace();
                }
                return;
        }
                        end_trace();
                }
                return;
        }
+#ifdef SOCKET_MISDN
+       if (hh->prim != PH_DATA_IND && hh->prim != DL_DATA_IND)
+       {
+               PERROR("Bchannel received unknown primitve: 0x%x\n", hh->prim);
+#else
        if (frm->prim != (PH_DATA | INDICATION) && frm->prim != (DL_DATA | INDICATION))
        {
                PERROR("Bchannel received unknown primitve: 0x%x\n", frm->prim);
        if (frm->prim != (PH_DATA | INDICATION) && frm->prim != (DL_DATA | INDICATION))
        {
                PERROR("Bchannel received unknown primitve: 0x%x\n", frm->prim);
+#endif
                return;
        }
                return;
        }
-
        /* calls will not process any audio data unless
         * the call is connected OR interface features audio during call setup.
         */
        /* calls will not process any audio data unless
         * the call is connected OR interface features audio during call setup.
         */
-//printf("%d -> %d prim=%x calldata=%d tones=%d\n", p_serial, ACTIVE_EPOINT(p_epointlist), frm->prim, p_m_calldata, p_m_mISDNport->earlyb);    
-#warning "disabled for debug"
-#if 0
+//printf("%d -> %d prim=%x joindata=%d tones=%d\n", p_serial, ACTIVE_EPOINT(p_epointlist), frm->prim, p_m_joindata, p_m_mISDNport->earlyb);    
+#ifndef DEBUG_COREBRIDGE
        if (p_state!=PORT_STATE_CONNECT
        if (p_state!=PORT_STATE_CONNECT
-        && !p_m_mISDNport->earlyb)
+        && !p_m_mISDNport->tones)
                return;
 #endif
 
                return;
 #endif
 
@@ -1009,26 +1602,26 @@ void PmISDN::bchannel_receive(iframe_t *frm)
 
        /* record data */
        if (p_record)
 
        /* record data */
        if (p_record)
-               record((unsigned char *)&frm->data.p, frm->len, 0); // from down
+               record(data, len, 0); // from down
 
        /* randomize and listen to crypt message if enabled */
        if (p_m_crypt_listen)
        {
                /* the noisy randomizer */
 
        /* randomize and listen to crypt message if enabled */
        if (p_m_crypt_listen)
        {
                /* the noisy randomizer */
-               p = (unsigned char *)&frm->data.p;
-               l = frm->len;
+               p = data;
+               l = len;
                while(l--)
                        mISDN_rand[mISDN_rand_count & 0xff] += *p++;
 
                while(l--)
                        mISDN_rand[mISDN_rand_count & 0xff] += *p++;
 
-               cryptman_listen_bch((unsigned char *)&frm->data.p, frm->len);
+               cryptman_listen_bch(data, len);
        }
 
        }
 
-       p = (unsigned char *)&frm->data.p;
+       p = data;
 
        /* send data to epoint */
 
        /* send data to epoint */
-       if (p_m_calldata && ACTIVE_EPOINT(p_epointlist)) /* only if we have an epoint object */
+       if (p_m_joindata && ACTIVE_EPOINT(p_epointlist)) /* only if we have an epoint object */
        {
        {
-               length_temp = frm->len;
+               length_temp = len;
                data_temp = p;
                while(length_temp)
                {
                data_temp = p;
                while(length_temp)
                {
@@ -1056,7 +1649,11 @@ void PmISDN::set_echotest(int echo)
                PDEBUG(DEBUG_ISDN, "we set echo to echo=%d.\n", p_m_echo);
                if (p_m_b_channel)
                        if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE)
                PDEBUG(DEBUG_ISDN, "we set echo to echo=%d.\n", p_m_echo);
                if (p_m_b_channel)
                        if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE)
+#ifdef SOCKET_MISDN
+                               ph_control(p_m_mISDNport, this, p_m_mISDNport->b_socket[p_m_b_index], p_m_echo?CMX_ECHO_ON:CMX_ECHO_OFF, 0, "DSP-ECHO", p_m_echo);
+#else
                                ph_control(p_m_mISDNport, this, p_m_mISDNport->b_addr[p_m_b_index], p_m_echo?CMX_ECHO_ON:CMX_ECHO_OFF, 0, "DSP-ECHO", p_m_echo);
                                ph_control(p_m_mISDNport, this, p_m_mISDNport->b_addr[p_m_b_index], p_m_echo?CMX_ECHO_ON:CMX_ECHO_OFF, 0, "DSP-ECHO", p_m_echo);
+#endif
        }
 }
 
        }
 }
 
@@ -1081,10 +1678,15 @@ void PmISDN::set_tone(char *dir, char *tone)
        {
                nodsp:
                if (p_m_tone)
        {
                nodsp:
                if (p_m_tone)
+               if (p_m_b_index >= 0)
                if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE)
                {
                        PDEBUG(DEBUG_ISDN, "we reset tone from id=%d to OFF.\n", p_m_tone);
                if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE)
                {
                        PDEBUG(DEBUG_ISDN, "we reset tone from id=%d to OFF.\n", p_m_tone);
+#ifdef SOCKET_MISDN
+                       ph_control(p_m_mISDNport, this, p_m_mISDNport->b_socket[p_m_b_index], TONE_PATT_OFF, 0, "DSP-TONE", 0);
+#else
                        ph_control(p_m_mISDNport, this, p_m_mISDNport->b_addr[p_m_b_index], TONE_PATT_OFF, 0, "DSP-TONE", 0);
                        ph_control(p_m_mISDNport, this, p_m_mISDNport->b_addr[p_m_b_index], TONE_PATT_OFF, 0, "DSP-TONE", 0);
+#endif
                }
                p_m_tone = 0;
                Port::set_tone(dir, tone);
                }
                p_m_tone = 0;
                Port::set_tone(dir, tone);
@@ -1164,9 +1766,13 @@ void PmISDN::set_tone(char *dir, char *tone)
                /* set new tone */
                p_m_tone = id;
                PDEBUG(DEBUG_ISDN, "we set tone to id=%d.\n", p_m_tone);
                /* set new tone */
                p_m_tone = id;
                PDEBUG(DEBUG_ISDN, "we set tone to id=%d.\n", p_m_tone);
-               if (p_m_b_channel)
-                       if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE)
-                               ph_control(p_m_mISDNport, this, p_m_mISDNport->b_addr[p_m_b_index], p_m_tone?TONE_PATT_ON:TONE_PATT_OFF, p_m_tone, "DSP-TONE", p_m_tone);
+               if (p_m_b_index >= 0)
+               if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE)
+#ifdef SOCKET_MISDN
+                       ph_control(p_m_mISDNport, this, p_m_mISDNport->b_socket[p_m_b_index], p_m_tone?TONE_PATT_ON:TONE_PATT_OFF, p_m_tone, "DSP-TONE", p_m_tone);
+#else
+                       ph_control(p_m_mISDNport, this, p_m_mISDNport->b_addr[p_m_b_index], p_m_tone?TONE_PATT_ON:TONE_PATT_OFF, p_m_tone, "DSP-TONE", p_m_tone);
+#endif
        }
        /* turn user-space tones off in cases of no tone OR dsp tone */
        Port::set_tone("",NULL);
        }
        /* turn user-space tones off in cases of no tone OR dsp tone */
        Port::set_tone("",NULL);
@@ -1184,18 +1790,26 @@ void PmISDN::message_mISDNsignal(unsigned long epoint_id, int message_id, union
                {
                        p_m_txvol = param->mISDNsignal.txvol;
                        PDEBUG(DEBUG_BCHANNEL, "we change tx-volume to shift=%d.\n", p_m_txvol);
                {
                        p_m_txvol = param->mISDNsignal.txvol;
                        PDEBUG(DEBUG_BCHANNEL, "we change tx-volume to shift=%d.\n", p_m_txvol);
-                       if (p_m_b_channel)
-                               if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE)
-                                       ph_control(p_m_mISDNport, this, p_m_mISDNport->b_addr[p_m_b_index], VOL_CHANGE_TX, p_m_txvol, "DSP-TXVOL", p_m_txvol);
+                       if (p_m_b_index >= 0)
+                       if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE)
+#ifdef SOCKET_MISDN
+                               ph_control(p_m_mISDNport, this, p_m_mISDNport->b_socket[p_m_b_index], VOL_CHANGE_TX, p_m_txvol, "DSP-TXVOL", p_m_txvol);
+#else
+                               ph_control(p_m_mISDNport, this, p_m_mISDNport->b_addr[p_m_b_index], VOL_CHANGE_TX, p_m_txvol, "DSP-TXVOL", p_m_txvol);
+#endif
                } else
                        PDEBUG(DEBUG_BCHANNEL, "we already have tx-volume shift=%d.\n", p_m_rxvol);
                if (p_m_rxvol != param->mISDNsignal.rxvol)
                {
                        p_m_rxvol = param->mISDNsignal.rxvol;
                        PDEBUG(DEBUG_BCHANNEL, "we change rx-volume to shift=%d.\n", p_m_rxvol);
                } else
                        PDEBUG(DEBUG_BCHANNEL, "we already have tx-volume shift=%d.\n", p_m_rxvol);
                if (p_m_rxvol != param->mISDNsignal.rxvol)
                {
                        p_m_rxvol = param->mISDNsignal.rxvol;
                        PDEBUG(DEBUG_BCHANNEL, "we change rx-volume to shift=%d.\n", p_m_rxvol);
-                       if (p_m_b_channel)
-                               if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE)
-                                       ph_control(p_m_mISDNport, this, p_m_mISDNport->b_addr[p_m_b_index], VOL_CHANGE_RX, p_m_rxvol, "DSP-RXVOL", p_m_rxvol);
+                       if (p_m_b_index >= 0)
+                       if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE)
+#ifdef SOCKET_MISDN
+                               ph_control(p_m_mISDNport, this, p_m_mISDNport->b_socket[p_m_b_index], VOL_CHANGE_RX, p_m_rxvol, "DSP-RXVOL", p_m_rxvol);
+#else
+                               ph_control(p_m_mISDNport, this, p_m_mISDNport->b_addr[p_m_b_index], VOL_CHANGE_RX, p_m_rxvol, "DSP-RXVOL", p_m_rxvol);
+#endif
                } else
                        PDEBUG(DEBUG_BCHANNEL, "we already have rx-volume shift=%d.\n", p_m_rxvol);
                break;
                } else
                        PDEBUG(DEBUG_BCHANNEL, "we already have rx-volume shift=%d.\n", p_m_rxvol);
                break;
@@ -1207,9 +1821,13 @@ void PmISDN::message_mISDNsignal(unsigned long epoint_id, int message_id, union
                {
                        p_m_conf = param->mISDNsignal.conf;
                        PDEBUG(DEBUG_BCHANNEL, "we change conference to conf=%d.\n", p_m_conf);
                {
                        p_m_conf = param->mISDNsignal.conf;
                        PDEBUG(DEBUG_BCHANNEL, "we change conference to conf=%d.\n", p_m_conf);
-                       if (p_m_b_channel)
-                               if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE)
-                                       ph_control(p_m_mISDNport, this, p_m_mISDNport->b_addr[p_m_b_index], (p_m_conf)?CMX_CONF_JOIN:CMX_CONF_SPLIT, p_m_conf, "DSP-CONF", p_m_conf);
+                       if (p_m_b_index >= 0)
+                       if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE)
+#ifdef SOCKET_MISDN
+                               ph_control(p_m_mISDNport, this, p_m_mISDNport->b_socket[p_m_b_index], (p_m_conf)?CMX_CONF_JOIN:CMX_CONF_SPLIT, p_m_conf, "DSP-CONF", p_m_conf);
+#else
+                               ph_control(p_m_mISDNport, this, p_m_mISDNport->b_addr[p_m_b_index], (p_m_conf)?CMX_CONF_JOIN:CMX_CONF_SPLIT, p_m_conf, "DSP-CONF", p_m_conf);
+#endif
                } else
                        PDEBUG(DEBUG_BCHANNEL, "we already have conf=%d.\n", p_m_conf);
                /* we must set, even if currently tone forbids conf */
                } else
                        PDEBUG(DEBUG_BCHANNEL, "we already have conf=%d.\n", p_m_conf);
                /* we must set, even if currently tone forbids conf */
@@ -1217,13 +1835,13 @@ void PmISDN::message_mISDNsignal(unsigned long epoint_id, int message_id, union
 //if (dddebug) PDEBUG(DEBUG_ISDN, "dddebug = %d\n", dddebug->type);
                break;
 
 //if (dddebug) PDEBUG(DEBUG_ISDN, "dddebug = %d\n", dddebug->type);
                break;
 
-               case mISDNSIGNAL_CALLDATA:
-               if (p_m_calldata != param->mISDNsignal.calldata)
+               case mISDNSIGNAL_JOINDATA:
+               if (p_m_joindata != param->mISDNsignal.joindata)
                {
                {
-                       p_m_calldata = param->mISDNsignal.calldata;
-                       PDEBUG(DEBUG_BCHANNEL, "we change to calldata=%d.\n", p_m_calldata);
+                       p_m_joindata = param->mISDNsignal.joindata;
+                       PDEBUG(DEBUG_BCHANNEL, "we change to joindata=%d.\n", p_m_joindata);
                } else
                } else
-                       PDEBUG(DEBUG_BCHANNEL, "we already have calldata=%d.\n", p_m_calldata);
+                       PDEBUG(DEBUG_BCHANNEL, "we already have joindata=%d.\n", p_m_joindata);
                break;
                
                case mISDNSIGNAL_DELAY:
                break;
                
                case mISDNSIGNAL_DELAY:
@@ -1231,9 +1849,13 @@ void PmISDN::message_mISDNsignal(unsigned long epoint_id, int message_id, union
                {
                        p_m_delay = param->mISDNsignal.delay;
                        PDEBUG(DEBUG_BCHANNEL, "we change delay mode to delay=%d.\n", p_m_delay);
                {
                        p_m_delay = param->mISDNsignal.delay;
                        PDEBUG(DEBUG_BCHANNEL, "we change delay mode to delay=%d.\n", p_m_delay);
-                       if (p_m_b_channel)
-                               if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE)
-                                       ph_control(p_m_mISDNport, this, p_m_mISDNport->b_addr[p_m_b_index], p_m_delay?CMX_DELAY:CMX_JITTER, p_m_delay, "DSP-DELAY", p_m_delay);
+                       if (p_m_b_index >= 0)
+                       if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE)
+#ifdef SOCKET_MISDN
+                               ph_control(p_m_mISDNport, this, p_m_mISDNport->b_socket[p_m_b_index], p_m_delay?CMX_DELAY:CMX_JITTER, p_m_delay, "DSP-DELAY", p_m_delay);
+#else
+                               ph_control(p_m_mISDNport, this, p_m_mISDNport->b_addr[p_m_b_index], p_m_delay?CMX_DELAY:CMX_JITTER, p_m_delay, "DSP-DELAY", p_m_delay);
+#endif
                } else
                        PDEBUG(DEBUG_BCHANNEL, "we already have delay=%d.\n", p_m_delay);
                break;
                } else
                        PDEBUG(DEBUG_BCHANNEL, "we already have delay=%d.\n", p_m_delay);
                break;
@@ -1264,9 +1886,13 @@ void PmISDN::message_crypt(unsigned long epoint_id, int message_id, union parame
                memcpy(p_m_crypt_key, param->crypt.data, p_m_crypt_key_len);
                crypt_off:
                PDEBUG(DEBUG_BCHANNEL, "we set encryption to crypt=%d. (0 means OFF)\n", p_m_crypt);
                memcpy(p_m_crypt_key, param->crypt.data, p_m_crypt_key_len);
                crypt_off:
                PDEBUG(DEBUG_BCHANNEL, "we set encryption to crypt=%d. (0 means OFF)\n", p_m_crypt);
-               if (p_m_b_channel)
-                       if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE)
-                               ph_control_block(p_m_mISDNport, this, p_m_mISDNport->b_addr[p_m_b_index], p_m_crypt?BF_ENABLE_KEY:BF_DISABLE, p_m_crypt_key, p_m_crypt_key_len, "DSP-CRYPT", p_m_crypt_key_len);
+               if (p_m_b_index >= 0)
+               if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE)
+#ifdef SOCKET_MISDN
+                       ph_control_block(p_m_mISDNport, this, p_m_mISDNport->b_socket[p_m_b_index], p_m_crypt?BF_ENABLE_KEY:BF_DISABLE, p_m_crypt_key, p_m_crypt_key_len, "DSP-CRYPT", p_m_crypt_key_len);
+#else
+                       ph_control_block(p_m_mISDNport, this, p_m_mISDNport->b_addr[p_m_b_index], p_m_crypt?BF_ENABLE_KEY:BF_DISABLE, p_m_crypt_key, p_m_crypt_key_len, "DSP-CRYPT", p_m_crypt_key_len);
+#endif
                break;
 
                case CC_DACT_REQ:            /* deactivate session encryption */
                break;
 
                case CC_DACT_REQ:            /* deactivate session encryption */
@@ -1291,13 +1917,17 @@ void PmISDN::message_crypt(unsigned long epoint_id, int message_id, union parame
                        break;
                }
                p_m_crypt_msg_current = 0; /* reset */
                        break;
                }
                p_m_crypt_msg_current = 0; /* reset */
-               p_m_crypt_msg_loops = 3; /* enable */
+               p_m_crypt_msg_loops = 6; /* enable */
 #if 0
                /* disable txmix, or we get corrupt data due to audio process */
 #if 0
                /* disable txmix, or we get corrupt data due to audio process */
-               if (p_m_txmix)
+               if (p_m_txmix && p_m_b_index>=0)
                {
                        PDEBUG(DEBUG_BCHANNEL, "for sending CR_MESSAGE_REQ, we reset txmix from txmix=%d.\n", p_m_txmix);
                {
                        PDEBUG(DEBUG_BCHANNEL, "for sending CR_MESSAGE_REQ, we reset txmix from txmix=%d.\n", p_m_txmix);
+#ifdef SOCKET_MISDN
+                       ph_control(p_m_mISDNport, this, p_mISDNport->b_socket[p_m_b_index], CMX_MIX_OFF, 0, "DSP-TXMIX", 0);
+#else
                        ph_control(p_m_mISDNport, this, p_mISDNport->b_addr[p_m_b_index], CMX_MIX_OFF, 0, "DSP-TXMIX", 0);
                        ph_control(p_m_mISDNport, this, p_mISDNport->b_addr[p_m_b_index], CMX_MIX_OFF, 0, "DSP-TXMIX", 0);
+#endif
                }
 #endif
                break;
                }
 #endif
                break;
@@ -1338,19 +1968,177 @@ int PmISDN::message_epoint(unsigned long epoint_id, int message_id, union parame
 
 
 /*
 
 
 /*
- * main loop for processing messages from mISDN device
+ * main loop for processing messages from mISDN
  */
  */
+#ifdef SOCKET_MISDN
+int mISDN_handler(void)
+{
+       int ret, work = 0;
+       struct mISDNport *mISDNport;
+       class PmISDN *isdnport;
+       int i;
+       char buffer[2048+MISDN_HEADER_LEN];
+       struct mISDNhead *hh = (struct mISDNhead *)buffer;
+
+       /* process all ports */
+       mISDNport = mISDNport_first;
+       while(mISDNport)
+       {
+               /* process all bchannels */
+               i = 0;
+               while(i < mISDNport->b_num)
+               {
+                       /* handle port of bchannel */
+                       isdnport=mISDNport->b_port[i];
+                       if (isdnport)
+                       {
+                               /* call bridges in user space OR crypto OR recording */
+                               if (isdnport->p_m_joindata || isdnport->p_m_crypt_msg_loops || isdnport->p_m_crypt_listen || isdnport->p_record)
+                               {
+                                       /* rx IS required */
+                                       if (isdnport->p_m_rxoff)
+                                       {
+                                               /* turn on RX */
+                                               isdnport->p_m_rxoff = 0;
+                                               PDEBUG(DEBUG_BCHANNEL, "%s: receive data is required, so we turn them on\n");
+                                               if (mISDNport->b_port[i] && mISDNport->b_state[i] == B_STATE_ACTIVE)
+                                                       ph_control(mISDNport, isdnport, mISDNport->b_socket[isdnport->p_m_b_index], CMX_RECEIVE_ON, 0, "DSP-RXOFF", 0);
+                                               return(1);
+                                       }
+                               } else
+                               {
+                                       /* rx NOT required */
+                                       if (!isdnport->p_m_rxoff)
+                                       {
+                                               /* turn off RX */
+                                               isdnport->p_m_rxoff = 1;
+                                               PDEBUG(DEBUG_BCHANNEL, "%s: receive data is not required, so we turn them off\n");
+                                               if (mISDNport->b_port[i] && mISDNport->b_state[i] == B_STATE_ACTIVE)
+                                                       ph_control(mISDNport, isdnport, mISDNport->b_socket[isdnport->p_m_b_index], CMX_RECEIVE_OFF, 0, "DSP-RXOFF", 1);
+                                               return(1);
+                                       }
+                               }
+                               /* recording */
+                               if (isdnport->p_record)
+                               {
+                                       /* txdata IS required */
+                                       if (!isdnport->p_m_txdata)
+                                       {
+                                               /* turn on RX */
+                                               isdnport->p_m_txdata = 1;
+                                               PDEBUG(DEBUG_BCHANNEL, "%s: transmit data is required, so we turn them on\n");
+                                               if (mISDNport->b_port[i] && mISDNport->b_state[i] == B_STATE_ACTIVE)
+                                                       ph_control(mISDNport, isdnport, mISDNport->b_socket[isdnport->p_m_b_index], CMX_TXDATA_ON, 0, "DSP-TXDATA", 1);
+                                               return(1);
+                                       }
+                               } else
+                               {
+                                       /* txdata NOT required */
+                                       if (isdnport->p_m_txdata)
+                                       {
+                                               /* turn off RX */
+                                               isdnport->p_m_txdata = 0;
+                                               PDEBUG(DEBUG_BCHANNEL, "%s: transmit data is not required, so we turn them off\n");
+                                               if (mISDNport->b_port[i] && mISDNport->b_state[i] == B_STATE_ACTIVE)
+                                                       ph_control(mISDNport, isdnport, mISDNport->b_socket[isdnport->p_m_b_index], CMX_TXDATA_OFF, 0, "DSP-TXDATA", 0);
+                                               return(1);
+                                       }
+                               }
+                       }
+
+                       /* handle message from bchannel */
+                       if (mISDNport->b_stack[i] > -1)
+                       {
+                               ret = recv(mISDNport->b_stack[i], buffer, sizeof(buffer), 0);
+                               if (ret >= MISDN_HEADER_LEN)
+                               {
+                                       work = 1;
+                                       switch(hh->prim)
+                                       {
+                                               /* we don't care about confirms, we use rx data to sync tx */
+                                               case PH_DATA_CONF:
+                                               case DL_DATA_CONF:
+                                               break;
+
+                                               /* we receive audio data, we respond to it AND we send tones */
+                                               case PH_DATA_IND:
+                                               case DL_DATA_IND:
+                                               case PH_SIGNAL_IND:
+                                               case PH_CONTROL_IND:
+                                               if (mISDNport->b_port[i])
+                                                       mISDNport->b_port[i]->bchannel_receive(hh, buffer+MISDN_HEADER_LEN, ret-MISDN_HEADER_LEN);
+                                               else
+                                                       PDEBUG(DEBUG_BCHANNEL, "b-channel is not associated to an ISDNPort (socket %d), ignoring.\n", mISDNport->b_stack[i]);
+                                               break;
+
+                                               case PH_ACTIVATE_IND:
+                                               case DL_ESTABLISH_IND:
+                                               case PH_ACTIVATE_CONF:
+                                               case DL_ESTABLISH_CONF:
+                                               PDEBUG(DEBUG_BCHANNEL, "DL_ESTABLISH confirm: bchannel is now activated (socket %d).\n", mISDNport->b_socket[i]);
+                                               bchannel_event(mISDNport, i, B_EVENT_ACTIVATED);
+                                               break;
+
+                                               case PH_DEACTIVATE_IND:
+                                               case DL_RELEASE_IND:
+                                               case PH_DEACTIVATE_CONF:
+                                               case DL_RELEASE_CONF:
+                                               PDEBUG(DEBUG_BCHANNEL, "DL_RELEASE confirm: bchannel is now de-activated (socket %d).\n", mISDNport->b_socket[i]);
+                                               bchannel_event(mISDNport, i, B_EVENT_DEACTIVATED);
+                                               break;
+
+                                               default:
+                                               PERROR("child message not handled: prim(0x%x) socket(%d) msg->len(%d)\n", hh->prim, mISDNport->b_socket[i], msg->len);
+                                       }
+                               } else
+                               {
+                                       if (ret < 0 && errno != EWOULDBLOCK)
+                                               PERROR("Read from port %d, index %d failed with return code %d\n", mISDNport->portnum, i, ret);
+                               }
+                       }
+                       
+                       i++;
+               }
+#if 0
+               if (mISDNport->l1timeout && now>mISDNport->l1timeout)
+               { ---}
+                       PDEBUG(DEBUG_ISDN, "the L1 establish timer expired, we release all pending messages.\n", mISDNport->portnum);
+                       mISDNport->l1timeout = 0;
+#endif
+
+               /* layer 2 establish timer */
+               if (mISDNport->l2establish)
+               {
+                       if (now-mISDNport->l2establish > 5)
+                       {
+
+                               PDEBUG(DEBUG_ISDN, "the L2 establish timer expired, we try to establish the link portnum=%d.\n", mISDNport->portnum);
+                               mISDNport->ml3->to_layer2(mISDNport->ml3, DL_ESTABLISH_REQ);
+                               l1l2l3_trace_header(mISDNport, NULL, DL_ESTABLISH_REQ, DIRECTION_OUT);
+                               end_trace();
+                               return(1);
+                       }
+               }
+
+
+               mISDNport = mISDNport->next;
+       }
+
+       /* if we received at least one b-frame, we will return 1 */
+       return(work);
+}
+#else
 int mISDN_handler(void)
 {
        int ret;
 int mISDN_handler(void)
 {
        int ret;
-       msg_t *msg;
-       iframe_t *frm;
        struct mISDNport *mISDNport;
        class PmISDN *isdnport;
        struct mISDNport *mISDNport;
        class PmISDN *isdnport;
-       net_stack_t *nst;
+       int i;
+       msg_t *msg;
+       iframe_t *frm;
        msg_t *dmsg;
        mISDNuser_head_t *hh;
        msg_t *dmsg;
        mISDNuser_head_t *hh;
-       int i;
+       net_stack_t *nst;
 
        /* the que avoids loopbacks when replying to stack after receiving
          * from stack. */
 
        /* the que avoids loopbacks when replying to stack after receiving
          * from stack. */
@@ -1365,7 +2153,7 @@ int mISDN_handler(void)
                        if (isdnport)
                        {
                                /* call bridges in user space OR crypto OR recording */
                        if (isdnport)
                        {
                                /* call bridges in user space OR crypto OR recording */
-                               if (isdnport->p_m_calldata || isdnport->p_m_crypt_msg_loops || isdnport->p_m_crypt_listen || isdnport->p_record)
+                               if (isdnport->p_m_joindata || isdnport->p_m_crypt_msg_loops || isdnport->p_m_crypt_listen || isdnport->p_record)
                                {
                                        /* rx IS required */
                                        if (isdnport->p_m_rxoff)
                                {
                                        /* rx IS required */
                                        if (isdnport->p_m_rxoff)
@@ -1421,7 +2209,7 @@ int mISDN_handler(void)
                }
 #if 0
                if (mISDNport->l1timeout && now>mISDNport->l1timeout)
                }
 #if 0
                if (mISDNport->l1timeout && now>mISDNport->l1timeout)
-               {
+               { ---}
                        PDEBUG(DEBUG_ISDN, "the L1 establish timer expired, we release all pending messages.\n", mISDNport->portnum);
                        mISDNport->l1timeout = 0;
 #endif
                        PDEBUG(DEBUG_ISDN, "the L1 establish timer expired, we release all pending messages.\n", mISDNport->portnum);
                        mISDNport->l1timeout = 0;
 #endif
@@ -1439,10 +2227,11 @@ int mISDN_handler(void)
                                        if (mISDNport->nst.manager_l3(&mISDNport->nst, dmsg))
                                                free_msg(dmsg);
                                } else {
                                        if (mISDNport->nst.manager_l3(&mISDNport->nst, dmsg))
                                                free_msg(dmsg);
                                } else {
+                                       iframe_t act;
+
                                        PDEBUG(DEBUG_ISDN, "the L2 establish timer expired, we try to establish the link TE portnum=%d.\n", mISDNport->portnum);
                                        time(&mISDNport->l2establish);
                                        /* establish */
                                        PDEBUG(DEBUG_ISDN, "the L2 establish timer expired, we try to establish the link TE portnum=%d.\n", mISDNport->portnum);
                                        time(&mISDNport->l2establish);
                                        /* establish */
-                                       iframe_t act;
                                        act.prim = DL_ESTABLISH | REQUEST; 
                                        act.addr = (mISDNport->upper_id & ~LAYER_ID_MASK) | 3 | FLG_MSG_DOWN;
                                        act.dinfo = 0;
                                        act.prim = DL_ESTABLISH | REQUEST; 
                                        act.addr = (mISDNport->upper_id & ~LAYER_ID_MASK) | 3 | FLG_MSG_DOWN;
                                        act.dinfo = 0;
@@ -1489,8 +2278,7 @@ int mISDN_handler(void)
                free_msg(msg);
                if (errno == EAGAIN)
                        return(0);
                free_msg(msg);
                if (errno == EAGAIN)
                        return(0);
-               PERROR("FATAL ERROR: failed to do mISDN_read()\n");
-               exit(-1); 
+               FATAL("Failed to do mISDN_read()\n");
        }
        if (!ret)
        {
        }
        if (!ret)
        {
@@ -1697,6 +2485,7 @@ int mISDN_handler(void)
                        case PH_DATA | INDICATION:
                        case DL_DATA | INDICATION:
                        case PH_CONTROL | INDICATION:
                        case PH_DATA | INDICATION:
                        case DL_DATA | INDICATION:
                        case PH_CONTROL | INDICATION:
+                       case PH_SIGNAL | INDICATION:
                        i = 0;
                        while(i < mISDNport->b_num)
                        {
                        i = 0;
                        while(i < mISDNport->b_num)
                        {
@@ -1766,69 +2555,249 @@ int mISDN_handler(void)
        free_msg(msg);
        return(1);
 }
        free_msg(msg);
        return(1);
 }
+#endif
+
+#ifdef SOCKET_MISDN
+int do_layer3(struct mlayer3 *ml3, unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
+{
+       struct mISDNport *mISDNport = ml3->private;
+
+       if (cmd == MT_ASSIGN)
+       {
+               ueberdenken!!!
+       }
+       
+       /* lock LCR */
+       achtung MT_ASSIGN kommt hier an
+       lock it baby
+
+       /* d-message */
+       switch(cmd)
+       {
+               case MGR_SHORTSTATUS_IND:
+               case MGR_SHORTSTATUS_CONF:
+               switch(frm->dinfo) {
+                       case SSTATUS_L1_ACTIVATED:
+                       l1l2l3_trace_header(mISDNport, NULL, PH_ACTIVATE_IND, DIRECTION_IN);
+                       end_trace();
+                       goto ss_act;
+                       case SSTATUS_L1_DEACTIVATED:
+                       l1l2l3_trace_header(mISDNport, NULL, PH_DEACTIVATE_IND, DIRECTION_IN);
+                       end_trace();
+                       goto ss_deact;
+                       case SSTATUS_L2_ESTABLISHED:
+                       l1l2l3_trace_header(mISDNport, NULL, DL_ESTABLISH_IND, DIRECTION_IN);
+                       end_trace();
+                       goto ss_estab;
+                       case SSTATUS_L2_RELEASED:
+                       l1l2l3_trace_header(mISDNport, NULL, DL_RELEASE_IND, DIRECTION_IN);
+                       end_trace();
+                       goto ss_rel;
+               }
+               break;
+
+               case PH_ACTIVATE_CONF:
+               case PH_ACTIVATE_IND:
+               l1l2l3_trace_header(mISDNport, NULL, cmd, DIRECTION_IN);
+               end_trace();
+               ss_act:
+               mISDNport->l1link = 1;
+#if 0
+               if (mISDNport->ntmode)
+                       setup_queue(mISDNport, 1);
+#endif
+               break;
+
+               case PH_DEACTIVATE | CONFIRM:
+               case PH_DEACTIVATE | INDICATION:
+               l1l2l3_trace_header(mISDNport, NULL, cmd, DIRECTION_IN);
+               end_trace();
+               ss_deact:
+               mISDNport->l1link = 0;
+raus mit der setup-queue, da dies im stack geschieht
+#if 0
+               if (mISDNport->ntmode)
+                       setup_queue(mISDNport, 0);
+#endif
+               break;
+
+               case PH_CONTROL_CONFIRM:
+               case PH_CONTROL_INDICATION:
+               PDEBUG(DEBUG_ISDN, "Received PH_CONTROL for port %d (%s).\n", mISDNport->portnum, mISDNport->ifport->interface->name);
+               break;
+
+               case DL_ESTABLISH_IND:
+               case DL_ESTABLISH_CONF:
+               l1l2l3_trace_header(mISDNport, NULL, cmd, DIRECTION_IN);
+               end_trace();
+               if (!mISDNport->ntmode) break; /* !!!!!!!!!!!!!!!! */
+               ss_estab:
+               if (mISDNport->l2establish)
+               {
+                       mISDNport->l2establish = 0;
+                       PDEBUG(DEBUG_ISDN, "the link became active before l2establish timer expiry.\n");
+               }
+               mISDNport->l2link = 1;
+               break;
+
+               case DL_RELEASE_IND:
+               case DL_RELEASE_CONF:
+               l1l2l3_trace_header(mISDNport, NULL, cmd, DIRECTION_IN);
+               end_trace();
+               ss_rel:
+               mISDNport->l2link = 0;
+               if (mISDNport->ptp)
+               {
+                       time(&mISDNport->l2establish);
+                       PDEBUG(DEBUG_ISDN, "because we are ptp, we set a l2establish timer.\n");
+               }
+               break;
+
+               default:
+               /* l3-data is sent to LCR */
+               message_from_mlayer3(mISDNport, cmd, pid, l3m);
+       }
+
+       /* unlock LCR */
+       unlock it baby
+
+       /* free message */
+       if (l3m)
+               free_l3_msg(l3m);
+       return(0);
+
+}
+#endif
 
 
 /*
  * global function to add a new card (port)
  */
 
 
 /*
  * global function to add a new card (port)
  */
-struct mISDNport *mISDNport_open(int port, int ptp, int ptmp, struct interface *interface)
+struct mISDNport *mISDNport_open(int port, int ptp, int ptmp, int force_nt, struct interface *interface)
 {
        int ret;
        unsigned char buff[1025];
        iframe_t *frm = (iframe_t *)buff;
 {
        int ret;
        unsigned char buff[1025];
        iframe_t *frm = (iframe_t *)buff;
-       stack_info_t *stinf;
        struct mISDNport *mISDNport, **mISDNportp;
        int i, cnt;
        struct mISDNport *mISDNport, **mISDNportp;
        int i, cnt;
+       int pri, bri, ports;
+       int nt, te;
+#ifdef SOCKET_MISDN
+       struct mlayer3 *ml3;
+       struct mISDN_devinfo devinfo;
+
+       ret = ioctl(mISDNsocket, IMGETCOUNT, &cnt);
+       if (ret < 0)
+       {
+               fprintf(stderr, "Cannot get number of mISDN devices. (ioctl IMGETCOUNT failed ret=%d)\n", ret);
+               return(NULL);
+       }
+#else
 //     interface_info_t ii;
        net_stack_t *nst;
        manager_t *mgr;
        layer_info_t li;
 //     interface_info_t ii;
        net_stack_t *nst;
        manager_t *mgr;
        layer_info_t li;
-       int pri = 0;
-       int nt = 0;
-
-       /* open mISDNdevice if not already open */
-       if (mISDNdevice < 0)
-       {
-               ret = mISDN_open();
-               if (ret < 0)
-               {
-                       PERROR("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(NULL);
-               }
-               mISDNdevice = ret;
-               PDEBUG(DEBUG_ISDN, "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(DEBUG_ISDN, "our entity for l3-processes is %d.\n", entity);
-       }
+       stack_info_t *stinf;
 
        /* query port's requirements */
        cnt = mISDN_get_stack_count(mISDNdevice);
 
        /* query port's requirements */
        cnt = mISDN_get_stack_count(mISDNdevice);
+#endif
+
        if (cnt <= 0)
        {
        if (cnt <= 0)
        {
-               PERROR("Found no card. Please be sure to load card drivers.\n");
+               PERROR_RUNTIME("Found no card. Please be sure to load card drivers.\n");
                return(NULL);
        }
        if (port>cnt || port<1)
        {
                return(NULL);
        }
        if (port>cnt || port<1)
        {
-               PERROR("Port (%d) given at 'ports' (options.conf) is out of existing port range (%d-%d)\n", port, 1, cnt);
+               PERROR_RUNTIME("Port (%d) given at 'ports' (options.conf) is out of existing port range (%d-%d)\n", port, 1, cnt);
+               return(NULL);
+       }
+
+       pri = bri = ports = nt = te = 0;
+#ifdef SOCKET_MISDN
+       devinfo.id = port - 1;
+       ret = ioctl(socket, IMGETDEVINFO, &devinfo);
+       if (ret <= 0)
+       {
+               PERROR_RUNTIME("Cannot get device information for port %d. (ioctl IMGETDEVINFO failed ret=%d)\n", i, ret);
+               break;
+       }
+       /* output the port info */
+       if (devinfo.Dprotocols & (1 << ISDN_P_TE_S0))
+       {
+               bri = 1;
+               te = 1;
+       }
+       if (devinfo.Dprotocols & (1 << ISDN_P_NT_S0))
+       {
+               bri = 1;
+               nt = 1;
+       }
+#ifdef ISDN_P_TE_E1
+       if (devinfo.Dprotocols & (1 << ISDN_P_TE_E1))
+       {
+               pri = 1;
+               te = 1;
+       }
+#endif
+#ifdef ISDN_P_NT_E1
+       if (devinfo.Dprotocols & (1 << ISDN_P_NT_E1))
+       {
+               pri = 1;
+               nt = 1;
+       }
+#endif
+#ifdef ISDN_P_FXS
+       if (devinfo.Dprotocols & (1 << ISDN_P_FXS))
+       {
+               pots = 1;
+               te = 1;
+       }
+#endif
+#ifdef ISDN_P_FXO
+       if (devinfo.Dprotocols & (1 << ISDN_P_FXO))
+       {
+               pots = 1;
+               nt = 1;
+       }
+#endif
+       if (force_nt && !nt)
+       {
+               PERROR_RUNTIME("Port %d does not support NT-mode.\n", port);
+               return(NULL);
+       }
+       if (bri && pri)
+       {
+               PERROR_RUNTIME("Port %d supports BRI and PRI?? What kind of controller is that?. (Can't use this!)\n", port);
+               return(NULL);
+       }
+       if (pots && !bri && !pri)
+       {
+               PERROR_RUNTIME("Port %d supports POTS, LCR does not!\n", port);
+               return(NULL);
+       }
+       if (!bri && !pri)
+       {
+               PERROR_RUNTIME("Port %d does not support BRI nor PRI!\n", port);
                return(NULL);
        }
                return(NULL);
        }
+       if (!nt && !te)
+       {
+               PERROR_RUNTIME("Port %d does not support NT-mode nor TE-mode!\n", port);
+               return(NULL);
+       }
+       /* force nt, by turning off TE */
+       if (force_nt && nt)
+               te = 0;
+       /* if TE an NT is supported (and not forced to NT), turn off NT */
+       if (te && nt)
+               nt = 0;
+#else
        ret = mISDN_get_stack_info(mISDNdevice, port, buff, sizeof(buff));
        if (ret < 0)
        {
        ret = mISDN_get_stack_info(mISDNdevice, port, buff, sizeof(buff));
        if (ret < 0)
        {
-               PERROR("Cannot get stack info for port %d (ret=%d)\n", port, ret);
+               PERROR_RUNTIME("Cannot get stack info for port %d (ret=%d)\n", port, ret);
                return(NULL);
        }
        stinf = (stack_info_t *)&frm->data.p;
                return(NULL);
        }
        stinf = (stack_info_t *)&frm->data.p;
@@ -1851,7 +2820,7 @@ struct mISDNport *mISDNport_open(int port, int ptp, int ptmp, struct interface *
                nt = 1;
                break;
                default:
                nt = 1;
                break;
                default:
-               PERROR("unknown port(%d) type 0x%08x\n", port, stinf->pid.protocol[0]);
+               PERROR_RUNTIME("unknown port(%d) type 0x%08x\n", port, stinf->pid.protocol[0]);
                return(NULL);
        }
        if (nt)
                return(NULL);
        }
        if (nt)
@@ -1859,30 +2828,31 @@ struct mISDNport *mISDNport_open(int port, int ptp, int ptmp, struct interface *
                /* NT */
                if (stinf->pid.protocol[1] == 0)
                {
                /* NT */
                if (stinf->pid.protocol[1] == 0)
                {
-                       PERROR("Given port %d: Missing layer 1 NT-mode protocol.\n", port);
+                       PERROR_RUNTIME("Given port %d: Missing layer 1 NT-mode protocol.\n", port);
                        return(NULL);
                }
                if (stinf->pid.protocol[2])
                {
                        return(NULL);
                }
                if (stinf->pid.protocol[2])
                {
-                       PERROR("Given port %d: Layer 2 protocol 0x%08x is detected, but not allowed for NT lib.\n", port, stinf->pid.protocol[2]);
+                       PERROR_RUNTIME("Given port %d: Layer 2 protocol 0x%08x is detected, but not allowed for NT lib.\n", port, stinf->pid.protocol[2]);
                        return(NULL);
                }
                        return(NULL);
                }
-       } else
+       }
+       if (te)
        {
                /* TE */
                if (stinf->pid.protocol[1] == 0)
                {
        {
                /* TE */
                if (stinf->pid.protocol[1] == 0)
                {
-                       PERROR("Given port %d: Missing layer 1 protocol.\n", port);
+                       PERROR_RUNTIME("Given port %d: Missing layer 1 protocol.\n", port);
                        return(NULL);
                }
                if (stinf->pid.protocol[2] == 0)
                {
                        return(NULL);
                }
                if (stinf->pid.protocol[2] == 0)
                {
-                       PERROR("Given port %d: Missing layer 2 protocol.\n", port);
+                       PERROR_RUNTIME("Given port %d: Missing layer 2 protocol.\n", port);
                        return(NULL);
                }
                if (stinf->pid.protocol[3] == 0)
                {
                        return(NULL);
                }
                if (stinf->pid.protocol[3] == 0)
                {
-                       PERROR("Given port %d: Missing layer 3 protocol.\n", port);
+                       PERROR_RUNTIME("Given port %d: Missing layer 3 protocol.\n", port);
                        return(NULL);
                } else
                {
                        return(NULL);
                } else
                {
@@ -1892,59 +2862,76 @@ struct mISDNport *mISDNport_open(int port, int ptp, int ptmp, struct interface *
                                break;
 
                                default:
                                break;
 
                                default:
-                               PERROR("Given port %d: own protocol 0x%08x", port,stinf->pid.protocol[3]);
+                               PERROR_RUNTIME("Given port %d: own protocol 0x%08x", port,stinf->pid.protocol[3]);
                                return(NULL);
                        }
                }
                if (stinf->pid.protocol[4])
                {
                                return(NULL);
                        }
                }
                if (stinf->pid.protocol[4])
                {
-                       PERROR("Given port %d: Layer 4 protocol not allowed.\n", port);
+                       PERROR_RUNTIME("Given port %d: Layer 4 protocol not allowed.\n", port);
                        return(NULL);
                }
        }
                        return(NULL);
                }
        }
+#endif
 
        /* add mISDNport structure */
        mISDNportp = &mISDNport_first;
        while(*mISDNportp)
                mISDNportp = &((*mISDNportp)->next);
 
        /* add mISDNport structure */
        mISDNportp = &mISDNport_first;
        while(*mISDNportp)
                mISDNportp = &((*mISDNportp)->next);
-       mISDNport = (struct mISDNport *)calloc(1, sizeof(struct mISDNport));
-       if (!mISDNport)
-       {
-               PERROR("Cannot alloc mISDNport structure\n");
-               return(NULL);
-       }
+       mISDNport = (struct mISDNport *)MALLOC(sizeof(struct mISDNport));
        pmemuse++;
        pmemuse++;
-       memset(mISDNport, 0, sizeof(mISDNport));
        *mISDNportp = mISDNport;
 
        /* allocate ressources of port */
        *mISDNportp = mISDNport;
 
        /* allocate ressources of port */
+#ifdef SOCKET_MISDN
+       /* open layer 3 */
+       protocol = (nt)?L3_PROTOCOL_DSS1_USER:L3_PROTOCOL_DSS1_NETWORK;
+       prop = 0;
+       if (ptp)
+              prop |= FLG_PTP;
+       if (ptmp && pri)
+              prop |= FLG_FORCE_PTMP;
+       mISDNport->ml3 = open_layer3(port-1, protocol, prop , do_dchannel, mISDNport);
+       if (!mISDNport->ml3)
+       {
+               PERROR_RUNTIME("Cannot get layer(%d) id of port %d\n", nt?2:4, port);
+               return(NULL);
+       }
+
+#if 0
+       /* if ntmode, establish L1 to send the tei removal during start */
+       if (mISDNport->ntmode)
+       {
+               iframe_t act;
+               /* L1 */
+               act.prim = PH_ACTIVATE | REQUEST; 
+               act.addr = mISDNport->upper_id | FLG_MSG_DOWN;
+               printf("UPPER ID 0x%x, addr 0x%x\n",mISDNport->upper_id, act.addr);
+               act.dinfo = 0;
+               act.len = 0;
+               mISDN_write(mISDNdevice, &act, mISDN_HEADER_LEN+act.len, TIMEOUT_1SEC);
+               usleep(10000); /* to be sure, that l1 is up */
+       }
+#endif
+
+       SCPY(mISDNport->name, devinfo.name);
+       mISDNport->b_num = devinfo.nrbchan;
+#else
        msg_queue_init(&mISDNport->downqueue);
        msg_queue_init(&mISDNport->downqueue);
-//     SCPY(mISDNport->name, "noname");
-       mISDNport->portnum = port;
-       mISDNport->ntmode = nt;
-       mISDNport->pri = pri;
        mISDNport->d_stid = stinf->id;
        PDEBUG(DEBUG_ISDN, "d_stid = 0x%x.\n", mISDNport->d_stid);
        mISDNport->d_stid = stinf->id;
        PDEBUG(DEBUG_ISDN, "d_stid = 0x%x.\n", mISDNport->d_stid);
-       mISDNport->b_num = stinf->childcnt;
-       PDEBUG(DEBUG_ISDN, "Port has %d b-channels.\n", mISDNport->b_num);
        if ((stinf->pid.protocol[2]&ISDN_PID_L2_DF_PTP) || (nt&&ptp) || pri)
        {
                PDEBUG(DEBUG_ISDN, "Port is point-to-point.\n");
        if ((stinf->pid.protocol[2]&ISDN_PID_L2_DF_PTP) || (nt&&ptp) || pri)
        {
                PDEBUG(DEBUG_ISDN, "Port is point-to-point.\n");
-               mISDNport->ptp = ptp = 1;
+               ptp = 1;
                if (ptmp && nt)
                {
                        PDEBUG(DEBUG_ISDN, "Port is forced to point-to-multipoint.\n");
                if (ptmp && nt)
                {
                        PDEBUG(DEBUG_ISDN, "Port is forced to point-to-multipoint.\n");
-                       mISDNport->ptp = ptp = 0;
+                       ptp = 0;
                }
        }
                }
        }
-       i = 0;
-       while(i < stinf->childcnt)
-       {
-               mISDNport->b_stid[i] = stinf->child[i];
-               mISDNport->b_state[i] = B_STATE_IDLE;
-               PDEBUG(DEBUG_ISDN, "b_stid[%d] = 0x%x.\n", i, mISDNport->b_stid[i]);
-               i++;
-       }
+
+       /* create layer intance */
        memset(&li, 0, sizeof(li));
        UCPY(&li.name[0], (nt)?"net l2":"pbx l4");
        li.object_id = -1;
        memset(&li, 0, sizeof(li));
        UCPY(&li.name[0], (nt)?"net l2":"pbx l4");
        li.object_id = -1;
@@ -2032,6 +3019,26 @@ struct mISDNport *mISDNport_open(int port, int ptp, int ptmp, struct interface *
                Isdnl3Init(nst);
        }
 
                Isdnl3Init(nst);
        }
 
+       mISDNport->b_num = stinf->childcnt;
+#endif
+       mISDNport->portnum = port;
+       mISDNport->ntmode = nt;
+       mISDNport->pri = pri;
+       mISDNport->ptp = ptp;
+       PDEBUG(DEBUG_ISDN, "Port has %d b-channels.\n", mISDNport->b_num);
+       i = 0;
+       while(i < mISDNport->b_num)
+       {
+               mISDNport->b_state[i] = B_STATE_IDLE;
+#ifdef SOCKET_MISDN
+               mISDNport->b_socket = -1;
+#else
+               mISDNport->b_stid[i] = stinf->child[i];
+               PDEBUG(DEBUG_ISDN, "b_stid[%d] = 0x%x.\n", i, mISDNport->b_stid[i]);
+#endif
+               i++;
+       }
+
        /* if te-mode, query state link */
        if (!mISDNport->ntmode)
        {
        /* if te-mode, query state link */
        if (!mISDNport->ntmode)
        {
@@ -2147,6 +3154,9 @@ void mISDNport_close(struct mISDNport *mISDNport)
                i++;
        }
 
                i++;
        }
 
+#ifdef SOCKET_MISDN
+       close_layer3(mISDNport->ml3);
+#else
        /* free ressources of port */
        msg_queue_purge(&mISDNport->downqueue);
 
        /* free ressources of port */
        msg_queue_purge(&mISDNport->downqueue);
 
@@ -2163,7 +3173,7 @@ void mISDNport_close(struct mISDNport *mISDNport)
                        /* phd */
                        msg_queue_purge(&nst->down_queue);
                        if (nst->phd_down_msg)
                        /* phd */
                        msg_queue_purge(&nst->down_queue);
                        if (nst->phd_down_msg)
-                               free(nst->phd_down_msg);
+                               FREE(nst->phd_down_msg, 0);
                }
        }
 
                }
        }
 
@@ -2173,6 +3183,7 @@ void mISDNport_close(struct mISDNport *mISDNport)
                if (mISDNport->upper_id)
                        mISDN_write_frame(mISDNdevice, buf, mISDNport->upper_id | FLG_MSG_DOWN, MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
        }
                if (mISDNport->upper_id)
                        mISDN_write_frame(mISDNdevice, buf, mISDNport->upper_id | FLG_MSG_DOWN, MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
        }
+#endif
 
        /* remove from list */
        mISDNportp = &mISDNport_first;
 
        /* remove from list */
        mISDNportp = &mISDNport_first;
@@ -2188,25 +3199,11 @@ void mISDNport_close(struct mISDNport *mISDNport)
        }
 
        if (mISDNportp)
        }
 
        if (mISDNportp)
-       {
-               PERROR("software error, mISDNport not in list\n");
-               exit(-1);
-       }
+               FATAL("mISDNport not in list\n");
        
        
-       memset(mISDNport, 0, sizeof(struct mISDNport));
-       free(mISDNport);
+       FREE(mISDNport, sizeof(struct mISDNport));
        pmemuse--;
 
        pmemuse--;
 
-       /* close mISDNdevice, if no port */
-       if (mISDNdevice>=0 && mISDNport_first==NULL)
-       {
-               /* free entity */
-               mISDN_write_frame(mISDNdevice, buf, 0, MGR_DELENTITY | REQUEST, entity, 0, NULL, TIMEOUT_1SEC);
-               /* close device */
-               mISDN_close(mISDNdevice);
-               mISDNdevice = -1;
-               PDEBUG(DEBUG_ISDN, "mISDN device closed.\n");
-       }
 }
 
 
 }
 
 
@@ -2215,79 +3212,171 @@ void mISDNport_close(struct mISDNport *mISDNport)
  */
 void mISDN_port_info(void)
 {
  */
 void mISDN_port_info(void)
 {
-       int err;
+       int ret;
        int i, ii, p;
        int i, ii, p;
-       int useable, nt, pri;
+       int useable, nt, te, pri, bri, pots;
        unsigned char buff[1025];
        iframe_t *frm = (iframe_t *)buff;
        unsigned char buff[1025];
        iframe_t *frm = (iframe_t *)buff;
+#ifdef SOCKET_MISDN
+       struct mISDN_devinfo devinfo;
+       int socket;
+
+       /* open mISDN */
+       socket = socket(PF_ISDN, SOCK_RAW, ISDN_P_BASE);
+       if (socket < 0)
+       {
+               fprintf(stderr, "Cannot open mISDN due to %s. (Does your Kernel support socket based mISDN?)\n", strerror(errno));
+               exit(EXIT_FAILURE);
+       }
+
+       /* get number of stacks */
+       i = 1;
+       ret = ioctl(socket, IMGETCOUNT, &ii);
+       if (ret < 0)
+       {
+               fprintf(stderr, "Cannot get number of mISDN devices. (ioctl IMGETCOUNT failed ret=%d)\n", ret);
+               goto done;
+       }
+#else
        stack_info_t *stinf;
        int device;
 
        /* open mISDN */
        if ((device = mISDN_open()) < 0)
        {
        stack_info_t *stinf;
        int device;
 
        /* open mISDN */
        if ((device = mISDN_open()) < 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", device, errno, strerror(errno));
-               exit(-1);
+               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", device, errno, strerror(errno));
+               exit(EXIT_FAILURE);
        }
 
        /* get number of stacks */
        i = 1;
        ii = mISDN_get_stack_count(device);
        }
 
        /* get number of stacks */
        i = 1;
        ii = mISDN_get_stack_count(device);
+#endif
        printf("\n");
        if (ii <= 0)
        {
                printf("Found no card. Please be sure to load card drivers.\n");
        printf("\n");
        if (ii <= 0)
        {
                printf("Found no card. Please be sure to load card drivers.\n");
+               goto done;
        }
 
        /* loop the number of cards and get their info */
        while(i <= ii)
        {
        }
 
        /* loop the number of cards and get their info */
        while(i <= ii)
        {
-               err = mISDN_get_stack_info(device, i, buff, sizeof(buff));
-               if (err <= 0)
+               nt = te = bri = pri = pots = 0;
+               useable = 0;
+
+#ifdef SOCKET_MISDN
+               devinfo.id = i - 1;
+               ret = ioctl(socket, IMGETDEVINFO, &devinfo);
+               if (ret <= 0)
                {
                {
-                       fprintf(stderr, "mISDN_get_stack_info() failed: port=%d err=%d\n", i, err);
+                       fprintf(stderr, "Cannot get device information for port %d. (ioctl IMGETDEVINFO failed ret=%d)\n", i, ret);
                        break;
                }
                        break;
                }
-               stinf = (stack_info_t *)&frm->data.p;
 
 
-               nt = pri = 0;
-               useable = 1;
+               /* output the port info */
+               printf("Port %2d name='%s': ", i, devinfo.name);
+               if (devinfo.Dprotocols & (1 << ISDN_P_TE_S0))
+               {
+                       bri = 1;
+                       te = 1;
+               }
+               if (devinfo.Dprotocols & (1 << ISDN_P_NT_S0))
+               {
+                       bri = 1;
+                       nt = 1;
+               }
+#ifdef ISDN_P_TE_E1
+               if (devinfo.Dprotocols & (1 << ISDN_P_TE_E1))
+               {
+                       pri = 1;
+                       te = 1;
+               }
+#endif
+#ifdef ISDN_P_NT_E1
+               if (devinfo.Dprotocols & (1 << ISDN_P_NT_E1))
+               {
+                       pri = 1;
+                       nt = 1;
+               }
+#endif
+#ifdef ISDN_P_FXS
+               if (devinfo.Dprotocols & (1 << ISDN_P_FXS))
+               {
+                       pots = 1;
+                       te = 1;
+               }
+#endif
+#ifdef ISDN_P_FXO
+               if (devinfo.Dprotocols & (1 << ISDN_P_FXO))
+               {
+                       pots = 1;
+                       nt = 1;
+               }
+#endif
+               if ((te || nt) && (bri || pri || ports))
+                       usable = 1;
+
+               if (te && bri)
+                       printf("TE-mode BRI S/T interface line (for phone lines)");
+               if (nt && bri)
+                       printf("NT-mode BRI S/T interface port (for phones)");
+               if (te && pri)
+                       printf("TE-mode PRI E1  interface line (for phone lines)");
+               if (nt && pri)
+                       printf("NT-mode PRI E1  interface port (for E1 terminals)");
+               if (te && pots)
+                       printf("FXS     POTS    interface port (for analog lines)");
+               if (nt && pots)
+                       printf("FXO     POTS    interface port (for analog phones)");
+               if (ports)
+               {
+                       usable = 0;
+                       printf("\n -> Analog interfaces are not supported.");
+               } else
+               if (!usable)
+               {
+                       printf("unsupported interface protocol bits 0x%016x", devinfo.Dprotocols);
+               }
+               printf("\n");
+
+               printf("  - %d B-channels\n", devinfo.nfbchan);
+#else
+               ret = mISDN_get_stack_info(device, i, buff, sizeof(buff));
+               if (ret <= 0)
+               {
+                       fprintf(stderr, "mISDN_get_stack_info() failed: port=%d error=%d\n", i, ret);
+                       break;
+               }
+               stinf = (stack_info_t *)&frm->data.p;
 
                /* output the port info */
                printf("Port %2d: ", i);
                switch(stinf->pid.protocol[0] & ~ISDN_PID_FEATURE_MASK)
                {
                        case ISDN_PID_L0_TE_S0:
 
                /* output the port info */
                printf("Port %2d: ", i);
                switch(stinf->pid.protocol[0] & ~ISDN_PID_FEATURE_MASK)
                {
                        case ISDN_PID_L0_TE_S0:
+                       useable = 1;
+                       te = 1;
+                       bri = 1;
                        printf("TE-mode BRI S/T interface line (for phone lines)");
                        printf("TE-mode BRI S/T interface line (for phone lines)");
-#if 0
-                       if (stinf->pid.protocol[0] & ISDN_PID_L0_TE_S0_HFC & ISDN_PID_FEATURE_MASK)
-                               printf(" HFC multiport card");
-#endif
                        break;
                        case ISDN_PID_L0_NT_S0:
                        break;
                        case ISDN_PID_L0_NT_S0:
+                       useable = 1;
                        nt = 1;
                        nt = 1;
+                       bri = 1;
                        printf("NT-mode BRI S/T interface port (for phones)");
                        printf("NT-mode BRI S/T interface port (for phones)");
-#if 0
-                       if (stinf->pid.protocol[0] & ISDN_PID_L0_NT_S0_HFC & ISDN_PID_FEATURE_MASK)
-                               printf(" HFC multiport card");
-#endif
                        break;
                        case ISDN_PID_L0_TE_E1:
                        break;
                        case ISDN_PID_L0_TE_E1:
+                       useable = 1;
+                       te = 1;
                        pri = 1;
                        printf("TE-mode PRI E1  interface line (for phone lines)");
                        pri = 1;
                        printf("TE-mode PRI E1  interface line (for phone lines)");
-#if 0
-                       if (stinf->pid.protocol[0] & ISDN_PID_L0_TE_E1_HFC & ISDN_PID_FEATURE_MASK)
-                               printf(" HFC-E1 card");
-#endif
                        break;
                        case ISDN_PID_L0_NT_E1:
                        break;
                        case ISDN_PID_L0_NT_E1:
+                       useable = 1;
                        nt = 1;
                        pri = 1;
                        nt = 1;
                        pri = 1;
-                       printf("NT-mode PRI E1  interface port (for phones)");
-#if 0
-                       if (stinf->pid.protocol[0] & ISDN_PID_L0_NT_E1_HFC & ISDN_PID_FEATURE_MASK)
-                               printf(" HFC-E1 card");
-#endif
+                       printf("NT-mode PRI E1  interface port (for E1 terminals)");
                        break;
                        default:
                        useable = 0;
                        break;
                        default:
                        useable = 0;
@@ -2307,7 +3396,7 @@ void mISDN_port_info(void)
                                if (stinf->pid.protocol[p])
                                {
                                        useable = 0;
                                if (stinf->pid.protocol[p])
                                {
                                        useable = 0;
-                                       printf(" -> Layer %d protocol 0x%08x is detected, but not allowed for NT lib.\n", p, stinf->pid.protocol[p]);
+                                       printf(" -> Layer %d protocol 0x%08x is detected, port already in use by another application.\n", p, stinf->pid.protocol[p]);
                                }
                                p++;
                        }
                                }
                                p++;
                        }
@@ -2318,7 +3407,8 @@ void mISDN_port_info(void)
                                else
                                        printf(" -> Interface can be Poin-To-Point/Multipoint.\n");
                        }
                                else
                                        printf(" -> Interface can be Poin-To-Point/Multipoint.\n");
                        }
-               } else
+               }
+               if (te)
                {
                        if (stinf->pid.protocol[1] == 0)
                        {
                {
                        if (stinf->pid.protocol[1] == 0)
                        {
@@ -2358,15 +3448,16 @@ void mISDN_port_info(void)
                                if (stinf->pid.protocol[p])
                                {
                                        useable = 0;
                                if (stinf->pid.protocol[p])
                                {
                                        useable = 0;
-                                       printf(" -> Layer %d protocol 0x%08x is detected, but not allowed for TE lib.\n", p, stinf->pid.protocol[p]);
+                                       printf(" -> Layer %d protocol 0x%08x is detected, port already in use by another application.\n", p, stinf->pid.protocol[p]);
                                }
                                p++;
                        }
                }
                printf("  - %d B-channels\n", stinf->childcnt);
                                }
                                p++;
                        }
                }
                printf("  - %d B-channels\n", stinf->childcnt);
+#endif
 
                if (!useable)
 
                if (!useable)
-                       printf(" * Port NOT useable for PBX\n");
+                       printf(" * Port NOT useable for LCR\n");
 
                printf("--------\n");
 
 
                printf("--------\n");
 
@@ -2374,12 +3465,14 @@ void mISDN_port_info(void)
        }
        printf("\n");
 
        }
        printf("\n");
 
+done:
+#ifdef SOCKET_MISDN
+       close(sd);
+#else
        /* close mISDN */
        /* close mISDN */
-       if ((err = mISDN_close(device)))
-       {
-               fprintf(stderr, "mISDN_close() failed: err=%d '%s'\n", err, strerror(err));
-               exit(-1);
-       }
+       if ((ret = mISDN_close(device)))
+               FATAL("mISDN_close() failed: err=%d '%s'\n", ret, strerror(ret));
+#endif
 }
 
 
 }
 
 
@@ -2388,26 +3481,65 @@ void mISDN_port_info(void)
  */
 void PmISDN::txfromup(unsigned char *data, int length)
 {
  */
 void PmISDN::txfromup(unsigned char *data, int length)
 {
-       int avail;
-       /* no data */
-       if (!length)
+#ifdef SOCKET_MISDN
+       unsigned char buf[MISDN_HEADER_LEN+((length>ISDN_LOAD)?length:ISDN_LOAD)];
+       struct mISDNhead *frm = (struct mISDNhead *)buf;
+
+       if (p_m_b_index < 0)
                return;
                return;
+       if (!p_m_mISDNport->b_socket[p_m_b_index])
+               return;
+#else
+       unsigned char buf[mISDN_HEADER_LEN+((length>ISDN_LOAD)?length:ISDN_LOAD)];
+       iframe_t *frm = (iframe_t *)buf;
 
 
-       /* get free samples in buffer */
-       avail = ((p_m_fromup_buffer_readp - p_m_fromup_buffer_writep - 1) & FROMUP_BUFFER_MASK);
-       if (avail < length)
-       {
-               PDEBUG(DEBUG_PORT, "Port(%d): fromup_buffer overflows, this shall not happen under normal conditions\n", p_serial);
+       if (p_m_b_index < 0)
                return;
                return;
-       }
+       if (!p_m_mISDNport->b_addr[p_m_b_index])
+               return;
+#endif
 
 
-       /* write data to buffer and return */
-       while(length)
+       /* check if high priority tones exist
+        * ignore data in this case
+        */
+       if (p_tone_name[0] || p_m_crypt_msg_loops)
+               return;
+
+       /* preload procedure
+        * if transmit buffer in DSP module is empty,
+        * preload it to DSP_LOAD to prevent jitter gaps.
+        */
+       if (p_m_load==0 && ISDN_LOAD>0)
        {
        {
-               p_m_fromup_buffer[p_m_fromup_buffer_writep] = *data++;
-               p_m_fromup_buffer_writep = (p_m_fromup_buffer_writep + 1) & FROMUP_BUFFER_MASK;
-               length--;
+
+               memcpy(buf+mISDN_HEADER_LEN, data, ISDN_LOAD);
+               frm->len = ISDN_LOAD;
+               mISDN_write(mISDNdevice, frm, mISDN_HEADER_LEN+frm->len, TIMEOUT_1SEC);
+               p_m_load += frm->len;
        }
        }
-       return; // must return, because length is 0
+
+       /* drop if load would exceed ISDN_MAXLOAD
+        * this keeps the delay not too high
+        */
+       if (p_m_load+length > ISDN_MAXLOAD)
+               return;
+
+       /* make and send frame */
+#ifdef SOCKET_MISDN
+       frm->prim = DL_DATA_REQ;
+       frm->id = 0;
+       memcpy(buf+MISDN_HEADER_LEN, data, length);
+       ret = sendto(p_m_mISDNport->b_socket[p_m_b_index], buf, MISDN_HEADER_LEN+length, 0, NULL, 0);
+       if (!ret)
+               PERROR("Failed to send to socket %d\n", handle);
+#else
+       frm->prim = DL_DATA | REQUEST; 
+       frm->addr = p_m_mISDNport->b_addr[p_m_b_index] | FLG_MSG_DOWN;
+       frm->dinfo = 0;
+       frm->len = length;
+       memcpy(buf+mISDN_HEADER_LEN, data, length);
+       mISDN_write(mISDNdevice, frm, mISDN_HEADER_LEN+frm->len, TIMEOUT_1SEC);
+#endif
+       p_m_load += length;
 }
 
 }