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
This commit is contained in:
Andreas Eversberg 2017-06-04 11:22:51 +02:00
parent d67fcefab0
commit 155d3b5a1d
10 changed files with 171 additions and 123 deletions

View File

@ -157,6 +157,7 @@
# A special case for GSM Network interface.
# optionally give "gsm-bs <name of network instance>".
# 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.

38
gsm.cpp
View File

@ -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;

4
gsm.h
View File

@ -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 */

View File

@ -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);
}
/* destroy all instances */
while (gsm_bs_first)
gsm_bs_delete(gsm_bs_first->name);
del_timer(&gsm_bs->socket_retry);
free(gsm_bs);
gsm_bs = NULL;
}
return(rc);
return rc;
}
int gsm_bs_init(struct interface *interface)
int gsm_bs_init(void)
{
return 0;
}
/* 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;
}

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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, "[<socket name>]",
"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_<socket name>."},
{"hr", &inter_gsm_bs_hr, "",
"Enable and prefer half rate for mobile terminating calls."},
{"gsm-ms", &inter_gsm_ms, "<socket>",
{"gsm-ms", &inter_gsm_ms, "<socket name>",
"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_<socket name>."},
{"sip", &inter_sip, "<local IP> <remote IP>",
"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)

View File

@ -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;

6
main.c
View File

@ -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