work on socket. (don't try yet)
[lcr.git] / mISDN.cpp
index 67d649e..2ee2c49 100644 (file)
--- a/mISDN.cpp
+++ b/mISDN.cpp
@@ -5,37 +5,73 @@
 **---------------------------------------------------------------------------**
 ** Copyright: Andreas Eversberg                                              **
 **                                                                           **
-** mISDN port abstraction for dss1 and sip                                   **
+** mISDN port abstraction for dss1                                           **
 **                                                                           **
 \*****************************************************************************/ 
 
-
 #include "main.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
+#include "myisdn.h"
+#ifndef SOCKET_MISDN
+// old mISDN
 extern "C" {
-#include <net_l2.h>
+#include <mISDNuser/net_l2.h>
 }
+
+#ifndef CMX_TXDATA_ON
+#define OLD_MISDN
+#endif
+#ifndef CMX_TXDATA_OFF
+#define OLD_MISDN
+#endif
+#ifndef CMX_DELAY
+#define OLD_MISDN
+#endif
+#ifndef PIPELINE_CFG
+#define OLD_MISDN
+#endif
+#ifndef CMX_TX_DATA
+#define OLD_MISDN
+#endif
+
+#ifdef OLD_MISDN
+#warning
+#warning *********************************************************
+#warning *
+#warning * It seems that you use an older version of mISDN.
+#warning * Features like voice recording or echo will not work.
+#warning * Also it causes problems with loading modules and may
+#warning * not work at all.
+#warning *
+#warning * Please upgrade to newer version. A working version can
+#warning * be found at www.linux-call-router.de.
+#warning *
+#warning * Do not use the mISDN_1_1 branch, it does not have all
+#warning * the features that are required. Use the master branch
+#warning * instead.
+#warning *
+#warning *********************************************************
+#warning
+#error
 #endif
 
 #ifndef ISDN_PID_L4_B_USER
 #define ISDN_PID_L4_B_USER 0x440000ff
 #endif
 
+#else
+// socket mISDN
+#include <sys/socket.h>
+extern "C" {
+}
+#include <mISDNuser/mISDNif.h>
+#include <mISDNuser/q931.h>
+#include <mISDNuser/mlayer3.h>
+#endif
+
+// timeouts if activating/deactivating response from mISDN got lost
+#define B_TIMER_ACTIVATING 1 // seconds
+#define B_TIMER_DEACTIVATING 1 // seconds
+
 /* list of mISDN ports */
 struct mISDNport *mISDNport_first;
 
@@ -43,18 +79,38 @@ struct mISDNport *mISDNport_first;
 unsigned char mISDN_rand[256];
 int mISDN_rand_count = 0;
 
-#ifdef MISDN_SOCKET
+#ifdef SOCKET_MISDN
+unsigned long mt_assign_pid = ~0;
+
+int mISDNsocket = -1;
+
 int mISDN_initialize(void)
 {
+       char filename[256];
+
        /* try to open raw socket to check kernel */
-       ret = socket(PF_ISDN, SOCK_RAW, ISDN_P_BASE);
-       if (ret < 0)
+       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);
        }
-       close(ret);
 
+       /* open debug, if enabled and not only stack debugging */
+       if (options.deb && (options.deb != DEBUG_STACK))
+       {
+               SPRINT(filename, "%s/debug.log", INSTALL_DATA);
+               debug_fp = fopen(filename, "a");
+       }
+
+       if (options.deb & DEBUG_STACK)
+       {
+               SPRINT(filename, "%s/debug_mISDN.log", INSTALL_DATA);
+               mISDN_debug_init(0xffffffff, filename, filename, filename);
+       } else
+               mISDN_debug_init(0, NULL, NULL, NULL);
+
+       /* init mlayer3 */
        init_layer3(4); // buffer of 4
 
        return(0);
@@ -63,6 +119,15 @@ int mISDN_initialize(void)
 void mISDN_deinitialize(void)
 {
        cleanup_layer3();
+
+       mISDN_debug_close();
+
+       if (debug_fp)
+               fclose(debug_fp);
+       debug_fp = NULL;
+
+       if (mISDNsocket > -1)
+               close(mISDNsocket);
 }
 #else
 int entity = 0; /* used for udevice */
@@ -122,8 +187,9 @@ void mISDN_deinitialize(void)
        unsigned char buff[1025];
 
        debug_close();
+       global_debug = 0;
 
