Add global variable for Law encoded silence
[lcr.git] / mISDN.cpp
index ce885d9..585ae82 100644 (file)
--- a/mISDN.cpp
+++ b/mISDN.cpp
 
 #include "main.h"
 #include "myisdn.h"
 
 #include "main.h"
 #include "myisdn.h"
-
-extern "C" {
-#define MISDN_OLD_AF_COMPATIBILITY 1
-#include <compat_af_isdn.h>
-}
-#include <q931.h>
+#include <mISDN/q931.h>
 
 #undef offsetof
 #ifdef __compiler_offsetof
 
 #undef offsetof
 #ifdef __compiler_offsetof
@@ -42,25 +37,46 @@ struct mISDNport *mISDNport_first;
 unsigned char mISDN_rand[256];
 int mISDN_rand_count = 0;
 
 unsigned char mISDN_rand[256];
 int mISDN_rand_count = 0;
 
+#ifdef OLD_MT_ASSIGN
 unsigned int mt_assign_pid = ~0;
 unsigned int mt_assign_pid = ~0;
+#endif
 
 int mISDNsocket = -1;
 
 int mISDNsocket = -1;
+static int upqueue_pipe[2];
+static struct lcr_fd upqueue_fd;
+int upqueue_avail = 0;
+
+static int mISDN_upqueue(struct lcr_fd *fd, unsigned int what, void *instance, int i);
+static int mISDN_timeout(struct lcr_timer *timer, void *instance, int i);
+
+static int my_mISDNlib_debug(const char *file, int line, const char *func, int level, const char *fmt, va_list va)
+{
+        int ret = 0;
+
+        if (debug_fp > 0)
+               ret = vfprintf(debug_fp, fmt, va);
+       return ret;
+}
+
+static struct mi_ext_fn_s myfn;
 
 int mISDN_initialize(void)
 {
        char filename[256];
 
 int mISDN_initialize(void)
 {
        char filename[256];
-
-       init_af_isdn();
+       int ver;
 
        /* try to open raw socket to check kernel */
        mISDNsocket = socket(PF_ISDN, SOCK_RAW, ISDN_P_BASE);
        if (mISDNsocket < 0) {
 
        /* try to open raw socket to check kernel */
        mISDNsocket = socket(PF_ISDN, SOCK_RAW, ISDN_P_BASE);
        if (mISDNsocket < 0) {
-               fprintf(stderr, "Cannot open mISDN due to '%s'. (Does your Kernel support socket based mISDN?)\n", strerror(errno));
+               fprintf(stderr, "Cannot open mISDN due to '%s'. (Does your Kernel support socket based mISDN? Protocol family is %d.)\n", strerror(errno), PF_ISDN);
                return(-1);
        }
 
        /* init mlayer3 */
                return(-1);
        }
 
        /* init mlayer3 */
-       init_layer3(4); // buffer of 4
+       // set debug printout function
+       myfn.prt_debug = my_mISDNlib_debug;
+
+       ver = init_layer3(4, &myfn); // buffer of 4
 
        /* open debug, if enabled and not only stack debugging */
        if (options.deb) {
 
        /* open debug, if enabled and not only stack debugging */
        if (options.deb) {
@@ -68,11 +84,16 @@ int mISDN_initialize(void)
                debug_fp = fopen(filename, "a");
        }
 
                debug_fp = fopen(filename, "a");
        }
 
-       if (options.deb & DEBUG_STACK) {
-               SPRINT(filename, "%s/debug_mISDN.log", LOG_DIR);
-               mISDN_debug_init(0xfffffeff, filename, filename, filename);
-       } else
-               mISDN_debug_init(0, NULL, NULL, NULL);
+       if (options.deb & DEBUG_STACK)
+               mISDN_set_debug_level(0xfffffeff);
+       else
+               mISDN_set_debug_level(0);
+
+       if (pipe(upqueue_pipe) < 0)
+               FATAL("Failed to open pipe\n");
+       memset(&upqueue_fd, 0, sizeof(upqueue_fd));
+       upqueue_fd.fd = upqueue_pipe[0];
+       register_fd(&upqueue_fd, LCR_FD_READ, mISDN_upqueue, NULL, 0);
 
        return(0);
 }
 
        return(0);
 }
@@ -81,16 +102,23 @@ void mISDN_deinitialize(void)
 {
        cleanup_layer3();
 
 {
        cleanup_layer3();
 
-       mISDN_debug_close();
-
        if (debug_fp)
                fclose(debug_fp);
        debug_fp = NULL;
 
        if (mISDNsocket > -1)
                close(mISDNsocket);
        if (debug_fp)
                fclose(debug_fp);
        debug_fp = NULL;
 
        if (mISDNsocket > -1)
                close(mISDNsocket);
+
+       if (upqueue_fd.inuse) {
+               unregister_fd(&upqueue_fd);
+               close(upqueue_pipe[0]);
+               close(upqueue_pipe[1]);
+       }
+       upqueue_avail = 0;
 }
 
 }
 
+int load_timer(struct lcr_timer *timer, void *instance, int index);
+
 /*
  * constructor
  */
 /*
  * constructor
  */
@@ -103,7 +131,6 @@ PmISDN::PmISDN(int type, mISDNport *mISDNport, char *portname, struct port_setti
        p_m_b_exclusive = 0;
        p_m_b_reserve = 0;
        p_m_b_mode = mode;
        p_m_b_exclusive = 0;
        p_m_b_reserve = 0;
        p_m_b_mode = mode;
-       p_m_delete = 0;
        p_m_hold = 0;
        p_m_tx_gain = mISDNport->ifport->interface->tx_gain;
        p_m_rx_gain = mISDNport->ifport->interface->rx_gain;
        p_m_hold = 0;
        p_m_tx_gain = mISDNport->ifport->interface->tx_gain;
        p_m_rx_gain = mISDNport->ifport->interface->rx_gain;
@@ -111,20 +138,20 @@ PmISDN::PmISDN(int type, mISDNport *mISDNport, char *portname, struct port_setti
        p_m_mute = 0;
        p_m_txdata = 0;
        p_m_delay = 0;
        p_m_mute = 0;
        p_m_txdata = 0;
        p_m_delay = 0;
+       p_m_tx_dejitter = 0;
        p_m_echo = 0;
        p_m_tone = 0;
        p_m_rxoff = 0;
        p_m_echo = 0;
        p_m_tone = 0;
        p_m_rxoff = 0;
-       p_m_joindata = 0;
        p_m_inband_send_on = 0;
        p_m_inband_receive_on = 0;
        p_m_dtmf = !mISDNport->ifport->nodtmf;
        p_m_inband_send_on = 0;
        p_m_inband_receive_on = 0;
        p_m_dtmf = !mISDNport->ifport->nodtmf;
-       p_m_timeout = 0;
-       p_m_timer = 0;
-       p_m_remote_ref = 0; /* channel shall be exported to given remote */
-       p_m_remote_id = 0; /* remote admin socket */
+       memset(&p_m_timeout, 0, sizeof(p_m_timeout));
+       add_timer(&p_m_timeout, mISDN_timeout, this, 0);
        SCPY(p_m_pipeline, mISDNport->ifport->interface->pipeline);
        
        /* audio */
        SCPY(p_m_pipeline, mISDNport->ifport->interface->pipeline);
        
        /* audio */
+       memset(&p_m_loadtimer, 0, sizeof(p_m_loadtimer));
+       add_timer(&p_m_loadtimer, load_timer, this, 0);
        p_m_load = 0;
        p_m_last_tv_sec = 0;
 
        p_m_load = 0;
        p_m_last_tv_sec = 0;
 
@@ -173,6 +200,9 @@ PmISDN::~PmISDN()
 {
        struct lcr_msg *message;
 
 {
        struct lcr_msg *message;
 
+       del_timer(&p_m_timeout);
+       del_timer(&p_m_loadtimer);
+
        /* remove bchannel relation */
        drop_bchannel();
 
        /* remove bchannel relation */
        drop_bchannel();
 
@@ -357,6 +387,7 @@ void ph_control_block(struct mISDNport *mISDNport, class PmISDN *isdnport, int s
        end_trace();
 }
 
        end_trace();
 }
 
+static int b_sock_callback(struct lcr_fd *fd, unsigned int what, void *instance, int i);
 
 /*
  * subfunction for bchannel_event
 
 /*
  * subfunction for bchannel_event
@@ -365,47 +396,40 @@ void ph_control_block(struct mISDNport *mISDNport, class PmISDN *isdnport, int s
 static int _bchannel_create(struct mISDNport *mISDNport, int i)
 {
        int ret;
 static int _bchannel_create(struct mISDNport *mISDNport, int i)
 {
        int ret;
-       unsigned int on = 1;
        struct sockaddr_mISDN addr;
 
        struct sockaddr_mISDN addr;
 
-       if (mISDNport->b_socket[i] > -1) {
+       if (mISDNport->b_sock[i].inuse) {
                PERROR("Error: Socket already created for index %d\n", i);
                return(0);
        }
 
        /* open socket */
 //#warning testing without DSP
                PERROR("Error: Socket already created for index %d\n", i);
                return(0);
        }
 
        /* open socket */
 //#warning testing without DSP
-//     mISDNport->b_socket[i] = socket(PF_ISDN, SOCK_DGRAM, (mISDNport->b_mode[i]==B_MODE_HDLC)?ISDN_P_B_HDLC:ISDN_P_B_RAW);
-       mISDNport->b_socket[i] = socket(PF_ISDN, SOCK_DGRAM, (mISDNport->b_mode[i]==B_MODE_HDLC)?ISDN_P_B_L2DSPHDLC:ISDN_P_B_L2DSP);
-       if (mISDNport->b_socket[i] < 0) {
+//     mISDNport->b_sock[i].fd = socket(PF_ISDN, SOCK_DGRAM, (mISDNport->b_mode[i]==B_MODE_HDLC)?ISDN_P_B_HDLC:ISDN_P_B_RAW);
+       mISDNport->b_sock[i].fd = socket(PF_ISDN, SOCK_DGRAM, (mISDNport->b_mode[i]==B_MODE_HDLC)?ISDN_P_B_L2DSPHDLC:ISDN_P_B_L2DSP);
+       if (mISDNport->b_sock[i].fd < 0) {
                PERROR("Error: Failed to open bchannel-socket for index %d with mISDN-DSP layer. Did you load mISDN_dsp.ko?\n", i);
                return(0);
        }
                PERROR("Error: Failed to open bchannel-socket for index %d with mISDN-DSP layer. Did you load mISDN_dsp.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);
-       }
 
 
+       /* register callback for read */
+       register_fd(&mISDNport->b_sock[i], LCR_FD_READ, b_sock_callback, mISDNport, i);
+       
        /* bind socket to bchannel */
        addr.family = AF_ISDN;
        addr.dev = mISDNport->portnum;
        addr.channel = i+1+(i>=15);
        /* bind socket to bchannel */
        addr.family = AF_ISDN;
        addr.dev = mISDNport->portnum;
        addr.channel = i+1+(i>=15);
-       ret = bind(mISDNport->b_socket[i], (struct sockaddr *)&addr, sizeof(addr));
+       ret = bind(mISDNport->b_sock[i].fd, (struct sockaddr *)&addr, sizeof(addr));
        if (ret < 0) {
                PERROR("Error: Failed to bind bchannel-socket for index %d with mISDN-DSP layer (errno=%d). Did you load mISDN_dsp.ko?\n", i, errno);
        if (ret < 0) {
                PERROR("Error: Failed to bind bchannel-socket for index %d with mISDN-DSP layer (errno=%d). Did you load mISDN_dsp.ko?\n", i, errno);
-               close(mISDNport->b_socket[i]);
-               mISDNport->b_socket[i] = -1;
+               close(mISDNport->b_sock[i].fd);
+               unregister_fd(&mISDNport->b_sock[i]);
                return(0);
        }
 
        chan_trace_header(mISDNport, mISDNport->b_port[i], "BCHANNEL create socket", DIRECTION_OUT);
        add_trace("channel", NULL, "%d", i+1+(i>=15));
                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]);
+       add_trace("socket", NULL, "%d", mISDNport->b_sock[i].fd);
        end_trace();
 
        return(1);
        end_trace();
 
        return(1);
@@ -416,23 +440,23 @@ static int _bchannel_create(struct mISDNport *mISDNport, int i)
  * subfunction for bchannel_event
  * activate / deactivate request
  */
  * subfunction for bchannel_event
  * activate / deactivate request
  */
-static void _bchannel_activate(struct mISDNport *mISDNport, int i, int activate)
+static void _bchannel_activate(struct mISDNport *mISDNport, int i, int activate, int timeout)
 {
        struct mISDNhead act;
        int ret;
 
 {
        struct mISDNhead act;
        int ret;
 
-       if (mISDNport->b_socket[i] < 0)
+       if (!mISDNport->b_sock[i].inuse)
                return;
        act.prim = (activate)?PH_ACTIVATE_REQ:PH_DEACTIVATE_REQ; 
        act.id = 0;
                return;
        act.prim = (activate)?PH_ACTIVATE_REQ:PH_DEACTIVATE_REQ; 
        act.id = 0;
-       ret = sendto(mISDNport->b_socket[i], &act, MISDN_HEADER_LEN, 0, NULL, 0);
+       ret = sendto(mISDNport->b_sock[i].fd, &act, MISDN_HEADER_LEN, 0, NULL, 0);
        if (ret <= 0)
        if (ret <= 0)
-               PERROR("Failed to send to socket %d\n", mISDNport->b_socket[i]);
+               PERROR("Failed to send to socket %d\n", mISDNport->b_sock[i].fd);
 
        /* trace */
        chan_trace_header(mISDNport, mISDNport->b_port[i], activate ? "BCHANNEL activate" : "BCHANNEL deactivate", DIRECTION_OUT);
        add_trace("channel", NULL, "%d", i+1+(i>=15));
 
        /* trace */
        chan_trace_header(mISDNport, mISDNport->b_port[i], activate ? "BCHANNEL activate" : "BCHANNEL deactivate", DIRECTION_OUT);
        add_trace("channel", NULL, "%d", i+1+(i>=15));
-       if (mISDNport->b_timer[i])
+       if (timeout)
                add_trace("event", NULL, "timeout recovery");
        end_trace();
 }
                add_trace("event", NULL, "timeout recovery");
        end_trace();
 }
@@ -447,9 +471,9 @@ static void _bchannel_configure(struct mISDNport *mISDNport, int i)
        struct PmISDN *port;
        int handle, mode;
 
        struct PmISDN *port;
        int handle, mode;
 
-       if (mISDNport->b_socket[i] < 0)
+       if (!mISDNport->b_sock[i].inuse)
                return;
                return;
-       handle = mISDNport->b_socket[i];
+       handle = mISDNport->b_sock[i].fd;
        port = mISDNport->b_port[i];
        mode = mISDNport->b_mode[i];
        if (!port) {
        port = mISDNport->b_port[i];
        mode = mISDNport->b_mode[i];
        if (!port) {
@@ -462,6 +486,8 @@ static void _bchannel_configure(struct mISDNport *mISDNport, int i)
                ph_control(mISDNport, port, handle, (port->p_m_txdata)?DSP_TXDATA_ON:DSP_TXDATA_OFF, 0, "DSP-TXDATA", port->p_m_txdata);
        if (port->p_m_delay && mode == B_MODE_TRANSPARENT)
                ph_control(mISDNport, port, handle, DSP_DELAY, port->p_m_delay, "DSP-DELAY", port->p_m_delay);
                ph_control(mISDNport, port, handle, (port->p_m_txdata)?DSP_TXDATA_ON:DSP_TXDATA_OFF, 0, "DSP-TXDATA", port->p_m_txdata);
        if (port->p_m_delay && mode == B_MODE_TRANSPARENT)
                ph_control(mISDNport, port, handle, DSP_DELAY, port->p_m_delay, "DSP-DELAY", port->p_m_delay);
+       if (port->p_m_tx_dejitter && mode == B_MODE_TRANSPARENT)
+               ph_control(mISDNport, port, handle, DSP_TX_DEJITTER, port->p_m_tx_dejitter, "DSP-TX_DEJITTER", port->p_m_tx_dejitter);
        if (port->p_m_tx_gain && mode == B_MODE_TRANSPARENT)
                ph_control(mISDNport, port, handle, DSP_VOL_CHANGE_TX, port->p_m_tx_gain, "DSP-TX_GAIN", port->p_m_tx_gain);
        if (port->p_m_rx_gain && mode == B_MODE_TRANSPARENT)
        if (port->p_m_tx_gain && mode == B_MODE_TRANSPARENT)
                ph_control(mISDNport, port, handle, DSP_VOL_CHANGE_TX, port->p_m_tx_gain, "DSP-TX_GAIN", port->p_m_tx_gain);
        if (port->p_m_rx_gain && mode == B_MODE_TRANSPARENT)
@@ -491,7 +517,7 @@ void PmISDN::set_conf(int oldconf, int newconf)
                        PDEBUG(DEBUG_BCHANNEL, "we change conference from conf=%d to conf=%d.\n", oldconf, newconf);
                        if (p_m_b_index > -1)
                        if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE)
                        PDEBUG(DEBUG_BCHANNEL, "we change conference from conf=%d to conf=%d.\n", oldconf, newconf);
                        if (p_m_b_index > -1)
                        if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE)
-                               ph_control(p_m_mISDNport, this, p_m_mISDNport->b_socket[p_m_b_index], (newconf)?DSP_CONF_JOIN:DSP_CONF_SPLIT, newconf, "DSP-CONF", newconf);
+                               ph_control(p_m_mISDNport, this, p_m_mISDNport->b_sock[p_m_b_index].fd, (newconf)?DSP_CONF_JOIN:DSP_CONF_SPLIT, newconf, "DSP-CONF", newconf);
                } else
                        PDEBUG(DEBUG_BCHANNEL, "we already have conf=%d.\n", newconf);
 }
                } else
                        PDEBUG(DEBUG_BCHANNEL, "we already have conf=%d.\n", newconf);
 }
