Adding interface support for remote app (chan_lcr).
authorAndreas Eversberg <jolly@eversberg.eu>
Mon, 13 Dec 2010 08:22:49 +0000 (09:22 +0100)
committerAndreas Eversberg <jolly@eversberg.eu>
Mon, 13 Dec 2010 08:22:49 +0000 (09:22 +0100)
chan_lcr can be handled as an interface. This way it is possible to (e.g.):
- make a SIP phone become an LCR extension with all LCR features.
- make conference calls. (untested)
- perform parallel ringing. (ISDN phone and SIP phones can ring in
  parallel.)
- do voice recoding.

It is still also possible to link chan_lcr directly without interface
(as before).

Documentation/howto for that will follow.

28 files changed:
Makefile.am
Makefile.in
apppbx.cpp
chan_lcr.c
default/gsm.conf
default/interface.conf
default/options.conf
gsm.cpp
gsm.h
gsm_conf.c
interface.c
interface.h
joinremote.cpp
joinremote.h
loop.c [new file with mode: 0644]
loop.h [new file with mode: 0644]
mISDN.cpp
mISDN.h
main.c
main.h
message.h
options.c
options.h
port.h
remote.cpp [new file with mode: 0644]
remote.h [new file with mode: 0644]
socket_server.c
socket_server.h

index f71d715..ea96ae7 100644 (file)
@@ -125,8 +125,8 @@ endif
 
 INCLUDES = $(all_includes) $(GSM_INCLUDE) $(SS5_INCLUDE) -Wall $(INSTALLATION_DEFINES)
 
-lcr_SOURCES = $(GSM_SOURCE) $(SS5_SOURCE) select.c action.cpp       mISDN.cpp        tones.c \
-       action_efi.cpp   crypt.cpp        mail.c           trace.c \
+lcr_SOURCES = $(GSM_SOURCE) $(SS5_SOURCE) select.c action.cpp mISDN.cpp \
+       tones.c loop.c remote.c action_efi.cpp crypt.cpp mail.c trace.c \
        action_vbox.cpp  dss1.cpp         main.c           \
        vbox.cpp alawulaw.c       endpoint.cpp     interface.c     message.c \
        apppbx.cpp       endpointapp.cpp  join.cpp        options.c       \
index 067dfe1..3568597 100644 (file)
@@ -97,12 +97,12 @@ am__lcr_SOURCES_DIST = gsm_audio.c gsm.cpp gsm_conf.c gsm_bs.cpp \
        openbsc/src/vty_interface_layer3.c openbsc/src/bsc_api.c \
        openbsc/src/bsc_version.c gsm_ms.cpp \
        layer23/src/mobile/app_mobile.c ss5.cpp ss5_encode.c \
-       ss5_decode.c select.c action.cpp mISDN.cpp tones.c \
-       action_efi.cpp crypt.cpp mail.c trace.c action_vbox.cpp \
-       dss1.cpp main.c vbox.cpp alawulaw.c endpoint.cpp interface.c \
-       message.c apppbx.cpp endpointapp.cpp join.cpp options.c \
-       extension.c joinpbx.cpp port.cpp callerid.c joinremote.cpp \
-       route.c cause.c socket_server.c
+       ss5_decode.c select.c action.cpp mISDN.cpp tones.c loop.c \
+       remote.c action_efi.cpp crypt.cpp mail.c trace.c \
+       action_vbox.cpp dss1.cpp main.c vbox.cpp alawulaw.c \
+       endpoint.cpp interface.c message.c apppbx.cpp endpointapp.cpp \
+       join.cpp options.c extension.c joinpbx.cpp port.cpp callerid.c \
+       joinremote.cpp route.c cause.c socket_server.c
 @ENABLE_GSM_TRUE@am__objects_1 = gsm_audio.$(OBJEXT) gsm.$(OBJEXT) \
 @ENABLE_GSM_TRUE@      gsm_conf.$(OBJEXT)
 @ENABLE_GSM_BS_TRUE@am__objects_2 = gsm_bs.$(OBJEXT) \
@@ -116,14 +116,15 @@ am__objects_4 = $(am__objects_1) $(am__objects_2) $(am__objects_3)
 @ENABLE_SS5_TRUE@      ss5_decode.$(OBJEXT)
 am_lcr_OBJECTS = $(am__objects_4) $(am__objects_5) select.$(OBJEXT) \
        action.$(OBJEXT) mISDN.$(OBJEXT) tones.$(OBJEXT) \
-       action_efi.$(OBJEXT) crypt.$(OBJEXT) mail.$(OBJEXT) \
-       trace.$(OBJEXT) action_vbox.$(OBJEXT) dss1.$(OBJEXT) \
-       main.$(OBJEXT) vbox.$(OBJEXT) alawulaw.$(OBJEXT) \
-       endpoint.$(OBJEXT) interface.$(OBJEXT) message.$(OBJEXT) \
-       apppbx.$(OBJEXT) endpointapp.$(OBJEXT) join.$(OBJEXT) \
-       options.$(OBJEXT) extension.$(OBJEXT) joinpbx.$(OBJEXT) \
-       port.$(OBJEXT) callerid.$(OBJEXT) joinremote.$(OBJEXT) \
-       route.$(OBJEXT) cause.$(OBJEXT) socket_server.$(OBJEXT)
+       loop.$(OBJEXT) remote.$(OBJEXT) action_efi.$(OBJEXT) \
+       crypt.$(OBJEXT) mail.$(OBJEXT) trace.$(OBJEXT) \
+       action_vbox.$(OBJEXT) dss1.$(OBJEXT) main.$(OBJEXT) \
+       vbox.$(OBJEXT) alawulaw.$(OBJEXT) endpoint.$(OBJEXT) \
+       interface.$(OBJEXT) message.$(OBJEXT) apppbx.$(OBJEXT) \
+       endpointapp.$(OBJEXT) join.$(OBJEXT) options.$(OBJEXT) \
+       extension.$(OBJEXT) joinpbx.$(OBJEXT) port.$(OBJEXT) \
+       callerid.$(OBJEXT) joinremote.$(OBJEXT) route.$(OBJEXT) \
+       cause.$(OBJEXT) socket_server.$(OBJEXT)
 lcr_OBJECTS = $(am_lcr_OBJECTS)
 am__DEPENDENCIES_1 =
 @ENABLE_GSM_BS_TRUE@am__DEPENDENCIES_2 = ./openbsc/src/libbsc.a \
@@ -285,8 +286,8 @@ GSM_LIB = $(am__append_3) $(am__append_6) $(am__append_9)
 @ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@chan_lcr_so_LDFLAGS = -shared
 @ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@chan_lcr_so_LDADD = chan_lcr.po bchannel.po options.po callerid.po select.po
 INCLUDES = $(all_includes) $(GSM_INCLUDE) $(SS5_INCLUDE) -Wall $(INSTALLATION_DEFINES)
-lcr_SOURCES = $(GSM_SOURCE) $(SS5_SOURCE) select.c action.cpp       mISDN.cpp        tones.c \
-       action_efi.cpp   crypt.cpp        mail.c           trace.c \
+lcr_SOURCES = $(GSM_SOURCE) $(SS5_SOURCE) select.c action.cpp mISDN.cpp \
+       tones.c loop.c remote.c action_efi.cpp crypt.cpp mail.c trace.c \
        action_vbox.cpp  dss1.cpp         main.c           \
        vbox.cpp alawulaw.c       endpoint.cpp     interface.c     message.c \
        apppbx.cpp       endpointapp.cpp  join.cpp        options.c       \
@@ -318,15 +319,15 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
        @for dep in $?; do \
          case '$(am__configure_deps)' in \
            *$$dep*) \
-             echo ' cd $(srcdir) && $(AUTOMAKE) --gnu'; \
-             $(am__cd) $(srcdir) && $(AUTOMAKE) --gnu \
+             echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \
+             $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \
                && exit 0; \
              exit 1;; \
          esac; \
        done; \
-       echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \
+       echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
        $(am__cd) $(top_srcdir) && \
-         $(AUTOMAKE) --gnu Makefile
+         $(AUTOMAKE) --foreign Makefile
 .PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
        @case '$?' in \
@@ -499,12 +500,14 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/joinpbx.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/joinremote.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lcradmin.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/loop.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mISDN.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mail.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/message.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/options.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/port.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/remote.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/route.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/select.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/socket_server.Po@am__quote@
index 87e4f41..aaa02cb 100644 (file)
@@ -851,6 +851,7 @@ void EndpointAppPBX::out_setup(int cfnr)
        int                     channel = 0;
        int                     earlyb;
        int                     mode = B_MODE_TRANSPARENT;
+       struct admin_list       *admin;
 
        /* set bchannel mode */
        mode = e_capainfo.source_mode;