-       if (mISDNdevice >= 0)
+       if (mISDNdevice > -1)
        {
                /* free entity */
                mISDN_write_frame(mISDNdevice, buff, 0, MGR_DELENTITY | REQUEST, entity, 0, NULL, TIMEOUT_1SEC);
@@ -148,7 +214,8 @@ PmISDN::PmISDN(int type, mISDNport *mISDNport, char *portname, struct port_setti
        p_m_b_reserve = 0;
        p_m_delete = 0;
        p_m_hold = 0;
-       p_m_txvol = p_m_rxvol = 0;
+       p_m_tx_gain = mISDNport->ifport->interface->tx_gain;
+       p_m_rx_gain = mISDNport->ifport->interface->rx_gain;
        p_m_conf = 0;
        p_m_txdata = 0;
        p_m_delay = 0;
@@ -161,7 +228,8 @@ PmISDN::PmISDN(int type, mISDNport *mISDNport, char *portname, struct port_setti
        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 */
-
+       SCPY(p_m_pipeline, mISDNport->ifport->interface->pipeline);
+       
        /* audio */
        p_m_load = 0;
        p_m_last_tv_sec = 0;
@@ -174,13 +242,18 @@ PmISDN::PmISDN(int type, mISDNport *mISDNport, char *portname, struct port_setti
        p_m_crypt_msg_len = 0;
        p_m_crypt_msg[0] = '\0';
        p_m_crypt_msg_current = 0;
-       p_m_crypt_key[0] = '\0';
        p_m_crypt_key_len = 0;
        p_m_crypt_listen = 0;
        p_m_crypt_listen_state = 0;
        p_m_crypt_listen_len = 0;
        p_m_crypt_listen_msg[0] = '\0';
        p_m_crypt_listen_crc = 0;
+       if (mISDNport->ifport->interface->bf_len >= 4 && mISDNport->ifport->interface->bf_len <= 56)
+       {
+               memcpy(p_m_crypt_key, mISDNport->ifport->interface->bf_key, p_m_crypt_key_len);
+               p_m_crypt_key_len = mISDNport->ifport->interface->bf_len;
+               p_m_crypt = 1;
+       }
 
        /* if any channel requested by constructor */
        if (channel == CHANNEL_ANY)
@@ -252,41 +325,46 @@ static struct isdn_message {
        char *name;
        unsigned long value;
 } isdn_message[] = {
-       {"TIMEOUT", CC_TIMEOUT},
-       {"SETUP", CC_SETUP},
-       {"SETUP_ACK", CC_SETUP_ACKNOWLEDGE},
-       {"PROCEEDING", CC_PROCEEDING},
-       {"ALERTING", CC_ALERTING},
-       {"CONNECT", CC_CONNECT},
-       {"CONNECT RES", CC_CONNECT},
-       {"CONNECT_ACK", CC_CONNECT_ACKNOWLEDGE},
-       {"DISCONNECT", CC_DISCONNECT},
-       {"RELEASE", CC_RELEASE},
-       {"RELEASE_COMP", CC_RELEASE_COMPLETE},
-       {"INFORMATION", CC_INFORMATION},
-       {"PROGRESS", CC_PROGRESS},
-       {"NOTIFY", CC_NOTIFY},
-       {"SUSPEND", CC_SUSPEND},
-       {"SUSPEND_ACK", CC_SUSPEND_ACKNOWLEDGE},
-       {"SUSPEND_REJ", CC_SUSPEND_REJECT},
-       {"RESUME", CC_RESUME},
-       {"RESUME_ACK", CC_RESUME_ACKNOWLEDGE},
-       {"RESUME_REJ", CC_RESUME_REJECT},
-       {"HOLD", CC_HOLD},
-       {"HOLD_ACK", CC_HOLD_ACKNOWLEDGE},
-       {"HOLD_REJ", CC_HOLD_REJECT},
-       {"RETRIEVE", CC_RETRIEVE},
-       {"RETRIEVE_ACK", CC_RETRIEVE_ACKNOWLEDGE},
-       {"RETRIEVE_REJ", CC_RETRIEVE_REJECT},
-       {"FACILITY", CC_FACILITY},
-       {"STATUS", CC_STATUS},
-       {"RESTART", CC_RESTART},
-       {"RELEASE_CR", CC_RELEASE_CR},
-       {"NEW_CR", CC_NEW_CR},
-       {"DL_ESTABLISH", DL_ESTABLISH},
-       {"DL_RELEASE", DL_RELEASE},
-       {"PH_ACTIVATE", PH_ACTIVATE},
-       {"PH_DEACTIVATE", PH_DEACTIVATE},
+       {"PH_ACTIVATE", L1_ACTIVATE_REQ},
+       {"PH_DEACTIVATE", L1_DEACTIVATE_REQ},
+       {"DL_ESTABLISH", L2_ESTABLISH_REQ},
+       {"DL_RELEASE", L2_RELEASE_REQ},
+       {"UNKNOWN", L3_UNKNOWN},
+       {"MT_TIMEOUT", L3_TIMEOUT_REQ},
+       {"MT_SETUP", L3_SETUP_REQ},
+       {"MT_SETUP_ACK", L3_SETUP_ACKNOWLEDGE_REQ},
+       {"MT_PROCEEDING", L3_PROCEEDING_REQ},
+       {"MT_ALERTING", L3_ALERTING_REQ},
+       {"MT_CONNECT", L3_CONNECT_REQ},
+       {"MT_CONNECT_ACK", L3_CONNECT_ACKNOWLEDGE_REQ},
+       {"MT_DISCONNECT", L3_DISCONNECT_REQ},
+       {"MT_RELEASE", L3_RELEASE_REQ},
+       {"MT_RELEASE_COMP", L3_RELEASE_COMPLETE_REQ},
+       {"MT_INFORMATION", L3_INFORMATION_REQ},
+       {"MT_PROGRESS", L3_PROGRESS_REQ},
+       {"MT_NOTIFY", L3_NOTIFY_REQ},
+       {"MT_SUSPEND", L3_SUSPEND_REQ},
+       {"MT_SUSPEND_ACK", L3_SUSPEND_ACKNOWLEDGE_REQ},
+       {"MT_SUSPEND_REJ", L3_SUSPEND_REJECT_REQ},
+       {"MT_RESUME", L3_RESUME_REQ},
+       {"MT_RESUME_ACK", L3_RESUME_ACKNOWLEDGE_REQ},
+       {"MT_RESUME_REJ", L3_RESUME_REJECT_REQ},
+       {"MT_HOLD", L3_HOLD_REQ},
+       {"MT_HOLD_ACK", L3_HOLD_ACKNOWLEDGE_REQ},
+       {"MT_HOLD_REJ", L3_HOLD_REJECT_REQ},
+       {"MT_RETRIEVE", L3_RETRIEVE_REQ},
+       {"MT_RETRIEVE_ACK", L3_RETRIEVE_ACKNOWLEDGE_REQ},
+       {"MT_RETRIEVE_REJ", L3_RETRIEVE_REJECT_REQ},
+       {"MT_FACILITY", L3_FACILITY_REQ},
+       {"MT_STATUS", L3_STATUS_REQ},
+       {"MT_RESTART", L3_RESTART_REQ},
+#ifdef SOCKET_MISDN
+       {"MT_NEW_L3ID", L3_NEW_L3ID_REQ},
+       {"MT_RELEASE_L3ID", L3_RELEASE_L3ID_REQ},
+#else
+       {"MT_NEW_CR", L3_NEW_CR_REQ},
+       {"MT_RELEASE_CR", L3_RELEASE_CR_REQ},
+#endif
 
        {NULL, 0},
 };
@@ -296,7 +374,7 @@ static char *isdn_prim[4] = {
        " INDICATION",
        " RESPONSE",
 };
-void l1l2l3_trace_header(struct mISDNport *mISDNport, class PmISDN *port, unsigned long prim, int direction)
+void l1l2l3_trace_header(struct mISDNport *mISDNport, class PmISDN *port, unsigned long msg, int direction)
 {
        int i;
        char msgtext[64] = "<<UNKNOWN MESSAGE>>";
@@ -305,17 +383,21 @@ void l1l2l3_trace_header(struct mISDNport *mISDNport, class PmISDN *port, unsign
        i = 0;
        while(isdn_message[i].name)
        {
-               if (isdn_message[i].value == (prim&0xffffff00))
+               if (isdn_message[i].value == (msg&0xffffff00))
                {
                        SCPY(msgtext, isdn_message[i].name);
                        break;
                }
                i++;
        }
-       SCAT(msgtext, isdn_prim[prim&0x00000003]);
+       SCAT(msgtext, isdn_prim[msg&0x00000003]);
 
        /* add direction */
-       if (direction && (prim&0xffffff00)!=CC_NEW_CR && (prim&0xffffff00)!=CC_RELEASE_CR)
+#ifdef SOCKET_MISDN
+       if (direction && (msg&0xffffff00)!=L3_NEW_L3ID_REQ && (msg&0xffffff00)!=L3_RELEASE_L3ID_REQ)
+#else
+       if (direction && (msg&0xffffff00)!=L3_NEW_CR_REQ && (msg&0xffffff00)!=L3_RELEASE_CR_REQ)
+#endif
        {
                if (mISDNport)
                {
@@ -350,19 +432,34 @@ void l1l2l3_trace_header(struct mISDNport *mISDNport, class PmISDN *port, unsign
 /*
  * 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 = (unsigned long *)(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;
-       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);
+#endif
        chan_trace_header(mISDNport, isdnport, "BCHANNEL control", DIRECTION_OUT);
        if (c1 == CMX_CONF_JOIN)
                add_trace(trace_name, NULL, "0x%08x", trace_value);
@@ -371,19 +468,34 @@ void ph_control(struct mISDNport *mISDNport, class PmISDN *isdnport, unsigned lo
        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 = (unsigned long *)(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;
-       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);
+#endif
        chan_trace_header(mISDNport, isdnport, "BCHANNEL control", DIRECTION_OUT);
        add_trace(trace_name, NULL, "%d", trace_value);
        end_trace();
@@ -396,10 +508,58 @@ void ph_control_block(struct mISDNport *mISDNport, class PmISDN *isdnport, unsig
  */
 static int _bchannel_create(struct mISDNport *mISDNport, int i)
 {
+       int ret;
+#ifdef SOCKET_MISDN
+       unsigned long on = 1;
+       struct sockaddr_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] < 0)
+       {
+               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->portnum-1;
+       addr.channel = i+1+(i>=15);
+       ret = bind(mISDNport->b_socket[i], (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();
+
+       return(1);
+#else
        unsigned char buff[1024];
        layer_info_t li;
        mISDN_pid_t pid;
-       int ret;
 
        if (!mISDNport->b_stid[i])
        {
@@ -469,6 +629,7 @@ static int _bchannel_create(struct mISDNport *mISDNport, int i)
 failed:
        mISDNport->b_addr[i] = 0;
        return(0);
+#endif
 }
 
 
@@ -478,17 +639,32 @@ failed:
  */
 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 */
-       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();
        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);
+#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));
+       if (mISDNport->b_timer[i])
+               add_trace("event", NULL, "timeout recovery");
+       end_trace();
 }
 
 
@@ -499,10 +675,16 @@ static void _bchannel_activate(struct mISDNport *mISDNport, int i, int activate)
 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];
-       addr = mISDNport->b_addr[i];
        if (!port)
        {
                PERROR("bchannel index i=%d not associated with a port object\n", i);
@@ -510,28 +692,34 @@ static void _bchannel_configure(struct mISDNport *mISDNport, int i)
        }
 
        /* set dsp features */
+#ifndef OLD_MISDN
        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)
-               ph_control(mISDNport, port, addr, CMX_DELAY, port->p_m_delay, "DSP-DELAY", port->p_m_delay);
-       if (port->p_m_txvol)
-               ph_control(mISDNport, port, addr, VOL_CHANGE_TX, port->p_m_txvol, "DSP-TXVOL", port->p_m_txvol);
-       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, CMX_DELAY, port->p_m_delay, "DSP-DELAY", port->p_m_delay);
+#endif
+       if (port->p_m_tx_gain)
+               ph_control(mISDNport, port, handle, VOL_CHANGE_TX, port->p_m_tx_gain, "DSP-TX_GAIN", port->p_m_tx_gain);
+       if (port->p_m_rx_gain)
+               ph_control(mISDNport, port, handle, VOL_CHANGE_RX, port->p_m_rx_gain, "DSP-RX_GAIN", port->p_m_rx_gain);
+#ifndef OLD_MISDN
+       if (port->p_m_pipeline[0])
+               ph_control_block(mISDNport, port, handle, PIPELINE_CFG, port->p_m_pipeline, strlen(port->p_m_pipeline)+1, "DSP-PIPELINE", 0);
+#endif
        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)
-               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)
-               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)
-               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)
-//             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)
-               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)
-               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);
+               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);
 }
 
 /*
@@ -540,6 +728,17 @@ static void _bchannel_configure(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);
@@ -555,6 +754,7 @@ static void _bchannel_destroy(struct mISDNport *mISDNport, int i)
                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;
        }
+#endif
 }
 
 
@@ -623,18 +823,18 @@ 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.
 
-if an export request is receive by remote application, p_m_exportremote is set.
-the b_remotejoin[index] indicates if linked port shall be exported.
+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_exportremote)
+- 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_remotesocket[index] is set to the remote socket id.
-if importing has been acknowledged. b_remotesockt[index] is cleared.
+if exporting, b_remote_*[index] is set to the remote socket id.
+if importing has been acknowledged. b_remote_*[index] is cleared.
 
 */
 