@@ -503,14 +529,14 @@ void PmISDN::set_conf(int oldconf, int newconf)
  */
 static void _bchannel_destroy(struct mISDNport *mISDNport, int i)
 {
  */
 static void _bchannel_destroy(struct mISDNport *mISDNport, int i)
 {
-       if (mISDNport->b_socket[i] < 0)
+       if (!mISDNport->b_sock[i].inuse)
                return;
        chan_trace_header(mISDNport, mISDNport->b_port[i], "BCHANNEL remove socket", DIRECTION_OUT);
        add_trace("channel", NULL, "%d", i+1+(i>=15));
                return;
        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]);
+       add_trace("socket", NULL, "%d", mISDNport->b_sock[i].fd);
        end_trace();
        end_trace();
-       close(mISDNport->b_socket[i]);
-       mISDNport->b_socket[i] = -1;
+       close(mISDNport->b_sock[i].fd);
+       unregister_fd(&mISDNport->b_sock[i]);
 }
 
 
 }
 
 
@@ -540,22 +566,6 @@ It may be linked to a Port class, that likes to reactivate it.
 See above.
 After deactivating bchannel, and if not used, the bchannel becomes idle again.
 
 See above.
 After deactivating bchannel, and if not used, the bchannel becomes idle again.
 
-Also the bchannel may be exported, but only if the state is or becomes idle:
-
-- B_STATE_EXPORTING
-The bchannel assignment has been sent to the remove application.
-
-- B_STATE_REMOTE
-The bchannel assignment is acknowledged by the remote application.
-
-- B_STATE_IMPORTING
-The bchannel is re-imported by mISDN port object.
-
-- B_STATE_IDLE
-See above.
-After re-importing bchannel, and if not used, the bchannel becomes idle again.
-
-
 A bchannel can have the following events:
 
 - B_EVENT_USE
 A bchannel can have the following events:
 
 - B_EVENT_USE
@@ -570,33 +580,8 @@ The bchannel is not required by Port class anymore
 - B_EVENT_DEACTIVATED
 The bchannel becomes inactive.
 
 - B_EVENT_DEACTIVATED
 The bchannel becomes inactive.
 
-- B_EVENT_EXPORTED
-The bchannel is now used by remote application.
-
-- B_EVENT_IMPORTED
-The bchannel is not used by remote application.
-
-- B_EVENT_EXPORTREQUEST
-The bchannel shall be exported to the remote application.
-
-- B_EVENT_IMPORTREQUEST
-The bchannel is released from the remote application.
-
 All actions taken on these events depend on the current bchannel's state and if it is linked to a Port class.
 
 All actions taken on these events depend on the current bchannel's state and if it is linked to a Port class.
 
-if an export request is receive by remote application, p_m_remote_* is set.
-the b_remote_*[index] indicates if and where the channel is exported to. (set from the point on, where export is initiated, until imported is acknowledged.)
-- set on export request from remote application (if port is assigned)
-- set on channel use, if requested by remote application (p_m_remote_*)
-- cleared on drop request
-
-the bchannel will be exported with ref and stack given. remote application uses the ref to link bchannel to the call.
-the bchannel will be imported with stack given only. remote application must store stack id with the bchannel process.
-the bchannel import/export is acknowledged with stack given.
-
-if exporting, b_remote_*[index] is set to the remote socket id.
-if importing has been acknowledged. b_remote_*[index] is cleared.
-
 */
 
 /*
 */
 
 /*
@@ -610,20 +595,15 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
 {
        class PmISDN *b_port = mISDNport->b_port[i];
        int state = mISDNport->b_state[i];
 {
        class PmISDN *b_port = mISDNport->b_port[i];
        int state = mISDNport->b_state[i];
-       double timer = mISDNport->b_timer[i];
-       unsigned int p_m_remote_ref = 0;
-       unsigned int p_m_remote_id = 0;
+       int timer = -1; // no change
        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;
        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;
-       unsigned int portid = (mISDNport->portnum<<8) + i+1+(i>=15);
 
        if (b_port) {
 
        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_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;
@@ -639,168 +619,41 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
                        FATAL("bchannel must be linked to a Port class\n");
                switch(state) {
                        case B_STATE_IDLE:
                        FATAL("bchannel must be linked to a Port class\n");
                switch(state) {
                        case B_STATE_IDLE:
-                       if (p_m_remote_ref) {
-                               /* export bchannel */
-                               message_bchannel_to_remote(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("channel", NULL, "%d.%d", portid>>8, portid&0xff);
-                               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 */
-                               if (_bchannel_create(mISDNport, i)) {
-                                       _bchannel_activate(mISDNport, i, 1);
-                                       state = B_STATE_ACTIVATING;
-                                       timer = now_d + B_TIMER_ACTIVATING;
-                               }
+                       /* create stack and send activation request */
+                       if (_bchannel_create(mISDNport, i)) {
+                               _bchannel_activate(mISDNport, i, 1, 0);
+                               state = B_STATE_ACTIVATING;
+                               timer = B_TIMER_ACTIVATING;
                        }
                        break;
 
                        case B_STATE_ACTIVATING:
                        }
                        break;
 
                        case B_STATE_ACTIVATING:
-                       case B_STATE_EXPORTING:
                        /* do nothing, because it is already activating */
                        break;
 
                        /* do nothing, because it is already activating */
                        break;
 
-                       case B_STATE_DEACTIVATING:
-                       case B_STATE_IMPORTING:
-                       /* do nothing, because we must wait until we can reactivate */
-                       break;
-
                        default:
                        /* problems that might ocurr:
                         * B_EVENT_USE is received when channel already in use.
                        default:
                        /* problems that might ocurr:
                         * B_EVENT_USE is received when channel already in use.
-                        * bchannel exported, but not freed by other port
                         */
                        PERROR("Illegal event %d at state %d, please correct.\n", event, state);
                }
                break;
 
                         */
                        PERROR("Illegal event %d at state %d, please correct.\n", event, state);
                }
                break;
 
