# 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.
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);
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);
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;
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 */
#include "main.h"
#include "mncc.h"
-struct lcr_gsm *gsm_bs = NULL;
+struct lcr_gsm *gsm_bs_first = NULL;
#define PAYLOAD_TYPE_GSM 3
*/
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);
}
/*
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 */
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 */
/*
* 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];
return 0;
}
- if (!port) {
+ if (!pgsm_bs) {
struct interface *interface;
if (msg_type != MNCC_SETUP_IND)
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);
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;
+}
+
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 */
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);
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;
/*
* 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)
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);
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);
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;
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);
#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
}
/* 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);
}
{"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."},
#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)
#endif
#ifdef WITH_GSM_BS
if (interface->gsm_bs)
- gsm_bs_init(interface);
+ gsm_bs_new(interface);
#endif
#ifdef WITH_SIP
if (interface->sip)
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;
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");
#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