@@ -649,14 +849,31 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
 {
        class PmISDN *b_port = mISDNport->b_port[i];
        int state = mISDNport->b_state[i];
+       double timer = mISDNport->b_timer[i];
        unsigned long p_m_remote_ref = 0;
        unsigned long p_m_remote_id = 0;
-       unsigned long addr = mISDNport->b_addr[i];
+       int p_m_tx_gain = 0;
+       int p_m_rx_gain = 0;
+       char *p_m_pipeline = NULL;
+       unsigned char *p_m_crypt_key = NULL;
+       int p_m_crypt_key_len = 0;
+       int p_m_crypt_key_type = 0;
+#ifdef SOCKET_MISDN
+       unsigned long portid = (mISDNport->portnum<<8) + i+1+(i>=15);
+#else
+       unsigned long portid = mISDNport->b_stid[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;
+               p_m_tx_gain = b_port->p_m_tx_gain;
+               p_m_rx_gain = b_port->p_m_rx_gain;
+               p_m_pipeline = b_port->p_m_pipeline;
+               p_m_crypt_key = b_port->p_m_crypt_key;
+               p_m_crypt_key_len = b_port->p_m_crypt_key_len;
+               p_m_crypt_key_type = /*b_port->p_m_crypt_key_type*/1;
        }
 
        switch(event)
@@ -668,16 +885,21 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
                switch(state)
                {
                        case B_STATE_IDLE:
-                       if (p_m_remote_id)
+                       if (p_m_remote_ref)
                        {
                                /* export bchannel */
-                               message_bchannel_to_join(p_m_remote_id, p_m_remote_ref, BCHANNEL_ASSIGN, addr);
+                               message_bchannel_to_join(p_m_remote_id, p_m_remote_ref, BCHANNEL_ASSIGN, portid, p_m_tx_gain, p_m_rx_gain, p_m_pipeline, p_m_crypt_key, p_m_crypt_key_len, p_m_crypt_key_type);
                                chan_trace_header(mISDNport, b_port, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
                                add_trace("type", NULL, "assign");
-                               add_trace("stack", "address", "%x", addr);
+#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
                        {
                                /* create stack and send activation request */
@@ -685,6 +907,7 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
                                {
                                        _bchannel_activate(mISDNport, i, 1);
                                        state = B_STATE_ACTIVATING;
+                                       timer = now_d + B_TIMER_ACTIVATING;
                                }
                        }
                        break;
@@ -710,7 +933,7 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
 
                case B_EVENT_EXPORTREQUEST:
                /* special case where the bchannel is requested by remote */
-               if (!p_m_remote_id)
+               if (!p_m_remote_ref)
                {
                        PERROR("export request without remote channel set, please correct.\n");
                        break;
@@ -721,13 +944,18 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
                        /* 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, addr);
+                       message_bchannel_to_join(p_m_remote_id, p_m_remote_ref, BCHANNEL_ASSIGN, portid, p_m_tx_gain, p_m_rx_gain, p_m_pipeline, p_m_crypt_key, p_m_crypt_key_len, p_m_crypt_key_type);
                        chan_trace_header(mISDNport, b_port, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
                        add_trace("type", NULL, "assign");
-                       add_trace("stack", "address", "%x", addr);
+#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:
@@ -744,6 +972,7 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
                        /* bchannel is active, so we deactivate */
                        _bchannel_activate(mISDNport, i, 0);
                        state = B_STATE_DEACTIVATING;
+                       timer = now_d + B_TIMER_DEACTIVATING;
                        break;
 
                        default:
@@ -756,6 +985,7 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
                break;
 
                case B_EVENT_ACTIVATED:
+               timer = 0;
                switch(state)
                {
                        case B_STATE_ACTIVATING:
@@ -769,6 +999,7 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
                                /* 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;
+                               timer = now_d + B_TIMER_DEACTIVATING;
                        }
                        break;
 
@@ -781,17 +1012,24 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
                switch(state)
                {
                        case B_STATE_EXPORTING:
-                       if (b_port && p_m_remote_id)
+                       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, so reimport, to later export to new remote */
-                               message_bchannel_to_join(mISDNport->b_remote_id[i], 0, BCHANNEL_REMOVE, addr);
+                               /* 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, 0,0,0,0,0,0);
                                chan_trace_header(mISDNport, b_port, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
                                add_trace("type", NULL, "remove");
-                               add_trace("stack", "address", "%x", addr);
+#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;
                        }
@@ -820,14 +1058,19 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
                        /* bchannel is active, so we deactivate */
                        _bchannel_activate(mISDNport, i, 0);
                        state = B_STATE_DEACTIVATING;
+                       timer = now_d + B_TIMER_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, addr);
+                       message_bchannel_to_join(mISDNport->b_remote_id[i], 0, BCHANNEL_REMOVE, portid, 0,0,0,0,0,0);
                        chan_trace_header(mISDNport, b_port, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
                        add_trace("type", NULL, "remove");
-                       add_trace("stack", "address", "%x", addr);
+#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;
@@ -843,6 +1086,7 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
                break;
 
                case B_EVENT_DEACTIVATED:
+               timer = 0;
                switch(state)
                {
                        case B_STATE_IDLE:
@@ -855,21 +1099,27 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
                        if (b_port)
                        {
                                /* bchannel is now deactivate, but is requied by Port class, so we reactivate / export */
-                               if (p_m_remote_id)
+                               if (p_m_remote_ref)
                                {
-                                       message_bchannel_to_join(p_m_remote_id, p_m_remote_ref, BCHANNEL_ASSIGN, addr);
+                                       message_bchannel_to_join(p_m_remote_id, p_m_remote_ref, BCHANNEL_ASSIGN, portid, p_m_tx_gain, p_m_rx_gain, p_m_pipeline, p_m_crypt_key, p_m_crypt_key_len, p_m_crypt_key_type);
                                        chan_trace_header(mISDNport, b_port, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
                                        add_trace("type", NULL, "assign");
-                                       add_trace("stack", "address", "%x", addr);
+#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;
+                                               timer = now_d + B_TIMER_ACTIVATING;
                                        }
                                }
                        }
@@ -886,24 +1136,31 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
                        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_id)
+                               if (p_m_remote_ref)
                                {
-                                       message_bchannel_to_join(p_m_remote_id, p_m_remote_ref, BCHANNEL_ASSIGN, addr);
+                                       message_bchannel_to_join(p_m_remote_id, p_m_remote_ref, BCHANNEL_ASSIGN, portid, p_m_tx_gain, p_m_rx_gain, p_m_pipeline, p_m_crypt_key, p_m_crypt_key_len, p_m_crypt_key_type);
                                        chan_trace_header(mISDNport, b_port, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
                                        add_trace("type", NULL, "assign");
-                                       add_trace("stack", "address", "%x", addr);
+#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;
+                                               timer = now_d + B_TIMER_ACTIVATING;
                                        }
                                }
                        }
@@ -915,11 +1172,35 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
                }
                break;
 
+               case B_EVENT_TIMEOUT:
+               timer = 0;
+               switch(state)
+               {
+                       case B_STATE_IDLE:
+                       /* ignore due to deactivation confirm after unloading */
+                       break;
+
+                       case B_STATE_ACTIVATING:
+                       _bchannel_activate(mISDNport, i, 1);
+                       timer = now_d + B_TIMER_ACTIVATING;
+                       break;
+
+                       case B_STATE_DEACTIVATING:
+                       _bchannel_activate(mISDNport, i, 0);
+                       timer = now_d + B_TIMER_DEACTIVATING;
+                       break;
+
+                       default:
+                       PERROR("Illegal event %d at state %d, please correct.\n", event, state);
+               }
+               break;
+
                default:
                PERROR("Illegal event %d, please correct.\n", event);
        }
 
        mISDNport->b_state[i] = state;
+       mISDNport->b_timer[i] = timer;
 }
 
 
@@ -1009,15 +1290,14 @@ seize:
  */
 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 */
+       if (p_m_b_index < 0)
+               return;
        if (!p_m_b_channel)
                return;
 
@@ -1032,7 +1312,7 @@ void PmISDN::drop_bchannel(void)
 }
 
 /* process bchannel export/import message from join */
-void message_bchannel_from_join(class JoinRemote *joinremote, int type, unsigned long addr)
+void message_bchannel_from_join(class JoinRemote *joinremote, int type, unsigned long handle)
 {
        class Endpoint *epoint;
        class Port *port;
@@ -1098,7 +1378,11 @@ void message_bchannel_from_join(class JoinRemote *joinremote, int type, unsigned
                        ii = mISDNport->b_num;
                        while(i < ii)
                        {
-                               if (mISDNport->b_addr[i] == addr)
+#ifdef SOCKET_MISDN
+                               if ((unsigned long)(mISDNport->portnum<<8)+i+1+(i>=15) == handle)
+#else
+                               if (mISDNport->b_addr[i] == handle)
+#endif
                                        break;
                                i++;
                        }
@@ -1108,7 +1392,7 @@ void message_bchannel_from_join(class JoinRemote *joinremote, int type, unsigned
                }
                if (!mISDNport)
                {
-                       PERROR("received assign/remove ack for addr=%x, but address does not exist.\n", addr);
+                       PERROR("received assign/remove ack for bchannel's handle=%x, but handle does not exist in any mISDNport structure.\n", handle);
                        break;
                }
                /* mISDNport may now be set or NULL */
@@ -1215,12 +1499,20 @@ int PmISDN::handler(void)
                        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)
+               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 char *p = 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)
@@ -1242,6 +1534,7 @@ int PmISDN::handler(void)
                                        /* next loop */
                                        p_m_crypt_msg_current = 0;
                                        p_m_crypt_msg_loops--;
+//                                     puts("eine loop weniger");
                                }
 
                                /* new length */