-               case B_EVENT_EXPORTREQUEST:
-               /* special case where the bchannel is requested by remote */
-               if (!p_m_remote_ref) {
-                       PERROR("export request without remote channel set, please correct.\n");
-                       break;
-               }
-               switch(state) {
-                       case B_STATE_IDLE:
-                       /* in case, the bchannel is exported right after seize_bchannel */
-                       /* export bchannel */
-                       /* p_m_remote_id is set, when this event happens. */
-                       message_bchannel_to_remote(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("channel", NULL, "%d.%d", portid>>8, portid&0xff);
-                       end_trace();
-                       state = B_STATE_EXPORTING;
-                       mISDNport->b_remote_id[i] = p_m_remote_id;
-                       mISDNport->b_remote_ref[i] = p_m_remote_ref;
-                       break;
-
-                       case B_STATE_ACTIVATING:
-                       case B_STATE_EXPORTING:
-                       /* do nothing, because it is already activating */
-                       break;
-
-                       case B_STATE_DEACTIVATING:
-                       case B_STATE_IMPORTING:
-                       /* do nothing, because we must wait until we can reactivate */
-                       break;
-
-                       case B_STATE_ACTIVE:
-                       /* bchannel is active, so we deactivate */
-                       _bchannel_activate(mISDNport, i, 0);
-                       state = B_STATE_DEACTIVATING;
-                       timer = now_d + B_TIMER_DEACTIVATING;
-                       break;
-
-                       default:
-                       /* problems that might ocurr:
-                        * ... when channel already in use.
-                        * bchannel exported, but not freed by other port
-                        */
-                       PERROR("Illegal event %d at state %d, please correct.\n", event, state);
-               }
-               break;
-
-               case B_EVENT_IMPORTREQUEST:
-               /* special case where the bchannel is released by remote */
-               if (p_m_remote_ref) {
-                       PERROR("import request with remote channel set, please correct.\n");
-                       break;
-               }
-               switch(state) {
-                       case B_STATE_IDLE:
-                       case B_STATE_ACTIVE:
-                       /* bchannel is not exported */
-                       break;
-
-                       case B_STATE_ACTIVATING:
-                       case B_STATE_EXPORTING:
-                       /* do nothing because we must wait until bchanenl is active before deactivating */
-                       break;
-
-                       case B_STATE_REMOTE:
-                       /* bchannel is exported, so we re-import */
-                       message_bchannel_to_remote(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("channel", NULL, "%d.%d", portid>>8, portid&0xff);
-                       end_trace();
-                       state = B_STATE_IMPORTING;
-                       break;
-
-                       case B_STATE_DEACTIVATING:
-                       case B_STATE_IMPORTING:
-                       /* we may have taken an already deactivating bchannel, but do not require it anymore, so we do nothing */
-                       break;
-
-                       default:
-                       PERROR("Illegal event %d at state %d, please correct.\n", event, state);
-               }
-               break;
 
                case B_EVENT_ACTIVATED:
                timer = 0;
                switch(state) {
                        case B_STATE_ACTIVATING:
 
                case B_EVENT_ACTIVATED:
                timer = 0;
                switch(state) {
                        case B_STATE_ACTIVATING:
-                       if (b_port && !p_m_remote_id) {
+                       if (b_port) {
                                /* bchannel is active and used by Port class, so we configure bchannel */
                                _bchannel_configure(mISDNport, i);
                                state = B_STATE_ACTIVE;
                                b_port->p_m_load = 0;
                        } else {
                                /* bchannel is active and used by Port class, so we configure bchannel */
                                _bchannel_configure(mISDNport, i);
                                state = B_STATE_ACTIVE;
                                b_port->p_m_load = 0;
                        } else {
-                               /* bchannel is active, but exported OR not used anymore (or has wrong stack config), so we deactivate */
-                               _bchannel_activate(mISDNport, i, 0);
+                               /* bchannel is active, but not used anymore (or has wrong stack config), so we deactivate */
+                               _bchannel_activate(mISDNport, i, 0, 0);
                                state = B_STATE_DEACTIVATING;
                                state = B_STATE_DEACTIVATING;
-                               timer = now_d + B_TIMER_DEACTIVATING;
-                       }
-                       break;
-
-                       default:
-                       PERROR("Illegal event %d at state %d, please correct.\n", event, state);
-               }
-               break;
-
-               case B_EVENT_EXPORTED:
-               switch(state) {
-                       case B_STATE_EXPORTING:
-                       if (b_port && p_m_remote_ref && p_m_remote_ref==mISDNport->b_remote_ref[i]) {
-                               /* remote export done */
-                               state = B_STATE_REMOTE;
-                       } else {
-                               /* bchannel is now exported, but we need bchannel back
-                                * OR bchannel is not used anymore
-                                * OR bchannel has been exported to an obsolete ref,
-                                * so reimport, to later export to new remote */
-                               message_bchannel_to_remote(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("channel", NULL, "%d.%d", portid>>8, portid&0xff);
-                               end_trace();
-                               state = B_STATE_IMPORTING;
+                               timer = B_TIMER_DEACTIVATING;
                        }
                        break;
 
                        }
                        break;
 
@@ -818,29 +671,17 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
                        break;
 
                        case B_STATE_ACTIVATING:
                        break;
 
                        case B_STATE_ACTIVATING:
-                       case B_STATE_EXPORTING:
                        /* do nothing because we must wait until bchanenl is active before deactivating */
                        break;
 
                        case B_STATE_ACTIVE:
                        /* bchannel is active, so we deactivate */
                        /* do nothing because we must wait until bchanenl is active before deactivating */
                        break;
 
                        case B_STATE_ACTIVE:
                        /* bchannel is active, so we deactivate */
-                       _bchannel_activate(mISDNport, i, 0);
+                       _bchannel_activate(mISDNport, i, 0, 0);
                        state = B_STATE_DEACTIVATING;
                        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_remote(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("channel", NULL, "%d.%d", portid>>8, portid&0xff);
-                       end_trace();
-                       state = B_STATE_IMPORTING;
+                       timer = B_TIMER_DEACTIVATING;
                        break;
 
                        case B_STATE_DEACTIVATING:
                        break;
 
                        case B_STATE_DEACTIVATING:
-                       case B_STATE_IMPORTING:
                        /* we may have taken an already deactivating bchannel, but do not require it anymore, so we do nothing */
                        break;
 
                        /* we may have taken an already deactivating bchannel, but do not require it anymore, so we do nothing */
                        break;
 
@@ -860,22 +701,11 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
                        _bchannel_destroy(mISDNport, i);
                        state = B_STATE_IDLE;
                        if (b_port) {
                        _bchannel_destroy(mISDNport, i);
                        state = B_STATE_IDLE;
                        if (b_port) {
-                               /* bchannel is now deactivate, but is requied by Port class, so we reactivate / export */
-                               if (p_m_remote_ref) {
-                                       message_bchannel_to_remote(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("channel", NULL, "%d.%d", portid>>8, portid&0xff);
-                                       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;
-                                       }
+                               /* bchannel is now deactivate, but is requied by Port class, so we reactivate */
+                               if (_bchannel_create(mISDNport, i)) {
+                                       _bchannel_activate(mISDNport, i, 1, 0);
+                                       state = B_STATE_ACTIVATING;
+                                       timer = B_TIMER_ACTIVATING;
                                }
                        }
                        break;
                                }
                        }
                        break;
@@ -885,39 +715,6 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
                }
                break;
 
                }
                break;
 
-               case B_EVENT_IMPORTED:
-               switch(state) {
-                       case B_STATE_IMPORTING:
-                       state = B_STATE_IDLE;
-                       mISDNport->b_remote_id[i] = 0;
-                       mISDNport->b_remote_ref[i] = 0;
-                       if (b_port) {
-                               /* bchannel is now imported, but is requied by Port class, so we reactivate / export */
-                               if (p_m_remote_ref) {
-                                       message_bchannel_to_remote(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("channel", NULL, "%d.%d", portid>>8, portid&0xff);
-                                       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;
-                                       }
-                               }
-                       }
-                       break;
-
-                       default:
-                       /* ignore, because not assigned */
-                       ;
-               }
-               break;
-
                case B_EVENT_TIMEOUT:
                timer = 0;
                switch(state) {
                case B_EVENT_TIMEOUT:
                timer = 0;
                switch(state) {
@@ -926,13 +723,13 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
                        break;
 
                        case B_STATE_ACTIVATING:
                        break;
 
                        case B_STATE_ACTIVATING:
-                       _bchannel_activate(mISDNport, i, 1);
-                       timer = now_d + B_TIMER_ACTIVATING;
+                       _bchannel_activate(mISDNport, i, 1, 1);
+                       timer = B_TIMER_ACTIVATING;
                        break;
 
                        case B_STATE_DEACTIVATING:
                        break;
 
                        case B_STATE_DEACTIVATING:
-                       _bchannel_activate(mISDNport, i, 0);
-                       timer = now_d + B_TIMER_DEACTIVATING;
+                       _bchannel_activate(mISDNport, i, 0, 1);
+                       timer = B_TIMER_DEACTIVATING;
                        break;
 
                        default:
                        break;
 
                        default:
@@ -945,7 +742,10 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
        }
 
        mISDNport->b_state[i] = state;
        }
 
        mISDNport->b_state[i] = state;
-       mISDNport->b_timer[i] = timer;
+       if (timer == 0)
+               unsched_timer(&mISDNport->b_timer[i]);
+       else if (timer > 0)
+               schedule_timer(&mISDNport->b_timer[i], timer, 0);
 }
 
 
 }
 
 
@@ -1053,101 +853,6 @@ void PmISDN::drop_bchannel(void)
        p_m_b_exclusive = 0;
 }
 
        p_m_b_exclusive = 0;
 }
 
-/* process bchannel export/import message from join */
-void message_bchannel_from_remote(class JoinRemote *joinremote, int type, unsigned int handle)
-{
-       class Endpoint *epoint;
-       class Port *port;
-       class PmISDN *isdnport;
-       struct mISDNport *mISDNport;
-       int i, ii;
-
-       switch(type) {
-               case BCHANNEL_REQUEST:
-               /* find the port object for the join object ref */
-               if (!(epoint = find_epoint_id(joinremote->j_epoint_id))) {
-                       PDEBUG(DEBUG_BCHANNEL, "join %d has no endpoint (anymore)\n", joinremote->j_serial);
-                       return;
-               }
-               if (!epoint->ep_portlist) {
-                       PDEBUG(DEBUG_BCHANNEL, "join %d has no port (anymore in portlist)\n", joinremote->j_serial);
-                       return;
-               }
-               if (epoint->ep_portlist->next) {
-                       PERROR("join %d has enpoint %d with more than one port. this shall not happen to remote joins.\n", joinremote->j_serial, epoint->ep_serial);
-               }
-               if (!(port = find_port_id(epoint->ep_portlist->port_id))) {
-                       PDEBUG(DEBUG_BCHANNEL, "join %d has no port (anymore as object)\n", joinremote->j_serial);
-                       return;
-               }
-               if ((port->p_type&PORT_CLASS_MASK) != PORT_CLASS_mISDN) {
-                       PERROR("join %d has port %d not of mISDN type. This shall not happen.\n", joinremote->j_serial, port->p_serial);
-               }
-               isdnport = (class PmISDN *)port;
-
-               /* assign */
-               if (isdnport->p_m_remote_id) {
-                       PERROR("join %d recevied bchannel request from remote, but channel is already assinged.\n", joinremote->j_serial);
-                       break;
-               }
-               mISDNport = isdnport->p_m_mISDNport;
-               i = isdnport->p_m_b_index;
-               chan_trace_header(mISDNport, isdnport, "MESSAGE_BCHANNEL (from remote application)", DIRECTION_NONE);
-               add_trace("type", NULL, "export request");
-               end_trace();
-               isdnport->p_m_remote_ref = joinremote->j_serial;
-               isdnport->p_m_remote_id = joinremote->j_remote_id;
-               if (mISDNport && i>=0) {
-                       bchannel_event(mISDNport, i, B_EVENT_EXPORTREQUEST);
-               }
-               break;
-
-               case BCHANNEL_RELEASE:
-               case BCHANNEL_ASSIGN_ACK:
-               case BCHANNEL_REMOVE_ACK:
-               /* find mISDNport for stack ID */
-               mISDNport = mISDNport_first;
-               while(mISDNport) {
-                       i = 0;
-                       ii = mISDNport->b_num;
-                       while(i < ii) {
-                               if ((unsigned int)(mISDNport->portnum<<8)+i+1+(i>=15) == handle)
-                                       break;
-                               i++;
-                       }
-                       if (i != ii)
-                               break;
-                       mISDNport = mISDNport->next;
-               }
-               if (!mISDNport) {
-                       PERROR("received assign/remove ack for bchannel's handle=%x, but handle does not exist in any mISDNport structure.\n", handle);
-                       break;
-               }
-               
-               if (type!=BCHANNEL_RELEASE) {
-                       /* ack */
-                       chan_trace_header(mISDNport, mISDNport->b_port[i], "MESSAGE_BCHANNEL (from remote application)", DIRECTION_NONE);
-                       add_trace("type", NULL, (type==BCHANNEL_ASSIGN_ACK)?"assign_ack":"remove_ack");
-                       end_trace();
-                       bchannel_event(mISDNport, i, (type==BCHANNEL_ASSIGN_ACK)?B_EVENT_EXPORTED:B_EVENT_IMPORTED);
-               } else {
-                       /* release */
-                       isdnport = mISDNport->b_port[i];
-                       chan_trace_header(mISDNport, isdnport, "MESSAGE_BCHANNEL (from remote application)", DIRECTION_NONE);
-                       add_trace("type", NULL, "import request");
-                       end_trace();
-                       if (isdnport) {
-                               isdnport->p_m_remote_ref = 0;
-                               isdnport->p_m_remote_id = 0;
-                       }
-                       bchannel_event(mISDNport, i, B_EVENT_IMPORTREQUEST);
-               }
-               break;
-               default:
-               PERROR("received wrong bchannel message type %d from remote\n", type);
-       }
-}
-
 
 /*
  * handler
 
 /*
  * handler
@@ -1204,31 +909,46 @@ on empty load, remote-audio causes the load with the remote audio to be increase
 +--------------------+----------------------+
 
  */
 +--------------------+----------------------+
 
  */