@@ -989,6 +990,21 @@ void EndpointAppPBX::out_setup(int cfnr)
                                port = new Pgsm_ms(PORT_TYPE_GSM_MS_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
                        else
 #endif
+                       if (mISDNport->ifport->remote) {
+                               admin = admin_first;
+                               while(admin) {
+                                       if (admin->remote_name[0] && !strcmp(admin->remote_name, mISDNport->ifport->remote_app))
+                                               break;
+                                       admin = admin->next;
+                               }
+                               if (!admin) {
+                                       trace_header("INTERFACE (remote not connected)", DIRECTION_NONE);
+                                       add_trace("application", NULL, "%s", mISDNport->ifport->remote_app);
+                                       end_trace();
+                                       continue;
+                               }
+                               port = new Premote(PORT_TYPE_REMOTE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode, admin->sock);
+                       } else
                                port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
                        if (!port)
                                FATAL("Failed to create Port instance\n");
@@ -1208,6 +1224,21 @@ void EndpointAppPBX::out_setup(int cfnr)
                                port = new Pgsm_ms(PORT_TYPE_GSM_MS_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
                        else
 #endif
+                       if (mISDNport->ifport->remote) {
+                               admin = admin_first;
+                               while(admin) {
+                                       if (admin->remote_name[0] && !strcmp(admin->remote_name, mISDNport->ifport->remote_app))
+                                               break;
+                                       admin = admin->next;
+                               }
+                               if (!admin) {
+                                       trace_header("INTERFACE (remote not connected)", DIRECTION_NONE);
+                                       add_trace("application", NULL, "%s", mISDNport->ifport->remote_app);
+                                       end_trace();
+                                       continue;
+                               }
+                               port = new Premote(PORT_TYPE_REMOTE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode, admin->sock);
+                       } else
                                port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
                        if (!port)
                                FATAL("No memory for Port instance\n");
@@ -2048,10 +2079,8 @@ void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type,
        /* other calls with no caller id (or not available for the extension) and force colp */
        if ((e_connectinfo.id[0]=='\0' || (e_connectinfo.present==INFO_PRESENT_RESTRICTED && !e_ext.anon_ignore))&& e_ext.colp==COLP_FORCE) {
                e_connectinfo.ntype = INFO_NTYPE_NOTPRESENT;
-               if (portlist->port_type==PORT_TYPE_DSS1_TE_OUT
-                || portlist->port_type==PORT_TYPE_DSS1_NT_OUT
-                || portlist->port_type==PORT_TYPE_GSM_BS_OUT
-                || portlist->port_type==PORT_TYPE_GSM_MS_OUT) { /* external extension answered */
+               if ((portlist->port_type & PORT_CLASS_DIR_MASK) == PORT_CLASS_DIR_OUT) {
+                       /* external extension answered */
                        port = find_port_id(portlist->port_id);
                        if (port) {
                                SCPY(e_connectinfo.id, nationalize_callerinfo(port->p_dialinginfo.id, &e_connectinfo.ntype, options.national, options.international));
@@ -3530,10 +3559,7 @@ void EndpointAppPBX::pick_join(char *extensions)
                                                        break;
                                                }
                                        }
-                                       if ((port->p_type==PORT_TYPE_DSS1_NT_OUT
-                                         || port->p_type==PORT_TYPE_DSS1_TE_OUT
-                                         || port->p_type==PORT_TYPE_GSM_BS_OUT
-                                         || port->p_type==PORT_TYPE_GSM_MS_OUT)
+                                       if ((portlist->port_type & PORT_CLASS_DIR_MASK) == PORT_CLASS_DIR_OUT
                                         && port->p_state==PORT_STATE_OUT_ALERTING)
                                                if (match_list(extensions, eapp->e_ext.number)) {
                                                        found = eapp;
index f4d8378..e9e26fa 100644 (file)
@@ -40,7 +40,7 @@ a new call reference (ref).
 The ref_was_assigned ist set to 1.
 Further dialing information is queued.
 After the new callref is received by special MESSAGE_NEWREF reply, new ref
-is stored in the chan_call structure. 
+is stored in the chan_call structure.
 The setup information is sent to LCR using MESSAGE_SETUP.
 The state changes to CHAN_LCR_STATE_OUT_SETUP.
 
@@ -207,7 +207,7 @@ int global_change = 0;
 int wake_global = 0;
 int wake_pipe[2];
 struct lcr_fd wake_fd;
-       
+
 int quit;
 
 int glob_channel = 0;
@@ -266,7 +266,7 @@ struct chan_call *find_call_ref(unsigned int ref)
 {
        struct chan_call *call = call_first;
        int assigned = (ref > 0);
-       
+
        while(call) {
                if (call->ref == ref && call->ref_was_assigned == assigned)
                        break;
@@ -595,8 +595,8 @@ void apply_opt(struct chan_call *call, char *data)
                default:
                        CERROR(call, call->ast, "Option '%s' unknown.\n", opt);
                }
-       }               
-       
+       }
+
        /* re-open, if bchannel is created */
        if (call->bchannel && call->bchannel->b_sock > -1) {
                bchannel_destroy(call->bchannel);
@@ -622,15 +622,16 @@ static void send_setup_to_lcr(struct chan_call *call)
 
        /* send setup message to LCR */
        memset(&newparam, 0, sizeof(union parameter));
-               newparam.setup.dialinginfo.itype = INFO_ITYPE_ISDN;     
-               newparam.setup.dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
+       newparam.setup.dialinginfo.itype = INFO_ITYPE_ISDN;
+       newparam.setup.dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
        if (call->keypad)
                strncpy(newparam.setup.dialinginfo.keypad, call->dialstring, sizeof(newparam.setup.dialinginfo.keypad)-1);
        else
                strncpy(newparam.setup.dialinginfo.id, call->dialstring, sizeof(newparam.setup.dialinginfo.id)-1);
-       strncpy(newparam.setup.dialinginfo.interfaces, call->interface, sizeof(newparam.setup.dialinginfo.interfaces)-1);
-               newparam.setup.callerinfo.itype = INFO_ITYPE_CHAN;      
-               newparam.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
+       if (!!strcmp(call->interface, "pbx"))
+               strncpy(newparam.setup.dialinginfo.interfaces, call->interface, sizeof(newparam.setup.dialinginfo.interfaces)-1);
+       newparam.setup.callerinfo.itype = INFO_ITYPE_CHAN;
+       newparam.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
        strncpy(newparam.setup.callerinfo.display, call->display, sizeof(newparam.setup.callerinfo.display)-1);
        call->display[0] = '\0';
        if (call->cid_num[0])
@@ -639,8 +640,8 @@ static void send_setup_to_lcr(struct chan_call *call)
                strncpy(newparam.setup.callerinfo.name, call->cid_name, sizeof(newparam.setup.callerinfo.name)-1);
        if (call->cid_rdnis[0]) {
                strncpy(newparam.setup.redirinfo.id, call->cid_rdnis, sizeof(newparam.setup.redirinfo.id)-1);
-                       newparam.setup.redirinfo.itype = INFO_ITYPE_CHAN;       
-               newparam.setup.redirinfo.ntype = INFO_NTYPE_UNKNOWN;    
+               newparam.setup.redirinfo.itype = INFO_ITYPE_CHAN;
+               newparam.setup.redirinfo.ntype = INFO_NTYPE_UNKNOWN;
        }
        switch(ast->cid.cid_pres & AST_PRES_RESTRICTION) {
                case AST_PRES_RESTRICTED:
@@ -697,7 +698,7 @@ static void send_dialque_to_lcr(struct chan_call *call)
 
        if (!call->ast || !call->ref || !call->dialque[0])
                return;
-       
+
        CDEBUG(call, call->ast, "Sending dial queue to LCR. (dialing=%s)\n", call->dialque);
 
        /* send setup message to LCR */
@@ -758,7 +759,7 @@ static void lcr_start_pbx(struct chan_call *call, struct ast_channel *ast, int c
                exten = "s";
 
        CDEBUG(call, ast, "Try to start pbx. (exten=%s context=%s complete=%s)\n", exten, ast->context, complete?"yes":"no");
-       
+
        if (complete) {
                /* if not match */
                if (!ast_canmatch_extension(ast, ast->context, exten, 1, call->oad)) {
@@ -822,16 +823,16 @@ static void lcr_start_pbx(struct chan_call *call, struct ast_channel *ast, int c
        call->state = CHAN_LCR_STATE_RELEASE;
        ast_hangup(ast); // call will be destroyed here
        return;
-       
+
        start:
        /* send setup to asterisk */
        CDEBUG(call, ast, "Starting call to Asterisk due to matching extension.\n");
 
-       #ifdef LCR_FOR_CALLWEAVER       
+       #ifdef LCR_FOR_CALLWEAVER
        ast->type = "LCR";
        snprintf(ast->name, sizeof(ast->name), "LCR/%s-%04x",ast->cid.cid_num, ast_random() & 0xffff);
        #endif
-       
+
        ret = ast_pbx_start(ast);
        if (ret < 0) {
                cause = (ret==-2)?34:27;
@@ -859,7 +860,7 @@ static void lcr_in_setup(struct chan_call *call, int message_type, union paramet
        #ifdef LCR_FOR_ASTERISK
        ast = ast_channel_alloc(1, AST_STATE_RESERVED, NULL, NULL, "", NULL, "", 0, "%s/%d", lcr_type, ++glob_channel);
        #endif
-       
+
        if (!ast) {
                /* release */
                CERROR(call, NULL, "Failed to create Asterisk channel - releasing.\n");
@@ -873,7 +874,7 @@ static void lcr_in_setup(struct chan_call *call, int message_type, union paramet
        ast->tech_pvt = call;
        ast->tech = &lcr_tech;
        ast->fds[0] = call->pipe[0];
-       
+
        /* fill setup information */
        if (param->setup.dialinginfo.id)
                strncpy(ast->exten, param->setup.dialinginfo.id, AST_MAX_EXTENSION-1);
@@ -1080,8 +1081,8 @@ static void lcr_in_release(struct chan_call *call, int message_type, union param
        call->state = CHAN_LCR_STATE_RELEASE;
        /* copy release info */
        if (!call->cause) {
-              call->cause = param->disconnectinfo.cause;
-              call->location = param->disconnectinfo.location;
+               call->cause = param->disconnectinfo.cause;
+               call->location = param->disconnectinfo.location;
        }
        /* if we have an asterisk instance, queue hangup, else we are done */
        if (ast) {
@@ -1099,7 +1100,7 @@ static void lcr_in_release(struct chan_call *call, int message_type, union param
        } else {
                free_call(call);
        }
-       
+
 }
 
 /*
@@ -1110,7 +1111,7 @@ static void lcr_in_information(struct chan_call *call, int message_type, union p
        struct ast_channel *ast = call->ast;
 
        CDEBUG(call, call->ast, "Incoming information from LCR. (dialing=%s)\n", param->information.id);
-       
+
        if (!ast) return;
 
        /* pbx not started */
@@ -1120,14 +1121,14 @@ static void lcr_in_information(struct chan_call *call, int message_type, union p
                lcr_start_pbx(call, ast, param->information.sending_complete);
                return;
        }
-       
+
        /* change dailing state after setup */
        if (call->state == CHAN_LCR_STATE_IN_SETUP) {
                CDEBUG(call, call->ast, "Changing from SETUP to DIALING state.\n");
                call->state = CHAN_LCR_STATE_IN_DIALING;
 //             ast_setstate(ast, AST_STATE_DIALING);
        }
-       
+
        /* queue digits */
        if (call->state == CHAN_LCR_STATE_IN_DIALING && param->information.id[0]) {
                if (!wake_global) {
@@ -1303,6 +1304,10 @@ int receive_message(int message_type, unsigned int ref, union parameter *param)
                                        CDEBUG(call, call->ast, "Join bchannel, because call is already bridged.\n");
                                        bchannel_join(bchannel, call->bridge_id);
                                }
+                               /* ignore all dsp features, if it is a loopback interface */
+                               if (param->bchannel.isloopback)
+                                       call->nodsp = 1;
+
                                /* create only, if call exists, othewhise it bchannel is freed below... */
                                if (bchannel_create(bchannel, ((call->nodsp || call->faxdetect > 0)?1:0) + ((call->hdlc)?2:0), call->nodsp_queue))
                                        bchannel_activate(bchannel, 1);
@@ -1333,7 +1338,7 @@ int receive_message(int message_type, unsigned int ref, union parameter *param)
                        newparam.bchannel.type = BCHANNEL_REMOVE_ACK;
                        newparam.bchannel.handle = param->bchannel.handle;
                        send_message(MESSAGE_BCHANNEL, 0, &newparam);
-                       
+
                        break;
 
                        default:
@@ -1344,7 +1349,7 @@ int receive_message(int message_type, unsigned int ref, union parameter *param)
 
        /* handle new ref */
        if (message_type == MESSAGE_NEWREF) {
-               if (param->direction) {
+               if (param->newref.direction) {
                        /* new ref from lcr */
                        CDEBUG(NULL, NULL, "Received new ref by LCR, due to incomming call. (ref=%ld)\n", ref);
                        if (!ref || find_call_ref(ref)) {
@@ -1527,7 +1532,7 @@ static int handle_socket(struct lcr_fd *fd, unsigned int what, void *instance, i
                /* read from socket */
                len = read(lcr_sock, &msg, sizeof(msg));
                if (len == 0) {
-                       CERROR(NULL, NULL, "Socket closed.\n");
+                       CERROR(NULL, NULL, "Socket closed.(read)\n");
                        error:
                        CERROR(NULL, NULL, "Handling of socket failed - closing for some seconds.\n");
                        close_socket();
@@ -1560,7 +1565,7 @@ static int handle_socket(struct lcr_fd *fd, unsigned int what, void *instance, i
                admin = admin_first;
                len = write(lcr_sock, &admin->msg, sizeof(msg));
                if (len == 0) {
-                       CERROR(NULL, NULL, "Socket closed.\n");
+                       CERROR(NULL, NULL, "Socket closed.(write)\n");
                        goto error;
                }
                if (len > 0) {
@@ -1638,7 +1643,7 @@ void close_socket(void)
        admin_first = NULL;
 
        /* close socket */
-       if (lcr_sock >= 0)      
+       if (lcr_sock >= 0)
                close(lcr_sock);
        lcr_sock = -1;
        global_change = 1;
@@ -1706,7 +1711,7 @@ again:
                                        CDEBUG(call, ast, "Sending queued digit '%c' to Asterisk.\n", *p);
                                        /* send digit to asterisk */
                                        memset(&fr, 0, sizeof(fr));
-                                       
+
                                        #ifdef LCR_FOR_ASTERISK
                                        fr.frametype = AST_FRAME_DTMF_BEGIN;
                                        #endif
@@ -1714,16 +1719,16 @@ again:
                                        #ifdef LCR_FOR_CALLWEAVER
                                        fr.frametype = AST_FRAME_DTMF;
                                        #endif
-                                       
+
                                        fr.subclass = *p;
                                        fr.delivery = ast_tv(0, 0);
                                        ast_queue_frame(ast, &fr);
-                                       
+
                                        #ifdef LCR_FOR_ASTERISK
                                        fr.frametype = AST_FRAME_DTMF_END;
                                        ast_queue_frame(ast, &fr);
                                        #endif
-                                                                                       
+
                                        break;
                                default:
                                        CDEBUG(call, ast, "Ignoring queued digit 0x%02x.\n", *p);
@@ -1805,7 +1810,7 @@ struct ast_channel *lcr_request(const char *type, int format, void *data, int *c
 {
        char exten[256], *dial, *interface, *opt;
        struct ast_channel *ast;
-        struct chan_call *call;
+       struct chan_call *call;
 
        ast_mutex_lock(&chan_lock);
        CDEBUG(NULL, NULL, "Received request from Asterisk. (data=%s)\n", (char *)data);
@@ -1830,11 +1835,11 @@ struct ast_channel *lcr_request(const char *type, int format, void *data, int *c
        #ifdef LCR_FOR_ASTERISK
        ast = ast_channel_alloc(1, AST_STATE_RESERVED, NULL, NULL, "", NULL, "", 0, "%s/%d", lcr_type, ++glob_channel);
        #endif
-       
+
        #ifdef LCR_FOR_CALLWEAVER
        ast = ast_channel_alloc(1);
        #endif
-               
+
        if (!ast) {
                CERROR(NULL, NULL, "Failed to create Asterisk channel.\n");
                free_call(call);
@@ -1894,16 +1899,16 @@ struct ast_channel *lcr_request(const char *type, int format, void *data, int *c
 static int lcr_call(struct ast_channel *ast, char *dest, int timeout)
 {
        union parameter newparam;
-        struct chan_call *call;
+       struct chan_call *call;
 
        ast_mutex_lock(&chan_lock);
-        call = ast->tech_pvt;
-        
-        #ifdef LCR_FOR_CALLWEAVER
-        ast->type = "LCR";
-        snprintf(ast->name, sizeof(ast->name), "LCR/%s-%04x",call->dialstring, ast_random() & 0xffff);
-        #endif
-        
+       call = ast->tech_pvt;
+
+       #ifdef LCR_FOR_CALLWEAVER
+       ast->type = "LCR";
+       snprintf(ast->name, sizeof(ast->name), "LCR/%s-%04x",call->dialstring, ast_random() & 0xffff);
+       #endif
+
        if (!call) {
                CERROR(NULL, ast, "Received call from Asterisk, but call instance does not exist.\n");
                ast_mutex_unlock(&chan_lock);
@@ -1916,7 +1921,9 @@ static int lcr_call(struct ast_channel *ast, char *dest, int timeout)
        call->pbx_started = 1;
        /* send MESSAGE_NEWREF */
        memset(&newparam, 0, sizeof(union parameter));
-       newparam.direction = 0; /* request from app */
+       newparam.newref.direction = 0; /* request from app */
+       if (!strcmp(call->interface, "pbx"))
+               newparam.newref.mode = 1;
        send_message(MESSAGE_NEWREF, 0, &newparam);
 
        /* set hdlc if capability requires hdlc */
@@ -1940,49 +1947,49 @@ static int lcr_call(struct ast_channel *ast, char *dest, int timeout)
                        sizeof(call->cid_num)-1);
 
        if (ast->cid.cid_name) if (ast->cid.cid_name[0])
-               strncpy(call->cid_name, ast->cid.cid_name, 
+               strncpy(call->cid_name, ast->cid.cid_name,
                        sizeof(call->cid_name)-1);
        if (ast->cid.cid_rdnis) if (ast->cid.cid_rdnis[0])
-               strncpy(call->cid_rdnis, ast->cid.cid_rdnis, 
+               strncpy(call->cid_rdnis, ast->cid.cid_rdnis,
                        sizeof(call->cid_rdnis)-1);
 
        ast_mutex_unlock(&chan_lock);
-       return 0; 
+       return 0;
 }
 
 static void send_digit_to_chan(struct ast_channel * ast, char digit )
 {
-        static const char* dtmf_tones[] = {
-                "!941+1336/100,!0/100", /* 0 */
-                "!697+1209/100,!0/100", /* 1 */
-                "!697+1336/100,!0/100", /* 2 */
-                "!697+1477/100,!0/100", /* 3 */
-                "!770+1209/100,!0/100", /* 4 */
-                "!770+1336/100,!0/100", /* 5 */
-                "!770+1477/100,!0/100", /* 6 */
-                "!852+1209/100,!0/100", /* 7 */
-                "!852+1336/100,!0/100", /* 8 */
-                "!852+1477/100,!0/100", /* 9 */
-                "!697+1633/100,!0/100", /* A */
-                "!770+1633/100,!0/100", /* B */
-                "!852+1633/100,!0/100", /* C */
-                "!941+1633/100,!0/100", /* D */
-                "!941+1209/100,!0/100", /* * */
-                "!941+1477/100,!0/100" };       /* # */
-
-        if (digit >= '0' && digit <='9')
-                ast_playtones_start(ast,0,dtmf_tones[digit-'0'], 0);
-        else if (digit >= 'A' && digit <= 'D')
-                ast_playtones_start(ast,0,dtmf_tones[digit-'A'+10], 0);
-        else if (digit == '*')
-                ast_playtones_start(ast,0,dtmf_tones[14], 0);
-        else if (digit == '#')
-                ast_playtones_start(ast,0,dtmf_tones[15], 0);
-        else {
-                /* not handled */
+       static const char* dtmf_tones[] = {
+               "!941+1336/100,!0/100", /* 0 */
+               "!697+1209/100,!0/100", /* 1 */
+               "!697+1336/100,!0/100", /* 2 */
+               "!697+1477/100,!0/100", /* 3 */
+               "!770+1209/100,!0/100", /* 4 */
+               "!770+1336/100,!0/100", /* 5 */
+               "!770+1477/100,!0/100", /* 6 */
+               "!852+1209/100,!0/100", /* 7 */
+               "!852+1336/100,!0/100", /* 8 */
+               "!852+1477/100,!0/100", /* 9 */
+               "!697+1633/100,!0/100", /* A */
+               "!770+1633/100,!0/100", /* B */
+               "!852+1633/100,!0/100", /* C */
+               "!941+1633/100,!0/100", /* D */
+               "!941+1209/100,!0/100", /* * */
+               "!941+1477/100,!0/100" };       /* # */
+
+       if (digit >= '0' && digit <='9')
+               ast_playtones_start(ast,0,dtmf_tones[digit-'0'], 0);
+       else if (digit >= 'A' && digit <= 'D')
+               ast_playtones_start(ast,0,dtmf_tones[digit-'A'+10], 0);
+       else if (digit == '*')
+               ast_playtones_start(ast,0,dtmf_tones[14], 0);
+       else if (digit == '#')
+               ast_playtones_start(ast,0,dtmf_tones[15], 0);
+       else {
+               /* not handled */
                CDEBUG(NULL, ast, "Unable to handle DTMF tone "
                        "'%c' for '%s'\n", digit, ast->name);
-        }
+       }
 }
 
 #ifdef LCR_FOR_ASTERISK
@@ -1992,7 +1999,7 @@ static int lcr_digit_begin(struct ast_channel *ast, char digit)
 static int lcr_digit(struct ast_channel *ast, char digit)
 #endif
 {
-        struct chan_call *call;
+       struct chan_call *call;
        union parameter newparam;
        char buf[]="x";
 
@@ -2005,7 +2012,7 @@ static int lcr_digit(struct ast_channel *ast, char digit)
                return 0;
 
        ast_mutex_lock(&chan_lock);
-        call = ast->tech_pvt;
+       call = ast->tech_pvt;
        if (!call) {
                CERROR(NULL, ast, "Received digit from Asterisk, but no call instance exists.\n");
                ast_mutex_unlock(&chan_lock);
@@ -2043,17 +2050,17 @@ static int lcr_digit(struct ast_channel *ast, char digit)
 static int lcr_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
 {
        int inband_dtmf = 0;
-        struct chan_call *call;
+       struct chan_call *call;
 #endif
 
        ast_mutex_lock(&chan_lock);
 
-        call = ast->tech_pvt;
+       call = ast->tech_pvt;
 
        if (!call) {
-               CERROR(NULL, ast, 
-                      "Received digit from Asterisk, "
-                      "but no call instance exists.\n");
+               CERROR(NULL, ast,
+                       "Received digit from Asterisk, "
+                       "but no call instance exists.\n");
                ast_mutex_unlock(&chan_lock);
                return -1;
        }
@@ -2077,18 +2084,18 @@ static int lcr_digit_end(struct ast_channel *ast, char digit, unsigned int durat
 static int lcr_answer(struct ast_channel *ast)
 {
        union parameter newparam;
-        struct chan_call *call;
+       struct chan_call *call;
 
        ast_mutex_lock(&chan_lock);
-        call = ast->tech_pvt;
+       call = ast->tech_pvt;
        if (!call) {
                CERROR(NULL, ast, "Received answer from Asterisk, but no call instance exists.\n");
                ast_mutex_unlock(&chan_lock);
                return -1;
        }
-       
+
        CDEBUG(call, ast, "Received answer from Asterisk (maybe during lcr_bridge).\n");
-               
+
        /* copy connectinfo, if bridged */
        if (call->bridge_call)
                memcpy(&call->connectinfo, &call->bridge_call->connectinfo, sizeof(struct connect_info));
@@ -2110,20 +2117,20 @@ static int lcr_answer(struct ast_channel *ast)
        /* enable keypad */
 //     memset(&newparam, 0, sizeof(union parameter));
 //     send_message(MESSAGE_ENABLEKEYPAD, call->ref, &newparam);
-       
-       ast_mutex_unlock(&chan_lock);
-        return 0;
+
+       ast_mutex_unlock(&chan_lock);
+       return 0;
 }
 
 static int lcr_hangup(struct ast_channel *ast)
 {
-        struct chan_call *call;
+       struct chan_call *call;
        pthread_t tid = pthread_self();
 
        if (!pthread_equal(tid, chan_tid)) {
                ast_mutex_lock(&chan_lock);
        }
-        call = ast->tech_pvt;
+       call = ast->tech_pvt;
        if (!call) {
                CERROR(NULL, ast, "Received hangup from Asterisk, but no call instance exists.\n");
                if (!pthread_equal(tid, chan_tid)) {
@@ -2165,7 +2172,7 @@ static int lcr_hangup(struct ast_channel *ast)
                        call->state = CHAN_LCR_STATE_RELEASE;
                        call->ast = NULL;
                }
-       } 
+       }
        if (!pthread_equal(tid, chan_tid)) {
                ast_mutex_unlock(&chan_lock);
        }
@@ -2174,14 +2181,14 @@ static int lcr_hangup(struct ast_channel *ast)
 
 static int lcr_write(struct ast_channel *ast, struct ast_frame *fr)
 {
-        struct chan_call *call;
+       struct chan_call *call;
        struct ast_frame * f = fr;
 
        if (!f->subclass)
                CDEBUG(NULL, ast, "No subclass\n");
        if (!(f->subclass & ast->nativeformats)) {
                CDEBUG(NULL, ast, 
-                      "Unexpected format. "
+                              "Unexpected format. "
                       "Activating emergency conversion...\n");
 
                ast_set_write_format(ast, f->subclass);
@@ -2190,7 +2197,7 @@ static int lcr_write(struct ast_channel *ast, struct ast_frame *fr)
        }
        
        ast_mutex_lock(&chan_lock);
-        call = ast->tech_pvt;
+       call = ast->tech_pvt;
        if (!call) {
                ast_mutex_unlock(&chan_lock);
                if (f != fr) {
@@ -2210,11 +2217,11 @@ static int lcr_write(struct ast_channel *ast, struct ast_frame *fr)
 
 static struct ast_frame *lcr_read(struct ast_channel *ast)
 {
-        struct chan_call *call;
+       struct chan_call *call;
        int len = 0;
 
        ast_mutex_lock(&chan_lock);
-        call = ast->tech_pvt;
+       call = ast->tech_pvt;
        if (!call) {
                ast_mutex_unlock(&chan_lock);
                return NULL;
@@ -2235,11 +2242,11 @@ static struct ast_frame *lcr_read(struct ast_channel *ast)
                        #ifdef LCR_FOR_ASTERISK
                        return &ast_null_frame;
                        #endif
-                       
+
                        #ifdef LCR_FOR_CALLWEAVER
                        return &nullframe;
                        #endif
-                       
+
                }
                if (len <= 0) {
                        close(call->pipe[0]);
@@ -2274,20 +2281,20 @@ static struct ast_frame *lcr_read(struct ast_channel *ast)
 static int lcr_indicate(struct ast_channel *ast, int cond, const void *data, size_t datalen)
 {
        union parameter newparam;
-        int res = 0;
-        struct chan_call *call;
+       int res = 0;
+       struct chan_call *call;
        const struct tone_zone_sound *ts = NULL;
 
        ast_mutex_lock(&chan_lock);
-        call = ast->tech_pvt;
+       call = ast->tech_pvt;
        if (!call) {
                CERROR(NULL, ast, "Received indicate from Asterisk, but no call instance exists.\n");
                ast_mutex_unlock(&chan_lock);
                return -1;
        }
 
-        switch (cond) {
-                case AST_CONTROL_BUSY:
+       switch (cond) {
+               case AST_CONTROL_BUSY:
                        CDEBUG(call, ast, "Received indicate AST_CONTROL_BUSY from Asterisk.\n");
                        ast_setstate(ast, AST_STATE_BUSY);
                        if (call->state != CHAN_LCR_STATE_OUT_DISCONNECT) {
@@ -2303,7 +2310,7 @@ static int lcr_indicate(struct ast_channel *ast, int cond, const void *data, siz
                                ts = ast_get_indication_tone(ast->zone, "busy");
                        }
                        break;
-                case AST_CONTROL_CONGESTION:
+               case AST_CONTROL_CONGESTION:
                        CDEBUG(call, ast, "Received indicate AST_CONTROL_CONGESTION from Asterisk. (cause %d)\n", ast->hangupcause);
                        if (call->state != CHAN_LCR_STATE_OUT_DISCONNECT) {
                                /* send message to lcr */
@@ -2318,7 +2325,7 @@ static int lcr_indicate(struct ast_channel *ast, int cond, const void *data, siz
                                ts = ast_get_indication_tone(ast->zone, "congestion");
                        }
                        break;
-                case AST_CONTROL_PROCEEDING:
+               case AST_CONTROL_PROCEEDING:
                        CDEBUG(call, ast, "Received indicate AST_CONTROL_PROCEEDING from Asterisk.\n");
                        if (call->state == CHAN_LCR_STATE_IN_SETUP
                         || call->state == CHAN_LCR_STATE_IN_DIALING) {
@@ -2329,7 +2336,7 @@ static int lcr_indicate(struct ast_channel *ast, int cond, const void *data, siz
                                call->state = CHAN_LCR_STATE_IN_PROCEEDING;
                        }
                        break;
-                case AST_CONTROL_RINGING:
+               case AST_CONTROL_RINGING:
                        CDEBUG(call, ast, "Received indicate AST_CONTROL_RINGING from Asterisk.\n");
                        ast_setstate(ast, AST_STATE_RING);
                        if (call->state == CHAN_LCR_STATE_IN_SETUP
@@ -2355,35 +2362,35 @@ static int lcr_indicate(struct ast_channel *ast, int cond, const void *data, siz
                                send_message(MESSAGE_BCHANNEL, call->ref, &newparam);
                        }
                        break;
-                case -1:
+               case -1:
                        CDEBUG(call, ast, "Received indicate -1.\n");
                        ast_playtones_stop(ast);
-                        res = -1;
+                       res = -1;
                        break;
 
-                case AST_CONTROL_VIDUPDATE:
+               case AST_CONTROL_VIDUPDATE:
                        CDEBUG(call, ast, "Received indicate AST_CONTROL_VIDUPDATE.\n");
-                        res = -1;
-                        break;
-                case AST_CONTROL_HOLD:
+                       res = -1;
+                       break;
+               case AST_CONTROL_HOLD:
                        CDEBUG(call, ast, "Received indicate AST_CONTROL_HOLD from Asterisk.\n");
                        /* send message to lcr */
                        memset(&newparam, 0, sizeof(union parameter));
                        newparam.notifyinfo.notify = INFO_NOTIFY_REMOTE_HOLD;
                        send_message(MESSAGE_NOTIFY, call->ref, &newparam);
-                       
+
                        /*start music onhold*/
                        #ifdef LCR_FOR_ASTERISK
                        ast_moh_start(ast,data,ast->musicclass);
                        #endif
-                       
+
                        #ifdef LCR_FOR_CALLWEAVER
                        ast_moh_start(ast, NULL);
                        #endif
-                       
+
                        call->on_hold = 1;
-                        break;
-                case AST_CONTROL_UNHOLD:
+                       break;
+               case AST_CONTROL_UNHOLD:
                        CDEBUG(call, ast, "Received indicate AST_CONTROL_UNHOLD from Asterisk.\n");
                        /* send message to lcr */
                        memset(&newparam, 0, sizeof(union parameter));
@@ -2391,21 +2398,21 @@ static int lcr_indicate(struct ast_channel *ast, int cond, const void *data, siz
                        send_message(MESSAGE_NOTIFY, call->ref, &newparam);
 
                        /*stop moh*/
-                       ast_moh_stop(ast);
+                       ast_moh_stop(ast);
                        call->on_hold = 0;
-                       break;
+                       break;
 #ifdef AST_CONTROL_SRCUPDATE
-               case AST_CONTROL_SRCUPDATE:
+               case AST_CONTROL_SRCUPDATE:
 #else
-               case 20:
+               case 20:
 #endif
                        CDEBUG(call, ast, "Received AST_CONTROL_SRCUPDATE from Asterisk.\n");
-                        break;
-                default:
+                       break;
+               default:
                        CERROR(call, ast, "Received indicate from Asterisk with unknown condition %d.\n", cond);
-                        res = -1;
+                       res = -1;
                        break;
-        }
+       }
 
        if (ts && ts->data[0]) {
                ast_playtones_start(ast, 0, ts->data, 1);
@@ -2413,7 +2420,7 @@ static int lcr_indicate(struct ast_channel *ast, int cond, const void *data, siz
 
        /* return */
        ast_mutex_unlock(&chan_lock);
-        return res;
+       return res;
 }
 
 /*
@@ -2421,7 +2428,7 @@ static int lcr_indicate(struct ast_channel *ast, int cond, const void *data, siz
  */
 static int lcr_fixup(struct ast_channel *oldast, struct ast_channel *ast)
 {
-        struct chan_call *call;
+       struct chan_call *call;
 
        if (!ast) {
                return -1;
@@ -2446,7 +2453,7 @@ static int lcr_fixup(struct ast_channel *oldast, struct ast_channel *ast)
  */
 static int lcr_send_text(struct ast_channel *ast, const char *text)
 {
-        struct chan_call *call;
+       struct chan_call *call;
        union parameter newparam;
 
        ast_mutex_lock(&chan_lock);
@@ -2495,15 +2502,15 @@ enum ast_bridge_result lcr_bridge(struct ast_channel *ast1,
                return AST_BRIDGE_COMPLETE;
        }
 
-       /* join, if both call instances uses dsp 
+       /* join, if both call instances uses dsp
           ignore the case of fax detection here it may be benificial for ISDN fax machines or pass through.
-       */
+       */
        if (!call1->nodsp && !call2->nodsp) {
                CDEBUG(NULL, NULL, "Both calls use DSP, bridging via DSP.\n");
 
                /* get bridge id and join */
                bridge_id = new_bridge_id();
-               
+
                call1->bridge_id = bridge_id;
                if (call1->bchannel)
                        bchannel_join(call1->bchannel, bridge_id);
@@ -2557,9 +2564,9 @@ enum ast_bridge_result lcr_bridge(struct ast_channel *ast1,
 
                call2->on_hold = 0;
        }
-       
+
        ast_mutex_unlock(&chan_lock);
-       
+
        while(1) {
                to = -1;
                who = ast_waitfor_n(carr, 2, &to);
@@ -2569,7 +2576,7 @@ enum ast_bridge_result lcr_bridge(struct ast_channel *ast1,
                        break;
                }
                f = ast_read(who);
-    
+
                if (!f || f->frametype == AST_FRAME_CONTROL) {
                        if (!f)
                                CDEBUG(NULL, NULL, "Got hangup.\n");
@@ -2580,14 +2587,14 @@ enum ast_bridge_result lcr_bridge(struct ast_channel *ast1,
                        *rc=who;
                        break;
                }
-               
+
                if ( f->frametype == AST_FRAME_DTMF ) {
                        CDEBUG(NULL, NULL, "Got DTMF.\n");
                        *fo=f;
                        *rc=who;
                        break;
                }
-       
+
 
                if (who == ast1) {
                        ast_write(ast2,f);
@@ -2595,9 +2602,9 @@ enum ast_bridge_result lcr_bridge(struct ast_channel *ast1,
                else {
                        ast_write(ast1,f);
                }
-    
+
        }
-       
+
        CDEBUG(NULL, NULL, "Releasing bridge.\n");
 
        /* split channels */
@@ -2640,7 +2647,7 @@ static struct ast_channel_tech lcr_tech = {
        #endif
 
        .call = lcr_call,
-       .bridge = lcr_bridge, 
+       .bridge = lcr_bridge,
        .hangup = lcr_hangup,
        .answer = lcr_answer,
        .read = lcr_read,
@@ -2757,11 +2764,11 @@ static int lcr_config_exec(struct ast_channel *ast, void *data, char **argv)
        #ifdef LCR_FOR_ASTERISK
        CDEBUG(NULL, ast, "Received lcr_config (data=%s)\n", (char *)data);
        #endif
-       
+
        #ifdef LCR_FOR_CALLWEAVER
        CDEBUG(NULL, ast, "Received lcr_config (data=%s)\n", argv[0]);
        #endif
-       
+
        /* find channel */
        call = call_first;
        while(call) {
@@ -2770,12 +2777,12 @@ static int lcr_config_exec(struct ast_channel *ast, void *data, char **argv)
                call = call->next;
        }
        if (call)
-               
+
                #ifdef LCR_FOR_ASTERISK
                apply_opt(call, (char *)data);
-               #endif          
-               
-               #ifdef LCR_FOR_CALLWEAVER               
+               #endif
+
+               #ifdef LCR_FOR_CALLWEAVER
                apply_opt(call, (char *)argv[0]);
                #endif
 
@@ -2804,12 +2811,12 @@ int load_module(void)
 
                #ifdef LCR_FOR_ASTERISK
                return AST_MODULE_LOAD_DECLINE;
-               #endif          
-               
+               #endif
+
                #ifdef LCR_FOR_CALLWEAVER
                return 0;
                #endif
-                       
+
        }
 
        ast_mutex_init(&chan_lock);
@@ -2818,11 +2825,11 @@ int load_module(void)
        if (bchannel_initialize()) {
                CERROR(NULL, NULL, "Unable to open mISDN device\n");
                close_socket();
-               
+
                #ifdef LCR_FOR_ASTERISK
                return AST_MODULE_LOAD_DECLINE;
-               #endif          
-               
+               #endif
+
                #ifdef LCR_FOR_CALLWEAVER
                return 0;
                #endif
@@ -2837,29 +2844,29 @@ int load_module(void)
 
                #ifdef LCR_FOR_ASTERISK
                return AST_MODULE_LOAD_DECLINE;
-               #endif          
-               
+               #endif
+
                #ifdef LCR_FOR_CALLWEAVER
                return 0;
                #endif
        }
 
        ast_register_application("lcr_config", lcr_config_exec, "lcr_config",
-                               
+
                                 #ifdef LCR_FOR_ASTERISK
                                 "lcr_config(<opt><optarg>:<opt>:...)\n"
                                 #endif
-                                
+
                                 #ifdef LCR_FOR_CALLWEAVER
-                                "lcr_config(<opt><optarg>:<opt>:...)\n",                                
+                                "lcr_config(<opt><optarg>:<opt>:...)\n",
                                 #endif
-                                                        
+
                                 "Sets LCR opts. and optargs\n"
                                 "\n"
                                 "The available options are:\n"
                                 "    d - Send display text on called phone, text is the optarg.\n"
                                 "    n - Don't detect dtmf tones on called channel.\n"
-                                "    h - Force data call (HDLC).\n" 
+                                "    h - Force data call (HDLC).\n"
                                 "    t - Disable mISDN_dsp features (required for fax application).\n"
                                 "    q - Add queue to make fax stream seamless (required for fax app).\n"
                                 "        Use queue size in miliseconds for optarg. (try 250)\n"
@@ -2882,8 +2889,8 @@ int load_module(void)
                                 "options: \"n:t:q250\" for seamless audio transmission.\n"
                );
 
-#if 0  
+
+#if 0
        ast_cli_register(&cli_show_lcr);
        ast_cli_register(&cli_show_calls);
        ast_cli_register(&cli_reload_routing);
@@ -2893,7 +2900,7 @@ int load_module(void)
        ast_cli_register(&cli_port_unload);
 #endif
 
-       quit = 0;       
+       quit = 0;
        if ((pthread_create(&chan_tid, NULL, chan_thread, NULL)<0)) {
                /* failed to create thread */
                bchannel_deinitialize();
@@ -2902,12 +2909,12 @@ int load_module(void)
 
                #ifdef LCR_FOR_ASTERISK
                return AST_MODULE_LOAD_DECLINE;
-               #endif          
-               
+               #endif
+
                #ifdef LCR_FOR_CALLWEAVER
                return 0;
                #endif
-               
+
        }
        return 0;
 }
@@ -2918,11 +2925,11 @@ int unload_module(void)
        CDEBUG(NULL, NULL, "-- Unregistering mISDN Channel Driver --\n");
 
        quit = 1;
-       pthread_join(chan_tid, NULL);   
-       
+       pthread_join(chan_tid, NULL);
+
        ast_channel_unregister(&lcr_tech);
 
-        ast_unregister_application("lcr_config");
+       ast_unregister_application("lcr_config");
 
 
        if (mISDN_created) {
index 148513b..713a620 100644 (file)
@@ -1,15 +1,7 @@
 # LCR GSM options
 #################
 
-# Two Loopback interfaces for audio transfer between OpenBSC and mISDN.
-# They are also used for any Osmocom-BB interface, if exists.
-# The first interface must provide B-channelis for each call mobile call.
-# The seond interface links them to LCR.
-# Use 30 B-channels unless you need more due to many TRXs or mobile stations.
-# -> Load with: "modprobe mISDN_l1loop pri=1 nchannel=30"
-# By default "mISDN_l1loop.1" and "mISDN_l1loop.2" is used.
-#interface-bsc mISDN_l1loop.1
-#interface-lcr mISDN_l1loop.2
+# interfaces-bsc and interface-lcr has been moved to options.conf!
 
 # Enable debugging of OpenBSC library.
 # Refer to OpenBSC project for debugging options.
index 6e19538..4c80fed 100644 (file)
 ##external
 
 
+# Use chan_lcr (Asterisk PBX interface) as internal interface.
+# The interface requires mISDN_l1loop.ko to be loaded:
+#  modprobe mISDN_l1loop nchannel=8 # use up to 8 b-channels
+# The caller ID is used as extension, if "extension" parameter is given.
+# Use "screen-in % xxx" to modify any caller id to xxx.
+# An internal extension does not receive tones ("earlyb"), but sends them. 
+#[ast]
+#remote asterisk
+#extension
+##screen-in % 209
+#earlyb no
+#tones yes
+
+
 # Hint: Enter "lcr interface" for quick help on interface options.
 
 
index e0e93a0..cb48ea7 100644 (file)
 # Enable polling in main loop.
 # This feature is temporarily for test purpose. Don't enable it
 #polling
+
+# Two Loopback interfaces for audio transfer between GSM/Asterisk and mISDN.
+# The first interface must provide B-channels for each GSM call or channel
+# instance, the seond interface links them to LCR.
+# Use 30 B-channels unless you need more due to more instances.
+# -> Load with: "modprobe mISDN_l1loop pri=1 nchannel=30"
+# By default "mISDN_l1loop.1" and "mISDN_l1loop.2" is used.
+#loopback-ext mISDN_l1loop.1
+#loopback-lcr mISDN_l1loop.2
+
diff --git a/gsm.cpp b/gsm.cpp
index 7245632..e7216dd 100644 (file)
--- a/gsm.cpp
+++ b/gsm.cpp
@@ -119,7 +119,7 @@ void Pgsm::bchannel_close(void)
 
 static int b_handler(struct lcr_fd *fd, unsigned int what, void *instance, int index);
 
-/* open bsc side bchannel */
+/* open external side bchannel */
 int Pgsm::bchannel_open(int index)
 {
        int ret;
@@ -295,70 +295,10 @@ void gsm_trace_header(struct mISDNport *mISDNport, class PmISDN *port, unsigned
                    msgtext);
 }
 
-/* select bchannel */
+/* select free bchannel from loopback interface */
 int Pgsm::hunt_bchannel(void)
 {
-       int channel;
-       int i;
-       char map[p_m_mISDNport->b_num];
-       struct interface *interface;
-       struct interface_port *ifport;
-
-       chan_trace_header(p_m_mISDNport, this, "CHANNEL SELECTION (setup)", DIRECTION_NONE);
-       add_trace("channel", "reserved", "%d", p_m_mISDNport->b_reserved);
-       if (p_m_mISDNport->b_reserved >= p_m_mISDNport->b_num) { // of out chan..
-               add_trace("conclusion", NULL, "all channels are reserved");
-               end_trace();
-               return(-34); // no channel
-       }
-
-       /* map all used ports of shared loopback interface */
-       memset(map, 0, sizeof(map));
-       interface = interface_first;
-       while(interface) {
-               ifport = interface->ifport;
-               while(ifport) {
-#if defined WITH_GSM_BS && defined WITH_GSM_MS
-                       if ((ifport->gsm_bs || ifport->gsm_ms) && ifport->mISDNport) {
-#else
-#ifdef WITH_GSM_BS
-                       if (ifport->gsm_bs && ifport->mISDNport) {
-#endif
-#ifdef WITH_GSM_MS
-                       if (ifport->gsm_ms && ifport->mISDNport) {
-#endif
-#endif
-                               i = 0;
-                               while(i < p_m_mISDNport->b_num) {
-                                       if (p_m_mISDNport->b_port[i])
-                                               map[i] = 1;
-                                       i++;
-                               }
-                       }
-                       ifport = ifport->next;
-               }
-               interface = interface->next;
-       }
-
-       /* find channel */
-       i = 0;
-       channel = 0;
-       while(i < p_m_mISDNport->b_num) {
-               if (!map[i]) {
-                       channel = i+1+(i>=15);
-                       break;
-               }
-               i++;
-       }
-       if (!channel) {
-               add_trace("conclusion", NULL, "no channel available");
-               end_trace();
-               return(-6); // channel unacceptable
-       }
-       add_trace("conclusion", NULL, "channel available");
-       add_trace("connect", "channel", "%d", channel);
-       end_trace();
-       return(channel);
+       return loop_hunt_bchannel(this, p_m_mISDNport);
 }
 
 /* PROCEEDING INDICATION */
@@ -884,87 +824,10 @@ static int b_handler(struct lcr_fd *fd, unsigned int what, void *instance, int i
        return 0;
 }
 
-static void gsm_sock_close(void)
-{
-       if (gsm->gsm_sock > -1)
-               close(gsm->gsm_sock);
-       gsm->gsm_sock = -1;
-}
-
-static int gsm_sock_open(char *portname)
-{
-       int ret;
-       int cnt;
-       unsigned long on = 1;
-       struct sockaddr_mISDN addr;
-       struct mISDN_devinfo devinfo;
-       int pri, bri;
-
-       /* check port counts */
-       ret = ioctl(mISDNsocket, IMGETCOUNT, &cnt);
-       if (ret < 0) {
-               fprintf(stderr, "Cannot get number of mISDN devices. (ioctl IMGETCOUNT failed ret=%d)\n", ret);
-               return(ret);
-       }
-
-       if (cnt <= 0) {
-               PERROR_RUNTIME("Found no card. Please be sure to load card drivers.\n");
-               return -EIO;
-       }
-       gsm->gsm_port = mISDN_getportbyname(mISDNsocket, cnt, portname);
-       if (gsm->gsm_port < 0) {
-               PERROR_RUNTIME("Port name '%s' not found, did you load loopback interface for GSM?.\n", portname);
-               return gsm->gsm_port;
-       }
-       /* get protocol */
-       bri = pri = 0;
-       devinfo.id = gsm->gsm_port;
-       ret = ioctl(mISDNsocket, IMGETDEVINFO, &devinfo);
-       if (ret < 0) {
-               PERROR_RUNTIME("Cannot get device information for port %d. (ioctl IMGETDEVINFO failed ret=%d)\n", gsm->gsm_port, ret);
-               return ret;
-       }
-       if (devinfo.Dprotocols & (1 << ISDN_P_TE_S0)) {
-               bri = 1;
-       }
-       if (devinfo.Dprotocols & (1 << ISDN_P_TE_E1)) {
-               pri = 1;
-       }
-       if (!pri && !pri) {
-               PERROR_RUNTIME("GSM port %d does not support TE PRI or TE BRI.\n", gsm->gsm_port);
-       }
-       /* open socket */
-       if ((gsm->gsm_sock = socket(PF_ISDN, SOCK_DGRAM, (pri)?ISDN_P_TE_E1:ISDN_P_TE_S0)) < 0) {
-               PERROR_RUNTIME("GSM port %d failed to open socket.\n", gsm->gsm_port);
-               gsm_sock_close();
-               return gsm->gsm_sock;
-       }
-       /* set nonblocking io */
-       if ((ret = ioctl(gsm->gsm_sock, FIONBIO, &on)) < 0) {
-               PERROR_RUNTIME("GSM port %d failed to set socket into nonblocking io.\n", gsm->gsm_port);
-               gsm_sock_close();
-               return ret;
-       }
-       /* bind socket to dchannel */
-       memset(&addr, 0, sizeof(addr));
-       addr.family = AF_ISDN;
-       addr.dev = gsm->gsm_port;
-       addr.channel = 0;
-       if ((ret = bind(gsm->gsm_sock, (struct sockaddr *)&addr, sizeof(addr))) < 0) {
-               PERROR_RUNTIME("GSM port %d failed to bind socket. (name = %s errno=%d)\n", gsm->gsm_port, portname, errno);
-               gsm_sock_close();
-               return (ret);
-       }
-
-       return 0;
-}
-
 int gsm_exit(int rc)
 {
        /* free gsm instance */
        if (gsm) {
-               if (gsm->gsm_sock > -1)
-                       gsm_sock_close();
                free(gsm);
                gsm = NULL;
        }
@@ -996,7 +859,7 @@ int gsm_init(void)
        }
 
        /* open gsm loop interface */
-       if (gsm_sock_open(gsm->conf.interface_bsc)) {
+       if (loopback_open()) {
                return gsm_exit(-1);
        }
 
diff --git a/gsm.h b/gsm.h
index 71ed759..de4c02b 100644 (file)
--- a/gsm.h
+++ b/gsm.h
@@ -2,8 +2,6 @@ extern int new_callref;
 
 struct gsm_conf {
        char debug[128];                /* debug info */
-       char interface_bsc[64];         /* loopback interface BSC side */
-       char interface_lcr[64];         /* loopback interface LCR side */
        char openbsc_cfg[128];          /* openbsc config file */
        char short_name[64];            /* short network name */
        char long_name[64];             /* long network name */
@@ -17,8 +15,6 @@ struct gsm_conf {
 struct lcr_gsm {
        void            *network;       /* OpenBSC network handle */
        struct gsm_conf conf;           /* gsm.conf options */
-       int             gsm_sock;       /* loopback interface GSM side */
-       int             gsm_port;       /* loopback interface port number */
 };
 
 extern struct lcr_gsm *gsm;
index a64f2ff..f25cf85 100644 (file)
@@ -29,8 +29,6 @@ int gsm_conf(struct gsm_conf *gsm_conf, char *conf_error)
 
        /* set defaults */
        SCPY(gsm_conf->debug, "");
-       SCPY(gsm_conf->interface_bsc, "mISDN_l1loop.1");
-       SCPY(gsm_conf->interface_lcr, "mISDN_l1loop.2");
        SCPY(gsm_conf->hlr, "hlr.sqlite3");
        SCPY(gsm_conf->openbsc_cfg, "openbsc.cfg");
        gsm_conf->reject_cause = 0;
@@ -105,22 +103,6 @@ int gsm_conf(struct gsm_conf *gsm_conf, char *conf_error)
                        SCPY(gsm_conf->debug, params[0]);
 
                } else
-               if (!strcmp(option,"interface-bsc")) {
-                       if (params[0][0]==0) {
-                               UPRINT(conf_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line, option);
-                               goto error;
-                       }
-                       SCPY(gsm_conf->interface_bsc, params[0]);
-
-               } else
-               if (!strcmp(option,"interface-lcr")) {
-                       if (params[0][0]==0) {
-                               UPRINT(conf_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line, option);
-                               goto error;
-                       }
-                       SCPY(gsm_conf->interface_lcr, params[0]);
-
-               } else
                if (!strcmp(option,"config")) {
                        if (params[0][0]==0) {
                                UPRINT(conf_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line, option);
index a312e4e..448affc 100644 (file)
@@ -327,9 +327,7 @@ static int inter_portname(struct interface *interface, char *filename, int line,
 
        /* check for port already assigned, but not for shared gsm interface */
        searchif = interface_newlist;
-#if defined WITH_GSM_BS || defined WITH_GSM_MS
-       if (!strcmp(value, gsm->conf.interface_lcr))
-#endif
+       if (!strcmp(value, options.loopback_lcr))
        {
                while(searchif) {
                        ifport = searchif->ifport;
@@ -918,7 +916,7 @@ static int inter_gsm_bs(struct interface *interface, char *filename, int line, c
        }
 
        /* set portname */
-       if (inter_portname(interface, filename, line, (char *)"portname", gsm->conf.interface_lcr))
+       if (inter_portname(interface, filename, line, (char *)"portname", options.loopback_lcr))
                return(-1);
 
        /* goto end of chain again to set gsmflag */
@@ -947,7 +945,7 @@ static int inter_gsm_ms(struct interface *interface, char *filename, int line, c
        }
 
        /* set portname */
-       if (inter_portname(interface, filename, line, (char *)"portname", gsm->conf.interface_lcr))
+       if (inter_portname(interface, filename, line, (char *)"portname", options.loopback_lcr))
                return(-1);
 
        /* goto end of chain again to set gsmflag and socket */
@@ -1054,6 +1052,42 @@ static int inter_ss5(struct interface *interface, char *filename, int line, char
        return(0);
 }
 #endif
+static int inter_remote(struct interface *interface, char *filename, int line, char *parameter, char *value)
+{
+       struct interface_port *ifport;
+       struct interface *searchif;
+
+       if (!value[0]) {
+               SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects application name as value.\n", filename, line, parameter);
+               return(-1);
+       }
+       searchif = interface_newlist;
+       while(searchif) {
+               ifport = searchif->ifport;
+               while(ifport) {
+                       if (ifport->remote && !strcmp(ifport->remote_app, value)) {
+                               SPRINT(interface_error, "Error in %s (line %d): port '%s' already uses remote application '%s'.\n", filename, line, ifport->portname, value);
+                               return(-1);
+                       }
+                       ifport = ifport->next;
+               }
+               searchif = searchif->next;
+       }
+
+       /* set portname */
+       if (inter_portname(interface, filename, line, (char *)"portname", options.loopback_lcr))
+               return(-1);
+
+       /* goto end of chain again to set application name */
+       ifport = interface->ifport;
+       while(ifport->next)
+               ifport = ifport->next;
+       ifport->remote = 1;
+       SCPY(ifport->remote_app, value);
+
+
+       return(0);
+}
 
 
 /*
@@ -1215,6 +1249,10 @@ struct interface_param interface_param[] = {
        " suppress - Suppress received tones, as they will be recognized."},
 #endif
 
+       {"remote", &inter_remote, "<application>",
+       "Sets up an interface that communicates with the remote application.\n"
+       "Use \"asterisk\" to use chan_lcr as remote application."},
+
        {NULL, NULL, NULL, NULL}
 };
 
index d1bea04..eea6915 100644 (file)
@@ -61,6 +61,8 @@ struct interface_port {
        char                    gsm_ms_service; /* see GSM_SERVICE_* */
 #endif
        unsigned int            ss5; /* set, if SS5 signalling enabled, also holds feature bits */
+       int                     remote; /* interface is a remote app interface */
+       char                    remote_app[32]; /* name of remote application */
        int                     channel_force; /* forces channel by protocol */
        int                     nodtmf; /* disables DTMF */
        struct select_channel   *out_channel; /* list of channels to select */
index 167bbce..c02de8e 100644 (file)
@@ -14,6 +14,7 @@
 //#define __u16 unsigned short
 //#define __u32 unsigned int
 
+extern unsigned int new_remote;
 
 /*
  * constructor for a new join 
@@ -27,6 +28,7 @@ JoinRemote::JoinRemote(unsigned int serial, char *remote_name, int remote_id) :
        SCPY(j_remote_name, remote_name);
        j_remote_id = remote_id;
        j_type = JOIN_TYPE_REMOTE;
+       j_remote_ref = new_remote++;
 
        j_epoint_id = serial; /* this is the endpoint, if created by epoint */
        if (j_epoint_id)
@@ -35,9 +37,8 @@ JoinRemote::JoinRemote(unsigned int serial, char *remote_name, int remote_id) :
        /* send new ref to remote socket */
        memset(&param, 0, sizeof(union parameter));
        if (serial)
-               param.direction = 1; /* new ref from lcr */
-       /* the j_serial is assigned by Join() parent. this is sent as new ref */
-       if (admin_message_from_join(j_remote_id, j_serial, MESSAGE_NEWREF, &param)<0)
+               param.newref.direction = 1; /* new ref from lcr */
+       if (admin_message_from_lcr(j_remote_id, j_remote_ref, MESSAGE_NEWREF, &param)<0)
                FATAL("No socket with remote application '%s' found, this shall not happen. because we already created one.\n", j_remote_name);
 }
 
@@ -56,7 +57,7 @@ void JoinRemote::message_epoint(unsigned int epoint_id, int message_type, union
                return;
        
        /* look for Remote's interface */
-       if (admin_message_from_join(j_remote_id, j_serial, message_type, param)<0) {
+       if (admin_message_from_lcr(j_remote_id, j_remote_ref, message_type, param)<0) {
                PERROR("No socket with remote application '%s' found, this shall not happen. Closing socket shall cause release of all joins.\n", j_remote_name);
                return;         
        }
@@ -100,25 +101,5 @@ void JoinRemote::message_remote(int message_type, union parameter *param)
        }
 }
 
-void message_bchannel_to_remote(unsigned int remote_id, unsigned int ref, int type, unsigned int handle, int tx_gain, int rx_gain, char *pipeline, unsigned char *crypt, int crypt_len, int crypt_type)
-{
-       union parameter param;
-
-       memset(&param, 0, sizeof(union parameter));
-       param.bchannel.type = type;
-       param.bchannel.handle = handle;
-       param.bchannel.tx_gain = tx_gain;
-       param.bchannel.rx_gain = rx_gain;
-       if (pipeline)
-               SCPY(param.bchannel.pipeline, pipeline);
-       if (crypt_len)
-               memcpy(param.bchannel.crypt, crypt, crypt_len);
-       param.bchannel.crypt_type = crypt_type;
-       if (admin_message_from_join(remote_id, ref, MESSAGE_BCHANNEL, &param)<0) {
-               PERROR("No socket with remote id %d found, this happens, if the socket is closed before all bchannels are imported.\n", remote_id);
-               return;         
-       }
-}
-
 
 
index 1582133..a933466 100644 (file)
@@ -17,10 +17,10 @@ class JoinRemote : public Join
        void message_epoint(unsigned int epoint_id, int message, union parameter *param);
        void message_remote(int message_type, union parameter *param);
 
+       unsigned int j_remote_ref;
        int j_remote_id;
        char j_remote_name[32];
        unsigned int j_epoint_id;
 }; 
 
 
-void message_bchannel_to_remote(unsigned int remote_id, unsigned int ref, int type, unsigned int handle, int tx_gain, int rx_gain, char *pipeline, unsigned char *crypt, int crypt_len, int crypt_type);
diff --git a/loop.c b/loop.c
new file mode 100644 (file)
index 0000000..cbd82e5
--- /dev/null
+++ b/loop.c
@@ -0,0 +1,153 @@
+/*****************************************************************************\
+**                                                                           **
+** LCR                                                                       **
+**                                                                           **
+**---------------------------------------------------------------------------**
+** Copyright: Andreas Eversberg                                              **
+**                                                                           **
+** loopback interface functions                                              **
+**                                                                           **
+\*****************************************************************************/ 
+
+#include "main.h"
+
+struct mISDNloop mISDNloop = { -1, 0 };
+
+void mISDNloop_close(void)
+{
+       if (mISDNloop.sock > -1)
+               close(mISDNloop.sock);
+       mISDNloop.sock = -1;
+}
+
+int mISDNloop_open()
+{
+       int ret;
+       int cnt;
+       unsigned long on = 1;
+       struct sockaddr_mISDN addr;
+       struct mISDN_devinfo devinfo;
+       int pri, bri;
+
+       /* already open */
+       if (mISDNloop.sock > -1)
+               return 0;
+
+       PDEBUG(DEBUG_PORT, "Open external interface of loopback.\n");
+
+       /* check port counts */
+       ret = ioctl(mISDNsocket, IMGETCOUNT, &cnt);
+       if (ret < 0) {
+               fprintf(stderr, "Cannot get number of mISDN devices. (ioctl IMGETCOUNT failed ret=%d)\n", ret);
+               return(ret);
+       }
+
+       if (cnt <= 0) {
+               PERROR_RUNTIME("Found no card. Please be sure to load card drivers.\n");
+               return -EIO;
+       }
+       mISDNloop.port = mISDN_getportbyname(mISDNsocket, cnt, options.loopback_ext);
+       if (mISDNloop.port < 0) {
+               PERROR_RUNTIME("Port name '%s' not found, did you load loopback interface?.\n", options.loopback_ext);
+               return mISDNloop.port;
+       }
+       /* get protocol */
+       bri = pri = 0;
+       devinfo.id = mISDNloop.port;
+       ret = ioctl(mISDNsocket, IMGETDEVINFO, &devinfo);
+       if (ret < 0) {
+               PERROR_RUNTIME("Cannot get device information for port %d. (ioctl IMGETDEVINFO failed ret=%d)\n", mISDNloop.port, ret);
+               return ret;
+       }
+       if (devinfo.Dprotocols & (1 << ISDN_P_TE_S0)) {
+               bri = 1;
+       }
+       if (devinfo.Dprotocols & (1 << ISDN_P_TE_E1)) {
+               pri = 1;
+       }
+       if (!bri && !pri) {
+               PERROR_RUNTIME("loop port %d does not support TE PRI or TE BRI.\n", mISDNloop.port);
+       }
+       /* open socket */
+       if ((mISDNloop.sock = socket(PF_ISDN, SOCK_DGRAM, (pri)?ISDN_P_TE_E1:ISDN_P_TE_S0)) < 0) {
+               PERROR_RUNTIME("loop port %d failed to open socket.\n", mISDNloop.port);
+               mISDNloop_close();
+               return mISDNloop.sock;
+       }
+       /* set nonblocking io */
+       if ((ret = ioctl(mISDNloop.sock, FIONBIO, &on)) < 0) {
+               PERROR_RUNTIME("loop port %d failed to set socket into nonblocking io.\n", mISDNloop.port);
+               mISDNloop_close();
+               return ret;
+       }
+       /* bind socket to dchannel */
+       memset(&addr, 0, sizeof(addr));
+       addr.family = AF_ISDN;
+       addr.dev = mISDNloop.port;
+       addr.channel = 0;
+       if ((ret = bind(mISDNloop.sock, (struct sockaddr *)&addr, sizeof(addr))) < 0) {
+               PERROR_RUNTIME("loop port %d failed to bind socket. (name = %s errno=%d)\n", mISDNloop.port, options.loopback_ext, errno);
+               mISDNloop_close();
+               return (ret);
+       }
+
+       return 0;
+}
+
+int loop_hunt_bchannel(class PmISDN *port, struct mISDNport *mISDNport)
+{
+       int channel;
+       int i;
+       char map[mISDNport->b_num];
+       struct interface *interface;
+       struct interface_port *ifport;
+
+       chan_trace_header(mISDNport, port, "CHANNEL SELECTION (setup)", DIRECTION_NONE);
+       add_trace("channel", "reserved", "%d", mISDNport->b_reserved);
+       if (mISDNport->b_reserved >= mISDNport->b_num) { // of out chan..
+               add_trace("conclusion", NULL, "all channels are reserved");
+               end_trace();
+               return(-34); // no channel
+       }
+
+       /* map all used ports of shared loopback interface */
+       memset(map, 0, sizeof(map));
+       interface = interface_first;
+       while(interface) {
+               ifport = interface->ifport;
+               while(ifport) {
+                       if (!strcmp(ifport->portname, options.loopback_lcr)) {
+                               i = 0;
+                               while(i < mISDNport->b_num) {
+                                       if (mISDNport->b_port[i])
+                                               map[i] = 1;
+                                       i++;
+                               }
+                       }
+                       ifport = ifport->next;
+               }
+               interface = interface->next;
+       }
+
+       /* find channel */
+       i = 0;
+       channel = 0;
+       while(i < mISDNport->b_num) {
+               if (!map[i]) {
+                       channel = i+1+(i>=15);
+                       break;
+               }
+               i++;
+       }
+       if (!channel) {
+               add_trace("conclusion", NULL, "no channel available");
+               end_trace();
+               return(-6); // channel unacceptable
+       }
+       add_trace("conclusion", NULL, "channel available");
+       add_trace("connect", "channel", "%d", channel);
+       end_trace();
+       return(channel);
+}
+
+
diff --git a/loop.h b/loop.h
new file mode 100644 (file)
index 0000000..cb2ad05
--- /dev/null
+++ b/loop.h
@@ -0,0 +1,12 @@
+
+struct mISDNloop {
+       int             sock;           /* loopback interface external side */
+       int             port;           /* port number for external side */
+};
+
+extern mISDNloop mISDNloop;
+
+void mISDNloop_close(void);
+int mISDNloop_open();
+int loop_hunt_bchannel(class PmISDN *port, struct mISDNport *mISDNport);
+
index ee50bf1..087963c 100644 (file)
--- a/mISDN.cpp
+++ b/mISDN.cpp
@@ -33,21 +33,6 @@ int __af_isdn = MISDN_AF_ISDN;
 #define B_TIMER_ACTIVATING 1 // seconds
 #define B_TIMER_DEACTIVATING 1 // seconds
 
-/* GSM condition */
-#if defined WITH_GSM_BS && defined WITH_GSM_MS
- #define MISDNPORT_GSM (mISDNport->gsm_bs || mISDNport->gsm_ms)
-#else
- #ifdef WITH_GSM_BS
-  #define MISDNPORT_GSM (mISDNport->gsm_bs)
- #endif
- #ifdef WITH_GSM_MS
-  #define MISDNPORT_GSM (mISDNport->gsm_ms)
- #endif
-#endif
-#ifndef MISDNPORT_GSM
- #define MISDNPORT_GSM (0)
-#endif
-
 /* list of mISDN ports */
 struct mISDNport *mISDNport_first;
 
@@ -671,7 +656,7 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
                        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);
+                               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, 0);
                                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);
@@ -719,7 +704,7 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
                        /* in case, the bchannel is exported right after seize_bchannel */
                        /* export bchannel */
                        /* p_m_remote_id is set, when this event happens. */
-                       message_bchannel_to_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);
+                       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, 0);
                        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);
@@ -774,7 +759,7 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
 
                        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);
+                       message_bchannel_to_remote(mISDNport->b_remote_id[i], 0, BCHANNEL_REMOVE, portid, 0,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);
@@ -825,7 +810,7 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
                                 * 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);
+                               message_bchannel_to_remote(mISDNport->b_remote_id[i], 0, BCHANNEL_REMOVE, portid, 0,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);
@@ -861,7 +846,7 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
 
                        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);
+                       message_bchannel_to_remote(mISDNport->b_remote_id[i], 0, BCHANNEL_REMOVE, portid, 0,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);
@@ -892,7 +877,7 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
                        if (b_port) {
                                /* bchannel is now deactivate, but is requied by Port class, so we reactivate / export */
                                if (p_m_remote_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);
+                                       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, 0);
                                        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);
@@ -924,7 +909,7 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
                        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);
+                                       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, 0);
                                        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);
@@ -1856,7 +1841,7 @@ static int mISDN_upqueue(struct lcr_fd *fd, unsigned int what, void *instance, i
        mISDNport = mISDNport_first;
        while(mISDNport) {
                /* handle queued up-messages (d-channel) */
-               if (!MISDNPORT_GSM) {
+               if (!mISDNport->isloopback) {
                        while ((mb = mdequeue(&mISDNport->upqueue))) {
                                l3m = &mb->l3;
                                switch(l3m->type) {
@@ -1932,7 +1917,7 @@ static int mISDN_upqueue(struct lcr_fd *fd, unsigned int what, void *instance, i
                                                if (!mISDNport->ntmode || mISDNport->ptp)
                                                        mISDNport->l2link = 0;
                                        }
-                                       if (!MISDNPORT_GSM && (!mISDNport->ntmode || mISDNport->ptp) && l3m->pid < 127) {
+                                       if (!mISDNport->isloopback && (!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);
@@ -1959,7 +1944,7 @@ static int l2establish_timeout(struct lcr_timer *timer, void *instance, int i)
 {
        struct mISDNport *mISDNport = (struct mISDNport *)instance;
 
-       if (!MISDNPORT_GSM && mISDNport->l2hold && (mISDNport->ptp || !mISDNport->ntmode)) {
+       if (!mISDNport->isloopback && 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 */
@@ -2119,7 +2104,7 @@ struct mISDNport *mISDNport_open(struct interface_port *ifport)
        int force_nt = ifport->nt;
        int l1hold = ifport->l1hold;
        int l2hold = ifport->l2hold;
-       int gsm = 0;
+       int loop = 0;
        int ss5 = ifport->ss5;
        int i, cnt;
        int pri, bri, pots;
@@ -2129,15 +2114,23 @@ struct mISDNport *mISDNport_open(struct interface_port *ifport)
        unsigned int protocol, prop;
 
 #if defined WITH_GSM_BS && defined WITH_GSM_MS
-       gsm = ifport->gsm_ms | ifport->gsm_bs;
+       loop = ifport->gsm_ms | ifport->gsm_bs;
 #else
 #ifdef WITH_GSM_BS
-       gsm = ifport->gsm_bs;
+       loop = ifport->gsm_bs;
 #endif
 #ifdef WITH_GSM_MS
-       gsm = ifport->gsm_ms;
+       loop = ifport->gsm_ms;
 #endif
 #endif
+//printf("%s == %s\n", ifport->portname, options.loopback_int);
+       if (!strcmp(ifport->portname, options.loopback_lcr))
+               loop = 1;
+
+       if (loop) {
+               if (mISDNloop_open())
+                       return NULL;
+       }
 
        /* check port counts */
        ret = ioctl(mISDNsocket, IMGETCOUNT, &cnt);
@@ -2153,8 +2146,8 @@ struct mISDNport *mISDNport_open(struct interface_port *ifport)
        if (port < 0) {
                port = mISDN_getportbyname(mISDNsocket, cnt, ifport->portname);
                if (port < 0) {
-                       if (gsm)
-                               PERROR_RUNTIME("Port name '%s' not found, did you load loopback interface for GSM?.\n", ifport->portname);
+                       if (loop)
+                               PERROR_RUNTIME("Port name '%s' not found, did you load loopback interface?.\n", ifport->portname);
                        else
                                PERROR_RUNTIME("Port name '%s' not found, use 'misdn_info' tool to list all existing ports.\n", ifport->portname);
                        return(NULL);
@@ -2270,8 +2263,8 @@ struct mISDNport *mISDNport_open(struct interface_port *ifport)
                mISDNportp = &((*mISDNportp)->next);
        mISDNport = (struct mISDNport *)MALLOC(sizeof(struct mISDNport));
        add_timer(&mISDNport->l2establish, l2establish_timeout, mISDNport, 0);
-       if (gsm | ss5) {
-               /* gsm/ss5 link is always active */
+       if (loop | ss5) {
+               /* loop/ss5 link is always active */
                mISDNport->l1link = 1;
                mISDNport->l2link = 1;
        } else {
@@ -2284,6 +2277,7 @@ struct mISDNport *mISDNport_open(struct interface_port *ifport)
 #ifdef WITH_GSM_MS
        mISDNport->gsm_ms = ifport->gsm_ms;
 #endif
+       mISDNport->isloopback = loop;
        pmemuse++;
        *mISDNportp = mISDNport;
 
@@ -2325,25 +2319,24 @@ struct mISDNport *mISDNport_open(struct interface_port *ifport)
        if (l2hold) // supports layer 2 hold
               prop |= (1 << MISDN_FLG_L2_HOLD);
        /* open layer 3 and init upqueue */
-       if (gsm) {
-#if defined WITH_GSM_BS || defined WITH_GSM_MS
+       if (loop) {
                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);
+                       printf("loop port %d has a low number of bchannels. (only %d) remember that all interfaces that requires a loopback could run out of channels\n", port, devinfo.nrbchan);
+//                     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);
+               if ((mISDNport->lcr_sock = socket(PF_ISDN, SOCK_DGRAM, (bri) ? ISDN_P_TE_S0 : ISDN_P_TE_E1)) < 0) {
+                       PERROR_RUNTIME("loop 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);
+                       PERROR_RUNTIME("loop port %d failed to set socket into nonblocking io.\n", port);
                        mISDNport_close(mISDNport);
                        return(NULL);
                }
@@ -2353,11 +2346,10 @@ struct mISDNport *mISDNport_open(struct interface_port *ifport)
                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);
+                       PERROR_RUNTIME("loop port %d failed to bind socket. (errno %d)\n", port, errno);
                        mISDNport_close(mISDNport);
                        return(NULL);
                }
-#endif
        } else {
                /* queue must be initializes, because l3-thread may send messages during open_layer3() */
                mqueue_init(&mISDNport->upqueue);
@@ -2398,7 +2390,7 @@ struct mISDNport *mISDNport_open(struct interface_port *ifport)
        }
 
        /* if ptp, pull up the link */
-       if (!MISDNPORT_GSM && mISDNport->l2hold && (mISDNport->ptp || !mISDNport->ntmode)) {
+       if (!mISDNport->isloopback && 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);
@@ -2511,19 +2503,17 @@ void mISDNport_close(struct mISDNport *mISDNport)
        del_timer(&mISDNport->l2establish);
 
        /* close layer 3, if open */
-       if (!MISDNPORT_GSM && mISDNport->ml3) {
+       if (!mISDNport->isloopback && mISDNport->ml3) {
                close_layer3(mISDNport->ml3);
        }
 
-#if defined WITH_GSM_BS || defined WITH_GSM_MS
        /* close gsm socket, if open */
-       if (MISDNPORT_GSM && mISDNport->lcr_sock > -1) {
+       if (mISDNport->isloopback && mISDNport->lcr_sock > -1) {
                close(mISDNport->lcr_sock);
        }
-#endif
 
        /* purge upqueue */
-       if (!MISDNPORT_GSM)
+       if (!mISDNport->isloopback)
                mqueue_purge(&mISDNport->upqueue);
 
        /* remove from list */
diff --git a/mISDN.h b/mISDN.h
index 644658b..de223c8 100644 (file)
--- a/mISDN.h
+++ b/mISDN.h
@@ -71,9 +71,8 @@ struct mISDNport {
 #ifdef WITH_GSM_MS
        int gsm_ms; /* this is the an GSM MS interface */
 #endif
-#if defined WITH_GSM_BS || defined WITH_GSM_MS
        int lcr_sock; /* socket of loopback on LCR side */
-#endif
+       int isloopback; /* will be set on open, in case it is a loopback if */
 
        /* ss5 */
        unsigned int ss5; /* set, if SS5 signalling enabled, also holds feature bits */
diff --git a/main.c b/main.c
index 98be1c0..0cc68a4 100644 (file)
--- a/main.c
+++ b/main.c
@@ -602,6 +602,10 @@ free:
 #endif
        }
 
+       /* close loopback, if used by GSM or remote */
+       if (mISDNloop.sock > -1)
+               mISDNloop_close();
+
        /* display memory leak */
 #define MEMCHECK(a, b) \
        if (b) { \
diff --git a/main.h b/main.h
index 8e45581..7aad3c2 100644 (file)
--- a/main.h
+++ b/main.h
@@ -148,6 +148,8 @@ extern "C" {
 #include "port.h"
 #include "mISDN.h"
 #include "dss1.h"
+#include "loop.h"
+#include "remote.h"
 #if defined WITH_GSM_BS || defined WITH_GSM_MS
 #include "gsm.h"
 #endif
index 471e2c8..c2076af 100644 (file)
--- a/message.h
+++ b/message.h
@@ -324,6 +324,7 @@ struct param_hello {
 struct param_bchannel {
        int type; /* BCHANNEL_* */
        unsigned int handle; /* bchannel stack/portid */
+       int isloopback; /* in this case the application behaves like an interface, dsp should not be used */
        int tx_gain, rx_gain;
        char pipeline[256];
        unsigned char crypt[128];
@@ -331,6 +332,11 @@ struct param_bchannel {
        int crypt_type; /* 1 = blowfish */
 };
 
+struct param_newref {
+        int direction; /* who requests a refe? */
+       int mode; /* 0 = direct-mode, 1 = PBX mode */
+};
+
 /* structure of message parameter */
 union parameter {
        struct param_tone tone; /* MESSAGE_TONE */
@@ -355,7 +361,7 @@ union parameter {
        struct param_crypt crypt; /* MESSAGE_CRYPT */
        struct param_hello hello; /* MESSAGE_HELLO */
        struct param_bchannel bchannel; /* MESSAGE_BCHANNEL */
-       int direction; /* MESSAGE_NEWREF */
+       struct param_newref newref; /* MESSAGE_NEWREF */
 };
 
 enum { /* message flow */
@@ -428,6 +434,7 @@ enum { /* messages between entities */
        "MESSAGE_RELEASE", \
        "MESSAGE_TIMEOUT", \
        "MESSAGE_NOTIFY", \
+       "MESSAGE_PROGRESS", \
        "MESSAGE_FACILITY", \
        "MESSAGE_SUSPEND", \
        "MESSAGE_RESUME", \
index 88f6424..7fb9bcb 100644 (file)
--- a/options.c
+++ b/options.c
@@ -36,7 +36,9 @@ struct options options = {
        -1,                             /* socket user (-1= no change) */
        -1,                             /* socket group (-1= no change) */
        0,                              /* enable gsm */
-       1                               /* use polling of main loop */
+       1,                              /* use polling of main loop */
+       "mISDN_l1loop.1",               /* GSM/Asterisk side */
+       "mISDN_l1loop.2",               /* LCR side */
 };
 
 char options_error[256];
@@ -239,6 +241,22 @@ int read_options(char *options_error)
                } else
                if (!strcmp(option,"polling")) {
                        options.polling = 1;
+               } else
+               if (!strcmp(option,"loopback-ext")) {
+                       if (param[0]==0) {
+                               UPRINT(options_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line, option);
+                               goto error;
+                       }
+                       SCPY(options.loopback_ext, param);
+
+               } else
+               if (!strcmp(option,"loopback-lcr")) {
+                       if (param[0]==0) {
+                               UPRINT(options_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line, option);
+                               goto error;
+                       }
+                       SCPY(options.loopback_lcr, param);
+
                } else {
                        UPRINT(options_error, "Error in %s (line %d): wrong option keyword %s.\n", filename,line,option);
                        goto error;
index c13ee2c..c7f9f8f 100644 (file)
--- a/options.h
+++ b/options.h
@@ -31,6 +31,8 @@ struct options {
        int     socketgroup;            /* socket chgrp to this group */
        int     gsm;                    /* enable gsm support */
        int     polling;
+       char loopback_ext[64];          /* loopback interface GSM side */
+       char loopback_lcr[64];          /* loopback interface LCR side */
 };     
 
 extern struct options options;
diff --git a/port.h b/port.h
index d7c0580..a4da7de 100644 (file)
--- a/port.h
+++ b/port.h
 #define PORT_CLASS_GSM_BS      0x1210
 #define PORT_CLASS_GSM_MS      0x1220
 #define PORT_CLASS_SS5         0x1300
+#define PORT_CLASS_REMOTE      0x1400
 #define PORT_CLASS_MASK                0xf000
 #define PORT_CLASS_mISDN_MASK  0xff00
 #define PORT_CLASS_DSS1_MASK   0xfff0
 #define PORT_CLASS_GSM_MASK    0xfff0
+#define PORT_CLASS_DIR_MASK    0x000f
+#define PORT_CLASS_DIR_IN      0x0001
+#define PORT_CLASS_DIR_OUT     0x0002
        /* nt-mode */
 #define        PORT_TYPE_DSS1_NT_IN    0x1111
 #define        PORT_TYPE_DSS1_NT_OUT   0x1112
@@ -41,6 +45,9 @@
 #define        PORT_TYPE_SS5_IN        0x1311
 #define        PORT_TYPE_SS5_OUT       0x1312
 #define        PORT_TYPE_SS5_IDLE      0x1313
+       /* remote */
+#define        PORT_TYPE_REMOTE_IN     0x1411
+#define        PORT_TYPE_REMOTE_OUT    0x1412
        /* answering machine */
 #define        PORT_TYPE_VBOX_OUT      0x3111
 
diff --git a/remote.cpp b/remote.cpp
new file mode 100644 (file)
index 0000000..e14c8e3
--- /dev/null
@@ -0,0 +1,221 @@
+/*****************************************************************************\
+**                                                                           **
+** LCR                                                                       **
+**                                                                           **
+**---------------------------------------------------------------------------**
+** Copyright: Andreas Eversberg                                              **
+**                                                                           **
+** mISDN remote                                                              **
+**                                                                           **
+\*****************************************************************************/ 
+
+#include "main.h"
+
+unsigned int new_remote = 0x00000001;
+
+/*
+ * constructor
+ */
+Premote::Premote(int type, struct mISDNport *mISDNport, char *portname, struct port_settings *settings, int channel, int exclusive, int mode, int remote_id) : PmISDN(type, mISDNport, portname, settings, channel, exclusive, mode)
+{
+       union parameter param;
+
+       p_callerinfo.itype = (mISDNport->ifport->interface->extension)?INFO_ITYPE_ISDN_EXTENSION:INFO_ITYPE_ISDN;
+       p_m_r_ref = new_remote++;
+       SCPY(p_m_r_remote_app, mISDNport->ifport->remote_app);
+       p_m_r_handle = 0;
+
+       /* send new ref to remote socket */
+       memset(&param, 0, sizeof(union parameter));
+       if (type == PORT_TYPE_REMOTE_OUT)
+               param.newref.direction = 1; /* new ref from lcr */
+       p_m_r_remote_id = remote_id;
+       if (admin_message_from_lcr(p_m_r_remote_id, p_m_r_ref, MESSAGE_NEWREF, &param) < 0)
+               FATAL("No socket with remote application '%s' found, this shall not happen. because we already created one.\n", mISDNport->ifport->remote_app);
+
+       PDEBUG(DEBUG_GSM, "Created new RemotePort(%s).\n", portname);
+
+}
+
+/*
+ * destructor
+ */
+Premote::~Premote()
+{
+       /* need to remote (import) external channel from remote application */
+       if (p_m_r_handle) {
+               message_bchannel_to_remote(p_m_r_remote_id, p_m_r_ref, BCHANNEL_REMOVE, p_m_r_handle, 0, 0, 0, 0, 0, 0, 1);
+               chan_trace_header(p_m_mISDNport, this, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
+               add_trace("type", NULL, "remove");
+               add_trace("channel", NULL, "%d.%d", p_m_r_handle>>8, p_m_r_handle&0xff);
+               end_trace();
+       }
+
+       PDEBUG(DEBUG_GSM, "Destroyed Remote process(%s).\n", p_name);
+
+}
+
+/*
+ * endpoint sends messages to the port
+ */
+int Premote::message_epoint(unsigned int epoint_id, int message_type, union parameter *param)
+{
+       struct lcr_msg *message;
+       int channel;
+       int ret;
+       struct epoint_list *epointlist;
+
+       if (PmISDN::message_epoint(epoint_id, message_type, param))
+               return 1;
+
+       if (message_type == MESSAGE_SETUP) {
+               ret = channel = hunt_bchannel();
+               if (ret < 0)
+                       goto no_channel;
+               /* open channel */
+               ret = seize_bchannel(channel, 1);
+               if (ret < 0) {
+                       no_channel:
+                       message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
+                       message->param.disconnectinfo.cause = 34;
+                       message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
+                       message_put(message);
+                       new_state(PORT_STATE_RELEASE);
+                       delete this;
+                       return 0;
+               }
+               bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE);
+
+               /* attach only if not already */
+               epointlist = p_epointlist;
+               while(epointlist) {
+                       if (epointlist->epoint_id == epoint_id)
+                               break;
+                       epointlist = epointlist->next;
+               }
+               if (!epointlist)
+                       epointlist_new(epoint_id);
+
+               /* set context to pbx */
+               SCPY(param->setup.context, "pbx");
+       }
+
+       /* look for Remote's interface */
+       if (admin_message_from_lcr(p_m_r_remote_id, p_m_r_ref, message_type, param)<0) {
+               PERROR("No socket with remote application '%s' found, this shall not happen. Closing socket shall cause release of all remote ports.\n", p_m_mISDNport->ifport->remote_app);
+               return 0;               
+       }
+
+       /* enable audio path */
+       if (message_type == MESSAGE_SETUP) {
+               union parameter newparam;
+               memset(&newparam, 0, sizeof(union parameter));
+               admin_message_from_lcr(p_m_r_remote_id, p_m_r_ref, MESSAGE_PATTERN, &newparam);
+               newparam.audiopath = 1;
+               admin_message_from_lcr(p_m_r_remote_id, p_m_r_ref, MESSAGE_AUDIOPATH, &newparam);
+       }
+
+       if (message_type == MESSAGE_RELEASE) {
+               new_state(PORT_STATE_RELEASE);
+               delete this;
+               return 0;
+       }
+
+       return 0;
+}
+
+void Premote::message_remote(int message_type, union parameter *param)
+{
+       class Endpoint *epoint;
+       struct lcr_msg *message;
+       int channel;
+       int ret;
+
+       if (message_type == MESSAGE_SETUP) {
+               /* enable audio path */
+               union parameter newparam;
+               memset(&newparam, 0, sizeof(union parameter));
+               admin_message_from_lcr(p_m_r_remote_id, p_m_r_ref, MESSAGE_PATTERN, &newparam);
+               newparam.audiopath = 1;
+               admin_message_from_lcr(p_m_r_remote_id, p_m_r_ref, MESSAGE_AUDIOPATH, &newparam);
+
+               /* set source interface */
+               param->setup.callerinfo.itype = p_callerinfo.itype;
+               param->setup.callerinfo.isdn_port = p_m_portnum;
+               SCPY(param->setup.callerinfo.interface, p_m_mISDNport->ifport->interface->name);
+               
+               ret = channel = hunt_bchannel();
+               if (ret < 0)
+                       goto no_channel;
+
+               /* open channel */
+               ret = seize_bchannel(channel, 1);
+               if (ret < 0) {
+                       no_channel:
+                       message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_RELEASE);
+                       message->param.disconnectinfo.cause = 34;
+                       message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
+                       message_put(message);
+                       new_state(PORT_STATE_RELEASE);
+                       delete this;
+                       return;
+               }
+               bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE);
+
+               /* create endpoint */
+               if (p_epointlist)
+                       FATAL("Incoming call but already got an endpoint.\n");
+               if (!(epoint = new Endpoint(p_serial, 0)))
+                       FATAL("No memory for Endpoint instance\n");
+               if (!(epoint->ep_app = new DEFAULT_ENDPOINT_APP(epoint, 0))) //incoming
+                       FATAL("No memory for Endpoint Application instance\n");
+
+               epointlist_new(epoint->ep_serial);
+       }
+
+       /* set serial on bchannel message
+        * also ref is given, so we send message with ref */
+       if (message_type == MESSAGE_BCHANNEL) {
+               int i = p_m_b_index;
+               unsigned int portid = (mISDNloop.port<<8) + i+1+(i>=15);
+               switch (param->bchannel.type) {
+               case BCHANNEL_REQUEST:
+                       p_m_r_handle = portid;
+                       message_bchannel_to_remote(p_m_r_remote_id, p_m_r_ref, BCHANNEL_ASSIGN, portid, 0, 0, 0, 0, 0, 0, 1);
+                       chan_trace_header(p_m_mISDNport, this, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
+                       add_trace("type", NULL, "assign");
+                       add_trace("channel", NULL, "%d.%d", portid>>8, portid&0xff);
+                       end_trace();
+                       break;
+               case BCHANNEL_RELEASE:
+                       p_m_r_handle = 0;
+                       message_bchannel_to_remote(p_m_r_remote_id, p_m_r_ref, BCHANNEL_REMOVE, portid, 0, 0, 0, 0, 0, 0, 1);
+                       chan_trace_header(p_m_mISDNport, this, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
+                       add_trace("type", NULL, "remove");
+                       add_trace("channel", NULL, "%d.%d", portid>>8, portid&0xff);
+                       end_trace();
+                       break;
+               }
+               return;
+       }
+       
+       /* cannot just forward, because param is not of container "struct lcr_msg" */
+       message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, message_type);
+       memcpy(&message->param, param, sizeof(message->param));
+       message_put(message);
+
+       if (message_type == MESSAGE_RELEASE) {
+               new_state(PORT_STATE_RELEASE);
+               delete this;
+               return;
+       }
+}
+
+/* select free bchannel from loopback interface */
+int Premote::hunt_bchannel(void)
+{
+       return loop_hunt_bchannel(this, p_m_mISDNport);
+}
+
+
+
diff --git a/remote.h b/remote.h
new file mode 100644 (file)
index 0000000..f39245b
--- /dev/null
+++ b/remote.h
@@ -0,0 +1,20 @@
+
+/* GSM port class */
+class Premote : public PmISDN
+{
+       public:
+       Premote(int type, struct mISDNport *mISDNport, char *portname, struct port_settings *settings, int channel, int exclusive, int mode, int remote_id);
+       ~Premote();
+
+       unsigned int p_m_r_ref;
+       int p_m_r_remote_id; /* remote instance (socket) */
+       char p_m_r_remote_app[32];
+       unsigned int p_m_r_handle; /* 0, if no bchannel is exported */
+
+       int message_epoint(unsigned int epoint_id, int message_id, union parameter *param);
+       void message_remote(int message_type, union parameter *param);
+
+       int hunt_bchannel(void);
+};
+
+
index e84fa5e..9922dc6 100644 (file)
@@ -19,6 +19,7 @@
 char socket_name[128];
 int sock = -1;
 struct sockaddr_un sock_address;
+extern unsigned int new_remote;
 
 struct admin_list *admin_first = NULL;
 static struct lcr_fd admin_fd;
@@ -84,6 +85,8 @@ void free_connection(struct admin_list *admin)
        struct mISDNport *mISDNport;
        int i, ii;
        struct admin_list **adminp;
+       class Port *port, *portnext;
+       class Premote *remote;
 
        /* free remote joins */
        if (admin->remote_name[0]) {
@@ -126,6 +129,22 @@ void free_connection(struct admin_list *admin)
                        }
                        join = joinnext;
                }
+               /* release remote port */
+               port = port_first;
+               while(port) {
+                       portnext = port->next;
+                       if ((port->p_type & PORT_CLASS_MASK) == PORT_CLASS_REMOTE) {
+                               remote = (class Premote *) port;
+                               if (remote->p_m_r_remote_id == admin->sock) {
+                                       memset(&param, 0, sizeof(param));
+                                       param.disconnectinfo.cause = CAUSE_OUTOFORDER;
+                                       param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
+                                       remote->message_remote(MESSAGE_RELEASE, &param);
+                                       /* port is now destroyed, so we go to next join */
+                               }
+                       }
+                       port = portnext;
+               }
        }
 
        if (admin->sock >= 0) {
@@ -586,9 +605,13 @@ void admin_call_response(int adminid, int message, const char *connected, int ca
 /*
  * send data to the remote socket join instance
  */
-int admin_message_to_join(struct admin_msg *msg, struct admin_list *admin)
+int admin_message_to_lcr(struct admin_msg *msg, struct admin_list *admin)
 {
+       struct mISDNport                *mISDNport;
        class Join                      *join;
+       class JoinRemote                *joinremote = NULL; /* make GCC happy */
+       class Port                      *port;
+       class Premote                   *remote = NULL; /* make GCC happy */
        struct admin_list               *temp;
 
        /* hello message */
@@ -629,13 +652,41 @@ int admin_message_to_join(struct admin_msg *msg, struct admin_list *admin)
                return(-1);
        }
 
-       /* new join */
+       /* new join. the reply (NEWREF assignment) is sent from constructor */
        if (msg->type == MESSAGE_NEWREF) {
-               /* create new join instance */
-               join = new JoinRemote(0, admin->remote_name, admin->sock); // must have no serial, because no endpoint is connected
-               if (!join) {
-                       FATAL("No memory for remote join instance\n");
-                       return(-1);
+               if (msg->param.newref.mode) {
+                       char name[32];
+                       /* find remote port */
+                       mISDNport = mISDNport_first;
+                       while(mISDNport) {
+                               if (mISDNport->ifport->remote && !strcmp(mISDNport->ifport->remote_app, admin->remote_name))
+                                       break;
+                               mISDNport = mISDNport->next;
+                       }
+                       if (!mISDNport) {
+                               unsigned int remote_ref = new_remote++;
+                               union parameter param;
+
+                               memset(&param, 0, sizeof(union parameter));
+                               admin_message_from_lcr(mISDNport->ifport->remote, remote_ref, MESSAGE_NEWREF, &param);
+                               memset(&param, 0, sizeof(union parameter));
+                               param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
+                               param.disconnectinfo.cause = CAUSE_RESSOURCEUNAVAIL;
+                               admin_message_from_lcr(mISDNport->ifport->remote, remote_ref, MESSAGE_RELEASE, &param);
+                               return 0;
+                       }
+                       /* creating port object, transparent until setup with hdlc */
+                       SPRINT(name, "%s-%s-in", mISDNport->ifport->interface->name, mISDNport->ifport->remote_app);
+                       if (!(remote = new Premote(PORT_TYPE_REMOTE_IN, mISDNport, name, NULL, 0, 0, B_MODE_TRANSPARENT, admin->sock)))
+
+                               FATAL("Cannot create Port instance.\n");
+               } else {
+                       /* create new join instance */
+                       join = new JoinRemote(0, admin->remote_name, admin->sock); // must have no serial, because no endpoint is connected
+                       if (!join) {
+                               FATAL("No memory for remote join instance\n");
+                               return(-1);
+                       }
                }
                return(0);
        }
@@ -646,6 +697,7 @@ int admin_message_to_join(struct admin_msg *msg, struct admin_list *admin)
        if (msg->param.bchannel.type == BCHANNEL_ASSIGN_ACK
         || msg->param.bchannel.type == BCHANNEL_REMOVE_ACK
         || msg->param.bchannel.type == BCHANNEL_RELEASE) {
+#warning TODO: depending on the mode (join / remoteport) forward message
                /* no ref, but address */
                message_bchannel_from_remote(NULL, msg->param.bchannel.type, msg->param.bchannel.handle);
                return(0);
@@ -660,36 +712,56 @@ int admin_message_to_join(struct admin_msg *msg, struct admin_list *admin)
        /* find join instance */
        join = join_first;
        while(join) {
-               if (join->j_serial == msg->ref)
-                       break;
+               if (join->j_type != JOIN_TYPE_REMOTE) {
+                       joinremote = (class JoinRemote *)join;
+                       if (joinremote->j_remote_ref == msg->ref)
+                               break;
+               }
                join = join->next;
        }
-       if (!join) {
-               PDEBUG(DEBUG_LOG, "No join found with serial %d. (May have been already released.)\n", msg->ref);
+       if (join) {
+               if (admin->sock != joinremote->j_remote_id) {
+                       PERROR("Ref %d belongs to remote application %s, but not to sending application %s.\n", msg->ref, joinremote->j_remote_name, admin->remote_name);
+                       return(-1);
+               }
+               /* send message */
+               joinremote->message_remote(msg->type, &msg->param);
+
                return(0);
        }
 
-       /* check application */
-       if (join->j_type != JOIN_TYPE_REMOTE) {
-               PERROR("Ref %d does not belong to a remote join instance.\n", msg->ref);
-               return(-1);
-       }
-       if (admin->sock != ((class JoinRemote *)join)->j_remote_id) {
-               PERROR("Ref %d belongs to remote application %s, but not to sending application %s.\n", msg->ref, ((class JoinRemote *)join)->j_remote_name, admin->remote_name);
-               return(-1);
+       /* find port instance */
+       port = port_first;
+       while(port) {
+               if ((port->p_type & PORT_CLASS_mISDN_MASK) == PORT_CLASS_REMOTE) {
+                       remote = (class Premote *) port;
+                       if (remote->p_m_r_ref == msg->ref)
+                               break;
+               }
+               port = port->next;
        }
+       if (port) {
+               if (admin->sock != remote->p_m_r_remote_id) {
+                       PERROR("Ref %d belongs to remote application %s, but not to sending application %s.\n", msg->ref, remote->p_m_r_remote_app, admin->remote_name);
+                       return(-1);
+               }
+
+               /* send message */
+               remote->message_remote(msg->type, &msg->param);
 
-       /* send message */
-       ((class JoinRemote *)join)->message_remote(msg->type, &msg->param);
+               return(0);
+       }
 
+       PDEBUG(DEBUG_LOG, "No remote instance found with ref %d. (May have been already released.)\n", msg->ref);
        return(0);
+
 }
 
 
 /*
  * this function is called for every message to remote socket
  */
-int admin_message_from_join(int remote_id, unsigned int ref, int message_type, union parameter *param)
+int admin_message_from_lcr(int remote_id, unsigned int ref, int message_type, union parameter *param)
 {
        struct admin_list       *admin;
        struct admin_queue      **responsep;    /* response pointer */
@@ -1234,7 +1306,7 @@ int admin_handle_con(struct lcr_fd *fd, unsigned int what, void *instance, int i
                        break;
 
                        case ADMIN_MESSAGE:
-                       if (admin_message_to_join(&msg.u.msg, admin) < 0) {
+                       if (admin_message_to_lcr(&msg.u.msg, admin) < 0) {
                                PERROR("Failed to deliver message for socket %d.\n", admin->sock);
                                goto response_error;
                        }
@@ -1281,3 +1353,24 @@ int admin_handle_con(struct lcr_fd *fd, unsigned int what, void *instance, int i
        return 0;
 }
 
+void message_bchannel_to_remote(unsigned int remote_id, unsigned int ref, int type, unsigned int handle, int tx_gain, int rx_gain, char *pipeline, unsigned char *crypt, int crypt_len, int crypt_type, int isloopback)
+{
+       union parameter param;
+
+       memset(&param, 0, sizeof(union parameter));
+       param.bchannel.isloopback = isloopback;
+       param.bchannel.type = type;
+       param.bchannel.handle = handle;
+       param.bchannel.tx_gain = tx_gain;
+       param.bchannel.rx_gain = rx_gain;
+       if (pipeline)
+               SCPY(param.bchannel.pipeline, pipeline);
+       if (crypt_len)
+               memcpy(param.bchannel.crypt, crypt, crypt_len);
+       param.bchannel.crypt_type = crypt_type;
+       if (admin_message_from_lcr(remote_id, ref, MESSAGE_BCHANNEL, &param)<0) {
+               PERROR("No socket with remote id %d found, this happens, if the socket is closed before all bchannels are imported.\n", remote_id);
+               return;         
+       }
+}
+
index b3ea89a..9a31b10 100644 (file)
@@ -33,8 +33,9 @@ extern struct admin_list *admin_first;
 int admin_init(void);
 void admin_cleanup(void);
 void admin_call_response(int adminid, int message, const char *connected, int cause, int location, int notify);
-int admin_message_to_join(struct admin_message *msg, int remote_id);
-int admin_message_from_join(int remote_id, unsigned int ref, int message_type, union parameter *param);
+int admin_message_to_lcr(struct admin_message *msg, int remote_id);
+int admin_message_from_lcr(int remote_id, unsigned int ref, int message_type, union parameter *param);
+void message_bchannel_to_remote(unsigned int remote_id, unsigned int ref, int type, unsigned int handle, int tx_gain, int rx_gain, char *pipeline, unsigned char *crypt, int crypt_len, int crypt_type, int isloopback);