@@ -1255,13 +1548,21 @@ int PmISDN::handler(void)
                        }
 
                        /* send data */
+#ifdef SOCKET_MISDN
+                       frm->prim = DL_DATA_REQ;
+                       frm->id = 0;
+                       ret = sendto(p_m_mISDNport->b_socket[p_m_b_index], buf, MISDN_HEADER_LEN+ISDN_LOAD-p_m_load-tosend, 0, NULL, 0);
+                       if (!ret)
+                               PERROR("Failed to send to socket %d\n", p_m_mISDNport->b_socket[p_m_b_index]);
+#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 = ISDN_LOAD - p_m_load - tosend;
                        if (frm->len)
                                mISDN_write(mISDNdevice, frm, mISDN_HEADER_LEN+frm->len, TIMEOUT_1SEC);
-                       p_m_load += frm->len;
+#endif
+                       p_m_load += ISDN_LOAD - p_m_load - tosend;
                }
        }
 
@@ -1289,23 +1590,34 @@ int PmISDN::handler(void)
 /*
  * whenever we get audio data from bchannel, we process it here
  */
+#ifdef SOCKET_MISDN
+void PmISDN::bchannel_receive(struct mISDNhead *hh, unsigned char *data, int len)
+{
+       unsigned long cont = *((unsigned long *)data);
+#else
 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 long cont;
 
+#ifdef SOCKET_MISDN
+       if (hh->prim == PH_CONTROL_IND)
+#else
        if (frm->prim == (PH_CONTROL | INDICATION))
+#endif
        {
-               if (frm->len < 4)
+               if (len < 4)
                {
                        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);
@@ -1339,6 +1651,25 @@ void PmISDN::bchannel_receive(iframe_t *frm)
                        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_CONTROL_IND)
+       {
+               switch(hh->id)
+#else
+       if (frm->prim == (PH_SIGNAL | INDICATION)
+        || frm->prim == (PH_CONTROL | INDICATION))
+       {
+               switch(frm->dinfo)
+#endif
+               {
+#ifndef OLD_MISDN
                        case CMX_TX_DATA:
                        if (!p_m_txdata)
                        {
@@ -1346,30 +1677,45 @@ void PmISDN::bchannel_receive(iframe_t *frm)
                                PDEBUG(DEBUG_BCHANNEL, "PmISDN(%s) ignoring tx data, because 'txdata' is turned off\n", p_name);
                                return;
                        }
+                       /* see below (same condition) */
+                       if (p_state!=PORT_STATE_CONNECT
+                                && !p_m_mISDNport->tones)
+                               break;
+//                     printf(".");fflush(stdout);return;
                        if (p_record)
-                               record((unsigned char *)(cont+1), frm->len - 4, 1); // from up
+                               record(data, len, 1); // from up
                        break;
+#endif
 
                        default:
                        chan_trace_header(p_m_mISDNport, this, "BCHANNEL control", DIRECTION_IN);
-                       add_trace("unknown", NULL, "0x%x", cont);
+#ifdef SOCKET_MISDN
+                       add_trace("unknown", NULL, "0x%x", hh->id);
+#else
+                       add_trace("unknown", NULL, "0x%x", frm->dinfo);
+#endif
                        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);
+#endif
                return;
        }
-
        /* calls will not process any audio data unless
         * the call is connected OR interface features audio during call setup.
         */
 //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
-        && !p_m_mISDNport->earlyb)
+        && !p_m_mISDNport->tones)
                return;
 #endif
 
@@ -1382,26 +1728,26 @@ void PmISDN::bchannel_receive(iframe_t *frm)
 
        /* 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 */
-               p = (unsigned char *)&frm->data.p;
-               l = frm->len;
+               p = data;
+               l = len;
                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 */
        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)
                {
@@ -1429,7 +1775,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)
+#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);
+#endif
        }
 }
 
@@ -1454,10 +1804,15 @@ void PmISDN::set_tone(char *dir, char *tone)
        {
                nodsp:
                if (p_m_tone)
+               if (p_m_b_index > -1)
                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);
+#endif
                }
                p_m_tone = 0;
                Port::set_tone(dir, tone);