-int PmISDN::handler(void)
+void PmISDN::update_load(void)
+{
+       /* don't trigger load event if: */
+       if (!p_tone_name[0] && !p_m_crypt_msg_loops && !p_m_inband_send_on)
+               return;
+
+       /* don't trigger load event if event already active */
+       if (p_m_loadtimer.active)
+               return;
+
+       schedule_timer(&p_m_loadtimer, 0, 0); /* no delay the first time */
+}
+
+int load_timer(struct lcr_timer *timer, void *instance, int index)
+{
+       class PmISDN *isdnport = (class PmISDN *)instance;
+
+       isdnport->load_tx();
+
+       return 0;
+}
+
+void PmISDN::load_tx(void)
 {
 {
-       struct lcr_msg *message;
        int elapsed = 0;
        int ret;
        int elapsed = 0;
        int ret;
-
-       if ((ret = Port::handler()))
-               return(ret);
+       struct timeval current_time;
 
        /* get elapsed */
 
        /* get elapsed */
+       gettimeofday(&current_time, NULL);
        if (p_m_last_tv_sec) {
        if (p_m_last_tv_sec) {
-               elapsed = 8000 * (now_tv.tv_sec - p_m_last_tv_sec)
-                       + 8 * (now_tv.tv_usec/1000 - p_m_last_tv_msec);
-       } else {
-               /* set clock of first process ever in this instance */
-               p_m_last_tv_sec = now_tv.tv_sec;
-               p_m_last_tv_msec = now_tv.tv_usec/1000;
+               elapsed = 8000 * (current_time.tv_sec - p_m_last_tv_sec)
+                       + 8 * (current_time.tv_usec/1000 - p_m_last_tv_msec);
        }
        }
-       /* process only if we have a minimum of samples, to make packets not too small */
-       if (elapsed >= ISDN_TRANSMIT
-        && p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE) {
-               /* set clock of last process! */
-               p_m_last_tv_sec = now_tv.tv_sec;
-               p_m_last_tv_msec = now_tv.tv_usec/1000;
+       /* set clock of last process! */
+       p_m_last_tv_sec = current_time.tv_sec;
+       p_m_last_tv_msec = current_time.tv_usec/1000;
 
 
+       /* process only if we have samples and we are active */
+       if (elapsed && p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE) {
                /* update load */
                if (elapsed < p_m_load)
                        p_m_load -= elapsed;
                /* update load */
                if (elapsed < p_m_load)
                        p_m_load -= elapsed;
@@ -1237,7 +957,7 @@ int PmISDN::handler(void)
 
                /* to send data, tone must be on */
                if ((p_tone_name[0] || p_m_crypt_msg_loops || p_m_inband_send_on) /* what tones? */
 
                /* to send data, tone must be on */
                if ((p_tone_name[0] || p_m_crypt_msg_loops || p_m_inband_send_on) /* what tones? */
-                && (p_m_load < ISDN_LOAD) /* enough load? */
+                && (p_m_load < ISDN_LOAD) /* not too much load? */
                 && (p_state==PORT_STATE_CONNECT || p_m_mISDNport->tones || p_m_inband_send_on)) { /* connected or inband-tones? */
                        int tosend = ISDN_LOAD - p_m_load, length; 
                        unsigned char buf[MISDN_HEADER_LEN+tosend];
                 && (p_state==PORT_STATE_CONNECT || p_m_mISDNport->tones || p_m_inband_send_on)) { /* connected or inband-tones? */
                        int tosend = ISDN_LOAD - p_m_load, length; 
                        unsigned char buf[MISDN_HEADER_LEN+tosend];
@@ -1267,6 +987,8 @@ int PmISDN::handler(void)
                                        /* next loop */
                                        p_m_crypt_msg_current = 0;
                                        p_m_crypt_msg_loops--;
                                        /* next loop */
                                        p_m_crypt_msg_current = 0;
                                        p_m_crypt_msg_loops--;
+                                       if (!p_m_crypt_msg_loops)
+                                               update_rxoff();
 //                                     puts("eine loop weniger");
                                }
 
 //                                     puts("eine loop weniger");
                                }
 
@@ -1283,32 +1005,34 @@ int PmISDN::handler(void)
                        if (ISDN_LOAD - p_m_load - tosend > 0) {
                                frm->prim = PH_DATA_REQ;
                                frm->id = 0;
                        if (ISDN_LOAD - p_m_load - tosend > 0) {
                                frm->prim = PH_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);
+                               ret = sendto(p_m_mISDNport->b_sock[p_m_b_index].fd, buf, MISDN_HEADER_LEN+ISDN_LOAD-p_m_load-tosend, 0, NULL, 0);
                                if (ret <= 0)
                                if (ret <= 0)
-                                       PERROR("Failed to send to socket %d (samples = %d)\n", p_m_mISDNport->b_socket[p_m_b_index], ISDN_LOAD-p_m_load-tosend);
+                                       PERROR("Failed to send to socket %d (samples = %d)\n", p_m_mISDNport->b_sock[p_m_b_index].fd, ISDN_LOAD-p_m_load-tosend);
                                p_m_load += ISDN_LOAD - p_m_load - tosend;
                        }
                }
        }
 
                                p_m_load += ISDN_LOAD - p_m_load - tosend;
                        }
                }
        }
 
-       // NOTE: deletion is done by the child class
-
-       /* handle timeouts */
-       if (p_m_timeout) {
-               if (p_m_timer+p_m_timeout < now_d) {
-                       PDEBUG(DEBUG_ISDN, "(%s) timeout after %d seconds detected (state=%d).\n", p_name, p_m_timeout, p_state);
-                       p_m_timeout = 0;
-                       /* send timeout to endpoint */
-                       message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_TIMEOUT);
-                       message->param.state = p_state;
-                       message_put(message);
-                       return(1);
-               }
+       if (p_tone_name[0] || p_m_crypt_msg_loops || p_m_inband_send_on || p_m_load) {
+               schedule_timer(&p_m_loadtimer, 0, PORT_TRANSMIT * 125);
        }
        }
-       
-       return(0); /* nothing done */
 }
 
 }
 
+/* handle timeouts */
+static int mISDN_timeout(struct lcr_timer *timer, void *instance, int i)
+{
+       class PmISDN *isdnport = (class PmISDN *)instance;
+       struct lcr_msg *message;
+
+       PDEBUG(DEBUG_ISDN, "(%s) timeout after %d seconds detected (state=%d).\n", isdnport->p_name, isdnport->p_m_timeout.timeout.tv_sec, isdnport->p_state);
+       /* send timeout to endpoint */
+       message = message_create(isdnport->p_serial, ACTIVE_EPOINT(isdnport->p_epointlist), PORT_TO_EPOINT, MESSAGE_TIMEOUT);
+       message->param.state = isdnport->p_state;
+       message_put(message);
+
+       return 0;
+}
+       
 
 /*
  * whenever we get audio data from bchannel, we process it here
 
 /*
  * whenever we get audio data from bchannel, we process it here
@@ -1316,8 +1040,6 @@ int PmISDN::handler(void)
 void PmISDN::bchannel_receive(struct mISDNhead *hh, unsigned char *data, int len)
 {
        unsigned int cont = *((unsigned int *)data);
 void PmISDN::bchannel_receive(struct mISDNhead *hh, unsigned char *data, int len)
 {
        unsigned int cont = *((unsigned int *)data);
-       unsigned char *data_temp;
-       unsigned int length_temp;
        struct lcr_msg *message;
        unsigned char *p;
        int l;
        struct lcr_msg *message;
        unsigned char *p;
        int l;
@@ -1330,7 +1052,11 @@ void PmISDN::bchannel_receive(struct mISDNhead *hh, unsigned char *data, int len
                if ((cont&(~DTMF_TONE_MASK)) == DTMF_TONE_VAL) {
                        chan_trace_header(p_m_mISDNport, this, "BCHANNEL control", DIRECTION_IN);
                        add_trace("DTMF", NULL, "%c", cont & DTMF_TONE_MASK);
                if ((cont&(~DTMF_TONE_MASK)) == DTMF_TONE_VAL) {
                        chan_trace_header(p_m_mISDNport, this, "BCHANNEL control", DIRECTION_IN);
                        add_trace("DTMF", NULL, "%c", cont & DTMF_TONE_MASK);
+                       if (!p_m_dtmf)
+                               add_trace("info", NULL, "DTMF is disabled");
                        end_trace();
                        end_trace();
+                       if (!p_m_dtmf)
+                               return;
                        message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_DTMF);
                        message->param.dtmf = cont & DTMF_TONE_MASK;
                        PDEBUG(DEBUG_PORT, "PmISDN(%s) PH_CONTROL INDICATION  DTMF digit '%c'\n", p_name, message->param.dtmf);
                        message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_DTMF);
                        message->param.dtmf = cont & DTMF_TONE_MASK;
                        PDEBUG(DEBUG_PORT, "PmISDN(%s) PH_CONTROL INDICATION  DTMF digit '%c'\n", p_name, message->param.dtmf);
@@ -1398,6 +1124,9 @@ void PmISDN::bchannel_receive(struct mISDNhead *hh, unsigned char *data, int len
        if (p_m_inband_receive_on)
                inband_receive(data, len);
 
        if (p_m_inband_receive_on)
                inband_receive(data, len);
 
+       /* send to remote, if bridged */
+       bridge_tx(data, len);
+
        /* calls will not process any audio data unless
         * the call is connected OR tones feature is enabled.
         */
        /* calls will not process any audio data unless
         * the call is connected OR tones feature is enabled.
         */
@@ -1435,24 +1164,6 @@ void PmISDN::bchannel_receive(struct mISDNhead *hh, unsigned char *data, int len
 
                cryptman_listen_bch(data, len);
        }
 
                cryptman_listen_bch(data, len);
        }
-
-       p = data;
-
-       /* send data to epoint */
-       if (p_m_joindata && ACTIVE_EPOINT(p_epointlist)) { /* only if we have an epoint object */
-               length_temp = len;
-               data_temp = p;
-               while(length_temp) {
-                       message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_DATA);
-                       message->param.data.len = (length_temp>sizeof(message->param.data.data))?sizeof(message->param.data.data):length_temp;
-                       memcpy(message->param.data.data, data_temp, message->param.data.len);
-                       message_put(message);
-                       if (length_temp <= sizeof(message->param.data.data))
-                               break;
-                       data_temp += sizeof(message->param.data.data);
-                       length_temp -= sizeof(message->param.data.data);
-               }
-       }
 }
 
 
 }
 
 
@@ -1466,7 +1177,7 @@ void PmISDN::set_echotest(int echo)
                PDEBUG(DEBUG_ISDN, "we set echo to echo=%d.\n", p_m_echo);
                if (p_m_b_channel)
                        if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE)
                PDEBUG(DEBUG_ISDN, "we set echo to echo=%d.\n", p_m_echo);
                if (p_m_b_channel)
                        if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE)
-                               ph_control(p_m_mISDNport, this, p_m_mISDNport->b_socket[p_m_b_index], p_m_echo?DSP_ECHO_ON:DSP_ECHO_OFF, 0, "DSP-ECHO", p_m_echo);
+                               ph_control(p_m_mISDNport, this, p_m_mISDNport->b_sock[p_m_b_index].fd, p_m_echo?DSP_ECHO_ON:DSP_ECHO_OFF, 0, "DSP-ECHO", p_m_echo);
        }
 }
 
        }
 }
 
