mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw.git
synced 2025-11-02 13:03:33 +00:00
Compare commits
32 Commits
on-waves/0
...
on-waves/0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fcb4468de4 | ||
|
|
9e96b2df12 | ||
|
|
72952d854c | ||
|
|
637dce99ba | ||
|
|
641b07ab73 | ||
|
|
6eae31e39f | ||
|
|
4647015f69 | ||
|
|
239f95467c | ||
|
|
cd80c73f37 | ||
|
|
d6f1c4afbb | ||
|
|
0c8af75c94 | ||
|
|
e4b33be6fc | ||
|
|
cc7461cefc | ||
|
|
e174061d17 | ||
|
|
6e1c3412ae | ||
|
|
bff54b3e00 | ||
|
|
e75eb4ca25 | ||
|
|
566737a4b8 | ||
|
|
2b7350240d | ||
|
|
d76b53c00e | ||
|
|
9c9ef7796a | ||
|
|
49fcc8fc90 | ||
|
|
51a4bcc96a | ||
|
|
d6238120dd | ||
|
|
7407aec921 | ||
|
|
e575ce69ce | ||
|
|
c1ca0ff091 | ||
|
|
661e68b78f | ||
|
|
376e146cfb | ||
|
|
eb3ab2f85b | ||
|
|
ebc38e4f26 | ||
|
|
e2ab44a439 |
@@ -1,7 +1,6 @@
|
||||
dnl Process this file with autoconf to produce a configure script
|
||||
AC_INIT
|
||||
|
||||
AM_INIT_AUTOMAKE(openbsc, 0.3.99.7onwaves)
|
||||
AC_INIT(openbsc, 0.3.99.11onwaves)
|
||||
AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION)
|
||||
|
||||
dnl kernel style compile messages
|
||||
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
|
||||
|
||||
@@ -92,7 +92,7 @@ int abis_nm_sw_act_req_ack(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i1,
|
||||
int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *msg);
|
||||
int abis_nm_event_reports(struct gsm_bts *bts, int on);
|
||||
int abis_nm_reset_resource(struct gsm_bts *bts);
|
||||
int abis_nm_software_load(struct gsm_bts *bts, const char *fname,
|
||||
int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
|
||||
u_int8_t win_size, int forced,
|
||||
gsm_cbfn *cbfn, void *cb_data);
|
||||
int abis_nm_software_load_status(struct gsm_bts *bts);
|
||||
@@ -148,7 +148,7 @@ int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type,
|
||||
u_int8_t *attr, int attr_len);
|
||||
int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, u_int8_t *attr,
|
||||
int attr_len);
|
||||
int abis_nm_ipaccess_restart(struct gsm_bts *bts);
|
||||
int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx);
|
||||
int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class,
|
||||
u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
|
||||
u_int8_t *attr, u_int8_t attr_len);
|
||||
@@ -164,7 +164,8 @@ enum nm_evt {
|
||||
EVT_STATECHG_ADM,
|
||||
};
|
||||
int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
|
||||
struct gsm_nm_state *old_state, struct gsm_nm_state *new_state);
|
||||
struct gsm_nm_state *old_state, struct gsm_nm_state *new_state,
|
||||
struct abis_om_obj_inst *obj_inst);
|
||||
|
||||
const char *nm_opstate_name(u_int8_t os);
|
||||
const char *nm_avail_name(u_int8_t avail);
|
||||
|
||||
@@ -36,6 +36,7 @@ struct bsc_msc_connection {
|
||||
void (*connection_loss) (struct bsc_msc_connection *);
|
||||
void (*connected) (struct bsc_msc_connection *);
|
||||
struct timer_list reconnect_timer;
|
||||
struct timer_list timeout_timer;
|
||||
};
|
||||
|
||||
struct bsc_msc_connection *bsc_msc_create(const char *ip, int port);
|
||||
|
||||
@@ -120,6 +120,9 @@ struct sccp_connections {
|
||||
int crcx;
|
||||
int msc_timeslot;
|
||||
int bsc_timeslot;
|
||||
|
||||
/* timeout handling */
|
||||
struct timespec creation_time;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -213,6 +216,7 @@ struct bsc_nat {
|
||||
char *msc_ip;
|
||||
int msc_port;
|
||||
int first_contact;
|
||||
struct bsc_msc_connection *msc_con;
|
||||
|
||||
/* timeouts */
|
||||
int auth_timeout;
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
struct bsc_msc_connection;
|
||||
|
||||
enum gsm_phys_chan_config {
|
||||
GSM_PCHAN_NONE,
|
||||
GSM_PCHAN_CCCH,
|
||||
@@ -673,6 +675,7 @@ struct gsm_network {
|
||||
char *bsc_token;
|
||||
char *msc_ip;
|
||||
int msc_port;
|
||||
struct bsc_msc_connection *msc_con;
|
||||
int ping_timeout;
|
||||
int pong_timeout;
|
||||
};
|
||||
|
||||
@@ -133,7 +133,7 @@ struct scall_signal_data {
|
||||
};
|
||||
|
||||
struct ipacc_ack_signal_data {
|
||||
struct gsm_bts *bts;
|
||||
struct gsm_bts_trx *trx;
|
||||
u_int8_t msg_type;
|
||||
};
|
||||
|
||||
|
||||
@@ -56,4 +56,4 @@ bsc_nat_SOURCES = nat/bsc_nat.c nat/bsc_filter.c nat/bsc_sccp.c \
|
||||
nat/bsc_nat_utils.c nat/bsc_nat_vty.c nat/bsc_mgcp_utils.c \
|
||||
mgcp/mgcp_protocol.c mgcp/mgcp_network.c mgcp/mgcp_vty.c \
|
||||
bsc_msc.c bssap.c
|
||||
bsc_nat_LDADD = libvty.a libbsc.a libsccp.a
|
||||
bsc_nat_LDADD = libvty.a libbsc.a libsccp.a -lrt
|
||||
|
||||
@@ -678,7 +678,7 @@ static int update_admstate(struct gsm_bts *bts, u_int8_t obj_class,
|
||||
new_state = *nm_state;
|
||||
new_state.administrative = adm_state;
|
||||
|
||||
rc = nm_state_event(EVT_STATECHG_ADM, obj_class, obj, nm_state, &new_state);
|
||||
rc = nm_state_event(EVT_STATECHG_ADM, obj_class, obj, nm_state, &new_state, obj_inst);
|
||||
|
||||
nm_state->administrative = adm_state;
|
||||
|
||||
@@ -732,7 +732,7 @@ static int abis_nm_rx_statechg_rep(struct msgb *mb)
|
||||
/* Update the operational state of a given object in our in-memory data
|
||||
* structures and send an event to the higher layer */
|
||||
void *obj = objclass2obj(bts, foh->obj_class, &foh->obj_inst);
|
||||
rc = nm_state_event(EVT_STATECHG_OPER, foh->obj_class, obj, nm_state, &new_state);
|
||||
rc = nm_state_event(EVT_STATECHG_OPER, foh->obj_class, obj, nm_state, &new_state, &foh->obj_inst);
|
||||
nm_state->operational = new_state.operational;
|
||||
nm_state->availability = new_state.availability;
|
||||
if (nm_state->administrative == 0)
|
||||
@@ -1139,6 +1139,7 @@ enum sw_state {
|
||||
|
||||
struct abis_nm_sw {
|
||||
struct gsm_bts *bts;
|
||||
int trx_nr;
|
||||
gsm_cbfn *cbfn;
|
||||
void *cb_data;
|
||||
int forced;
|
||||
@@ -1592,7 +1593,7 @@ static int abis_nm_rcvmsg_sw(struct msgb *mb)
|
||||
}
|
||||
|
||||
/* Load the specified software into the BTS */
|
||||
int abis_nm_software_load(struct gsm_bts *bts, const char *fname,
|
||||
int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
|
||||
u_int8_t win_size, int forced,
|
||||
gsm_cbfn *cbfn, void *cb_data)
|
||||
{
|
||||
@@ -1606,6 +1607,7 @@ int abis_nm_software_load(struct gsm_bts *bts, const char *fname,
|
||||
return -EBUSY;
|
||||
|
||||
sw->bts = bts;
|
||||
sw->trx_nr = trx_nr;
|
||||
|
||||
switch (bts->type) {
|
||||
case GSM_BTS_TYPE_BS11:
|
||||
@@ -1616,8 +1618,8 @@ int abis_nm_software_load(struct gsm_bts *bts, const char *fname,
|
||||
break;
|
||||
case GSM_BTS_TYPE_NANOBTS:
|
||||
sw->obj_class = NM_OC_BASEB_TRANSC;
|
||||
sw->obj_instance[0] = 0x00;
|
||||
sw->obj_instance[1] = 0x00;
|
||||
sw->obj_instance[0] = sw->bts->nr;
|
||||
sw->obj_instance[1] = sw->trx_nr;
|
||||
sw->obj_instance[2] = 0xff;
|
||||
break;
|
||||
case GSM_BTS_TYPE_UNKNOWN:
|
||||
@@ -2551,7 +2553,7 @@ static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
|
||||
fle = fl_dequeue(&bs11_sw->file_list);
|
||||
if (fle) {
|
||||
/* start download the next file of our file list */
|
||||
rc = abis_nm_software_load(bs11_sw->bts, fle->fname,
|
||||
rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
|
||||
bs11_sw->win_size,
|
||||
bs11_sw->forced,
|
||||
&bs11_swload_cbfn, bs11_sw);
|
||||
@@ -2607,7 +2609,7 @@ int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
|
||||
return -EINVAL;
|
||||
|
||||
/* start download the next file of our file list */
|
||||
rc = abis_nm_software_load(bts, fle->fname, win_size, forced,
|
||||
rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
|
||||
bs11_swload_cbfn, bs11_sw);
|
||||
talloc_free(fle);
|
||||
return rc;
|
||||
@@ -2775,12 +2777,12 @@ static int abis_nm_rx_ipacc(struct msgb *msg)
|
||||
case NM_MT_IPACC_RSL_CONNECT_NACK:
|
||||
case NM_MT_IPACC_SET_NVATTR_NACK:
|
||||
case NM_MT_IPACC_GET_NVATTR_NACK:
|
||||
signal.bts = msg->trx->bts;
|
||||
signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
|
||||
signal.msg_type = foh->msg_type;
|
||||
dispatch_signal(SS_NM, S_NM_IPACC_NACK, &signal);
|
||||
break;
|
||||
case NM_MT_IPACC_SET_NVATTR_ACK:
|
||||
signal.bts = msg->trx->bts;
|
||||
signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
|
||||
signal.msg_type = foh->msg_type;
|
||||
dispatch_signal(SS_NM, S_NM_IPACC_ACK, &signal);
|
||||
break;
|
||||
@@ -2866,9 +2868,16 @@ int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
|
||||
}
|
||||
|
||||
/* restart / reboot an ip.access nanoBTS */
|
||||
int abis_nm_ipaccess_restart(struct gsm_bts *bts)
|
||||
int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
|
||||
{
|
||||
return __simple_cmd(bts, NM_MT_IPACC_RESTART);
|
||||
struct abis_om_hdr *oh;
|
||||
struct msgb *msg = nm_msgb_alloc();
|
||||
|
||||
oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
|
||||
fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
|
||||
trx->bts->nr, trx->nr, 0xff);
|
||||
|
||||
return abis_nm_sendmsg(trx->bts, msg);
|
||||
}
|
||||
|
||||
int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class,
|
||||
|
||||
@@ -481,7 +481,7 @@ static int handle_state_resp(enum abis_bs11_phase state)
|
||||
* argument, so our swload_cbfn can distinguish
|
||||
* a safety load from a regular software */
|
||||
if (file_is_readable(fname_safety))
|
||||
rc = abis_nm_software_load(g_bts, fname_safety,
|
||||
rc = abis_nm_software_load(g_bts, 0xff, fname_safety,
|
||||
win_size, param_forced,
|
||||
swload_cbfn, g_bts);
|
||||
else
|
||||
@@ -697,7 +697,8 @@ int handle_serial_msg(struct msgb *rx_msg)
|
||||
}
|
||||
|
||||
int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
|
||||
struct gsm_nm_state *old_state, struct gsm_nm_state *new_state)
|
||||
struct gsm_nm_state *old_state, struct gsm_nm_state *new_state,
|
||||
struct abis_om_obj_inst *obj_ins)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -401,7 +401,8 @@ static unsigned char nanobts_attr_nsvc0[] = {
|
||||
|
||||
/* Callback function to be called whenever we get a GSM 12.21 state change event */
|
||||
int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
|
||||
struct gsm_nm_state *old_state, struct gsm_nm_state *new_state)
|
||||
struct gsm_nm_state *old_state, struct gsm_nm_state *new_state,
|
||||
struct abis_om_obj_inst *obj_inst)
|
||||
{
|
||||
struct gsm_bts *bts;
|
||||
struct gsm_bts_trx *trx;
|
||||
|
||||
@@ -49,6 +49,14 @@ static void connection_loss(struct bsc_msc_connection *con)
|
||||
con->connection_loss(con);
|
||||
}
|
||||
|
||||
static void msc_con_timeout(void *_con)
|
||||
{
|
||||
struct bsc_msc_connection *con = _con;
|
||||
|
||||
LOGP(DMSC, LOGL_ERROR, "MSC Connection timeout.\n");
|
||||
bsc_msc_lost(con);
|
||||
}
|
||||
|
||||
static int bsc_msc_except(struct bsc_fd *bfd)
|
||||
{
|
||||
struct write_queue *wrt;
|
||||
@@ -98,6 +106,7 @@ static int msc_connection_connect(struct bsc_fd *fd, unsigned int what)
|
||||
fd->when = BSC_FD_READ | BSC_FD_EXCEPT;
|
||||
|
||||
con->is_connected = 1;
|
||||
bsc_del_timer(&con->timeout_timer);
|
||||
LOGP(DMSC, LOGL_NOTICE, "(Re)Connected to the MSC.\n");
|
||||
if (con->connected)
|
||||
con->connected(con);
|
||||
@@ -165,6 +174,9 @@ int bsc_msc_connect(struct bsc_msc_connection *con)
|
||||
LOGP(DMSC, LOGL_ERROR, "MSC Connection in progress\n");
|
||||
fd->when = BSC_FD_WRITE;
|
||||
fd->cb = msc_connection_connect;
|
||||
con->timeout_timer.cb = msc_con_timeout;
|
||||
con->timeout_timer.data = con;
|
||||
bsc_schedule_timer(&con->timeout_timer, 20, 0);
|
||||
} else if (ret < 0) {
|
||||
perror("Connection failed");
|
||||
connection_loss(con);
|
||||
|
||||
@@ -47,9 +47,12 @@
|
||||
#include <openbsc/bsc_nat.h>
|
||||
#include <openbsc/bsc_msc_rf.h>
|
||||
|
||||
#include <vty/command.h>
|
||||
|
||||
#include <osmocore/select.h>
|
||||
#include <osmocore/talloc.h>
|
||||
#include <osmocore/write_queue.h>
|
||||
#include <osmocore/gsm0808.h>
|
||||
|
||||
#include <sccp/sccp.h>
|
||||
|
||||
@@ -65,22 +68,37 @@ static struct in_addr local_addr;
|
||||
static LLIST_HEAD(active_connections);
|
||||
static struct write_queue mgcp_agent;
|
||||
static const char *rf_ctl = NULL;
|
||||
static int testmode = 0;
|
||||
extern int ipacc_rtp_direct;
|
||||
|
||||
/* msc handling */
|
||||
static struct bsc_msc_connection *msc_con;
|
||||
static struct timer_list msc_ping_timeout;
|
||||
static struct timer_list msc_pong_timeout;
|
||||
|
||||
extern int bsc_bootstrap_network(int (*layer4)(struct gsm_network *, int, void *), const char *cfg_file);
|
||||
extern int bsc_shutdown_net(struct gsm_network *net);
|
||||
|
||||
static void install_extra_commands();
|
||||
|
||||
|
||||
struct llist_head *bsc_sccp_connections()
|
||||
{
|
||||
return &active_connections;
|
||||
}
|
||||
|
||||
/*
|
||||
* Having a subscriber in the lchan is used to indicate that a SACH DEACTIVATE
|
||||
* should be send. We will just introduce a fake subscriber and bind it to the
|
||||
* lchan.
|
||||
*/
|
||||
static void assign_dummy_subscr(struct gsm_lchan *lchan)
|
||||
{
|
||||
if (!lchan->conn.subscr) {
|
||||
lchan->conn.subscr = subscr_get_or_create(bsc_gsmnet, "2323");
|
||||
lchan->conn.subscr->lac = 2323;
|
||||
}
|
||||
}
|
||||
|
||||
struct bss_sccp_connection_data *bss_sccp_create_data()
|
||||
{
|
||||
struct bss_sccp_connection_data *data;
|
||||
@@ -270,7 +288,7 @@ static int open_sccp_connection(struct msgb *layer3)
|
||||
struct msgb *data;
|
||||
|
||||
/* When not connected to a MSC. We will simply close things down. */
|
||||
if (!msc_con->is_authenticated) {
|
||||
if (!bsc_gsmnet->msc_con->is_authenticated) {
|
||||
LOGP(DMSC, LOGL_ERROR, "Not connected to a MSC. Not forwarding data.\n");
|
||||
use_subscr_con(&layer3->lchan->conn);
|
||||
put_subscr_con(&layer3->lchan->conn, 0);
|
||||
@@ -314,6 +332,8 @@ static int open_sccp_connection(struct msgb *layer3)
|
||||
bsc_schedule_timer(&con_data->sccp_cc_timeout, 10, 0);
|
||||
|
||||
/* FIXME: Use transaction for this */
|
||||
/* assign a dummy subscriber */
|
||||
assign_dummy_subscr(layer3->lchan);
|
||||
use_subscr_con(&layer3->lchan->conn);
|
||||
sccp_connection_connect(sccp_connection, &sccp_ssn_bssap, data);
|
||||
msgb_free(data);
|
||||
@@ -421,6 +441,9 @@ static int handle_ass_compl(struct msgb *msg)
|
||||
msg->lchan->msc_data->secondary_lchan = NULL;
|
||||
old_chan->msc_data = NULL;
|
||||
|
||||
/* assign a dummy subscriber */
|
||||
assign_dummy_subscr(msg->lchan);
|
||||
|
||||
/* give up the old channel to not do a SACCH deactivate */
|
||||
if (old_chan->conn.subscr)
|
||||
subscr_put(old_chan->conn.subscr);
|
||||
@@ -636,7 +659,7 @@ static void print_usage()
|
||||
static int msc_queue_write(struct msgb *msg, int proto)
|
||||
{
|
||||
ipaccess_prepend_header(msg, proto);
|
||||
if (write_queue_enqueue(&msc_con->write_queue, msg) != 0) {
|
||||
if (write_queue_enqueue(&bsc_gsmnet->msc_con->write_queue, msg) != 0) {
|
||||
LOGP(DMSC, LOGL_FATAL, "Failed to queue IPA/%d\n", proto);
|
||||
msgb_free(msg);
|
||||
return -1;
|
||||
@@ -652,7 +675,7 @@ static int msc_sccp_do_write(struct bsc_fd *fd, struct msgb *msg)
|
||||
LOGP(DMSC, LOGL_DEBUG, "Sending SCCP to MSC: %u\n", msgb_l2len(msg));
|
||||
LOGP(DMI, LOGL_DEBUG, "MSC TX %s\n", hexdump(msg->l2h, msgb_l2len(msg)));
|
||||
|
||||
ret = write(msc_con->write_queue.bfd.fd, msg->data, msg->len);
|
||||
ret = write(bsc_gsmnet->msc_con->write_queue.bfd.fd, msg->data, msg->len);
|
||||
if (ret < msg->len)
|
||||
perror("MSC: Failed to send SCCP");
|
||||
|
||||
@@ -824,9 +847,9 @@ static void initialize_if_needed(void)
|
||||
struct msgb *msg;
|
||||
|
||||
|
||||
if (!msc_con->is_authenticated) {
|
||||
if (!bsc_gsmnet->msc_con->is_authenticated) {
|
||||
/* send a gsm 08.08 reset message from here */
|
||||
msg = bssmap_create_reset();
|
||||
msg = gsm0808_create_reset();
|
||||
if (!msg) {
|
||||
LOGP(DMSC, LOGL_ERROR, "Failed to create the reset message.\n");
|
||||
return;
|
||||
@@ -834,7 +857,7 @@ static void initialize_if_needed(void)
|
||||
|
||||
sccp_write(msg, &sccp_ssn_bssap, &sccp_ssn_bssap, 0);
|
||||
msgb_free(msg);
|
||||
msc_con->is_authenticated = 1;
|
||||
bsc_gsmnet->msc_con->is_authenticated = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -859,6 +882,32 @@ static void send_id_get_response(int fd)
|
||||
msc_queue_write(msg, IPAC_PROTO_IPACCESS);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send some packets to test the MSC.
|
||||
*/
|
||||
static void test_msc()
|
||||
{
|
||||
struct msgb *msg;
|
||||
|
||||
if (!testmode)
|
||||
return;
|
||||
|
||||
static const uint8_t pag_resp[] = {
|
||||
0x01, 0xf3, 0x26, 0x09, 0x02, 0x02, 0x04, 0x02, 0x42,
|
||||
0xfe, 0x0f, 0x1f, 0x00, 0x1d, 0x57, 0x05, 0x08, 0x00,
|
||||
0x72, 0xf4, 0x80, 0x10, 0x1c, 0x9c, 0x40, 0x17, 0x10,
|
||||
0x06, 0x27, 0x02, 0x03, 0x30, 0x18, 0xa0, 0x08, 0x59,
|
||||
0x51, 0x30, 0x10, 0x30, 0x32, 0x80, 0x06, 0x00
|
||||
};
|
||||
|
||||
msg = msgb_alloc_headroom(4096, 128, "paging response");
|
||||
if (!msg)
|
||||
return;
|
||||
msg->l2h = msgb_put(msg, sizeof(pag_resp));
|
||||
memcpy(msg->l2h, pag_resp, sizeof(pag_resp));
|
||||
msc_queue_write(msg, IPAC_PROTO_SCCP);
|
||||
}
|
||||
|
||||
/*
|
||||
* The connection to the MSC was lost and we will need to free all
|
||||
* resources and then attempt to reconnect.
|
||||
@@ -883,7 +932,7 @@ static void msc_connection_was_lost(struct bsc_msc_connection *msc)
|
||||
static void msc_pong_timeout_cb(void *data)
|
||||
{
|
||||
LOGP(DMSC, LOGL_ERROR, "MSC didn't answer PING. Closing connection.\n");
|
||||
bsc_msc_lost(msc_con);
|
||||
bsc_msc_lost(bsc_gsmnet->msc_con);
|
||||
}
|
||||
|
||||
static void send_ping(void)
|
||||
@@ -939,7 +988,7 @@ static int ipaccess_a_fd_cb(struct bsc_fd *bfd)
|
||||
if (!msg) {
|
||||
if (error == 0) {
|
||||
LOGP(DMSC, LOGL_ERROR, "The connection to the MSC was lost.\n");
|
||||
bsc_msc_lost(msc_con);
|
||||
bsc_msc_lost(bsc_gsmnet->msc_con);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -959,6 +1008,7 @@ static int ipaccess_a_fd_cb(struct bsc_fd *bfd)
|
||||
initialize_if_needed();
|
||||
else if (msg->l2h[0] == IPAC_MSGT_ID_GET) {
|
||||
send_id_get_response(bfd->fd);
|
||||
test_msc();
|
||||
} else if (msg->l2h[0] == IPAC_MSGT_PONG) {
|
||||
bsc_del_timer(&msc_pong_timeout);
|
||||
}
|
||||
@@ -984,6 +1034,7 @@ static void print_help()
|
||||
printf(" -l --local=IP. The local address of the MGCP.\n");
|
||||
printf(" -e --log-level number. Set a global loglevel.\n");
|
||||
printf(" -r --rf-ctl NAME. A unix domain socket to listen for cmds.\n");
|
||||
printf(" -t --testmode. A special mode to provoke failures at the MSC.\n");
|
||||
}
|
||||
|
||||
static void handle_options(int argc, char** argv)
|
||||
@@ -1000,10 +1051,11 @@ static void handle_options(int argc, char** argv)
|
||||
{"local", 1, 0, 'l'},
|
||||
{"log-level", 1, 0, 'e'},
|
||||
{"rf-ctl", 1, 0, 'r'},
|
||||
{"testmode", 0, 0, 't'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
c = getopt_long(argc, argv, "hd:sTc:m:l:e:r:",
|
||||
c = getopt_long(argc, argv, "hd:sTc:m:l:e:r:t",
|
||||
long_options, &option_index);
|
||||
if (c == -1)
|
||||
break;
|
||||
@@ -1040,6 +1092,9 @@ static void handle_options(int argc, char** argv)
|
||||
case 'r':
|
||||
rf_ctl = optarg;
|
||||
break;
|
||||
case 't':
|
||||
testmode = 1;
|
||||
break;
|
||||
default:
|
||||
/* ignore */
|
||||
break;
|
||||
@@ -1066,9 +1121,9 @@ static void signal_handler(int signal)
|
||||
talloc_report_full(tall_bsc_ctx, stderr);
|
||||
break;
|
||||
case SIGUSR2:
|
||||
if (!msc_con || !msc_con->is_connected)
|
||||
if (!bsc_gsmnet->msc_con || !bsc_gsmnet->msc_con->is_connected)
|
||||
return;
|
||||
bsc_msc_lost(msc_con);
|
||||
bsc_msc_lost(bsc_gsmnet->msc_con);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -1183,20 +1238,22 @@ int main(int argc, char **argv)
|
||||
if (msc_address)
|
||||
msc = msc_address;
|
||||
|
||||
msc_con = bsc_msc_create(msc, bsc_gsmnet->msc_port);
|
||||
if (!msc_con) {
|
||||
bsc_gsmnet->msc_con = bsc_msc_create(msc, bsc_gsmnet->msc_port);
|
||||
if (!bsc_gsmnet->msc_con) {
|
||||
fprintf(stderr, "Creating a bsc_msc_connection failed.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
install_extra_commands();
|
||||
|
||||
msc_ping_timeout.cb = msc_ping_timeout_cb;
|
||||
msc_pong_timeout.cb = msc_pong_timeout_cb;
|
||||
|
||||
msc_con->connection_loss = msc_connection_was_lost;
|
||||
msc_con->connected = msc_connection_connected;
|
||||
msc_con->write_queue.read_cb = ipaccess_a_fd_cb;
|
||||
msc_con->write_queue.write_cb = msc_sccp_do_write;
|
||||
bsc_msc_connect(msc_con);
|
||||
bsc_gsmnet->msc_con->connection_loss = msc_connection_was_lost;
|
||||
bsc_gsmnet->msc_con->connected = msc_connection_connected;
|
||||
bsc_gsmnet->msc_con->write_queue.read_cb = ipaccess_a_fd_cb;
|
||||
bsc_gsmnet->msc_con->write_queue.write_cb = msc_sccp_do_write;
|
||||
bsc_msc_connect(bsc_gsmnet->msc_con);
|
||||
|
||||
|
||||
|
||||
@@ -1204,3 +1261,25 @@ int main(int argc, char **argv)
|
||||
bsc_select_main(0);
|
||||
}
|
||||
}
|
||||
|
||||
DEFUN(show_msc,
|
||||
show_msc_cmd,
|
||||
"show msc connection",
|
||||
SHOW_STR "Show the status of the MSC connection.")
|
||||
{
|
||||
if (!bsc_gsmnet->msc_con) {
|
||||
vty_out(vty, "The MSC is not yet configured.\n");
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
vty_out(vty, "MSC on %s:%d is connected: %d%s\n",
|
||||
bsc_gsmnet->msc_con->ip, bsc_gsmnet->msc_con->port,
|
||||
bsc_gsmnet->msc_con->is_connected, VTY_NEWLINE);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static void install_extra_commands()
|
||||
{
|
||||
install_element(VIEW_NODE, &show_msc_cmd);
|
||||
}
|
||||
|
||||
@@ -59,14 +59,14 @@ static void handle_query(struct bsc_msc_rf_conn *conn)
|
||||
{
|
||||
struct msgb *msg;
|
||||
struct gsm_bts *bts;
|
||||
char send = '0';
|
||||
char send = RF_CMD_OFF;
|
||||
|
||||
llist_for_each_entry(bts, &conn->gsm_network->bts_list, list) {
|
||||
struct gsm_bts_trx *trx;
|
||||
llist_for_each_entry(trx, &bts->trx_list, list) {
|
||||
if (trx->nm_state.availability == NM_AVSTATE_OK &&
|
||||
trx->nm_state.operational != NM_STATE_LOCKED) {
|
||||
send = '1';
|
||||
send = RF_CMD_ON;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ static int bssmap_handle_clear_command(struct sccp_connection *conn,
|
||||
}
|
||||
|
||||
/* send the clear complete message */
|
||||
resp = bssmap_create_clear_complete();
|
||||
resp = gsm0808_create_clear_complete();
|
||||
if (!resp) {
|
||||
LOGP(DMSC, LOGL_ERROR, "Sending clear complete failed.\n");
|
||||
return -1;
|
||||
@@ -312,7 +312,7 @@ static void bssmap_t10_fired(void *_conn)
|
||||
msc_data = conn->data_ctx;
|
||||
bssmap_free_secondary(msc_data);
|
||||
|
||||
resp = bssmap_create_assignment_failure(
|
||||
resp = gsm0808_create_assignment_failure(
|
||||
GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE, NULL);
|
||||
if (!resp) {
|
||||
LOGP(DMSC, LOGL_ERROR, "Allocation failure: %p\n", conn);
|
||||
@@ -765,36 +765,6 @@ struct msgb *bssmap_create_layer3(struct msgb *msg_l3)
|
||||
return msg;
|
||||
}
|
||||
|
||||
struct msgb *bssmap_create_reset(void)
|
||||
{
|
||||
struct msgb *msg = msgb_alloc(30, "bssmap: reset");
|
||||
if (!msg)
|
||||
return NULL;
|
||||
|
||||
msg->l3h = msgb_put(msg, 6);
|
||||
msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
|
||||
msg->l3h[1] = 0x04;
|
||||
msg->l3h[2] = 0x30;
|
||||
msg->l3h[3] = 0x04;
|
||||
msg->l3h[4] = 0x01;
|
||||
msg->l3h[5] = 0x20;
|
||||
return msg;
|
||||
}
|
||||
|
||||
struct msgb *bssmap_create_clear_complete(void)
|
||||
{
|
||||
struct msgb *msg = msgb_alloc(30, "bssmap: clear complete");
|
||||
if (!msg)
|
||||
return NULL;
|
||||
|
||||
msg->l3h = msgb_put(msg, 3);
|
||||
msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
|
||||
msg->l3h[1] = 1;
|
||||
msg->l3h[2] = BSS_MAP_MSG_CLEAR_COMPLETE;
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
struct msgb *bssmap_create_cipher_complete(struct msgb *layer3)
|
||||
{
|
||||
struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
|
||||
@@ -1005,36 +975,6 @@ struct msgb *bssmap_create_assignment_completed(struct gsm_lchan *lchan, u_int8_
|
||||
return msg;
|
||||
}
|
||||
|
||||
struct msgb *bssmap_create_assignment_failure(u_int8_t cause, u_int8_t *rr_cause)
|
||||
{
|
||||
u_int8_t *data;
|
||||
struct msgb *msg = msgb_alloc(35, "bssmap: ass fail");
|
||||
if (!msg)
|
||||
return NULL;
|
||||
|
||||
msg->l3h = msgb_put(msg, 6);
|
||||
msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
|
||||
msg->l3h[1] = 0xff;
|
||||
msg->l3h[2] = BSS_MAP_MSG_ASSIGMENT_FAILURE;
|
||||
msg->l3h[3] = GSM0808_IE_CAUSE;
|
||||
msg->l3h[4] = 1;
|
||||
msg->l3h[5] = cause;
|
||||
|
||||
/* RR cause 3.2.2.22 */
|
||||
if (rr_cause) {
|
||||
data = msgb_put(msg, 2);
|
||||
data[0] = GSM0808_IE_RR_CAUSE;
|
||||
data[1] = *rr_cause;
|
||||
}
|
||||
|
||||
/* Circuit pool 3.22.45 */
|
||||
/* Circuit pool list 3.2.2.46 */
|
||||
|
||||
/* update the size */
|
||||
msg->l3h[1] = msgb_l3len(msg) - 2;
|
||||
return msg;
|
||||
}
|
||||
|
||||
struct msgb *dtap_create_msg(struct msgb *msg_l3, u_int8_t link_id)
|
||||
{
|
||||
struct dtap_header *header;
|
||||
@@ -1312,7 +1252,7 @@ void gsm0808_send_assignment_failure(struct gsm_lchan *lchan, u_int8_t cause, u_
|
||||
|
||||
bsc_del_timer(&lchan->msc_data->T10);
|
||||
bssmap_free_secondary(lchan->msc_data);
|
||||
resp = bssmap_create_assignment_failure(cause, rr_value);
|
||||
resp = gsm0808_create_assignment_failure(cause, rr_value);
|
||||
if (!resp) {
|
||||
LOGP(DMSC, LOGL_ERROR, "Allocation failure: %p\n", lchan_get_sccp(lchan));
|
||||
return;
|
||||
|
||||
@@ -381,6 +381,11 @@ static void _lchan_handle_release(struct gsm_lchan *lchan)
|
||||
++lchan->conn.use_count;
|
||||
gsm48_send_rr_release(lchan);
|
||||
--lchan->conn.use_count;
|
||||
|
||||
/* avoid reentrancy */
|
||||
subscr_put(lchan->conn.subscr);
|
||||
lchan->conn.subscr = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
/* spoofed? message */
|
||||
|
||||
@@ -321,7 +321,7 @@ int gsm48_handle_paging_resp(struct msgb *msg, struct gsm_subscriber *subscr)
|
||||
sig_data.bts = msg->lchan->ts->trx->bts;
|
||||
sig_data.lchan = msg->lchan;
|
||||
|
||||
bts->network->stats.paging.completed++;
|
||||
counter_inc(bts->network->stats.paging.completed);
|
||||
|
||||
dispatch_signal(SS_PAGING, S_PAGING_SUCCEEDED, &sig_data);
|
||||
|
||||
|
||||
@@ -265,7 +265,7 @@ static int ipaccess_rcvmsg(struct e1inp_line *line, struct msgb *msg,
|
||||
trx->rsl_link = e1inp_sign_link_create(e1i_ts,
|
||||
E1INP_SIGN_RSL, trx,
|
||||
trx->rsl_tei, 0);
|
||||
trx->rsl_link->ts->sign.delay = 10;
|
||||
trx->rsl_link->ts->sign.delay = 0;
|
||||
|
||||
/* get rid of our old temporary bfd */
|
||||
memcpy(newbfd, bfd, sizeof(*newbfd));
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/* ip.access nanoBTS configuration tool */
|
||||
|
||||
/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
|
||||
* (C) 2009 by Holger Hans Peter Freyther
|
||||
* (C) 2009 by On Waves
|
||||
* (C) 2009,2010 by Holger Hans Peter Freyther
|
||||
* (C) 2009,2010 by On Waves
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -59,7 +59,7 @@ static int sw_load_state = 0;
|
||||
static int oml_state = 0;
|
||||
static int dump_files = 0;
|
||||
static char *firmware_analysis = NULL;
|
||||
static int trx_nr = 0;
|
||||
static int found_trx = 0;
|
||||
|
||||
struct sw_load {
|
||||
u_int8_t file_id[255];
|
||||
@@ -92,23 +92,23 @@ static int ipacc_msg_nack(u_int8_t mt)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ipacc_msg_ack(u_int8_t mt, struct gsm_bts *bts)
|
||||
static void check_restart_or_exit(struct gsm_bts_trx *trx)
|
||||
{
|
||||
if (restart) {
|
||||
abis_nm_ipaccess_restart(trx);
|
||||
} else {
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
static int ipacc_msg_ack(u_int8_t mt, struct gsm_bts_trx *trx)
|
||||
{
|
||||
if (sw_load_state == 1) {
|
||||
fprintf(stderr, "The new software is activaed.\n");
|
||||
|
||||
if (restart) {
|
||||
abis_nm_ipaccess_restart(bts);
|
||||
} else {
|
||||
exit(0);
|
||||
}
|
||||
check_restart_or_exit(trx);
|
||||
} else if (oml_state == 1) {
|
||||
fprintf(stderr, "Set the primary OML IP.\n");
|
||||
if (restart) {
|
||||
abis_nm_ipaccess_restart(bts);
|
||||
} else {
|
||||
exit(0);
|
||||
}
|
||||
check_restart_or_exit(trx);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -203,7 +203,7 @@ static int nm_sig_cb(unsigned int subsys, unsigned int signal,
|
||||
return ipacc_msg_nack(ipacc_data->msg_type);
|
||||
case S_NM_IPACC_ACK:
|
||||
ipacc_data = signal_data;
|
||||
return ipacc_msg_ack(ipacc_data->msg_type, ipacc_data->bts);
|
||||
return ipacc_msg_ack(ipacc_data->msg_type, ipacc_data->trx);
|
||||
case S_NM_TEST_REP:
|
||||
return test_rep(signal_data);
|
||||
case S_NM_IPACC_RESTART_ACK:
|
||||
@@ -228,12 +228,12 @@ static int swload_cbfn(unsigned int hook, unsigned int event, struct msgb *_msg,
|
||||
void *data, void *param)
|
||||
{
|
||||
struct msgb *msg;
|
||||
struct gsm_bts *bts;
|
||||
struct gsm_bts_trx *trx;
|
||||
|
||||
if (hook != GSM_HOOK_NM_SWLOAD)
|
||||
return 0;
|
||||
|
||||
bts = (struct gsm_bts *) data;
|
||||
trx = (struct gsm_bts_trx *) data;
|
||||
|
||||
switch (event) {
|
||||
case NM_MT_LOAD_INIT_ACK:
|
||||
@@ -272,7 +272,7 @@ static int swload_cbfn(unsigned int hook, unsigned int event, struct msgb *_msg,
|
||||
msg->l2h[1] = msgb_l3len(msg) >> 8;
|
||||
msg->l2h[2] = msgb_l3len(msg) & 0xff;
|
||||
printf("Foo l2h: %p l3h: %p... length l2: %u l3: %u\n", msg->l2h, msg->l3h, msgb_l2len(msg), msgb_l3len(msg));
|
||||
abis_nm_ipaccess_set_nvattr(bts->c0, msg->l2h, msgb_l2len(msg));
|
||||
abis_nm_ipaccess_set_nvattr(trx, msg->l2h, msgb_l2len(msg));
|
||||
msgb_free(msg);
|
||||
break;
|
||||
case NM_MT_LOAD_END_NACK:
|
||||
@@ -286,7 +286,7 @@ static int swload_cbfn(unsigned int hook, unsigned int event, struct msgb *_msg,
|
||||
case NM_MT_ACTIVATE_SW_ACK:
|
||||
break;
|
||||
case NM_MT_LOAD_SEG_ACK:
|
||||
percent = abis_nm_software_load_status(bts);
|
||||
percent = abis_nm_software_load_status(trx->bts);
|
||||
if (percent > percent_old)
|
||||
printf("Software Download Progress: %d%%\n", percent);
|
||||
percent_old = percent;
|
||||
@@ -299,13 +299,13 @@ static int swload_cbfn(unsigned int hook, unsigned int event, struct msgb *_msg,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bootstrap_om(struct gsm_bts *bts)
|
||||
static void bootstrap_om(struct gsm_bts_trx *trx)
|
||||
{
|
||||
int len;
|
||||
static u_int8_t buf[1024];
|
||||
u_int8_t *cur = buf;
|
||||
|
||||
printf("OML link established\n");
|
||||
printf("OML link established using TRX %d\n", trx->nr);
|
||||
|
||||
if (unit_id) {
|
||||
len = strlen(unit_id);
|
||||
@@ -317,8 +317,7 @@ static void bootstrap_om(struct gsm_bts *bts)
|
||||
memcpy(buf+3, unit_id, len);
|
||||
buf[3+len] = 0;
|
||||
printf("setting Unit ID to '%s'\n", unit_id);
|
||||
abis_nm_ipaccess_set_nvattr(gsm_bts_trx_by_nr(bts, trx_nr),
|
||||
buf, 3+len+1);
|
||||
abis_nm_ipaccess_set_nvattr(trx, buf, 3+len+1);
|
||||
}
|
||||
if (prim_oml_ip) {
|
||||
struct in_addr ia;
|
||||
@@ -342,7 +341,7 @@ static void bootstrap_om(struct gsm_bts *bts)
|
||||
*cur++ = 0;
|
||||
printf("setting primary OML link IP to '%s'\n", inet_ntoa(ia));
|
||||
oml_state = 1;
|
||||
abis_nm_ipaccess_set_nvattr(bts->c0, buf, 3+len);
|
||||
abis_nm_ipaccess_set_nvattr(trx, buf, 3+len);
|
||||
}
|
||||
if (nv_mask) {
|
||||
len = 4;
|
||||
@@ -356,13 +355,12 @@ static void bootstrap_om(struct gsm_bts *bts)
|
||||
*cur++ = nv_mask >> 8;
|
||||
printf("setting NV Flags/Mask to 0x%04x/0x%04x\n",
|
||||
nv_flags, nv_mask);
|
||||
abis_nm_ipaccess_set_nvattr(gsm_bts_trx_by_nr(bts, trx_nr),
|
||||
buf, 3+len);
|
||||
abis_nm_ipaccess_set_nvattr(trx, buf, 3+len);
|
||||
}
|
||||
|
||||
if (restart && !prim_oml_ip && !software) {
|
||||
printf("restarting BTS\n");
|
||||
abis_nm_ipaccess_restart(bts);
|
||||
abis_nm_ipaccess_restart(trx);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -373,7 +371,6 @@ void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx)
|
||||
case EVT_E1_TEI_UP:
|
||||
switch (type) {
|
||||
case E1INP_SIGN_OML:
|
||||
bootstrap_om(trx->bts);
|
||||
break;
|
||||
case E1INP_SIGN_RSL:
|
||||
/* FIXME */
|
||||
@@ -392,22 +389,29 @@ void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx)
|
||||
}
|
||||
|
||||
int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
|
||||
struct gsm_nm_state *old_state, struct gsm_nm_state *new_state)
|
||||
struct gsm_nm_state *old_state, struct gsm_nm_state *new_state,
|
||||
struct abis_om_obj_inst *obj_inst)
|
||||
{
|
||||
if (evt == EVT_STATECHG_OPER &&
|
||||
if (obj_class == NM_OC_BASEB_TRANSC) {
|
||||
if (!found_trx && obj_inst->trx_nr != 0xff) {
|
||||
struct gsm_bts_trx *trx = container_of(obj, struct gsm_bts_trx, bb_transc);
|
||||
bootstrap_om(trx);
|
||||
found_trx = 1;
|
||||
}
|
||||
} else if (evt == EVT_STATECHG_OPER &&
|
||||
obj_class == NM_OC_RADIO_CARRIER &&
|
||||
new_state->availability == 3) {
|
||||
struct gsm_bts_trx *trx = obj;
|
||||
|
||||
if (net_listen_testnr) {
|
||||
u_int8_t phys_config[] = { 0x02, 0x0a, 0x00, 0x01, 0x02 };
|
||||
abis_nm_perform_test(trx->bts, 2, 0, 0, 0xff,
|
||||
abis_nm_perform_test(trx->bts, 2, 0, trx->nr, 0xff,
|
||||
net_listen_testnr, 1,
|
||||
phys_config, sizeof(phys_config));
|
||||
} else if (software) {
|
||||
int rc;
|
||||
printf("Attempting software upload with '%s'\n", software);
|
||||
rc = abis_nm_software_load(trx->bts, software, 19, 0, swload_cbfn, trx->bts);
|
||||
rc = abis_nm_software_load(trx->bts, trx->nr, software, 19, 0, swload_cbfn, trx);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "Failed to start software load\n");
|
||||
exit(-3);
|
||||
@@ -608,7 +612,6 @@ static void print_help(void)
|
||||
printf(" -d --software firmware\n");
|
||||
printf(" -f --firmware firmware Provide firmware information\n");
|
||||
printf(" -w --write-firmware. This will dump the firmware parts to the filesystem. Use with -f.\n");
|
||||
printf(" -t --trx NR. The TRX to use for the Unit ID and NVRAM attributes.\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
@@ -643,11 +646,10 @@ int main(int argc, char **argv)
|
||||
{ "software", 1, 0, 'd' },
|
||||
{ "firmware", 1, 0, 'f' },
|
||||
{ "write-firmware", 0, 0, 'w' },
|
||||
{ "trx", 1, 0, 't' },
|
||||
{ 0, 0, 0, 0 },
|
||||
};
|
||||
|
||||
c = getopt_long(argc, argv, "u:o:rn:l:hs:d:f:wt:", long_options,
|
||||
c = getopt_long(argc, argv, "u:o:rn:l:hs:d:f:w", long_options,
|
||||
&option_index);
|
||||
|
||||
if (c == -1)
|
||||
@@ -689,9 +691,6 @@ int main(int argc, char **argv)
|
||||
case 'w':
|
||||
dump_files = 1;
|
||||
break;
|
||||
case 't':
|
||||
trx_nr = atoi(optarg);
|
||||
break;
|
||||
case 'h':
|
||||
print_usage();
|
||||
print_help();
|
||||
|
||||
@@ -135,7 +135,7 @@ static struct msgb *mgcp_msgb_alloc(void)
|
||||
struct msgb *msg;
|
||||
msg = msgb_alloc_headroom(4096, 128, "MGCP msg");
|
||||
if (!msg)
|
||||
LOGP(DMGCP, LOGL_ERROR, "Failed to msgb for MGCP data.\n");
|
||||
LOGP(DMGCP, LOGL_ERROR, "Failed to msgb for MGCP data.\n");
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
@@ -50,12 +50,15 @@
|
||||
|
||||
#include <sccp/sccp.h>
|
||||
|
||||
#define SCCP_CLOSE_TIME 20
|
||||
#define SCCP_CLOSE_TIME_TIMEOUT 19
|
||||
|
||||
struct log_target *stderr_target;
|
||||
static const char *config_file = "bsc-nat.cfg";
|
||||
static struct in_addr local_addr;
|
||||
static struct bsc_msc_connection *msc_con;
|
||||
static struct bsc_fd bsc_listen;
|
||||
static const char *msc_ip = NULL;
|
||||
static struct timer_list sccp_close;
|
||||
|
||||
|
||||
static struct bsc_nat *nat;
|
||||
@@ -77,7 +80,8 @@ struct bsc_config *bsc_config_num(struct bsc_nat *nat, int num)
|
||||
* below are stubs we need to link
|
||||
*/
|
||||
int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
|
||||
struct gsm_nm_state *old_state, struct gsm_nm_state *new_state)
|
||||
struct gsm_nm_state *old_state, struct gsm_nm_state *new_state,
|
||||
struct abis_om_obj_inst *obj_ins)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
@@ -92,7 +96,7 @@ int gsm0408_rcvmsg(struct msgb *msg, u_int8_t link_id)
|
||||
|
||||
static void queue_for_msc(struct bsc_msc_connection *con, struct msgb *msg)
|
||||
{
|
||||
if (write_queue_enqueue(&msc_con->write_queue, msg) != 0) {
|
||||
if (write_queue_enqueue(&nat->msc_con->write_queue, msg) != 0) {
|
||||
LOGP(DINP, LOGL_ERROR, "Failed to enqueue the write.\n");
|
||||
msgb_free(msg);
|
||||
}
|
||||
@@ -207,7 +211,7 @@ static void nat_send_rlsd(struct sccp_connections *conn)
|
||||
|
||||
ipaccess_prepend_header(msg, IPAC_PROTO_SCCP);
|
||||
|
||||
queue_for_msc(msc_con, msg);
|
||||
queue_for_msc(nat->msc_con, msg);
|
||||
}
|
||||
|
||||
static void nat_send_rlc(struct sccp_source_reference *src,
|
||||
@@ -230,7 +234,7 @@ static void nat_send_rlc(struct sccp_source_reference *src,
|
||||
|
||||
ipaccess_prepend_header(msg, IPAC_PROTO_SCCP);
|
||||
|
||||
queue_for_msc(msc_con, msg);
|
||||
queue_for_msc(nat->msc_con, msg);
|
||||
}
|
||||
|
||||
static void send_mgcp_reset(struct bsc_connection *bsc)
|
||||
@@ -253,7 +257,7 @@ static void initialize_msc_if_needed()
|
||||
return;
|
||||
|
||||
nat->first_contact = 1;
|
||||
msc_send_reset(msc_con);
|
||||
msc_send_reset(nat->msc_con);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -423,7 +427,7 @@ static void msc_send_reset(struct bsc_msc_connection *msc_con)
|
||||
msg->l2h = msgb_put(msg, sizeof(reset));
|
||||
memcpy(msg->l2h, reset, msgb_l2len(msg));
|
||||
|
||||
queue_for_msc(msc_con, msg);
|
||||
queue_for_msc(nat->msc_con, msg);
|
||||
|
||||
LOGP(DMSC, LOGL_NOTICE, "Scheduled GSM0808 reset msg for the MSC.\n");
|
||||
}
|
||||
@@ -440,7 +444,7 @@ static int ipaccess_msc_read_cb(struct bsc_fd *bfd)
|
||||
else
|
||||
LOGP(DNAT, LOGL_ERROR, "Failed to parse ip access message: %d\n", error);
|
||||
|
||||
bsc_msc_lost(msc_con);
|
||||
bsc_msc_lost(nat->msc_con);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -627,7 +631,7 @@ static int forward_sccp_to_msc(struct bsc_connection *bsc, struct msgb *msg)
|
||||
}
|
||||
|
||||
/* send the non-filtered but maybe modified msg */
|
||||
queue_for_msc(msc_con, msg);
|
||||
queue_for_msc(nat->msc_con, msg);
|
||||
talloc_free(parsed);
|
||||
return 0;
|
||||
|
||||
@@ -736,14 +740,14 @@ static int ipaccess_listen_bsc_cb(struct bsc_fd *bfd, unsigned int what)
|
||||
/*
|
||||
* if we are not connected to a msc... just close the socket
|
||||
*/
|
||||
if (!msc_con->is_connected) {
|
||||
if (!nat->msc_con->is_connected) {
|
||||
LOGP(DNAT, LOGL_NOTICE, "Disconnecting BSC due lack of MSC connection.\n");
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
on = 1;
|
||||
rc = setsockopt(bfd->fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
|
||||
rc = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
|
||||
if (rc != 0)
|
||||
LOGP(DNAT, LOGL_ERROR, "Failed to set TCP_NODELAY: %s\n", strerror(errno));
|
||||
|
||||
@@ -905,6 +909,29 @@ static void signal_handler(int signal)
|
||||
}
|
||||
}
|
||||
|
||||
static void sccp_close_unconfirmed(void *_data)
|
||||
{
|
||||
struct sccp_connections *conn, *tmp1;
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
|
||||
llist_for_each_entry_safe(conn, tmp1, &nat->sccp_connections, list_entry) {
|
||||
if (conn->has_remote_ref)
|
||||
continue;
|
||||
|
||||
int diff = (now.tv_sec - conn->creation_time.tv_sec) / 60;
|
||||
if (diff < SCCP_CLOSE_TIME_TIMEOUT)
|
||||
continue;
|
||||
|
||||
LOGP(DNAT, LOGL_ERROR, "SCCP connection 0x%x/0x%x was never confirmed.\n",
|
||||
sccp_src_ref_to_int(&conn->real_ref),
|
||||
sccp_src_ref_to_int(&conn->patched_ref));
|
||||
sccp_connection_destroy(conn);
|
||||
}
|
||||
|
||||
bsc_schedule_timer(&sccp_close, SCCP_CLOSE_TIME, 0);
|
||||
}
|
||||
|
||||
extern void *tall_msgb_ctx;
|
||||
extern void *tall_ctr_ctx;
|
||||
static void talloc_init_ctx()
|
||||
@@ -961,16 +988,16 @@ int main(int argc, char** argv)
|
||||
return -4;
|
||||
|
||||
/* connect to the MSC */
|
||||
msc_con = bsc_msc_create(nat->msc_ip, nat->msc_port);
|
||||
if (!msc_con) {
|
||||
nat->msc_con = bsc_msc_create(nat->msc_ip, nat->msc_port);
|
||||
if (!nat->msc_con) {
|
||||
fprintf(stderr, "Creating a bsc_msc_connection failed.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
msc_con->connection_loss = msc_connection_was_lost;
|
||||
msc_con->write_queue.read_cb = ipaccess_msc_read_cb;
|
||||
msc_con->write_queue.write_cb = ipaccess_msc_write_cb;;
|
||||
bsc_msc_connect(msc_con);
|
||||
nat->msc_con->connection_loss = msc_connection_was_lost;
|
||||
nat->msc_con->write_queue.read_cb = ipaccess_msc_read_cb;
|
||||
nat->msc_con->write_queue.write_cb = ipaccess_msc_write_cb;;
|
||||
bsc_msc_connect(nat->msc_con);
|
||||
|
||||
/* wait for the BSC */
|
||||
if (listen_for_bsc(&bsc_listen, &local_addr, 5000) < 0) {
|
||||
@@ -982,6 +1009,11 @@ int main(int argc, char** argv)
|
||||
signal(SIGUSR1, &signal_handler);
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
/* recycle timer */
|
||||
sccp_close.cb = sccp_close_unconfirmed;
|
||||
sccp_close.data = NULL;
|
||||
bsc_schedule_timer(&sccp_close, SCCP_CLOSE_TIME, 0);
|
||||
|
||||
while (1) {
|
||||
bsc_select_main(0);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <vty/vty.h>
|
||||
|
||||
#include <openbsc/bsc_nat.h>
|
||||
#include <openbsc/bsc_msc.h>
|
||||
#include <openbsc/gsm_04_08.h>
|
||||
#include <openbsc/mgcp.h>
|
||||
#include <openbsc/vty.h>
|
||||
@@ -181,6 +182,22 @@ DEFUN(show_stats,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(show_msc,
|
||||
show_msc_cmd,
|
||||
"show msc connection",
|
||||
SHOW_STR "Show the status of the MSC connection.")
|
||||
{
|
||||
if (!_nat->msc_con) {
|
||||
vty_out(vty, "The MSC is not yet configured.\n");
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
vty_out(vty, "MSC on %s:%d is connected: %d%s\n",
|
||||
_nat->msc_con->ip, _nat->msc_con->port,
|
||||
_nat->msc_con->is_connected, VTY_NEWLINE);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(close_bsc,
|
||||
close_bsc_cmd,
|
||||
"close bsc connection BSC_NR",
|
||||
@@ -406,6 +423,7 @@ int bsc_nat_vty_init(struct bsc_nat *nat)
|
||||
install_element(VIEW_NODE, &show_bsc_cfg_cmd);
|
||||
install_element(VIEW_NODE, &show_stats_cmd);
|
||||
install_element(VIEW_NODE, &close_bsc_cmd);
|
||||
install_element(VIEW_NODE, &show_msc_cmd);
|
||||
|
||||
openbsc_vty_add_cmds();
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <osmocore/talloc.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
static int equal(struct sccp_source_reference *ref1, struct sccp_source_reference *ref2)
|
||||
{
|
||||
@@ -97,10 +98,12 @@ int create_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc
|
||||
if (assign_src_local_reference(&conn->patched_ref, bsc->nat) != 0) {
|
||||
LOGP(DNAT, LOGL_ERROR, "BSC %d reused src ref: %d and we failed to generate a new id.\n",
|
||||
bsc->cfg->nr, sccp_src_ref_to_int(parsed->src_local_ref));
|
||||
bsc_mgcp_dlcx(conn);
|
||||
llist_del(&conn->list_entry);
|
||||
talloc_free(conn);
|
||||
return -1;
|
||||
} else {
|
||||
clock_gettime(CLOCK_MONOTONIC, &conn->creation_time);
|
||||
bsc_mgcp_dlcx(conn);
|
||||
return 0;
|
||||
}
|
||||
@@ -114,6 +117,7 @@ int create_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc
|
||||
}
|
||||
|
||||
conn->bsc = bsc;
|
||||
clock_gettime(CLOCK_MONOTONIC, &conn->creation_time);
|
||||
conn->real_ref = *parsed->src_local_ref;
|
||||
if (assign_src_local_reference(&conn->patched_ref, bsc->nat) != 0) {
|
||||
LOGP(DNAT, LOGL_ERROR, "Failed to assign a ref.\n");
|
||||
|
||||
@@ -359,6 +359,8 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
|
||||
bts->rach_ldavg_slots, VTY_NEWLINE);
|
||||
if (bts->si_common.rach_control.cell_bar)
|
||||
vty_out(vty, " cell barred 1%s", VTY_NEWLINE);
|
||||
if ((bts->si_common.rach_control.t2 & 0x4) == 0)
|
||||
vty_out(vty, " rach emergency call allowed 1%s", VTY_NEWLINE);
|
||||
if (is_ipaccess_bts(bts)) {
|
||||
vty_out(vty, " ip.access unit_id %u %u%s",
|
||||
bts->ip_access.site_id, bts->ip_access.bts_id, VTY_NEWLINE);
|
||||
@@ -1661,6 +1663,20 @@ DEFUN(cfg_bts_cell_barred, cfg_bts_cell_barred_cmd,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_rach_ec_allowed, cfg_bts_rach_ec_allowed_cmd,
|
||||
"rach emergency call allowed (0|1)",
|
||||
"Should this cell allow emergency calls?")
|
||||
{
|
||||
struct gsm_bts *bts = vty->index;
|
||||
|
||||
if (atoi(argv[0]) == 0)
|
||||
bts->si_common.rach_control.t2 |= 0x4;
|
||||
else
|
||||
bts->si_common.rach_control.t2 &= ~0x4;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_ms_max_power, cfg_bts_ms_max_power_cmd,
|
||||
"ms max power <0-40>",
|
||||
"Maximum transmit power of the MS")
|
||||
@@ -2111,6 +2127,7 @@ int bsc_vty_init(struct gsm_network *net)
|
||||
install_element(BTS_NODE, &cfg_bts_rach_nm_b_thresh_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_rach_nm_ldavg_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_cell_barred_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_rach_ec_allowed_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_ms_max_power_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_per_loc_upd_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_cell_resel_hyst_cmd);
|
||||
|
||||
@@ -13,5 +13,5 @@ bsc_nat_test_SOURCES = bsc_nat_test.c \
|
||||
$(top_srcdir)/src/mgcp/mgcp_protocol.c \
|
||||
$(top_srcdir)/src/mgcp/mgcp_network.c \
|
||||
$(top_srcdir)/src/bssap.c
|
||||
bsc_nat_test_LDADD = $(top_builddir)/src/libbsc.a $(top_builddir)/src/libsccp.a $(LIBOSMOCORE_LIBS)
|
||||
bsc_nat_test_LDADD = $(top_builddir)/src/libbsc.a $(top_builddir)/src/libsccp.a $(LIBOSMOCORE_LIBS) -lrt
|
||||
|
||||
|
||||
Reference in New Issue
Block a user