@@ -1537,9 +1892,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);
-               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 > -1)
+               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);
@@ -1553,24 +1912,32 @@ void PmISDN::message_mISDNsignal(unsigned long epoint_id, int message_id, union
        switch(param->mISDNsignal.message)
        {
                case mISDNSIGNAL_VOLUME:
-               if (p_m_txvol != param->mISDNsignal.txvol)
+               if (p_m_tx_gain != param->mISDNsignal.tx_gain)
                {
-                       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);
+                       p_m_tx_gain = param->mISDNsignal.tx_gain;
+                       PDEBUG(DEBUG_BCHANNEL, "we change tx-volume to shift=%d.\n", p_m_tx_gain);
+                       if (p_m_b_index > -1)
+                       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_tx_gain, "DSP-TX_GAIN", p_m_tx_gain);
+#else
+                               ph_control(p_m_mISDNport, this, p_m_mISDNport->b_addr[p_m_b_index], VOL_CHANGE_TX, p_m_tx_gain, "DSP-TX_GAIN", p_m_tx_gain);
+#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);
-                       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);
+                       PDEBUG(DEBUG_BCHANNEL, "we already have tx-volume shift=%d.\n", p_m_rx_gain);
+               if (p_m_rx_gain != param->mISDNsignal.rx_gain)
+               {
+                       p_m_rx_gain = param->mISDNsignal.rx_gain;
+                       PDEBUG(DEBUG_BCHANNEL, "we change rx-volume to shift=%d.\n", p_m_rx_gain);
+                       if (p_m_b_index > -1)
+                       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_rx_gain, "DSP-RX_GAIN", p_m_rx_gain);
+#else
+                               ph_control(p_m_mISDNport, this, p_m_mISDNport->b_addr[p_m_b_index], VOL_CHANGE_RX, p_m_rx_gain, "DSP-RX_GAIN", p_m_rx_gain);
+#endif
                } else
-                       PDEBUG(DEBUG_BCHANNEL, "we already have rx-volume shift=%d.\n", p_m_rxvol);
+                       PDEBUG(DEBUG_BCHANNEL, "we already have rx-volume shift=%d.\n", p_m_rx_gain);
                break;
 
                case mISDNSIGNAL_CONF:
@@ -1580,9 +1947,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);
-                       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 > -1)
+                       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 */
@@ -1604,9 +1975,15 @@ 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);
-                       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);
+#ifndef OLD_MISDN
+                       if (p_m_b_index > -1)
+                       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
+#endif
                } else
                        PDEBUG(DEBUG_BCHANNEL, "we already have delay=%d.\n", p_m_delay);
                break;
@@ -1637,9 +2014,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);
-               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 > -1)
+               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 */
@@ -1664,13 +2045,17 @@ void PmISDN::message_crypt(unsigned long epoint_id, int message_id, union parame
                        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 (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);
+#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);
+#endif
                }
 #endif
                break;
@@ -1711,29 +2096,33 @@ 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;
-       msg_t *msg;
-       iframe_t *frm;
+       int ret, work = 0;
        struct mISDNport *mISDNport;
        class PmISDN *isdnport;
-       net_stack_t *nst;
-       msg_t *dmsg;
-       mISDNuser_head_t *hh;
        int i;
+       unsigned char buffer[2048+MISDN_HEADER_LEN];
+       struct mISDNhead *hh = (struct mISDNhead *)buffer;
 
-       /* the que avoids loopbacks when replying to stack after receiving
-         * from stack. */
+       /* process all ports */
        mISDNport = mISDNport_first;
        while(mISDNport)
        {
-               /* process turning on/off rx */
+               /* process all bchannels */
                i = 0;
                while(i < mISDNport->b_num)
                {
+                       /* process timer events for bchannel handling */
+                       if (mISDNport->b_timer[i])
+                       {
+                               if (mISDNport->b_timer[i] <= now_d)
+                                       bchannel_event(mISDNport, i, B_EVENT_TIMEOUT);
+                       }
+                       /* handle port of bchannel */
                        isdnport=mISDNport->b_port[i];
                        if (isdnport)
                        {
@@ -1747,7 +2136,7 @@ int mISDN_handler(void)
                                                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_addr[isdnport->p_m_b_index], CMX_RECEIVE_ON, 0, "DSP-RXOFF", 0);
+                                                       ph_control(mISDNport, isdnport, mISDNport->b_socket[isdnport->p_m_b_index], CMX_RECEIVE_ON, 0, "DSP-RXOFF", 0);
                                                return(1);
                                        }
                                } else
@@ -1759,7 +2148,7 @@ int mISDN_handler(void)
                                                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_addr[isdnport->p_m_b_index], CMX_RECEIVE_OFF, 0, "DSP-RXOFF", 1);
+                                                       ph_control(mISDNport, isdnport, mISDNport->b_socket[isdnport->p_m_b_index], CMX_RECEIVE_OFF, 0, "DSP-RXOFF", 1);
                                                return(1);
                                        }
                                }
@@ -1773,7 +2162,7 @@ int mISDN_handler(void)
                                                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_addr[isdnport->p_m_b_index], CMX_TXDATA_ON, 0, "DSP-TXDATA", 1);
+                                                       ph_control(mISDNport, isdnport, mISDNport->b_socket[isdnport->p_m_b_index], CMX_TXDATA_ON, 0, "DSP-TXDATA", 1);
                                                return(1);
                                        }
                                } else
@@ -1785,16 +2174,185 @@ int mISDN_handler(void)
                                                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_addr[isdnport->p_m_b_index], CMX_TXDATA_OFF, 0, "DSP-TXDATA", 0);
+                                                       ph_control(mISDNport, isdnport, mISDNport->b_socket[isdnport->p_m_b_index], CMX_TXDATA_OFF, 0, "DSP-TXDATA", 0);
                                                return(1);
                                        }
                                }
                        }
-                       i++;
-               }
-#if 0
+
+                       /* handle message from bchannel */
+                       if (mISDNport->b_socket[i] > -1)
+                       {
+                               ret = recv(mISDNport->b_socket[i], buffer, sizeof(buffer), 0);
+                               if (ret >= (int)MISDN_HEADER_LEN)
+                               {
+                                       work = 1;
+                                       switch(hh->prim)
+                                       {
+                                               /* we don't care about confirms, we use rx data to sync tx */
+                                               case PH_DATA_CNF:
+                                               break;
+
+                                               /* we receive audio data, we respond to it AND we send tones */
+                                               case PH_DATA_IND:
+                                               case DL_DATA_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_socket[i]);
+                                               break;
+
+                                               case PH_ACTIVATE_IND:
+                                               case DL_ESTABLISH_IND:
+                                               case PH_ACTIVATE_CNF:
+                                               case DL_ESTABLISH_CNF:
+                                               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_CNF:
+                                               case DL_RELEASE_CNF:
+                                               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], ret-MISDN_HEADER_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);
+#warning SOCKET TBD
+//                             mISDNport->ml3->to_layer2(mISDNport->ml3, DL_ESTABLISH_REQ);
+//                             l1l2l3_trace_header(mISDNport, NULL, L2_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;
+       struct mISDNport *mISDNport;
+       class PmISDN *isdnport;
+       int i;
+       msg_t *msg;
+       iframe_t *frm;
+       msg_t *dmsg;
+       mISDNuser_head_t *hh;
+       net_stack_t *nst;
+
+       /* the que avoids loopbacks when replying to stack after receiving
+         * from stack. */
+       mISDNport = mISDNport_first;
+       while(mISDNport)
+       {
+               /* process turning on/off rx */
+               i = 0;
+               while(i < mISDNport->b_num)
+               {
+                       /* process timer events for bchannel handling */
+                       if (mISDNport->b_timer[i])
+                       {
+                               if (mISDNport->b_timer[i] <= now_d)
+                                       bchannel_event(mISDNport, i, B_EVENT_TIMEOUT);
+                       }
+                       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_addr[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_addr[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");
+#ifndef OLD_MISDN
+                                               if (mISDNport->b_port[i] && mISDNport->b_state[i] == B_STATE_ACTIVE)
+                                                       ph_control(mISDNport, isdnport, mISDNport->b_addr[isdnport->p_m_b_index], CMX_TXDATA_ON, 0, "DSP-TXDATA", 1);
+#endif
+                                               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");
+#ifndef OLD_MISDN
+                                               if (mISDNport->b_port[i] && mISDNport->b_state[i] == B_STATE_ACTIVE)
+                                                       ph_control(mISDNport, isdnport, mISDNport->b_addr[isdnport->p_m_b_index], CMX_TXDATA_OFF, 0, "DSP-TXDATA", 0);
+#endif
+                                               return(1);
+                                       }
+                               }
+                       }
+                       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
@@ -1812,17 +2370,18 @@ int mISDN_handler(void)
                                        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 */
-                                       iframe_t act;
                                        act.prim = DL_ESTABLISH | REQUEST; 
                                        act.addr = (mISDNport->upper_id & ~LAYER_ID_MASK) | 3 | FLG_MSG_DOWN;
                                        act.dinfo = 0;
                                        act.len = 0;
                                        mISDN_write(mISDNdevice, &act, mISDN_HEADER_LEN+act.len, TIMEOUT_1SEC);
                                }
