Modify GSM BS (OpenBTS) to use unix domain socket based MNCC
Author: Harald Welte <laforge@gnumonks.org>
This commit is contained in:
parent
7308159228
commit
d40eedaf16
|
@ -64,9 +64,7 @@ if ENABLE_GSM_BS
|
||||||
|
|
||||||
GSM_INCLUDE += -DWITH_GSM_BS -I./openbsc/include -I./libosmocore/include -I./openbsc
|
GSM_INCLUDE += -DWITH_GSM_BS -I./openbsc/include -I./libosmocore/include -I./openbsc
|
||||||
|
|
||||||
GSM_SOURCE += gsm_bs.cpp openbsc/src/bsc_init.c openbsc/src/bsc_vty.c openbsc/src/vty_interface_layer3.c openbsc/src/bsc_api.c openbsc/src/bsc_version.c
|
GSM_SOURCE += gsm_bs.cpp
|
||||||
|
|
||||||
GSM_LIB += ./openbsc/src/libbsc.a ./openbsc/src/libmsc.a ./openbsc/src/libvty.a -losmovty -losmocore -ldbi -lcrypt
|
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
2
gsm.cpp
2
gsm.cpp
|
@ -263,7 +263,7 @@ void gsm_trace_header(struct mISDNport *mISDNport, class PmISDN *port, unsigned
|
||||||
char msgtext[64];
|
char msgtext[64];
|
||||||
|
|
||||||
/* select message and primitive text */
|
/* select message and primitive text */
|
||||||
SCPY(msgtext, get_mncc_name(msg_type));
|
//SCPY(msgtext, get_mncc_name(msg_type));
|
||||||
|
|
||||||
/* add direction */
|
/* add direction */
|
||||||
if (port) {
|
if (port) {
|
||||||
|
|
12
gsm.h
12
gsm.h
|
@ -12,9 +12,21 @@ struct gsm_conf {
|
||||||
int reject_cause; /* reject cause for unsubcribed IMSIs */
|
int reject_cause; /* reject cause for unsubcribed IMSIs */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct mncc_q_entry {
|
||||||
|
struct mncc_q_entry *next;
|
||||||
|
unsigned int len;
|
||||||
|
char data[0]; /* struct gsm_mncc */
|
||||||
|
};
|
||||||
|
|
||||||
struct lcr_gsm {
|
struct lcr_gsm {
|
||||||
void *network; /* OpenBSC network handle */
|
void *network; /* OpenBSC network handle */
|
||||||
struct gsm_conf conf; /* gsm.conf options */
|
struct gsm_conf conf; /* gsm.conf options */
|
||||||
|
int gsm_sock; /* loopback interface GSM side */
|
||||||
|
int gsm_port; /* loopback interface port number */
|
||||||
|
|
||||||
|
struct lcr_fd mncc_lfd; /* Unix domain socket to OpenBSC MNCC */
|
||||||
|
struct mncc_q_entry *mncc_q_hd;
|
||||||
|
struct mncc_q_entry *mncc_q_tail;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct lcr_gsm *gsm;
|
extern struct lcr_gsm *gsm;
|
||||||
|
|
299
gsm_bs.cpp
299
gsm_bs.cpp
|
@ -16,73 +16,14 @@
|
||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
#endif
|
#endif
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
#include <assert.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
|
||||||
#include <openbsc/db.h>
|
#include <sys/socket.h>
|
||||||
#include <osmocore/select.h>
|
#include <sys/un.h>
|
||||||
#include <openbsc/debug.h>
|
|
||||||
#include <openbsc/e1_input.h>
|
|
||||||
#include <osmocore/talloc.h>
|
|
||||||
#include <openbsc/mncc.h>
|
#include <openbsc/mncc.h>
|
||||||
#include <openbsc/trau_frame.h>
|
#include <openbsc/trau_frame.h>
|
||||||
#include <openbsc/osmo_msc.h>
|
|
||||||
//#include <osmocom/vty/command.h>
|
|
||||||
struct gsm_network *bsc_gsmnet = 0;
|
|
||||||
extern int ipacc_rtp_direct;
|
|
||||||
extern int bsc_bootstrap_network(int (*mmc_rev)(struct gsm_network *, int, void *),
|
|
||||||
const char *cfg_file);
|
|
||||||
extern int bsc_shutdown_net(struct gsm_network *net);
|
|
||||||
void talloc_ctx_init(void);
|
|
||||||
void on_dso_load_token(void);
|
|
||||||
void on_dso_load_rrlp(void);
|
|
||||||
void on_dso_load_ho_dec(void);
|
|
||||||
int bts_model_unknown_init(void);
|
|
||||||
int bts_model_bs11_init(void);
|
|
||||||
int bts_model_nanobts_init(void);
|
|
||||||
static struct log_target *stderr_target;
|
|
||||||
extern const char *openbsc_copyright;
|
|
||||||
|
|
||||||
/* timer to store statistics */
|
|
||||||
#define DB_SYNC_INTERVAL 60, 0
|
|
||||||
static struct timer_list db_sync_timer;
|
|
||||||
|
|
||||||
/* FIXME: copied from the include file, because it will con compile with C++ */
|
|
||||||
struct vty_app_info {
|
|
||||||
const char *name;
|
|
||||||
const char *version;
|
|
||||||
const char *copyright;
|
|
||||||
void *tall_ctx;
|
|
||||||
int (*go_parent_cb)(struct vty *vty);
|
|
||||||
int (*is_config_node)(struct vty *vty, int node);
|
|
||||||
};
|
|
||||||
|
|
||||||
extern int bsc_vty_go_parent(struct vty *vty);
|
|
||||||
extern int bsc_vty_is_config_node(struct vty *vty, int node);
|
|
||||||
static struct vty_app_info vty_info = {
|
|
||||||
"OpenBSC",
|
|
||||||
PACKAGE_VERSION,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
bsc_vty_go_parent,
|
|
||||||
bsc_vty_is_config_node,
|
|
||||||
};
|
|
||||||
|
|
||||||
void vty_init(struct vty_app_info *app_info);
|
|
||||||
int bsc_vty_init(void);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* timer handling */
|
|
||||||
static int _db_store_counter(struct counter *counter, void *data)
|
|
||||||
{
|
|
||||||
return db_store_counter(counter);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void db_sync_timer_cb(void *data)
|
|
||||||
{
|
|
||||||
/* store counters to database and re-schedule */
|
|
||||||
counters_for_each(_db_store_counter, NULL);
|
|
||||||
bsc_schedule_timer(&db_sync_timer, DB_SYNC_INTERVAL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -838,6 +779,7 @@ int Pgsm_bs::message_epoint(unsigned int epoint_id, int message_id, union parame
|
||||||
|
|
||||||
int gsm_bs_exit(int rc)
|
int gsm_bs_exit(int rc)
|
||||||
{
|
{
|
||||||
|
#if 0
|
||||||
/* free gsm instance */
|
/* free gsm instance */
|
||||||
if (gsm) {
|
if (gsm) {
|
||||||
/* shutdown network */
|
/* shutdown network */
|
||||||
|
@ -848,110 +790,173 @@ int gsm_bs_exit(int rc)
|
||||||
// free((struct gsm_network *)gsm->network); /* TBD */
|
// free((struct gsm_network *)gsm->network); /* TBD */
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
return(rc);
|
return(rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
int gsm_bs_init(void)
|
extern "C" {
|
||||||
|
|
||||||
|
static int mncc_q_enqueue(struct gsm_mncc *mncc, unsigned int len)
|
||||||
{
|
{
|
||||||
char hlr[128], cfg[128], filename[128];
|
struct mncc_q_entry *qe;
|
||||||
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
|
|
||||||
int pcapfd, rc;
|
|
||||||
|
|
||||||
vty_info.copyright = openbsc_copyright;
|
qe = (struct mncc_q_entry *) MALLOC(sizeof(*qe)+sizeof(*mncc)+len);
|
||||||
|
if (!qe)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
log_init(&log_info);
|
qe->next = NULL;
|
||||||
tall_bsc_ctx = talloc_named_const(NULL, 1, "openbsc");
|
qe->len = len;
|
||||||
talloc_ctx_init();
|
memcpy(qe->data, mncc, len);
|
||||||
on_dso_load_token();
|
|
||||||
on_dso_load_rrlp();
|
|
||||||
on_dso_load_ho_dec();
|
|
||||||
stderr_target = log_target_create_stderr();
|
|
||||||
log_add_target(stderr_target);
|
|
||||||
|
|
||||||
bts_model_unknown_init();
|
/* in case of empty list ... */
|
||||||
bts_model_bs11_init();
|
if (!gsm->mncc_q_hd && !gsm->mncc_q_tail) {
|
||||||
bts_model_nanobts_init();
|
/* the list head and tail both point to the new qe */
|
||||||
|
gsm->mncc_q_hd = gsm->mncc_q_tail = qe;
|
||||||
/* enable filters */
|
} else {
|
||||||
log_set_all_filter(stderr_target, 1);
|
/* append to tail of list */
|
||||||
|
gsm->mncc_q_tail->next = qe;
|
||||||
/* Init VTY (need to preceed options) */
|
|
||||||
vty_init(&vty_info);
|
|
||||||
bsc_vty_init();
|
|
||||||
|
|
||||||
/* set debug */
|
|
||||||
if (gsm->conf.debug[0])
|
|
||||||
log_parse_category_mask(stderr_target, gsm->conf.debug);
|
|
||||||
|
|
||||||
/* open pcap file */
|
|
||||||
if (gsm->conf.pcapfile[0]) {
|
|
||||||
if (gsm->conf.pcapfile[0] == '/')
|
|
||||||
SCPY(filename, gsm->conf.pcapfile);
|
|
||||||
else
|
|
||||||
SPRINT(filename, "%s/%s", CONFIG_DATA, gsm->conf.pcapfile);
|
|
||||||
pcapfd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, mode);
|
|
||||||
if (pcapfd < 0) {
|
|
||||||
PERROR("Failed to open file for pcap\n");
|
|
||||||
return gsm_exit(-1);
|
|
||||||
}
|
|
||||||
e1_set_pcap_fd(pcapfd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* use RTP proxy for audio streaming */
|
gsm->mncc_lfd.when |= LCR_FD_WRITE;
|
||||||
ipacc_rtp_direct = 0;
|
|
||||||
|
|
||||||
/* bootstrap network */
|
return 0;
|
||||||
if (gsm->conf.openbsc_cfg[0] == '/')
|
}
|
||||||
SCPY(cfg, gsm->conf.openbsc_cfg);
|
|
||||||
else
|
|
||||||
SPRINT(cfg, "%s/%s", CONFIG_DATA, gsm->conf.openbsc_cfg);
|
|
||||||
rc = bsc_bootstrap_network(&message_bsc, cfg);
|
|
||||||
if (rc < 0) {
|
|
||||||
PERROR("Failed to bootstrap GSM network.\n");
|
|
||||||
return gsm_exit(-1);
|
|
||||||
}
|
|
||||||
bsc_api_init(bsc_gsmnet, msc_bsc_api());
|
|
||||||
gsm->network = bsc_gsmnet;
|
|
||||||
|
|
||||||
/* init database */
|
static struct mncc_q_entry *mncc_q_dequeue(void)
|
||||||
if (gsm->conf.hlr[0] == '/')
|
{
|
||||||
SCPY(hlr, gsm->conf.hlr);
|
struct mncc_q_entry *qe = gsm->mncc_q_hd;
|
||||||
else
|
if (!qe)
|
||||||
SPRINT(hlr, "%s/%s", CONFIG_DATA, gsm->conf.hlr);
|
return NULL;
|
||||||
if (db_init(hlr)) {
|
|
||||||
PERROR("GSM DB: Failed to init database '%s'. Please check the option settings.\n", hlr);
|
|
||||||
return gsm_exit(-1);
|
|
||||||
}
|
|
||||||
printf("DB: Database initialized.\n");
|
|
||||||
if (db_prepare()) {
|
|
||||||
PERROR("GSM DB: Failed to prepare database.\n");
|
|
||||||
return gsm_exit(-1);
|
|
||||||
}
|
|
||||||
printf("DB: Database prepared.\n");
|
|
||||||
|
|
||||||
/* setup the timer */
|
/* dequeue the successfully sent message */
|
||||||
db_sync_timer.cb = db_sync_timer_cb;
|
gsm->mncc_q_hd = qe->next;
|
||||||
db_sync_timer.data = NULL;
|
if (!qe)
|
||||||
bsc_schedule_timer(&db_sync_timer, DB_SYNC_INTERVAL);
|
return NULL;
|
||||||
|
if (qe == gsm->mncc_q_tail)
|
||||||
|
gsm->mncc_q_tail = NULL;
|
||||||
|
|
||||||
|
return qe;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* routine called by LCR code if it wants to send a message to OpenBSC */
|
||||||
|
int mncc_send(struct gsm_network *instance, int msg_type, void *data)
|
||||||
|
{
|
||||||
|
int len = 0;
|
||||||
|
|
||||||
|
/* FIXME: the caller should provide this */
|
||||||
|
switch (msg_type) {
|
||||||
|
case GSM_TCHF_FRAME:
|
||||||
|
len = 33;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
len = sizeof(struct gsm_mncc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mncc_q_enqueue((struct gsm_mncc *)data, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // extern "C"
|
||||||
|
|
||||||
|
/* close MNCC socket */
|
||||||
|
static int mncc_fd_close(struct lcr_fd *lfd)
|
||||||
|
{
|
||||||
|
close(lfd->fd);
|
||||||
|
unregister_fd(lfd);
|
||||||
|
lfd->fd = -1;
|
||||||
|
|
||||||
|
/* flush the queue */
|
||||||
|
while (mncc_q_dequeue())
|
||||||
|
;
|
||||||
|
|
||||||
|
/* FIXME: free all the calls that were running through the MNCC interface */
|
||||||
|
|
||||||
|
/* FIXME: start a re-connect timer */
|
||||||
|
|
||||||
generate_dtmf();
|
generate_dtmf();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* read from OpenBSC via MNCC socket */
|
||||||
* handles bsc select function within LCR's main loop
|
static int mncc_fd_write(struct lcr_fd *lfd, void *inst, int idx)
|
||||||
*/
|
|
||||||
int handle_gsm_bs(void)
|
|
||||||
{
|
{
|
||||||
int ret1, ret2;
|
struct mncc_q_entry *qe, *qe2;
|
||||||
|
int rc;
|
||||||
|
|
||||||
ret1 = bsc_upqueue((struct gsm_network *)gsm->network);
|
while (1) {
|
||||||
log_reset_context();
|
qe = gsm->mncc_q_hd;
|
||||||
ret2 = bsc_select_main(1); /* polling */
|
if (!qe) {
|
||||||
if (ret1 || ret2)
|
lfd->when &= ~LCR_FD_WRITE;
|
||||||
return 1;
|
break;
|
||||||
|
}
|
||||||
|
rc = write(lfd->fd, qe->data, qe->len);
|
||||||
|
if (rc == 0)
|
||||||
|
return mncc_fd_close(lfd);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
if (rc < qe->len)
|
||||||
|
return -1;
|
||||||
|
/* dequeue the successfully sent message */
|
||||||
|
qe2 = mncc_q_dequeue();
|
||||||
|
assert(qe == qe2);
|
||||||
|
free(qe);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* read from OpenBSC via MNCC socket */
|
||||||
|
static int mncc_fd_read(struct lcr_fd *lfd, void *inst, int idx)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
static char buf[sizeof(struct gsm_mncc)+1024];
|
||||||
|
struct gsm_mncc *mncc_prim = (struct gsm_mncc *) buf;
|
||||||
|
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
rc = recv(lfd->fd, buf, sizeof(buf), 0);
|
||||||
|
if (rc == 0)
|
||||||
|
return mncc_fd_close(lfd);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* Hand the MNCC message into LCR */
|
||||||
|
return message_bsc(NULL, mncc_prim->msg_type, mncc_prim);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* file descriptor callback if we can read or write form MNCC socket */
|
||||||
|
static int mncc_fd_cb(struct lcr_fd *lfd, unsigned int what, void *instance, int idx)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
if (what & LCR_FD_READ)
|
||||||
|
rc = mncc_fd_read(lfd, instance, idx);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
if (what & LCR_FD_WRITE)
|
||||||
|
rc = mncc_fd_write(lfd, instance, idx);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gsm_bs_init(void)
|
||||||
|
{
|
||||||
|
struct sockaddr_un sun;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = socket(PF_UNIX, SOCK_SEQPACKET, 0);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
gsm->mncc_lfd.fd = rc;
|
||||||
|
|
||||||
|
sun.sun_family = AF_UNIX;
|
||||||
|
strcpy(sun.sun_path, "/tmp/bsc_mncc");
|
||||||
|
rc = connect(rc, (struct sockaddr *)&sun, sizeof(sun));
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
rc = register_fd(&gsm->mncc_lfd, LCR_FD_READ, &mncc_fd_cb, NULL, 0);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
4
main.c
4
main.c
|
@ -469,10 +469,6 @@ int main(int argc, char *argv[])
|
||||||
if (options.gsm) {
|
if (options.gsm) {
|
||||||
if (handle_gsm())
|
if (handle_gsm())
|
||||||
all_idle = 0;
|
all_idle = 0;
|
||||||
#ifdef WITH_GSM_BS
|
|
||||||
if (handle_gsm_bs())
|
|
||||||
all_idle = 0;
|
|
||||||
#endif
|
|
||||||
#ifdef WITH_GSM_MS
|
#ifdef WITH_GSM_MS
|
||||||
if (handle_gsm_ms())
|
if (handle_gsm_ms())
|
||||||
all_idle = 0;
|
all_idle = 0;
|
||||||
|
|
Loading…
Reference in New Issue