backup
[lcr.git] / mISDN.cpp
index cf70697..4f6f678 100644 (file)
--- a/mISDN.cpp
+++ b/mISDN.cpp
@@ -141,9 +141,9 @@ void chan_trace_header(struct mISDNport *mISDNport, class PmISDN *port, char *ms
 {
        /* init trace with given values */
        start_trace(mISDNport?mISDNport->portnum:0,
-                   mISDNport?mISDNport->ifport->interface:NULL,
+                   (mISDNport)?((mISDNport->ifport)?mISDNport->ifport->interface:NULL):NULL,
                    port?numberrize_callerinfo(port->p_callerinfo.id, port->p_callerinfo.ntype):NULL,
-                   port?port->p_dialinginfo.number:NULL,
+                   port?port->p_dialinginfo.id:NULL,
                    direction,
                    CATEGORY_CH,
                    port?port->p_serial:0,
@@ -245,7 +245,7 @@ void l1l2l3_trace_header(struct mISDNport *mISDNport, class PmISDN *port, unsign
        start_trace(mISDNport?mISDNport->portnum:0,
                    mISDNport?mISDNport->ifport->interface:NULL,
                    port?numberrize_callerinfo(port->p_callerinfo.id, port->p_callerinfo.ntype):NULL,
-                   port?port->p_dialinginfo.number:NULL,
+                   port?port->p_dialinginfo.id:NULL,
                    direction,
                    CATEGORY_CH,
                    port?port->p_serial:0,
@@ -304,15 +304,15 @@ static int _bchannel_create(struct mISDNport *mISDNport, int i)
        mISDN_pid_t pid;
        int ret;
 
-       if (mISDNport->b_stid[i])
+       if (!mISDNport->b_stid[i])
        {
-               PERROR("Error: no stack for index");
-               return(-1);
+               PERROR("Error: no stack for index %d\n", i);
+               return(0);
        }
        if (mISDNport->b_addr[i])
        {
-               PERROR("Error: stack already created");
-               return(-1);
+               PERROR("Error: stack already created for index %d\n", i);
+               return(0);
        }
 
        /* create new layer */
@@ -363,15 +363,15 @@ static int _bchannel_create(struct mISDNport *mISDNport, int i)
                goto stack_error;
        chan_trace_header(mISDNport, mISDNport->b_port[i], "BCHANNEL create stack", DIRECTION_OUT);
        add_trace("channel", NULL, "%d", i+1+(i>=15));
-       add_trace("stack", "id", "%d", mISDNport->b_stid[i]);
-       add_trace("stack", "address", "%d", mISDNport->b_addr[i]);
+       add_trace("stack", "id", "0x%8x", mISDNport->b_stid[i]);
+       add_trace("stack", "address", "0x%8x", mISDNport->b_addr[i]);
        end_trace();
 
-       return(0);
+       return(1);
 
 failed:
        mISDNport->b_addr[i] = 0;
-       return(-1);
+       return(0);
 }
 
 
@@ -444,13 +444,12 @@ static void _bchannel_configure(struct mISDNport *mISDNport, int i)
 static void _bchannel_deactivate(struct mISDNport *mISDNport, int i)
 {
        iframe_t dact;
-       int addr;
        
        chan_trace_header(mISDNport, mISDNport->b_port[i], "BCHANNEL deactivate", DIRECTION_OUT);
        add_trace("channel", NULL, "%d", i+1+(i>=15));
        end_trace();
        dact.prim = DL_RELEASE | REQUEST; 
-       dact.addr = addr | FLG_MSG_DOWN;
+       dact.addr = mISDNport->b_addr[i] | FLG_MSG_DOWN;
        dact.dinfo = 0;
        dact.len = 0;
        mISDN_write(mISDNdevice, &dact, mISDN_HEADER_LEN+dact.len, TIMEOUT_1SEC);
@@ -466,8 +465,8 @@ static void _bchannel_destroy(struct mISDNport *mISDNport, int i)
 
        chan_trace_header(mISDNport, mISDNport->b_port[i], "BCHANNEL remove stack", DIRECTION_OUT);
        add_trace("channel", NULL, "%d", i+1+(i>=15));
-       add_trace("stack", "id", "%d", mISDNport->b_stid[i]);
-       add_trace("stack", "address", "%d", mISDNport->b_addr[i]);
+       add_trace("stack", "id", "0x%8x", mISDNport->b_stid[i]);
+       add_trace("stack", "address", "0x%8x", mISDNport->b_addr[i]);
        end_trace();
        /* remove our stack only if set */
        PDEBUG(DEBUG_BCHANNEL, "free stack (b_addr=0x%x)\n", mISDNport->b_addr[i]);
@@ -533,14 +532,14 @@ All actions taken on these events depend on the current bchannel's state and if
 void bchannel_event(struct mISDNport *mISDNport, int i, int event)
 {
        int state = mISDNport->b_state[i];
-       
+
        switch(event)
        {
                case B_EVENT_ACTIVATE:
-               /* port may not be used by any other bchannel */
-               if (mISDNport->b_port[i])
+               /* port must be linked in order to allow activation */
+               if (!mISDNport->b_port[i])
                {
-                       PERROR("SOFTWARE ERROR: bchannel must not be linked to a Port class\n");
+                       PERROR("SOFTWARE ERROR: bchannel must be linked to a Port class\n");
                        exit(-1);
                }
                switch(state)
@@ -621,11 +620,15 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
                break;
 
                case B_EVENT_DEACTIVATED:
-               _bchannel_destroy(mISDNport, i);
-               state = B_STATE_IDLE;
                switch(state)
                {
+                       case B_STATE_IDLE:
+                       /* ignore due to deactivation confirm after unloading */
+                       break;
+
                        case B_STATE_DEACTIVATING:
+                       _bchannel_destroy(mISDNport, i);
+                       state = B_STATE_IDLE;
                        if (mISDNport->b_port[i])
                        {
                                /* bchannel is now deactivate, but is requied by Port class, so we reactivate */
@@ -775,7 +778,7 @@ int PmISDN::handler(void)
 
        inbuffer = (p_m_fromup_buffer_writep - p_m_fromup_buffer_readp) & FROMUP_BUFFER_MASK;
        /* send tone data to isdn device only if we have data */
-       if (p_tone_fh>=0 || p_tone_fetched || p_m_crypt_msg_loops || inbuffer)
+       if (p_tone_name[0] || p_m_crypt_msg_loops || inbuffer)
        {
                /* calculate how much to transmit */
                if (!p_last_tv_sec)
@@ -793,13 +796,14 @@ int PmISDN::handler(void)
                }
                if (elapsed >= ISDN_TRANSMIT)
                {
-                       unsigned char buf[mISDN_HEADER_LEN+ISDN_PRELOAD], *p = buf;
+                       unsigned char buf[mISDN_HEADER_LEN+ISDN_PRELOAD];
                        iframe_t *frm = (iframe_t *)buf;
+                       unsigned char *p = buf+mISDN_HEADER_LEN;
 
                        p_last_tv_sec = now_tv.tv_sec;
                        p_last_tv_msec = now_tv.tv_usec/1000;
 
-                       /* read tones */
+                       /* read tones or fill with silence */
                        length = read_audio(p, elapsed);
 
                        /*
@@ -810,6 +814,7 @@ int PmISDN::handler(void)
                         */
                        if (inbuffer)
                        {
+                               printf("nix\n");
                                /* inbuffer might be less than we skip due to audio */
                                if (inbuffer <= length)
                                {
@@ -840,6 +845,7 @@ int PmISDN::handler(void)
                        /* overwrite buffer with crypto stuff */
                        if (p_m_crypt_msg_loops)
                        {
+                               printf("nix2\n");
                                /* send pending message */
                                int tosend;
 
@@ -853,7 +859,7 @@ int PmISDN::handler(void)
                                        length = tosend;
 
                                /* copy message (part) to buffer */
-                               memcpy(buf, p_m_crypt_msg+p_m_crypt_msg_current, tosend);
+                               memcpy(p, p_m_crypt_msg+p_m_crypt_msg_current, tosend);
                                p_m_crypt_msg_current += tosend;
                                if (p_m_crypt_msg_current == p_m_crypt_msg_len)
                                {
@@ -865,7 +871,6 @@ int PmISDN::handler(void)
                        frm->addr = p_m_mISDNport->b_addr[p_m_b_index] | FLG_MSG_DOWN;
                        frm->dinfo = 0;
                        frm->len = length;
-                       memcpy(&frm->data.p, buf, length);
                        mISDN_write(mISDNdevice, frm, mISDN_HEADER_LEN+frm->len, TIMEOUT_1SEC);
 
                        if (p_debug_nothingtosend)
@@ -999,7 +1004,7 @@ void PmISDN::bchannel_receive(iframe_t *frm)
                }
                return;
        }       
-       if (frm->prim != (PH_DATA | INDICATION))
+       if (frm->prim != (PH_DATA | INDICATION) && frm->prim != (DL_DATA | INDICATION))
        {
                PERROR("Bchannel received unknown primitve: 0x%x\n", frm->prim);
                return;
@@ -1009,7 +1014,7 @@ void PmISDN::bchannel_receive(iframe_t *frm)
         * the call is connected OR tones feature is enabled.
         */
        if (p_state!=PORT_STATE_CONNECT
-        && !p_m_mISDNport->is_tones)
+        && !p_m_mISDNport->tones)
                return;
 
 #if 0
@@ -1501,6 +1506,10 @@ int mISDN_handler(void)
                mISDNport = mISDNport->next;
        } 
 
+       /* no device, no read */
+       if (mISDNdevice < 0)
+               return(0);
+
        /* get message from kernel */
        if (!(msg = alloc_msg(MAX_MSG_SIZE)))
                return(1);
@@ -1525,249 +1534,265 @@ int mISDN_handler(void)
        /* global prim */
        switch(frm->prim)
        {
+               case MGR_DELLAYER | CONFIRM:
                case MGR_INITTIMER | CONFIRM:
                case MGR_ADDTIMER | CONFIRM:
                case MGR_DELTIMER | CONFIRM:
                case MGR_REMOVETIMER | CONFIRM:
-//             if (options.deb & DEBUG_ISDN)
-//                     PDEBUG(DEBUG_ISDN, "timer-confirm\n");
                free_msg(msg);
                return(1);
        }
 
-       /* find the port */
-       mISDNport = mISDNport_first;
-       while(mISDNport)
+       /* handle timer events from mISDN for NT-stack
+        * note: they do not associate with a stack */
+       if (frm->prim == (MGR_TIMER | INDICATION))
        {
-               if ((frm->prim==(MGR_TIMER | INDICATION)) && mISDNport->ntmode)
-               {
-                       itimer_t *it = mISDNport->nst.tlist;
+               itimer_t *it;
 
-                       /* find timer */
-                       while(it)
+               /* find mISDNport */
+               mISDNport = mISDNport_first;
+               while(mISDNport)
+               {
+                       /* nt mode only */
+                       if (mISDNport->ntmode)
                        {
-                               if (it->id == (int)frm->addr)
+                               it = mISDNport->nst.tlist;
+                               /* find timer */
+                               while(it)
+                               {
+                                       if (it->id == (int)frm->addr)
+                                               break;
+                                       it = it->next;
+                               }
+                               if (it)
                                        break;
-                               it = it->next;
                        }
-                       if (it)
-                       {
-                               mISDN_write_frame(mISDNdevice, msg->data, mISDNport->upper_id | FLG_MSG_DOWN,
-                                       MGR_TIMER | RESPONSE, 0, 0, NULL, TIMEOUT_1SEC);
-
-                               PDEBUG(DEBUG_ISDN, "timer-indication %s port %d it=%p\n", (mISDNport->ntmode)?"NT":"TE", mISDNport->portnum, it);
-                               test_and_clear_bit(FLG_TIMER_RUNING, (long unsigned int *)&it->Flags);
-                               ret = it->function(it->data);
-                               break;
-                       }
-                       /* we will continue here because we have a timer for a different mISDNport */
+                       mISDNport = mISDNport->next;
                }
-//printf("comparing frm->addr %x with upper_id %x\n", frm->addr, mISDNport->upper_id);
-               if ((frm->addr&STACK_ID_MASK) == (unsigned int)(mISDNport->upper_id&STACK_ID_MASK))
+               if (mISDNport)
                {
-                       /* d-message */
-                       switch(frm->prim)
-                       {
-                               case MGR_SHORTSTATUS | INDICATION:
-                               case MGR_SHORTSTATUS | CONFIRM:
-                               switch(frm->dinfo) {
-                                       case SSTATUS_L1_ACTIVATED:
-                                       l1l2l3_trace_header(mISDNport, NULL, PH_ACTIVATE | (frm->prim & 0x3), DIRECTION_IN);
-                                       end_trace();
-                                       goto ss_act;
-                                       case SSTATUS_L1_DEACTIVATED:
-                                       l1l2l3_trace_header(mISDNport, NULL, PH_DEACTIVATE | (frm->prim & 0x3), DIRECTION_IN);
-                                       end_trace();
-                                       goto ss_deact;
-                                       case SSTATUS_L2_ESTABLISHED:
-                                       l1l2l3_trace_header(mISDNport, NULL, DL_ESTABLISH | (frm->prim & 0x3), DIRECTION_IN);
-                                       end_trace();
-                                       goto ss_estab;
-                                       case SSTATUS_L2_RELEASED:
-                                       l1l2l3_trace_header(mISDNport, NULL, DL_RELEASE | (frm->prim & 0x3), DIRECTION_IN);
-                                       end_trace();
-                                       goto ss_rel;
-                               }
-                               break;
+                       mISDN_write_frame(mISDNdevice, msg->data, mISDNport->upper_id | FLG_MSG_DOWN,
+                               MGR_TIMER | RESPONSE, 0, 0, NULL, TIMEOUT_1SEC);
+
+                       PDEBUG(DEBUG_ISDN, "timer-indication port %d it=%p\n", mISDNport->portnum, it);
+                       test_and_clear_bit(FLG_TIMER_RUNING, (long unsigned int *)&it->Flags);
+                       ret = it->function(it->data);
+               } else
+               {
+                       PDEBUG(DEBUG_ISDN, "timer-indication not handled\n");
+               }
+               goto out;
+       }
+
+       /* find the mISDNport that belongs to the stack */
+       mISDNport = mISDNport_first;
+       while(mISDNport)
+       {
+               if ((frm->addr&MASTER_ID_MASK) == (unsigned int)(mISDNport->upper_id&MASTER_ID_MASK))
+                       break;
+               mISDNport = mISDNport->next;
+       } 
+       if (!mISDNport)
+       {
+               PERROR("message belongs to no mISDNport: prim(0x%x) addr(0x%x) msg->len(%d)\n", frm->prim, frm->addr, msg->len);
+               goto out;
+       }
 
-                               case PH_ACTIVATE | CONFIRM:
-                               case PH_ACTIVATE | INDICATION:
-                               l1l2l3_trace_header(mISDNport, NULL, frm->prim, DIRECTION_IN);
+       /* master stack */
+       if (!(frm->addr&FLG_CHILD_STACK))
+       {
+               /* d-message */
+               switch(frm->prim)
+               {
+                       case MGR_SHORTSTATUS | INDICATION:
+                       case MGR_SHORTSTATUS | CONFIRM:
+                       switch(frm->dinfo) {
+                               case SSTATUS_L1_ACTIVATED:
+                               l1l2l3_trace_header(mISDNport, NULL, PH_ACTIVATE | (frm->prim & 0x3), DIRECTION_IN);
                                end_trace();
-                               if (mISDNport->ntmode)
-                               {
-                                       mISDNport->l1link = 1;
-                                       setup_queue(mISDNport, 1);
-                                       goto l1_msg;
-                               }
-                               ss_act:
+                               goto ss_act;
+                               case SSTATUS_L1_DEACTIVATED:
+                               l1l2l3_trace_header(mISDNport, NULL, PH_DEACTIVATE | (frm->prim & 0x3), DIRECTION_IN);
+                               end_trace();
+                               goto ss_deact;
+                               case SSTATUS_L2_ESTABLISHED:
+                               l1l2l3_trace_header(mISDNport, NULL, DL_ESTABLISH | (frm->prim & 0x3), DIRECTION_IN);
+                               end_trace();
+                               goto ss_estab;
+                               case SSTATUS_L2_RELEASED:
+                               l1l2l3_trace_header(mISDNport, NULL, DL_RELEASE | (frm->prim & 0x3), DIRECTION_IN);
+                               end_trace();
+                               goto ss_rel;
+                       }
+                       break;
+
+                       case PH_ACTIVATE | CONFIRM:
+                       case PH_ACTIVATE | INDICATION:
+                       l1l2l3_trace_header(mISDNport, NULL, frm->prim, DIRECTION_IN);
+                       end_trace();
+                       if (mISDNport->ntmode)
+                       {
                                mISDNport->l1link = 1;
                                setup_queue(mISDNport, 1);
-                               break;
+                               goto l1_msg;
+                       }
+                       ss_act:
+                       mISDNport->l1link = 1;
+                       setup_queue(mISDNport, 1);
+                       break;
 
-                               case PH_DEACTIVATE | CONFIRM:
-                               case PH_DEACTIVATE | INDICATION:
-                               l1l2l3_trace_header(mISDNport, NULL, frm->prim, DIRECTION_IN);
-                               end_trace();
-                               if (mISDNport->ntmode)
-                               {
-                                       mISDNport->l1link = 0;
-                                       setup_queue(mISDNport, 0);
-                                       goto l1_msg;
-                               }
-                               ss_deact:
+                       case PH_DEACTIVATE | CONFIRM:
+                       case PH_DEACTIVATE | INDICATION:
+                       l1l2l3_trace_header(mISDNport, NULL, frm->prim, DIRECTION_IN);
+                       end_trace();
+                       if (mISDNport->ntmode)
+                       {
                                mISDNport->l1link = 0;
                                setup_queue(mISDNport, 0);
-                               break;
-
-                               case PH_CONTROL | CONFIRM:
-                               case PH_CONTROL | INDICATION:
-                               PDEBUG(DEBUG_ISDN, "Received PH_CONTROL for port %d (%s).\n", mISDNport->portnum, mISDNport->ifport->interface->name);
-                               break;
+                               goto l1_msg;
+                       }
+                       ss_deact:
+                       mISDNport->l1link = 0;
+                       setup_queue(mISDNport, 0);
+                       break;
 
-                               case DL_ESTABLISH | INDICATION:
-                               case DL_ESTABLISH | CONFIRM:
-                               l1l2l3_trace_header(mISDNport, NULL, frm->prim, DIRECTION_IN);
-                               end_trace();
-                               if (!mISDNport->ntmode) break; /* !!!!!!!!!!!!!!!! */
-                               ss_estab:
-                               if (mISDNport->l2establish)
-                               {
-                                       mISDNport->l2establish = 0;
-                                       PDEBUG(DEBUG_ISDN, "the link became active before l2establish timer expiry.\n");
-                               }
-                               mISDNport->l2link = 1;
-                               break;
+                       case PH_CONTROL | CONFIRM:
+                       case PH_CONTROL | INDICATION:
+                       PDEBUG(DEBUG_ISDN, "Received PH_CONTROL for port %d (%s).\n", mISDNport->portnum, mISDNport->ifport->interface->name);
+                       break;
 
-                               case DL_RELEASE | INDICATION:
-                               case DL_RELEASE | CONFIRM:
-                               l1l2l3_trace_header(mISDNport, NULL, frm->prim, DIRECTION_IN);
-                               end_trace();
-                               if (!mISDNport->ntmode) break; /* !!!!!!!!!!!!!!!! */
-                               ss_rel:
-                               mISDNport->l2link = 0;
-                               if (mISDNport->ptp)
-                               {
-                                       time(&mISDNport->l2establish);
-                                       PDEBUG(DEBUG_ISDN, "because we are ptp, we set a l2establish timer.\n");
-                               }
-                               break;
+                       case DL_ESTABLISH | INDICATION:
+                       case DL_ESTABLISH | CONFIRM:
+                       l1l2l3_trace_header(mISDNport, NULL, frm->prim, DIRECTION_IN);
+                       end_trace();
+                       if (!mISDNport->ntmode) break; /* !!!!!!!!!!!!!!!! */
+                       ss_estab:
+                       if (mISDNport->l2establish)
+                       {
+                               mISDNport->l2establish = 0;
+                               PDEBUG(DEBUG_ISDN, "the link became active before l2establish timer expiry.\n");
+                       }
+                       mISDNport->l2link = 1;
+                       break;
 
-                               default:
-                               l1_msg:
-                               PDEBUG(DEBUG_STACK, "GOT d-msg from %s port %d prim 0x%x dinfo 0x%x addr 0x%x\n", (mISDNport->ntmode)?"NT":"TE", mISDNport->portnum, frm->prim, frm->dinfo, frm->addr);
-                               if (frm->dinfo==(signed long)0xffffffff && frm->prim==(PH_DATA|CONFIRM))
-                               {
-                                       PERROR("SERIOUS BUG, dinfo == 0xffffffff, prim == PH_DATA | CONFIRM !!!!\n");
-                               }
-                               /* d-message */
-                               if (mISDNport->ntmode)
-                               {
-                                       /* l1-data enters the nt-mode library */
-                                       nst = &mISDNport->nst;
-                                       if (nst->l1_l2(nst, msg))
-                                               free_msg(msg);
-                                       return(1);
-                               } else
-                               {
-                                       /* l3-data is sent to pbx */
-                                       if (stack2manager_te(mISDNport, msg))
-                                               free_msg(msg);
-                                       return(1);
-                               }
+                       case DL_RELEASE | INDICATION:
+                       case DL_RELEASE | CONFIRM:
+                       l1l2l3_trace_header(mISDNport, NULL, frm->prim, DIRECTION_IN);
+                       end_trace();
+                       if (!mISDNport->ntmode) break; /* !!!!!!!!!!!!!!!! */
+                       ss_rel:
+                       mISDNport->l2link = 0;
+                       if (mISDNport->ptp)
+                       {
+                               time(&mISDNport->l2establish);
+                               PDEBUG(DEBUG_ISDN, "because we are ptp, we set a l2establish timer.\n");
                        }
                        break;
+
+                       default:
+                       l1_msg:
+                       PDEBUG(DEBUG_STACK, "GOT d-msg from %s port %d prim 0x%x dinfo 0x%x addr 0x%x\n", (mISDNport->ntmode)?"NT":"TE", mISDNport->portnum, frm->prim, frm->dinfo, frm->addr);
+                       if (frm->dinfo==(signed long)0xffffffff && frm->prim==(PH_DATA|CONFIRM))
+                       {
+                               PERROR("SERIOUS BUG, dinfo == 0xffffffff, prim == PH_DATA | CONFIRM !!!!\n");
+                       }
+                       /* d-message */
+                       if (mISDNport->ntmode)
+                       {
+                               /* l1-data enters the nt-mode library */
+                               nst = &mISDNport->nst;
+                               if (nst->l1_l2(nst, msg))
+                                       free_msg(msg);
+                               return(1);
+                       } else
+                       {
+                               /* l3-data is sent to pbx */
+                               if (stack2manager_te(mISDNport, msg))
+                                       free_msg(msg);
+                               return(1);
+                       }
                }
-//PDEBUG(DEBUG_ISDN, "flg:%d upper_id=%x addr=%x\n", (frm->addr&FLG_CHILD_STACK), (mISDNport->b_addr[0])&(~IF_CHILDMASK), (frm->addr)&(~IF_CHILDMASK));
-               /* check if child, and if parent stack match */
-               if ((frm->addr&FLG_CHILD_STACK) && (((unsigned int)(mISDNport->b_addr[0])&(~CHILD_ID_MASK)&STACK_ID_MASK) == ((frm->addr)&(~CHILD_ID_MASK)&STACK_ID_MASK)))
+       } else
+       /* child stack */
+       {
+               /* b-message */
+               switch(frm->prim)
                {
-                       /* b-message */
-                       switch(frm->prim)
-                       {
-                               /* we don't care about confirms, we use rx data to sync tx */
-                               case PH_DATA | CONFIRM:
-                               case DL_DATA | CONFIRM:
-                               break;
+                       /* we don't care about confirms, we use rx data to sync tx */
+                       case PH_DATA | CONFIRM:
+                       case DL_DATA | CONFIRM:
+                       break;
 
-                               /* we receive audio data, we respond to it AND we send tones */
-                               case PH_DATA | INDICATION:
-                               case DL_DATA | INDICATION:
-                               case PH_CONTROL | INDICATION:
-                               i = 0;
-                               while(i < mISDNport->b_num)
-                               {
-                                       if ((unsigned int)(mISDNport->b_addr[i]&STACK_ID_MASK) == (frm->addr&STACK_ID_MASK))
-                                               break;
-                                       i++;
-                               }
-                               if (i == mISDNport->b_num)
-                               {
-                                       PERROR("unhandled b-message (address 0x%x).\n", frm->addr);
+                       /* we receive audio data, we respond to it AND we send tones */
+                       case PH_DATA | INDICATION:
+                       case DL_DATA | INDICATION:
+                       case PH_CONTROL | INDICATION:
+                       i = 0;
+                       while(i < mISDNport->b_num)
+                       {
+                               if ((unsigned int)(mISDNport->b_addr[i]&STACK_ID_MASK) == (frm->addr&STACK_ID_MASK))
                                        break;
-                               }
-                               if (mISDNport->b_port[i])
-                               {
-//PERROR("port sech: %s data\n", mISDNport->b_port[i]->p_name);
-                                       mISDNport->b_port[i]->bchannel_receive(frm);
-                               } else
-                                       PDEBUG(DEBUG_BCHANNEL, "b-channel is not associated to an ISDNPort (address 0x%x), ignoring.\n", frm->addr);
+                               i++;
+                       }
+                       if (i == mISDNport->b_num)
+                       {
+                               PERROR("unhandled b-message (address 0x%x).\n", frm->addr);
                                break;
+                       }
+                       if (mISDNport->b_port[i])
+                       {
+//PERROR("port sech: %s data\n", mISDNport->b_port[i]->p_name);
+                               mISDNport->b_port[i]->bchannel_receive(frm);
+                       } else
+                               PDEBUG(DEBUG_BCHANNEL, "b-channel is not associated to an ISDNPort (address 0x%x), ignoring.\n", frm->addr);
+                       break;
 
-                               case PH_ACTIVATE | INDICATION:
-                               case DL_ESTABLISH | INDICATION:
-                               case PH_ACTIVATE | CONFIRM:
-                               case DL_ESTABLISH | CONFIRM:
-                               PDEBUG(DEBUG_BCHANNEL, "DL_ESTABLISH confirm: bchannel is now activated (address 0x%x).\n", frm->addr);
-                               i = 0;
-                               while(i < mISDNport->b_num)
-                               {
-                                       if ((unsigned int)(mISDNport->b_addr[i]&STACK_ID_MASK) == (frm->addr&STACK_ID_MASK))
-                                               break;
-                                       i++;
-                               }
-                               if (i == mISDNport->b_num)
-                               {
-                                       PERROR("unhandled b-establish (address 0x%x).\n", frm->addr);
+                       case PH_ACTIVATE | INDICATION:
+                       case DL_ESTABLISH | INDICATION:
+                       case PH_ACTIVATE | CONFIRM:
+                       case DL_ESTABLISH | CONFIRM:
+                       PDEBUG(DEBUG_BCHANNEL, "DL_ESTABLISH confirm: bchannel is now activated (address 0x%x).\n", frm->addr);
+                       i = 0;
+                       while(i < mISDNport->b_num)
+                       {
+                               if ((unsigned int)(mISDNport->b_addr[i]&STACK_ID_MASK) == (frm->addr&STACK_ID_MASK))
                                        break;
-                               }
-                               bchannel_event(mISDNport, i, B_EVENT_ACTIVATED);
+                               i++;
+                       }
+                       if (i == mISDNport->b_num)
+                       {
+                               PERROR("unhandled b-establish (address 0x%x).\n", frm->addr);
                                break;
+                       }
+                       bchannel_event(mISDNport, i, B_EVENT_ACTIVATED);
+                       break;
 
-                               case PH_DEACTIVATE | INDICATION:
-                               case DL_RELEASE | INDICATION:
-                               case PH_DEACTIVATE | CONFIRM:
-                               case DL_RELEASE | CONFIRM:
-                               PDEBUG(DEBUG_BCHANNEL, "DL_RELEASE confirm: bchannel is now de-activated (address 0x%x).\n", frm->addr);
-                               i = 0;
-                               while(i < mISDNport->b_num)
-                               {
-                                       if ((unsigned int)(mISDNport->b_addr[i]&STACK_ID_MASK) == (frm->addr&STACK_ID_MASK))
-                                               break;
-                                       i++;
-                               }
-                               if (i == mISDNport->b_num)
-                               {
-                                       PERROR("unhandled b-release (address 0x%x).\n", frm->addr);
+                       case PH_DEACTIVATE | INDICATION:
+                       case DL_RELEASE | INDICATION:
+                       case PH_DEACTIVATE | CONFIRM:
+                       case DL_RELEASE | CONFIRM:
+                       PDEBUG(DEBUG_BCHANNEL, "DL_RELEASE confirm: bchannel is now de-activated (address 0x%x).\n", frm->addr);
+                       i = 0;
+                       while(i < mISDNport->b_num)
+                       {
+                               if ((unsigned int)(mISDNport->b_addr[i]&STACK_ID_MASK) == (frm->addr&STACK_ID_MASK))
                                        break;
-                               }
-                               bchannel_event(mISDNport, i, B_EVENT_DEACTIVATED);
+                               i++;
+                       }
+                       if (i == mISDNport->b_num)
+                       {
+                               PERROR("unhandled b-release (address 0x%x).\n", frm->addr);
                                break;
                        }
+                       bchannel_event(mISDNport, i, B_EVENT_DEACTIVATED);
                        break;
-               }
 
-               mISDNport = mISDNport->next;
-       } 
-       if (!mISDNport)
-       {
-               if (frm->prim == (MGR_TIMER | INDICATION))
-                       PERROR("unhandled timer indication message: prim(0x%x) addr(0x%x) msg->len(%d)\n", frm->prim, frm->addr, msg->len);
-               else
-                       PERROR("unhandled message: prim(0x%x) addr(0x%x) msg->len(%d)\n", frm->prim, frm->addr, msg->len);
-//             PERROR("test: is_child: %x  of stack %x == %x (baddr %x frm %x)\n", (frm->addr&FLG_CHILD_STACK), ((unsigned int)(mISDNport_first->b_addr[0])&(~CHILD_ID_MASK)&STACK_ID_MASK), ((frm->addr)&(~CHILD_ID_MASK)&STACK_ID_MASK), mISDNport_first->b_addr[0], frm->addr);
+                       default:
+                       PERROR("child message not handled: prim(0x%x) addr(0x%x) msg->len(%d)\n", frm->prim, frm->addr, msg->len);
+               }
        }
 
+       out:
        free_msg(msg);
        return(1);
 }
@@ -1776,7 +1801,7 @@ int mISDN_handler(void)
 /*
  * global function to add a new card (port)
  */
-struct mISDNport *mISDNport_open(int port, int ptp, int ptmp)
+struct mISDNport *mISDNport_open(int port, int ptp, int ptmp, struct interface *interface)
 {
        int ret;
        unsigned char buff[1025];
@@ -1911,7 +1936,7 @@ struct mISDNport *mISDNport_open(int port, int ptp, int ptmp)
        /* add mISDNport structure */
        mISDNportp = &mISDNport_first;
        while(*mISDNportp)
-               mISDNportp = &mISDNport->next;
+               mISDNportp = &((*mISDNportp)->next);
        mISDNport = (struct mISDNport *)calloc(1, sizeof(struct mISDNport));
        if (!mISDNport)
        {
@@ -2075,7 +2100,7 @@ struct mISDNport *mISDNport_open(int port, int ptp, int ptmp)
        PDEBUG(DEBUG_BCHANNEL, "using 'mISDN_dsp.o' module\n");
 
        start_trace(mISDNport->portnum,
-                   mISDNport->ifport->interface,
+                   interface,
                    NULL,
                    NULL,
                    DIRECTION_NONE,
@@ -2126,21 +2151,25 @@ void mISDNport_close(struct mISDNport *mISDNport)
                port = port->next;
        }
 
-       start_trace(mISDNport->portnum,
-                   mISDNport->ifport->interface,
-                   NULL,
-                   NULL,
-                   DIRECTION_NONE,
-                   CATEGORY_CH,
-                   0,
-                   "PORT (close)");
-       end_trace();
+       /* only if we are already part of interface */
+       if (mISDNport->ifport)
+       {
+               start_trace(mISDNport->portnum,
+                           mISDNport->ifport->interface,
+                           NULL,
+                           NULL,
+                           DIRECTION_NONE,
+                           CATEGORY_CH,
+                           0,
+                           "PORT (close)");
+               end_trace();
+       }
 
        /* free bchannels */
        i = 0;
        while(i < mISDNport->b_num)
        {
-               if (mISDNport->b_stid[i])
+               if (mISDNport->b_addr[i])
                {
                        _bchannel_destroy(mISDNport, i);
                        PDEBUG(DEBUG_BCHANNEL, "freeing %s port %d bchannel (index %d).\n", (mISDNport->ntmode)?"NT":"TE", mISDNport->portnum, i);
@@ -2171,9 +2200,8 @@ void mISDNport_close(struct mISDNport *mISDNport)
        PDEBUG(DEBUG_BCHANNEL, "freeing d-stack.\n");
        if (mISDNport->d_stid)
        {
-//             mISDN_clear_stack(mISDNdevice, mISDNport->d_stid);
-               if (mISDNport->lower_id)
-                       mISDN_write_frame(mISDNdevice, buf, mISDNport->lower_id, MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
+               if (mISDNport->upper_id)
+                       mISDN_write_frame(mISDNdevice, buf, mISDNport->upper_id | FLG_MSG_DOWN, MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
        }
 
        /* remove from list */
@@ -2183,12 +2211,13 @@ void mISDNport_close(struct mISDNport *mISDNport)
                if (*mISDNportp == mISDNport)
                {
                        *mISDNportp = (*mISDNportp)->next;
+                       mISDNportp = NULL;
                        break;
                }
                mISDNportp = &((*mISDNportp)->next);
        }
 
-       if (!(*mISDNportp))
+       if (mISDNportp)
        {
                PERROR("software error, mISDNport not in list\n");
                exit(-1);