@@ -1509,7 +1220,7 @@ void PmISDN::set_tone(const char *dir, const char *tone)
                if (p_m_b_index > -1)
                if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE && p_m_mISDNport->b_mode[p_m_b_index] == B_MODE_TRANSPARENT) {
                        PDEBUG(DEBUG_ISDN, "we reset tone from id=%d to OFF.\n", p_m_tone);
                if (p_m_b_index > -1)
                if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE && p_m_mISDNport->b_mode[p_m_b_index] == B_MODE_TRANSPARENT) {
                        PDEBUG(DEBUG_ISDN, "we reset tone from id=%d to OFF.\n", p_m_tone);
-                       ph_control(p_m_mISDNport, this, p_m_mISDNport->b_socket[p_m_b_index], DSP_TONE_PATT_OFF, 0, "DSP-TONE", 0);
+                       ph_control(p_m_mISDNport, this, p_m_mISDNport->b_sock[p_m_b_index].fd, DSP_TONE_PATT_OFF, 0, "DSP-TONE", 0);
                }
                p_m_tone = 0;
                Port::set_tone(dir, tone);
                }
                p_m_tone = 0;
                Port::set_tone(dir, tone);
@@ -1581,7 +1292,7 @@ void PmISDN::set_tone(const char *dir, const char *tone)
                PDEBUG(DEBUG_ISDN, "we set tone to id=%d.\n", p_m_tone);
                if (p_m_b_index > -1)
                if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE && p_m_mISDNport->b_mode[p_m_b_index] == B_MODE_TRANSPARENT)
                PDEBUG(DEBUG_ISDN, "we set tone to id=%d.\n", p_m_tone);
                if (p_m_b_index > -1)
                if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE && p_m_mISDNport->b_mode[p_m_b_index] == B_MODE_TRANSPARENT)
-                       ph_control(p_m_mISDNport, this, p_m_mISDNport->b_socket[p_m_b_index], p_m_tone?DSP_TONE_PATT_ON:DSP_TONE_PATT_OFF, p_m_tone, "DSP-TONE", p_m_tone);
+                       ph_control(p_m_mISDNport, this, p_m_mISDNport->b_sock[p_m_b_index].fd, p_m_tone?DSP_TONE_PATT_ON:DSP_TONE_PATT_OFF, p_m_tone, "DSP-TONE", p_m_tone);
        }
        /* turn user-space tones off in cases of no tone OR dsp tone */
        Port::set_tone("",NULL);
        }
        /* turn user-space tones off in cases of no tone OR dsp tone */
        Port::set_tone("",NULL);
@@ -1600,7 +1311,7 @@ void PmISDN::message_mISDNsignal(unsigned int epoint_id, int message_id, union p
                        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 && p_m_mISDNport->b_mode[p_m_b_index] == B_MODE_TRANSPARENT)
                        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 && p_m_mISDNport->b_mode[p_m_b_index] == B_MODE_TRANSPARENT)
-                               ph_control(p_m_mISDNport, this, p_m_mISDNport->b_socket[p_m_b_index], DSP_VOL_CHANGE_TX, p_m_tx_gain, "DSP-TX_GAIN", p_m_tx_gain);
+                               ph_control(p_m_mISDNport, this, p_m_mISDNport->b_sock[p_m_b_index].fd, DSP_VOL_CHANGE_TX, p_m_tx_gain, "DSP-TX_GAIN", p_m_tx_gain);
                } else
                        PDEBUG(DEBUG_BCHANNEL, "we already have tx-volume shift=%d.\n", p_m_rx_gain);
                if (p_m_rx_gain != param->mISDNsignal.rx_gain) {
                } else
                        PDEBUG(DEBUG_BCHANNEL, "we already have tx-volume shift=%d.\n", p_m_rx_gain);
                if (p_m_rx_gain != param->mISDNsignal.rx_gain) {
@@ -1608,7 +1319,7 @@ void PmISDN::message_mISDNsignal(unsigned int epoint_id, int message_id, union p
                        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 && p_m_mISDNport->b_mode[p_m_b_index] == B_MODE_TRANSPARENT)
                        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 && p_m_mISDNport->b_mode[p_m_b_index] == B_MODE_TRANSPARENT)
-                               ph_control(p_m_mISDNport, this, p_m_mISDNport->b_socket[p_m_b_index], DSP_VOL_CHANGE_RX, p_m_rx_gain, "DSP-RX_GAIN", p_m_rx_gain);
+                               ph_control(p_m_mISDNport, this, p_m_mISDNport->b_sock[p_m_b_index].fd, DSP_VOL_CHANGE_RX, p_m_rx_gain, "DSP-RX_GAIN", p_m_rx_gain);
                } else
                        PDEBUG(DEBUG_BCHANNEL, "we already have rx-volume shift=%d.\n", p_m_rx_gain);
                break;
                } else
                        PDEBUG(DEBUG_BCHANNEL, "we already have rx-volume shift=%d.\n", p_m_rx_gain);
                break;
@@ -1620,21 +1331,13 @@ void PmISDN::message_mISDNsignal(unsigned int epoint_id, int message_id, union p
                set_conf(oldconf, newconf);
                break;
 
                set_conf(oldconf, newconf);
                break;
 
-               case mISDNSIGNAL_JOINDATA:
-               if (p_m_joindata != param->mISDNsignal.joindata) {
-                       p_m_joindata = param->mISDNsignal.joindata;
-                       PDEBUG(DEBUG_BCHANNEL, "we change to joindata=%d.\n", p_m_joindata);
-               } else
-                       PDEBUG(DEBUG_BCHANNEL, "we already have joindata=%d.\n", p_m_joindata);
-               break;
-               
                case mISDNSIGNAL_DELAY:
                if (p_m_delay != param->mISDNsignal.delay) {
                        p_m_delay = param->mISDNsignal.delay;
                        PDEBUG(DEBUG_BCHANNEL, "we change delay mode to delay=%d.\n", p_m_delay);
                        if (p_m_b_index > -1)
                        if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE && p_m_mISDNport->b_mode[p_m_b_index] == B_MODE_TRANSPARENT)
                case mISDNSIGNAL_DELAY:
                if (p_m_delay != param->mISDNsignal.delay) {
                        p_m_delay = param->mISDNsignal.delay;
                        PDEBUG(DEBUG_BCHANNEL, "we change delay mode to delay=%d.\n", p_m_delay);
                        if (p_m_b_index > -1)
                        if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE && p_m_mISDNport->b_mode[p_m_b_index] == B_MODE_TRANSPARENT)
-                               ph_control(p_m_mISDNport, this, p_m_mISDNport->b_socket[p_m_b_index], p_m_delay?DSP_DELAY:DSP_JITTER, p_m_delay, "DSP-DELAY", p_m_delay);
+                               ph_control(p_m_mISDNport, this, p_m_mISDNport->b_sock[p_m_b_index].fd, p_m_delay?DSP_DELAY:DSP_JITTER, p_m_delay, "DSP-DELAY", p_m_delay);
                } else
                        PDEBUG(DEBUG_BCHANNEL, "we already have delay=%d.\n", p_m_delay);
                break;
                } else
                        PDEBUG(DEBUG_BCHANNEL, "we already have delay=%d.\n", p_m_delay);
                break;
@@ -1665,7 +1368,7 @@ void PmISDN::message_crypt(unsigned int epoint_id, int message_id, union paramet
                PDEBUG(DEBUG_BCHANNEL, "we set encryption to crypt=%d. (0 means OFF)\n", p_m_crypt);
                if (p_m_b_index > -1)
                if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE && p_m_mISDNport->b_mode[p_m_b_index] == B_MODE_TRANSPARENT)
                PDEBUG(DEBUG_BCHANNEL, "we set encryption to crypt=%d. (0 means OFF)\n", p_m_crypt);
                if (p_m_b_index > -1)
                if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE && p_m_mISDNport->b_mode[p_m_b_index] == B_MODE_TRANSPARENT)
-                       ph_control_block(p_m_mISDNport, this, p_m_mISDNport->b_socket[p_m_b_index], p_m_crypt?DSP_BF_ENABLE_KEY:DSP_BF_DISABLE, p_m_crypt_key, p_m_crypt_key_len, "DSP-CRYPT", p_m_crypt_key_len);
+                       ph_control_block(p_m_mISDNport, this, p_m_mISDNport->b_sock[p_m_b_index].fd, p_m_crypt?DSP_BF_ENABLE_KEY:DSP_BF_DISABLE, p_m_crypt_key, p_m_crypt_key_len, "DSP-CRYPT", p_m_crypt_key_len);
                break;
 
                case CC_DACT_REQ:            /* deactivate session encryption */
                break;
 
                case CC_DACT_REQ:            /* deactivate session encryption */
@@ -1675,11 +1378,13 @@ void PmISDN::message_crypt(unsigned int epoint_id, int message_id, union paramet
 
                case CR_LISTEN_REQ:          /* start listening to messages */
                p_m_crypt_listen = 1;
 
                case CR_LISTEN_REQ:          /* start listening to messages */
                p_m_crypt_listen = 1;
+               update_rxoff();
                p_m_crypt_listen_state = 0;
                break;
 
                case CR_UNLISTEN_REQ:        /* stop listening to messages */
                p_m_crypt_listen = 0;
                p_m_crypt_listen_state = 0;
                break;
 
                case CR_UNLISTEN_REQ:        /* stop listening to messages */
                p_m_crypt_listen = 0;
+               update_rxoff();
                break;
 
                case CR_MESSAGE_REQ:         /* send message */
                break;
 
                case CR_MESSAGE_REQ:         /* send message */
@@ -1690,11 +1395,13 @@ void PmISDN::message_crypt(unsigned int epoint_id, int message_id, union paramet
                }
                p_m_crypt_msg_current = 0; /* reset */
                p_m_crypt_msg_loops = 6; /* enable */
                }
                p_m_crypt_msg_current = 0; /* reset */
                p_m_crypt_msg_loops = 6; /* enable */
+               update_rxoff();
+               update_load();
 #if 0
                /* disable txmix, or we get corrupt data due to audio process */
                if (p_m_txmix && p_m_b_index>=0 && p_m_mISDNport->b_mode[p_m_b_index] == B_MODE_TRANSPARENT) {
                        PDEBUG(DEBUG_BCHANNEL, "for sending CR_MESSAGE_REQ, we reset txmix from txmix=%d.\n", p_m_txmix);
 #if 0
                /* disable txmix, or we get corrupt data due to audio process */
                if (p_m_txmix && p_m_b_index>=0 && p_m_mISDNport->b_mode[p_m_b_index] == B_MODE_TRANSPARENT) {
                        PDEBUG(DEBUG_BCHANNEL, "for sending CR_MESSAGE_REQ, we reset txmix from txmix=%d.\n", p_m_txmix);
-                       ph_control(p_m_mISDNport, this, p_mISDNport->b_socket[p_m_b_index], DSP_MIX_OFF, 0, "DSP-TXMIX", 0);
+                       ph_control(p_m_mISDNport, this, p_mISDNport->b_sock[p_m_b_index].fd, DSP_MIX_OFF, 0, "DSP-TXMIX", 0);
                }
 #endif
                break;
                }
 #endif
                break;