-                               l1l2l3_trace_header(mISDNport, NULL, DL_ESTABLISH | REQUEST, DIRECTION_OUT);
+                               l1l2l3_trace_header(mISDNport, NULL, L2_ESTABLISH_REQ, DIRECTION_OUT);
                                end_trace();
                                return(1);
                        }
@@ -1937,6 +2496,15 @@ int mISDN_handler(void)
        if (!mISDNport)
        {
                PERROR("message belongs to no mISDNport: prim(0x%x) addr(0x%x) msg->len(%d)\n", frm->prim, frm->addr, msg->len);
+               // show a list of all mISDNports and their address
+#if 0
+               mISDNport = mISDNport_first;
+               while(mISDNport)
+               {
+                       PERROR(" port %s  %x -> %x\n", mISDNport->name, (frm->addr&MASTER_ID_MASK), (unsigned int)(mISDNport->upper_id&MASTER_ID_MASK));
+                       mISDNport = mISDNport->next;
+               } 
+#endif
                goto out;
        }
 
@@ -1950,19 +2518,19 @@ int mISDN_handler(void)
                        case MGR_SHORTSTATUS | CONFIRM:
                        switch(frm->dinfo) {
                                case SSTATUS_L1_ACTIVATED:
-                               l1l2l3_trace_header(mISDNport, NULL, PH_ACTIVATE | (frm->prim & 0x3), DIRECTION_IN);
+                               l1l2l3_trace_header(mISDNport, NULL, L1_ACTIVATE_REQ | (frm->prim & 0x3), DIRECTION_IN);
                                end_trace();
                                goto ss_act;
                                case SSTATUS_L1_DEACTIVATED:
-                               l1l2l3_trace_header(mISDNport, NULL, PH_DEACTIVATE | (frm->prim & 0x3), DIRECTION_IN);
+                               l1l2l3_trace_header(mISDNport, NULL, L1_DEACTIVATE_REQ | (frm->prim & 0x3), DIRECTION_IN);
                                end_trace();
                                goto ss_deact;
                                case SSTATUS_L2_ESTABLISHED:
-                               l1l2l3_trace_header(mISDNport, NULL, DL_ESTABLISH | (frm->prim & 0x3), DIRECTION_IN);
+                               l1l2l3_trace_header(mISDNport, NULL, L2_ESTABLISH_REQ | (frm->prim & 0x3), DIRECTION_IN);
                                end_trace();
                                goto ss_estab;
                                case SSTATUS_L2_RELEASED:
-                               l1l2l3_trace_header(mISDNport, NULL, DL_RELEASE | (frm->prim & 0x3), DIRECTION_IN);
+                               l1l2l3_trace_header(mISDNport, NULL, L2_RELEASE_REQ | (frm->prim & 0x3), DIRECTION_IN);
                                end_trace();
                                goto ss_rel;
                        }
@@ -1970,7 +2538,7 @@ int mISDN_handler(void)
 
                        case PH_ACTIVATE | CONFIRM:
                        case PH_ACTIVATE | INDICATION:
