chan_lcr: this fixes hanging with app_rxfax and a race condition
[lcr.git] / dss1.cpp
index 79f0674..fea2e29 100644 (file)
--- a/dss1.cpp
+++ b/dss1.cpp
@@ -23,7 +23,7 @@ extern unsigned int mt_assign_pid;
 /*
  * constructor
  */
-Pdss1::Pdss1(int type, struct mISDNport *mISDNport, char *portname, struct port_settings *settings, int channel, int exclusive) : PmISDN(type, mISDNport, portname, settings, channel, exclusive)
+Pdss1::Pdss1(int type, struct mISDNport *mISDNport, char *portname, struct port_settings *settings, int channel, int exclusive, int mode) : PmISDN(type, mISDNport, portname, settings, channel, exclusive, mode)
 {
        p_callerinfo.itype = (mISDNport->ifport->interface->extension)?INFO_ITYPE_ISDN_EXTENSION:INFO_ITYPE_ISDN;
        p_m_d_ntmode = mISDNport->ntmode;
@@ -326,13 +326,22 @@ int Pdss1::hunt_bchannel(int channel, int exclusive)
                /* exclusive channel requests must be in the list */
                if (exclusive)
                {
+                       /* no exclusive channel */
                        if (!channel)
                        {
                                add_trace("conclusion", NULL, "exclusively requested channel not in list");
                                end_trace();
                                return(-6); // channel unacceptable
                        }
-                       i = selchannel->channel-1-(selchannel->channel>=17);
+                       /* get index for channel */
+                       i = channel-1-(channel>=17);
+                       if (i < 0 || i >= p_m_mISDNport->b_num || channel == 16)
+                       {
+                               add_trace("conclusion", NULL, "exclusively requested channel outside interface range");
+                               end_trace();
+                               return(-6); // channel unacceptable
+                       }
+                       /* check if busy */
                        if (p_m_mISDNport->b_port[i] == NULL)
                                goto use_channel;
                        add_trace("conclusion", NULL, "exclusively requested channel is busy");
@@ -343,7 +352,12 @@ int Pdss1::hunt_bchannel(int channel, int exclusive)
                /* requested channels in list will be used */
                if (channel)
                {
-                       i = selchannel->channel-1-(selchannel->channel>=17);
+                       /* get index for channel */
+                       i = channel-1-(channel>=17);
+                       if (i < 0 || i >= p_m_mISDNport->b_num || channel == 16)
+                       {
+                               add_trace("info", NULL, "requested channel %d outside interface range", channel);
+                       } else /* if inside range (else) check if available */
                        if (p_m_mISDNport->b_port[i] == NULL)
                                goto use_channel;
                }
@@ -460,6 +474,7 @@ void Pdss1::setup_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
        dec_ie_channel_id(l3m, &exclusive, &channel);
        dec_ie_hlc(l3m, &hlc_coding, &hlc_interpretation, &hlc_presentation, &hlc_hlc, &hlc_exthlc);
        dec_ie_bearer(l3m, &bearer_coding, &bearer_capability, &bearer_mode, &bearer_rate, &bearer_multi, &bearer_user);
+       dec_ie_display(l3m, (unsigned char *)p_dialinginfo.display, sizeof(p_dialinginfo.display));
        end_trace();
 
        /* if blocked, release call with MT_RELEASE_COMPLETE */
@@ -654,6 +669,15 @@ void Pdss1::setup_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
                break;
        }
 
+       /* set bchannel mode */
+       if (p_capainfo.bearer_capa==INFO_BC_DATAUNRESTRICTED
+        || p_capainfo.bearer_capa==INFO_BC_DATARESTRICTED
+        || p_capainfo.bearer_capa==INFO_BC_VIDEO)
+               p_capainfo.source_mode = B_MODE_HDLC;
+       else
+               p_capainfo.source_mode = B_MODE_TRANSPARENT;
+       p_m_b_mode = p_capainfo.source_mode;
+
        /* hunt channel */
        ret = channel = hunt_bchannel(channel, exclusive);
        if (ret < 0)
@@ -709,12 +733,13 @@ void Pdss1::setup_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
 void Pdss1::information_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
 {
        int type, plan;
-       unsigned char keypad[32] = "";
+       unsigned char keypad[32] = "", display[128] = "";
        struct lcr_msg *message;
 
        l1l2l3_trace_header(p_m_mISDNport, this, L3_INFORMATION_IND, DIRECTION_IN);
        dec_ie_called_pn(l3m, &type, &plan, (unsigned char *)p_dialinginfo.id, sizeof(p_dialinginfo.id));
        dec_ie_keypad(l3m, (unsigned char *)keypad, sizeof(keypad));
+       dec_ie_display(l3m, (unsigned char *)display, sizeof(display));
        dec_ie_complete(l3m, &p_dialinginfo.sending_complete);
        end_trace();
 
@@ -734,6 +759,7 @@ void Pdss1::information_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l
                p_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
                break;
        }
+       SCAT(p_dialinginfo.display, (char *)display);
        message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_INFORMATION);
        memcpy(&message->param.information, &p_dialinginfo, sizeof(struct dialing_info));
        message_put(message);