@@ -1710,277 +1417,284 @@ void PmISDN::message_crypt(unsigned int epoint_id, int message_id, union paramet
  */
 int PmISDN::message_epoint(unsigned int epoint_id, int message_id, union parameter *param)
 {
  */
 int PmISDN::message_epoint(unsigned int epoint_id, int message_id, union parameter *param)
 {
-       if (Port::message_epoint(epoint_id, message_id, param))
-               return(1);
+       if (Port::message_epoint(epoint_id, message_id, param)) {
+               if (message_id == MESSAGE_BRIDGE)
+                       update_rxoff();
+               return 1;
+       }
 
        switch(message_id) {
 
        switch(message_id) {
-               case MESSAGE_DATA: /* tx-data from upper layer */
-               txfromup(param->data.data, param->data.len);
-               return(1);
-
                case MESSAGE_mISDNSIGNAL: /* user command */
                PDEBUG(DEBUG_ISDN, "PmISDN(%s) received special ISDN SIGNAL %d.\n", p_name, param->mISDNsignal.message);
                message_mISDNsignal(epoint_id, message_id, param);
                case MESSAGE_mISDNSIGNAL: /* user command */
                PDEBUG(DEBUG_ISDN, "PmISDN(%s) received special ISDN SIGNAL %d.\n", p_name, param->mISDNsignal.message);
                message_mISDNsignal(epoint_id, message_id, param);
-               return(1);
+               return 1;
 
                case MESSAGE_CRYPT: /* crypt control command */
                PDEBUG(DEBUG_ISDN, "PmISDN(%s) received encryption command '%d'.\n", p_name, param->crypt.type);
                message_crypt(epoint_id, message_id, param);
 
                case MESSAGE_CRYPT: /* crypt control command */
                PDEBUG(DEBUG_ISDN, "PmISDN(%s) received encryption command '%d'.\n", p_name, param->crypt.type);
                message_crypt(epoint_id, message_id, param);
-               return(1);
+               return 1;
        }
 
        }
 
-       return(0);
+       return 0;
 }
 
 }
 
+void PmISDN::update_rxoff(void)
+{
+       int tx_dejitter = 0;
+
+       /* call bridges in user space OR crypto OR recording */
+       if (p_bridge || p_m_crypt_msg_loops || p_m_crypt_listen || p_record || p_m_inband_receive_on) {
+               /* rx IS required */
+               if (p_m_rxoff) {
+                       /* turn on RX */
+                       p_m_rxoff = 0;
+                       PDEBUG(DEBUG_BCHANNEL, "%s: receive data is required, so we turn them on\n", __FUNCTION__);
+                       if (p_m_b_index > -1)
+                               if (p_m_mISDNport->b_port[p_m_b_index] && p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE)
+                                       ph_control(p_m_mISDNport, this, p_m_mISDNport->b_sock[p_m_b_index].fd, DSP_RECEIVE_ON, 0, "DSP-RXOFF", 0);
+               }
+       } else {
+               /* rx NOT required */
+               if (!p_m_rxoff) {
+                       /* turn off RX */
+                       p_m_rxoff = 1;
+                       PDEBUG(DEBUG_BCHANNEL, "%s: receive data is not required, so we turn them off\n", __FUNCTION__);
+                       if (p_m_b_index > -1)
+                               if (p_m_mISDNport->b_port[p_m_b_index] && p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE)
+                                       ph_control(p_m_mISDNport, this, p_m_mISDNport->b_sock[p_m_b_index].fd, DSP_RECEIVE_OFF, 0, "DSP-RXOFF", 1);
+               }
+       }
+       /* recording */
+       if (p_record) {
+               /* txdata IS required */
+               if (!p_m_txdata) {
+                       /* turn on RX */
+                       p_m_txdata = 1;
+                       PDEBUG(DEBUG_BCHANNEL, "%s: transmit data is required, so we turn them on\n", __FUNCTION__);
+                       if (p_m_b_index > -1)
+                               if (p_m_mISDNport->b_port[p_m_b_index] && p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE)
+                                       ph_control(p_m_mISDNport, this, p_m_mISDNport->b_sock[p_m_b_index].fd, DSP_TXDATA_ON, 0, "DSP-TXDATA", 1);
+               }
+       } else {
+               /* txdata NOT required */
+               if (p_m_txdata) {
+                       /* turn off RX */
+                       p_m_txdata = 0;
+                       PDEBUG(DEBUG_BCHANNEL, "%s: transmit data is not required, so we turn them off\n", __FUNCTION__);
+                       if (p_m_b_index > -1)
+                               if (p_m_mISDNport->b_port[p_m_b_index] && p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE)
+                                       ph_control(p_m_mISDNport, this, p_m_mISDNport->b_sock[p_m_b_index].fd, DSP_TXDATA_OFF, 0, "DSP-TXDATA", 0);
+               }
+       }
+       /* dejitter on bridge */
+       if (p_bridge)
+               tx_dejitter = 1;
+       if (p_m_tx_dejitter != tx_dejitter) {
+               p_m_tx_dejitter = tx_dejitter;
+               PDEBUG(DEBUG_BCHANNEL, "we change dejitter mode to delay=%d.\n", p_m_tx_dejitter);
+               if (p_m_b_index > -1)
+                       if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE && p_m_mISDNport->b_mode[p_m_b_index] == B_MODE_TRANSPARENT)
+                               ph_control(p_m_mISDNport, this, p_m_mISDNport->b_sock[p_m_b_index].fd, DSP_TX_DEJITTER, p_m_tx_dejitter, "DSP-TX_DEJITTER", p_m_tx_dejitter);
+       }
+}
 
 
-/*
- * main loop for processing messages from mISDN
- */
-int mISDN_handler(void)
+static int mISDN_upqueue(struct lcr_fd *fd, unsigned int what, void *instance, int i)
 {
 {
-       int ret, work = 0;
        struct mISDNport *mISDNport;
        struct mISDNport *mISDNport;
-       class PmISDN *isdnport;
-       int i;
-       unsigned char buffer[2048+MISDN_HEADER_LEN];
-       struct mISDNhead *hh = (struct mISDNhead *)buffer;
        struct mbuffer *mb;
        struct l3_msg *l3m;
        struct mbuffer *mb;
        struct l3_msg *l3m;
+       char byte;
+       int ret;
+
+       /* unset global semaphore */
+       upqueue_avail = 0;
+       // with a very small incident, upqueue_avail may be set by mISDN thread and
+       // another byte may be sent to the pipe, which causes a call to this function
+       // again with nothing in the upqueue. this is no problem.
+       ret = read(fd->fd, &byte, 1);
 
        /* process all ports */
        mISDNport = mISDNport_first;
        while(mISDNport) {
 
        /* process all ports */
        mISDNport = mISDNport_first;
        while(mISDNport) {
-               /* 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) {
-                               /* 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 || isdnport->p_m_inband_receive_on) {
-                                       /* 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", __FUNCTION__);
-                                               if (mISDNport->b_port[i] && mISDNport->b_state[i] == B_STATE_ACTIVE)
-                                                       ph_control(mISDNport, isdnport, mISDNport->b_socket[i], DSP_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", __FUNCTION__);
-                                               if (mISDNport->b_port[i] && mISDNport->b_state[i] == B_STATE_ACTIVE)
-                                                       ph_control(mISDNport, isdnport, mISDNport->b_socket[i], DSP_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", __FUNCTION__);
-                                               if (mISDNport->b_port[i] && mISDNport->b_state[i] == B_STATE_ACTIVE)
-                                                       ph_control(mISDNport, isdnport, mISDNport->b_socket[i], DSP_TXDATA_ON, 0, "DSP-TXDATA", 1);
-                                               return(1);
-                                       }
-                               } else {
-                                       /* txdata NOT required */
-                                       if (isdnport->p_m_txdata) {
-                                               /* turn off RX */
-                                               isdnport->p_m_txdata = 0;
-                                               PDEBUG(DEBUG_BCHANNEL, "%s: transmit data is not required, so we turn them off\n", __FUNCTION__);
-                                               if (mISDNport->b_port[i] && mISDNport->b_state[i] == B_STATE_ACTIVE)
-                                                       ph_control(mISDNport, isdnport, mISDNport->b_socket[i], DSP_TXDATA_OFF, 0, "DSP-TXDATA", 0);
-                                               return(1);
-                                       }
+               /* handle queued up-messages (d-channel) */
+               while ((mb = mdequeue(&mISDNport->upqueue))) {
+                       l3m = &mb->l3;
+                       switch(l3m->type) {
+                               case MPH_ACTIVATE_IND:
+                               if (mISDNport->l1link != 1) {
+                                       l1l2l3_trace_header(mISDNport, NULL, L1_ACTIVATE_IND, DIRECTION_IN);
+                                       end_trace();
+                                       mISDNport->l1link = 1;
                                }
                                }
-                       }
-
-                       /* 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_DATA_REQ:
-                                               case DL_DATA_REQ:
-                                               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);
+                               break;
+       
+                               case MPH_DEACTIVATE_IND:
+                               if (mISDNport->l1link != 0) {
+                                       l1l2l3_trace_header(mISDNport, NULL, L1_DEACTIVATE_IND, DIRECTION_IN);
+                                       end_trace();
+                                       mISDNport->l1link = 0;
                                }
                                }
-                       }
-                       
-                       i++;
-               }
+                               break;
 
 
-               /* handle queued up-messages (d-channel) */
-               if (!mISDNport->gsm) {
-                       while ((mb = mdequeue(&mISDNport->upqueue))) {
-                               l3m = &mb->l3;
-                               switch(l3m->type) {
-                                       case MPH_ACTIVATE_IND:
-                                       if (mISDNport->l1link != 1) {
-                                               l1l2l3_trace_header(mISDNport, NULL, L1_ACTIVATE_IND, DIRECTION_IN);
-                                               end_trace();
-                                               mISDNport->l1link = 1;
-                                       }
+                               case MPH_INFORMATION_IND:
+                               PDEBUG(DEBUG_ISDN, "Received MPH_INFORMATION_IND for port %d (%s).\n", mISDNport->portnum, mISDNport->ifport->interface->name);
+                               switch (l3m->pid) {
+                                       case L1_SIGNAL_LOS_ON:
+                                       mISDNport->los = 1;
                                        break;
                                        break;
-               
-                                       case MPH_DEACTIVATE_IND:
-                                       if (mISDNport->l1link != 0) {
-                                               l1l2l3_trace_header(mISDNport, NULL, L1_DEACTIVATE_IND, DIRECTION_IN);
-                                               end_trace();
-                                               mISDNport->l1link = 0;
-                                       }
+                                       case L1_SIGNAL_LOS_OFF:
+                                       mISDNport->los = 0;
+                                       break;
+                                       case L1_SIGNAL_AIS_ON:
+                                       mISDNport->ais = 1;
+                                       break;
+                                       case L1_SIGNAL_AIS_OFF:
+                                       mISDNport->ais = 0;
                                        break;
                                        break;
+                                       case L1_SIGNAL_RDI_ON:
+                                       mISDNport->rdi = 1;
+                                       break;
+                                       case L1_SIGNAL_RDI_OFF:
+                                       mISDNport->rdi = 0;
+                                       break;
+                                       case L1_SIGNAL_SLIP_TX:
+                                       mISDNport->slip_tx++;
+                                       break;
+                                       case L1_SIGNAL_SLIP_RX:
+                                       mISDNport->slip_rx++;
+                                       break;
+                               }
+                               break;
 
 
-                                       case MPH_INFORMATION_IND:
-                                       PDEBUG(DEBUG_ISDN, "Received MPH_INFORMATION_IND for port %d (%s).\n", mISDNport->portnum, mISDNport->ifport->interface->name);
-                                       switch (l3m->pid) {
-                                               case L1_SIGNAL_LOS_ON:
-                                               mISDNport->los = 1;
-                                               break;
-                                               case L1_SIGNAL_LOS_OFF:
-                                               mISDNport->los = 0;
-                                               break;
-                                               case L1_SIGNAL_AIS_ON:
-                                               mISDNport->ais = 1;
-                                               break;
-                                               case L1_SIGNAL_AIS_OFF:
-                                               mISDNport->ais = 0;
-                                               break;
-                                               case L1_SIGNAL_RDI_ON:
-                                               mISDNport->rdi = 1;
-                                               break;
-                                               case L1_SIGNAL_RDI_OFF:
-                                               mISDNport->rdi = 0;
-                                               break;
-                                               case L1_SIGNAL_SLIP_TX:
-                                               mISDNport->slip_tx++;
-                                               break;
-                                               case L1_SIGNAL_SLIP_RX:
-                                               mISDNport->slip_rx++;
-                                               break;
+                               case MT_L2ESTABLISH:
+                               l1l2l3_trace_header(mISDNport, NULL, L2_ESTABLISH_IND, DIRECTION_IN);
+                               add_trace("tei", NULL, "%d", l3m->pid);
+                               end_trace();
+                               mISDNport->l2link = 1;
+                               if (l3m->pid < 128)
+                                       mISDNport->l2mask[l3m->pid >> 3] |= (1 << (l3m->pid & 7));
+                               if ((!mISDNport->ntmode || mISDNport->ptp) && l3m->pid < 127) {
+                                       if (mISDNport->l2establish.active) {
+                                               unsched_timer(&mISDNport->l2establish);
+                                               PDEBUG(DEBUG_ISDN, "the link became active before l2establish timer expiry.\n");
                                        }
                                        }
-                                       break;
+                               }
+                               break;
 
 
-                                       case MT_L2ESTABLISH:
-                                       l1l2l3_trace_header(mISDNport, NULL, L2_ESTABLISH_IND, DIRECTION_IN);
+                               case MT_L2RELEASE:
+                               if (l3m->pid < 128)
+                                       mISDNport->l2mask[l3m->pid >> 3] &= ~(1 << (l3m->pid & 7));
+                               if (!mISDNport->l2establish.active) {
+                                       l1l2l3_trace_header(mISDNport, NULL, L2_RELEASE_IND, DIRECTION_IN);
                                        add_trace("tei", NULL, "%d", l3m->pid);
                                        end_trace();
                                        add_trace("tei", NULL, "%d", l3m->pid);
                                        end_trace();
-                                       mISDNport->l2link = 1;
-                                       if (l3m->pid < 128)
-                                               mISDNport->l2mask[l3m->pid >> 3] |= (1 << (l3m->pid & 7));
-                                       if ((!mISDNport->ntmode || mISDNport->ptp) && l3m->pid < 127) {
-                                               if (mISDNport->l2establish) {
-                                                       mISDNport->l2establish = 0;
-                                                       PDEBUG(DEBUG_ISDN, "the link became active before l2establish timer expiry.\n");
-                                               }
-                                       }
-                                       break;
-
-                                       case MT_L2RELEASE:
-                                       if (l3m->pid < 128)
-                                               mISDNport->l2mask[l3m->pid >> 3] &= ~(1 << (l3m->pid & 7));
-                                       if (!mISDNport->l2establish) {
-                                               l1l2l3_trace_header(mISDNport, NULL, L2_RELEASE_IND, DIRECTION_IN);
-                                               add_trace("tei", NULL, "%d", l3m->pid);
-                                               end_trace();
-                                               /* down if not nt-ptmp */ 
-                                               if (!mISDNport->ntmode || mISDNport->ptp)
-                                                       mISDNport->l2link = 0;
-                                       }
-                                       if (!mISDNport->gsm && (!mISDNport->ntmode || mISDNport->ptp) && l3m->pid < 127) {
-                                               if (!mISDNport->l2establish && mISDNport->l2hold) {
-                                                       PDEBUG(DEBUG_ISDN, "set timer and establish.\n");
-                                                       time(&mISDNport->l2establish);
-                                                       mISDNport->ml3->to_layer3(mISDNport->ml3, MT_L2ESTABLISH, 0, NULL);
-                                               }
+                                       /* down if not nt-ptmp */ 
+                                       if (!mISDNport->ntmode || mISDNport->ptp)
+                                               mISDNport->l2link = 0;
+                               }
+                               if ((!mISDNport->ntmode || mISDNport->ptp) && l3m->pid < 127) {
+                                       if (!mISDNport->l2establish.active && mISDNport->l2hold) {
+                                               PDEBUG(DEBUG_ISDN, "set timer and establish.\n");
+                                               schedule_timer(&mISDNport->l2establish, 5, 0);
+                                               mISDNport->ml3->to_layer3(mISDNport->ml3, MT_L2ESTABLISH, 0, NULL);
                                        }
                                        }
-                                       break;
-
-                                       default:
-                                       /* l3-data is sent to LCR */
-                                       stack2manager(mISDNport, l3m->type, l3m->pid, l3m);
                                }
                                }
-                               /* free message */
-                               free_l3_msg(l3m);
+                               break;
+
+                               default:
+                               /* l3-data is sent to LCR */
+                               stack2manager(mISDNport, l3m->type, l3m->pid, l3m);
                        }
                        }
+                       /* free message */
+                       free_l3_msg(l3m);
                }
                }
+               mISDNport = mISDNport->next;
+       }
+       return 0;
+}
 
 
-#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
+/* l2 establish timer fires */
+static int l2establish_timeout(struct lcr_timer *timer, void *instance, int i)
+{
+       struct mISDNport *mISDNport = (struct mISDNport *)instance;
 
 
-               /* layer 2 establish timer */
-               if (mISDNport->l2establish) {
-                       if (now-mISDNport->l2establish > 5) {
-                               mISDNport->l2establish = 0;
-                               if (!mISDNport->gsm && mISDNport->l2hold && (mISDNport->ptp || !mISDNport->ntmode)) {
+       if (mISDNport->l2hold && (mISDNport->ptp || !mISDNport->ntmode)) {
+               PDEBUG(DEBUG_ISDN, "the L2 establish timer expired, we try to establish the link portnum=%d.\n", mISDNport->portnum);
+               mISDNport->ml3->to_layer3(mISDNport->ml3, MT_L2ESTABLISH, 0, NULL);
+               schedule_timer(&mISDNport->l2establish, 5, 0); /* 5 seconds */
+       }
 
 
-//                                     PDEBUG(DEBUG_ISDN, "the L2 establish timer expired, we try to establish the link portnum=%d.\n", mISDNport->portnum);
-                                       mISDNport->ml3->to_layer3(mISDNport->ml3, MT_L2ESTABLISH, 0, NULL);
-                                       time(&mISDNport->l2establish);
-                                       return(1);
-                               }
-                       }
-               }
+       return 0;
+}
 
 
+/* handle frames from bchannel */
+static int b_sock_callback(struct lcr_fd *fd, unsigned int what, void *instance, int i)
+{
+       struct mISDNport *mISDNport = (struct mISDNport *)instance;
+       unsigned char buffer[2048+MISDN_HEADER_LEN];
+       struct mISDNhead *hh = (struct mISDNhead *)buffer;
+       int ret;
 
 
-               mISDNport = mISDNport->next;
+       ret = recv(fd->fd, buffer, sizeof(buffer), 0);
+       if (ret < 0) {
+               PERROR("read error frame, errno %d\n", errno);
+               return 0;
+       }
+       if (ret < (int)MISDN_HEADER_LEN) {
+               PERROR("read short frame, got %d, expected %d\n", ret, (int)MISDN_HEADER_LEN);
+               return 0;
        }
        }
