From 155d3b5a1d18ea9563226b833b5099a2f4f153e0 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sun, 4 Jun 2017 11:22:51 +0200 Subject: [PATCH] GSM: Fixes to GSM interface (multiple networks) * Multiple network instances are now possible to attach multiple networks * Early audio handling fixed * Number type can be given from base station (setup / setup confirm) * Equal callref for different GSM-MS instances are handled correctly --- default/interface.conf | 1 + gsm.cpp | 38 ++++++++++++-- gsm.h | 4 +- gsm_bs.cpp | 134 +++++++++++++++++++++++++++++++++++-------------- gsm_bs.h | 7 ++- gsm_ms.cpp | 66 ++++-------------------- gsm_ms.h | 2 +- interface.c | 33 ++++++------ interface.h | 1 + main.c | 6 --- 10 files changed, 170 insertions(+), 122 deletions(-) diff --git a/default/interface.conf b/default/interface.conf index 19c7a34..1450ae3 100644 --- a/default/interface.conf +++ b/default/interface.conf @@ -157,6 +157,7 @@ # A special case for GSM Network interface. +# optionally give "gsm-bs ". # You may add 'extension' and 'msn' keywords to turn all your subscribers # in you GSM network to internal 'extensions'. # The MSN numbers will equal the subscriber number. diff --git a/gsm.cpp b/gsm.cpp index b9b88ee..8f9005b 100644 --- a/gsm.cpp +++ b/gsm.cpp @@ -667,7 +667,20 @@ void Pgsm::setup_cnf(unsigned int msg_type, unsigned int callref, struct gsm_mnc SCPY(p_connectinfo.imsi, mncc->imsi); p_connectinfo.present = INFO_PRESENT_ALLOWED; p_connectinfo.screen = INFO_SCREEN_NETWORK; - p_connectinfo.ntype = INFO_NTYPE_UNKNOWN; + switch (mncc->connected.type) { + case 0x1: + p_connectinfo.ntype = INFO_NTYPE_INTERNATIONAL; + break; + case 0x2: + p_connectinfo.ntype = INFO_NTYPE_NATIONAL; + break; + case 0x4: + p_connectinfo.ntype = INFO_NTYPE_SUBSCRIBER; + break; + default: + p_connectinfo.ntype = INFO_NTYPE_UNKNOWN; + break; + } SCPY(p_connectinfo.interface, p_interface_name); gsm_trace_header(p_interface_name, this, msg_type, DIRECTION_IN); @@ -1355,6 +1368,9 @@ static int mncc_fd_read(struct lcr_fd *lfd, void *inst, int idx) static char buf[sizeof(struct gsm_mncc)+1024]; struct gsm_mncc *mncc_prim = (struct gsm_mncc *) buf; struct gsm_mncc_hello *hello = (struct gsm_mncc_hello *) buf; + class Port *port; + class Pgsm *pgsm = NULL; + unsigned int callref; memset(buf, 0, sizeof(buf)); rc = recv(lfd->fd, buf, sizeof(buf), 0); @@ -1402,15 +1418,31 @@ static int mncc_fd_read(struct lcr_fd *lfd, void *inst, int idx) break; } + /* Find port object */ + callref = mncc_prim->callref; + port = port_first; + while(port) { + if ((port->p_type & PORT_CLASS_MASK) == PORT_CLASS_GSM) { + pgsm = (class Pgsm *)port; + if (pgsm->p_g_lcr_gsm == lcr_gsm && pgsm->p_g_callref == callref) + break; + } + port = port->next; + } + /* Hand the MNCC message into LCR */ switch (lcr_gsm->type) { #ifdef WITH_GSM_BS case LCR_GSM_TYPE_NETWORK: - return message_bsc(lcr_gsm, mncc_prim->msg_type, mncc_prim); + if (port && (port->p_type & PORT_CLASS_GSM_MASK) != PORT_CLASS_GSM_BS) + FATAL("Port is set and bound to network socket, but is not of network type, please fix"); + return message_bsc((class Pgsm_bs *)port, lcr_gsm, mncc_prim->msg_type, mncc_prim); #endif #ifdef WITH_GSM_MS case LCR_GSM_TYPE_MS: - return message_ms(lcr_gsm, mncc_prim->msg_type, mncc_prim); + if (port && (port->p_type & PORT_CLASS_GSM_MASK) != PORT_CLASS_GSM_MS) + FATAL("Port is set and bound to mobile socket, but is not of mobile type, please fix"); + return message_ms((class Pgsm_ms *)port, lcr_gsm, mncc_prim->msg_type, mncc_prim); #endif default: return 0; diff --git a/gsm.h b/gsm.h index b0b9b89..f14794f 100644 --- a/gsm.h +++ b/gsm.h @@ -16,8 +16,8 @@ enum { struct lcr_gsm { char interface_name[64]; /* name of interface this instance is associated to */ - struct lcr_gsm *gsm_ms_next; /* list of MS instances, in case of MS */ - char name[16]; /* name of MS instance, in case of MS */ + struct lcr_gsm *gsm_next; /* list of MS/BS instances */ + char name[16]; /* name of MS/BS instance */ int type; /* LCR_GSM_TYPE_*/ struct lcr_fd mncc_lfd; /* Unix domain socket to OpenBSC MNCC */ diff --git a/gsm_bs.cpp b/gsm_bs.cpp index 6d1a122..81a0672 100644 --- a/gsm_bs.cpp +++ b/gsm_bs.cpp @@ -12,7 +12,7 @@ #include "main.h" #include "mncc.h" -struct lcr_gsm *gsm_bs = NULL; +struct lcr_gsm *gsm_bs_first = NULL; #define PAYLOAD_TYPE_GSM 3 @@ -49,11 +49,23 @@ void generate_dtmf(void) */ Pgsm_bs::Pgsm_bs(int type, char *portname, struct port_settings *settings, struct interface *interface) : Pgsm(type, portname, settings, interface) { - p_g_lcr_gsm = gsm_bs; + struct lcr_gsm *gsm_bs = gsm_bs_first; + + p_g_lcr_gsm = NULL; + SCPY(p_g_bs_name, interface->gsm_bs_name); + + while (gsm_bs) { + if (gsm_bs->type == LCR_GSM_TYPE_NETWORK && !strcmp(gsm_bs->name, p_g_bs_name)) { + p_g_lcr_gsm = gsm_bs; + break; + } + gsm_bs = gsm_bs->gsm_next; + } + p_g_dtmf = NULL; p_g_dtmf_index = 0; - PDEBUG(DEBUG_GSM, "Created new GSMBSPort(%s).\n", portname); + PDEBUG(DEBUG_GSM, "Created new GSMBSPort(%s %s).\n", portname, p_g_bs_name); } /* @@ -181,6 +193,15 @@ void Pgsm_bs::call_conf_ind(unsigned int msg_type, unsigned int callref, struct modify_lchan(media_types[0]); p_g_payload_type = payload_types[0]; } + + if (p_g_earlyb && !p_g_tch_connected) { /* only if ... */ + struct gsm_mncc *frame; + gsm_trace_header(p_interface_name, this, MNCC_FRAME_RECV, DIRECTION_OUT); + end_trace(); + frame = create_mncc(MNCC_FRAME_RECV, p_g_callref); + send_and_free_mncc(p_g_lcr_gsm, frame->msg_type, frame); + p_g_tch_connected = 1; + } } /* DTMF INDICATION */ @@ -507,7 +528,20 @@ reject: p_callerinfo.present = INFO_PRESENT_NOTAVAIL; SCPY(p_callerinfo.imsi, mncc->imsi); p_callerinfo.screen = INFO_SCREEN_NETWORK; - p_callerinfo.ntype = INFO_NTYPE_UNKNOWN; + switch (mncc->calling.type) { + case 0x1: + p_callerinfo.ntype = INFO_NTYPE_INTERNATIONAL; + break; + case 0x2: + p_callerinfo.ntype = INFO_NTYPE_NATIONAL; + break; + case 0x4: + p_callerinfo.ntype = INFO_NTYPE_SUBSCRIBER; + break; + default: + p_callerinfo.ntype = INFO_NTYPE_UNKNOWN; + break; + } SCPY(p_callerinfo.interface, p_interface_name); /* dialing information */ @@ -660,39 +694,23 @@ reject: /* * BSC sends message to port */ -int message_bsc(struct lcr_gsm *lcr_gsm, int msg_type, void *arg) +int message_bsc(class Pgsm_bs *pgsm_bs, struct lcr_gsm *lcr_gsm, int msg_type, void *arg) { struct gsm_mncc *mncc = (struct gsm_mncc *)arg; unsigned int callref = mncc->callref; - class Port *port; - class Pgsm_bs *pgsm_bs = NULL; char name[64]; -// struct mISDNport *mISDNport; /* Special messages */ switch(msg_type) { } - /* find callref */ - callref = mncc->callref; - port = port_first; - while(port) { - if ((port->p_type & PORT_CLASS_GSM_MASK) == PORT_CLASS_GSM_BS) { - pgsm_bs = (class Pgsm_bs *)port; - if (pgsm_bs->p_g_callref == callref) { - break; - } - } - port = port->next; - } - if (msg_type == GSM_TCHF_FRAME || msg_type == GSM_TCHF_FRAME_EFR || msg_type == GSM_TCHH_FRAME || msg_type == GSM_TCH_FRAME_AMR || msg_type == ANALOG_8000HZ || msg_type == GSM_BAD_FRAME) { - if (port) { + if (pgsm_bs) { /* inject DTMF, if enabled */ if (pgsm_bs->p_g_dtmf) { unsigned char data[160]; @@ -720,7 +738,7 @@ int message_bsc(struct lcr_gsm *lcr_gsm, int msg_type, void *arg) return 0; } - if (!port) { + if (!pgsm_bs) { struct interface *interface; if (msg_type != MNCC_SETUP_IND) @@ -1080,31 +1098,41 @@ int Pgsm_bs::message_epoint(unsigned int epoint_id, int message_id, union parame int gsm_bs_exit(int rc) { - /* free gsm instance */ - if (gsm_bs) { - if (gsm_bs->mncc_lfd.fd > -1) { - close(gsm_bs->mncc_lfd.fd); - unregister_fd(&gsm_bs->mncc_lfd); - } - - del_timer(&gsm_bs->socket_retry); - free(gsm_bs); - gsm_bs = NULL; - } + /* destroy all instances */ + while (gsm_bs_first) + gsm_bs_delete(gsm_bs_first->name); + return rc; +} - return(rc); +int gsm_bs_init(void) +{ + return 0; } -int gsm_bs_init(struct interface *interface) +/* add a new GSM base station instance */ +int gsm_bs_new(struct interface *interface) { + struct lcr_gsm *gsm_bs = gsm_bs_first, **gsm_bs_p = &gsm_bs_first; + + while (gsm_bs) { + gsm_bs_p = &gsm_bs->gsm_next; + gsm_bs = gsm_bs->gsm_next; + } + + PDEBUG(DEBUG_GSM, "GSM: interface for BS '%s' is created\n", interface->gsm_bs_name); + /* create gsm instance */ gsm_bs = (struct lcr_gsm *)MALLOC(sizeof(struct lcr_gsm)); SCPY(gsm_bs->interface_name, interface->name); gsm_bs->type = LCR_GSM_TYPE_NETWORK; + SCPY(gsm_bs->name, interface->gsm_bs_name); gsm_bs->sun.sun_family = AF_UNIX; - SCPY(gsm_bs->sun.sun_path, "/tmp/bsc_mncc"); + if (gsm_bs->name[0]) + SPRINT(gsm_bs->sun.sun_path, "/tmp/bsc_mncc_%s", gsm_bs->name); + else + SCPY(gsm_bs->sun.sun_path, "/tmp/bsc_mncc"); memset(&gsm_bs->socket_retry, 0, sizeof(gsm_bs->socket_retry)); add_timer(&gsm_bs->socket_retry, mncc_socket_retry_cb, gsm_bs, 0); @@ -1114,5 +1142,37 @@ int gsm_bs_init(struct interface *interface) generate_dtmf(); + *gsm_bs_p = gsm_bs; + return 0; } + +int gsm_bs_delete(const char *name) +{ + struct lcr_gsm *gsm_bs = gsm_bs_first, **gsm_bs_p = &gsm_bs_first; + + PDEBUG(DEBUG_GSM, "GSM: interface for BS '%s' is deleted\n", name); + + while (gsm_bs) { + if (gsm_bs->type == LCR_GSM_TYPE_NETWORK && !strcmp(gsm_bs->name, name)) + break; + gsm_bs_p = &gsm_bs->gsm_next; + gsm_bs = gsm_bs->gsm_next; + } + + if (!gsm_bs) + return 0; + + if (gsm_bs->mncc_lfd.fd > -1) { + close(gsm_bs->mncc_lfd.fd); + unregister_fd(&gsm_bs->mncc_lfd); + } + del_timer(&gsm_bs->socket_retry); + + /* remove instance from list */ + *gsm_bs_p = gsm_bs->gsm_next; + FREE(gsm_bs, sizeof(struct lcr_gsm)); + + return 0; +} + diff --git a/gsm_bs.h b/gsm_bs.h index 5575daa..afb0415 100644 --- a/gsm_bs.h +++ b/gsm_bs.h @@ -6,6 +6,7 @@ class Pgsm_bs : public Pgsm Pgsm_bs(int type, char *portname, struct port_settings *settings, struct interface *interface); ~Pgsm_bs(); + char p_g_bs_name[32]; unsigned char *p_g_dtmf; /* DTMF tone generation (MS only) */ int p_g_dtmf_index; /* DTMF tone generation index */ @@ -22,6 +23,8 @@ class Pgsm_bs : public Pgsm int gsm_bs_conf(struct gsm_conf *gsm_conf, char *conf_error); int gsm_bs_exit(int rc); -int gsm_bs_init(struct interface *interface); +int gsm_bs_init(void); +int gsm_bs_new(struct interface *interface); +int gsm_bs_delete(const char *name); -int message_bsc(struct lcr_gsm *lcr_gsm, int msg_type, void *arg); +int message_bsc(class Pgsm_bs *pgsm_bs, struct lcr_gsm *lcr_gsm, int msg_type, void *arg); diff --git a/gsm_ms.cpp b/gsm_ms.cpp index 6ef0a82..4d42ee7 100644 --- a/gsm_ms.cpp +++ b/gsm_ms.cpp @@ -40,7 +40,7 @@ Pgsm_ms::Pgsm_ms(int type, char *portname, struct port_settings *settings, struc p_g_lcr_gsm = gsm_ms; break; } - gsm_ms = gsm_ms->gsm_ms_next; + gsm_ms = gsm_ms->gsm_next; } p_g_dtmf_state = DTMF_ST_IDLE; @@ -332,40 +332,24 @@ reject: /* * MS sends message to port */ -int message_ms(struct lcr_gsm *gsm_ms, int msg_type, void *arg) +int message_ms(class Pgsm_ms *pgsm_ms, struct lcr_gsm *gsm_ms, int msg_type, void *arg) { struct gsm_mncc *mncc = (struct gsm_mncc *)arg; unsigned int callref = mncc->callref; - class Port *port; - class Pgsm_ms *pgsm_ms = NULL; char name[64]; -// struct mISDNport *mISDNport; /* Special messages */ switch (msg_type) { } - /* find callref */ - callref = mncc->callref; - port = port_first; - while(port) { - if ((port->p_type & PORT_CLASS_GSM_MASK) == PORT_CLASS_GSM_MS) { - pgsm_ms = (class Pgsm_ms *)port; - if (pgsm_ms->p_g_callref == callref) { - break; - } - } - port = port->next; - } - if (msg_type == GSM_TCHF_FRAME || msg_type == GSM_BAD_FRAME) { - if (port) + if (pgsm_ms) pgsm_ms->frame_receive(arg); return 0; } - if (!port) { + if (!pgsm_ms) { struct interface *interface; if (msg_type != MNCC_SETUP_IND) @@ -726,8 +710,8 @@ int gsm_ms_new(struct interface *interface) struct lcr_gsm *gsm_ms = gsm_ms_first, **gsm_ms_p = &gsm_ms_first; while (gsm_ms) { - gsm_ms_p = &gsm_ms->gsm_ms_next; - gsm_ms = gsm_ms->gsm_ms_next; + gsm_ms_p = &gsm_ms->gsm_next; + gsm_ms = gsm_ms->gsm_next; } PDEBUG(DEBUG_GSM, "GSM: interface for MS '%s' is created\n", interface->gsm_ms_name); @@ -755,51 +739,19 @@ int gsm_ms_new(struct interface *interface) int gsm_ms_delete(const char *name) { struct lcr_gsm *gsm_ms = gsm_ms_first, **gsm_ms_p = &gsm_ms_first; -// class Port *port; -// class Pgsm_ms *pgsm_ms = NULL; PDEBUG(DEBUG_GSM, "GSM: interface for MS '%s' is deleted\n", name); while (gsm_ms) { if (gsm_ms->type == LCR_GSM_TYPE_MS && !strcmp(gsm_ms->name, name)) break; - gsm_ms_p = &gsm_ms->gsm_ms_next; - gsm_ms = gsm_ms->gsm_ms_next; + gsm_ms_p = &gsm_ms->gsm_next; + gsm_ms = gsm_ms->gsm_next; } if (!gsm_ms) return 0; -/* not needed, because: - * - shutdown of interface will destry port instances locally - * - closing of socket will make remote socket destroy calls locally - */ -#if 0 - port = port_first; - while(port) { - if ((port->p_type & PORT_CLASS_GSM_MASK) == PORT_CLASS_GSM_MS) { - pgsm_ms = (class Pgsm_ms *)port; - if (pgsm_ms->p_g_lcr_gsm == gsm_ms && pgsm_ms->p_g_callref) { - struct gsm_mncc *rej; - - rej = create_mncc(MNCC_REL_REQ, pgsm_ms->p_g_callref); - rej->fields |= MNCC_F_CAUSE; - rej->cause.coding = 3; - rej->cause.location = 1; - rej->cause.value = 27; - gsm_trace_header(NULL, NULL, MNCC_REJ_REQ, DIRECTION_OUT); - add_trace("cause", "coding", "%d", rej->cause.coding); - add_trace("cause", "location", "%d", rej->cause.location); - add_trace("cause", "value", "%d", rej->cause.value); - end_trace(); - send_and_free_mncc(gsm_ms, rej->msg_type, rej); - pgsm_ms->new_state(PORT_STATE_RELEASE); - trigger_work(&pgsm_ms->p_g_delete); - } - } - } -#endif - if (gsm_ms->mncc_lfd.fd > -1) { close(gsm_ms->mncc_lfd.fd); unregister_fd(&gsm_ms->mncc_lfd); @@ -807,7 +759,7 @@ int gsm_ms_delete(const char *name) del_timer(&gsm_ms->socket_retry); /* remove instance from list */ - *gsm_ms_p = gsm_ms->gsm_ms_next; + *gsm_ms_p = gsm_ms->gsm_next; FREE(gsm_ms, sizeof(struct lcr_gsm)); return 0; diff --git a/gsm_ms.h b/gsm_ms.h index 82202f5..aeff505 100644 --- a/gsm_ms.h +++ b/gsm_ms.h @@ -25,5 +25,5 @@ int gsm_ms_exit(int rc); int gsm_ms_init(void); int gsm_ms_new(struct interface *interface); int gsm_ms_delete(const char *name); -int message_ms(struct lcr_gsm *lcr_gsm, int msg_type, void *arg); +int message_ms(class Pgsm_ms *pgsm_ms, struct lcr_gsm *lcr_gsm, int msg_type, void *arg); diff --git a/interface.c b/interface.c index 292c9aa..7619294 100644 --- a/interface.c +++ b/interface.c @@ -907,18 +907,23 @@ static int inter_gsm_bs(struct interface *interface, char *filename, int line, c #else struct interface *searchif; + interface->gsm_bs = 1; + + if (!value) + interface->gsm_bs_name[0] = '\0'; + else + SCPY(interface->gsm_bs_name, value); + + /* check if name is used multiple times */ searchif = interface_newlist; while(searchif) { - if (searchif->gsm_bs) { - SPRINT(interface_error, "Error in %s (line %d): interface '%s' already uses gsm BS side.\n", filename, line, searchif->name); + if (searchif != interface && searchif->gsm_bs && !strcmp(searchif->gsm_bs_name, interface->gsm_bs_name)) { + SPRINT(interface_error, "Error in %s (line %d): network '%s' already uses the given MS name '%s', choose a different one.\n", filename, line, interface->gsm_bs_name, searchif->gsm_bs_name); return(-1); } searchif = searchif->next; } - /* goto end of chain again to set gsmflag */ - interface->gsm_bs = 1; - return(0); #endif } @@ -953,7 +958,7 @@ static int inter_gsm_ms(struct interface *interface, char *filename, int line, c /* check if name is used multiple times */ searchif = interface_newlist; while(searchif) { - if (searchif != interface && !strcmp(searchif->gsm_ms_name, interface->gsm_ms_name)) { + if (searchif != interface && searchif->gsm_bs && !strcmp(searchif->gsm_ms_name, interface->gsm_ms_name)) { SPRINT(interface_error, "Error in %s (line %d): mobile '%s' already uses the given MS name '%s', choose a different one.\n", filename, line, interface->gsm_ms_name, searchif->gsm_ms_name); return(-1); } @@ -1352,15 +1357,15 @@ struct interface_param interface_param[] = { {"gsm", &inter_gsm, "", ""}, - {"gsm-bs", &inter_gsm_bs, "", - "Sets up GSM base station interface for using OpenBSC."}, + {"gsm-bs", &inter_gsm_bs, "[]", + "Sets up GSM base station interface for using OpenBSC.\n" + "The socket is /tmp/bsc_mncc by default. If socket name is given, the socket will be\n" + "extended to /tmp/bsc_mncc_."}, {"hr", &inter_gsm_bs_hr, "", "Enable and prefer half rate for mobile terminating calls."}, - {"gsm-ms", &inter_gsm_ms, "", + {"gsm-ms", &inter_gsm_ms, "", "Sets up GSM mobile station interface for using Osmocom-BB.\n" - "The name of the MS folows the interface name.\n" - "The socket is /tmp/osmocom_l2 by default and need to be changed when multiple\n" - "MS interfaces are used."}, + "The socket will be /tmp/ms_mncc_."}, {"sip", &inter_sip, " ", "Sets up SIP interface that represents one SIP endpoint.\n" "Give SIP configuration file."}, @@ -1697,7 +1702,7 @@ void relink_interfaces(void) #endif #ifdef WITH_GSM_BS if (interface->gsm_bs) - gsm_bs_exit(0); + gsm_bs_delete(interface->gsm_bs_name); #endif #ifdef WITH_SIP if (interface->sip) @@ -1732,7 +1737,7 @@ void relink_interfaces(void) #endif #ifdef WITH_GSM_BS if (interface->gsm_bs) - gsm_bs_init(interface); + gsm_bs_new(interface); #endif #ifdef WITH_SIP if (interface->sip) diff --git a/interface.h b/interface.h index a4b4baa..4b624f3 100644 --- a/interface.h +++ b/interface.h @@ -113,6 +113,7 @@ struct interface { char remote_context[128]; /* context feld to use for remote application */ #ifdef WITH_GSM_BS int gsm_bs; /* interface is an GSM BS interface */ + char gsm_bs_name[32]; /* name of bs */ int gsm_bs_hr; /* prefer half rate for MOT calls */ #if 0 int gsm_bs_payloads; diff --git a/main.c b/main.c index 1e85e39..b1f3ee7 100644 --- a/main.c +++ b/main.c @@ -397,15 +397,12 @@ int main(int argc, char *argv[]) goto free; } #endif -#if 0 -init is done when interface is up #ifdef WITH_GSM_BS if (gsm_bs_init()) { fprintf(stderr, "GSM BS initialization failed.\n"); goto free; } #endif -#endif #ifdef WITH_GSM_MS if (gsm_ms_init()) { fprintf(stderr, "GSM MS initialization failed.\n"); @@ -618,12 +615,9 @@ free: #endif /* free gsm */ -#if 0 -exit is done when interface is down #ifdef WITH_GSM_BS gsm_bs_exit(0); #endif -#endif #ifdef WITH_GSM_MS gsm_ms_exit(0); #endif -- 2.13.6