@@ -947,6 +973,7 @@ void Pdss1::connect_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
        l1l2l3_trace_header(p_m_mISDNport, this, L3_CONNECT_IND, DIRECTION_IN);
        dec_ie_channel_id(l3m, &exclusive, &channel);
        dec_ie_connected_pn(l3m, &type, &plan, &present, &screen, (unsigned char *)p_connectinfo.id, sizeof(p_connectinfo.id));
+       dec_ie_display(l3m, (unsigned char *)p_connectinfo.display, sizeof(p_connectinfo.display));
        /* te-mode: CONP (connected name identification presentation) */
        if (!p_m_d_ntmode)
                dec_facility_centrex(l3m, (unsigned char *)p_connectinfo.name, sizeof(p_connectinfo.name));
@@ -1036,10 +1063,12 @@ void Pdss1::disconnect_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3
        int location, cause;
        int coding, proglocation, progress;
        struct lcr_msg *message;
+       unsigned char display[128] = "";
 
        l1l2l3_trace_header(p_m_mISDNport, this, L3_DISCONNECT_IND, DIRECTION_IN);
        dec_ie_progress(l3m, &coding, &proglocation, &progress);
        dec_ie_cause(l3m, &location, &cause);
+       dec_ie_display(l3m, (unsigned char *)display, sizeof(display));
        end_trace();
 
        if (cause < 0)
@@ -1065,6 +1094,7 @@ void Pdss1::disconnect_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3
                        message = message_create(p_serial, p_epointlist->epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
                        message->param.disconnectinfo.cause = cause;
                        message->param.disconnectinfo.location = location;
+                       SCAT(message->param.disconnectinfo.display, (char *)display);
                        message_put(message);
                        /* remove epoint */
                        free_epointlist(p_epointlist);
@@ -1082,6 +1112,7 @@ void Pdss1::disconnect_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3
                message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_DISCONNECT);
                message->param.disconnectinfo.location = location;
                message->param.disconnectinfo.cause = cause;
+               SCAT(message->param.disconnectinfo.display, (char *)display);
                message_put(message);
        }
        while(INACTIVE_EPOINT(p_epointlist))
@@ -1089,6 +1120,7 @@ void Pdss1::disconnect_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3
                message = message_create(p_serial, INACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_RELEASE);
                message->param.disconnectinfo.location = location;
                message->param.disconnectinfo.cause = cause;
+               SCAT(message->param.disconnectinfo.display, (char *)display);
                message_put(message);
                /* remove epoint */
                free_epointid(INACTIVE_EPOINT(p_epointlist));