+       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_DATA_REQ:
+               case DL_DATA_REQ:
+               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", fd->fd);
+               break;
 
 
-       /* if we received at least one b-frame, we will return 1 */
-       return(work);
+               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", fd->fd);
+               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", fd->fd);
+               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, fd->fd, ret-MISDN_HEADER_LEN);
+       }
+
+       return 0;
 }
 
 }
 
+/* process timer events for bchannel handling */
+static int b_timer_timeout(struct lcr_timer *timer, void *instance, int i)
+{
+       struct mISDNport *mISDNport = (struct mISDNport *)instance;
+
+       bchannel_event(mISDNport, i, B_EVENT_TIMEOUT);
+
+       return 0;
+}
+
+
 int do_layer3(struct mlayer3 *ml3, unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
 {
        /* IMPORTAINT:
 int do_layer3(struct mlayer3 *ml3, unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
 {
        /* IMPORTAINT:
@@ -1991,6 +1705,7 @@ int do_layer3(struct mlayer3 *ml3, unsigned int cmd, unsigned int pid, struct l3
        struct mISDNport *mISDNport = (struct mISDNport *)ml3->priv;
        struct mbuffer *mb;
 
        struct mISDNport *mISDNport = (struct mISDNport *)ml3->priv;
        struct mbuffer *mb;
 
+#ifdef OLD_MT_ASSIGN
        /* special MT_ASSIGN handling:
         *
         * if we request a PID from mlayer, we always do it while lcr is locked.
        /* special MT_ASSIGN handling:
         *
         * if we request a PID from mlayer, we always do it while lcr is locked.
@@ -2008,6 +1723,7 @@ int do_layer3(struct mlayer3 *ml3, unsigned int cmd, unsigned int pid, struct l3
                mt_assign_pid = pid;
                return(0);
        }
                mt_assign_pid = pid;
                return(0);
        }
+#endif
        /* queue message, create, if required */
        if (!l3m) {
                l3m = alloc_l3_msg();
        /* queue message, create, if required */
        if (!l3m) {
                l3m = alloc_l3_msg();
@@ -2018,6 +1734,15 @@ int do_layer3(struct mlayer3 *ml3, unsigned int cmd, unsigned int pid, struct l3
        l3m->type = cmd;
        l3m->pid = pid;
        mqueue_tail(&mISDNport->upqueue, mb);
        l3m->type = cmd;
        l3m->pid = pid;
        mqueue_tail(&mISDNport->upqueue, mb);
+       if (!upqueue_avail) {
+               // multiple threads may cause multiple calls of this section, but this
+               // results only in multiple processing of the upqueue read.
+               // this is no problem.
+               upqueue_avail = 1;
+               char byte = 0;
+               int ret;
+               ret = write(upqueue_pipe[1], &byte, 1);
+       }
        return 0;
 }
 
        return 0;
 }
 
@@ -2045,10 +1770,16 @@ int mISDN_getportbyname(int sock, int cnt, char *portname)
 /*
  * global function to add a new card (port)
  */
 /*
  * global function to add a new card (port)
  */
-struct mISDNport *mISDNport_open(int port, char *portname, int ptp, int force_nt, int te_special, int l1hold, int l2hold, struct interface *interface, int gsm, unsigned int ss5)
+struct mISDNport *mISDNport_open(struct interface_port *ifport)
 {
        int ret;
        struct mISDNport *mISDNport, **mISDNportp;
 {
        int ret;
        struct mISDNport *mISDNport, **mISDNportp;
+       int port = ifport->portnum;
+       int ptp = ifport->ptp;
+       int force_nt = ifport->nt;
+       int l1hold = ifport->l1hold;
+       int l2hold = ifport->l2hold;
+       int ss5 = ifport->ss5;
        int i, cnt;
        int pri, bri, pots;
        int nt, te;
        int i, cnt;
        int pri, bri, pots;
        int nt, te;
@@ -2068,12 +1799,9 @@ struct mISDNport *mISDNport_open(int port, char *portname, int ptp, int force_nt
                return(NULL);
        }
        if (port < 0) {
                return(NULL);
        }
        if (port < 0) {
-               port = mISDN_getportbyname(mISDNsocket, cnt, portname);
+               port = mISDN_getportbyname(mISDNsocket, cnt, ifport->portname);
                if (port < 0) {
                if (port < 0) {
-                       if (gsm)
-                               PERROR_RUNTIME("Port name '%s' not found, did you load loopback interface for GSM?.\n", portname);
-                       else
-                               PERROR_RUNTIME("Port name '%s' not found, use 'misdn_info' tool to list all existing ports.\n", portname);
+                       PERROR_RUNTIME("Port name '%s' not found, use 'misdn_info' tool to list all existing ports.\n", ifport->portname);
                        return(NULL);
                }
                // note: 'port' has still the port number
                        return(NULL);
                }
                // note: 'port' has still the port number
@@ -2186,15 +1914,15 @@ struct mISDNport *mISDNport_open(int port, char *portname, int ptp, int force_nt
        while(*mISDNportp)
                mISDNportp = &((*mISDNportp)->next);
        mISDNport = (struct mISDNport *)MALLOC(sizeof(struct mISDNport));
        while(*mISDNportp)
                mISDNportp = &((*mISDNportp)->next);
        mISDNport = (struct mISDNport *)MALLOC(sizeof(struct mISDNport));
-       if (gsm | ss5) {
-               /* gsm/ss5 link is always active */
+       add_timer(&mISDNport->l2establish, l2establish_timeout, mISDNport, 0);
+       if (ss5) {
+               /* ss5 link is always active */
                mISDNport->l1link = 1;
                mISDNport->l2link = 1;
        } else {
                mISDNport->l1link = -1;
                mISDNport->l2link = -1;
        }
                mISDNport->l1link = 1;
                mISDNport->l2link = 1;
        } else {
                mISDNport->l1link = -1;
                mISDNport->l2link = -1;
        }
-       mISDNport->gsm = gsm;
        pmemuse++;
        *mISDNportp = mISDNport;
 
        pmemuse++;
        *mISDNportp = mISDNport;
 
@@ -2206,7 +1934,7 @@ struct mISDNport *mISDNport_open(int port, char *portname, int ptp, int force_nt
        if (ss5) {
                /* try to keep interface enabled */
                l1hold = 1;
        if (ss5) {
                /* try to keep interface enabled */
                l1hold = 1;
-               l2hold = 1;
+               l2hold = 0;
        }
        /* set l2hold */
        switch (l2hold) {
        }
        /* set l2hold */
        switch (l2hold) {
@@ -2236,63 +1964,30 @@ struct mISDNport *mISDNport_open(int port, char *portname, int ptp, int force_nt
        if (l2hold) // supports layer 2 hold
               prop |= (1 << MISDN_FLG_L2_HOLD);
        /* open layer 3 and init upqueue */
        if (l2hold) // supports layer 2 hold
               prop |= (1 << MISDN_FLG_L2_HOLD);
        /* open layer 3 and init upqueue */
-       if (gsm) {
-               unsigned long on = 1;
-               struct sockaddr_mISDN addr;
-
-               if (devinfo.nrbchan < 8) {
-                       PERROR_RUNTIME("GSM port %d must have at least 8 b-channels.\n", port);
-                       mISDNport_close(mISDNport);
-                       return(NULL);
-               }
-
-               if ((mISDNport->lcr_sock = socket(PF_ISDN, SOCK_DGRAM, ISDN_P_NT_S0)) < 0) {
-                       PERROR_RUNTIME("GSM port %d failed to open socket.\n", port);
-                       mISDNport_close(mISDNport);
-                       return(NULL);
-               }
-               /* set nonblocking io */
-               if (ioctl(mISDNport->lcr_sock, FIONBIO, &on) < 0) {
-                       PERROR_RUNTIME("GSM port %d failed to set socket into nonblocking io.\n", port);
-                       mISDNport_close(mISDNport);
-                       return(NULL);
-               }
-               /* bind socket to dchannel */
-               memset(&addr, 0, sizeof(addr));
-               addr.family = AF_ISDN;
-               addr.dev = port;
-               addr.channel = 0;
-               if (bind(mISDNport->lcr_sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
-                       PERROR_RUNTIME("GSM port %d failed to bind socket. (errno %d)\n", port, errno);
-                       mISDNport_close(mISDNport);
-                       return(NULL);
-               }
-       } else {
-               /* queue must be initializes, because l3-thread may send messages during open_layer3() */
-               mqueue_init(&mISDNport->upqueue);
-               mISDNport->ml3 = open_layer3(port, protocol, prop , do_layer3, mISDNport);
-               if (!mISDNport->ml3) {
-                       mqueue_purge(&mISDNport->upqueue);
-                       PERROR_RUNTIME("open_layer3() failed for port %d\n", port);
-                       start_trace(port,
-                               interface,
-                               NULL,
-                               NULL,
-                               DIRECTION_NONE,
-                               CATEGORY_CH,
-                               0,
-                               "PORT (open failed)");
-                       end_trace();
-                       mISDNport_close(mISDNport);
-                       return(NULL);
-               }
+       /* queue must be initializes, because l3-thread may send messages during open_layer3() */
+       mqueue_init(&mISDNport->upqueue);
+       mISDNport->ml3 = open_layer3(port, protocol, prop , do_layer3, mISDNport);
+       if (!mISDNport->ml3) {
+               mqueue_purge(&mISDNport->upqueue);
+               PERROR_RUNTIME("open_layer3() failed for port %d\n", port);
+               start_trace(port,
+                       ifport->interface,
+                       NULL,
+                       NULL,
+                       DIRECTION_NONE,
+                       CATEGORY_CH,
+                       0,
+                       "PORT (open failed)");
+               end_trace();
+               mISDNport_close(mISDNport);
+               return(NULL);
        }
 
        SCPY(mISDNport->name, devinfo.name);
        mISDNport->b_num = devinfo.nrbchan;
        mISDNport->portnum = port;
        mISDNport->ntmode = nt;
        }
 
        SCPY(mISDNport->name, devinfo.name);
        mISDNport->b_num = devinfo.nrbchan;
        mISDNport->portnum = port;
        mISDNport->ntmode = nt;
-       mISDNport->tespecial = te_special;
+       mISDNport->tespecial = ifport->tespecial;
        mISDNport->pri = pri;
        mISDNport->ptp = ptp;
        mISDNport->l1hold = l1hold;
        mISDNport->pri = pri;
        mISDNport->ptp = ptp;
        mISDNport->l1hold = l1hold;
@@ -2302,17 +1997,17 @@ struct mISDNport *mISDNport_open(int port, char *portname, int ptp, int force_nt
        i = 0;
        while(i < mISDNport->b_num) {
                mISDNport->b_state[i] = B_STATE_IDLE;
        i = 0;
        while(i < mISDNport->b_num) {
                mISDNport->b_state[i] = B_STATE_IDLE;
-               mISDNport->b_socket[i] = -1;
+               add_timer(&mISDNport->b_timer[i], b_timer_timeout, mISDNport, i);
                i++;
        }
 
        /* if ptp, pull up the link */
                i++;
        }
 
        /* if ptp, pull up the link */
-       if (!mISDNport->gsm && mISDNport->l2hold && (mISDNport->ptp || !mISDNport->ntmode)) {
+       if (mISDNport->l2hold && (mISDNport->ptp || !mISDNport->ntmode)) {
                mISDNport->ml3->to_layer3(mISDNport->ml3, MT_L2ESTABLISH, 0, NULL);
                l1l2l3_trace_header(mISDNport, NULL, L2_ESTABLISH_REQ, DIRECTION_OUT);
                add_trace("tei", NULL, "%d", 0);
                end_trace();
                mISDNport->ml3->to_layer3(mISDNport->ml3, MT_L2ESTABLISH, 0, NULL);
                l1l2l3_trace_header(mISDNport, NULL, L2_ESTABLISH_REQ, DIRECTION_OUT);
                add_trace("tei", NULL, "%d", 0);
                end_trace();
-               time(&mISDNport->l2establish);
+               schedule_timer(&mISDNport->l2establish, 5, 0); /* 5 seconds */
        }
 
        /* for nt-mode ptmp the link is always up */
        }
 
        /* for nt-mode ptmp the link is always up */
@@ -2322,7 +2017,7 @@ struct mISDNport *mISDNport_open(int port, char *portname, int ptp, int force_nt
        PDEBUG(DEBUG_BCHANNEL, "using 'mISDN_dsp.o' module\n");
 
        start_trace(mISDNport->portnum,
        PDEBUG(DEBUG_BCHANNEL, "using 'mISDN_dsp.o' module\n");
 
        start_trace(mISDNport->portnum,
-                   interface,
+                   ifport->interface,
                    NULL,
                    NULL,
                    DIRECTION_NONE,
                    NULL,
                    NULL,
                    DIRECTION_NONE,
@@ -2408,26 +2103,24 @@ void mISDNport_close(struct mISDNport *mISDNport)
        /* free bchannels */
        i = 0;
        while(i < mISDNport->b_num) {
        /* free bchannels */
        i = 0;
        while(i < mISDNport->b_num) {
-               if (mISDNport->b_socket[i] > -1) {
+               if (mISDNport->b_sock[i].inuse) {
                        _bchannel_destroy(mISDNport, i);
                        PDEBUG(DEBUG_BCHANNEL, "freeing %s port %d bchannel (index %d).\n", (mISDNport->ntmode)?"NT":"TE", mISDNport->portnum, i);
                }
                        _bchannel_destroy(mISDNport, i);
                        PDEBUG(DEBUG_BCHANNEL, "freeing %s port %d bchannel (index %d).\n", (mISDNport->ntmode)?"NT":"TE", mISDNport->portnum, i);
                }
+               if (mISDNport->b_timer[i].inuse) {
+                       del_timer(&mISDNport->b_timer[i]);
+               }
                i++;
        }
                i++;
        }
+       del_timer(&mISDNport->l2establish);
 
        /* close layer 3, if open */
 
        /* close layer 3, if open */
-       if (!mISDNport->gsm && mISDNport->ml3) {
+       if (mISDNport->ml3) {
                close_layer3(mISDNport->ml3);
        }
 
                close_layer3(mISDNport->ml3);
        }
 
-       /* close gsm socket, if open */
-       if (mISDNport->gsm && mISDNport->lcr_sock > -1) {
-               close(mISDNport->lcr_sock);
-       }
-
        /* purge upqueue */
        /* purge upqueue */
-       if (!mISDNport->gsm)
-               mqueue_purge(&mISDNport->upqueue);
+       mqueue_purge(&mISDNport->upqueue);
 
        /* remove from list */
        mISDNportp = &mISDNport_first;
 
        /* remove from list */
        mISDNportp = &mISDNport_first;
@@ -2452,51 +2145,54 @@ void mISDNport_close(struct mISDNport *mISDNport)
 /*
  * enque data from upper buffer
  */
 /*
  * enque data from upper buffer
  */
-void PmISDN::txfromup(unsigned char *data, int length)
+int PmISDN::bridge_rx(unsigned char *data, int length)
 {
        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)
 {
        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;
+               return -EIO;
        if (p_m_mISDNport->b_state[p_m_b_index] != B_STATE_ACTIVE)
        if (p_m_mISDNport->b_state[p_m_b_index] != B_STATE_ACTIVE)
-               return;
+               return -EINVAL;
 
        /* check if high priority tones exist
         * ignore data in this case
         */
        if (p_tone_name[0] || p_m_crypt_msg_loops || p_m_inband_send_on)
 
        /* check if high priority tones exist
         * ignore data in this case
         */
        if (p_tone_name[0] || p_m_crypt_msg_loops || p_m_inband_send_on)
-               return;
+               return -EBUSY;
 
        /* preload procedure
         * if transmit buffer in DSP module is empty,
         * preload it to DSP_LOAD to prevent jitter gaps.
         */
 
        /* preload procedure
         * if transmit buffer in DSP module is empty,
         * preload it to DSP_LOAD to prevent jitter gaps.
         */
-       if (p_m_load==0 && ISDN_LOAD>0) {
+       if (p_m_load == 0 && ISDN_LOAD > 0) {
                hh->prim = PH_DATA_REQ; 
                hh->id = 0;
                hh->prim = PH_DATA_REQ; 
                hh->id = 0;
-               memset(buf+MISDN_HEADER_LEN, (options.law=='a')?0x2a:0xff, ISDN_LOAD);
-               ret = sendto(p_m_mISDNport->b_socket[p_m_b_index], buf, MISDN_HEADER_LEN+ISDN_LOAD, 0, NULL, 0);
+               memset(buf+MISDN_HEADER_LEN, silence, ISDN_LOAD);
+               ret = sendto(p_m_mISDNport->b_sock[p_m_b_index].fd, buf, MISDN_HEADER_LEN+ISDN_LOAD, 0, NULL, 0);
                if (ret <= 0)
                if (ret <= 0)
-                       PERROR("Failed to send to socket %d\n", p_m_mISDNport->b_socket[p_m_b_index]);
+                       PERROR("Failed to send to socket %d\n", p_m_mISDNport->b_sock[p_m_b_index].fd);
                p_m_load += ISDN_LOAD;
                p_m_load += ISDN_LOAD;
+               schedule_timer(&p_m_loadtimer, 0, PORT_TRANSMIT * 125);
        }
 
        /* drop if load would exceed ISDN_MAXLOAD
         * this keeps the delay not too high
         */
        if (p_m_load+length > ISDN_MAXLOAD)
        }
 
        /* drop if load would exceed ISDN_MAXLOAD
         * this keeps the delay not too high
         */
        if (p_m_load+length > ISDN_MAXLOAD)
-               return;
+               return -EINVAL;
 
        /* make and send frame */
        hh->prim = PH_DATA_REQ;
        hh->id = 0;
        memcpy(buf+MISDN_HEADER_LEN, data, length);
 
        /* make and send frame */
        hh->prim = PH_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);
+       ret = sendto(p_m_mISDNport->b_sock[p_m_b_index].fd, buf, MISDN_HEADER_LEN+length, 0, NULL, 0);
        if (ret <= 0)
        if (ret <= 0)
-               PERROR("Failed to send to socket %d\n", p_m_mISDNport->b_socket[p_m_b_index]);
+               PERROR("Failed to send to socket %d\n", p_m_mISDNport->b_sock[p_m_b_index].fd);
        p_m_load += length;
        p_m_load += length;
+
+       return 0;
 }
 
 int PmISDN::inband_send(unsigned char *buffer, int len)
 }
 
 int PmISDN::inband_send(unsigned char *buffer, int len)
@@ -2509,6 +2205,8 @@ void PmISDN::inband_send_on(void)
 {
        PDEBUG(DEBUG_PORT, "turning inband signalling send on.\n");
        p_m_inband_send_on = 1;
 {
        PDEBUG(DEBUG_PORT, "turning inband signalling send on.\n");
        p_m_inband_send_on = 1;
+       /* trigger inband transmit */
+       update_load();
 }
 
 void PmISDN::inband_send_off(void)
 }
 
 void PmISDN::inband_send_off(void)
@@ -2530,12 +2228,14 @@ void PmISDN::inband_receive_on(void)
        /* this must work during constructor, see ss5.cpp */
        PDEBUG(DEBUG_PORT, "turning inband signalling receive on.\n");
        p_m_inband_receive_on = 1;
        /* this must work during constructor, see ss5.cpp */
        PDEBUG(DEBUG_PORT, "turning inband signalling receive on.\n");
        p_m_inband_receive_on = 1;
+       update_rxoff();
 }
 
 void PmISDN::inband_receive_off(void)
 {
        PDEBUG(DEBUG_PORT, "turning inband signalling receive off.\n");
        p_m_inband_receive_on = 0;
 }
 
 void PmISDN::inband_receive_off(void)
 {
        PDEBUG(DEBUG_PORT, "turning inband signalling receive off.\n");
        p_m_inband_receive_on = 0;
+       update_rxoff();
 }
 
 void PmISDN::mute_on(void)
 }
 
 void PmISDN::mute_on(void)