-                       l1l2l3_trace_header(mISDNport, NULL, frm->prim, DIRECTION_IN);
+                       l1l2l3_trace_header(mISDNport, NULL, L1_ACTIVATE_REQ | (frm->prim & 0x3), DIRECTION_IN);
                        end_trace();
                        if (mISDNport->ntmode)
                        {
@@ -1985,7 +2553,7 @@ int mISDN_handler(void)
 
                        case PH_DEACTIVATE | CONFIRM:
                        case PH_DEACTIVATE | INDICATION:
-                       l1l2l3_trace_header(mISDNport, NULL, frm->prim, DIRECTION_IN);
+                       l1l2l3_trace_header(mISDNport, NULL, L1_DEACTIVATE_REQ | (frm->prim & 0x3), DIRECTION_IN);
                        end_trace();
                        if (mISDNport->ntmode)
                        {
@@ -2005,7 +2573,7 @@ int mISDN_handler(void)
 
                        case DL_ESTABLISH | INDICATION:
                        case DL_ESTABLISH | CONFIRM:
-                       l1l2l3_trace_header(mISDNport, NULL, frm->prim, DIRECTION_IN);
+                       l1l2l3_trace_header(mISDNport, NULL, DL_ESTABLISH_REQ | (frm->prim & 0x3), DIRECTION_IN);
                        end_trace();
                        if (!mISDNport->ntmode) break; /* !!!!!!!!!!!!!!!! */
                        ss_estab:
@@ -2019,7 +2587,7 @@ int mISDN_handler(void)
 
                        case DL_RELEASE | INDICATION:
                        case DL_RELEASE | CONFIRM:
-                       l1l2l3_trace_header(mISDNport, NULL, frm->prim, DIRECTION_IN);
+                       l1l2l3_trace_header(mISDNport, NULL, DL_RELEASE_REQ | (frm->prim & 0x3), DIRECTION_IN);
                        end_trace();
                        if (!mISDNport->ntmode) break; /* !!!!!!!!!!!!!!!! */
                        ss_rel:
@@ -2069,6 +2637,7 @@ int mISDN_handler(void)
                        case PH_DATA | INDICATION:
                        case DL_DATA | INDICATION:
                        case PH_CONTROL | INDICATION:
+                       case PH_SIGNAL | INDICATION:
                        i = 0;
                        while(i < mISDNport->b_num)
                        {
@@ -2138,32 +2707,168 @@ int mISDN_handler(void)
        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)
+{
+       /* IMPORTAINT:
+        *
+        * l3m must be freed, except for MT_ASSIGN
+        *
+        */
+       struct mISDNport *mISDNport = (struct mISDNport *)ml3->priv;
+
+       /* special MT_ASSIGN handling:
+        *
+        * if we request a PID from mlayer, we always do it while lcr is locked.
+        * therefore we must check the MT_ASSIGN reply first before we lock.
+        * this is because the MT_ASSIGN reply is received with the requesting
+        * process, not by the mlayer thread!
+        * this means, that the reply is sent during call of the request.
+        * we must check if we get a reply and we know that we lcr is currently
+        * locked.
+        */
+       if (cmd == MT_ASSIGN)
+       {
+               /* let's do some checking if someone changes stack behaviour */
+               if (mt_assign_pid != 0)
+                       FATAL("someone played with the mISDNuser stack. MT_ASSIGN not currently expected.\n");
+               if ((pid >> 16) != MISDN_CES_MASTER)
+                       FATAL("someone played with the mISDNuser stack. MT_ASSIGN is expected with master CES.\n");
+               mt_assign_pid = pid;
+               return(0);
+       }
+       
+       /* lock LCR */
+       pthread_mutex_lock(&mutex_lcr);
+
+       /* d-message */
+       switch(cmd)
+       {
+#warning SOCKET TBD
+#if 0
+               case MGR_SHORTSTATUS_IND:
+               case MGR_SHORTSTATUS_CNF:
+               switch(frm->dinfo) {
+                       case SSTATUS_L1_ACTIVATED:
+                       l1l2l3_trace_header(mISDNport, NULL, L1_ACTIVATE_IND, DIRECTION_IN);
+                       end_trace();
+                       goto ss_act;
+                       case SSTATUS_L1_DEACTIVATED:
+                       l1l2l3_trace_header(mISDNport, NULL, L1_DEACTIVATE_IND, DIRECTION_IN);
+                       end_trace();
+                       goto ss_deact;
+                       case SSTATUS_L2_ESTABLISHED:
+                       l1l2l3_trace_header(mISDNport, NULL, L2_ESTABLISH_IND, DIRECTION_IN);
+                       end_trace();
+                       goto ss_estab;
+                       case SSTATUS_L2_RELEASED:
+                       l1l2l3_trace_header(mISDNport, NULL, L2_RELEASE_IND, DIRECTION_IN);
+                       end_trace();
+                       goto ss_rel;
+               }
+               break;
+#endif
+
+#warning SOCKET TBD
+#if 0
+               case MT_L1ACTIVATE:
+               l1l2l3_trace_header(mISDNport, NULL, L1_ACTIVATE_IND, DIRECTION_IN);
+               end_trace();
+//             ss_act:
+               mISDNport->l1link = 1;
+               break;
+
+               case MT_L1DEACTIVATE:
+               l1l2l3_trace_header(mISDNport, NULL, L1_DEACTIVATE_IND, DIRECTION_IN);
+               end_trace();
+//             ss_deact:
+               mISDNport->l1link = 0;
+               break;
+
+               case MT_L1CONTROL:
+               PDEBUG(DEBUG_ISDN, "Received PH_CONTROL for port %d (%s).\n", mISDNport->portnum, mISDNport->ifport->interface->name);
+               // special config commands for interface (ip-address/LOS/AIS/RDI/SLIP)
+               break;
+#endif
+
+               case MT_L2ESTABLISH:
+               l1l2l3_trace_header(mISDNport, NULL, L2_ESTABLISH_IND, DIRECTION_IN);
+               end_trace();
+//             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 MT_L2RELEASE:
+               l1l2l3_trace_header(mISDNport, NULL, L2_RELEASE_IND, 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 */
+               stack2manager(mISDNport, cmd, pid, l3m);
+       }
+
+       /* free message */
+       if (l3m)
+               free_l3_msg(l3m);
+
+       /* unlock LCR */
+       pthread_mutex_unlock(&mutex_lcr);
+
+       return(0);
+
+}
+#endif
 
 
 /*
  * 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;
        struct mISDNport *mISDNport, **mISDNportp;
        int i, cnt;
-       int pri = 0;
-       int nt = 0;
+       int pri, bri, pots;
+       int nt, te;
 #ifdef SOCKET_MISDN
-//     struct mlayer3 *layer3;
+//     struct mlayer3 *ml3;
+       struct mISDN_devinfo devinfo;
+       unsigned int protocol, prop;
+
+       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
+       unsigned char buff[1025];
+       iframe_t *frm = (iframe_t *)buff;
 //     interface_info_t ii;
        net_stack_t *nst;
        manager_t *mgr;
        layer_info_t li;
        stack_info_t *stinf;
-#endif
 
        /* query port's requirements */
        cnt = mISDN_get_stack_count(mISDNdevice);
+#endif
+
        if (cnt <= 0)
        {
                PERROR_RUNTIME("Found no card. Please be sure to load card drivers.\n");
@@ -2174,6 +2879,87 @@ struct mISDNport *mISDNport_open(int port, int ptp, int ptmp, struct interface *
                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 = pots = nt = te = 0;
+#ifdef SOCKET_MISDN
+       devinfo.id = port - 1;
+       ret = ioctl(mISDNsocket, IMGETDEVINFO, &devinfo);
+       if (ret <= 0)
+       {
+               PERROR_RUNTIME("Cannot get device information for port %d. (ioctl IMGETDEVINFO failed ret=%d)\n", i, ret);
+               return(NULL);
+       }
+       /* 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);
+       }
+       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)
        {
@@ -2216,7 +3002,8 @@ struct mISDNport *mISDNport_open(int port, int ptp, int ptmp, struct interface *
                        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);
                }
-       } else
+       }
+       if (te)
        {
                /* TE */
                if (stinf->pid.protocol[1] == 0)
@@ -2251,6 +3038,7 @@ struct mISDNport *mISDNport_open(int port, int ptp, int ptmp, struct interface *
                        return(NULL);
                }
        }
+#endif
 
        /* add mISDNport structure */
        mISDNportp = &mISDNport_first;
@@ -2263,20 +3051,25 @@ struct mISDNport *mISDNport_open(int port, int ptp, int ptmp, struct interface *
        /* allocate ressources of port */
 #ifdef SOCKET_MISDN
        /* open layer 3 */
-       protocol = (nt)?L3_PROTOCOL_DSS1_USER:L3_PROTOCOL_DSS1_NETWORK;
+       protocol = (nt)?L3_PROTOCOL_DSS1_USER:L3_PROTOCOL_DSS1_NET;
        prop = 0;
-       if (ptp)
-              prop |= FLG_PTP;
-       if (ptp)
+       if (ptp) // ptp forced
+              prop |= MISDN_FLG_PTP;
+#warning SOCKET TBD
+#if 0
+       if (ptmp && pri) // ptmp forced
               prop |= FLG_FORCE_PTMP;
-       mISDNport->layer3 = open_layer3(port-1, protocol, prop , do_dchannel, mISDNport);
-       if (!mISDNport->layer3)
+#endif
+       if (nt) // supports hold/retrieve on nt-mode
+              prop |= MISDN_FLG_NET_HOLD;
+       mISDNport->ml3 = open_layer3(port-1, protocol, prop , do_layer3, mISDNport);
+       if (!mISDNport->ml3)
        {
                PERROR_RUNTIME("Cannot get layer(%d) id of port %d\n", nt?2:4, port);
                return(NULL);
        }
 
-#warning KKEIL: braucht man das noch?
+#if 0
        /* if ntmode, establish L1 to send the tei removal during start */
        if (mISDNport->ntmode)
        {
@@ -2290,7 +3083,10 @@ struct mISDNport *mISDNport_open(int port, int ptp, int ptmp, struct interface *
                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);
        mISDNport->d_stid = stinf->id;
@@ -2394,23 +3190,37 @@ struct mISDNport *mISDNport_open(int port, int ptp, int ptmp, struct interface *
                Isdnl3Init(nst);
        }
 
+       mISDNport->b_num = stinf->childcnt;
 #endif
-//     SCPY(mISDNport->name, "noname");
        mISDNport->portnum = port;
        mISDNport->ntmode = nt;
        mISDNport->pri = pri;
        mISDNport->ptp = ptp;
-       mISDNport->b_num = stinf->childcnt;
        PDEBUG(DEBUG_ISDN, "Port has %d b-channels.\n", mISDNport->b_num);
        i = 0;
-       while(i < stinf->childcnt)
+       while(i < mISDNport->b_num)
        {
-               mISDNport->b_stid[i] = stinf->child[i];
                mISDNport->b_state[i] = B_STATE_IDLE;
+#ifdef SOCKET_MISDN
+               mISDNport->b_socket[i] = -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++;
        }
 
+#ifdef SOCKET_MISDN
+       /* if ptp, pull up the link */
+       if (mISDNport->ptp)
+       {
+#warning SOCKET TBD
+//             mISDNport->ml3->to_layer2(mISDNport->ml3, DL_ESTABLISH_REQ);
+//             l1l2l3_trace_header(mISDNport, NULL, L2_ESTABLISH_REQ, DIRECTION_OUT);
+//             end_trace();
+               time(&mISDNport->l2establish);
+       }
+#else
        /* if te-mode, query state link */
        if (!mISDNport->ntmode)
        {
@@ -2422,6 +3232,7 @@ struct mISDNport *mISDNport_open(int port, int ptp, int ptmp, struct interface *
                act.dinfo = SSTATUS_BROADCAST_BIT | SSTATUS_ALL;
                act.len = 0;
                mISDN_write(mISDNdevice, &act, mISDN_HEADER_LEN+act.len, TIMEOUT_1SEC);
+               time(&mISDNport->l2establish);
        }
        /* if ptp AND te-mode, pull up the link */
        if (mISDNport->ptp && !mISDNport->ntmode)
@@ -2433,6 +3244,10 @@ struct mISDNport *mISDNport_open(int port, int ptp, int ptmp, struct interface *
                act.dinfo = 0;
                act.len = 0;
                mISDN_write(mISDNdevice, &act, mISDN_HEADER_LEN+act.len, TIMEOUT_1SEC);
+               time(&mISDNport->l2establish);
+
+               l1l2l3_trace_header(mISDNport, NULL, L2_ESTABLISH_REQ, DIRECTION_OUT);
+               end_trace();
        }
        /* if ptp AND nt-mode, pull up the link */
        if (mISDNport->ptp && mISDNport->ntmode)
@@ -2442,7 +3257,10 @@ struct mISDNport *mISDNport_open(int port, int ptp, int ptmp, struct interface *
                dmsg = create_l2msg(DL_ESTABLISH | REQUEST, 0, 0);
                if (mISDNport->nst.manager_l3(&mISDNport->nst, dmsg))
                        free_msg(dmsg);
+               l1l2l3_trace_header(mISDNport, NULL, L2_ESTABLISH_REQ, DIRECTION_OUT);
+               end_trace();
        }
+#endif
        /* initially, we assume that the link is down, exept for nt-ptmp */
        mISDNport->l2link = (mISDNport->ntmode && !mISDNport->ptp)?1:0;
 
@@ -2480,8 +3298,11 @@ void mISDNport_close(struct mISDNport *mISDNport)
        struct mISDNport **mISDNportp;
        class Port *port;
        class PmISDN *isdnport;
+#ifdef SOCKET_MISDN
+#else
        net_stack_t *nst;
        unsigned char buf[32];
+#endif
        int i;
 
        /* remove all port instance that are linked to this mISDNport */
@@ -2518,7 +3339,11 @@ void mISDNport_close(struct mISDNport *mISDNport)
        i = 0;
        while(i < mISDNport->b_num)
        {
+#ifdef SOCKET_MISDN
+               if (mISDNport->b_socket[i] > -1)
+#else
                if (mISDNport->b_addr[i])
+#endif
                {
                        _bchannel_destroy(mISDNport, i);
                        PDEBUG(DEBUG_BCHANNEL, "freeing %s port %d bchannel (index %d).\n", (mISDNport->ntmode)?"NT":"TE", mISDNport->portnum, i);
@@ -2526,6 +3351,9 @@ void mISDNport_close(struct mISDNport *mISDNport)
                i++;
        }
 
+#ifdef SOCKET_MISDN
+       close_layer3(mISDNport->ml3);
+#else
        /* free ressources of port */
        msg_queue_purge(&mISDNport->downqueue);
 
@@ -2552,6 +3380,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);
        }
+#endif
 
        /* remove from list */
        mISDNportp = &mISDNport_first;
@@ -2580,9 +3409,31 @@ void mISDNport_close(struct mISDNport *mISDNport)
  */
 void mISDN_port_info(void)
 {
-       int err;
-       int i, ii, p;
-       int useable, nt, pri;
+       int ret;
+       int i, ii;
+       int useable, nt, te, pri, bri, pots;
+#ifdef SOCKET_MISDN
+       struct mISDN_devinfo devinfo;
+       int sock;
+
+       /* open mISDN */
+       sock = socket(PF_ISDN, SOCK_RAW, ISDN_P_BASE);
+       if (sock < 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(sock, IMGETCOUNT, &ii);
+       if (ret < 0)
+       {
+               fprintf(stderr, "Cannot get number of mISDN devices. (ioctl IMGETCOUNT failed ret=%d)\n", ret);
+               goto done;
+       }
+#else
+       int p;
        unsigned char buff[1025];
        iframe_t *frm = (iframe_t *)buff;
        stack_info_t *stinf;
@@ -2591,68 +3442,139 @@ void mISDN_port_info(void)
        /* 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));
+               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);
+#endif
        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)
        {
-               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(sock, 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;
                }
-               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 || pots))
+                       useable = 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 (pots)
+               {
+                       useable = 0;
+                       printf("\n -> Analog interfaces are not supported.");
+               } else
+               if (!useable)
+               {
+                       printf("unsupported interface protocol bits 0x%016x", devinfo.Dprotocols);
+               }
+               printf("\n");
+
+               printf("  - %d B-channels\n", devinfo.nrbchan);
+#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:
+                       useable = 1;
+                       te = 1;
+                       bri = 1;
                        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:
+                       useable = 1;
                        nt = 1;
+                       bri = 1;
                        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:
+                       useable = 1;
+                       te = 1;
                        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:
+                       useable = 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;
@@ -2683,7 +3605,8 @@ void mISDN_port_info(void)
                                else
                                        printf(" -> Interface can be Poin-To-Point/Multipoint.\n");
                        }
-               } else
+               }
+               if (te)
                {
                        if (stinf->pid.protocol[1] == 0)
                        {
@@ -2729,6 +3652,7 @@ void mISDN_port_info(void)
                        }
                }
                printf("  - %d B-channels\n", stinf->childcnt);
+#endif
 
                if (!useable)
                        printf(" * Port NOT useable for LCR\n");
@@ -2739,9 +3663,14 @@ void mISDN_port_info(void)
        }
        printf("\n");
 
+done:
+#ifdef SOCKET_MISDN
+       close(sock);
+#else
        /* close mISDN */
-       if ((err = mISDN_close(device)))
-               FATAL("mISDN_close() failed: err=%d '%s'\n", err, strerror(err));
+       if ((ret = mISDN_close(device)))
+               FATAL("mISDN_close() failed: err=%d '%s'\n", ret, strerror(ret));
+#endif
 }
 
 
@@ -2750,13 +3679,24 @@ void mISDN_port_info(void)
  */
 void PmISDN::txfromup(unsigned char *data, int length)
 {
+#ifdef SOCKET_MISDN
+       unsigned char buf[MISDN_HEADER_LEN+((length>ISDN_LOAD)?length:ISDN_LOAD)];
+       struct mISDNhead *hh = (struct mISDNhead *)buf;
+       int ret;
+
+       if (p_m_b_index < 0)
+               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;
 
-       /* configure frame */
-       frm->prim = DL_DATA | REQUEST; 
-       frm->addr = p_m_mISDNport->b_addr[p_m_b_index] | FLG_MSG_DOWN;
-       frm->dinfo = 0;
+       if (p_m_b_index < 0)
+               return;
+       if (!p_m_mISDNport->b_addr[p_m_b_index])
+               return;
+#endif
 
        /* check if high priority tones exist
         * ignore data in this case
@@ -2770,11 +3710,22 @@ void PmISDN::txfromup(unsigned char *data, int length)
         */
        if (p_m_load==0 && ISDN_LOAD>0)
        {
-
-               memcpy(buf+mISDN_HEADER_LEN, data, ISDN_LOAD);
+#ifdef SOCKET_MISDN
+               hh->prim = DL_DATA_REQ; 
+               hh->id = 0;
+               memcpy(buf+MISDN_HEADER_LEN, data, ISDN_LOAD);
+               ret = sendto(p_m_mISDNport->b_socket[p_m_b_index], buf, MISDN_HEADER_LEN+ISDN_LOAD, 0, NULL, 0);
+               if (!ret)
+                       PERROR("Failed to send to socket %d\n", p_m_mISDNport->b_socket[p_m_b_index]);
+#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 = ISDN_LOAD;
-               mISDN_write(mISDNdevice, frm, mISDN_HEADER_LEN+frm->len, TIMEOUT_1SEC);
-               p_m_load += frm->len;
+               memcpy(buf+mISDN_HEADER_LEN, data, ISDN_LOAD);
+               mISDN_write(mISDNdevice, frm, mISDN_HEADER_LEN+ISDN_LOAD, TIMEOUT_1SEC);
+#endif
+               p_m_load += ISDN_LOAD;
        }
 
        /* drop if load would exceed ISDN_MAXLOAD
@@ -2783,11 +3734,22 @@ void PmISDN::txfromup(unsigned char *data, int length)
        if (p_m_load+length > ISDN_MAXLOAD)
                return;
 
-       /* load data to buffer
-        */
-       memcpy(buf+mISDN_HEADER_LEN, data, length);
+       /* make and send frame */
+#ifdef SOCKET_MISDN
+       hh->prim = DL_DATA_REQ;
+       hh->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", p_m_mISDNport->b_socket[p_m_b_index]);
+#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);
-       p_m_load += frm->len;
+#endif
+       p_m_load += length;
 }