@@ -1125,9 +1157,11 @@ void Pdss1::release_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
 {
        int location, cause;
        struct lcr_msg *message;
+       unsigned char display[128] = "";
 
        l1l2l3_trace_header(p_m_mISDNport, this, L3_RELEASE_IND, DIRECTION_IN);
        dec_ie_cause(l3m, &location, &cause);
+       dec_ie_display(l3m, (unsigned char *)display, sizeof(display));
        end_trace();
 
        if (cause < 0)
@@ -1141,6 +1175,7 @@ void Pdss1::release_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
                message = message_create(p_serial, p_epointlist->epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
                message->param.disconnectinfo.cause = cause;
                message->param.disconnectinfo.location = location;
+               SCAT(message->param.disconnectinfo.display, (char *)display);
                message_put(message);
                /* remove epoint */
                free_epointlist(p_epointlist);
@@ -1167,14 +1202,17 @@ void Pdss1::release_complete_ind(unsigned int cmd, unsigned int pid, struct l3_m
        
        l1l2l3_trace_header(p_m_mISDNport, this, L3_RELEASE_COMPLETE_IND, DIRECTION_IN);
        /* in case layer 2 is down during setup, we send cause 27 loc 5 */
-       if (p_state == PORT_STATE_OUT_SETUP && !p_m_mISDNport->l1link)
+       if (p_state == PORT_STATE_OUT_SETUP && p_m_mISDNport->l1link == 0)
        {
                cause = 27;
                location = 5;
        } else
        {
                dec_ie_cause(l3m, &location, &cause);
-               add_trace("layer 1", NULL, (p_m_mISDNport->l1link)?"up":"down");
+               if (p_m_mISDNport->l1link < 0)
+                       add_trace("layer 1", NULL, "unknown");
+               else
+                       add_trace("layer 1", NULL, (p_m_mISDNport->l1link)?"up":"down");
        }
        end_trace();
        if (location == LOCATION_PRIVATE_LOCAL)
@@ -1210,10 +1248,12 @@ void Pdss1::notify_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
        struct lcr_msg *message;
        int notify, type, plan, present;
        unsigned char notifyid[sizeof(message->param.notifyinfo.id)];
+       unsigned char display[128] = "";
 
        l1l2l3_trace_header(p_m_mISDNport, this, L3_NOTIFY_IND, DIRECTION_IN);
        dec_ie_notify(l3m, &notify);
        dec_ie_redir_dn(l3m, &type, &plan, &present, notifyid, sizeof(notifyid));
+       dec_ie_display(l3m, (unsigned char *)display, sizeof(display));
        end_trace();
 
        if (!ACTIVE_EPOINT(p_epointlist))
@@ -1257,6 +1297,7 @@ void Pdss1::notify_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
                message->param.notifyinfo.ntype = INFO_NTYPE_UNKNOWN;
                break;
        }
+       SCAT(message->param.notifyinfo.display, (char *)display);
        message->param.notifyinfo.isdn_port = p_m_portnum;
        message_put(message);
 }
@@ -1503,6 +1544,7 @@ void Pdss1::resume_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
        if (ret < 0)
                goto no_channel;
 
+// mode (if hdlc parked) to be done. never mind, this is almost never requested
        /* open channel */
        ret = seize_bchannel(channel, 1);
        if (ret < 0)
@@ -1849,6 +1891,8 @@ void Pdss1::message_information(unsigned int epoint_id, int message_id, union pa
                l3m = create_l3msg();
                l1l2l3_trace_header(p_m_mISDNport, this, L3_INFORMATION_REQ, DIRECTION_OUT);
                enc_ie_called_pn(l3m, 0, 1, (unsigned char *)param->information.id);
+               if (p_m_d_ntmode)
+                       enc_ie_display(l3m, (unsigned char *)param->information.display);
                end_trace();
                p_m_mISDNport->ml3->to_layer3(p_m_mISDNport->ml3, MT_INFORMATION, p_m_d_l3id, l3m);
        }
@@ -2245,6 +2289,14 @@ void Pdss1::message_overlap(unsigned int epoint_id, int message_id, union parame
 {
        l3_msg *l3m;
 
+       /* in case of sending complete, we proceed */
+       if (p_dialinginfo.sending_complete)
+       {
+               PDEBUG(DEBUG_ISDN, "sending proceeding instead of setup_acknowledge, because address is complete.\n");
+               message_proceeding(epoint_id, message_id, param);
+               return;
+       }
+
        /* sending setup_acknowledge */
        l3m = create_l3msg();
        l1l2l3_trace_header(p_m_mISDNport, this, L3_SETUP_ACKNOWLEDGE_REQ, DIRECTION_OUT);
@@ -2850,18 +2902,18 @@ int stack2manager(struct mISDNport *mISDNport, unsigned int cmd, unsigned int pi
        switch(cmd)
        {
                case MT_SETUP:
-               /* creating port object */
+               /* creating port object, transparent until setup with hdlc */
                SPRINT(name, "%s-%d-in", mISDNport->ifport->interface->name, mISDNport->portnum);
-               if (!(pdss1 = new Pdss1(PORT_TYPE_DSS1_NT_IN, mISDNport, name, NULL, 0, 0)))
+               if (!(pdss1 = new Pdss1(PORT_TYPE_DSS1_NT_IN, mISDNport, name, NULL, 0, 0, B_MODE_TRANSPARENT)))
 
                        FATAL("Cannot create Port instance.\n");
                pdss1->message_isdn(cmd, pid, l3m);
                break;
 
                case MT_RESUME:
-               /* creating port object */
+               /* creating port object, transparent until setup with hdlc */
                SPRINT(name, "%s-%d-in", mISDNport->ifport->interface->name, mISDNport->portnum);
-               if (!(pdss1 = new Pdss1(PORT_TYPE_DSS1_NT_IN, mISDNport, name, NULL, 0, 0)))
+               if (!(pdss1 = new Pdss1(PORT_TYPE_DSS1_NT_IN, mISDNport, name, NULL, 0, 0, B_MODE_TRANSPARENT)))
                        FATAL("Cannot create Port instance.\n");
                pdss1->message_isdn(cmd, pid, l3m);
                break;