aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src
diff options
context:
space:
mode:
Diffstat (limited to 'openbsc/src')
-rw-r--r--openbsc/src/Makefile.am4
-rw-r--r--openbsc/src/abis_nm.c22
-rw-r--r--openbsc/src/bsc_hack.c22
-rw-r--r--openbsc/src/bsc_init.c153
-rw-r--r--openbsc/src/bsc_version.c32
-rw-r--r--openbsc/src/debug.c2
-rw-r--r--openbsc/src/gsm_data.c46
-rw-r--r--openbsc/src/input/ipaccess.c48
-rw-r--r--openbsc/src/ipaccess/ipaccess-config.c94
-rw-r--r--openbsc/src/ipaccess/ipaccess-firmware.c39
-rw-r--r--openbsc/src/mgcp/mgcp_main.c23
-rw-r--r--openbsc/src/rest_octets.c2
-rw-r--r--openbsc/src/system_information.c20
-rw-r--r--openbsc/src/telnet_interface.c15
-rw-r--r--openbsc/src/vty/cardshell.h5
-rw-r--r--openbsc/src/vty_interface.c166
16 files changed, 602 insertions, 91 deletions
diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am
index 2c695993d..b920d0b65 100644
--- a/openbsc/src/Makefile.am
+++ b/openbsc/src/Makefile.am
@@ -1,4 +1,4 @@
-INCLUDES = $(all_includes) -I$(top_srcdir)/include
+INCLUDES = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS)
AM_LDFLAGS = $(LIBOSMOCORE_LIBS)
@@ -18,7 +18,7 @@ libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \
input/misdn.c input/ipaccess.c \
talloc_ctx.c system_information.c rest_octets.c \
rtp_proxy.c bts_siemens_bs11.c bts_ipaccess_nanobts.c \
- bts_unknown.c telnet_interface.c meas_rep.c
+ bts_unknown.c telnet_interface.c meas_rep.c bsc_version.c
libmsc_a_SOURCES = gsm_subscriber.c db.c \
mncc.c gsm_04_08.c gsm_04_11.c transaction.c \
diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c
index 99d8dd621..1e5e1c87c 100644
--- a/openbsc/src/abis_nm.c
+++ b/openbsc/src/abis_nm.c
@@ -856,28 +856,20 @@ static int abis_nm_rx_sw_act_req(struct msgb *mb)
const u_int8_t *sw_config;
int sw_config_len;
int file_id_len;
- int nack = 0;
int ret;
debugp_foh(foh);
DEBUGPC(DNM, "SW Activate Request: ");
- if (foh->obj_class >= 0xf0 && foh->obj_class <= 0xf3) {
- DEBUGPC(DNM, "NACKing for GPRS obj_class 0x%02x\n", foh->obj_class);
- nack = 1;
- } else
- DEBUGPC(DNM, "ACKing and Activating\n");
+ DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
foh->obj_inst.bts_nr,
foh->obj_inst.trx_nr,
- foh->obj_inst.ts_nr, nack,
+ foh->obj_inst.ts_nr, 0,
foh->data, oh->length-sizeof(*foh));
- if (nack)
- return ret;
-
abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
@@ -2881,6 +2873,14 @@ int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class,
attr, attr_len);
}
+void abis_nm_ipaccess_cgi(u_int8_t *buf, struct gsm_bts *bts)
+{
+ /* we simply reuse the GSM48 function and overwrite the RAC
+ * with the Cell ID */
+ gsm48_ra_id_by_bts(buf, bts);
+ *((u_int16_t *)(buf + 5)) = htons(bts->cell_identity);
+}
+
void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
{
int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
@@ -3000,5 +3000,3 @@ int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf)
return 0;
}
-
-
diff --git a/openbsc/src/bsc_hack.c b/openbsc/src/bsc_hack.c
index 49c9d36ef..f18f7f835 100644
--- a/openbsc/src/bsc_hack.c
+++ b/openbsc/src/bsc_hack.c
@@ -42,7 +42,8 @@ static struct debug_target *stderr_target;
struct gsm_network *bsc_gsmnet = 0;
static const char *database_name = "hlr.sqlite3";
static const char *config_file = "openbsc.cfg";
-
+extern const char *openbsc_version;
+extern const char *openbsc_copyright;
/* timer to store statistics */
#define DB_SYNC_INTERVAL 60, 0
@@ -83,6 +84,16 @@ static void print_help()
printf(" -P --rtp-proxy Enable the RTP Proxy code inside OpenBSC\n");
}
+static void print_version()
+{
+ printf("%s\n", openbsc_version);
+}
+
+static void print_copyright()
+{
+ puts(openbsc_copyright);
+}
+
static void handle_options(int argc, char** argv)
{
while (1) {
@@ -96,11 +107,12 @@ static void handle_options(int argc, char** argv)
{"authorize-everyone", 0, 0, 'a'},
{"pcap", 1, 0, 'p'},
{"timestamp", 0, 0, 'T'},
+ {"version", 0, 0, 'V' },
{"rtp-proxy", 0, 0, 'P'},
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, "hd:sl:ar:p:TPc:",
+ c = getopt_long(argc, argv, "hd:sl:ar:p:TPVc:",
long_options, &option_index);
if (c == -1)
break;
@@ -131,6 +143,12 @@ static void handle_options(int argc, char** argv)
case 'P':
ipacc_rtp_direct = 0;
break;
+ case 'V':
+ print_version();
+ printf("\n");
+ print_copyright();
+ exit(0);
+ break;
default:
/* ignore */
break;
diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c
index ecf0f03cd..5ef22db40 100644
--- a/openbsc/src/bsc_init.c
+++ b/openbsc/src/bsc_init.c
@@ -330,6 +330,7 @@ static unsigned char nanobts_attr_bts[] = {
NM_ATT_NY1, 10, /* 10 retransmissions of physical config */
NM_ATT_BCCH_ARFCN, HARDCODED_ARFCN >> 8, HARDCODED_ARFCN & 0xff,
NM_ATT_BSIC, HARDCODED_BSIC,
+ NM_ATT_IPACC_CGI, 0, 7, 0x00, 0xf1, 0x10, 0x00, 0x01, 0x00, 0x00,
};
static unsigned char nanobts_attr_radio[] = {
@@ -337,6 +338,66 @@ static unsigned char nanobts_attr_radio[] = {
NM_ATT_ARFCN_LIST, 0x00, 0x02, HARDCODED_ARFCN >> 8, HARDCODED_ARFCN & 0xff,
};
+static unsigned char nanobts_attr_nse[] = {
+ NM_ATT_IPACC_NSEI, 0, 2, 0x03, 0x9d, /* NSEI 925 */
+ NM_ATT_IPACC_NS_CFG, 0, 7, 3, /* (un)blocking timer (Tns-block) */
+ 3, /* (un)blocking retries */
+ 3, /* reset timer (Tns-reset) */
+ 3, /* reset retries */
+ 30, /* test timer (Tns-test) */
+ 3, /* alive timer (Tns-alive) */
+ 10, /* alive retrires */
+ NM_ATT_IPACC_BSSGP_CFG, 0, 11,
+ 3, /* blockimg timer (T1) */
+ 3, /* blocking retries */
+ 3, /* unblocking retries */
+ 3, /* reset timer */
+ 3, /* reset retries */
+ 10, /* suspend timer (T3) in 100ms */
+ 3, /* suspend retries */
+ 10, /* resume timer (T4) in 100ms */
+ 3, /* resume retries */
+ 10, /* capability update timer (T5) */
+ 3, /* capability update retries */
+};
+
+static unsigned char nanobts_attr_cell[] = {
+ NM_ATT_IPACC_RAC, 0, 1, 1, /* routing area code */
+ NM_ATT_IPACC_GPRS_PAGING_CFG, 0, 2,
+ 5, /* repeat time (50ms) */
+ 3, /* repeat count */
+ NM_ATT_IPACC_BVCI, 0, 2, 0x03, 0x9d, /* BVCI 925 */
+ NM_ATT_IPACC_RLC_CFG, 0, 9,
+ 20, /* T3142 */
+ 5, /* T3169 */
+ 5, /* T3191 */
+ 200, /* T3193 */
+ 5, /* T3195 */
+ 10, /* N3101 */
+ 4, /* N3103 */
+ 8, /* N3105 */
+ 15, /* RLC CV countdown */
+ NM_ATT_IPACC_CODING_SCHEMES, 0, 2, 0x0f, 0x00,
+ NM_ATT_IPACC_RLC_CFG_2, 0, 5,
+ 0x00, 250,
+ 0x00, 250,
+ 2, /* MCS2 */
+#if 0
+ /* EDGE model only, breaks older models.
+ * Should inquire the BTS capabilities */
+ NM_ATT_IPACC_RLC_CFG_3, 0, 1,
+ 2, /* MCS2 */
+#endif
+};
+
+static unsigned char nanobts_attr_nsvc0[] = {
+ NM_ATT_IPACC_NSVCI, 0, 2, 0x03, 0x9d, /* 925 */
+ NM_ATT_IPACC_NS_LINK_CFG, 0, 8,
+ 0x59, 0xd8, /* remote udp port (23000) */
+ 192, 168, 100, 11, /* remote ip address */
+ 0x59, 0xd8, /* local udp port (23000) */
+};
+
/* 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)
@@ -344,6 +405,7 @@ int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
struct gsm_bts *bts;
struct gsm_bts_trx *trx;
struct gsm_bts_trx_ts *ts;
+ struct gsm_bts_gprs_nsvc *nsvc;
/* This event-driven BTS setup is currently only required on nanoBTS */
@@ -399,6 +461,53 @@ int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
abis_nm_opstart(trx->bts, obj_class, trx->bts->bts_nr,
trx->nr, 0xff);
break;
+ case NM_OC_GPRS_NSE:
+ bts = container_of(obj, struct gsm_bts, gprs.nse);
+ if (!bts->gprs.enabled)
+ break;
+ if (new_state->availability == 5) {
+ abis_nm_ipaccess_set_attr(bts, obj_class, bts->bts_nr,
+ 0xff, 0xff, nanobts_attr_nse,
+ sizeof(nanobts_attr_nse));
+ abis_nm_opstart(bts, obj_class, bts->bts_nr,
+ 0xff, 0xff);
+ abis_nm_chg_adm_state(bts, obj_class, bts->bts_nr,
+ 0xff, 0xff, NM_STATE_UNLOCKED);
+ }
+ break;
+ case NM_OC_GPRS_CELL:
+ bts = container_of(obj, struct gsm_bts, gprs.cell);
+ if (!bts->gprs.enabled)
+ break;
+ if (new_state->availability == 5) {
+ abis_nm_ipaccess_set_attr(bts, obj_class, bts->bts_nr,
+ 0, 0xff, nanobts_attr_cell,
+ sizeof(nanobts_attr_cell));
+ abis_nm_opstart(bts, obj_class, bts->bts_nr,
+ 0, 0xff);
+ abis_nm_chg_adm_state(bts, obj_class, bts->bts_nr,
+ 0, 0xff, NM_STATE_UNLOCKED);
+ }
+ break;
+ case NM_OC_GPRS_NSVC:
+ nsvc = obj;
+ bts = nsvc->bts;
+ if (!bts->gprs.enabled)
+ break;
+ /* We skip NSVC1 since we only use NSVC0 */
+ if (nsvc->id == 1)
+ break;
+ if (new_state->availability == NM_AVSTATE_OFF_LINE) {
+ abis_nm_ipaccess_set_attr(bts, obj_class, bts->bts_nr,
+ nsvc->id, 0xff,
+ nanobts_attr_nsvc0,
+ sizeof(nanobts_attr_nsvc0));
+ abis_nm_opstart(bts, obj_class, bts->bts_nr,
+ nsvc->id, 0xff);
+ abis_nm_chg_adm_state(bts, obj_class, bts->bts_nr,
+ nsvc->id, 0xff,
+ NM_STATE_UNLOCKED);
+ }
default:
break;
}
@@ -691,14 +800,14 @@ static int set_system_infos(struct gsm_bts_trx *trx)
DEBUGP(DRR, "SI%2u: %s\n", i, hexdump(si_tmp, rc));
rsl_bcch_info(trx, i, si_tmp, sizeof(si_tmp));
}
-#ifdef GPRS
- i = 13;
- rc = gsm_generate_si(si_tmp, trx->bts, RSL_SYSTEM_INFO_13);
- if (rc < 0)
- goto err_out;
- DEBUGP(DRR, "SI%2u: %s\n", i, hexdump(si_tmp, rc));
- rsl_bcch_info(trx, RSL_SYSTEM_INFO_13, si_tmp, rc);
-#endif
+ if (bts->gprs.enabled) {
+ i = 13;
+ rc = gsm_generate_si(si_tmp, trx->bts, RSL_SYSTEM_INFO_13);
+ if (rc < 0)
+ goto err_out;
+ DEBUGP(DRR, "SI%2u: %s\n", i, hexdump(si_tmp, rc));
+ rsl_bcch_info(trx, RSL_SYSTEM_INFO_13, si_tmp, rc);
+ }
}
i = 5;
@@ -747,11 +856,37 @@ static void patch_nm_tables(struct gsm_bts *bts)
/* patch BSIC */
bs11_attr_bts[1] = bts->bsic;
- nanobts_attr_bts[sizeof(nanobts_attr_bts)-1] = bts->bsic;
+ nanobts_attr_bts[sizeof(nanobts_attr_bts)-11] = bts->bsic;
+
+ /* patch CGI */
+ abis_nm_ipaccess_cgi(nanobts_attr_bts+sizeof(nanobts_attr_bts)-7, bts);
/* patch the power reduction */
bs11_attr_radio[5] = bts->c0->max_power_red / 2;
nanobts_attr_radio[1] = bts->c0->max_power_red / 2;
+
+ /* patch NSEI */
+ nanobts_attr_nse[3] = bts->gprs.nse.nsei >> 8;
+ nanobts_attr_nse[4] = bts->gprs.nse.nsei & 0xff;
+
+ /* patch NSVCI */
+ nanobts_attr_nsvc0[3] = bts->gprs.nsvc[0].nsvci >> 8;
+ nanobts_attr_nsvc0[4] = bts->gprs.nsvc[0].nsvci & 0xff;
+
+ /* patch IP address as SGSN IP */
+ *(u_int16_t *)(nanobts_attr_nsvc0+8) =
+ htons(bts->gprs.nsvc[0].remote_port);
+ *(u_int32_t *)(nanobts_attr_nsvc0+10) =
+ htonl(bts->gprs.nsvc[0].remote_ip);
+ *(u_int16_t *)(nanobts_attr_nsvc0+14) =
+ htons(bts->gprs.nsvc[0].local_port);
+
+ /* patch BVCI */
+ nanobts_attr_cell[12] = bts->gprs.cell.bvci >> 8;
+ nanobts_attr_cell[13] = bts->gprs.cell.bvci & 0xff;
+ /* patch RAC */
+ nanobts_attr_cell[3] = bts->gprs.rac;
+
}
static void bootstrap_rsl(struct gsm_bts_trx *trx)
diff --git a/openbsc/src/bsc_version.c b/openbsc/src/bsc_version.c
new file mode 100644
index 000000000..02661940e
--- /dev/null
+++ b/openbsc/src/bsc_version.c
@@ -0,0 +1,32 @@
+/* Hold the copyright and version string */
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include "bscconfig.h"
+
+const char *openbsc_version = "OpenBSC " PACKAGE_VERSION;
+const char *openbsc_copyright =
+ "Copyright (C) 2008-2010 Harald Welte, Holger Freyther\n"
+ "Contributions by Daniel Willmann, Jan Lübbe,Stefan Schmidt\n"
+ "Dieter Spaar, Andreas Eversberg\n\n"
+ "License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>\n"
+ "This is free software: you are free to change and redistribute it.\n"
+ "There is NO WARRANTY, to the extent permitted by law.\n";
+
+
diff --git a/openbsc/src/debug.c b/openbsc/src/debug.c
index dabd14f43..cff59ca36 100644
--- a/openbsc/src/debug.c
+++ b/openbsc/src/debug.c
@@ -99,7 +99,7 @@ static const struct debug_info debug_info[] = {
DEBUG_CATEGORY(DHO, "DHO", "", "")
DEBUG_CATEGORY(DNAT, "DNAT", "", "")
DEBUG_CATEGORY(DDB, "DDB", "", "")
- DEBUG_CATEGORY(DDB, "DREF", "", "")
+ DEBUG_CATEGORY(DREF, "DREF", "", "")
};
static const struct value_string loglevel_strs[] = {
diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c
index bd331911e..c4d0431a3 100644
--- a/openbsc/src/gsm_data.c
+++ b/openbsc/src/gsm_data.c
@@ -25,6 +25,8 @@
#include <errno.h>
#include <ctype.h>
+#include <netinet/in.h>
+
#include <openbsc/gsm_data.h>
#include <osmocore/talloc.h>
#include <osmocore/gsm_utils.h>
@@ -463,6 +465,50 @@ const char *gsm_auth_policy_name(enum gsm_auth_policy policy)
return gsm_auth_policy_names[policy];
}
+/* this should not be here but in gsm_04_08... but that creates
+ in turn a dependency nightmare (abis_nm depending on 04_08, ...) */
+static int gsm48_construct_ra(u_int8_t *buf, const struct gprs_ra_id *raid)
+{
+ u_int16_t mcc = raid->mcc;
+ u_int16_t mnc = raid->mnc;
+
+ buf[0] = ((mcc / 100) % 10) | (((mcc / 10) % 10) << 4);
+ buf[1] = (mcc % 10);
+
+ /* I wonder who came up with the stupidity of encoding the MNC
+ * differently depending on how many digits its decimal number has! */
+ if (mnc < 100) {
+ buf[1] |= 0xf0;
+ buf[2] = ((mnc / 10) % 10) | ((mnc % 10) << 4);
+ } else {
+ buf[1] |= (mnc % 10) << 4;
+ buf[2] = ((mnc / 100) % 10) | (((mcc / 10) % 10) << 4);
+ }
+
+ *(u_int16_t *)(buf+3) = htons(raid->lac);
+
+ buf[5] = raid->rac;
+
+ return 6;
+}
+
+void gprs_ra_id_by_bts(struct gprs_ra_id *raid, struct gsm_bts *bts)
+{
+ raid->mcc = bts->network->country_code;
+ raid->mnc = bts->network->network_code;
+ raid->lac = bts->location_area_code;
+ raid->rac = bts->gprs.rac;
+}
+
+int gsm48_ra_id_by_bts(u_int8_t *buf, struct gsm_bts *bts)
+{
+ struct gprs_ra_id raid;
+
+ gprs_ra_id_by_bts(&raid, bts);
+
+ return gsm48_construct_ra(buf, &raid);
+}
+
static const char *rrlp_mode_names[] = {
[RRLP_MODE_NONE] = "none",
[RRLP_MODE_MS_BASED] = "ms-based",
diff --git a/openbsc/src/input/ipaccess.c b/openbsc/src/input/ipaccess.c
index 943a5e88d..3e266894b 100644
--- a/openbsc/src/input/ipaccess.c
+++ b/openbsc/src/input/ipaccess.c
@@ -44,6 +44,9 @@
#include <openbsc/ipaccess.h>
#include <osmocore/talloc.h>
+#define PRIV_OML 1
+#define PRIV_RSL 2
+
/* data structure for one E1 interface with A-bis */
struct ia_e1_handle {
struct bsc_fd listen_fd;
@@ -230,26 +233,33 @@ static int ipaccess_rcvmsg(struct e1inp_line *line, struct msgb *msg,
return -EIO;
}
DEBUGP(DINP, "Identified BTS %u/%u/%u\n", site_id, bts_id, trx_id);
- if (bfd->priv_nr == 1) {
- bts->oml_link = e1inp_sign_link_create(&line->ts[1-1],
+ if (bfd->priv_nr == PRIV_OML) {
+ bts->oml_link = e1inp_sign_link_create(&line->ts[PRIV_OML - 1],
E1INP_SIGN_OML, bts->c0,
bts->oml_tei, 0);
- } else if (bfd->priv_nr == 2) {
+ } else if (bfd->priv_nr == PRIV_RSL) {
struct e1inp_ts *e1i_ts;
struct bsc_fd *newbfd;
struct gsm_bts_trx *trx = gsm_bts_trx_num(bts, trx_id);
bfd->data = line = bts->oml_link->ts->line;
- e1i_ts = &line->ts[2+trx_id - 1];
+ e1i_ts = &line->ts[PRIV_RSL + trx_id - 1];
newbfd = &e1i_ts->driver.ipaccess.fd;
e1inp_ts_config(e1i_ts, line, E1INP_TS_TYPE_SIGN);
trx->rsl_link = e1inp_sign_link_create(e1i_ts,
E1INP_SIGN_RSL, trx,
trx->rsl_tei, 0);
+
+ if (newbfd->fd >= 0) {
+ LOGP(DINP, LOGL_ERROR, "BTS is still registered. Closing old connection.\n");
+ bsc_unregister_fd(newbfd);
+ close(newbfd->fd);
+ }
+
/* get rid of our old temporary bfd */
memcpy(newbfd, bfd, sizeof(*newbfd));
- newbfd->priv_nr = 2+trx_id;
+ newbfd->priv_nr = PRIV_RSL + trx_id;
bsc_unregister_fd(bfd);
bsc_register_fd(newbfd);
talloc_free(bfd);
@@ -279,14 +289,14 @@ struct msgb *ipaccess_read_msg(struct bsc_fd *bfd, int *error)
/* first read our 3-byte header */
hh = (struct ipaccess_head *) msg->data;
- ret = recv(bfd->fd, msg->data, 3, 0);
- if (ret < 0) {
- if (errno != EAGAIN)
- LOGP(DINP, LOGL_ERROR, "recv error %d %s\n", ret, strerror(errno));
+ ret = recv(bfd->fd, msg->data, sizeof(*hh), 0);
+ if (ret == 0) {
msgb_free(msg);
*error = ret;
return NULL;
- } else if (ret == 0) {
+ } else if (ret != sizeof(*hh)) {
+ if (errno != EAGAIN)
+ LOGP(DINP, LOGL_ERROR, "recv error %d %s\n", ret, strerror(errno));
msgb_free(msg);
*error = ret;
return NULL;
@@ -297,9 +307,17 @@ struct msgb *ipaccess_read_msg(struct bsc_fd *bfd, int *error)
/* then read te length as specified in header */
msg->l2h = msg->data + sizeof(*hh);
len = ntohs(hh->len);
+
+ if (len < 0 || TS1_ALLOC_SIZE < len + sizeof(*hh)) {
+ LOGP(DINP, LOGL_ERROR, "Can not read this packet. %d avail\n", len);
+ msgb_free(msg);
+ *error = -EIO;
+ return NULL;
+ }
+
ret = recv(bfd->fd, msg->l2h, len, 0);
if (ret < len) {
- LOGP(DINP, LOGL_ERROR, "short read!\n");
+ LOGP(DINP, LOGL_ERROR, "short read! Got %d from %d\n", ret, len);
msgb_free(msg);
*error = -EIO;
return NULL;
@@ -456,7 +474,7 @@ static int handle_ts1_write(struct bsc_fd *bfd)
/* set tx delay timer for next event */
e1i_ts->sign.tx_timer.cb = timeout_ts1_write;
e1i_ts->sign.tx_timer.data = e1i_ts;
- bsc_schedule_timer(&e1i_ts->sign.tx_timer, 0, 100000);
+ bsc_schedule_timer(&e1i_ts->sign.tx_timer, 0, 100);
return ret;
}
@@ -529,7 +547,7 @@ static int listen_fd_cb(struct bsc_fd *listen_bfd, unsigned int what)
bfd = &e1i_ts->driver.ipaccess.fd;
bfd->fd = ret;
bfd->data = line;
- bfd->priv_nr = 1;
+ bfd->priv_nr = PRIV_OML;
bfd->cb = ipaccess_fd_cb;
bfd->when = BSC_FD_READ;
ret = bsc_register_fd(bfd);
@@ -571,7 +589,7 @@ static int rsl_listen_fd_cb(struct bsc_fd *listen_bfd, unsigned int what)
return bfd->fd;
}
LOGP(DINP, LOGL_NOTICE, "accept()ed new RSL link from %s\n", inet_ntoa(sa.sin_addr));
- bfd->priv_nr = 2;
+ bfd->priv_nr = PRIV_RSL;
bfd->cb = ipaccess_fd_cb;
bfd->when = BSC_FD_READ;
ret = bsc_register_fd(bfd);
@@ -645,7 +663,7 @@ int ipaccess_connect(struct e1inp_line *line, struct sockaddr_in *sa)
bfd->cb = ipaccess_fd_cb;
bfd->when = BSC_FD_READ | BSC_FD_WRITE;
bfd->data = line;
- bfd->priv_nr = 1;
+ bfd->priv_nr = PRIV_OML;
if (bfd->fd < 0) {
LOGP(DINP, LOGL_ERROR, "could not create TCP socket.\n");
diff --git a/openbsc/src/ipaccess/ipaccess-config.c b/openbsc/src/ipaccess/ipaccess-config.c
index 037ed6000..870950d0e 100644
--- a/openbsc/src/ipaccess/ipaccess-config.c
+++ b/openbsc/src/ipaccess/ipaccess-config.c
@@ -57,6 +57,8 @@ static u_int16_t nv_mask;
static char *software = NULL;
static int sw_load_state = 0;
static int oml_state = 0;
+static int dump_files = 0;
+static char *firmware_analysis = NULL;
struct sw_load {
u_int8_t file_id[255];
@@ -427,7 +429,7 @@ static struct sw_load *create_swload(struct sdp_header *header)
return load;
}
-static void find_sw_load_params(const char *filename)
+static int find_sw_load_params(const char *filename)
{
struct stat stat;
struct sdp_header *header;
@@ -441,19 +443,19 @@ static void find_sw_load_params(const char *filename)
fd = open(filename, O_RDONLY);
if (!fd) {
perror("nada");
- return;
+ return -1;
}
/* verify the file */
if (fstat(fd, &stat) == -1) {
perror("Can not stat the file");
- return;
+ return -1;
}
ipaccess_analyze_file(fd, stat.st_size, 0, entry);
if (close(fd) != 0) {
perror("Close failed.\n");
- return;
+ return -1;
}
/* try to find what we are looking for */
@@ -465,7 +467,57 @@ static void find_sw_load_params(const char *filename)
}
}
+ if (!sw_load1 || !sw_load2) {
+ fprintf(stderr, "Did not find data.\n");
+ talloc_free(tall_firm_ctx);
+ return -1;
+ }
+
talloc_free(tall_firm_ctx);
+ return 0;
+}
+
+static void dump_entry(struct sdp_header_item *sub_entry, int part, int fd)
+{
+ int out_fd;
+ int copied;
+ char filename[4096];
+ off_t target;
+
+ if (!dump_files)
+ return;
+
+ if (sub_entry->header_entry.something1 == 0)
+ return;
+
+ snprintf(filename, sizeof(filename), "part.%d", part++);
+ out_fd = open(filename, O_WRONLY | O_CREAT, 0660);
+ if (out_fd < 0) {
+ perror("Can not dump firmware");
+ return;
+ }
+
+ target = sub_entry->absolute_offset + ntohl(sub_entry->header_entry.start) + 4;
+ if (lseek(fd, target, SEEK_SET) != target) {
+ perror("seek failed");
+ close(out_fd);
+ return;
+ }
+
+ for (copied = 0; copied < ntohl(sub_entry->header_entry.length); ++copied) {
+ char c;
+ if (read(fd, &c, sizeof(c)) != sizeof(c)) {
+ perror("copy failed");
+ break;
+ }
+
+ if (write(out_fd, &c, sizeof(c)) != sizeof(c)) {
+ perror("write failed");
+ break;
+ }
+ }
+
+ close(out_fd);
}
static void analyze_firmware(const char *filename)
@@ -476,6 +528,7 @@ static void analyze_firmware(const char *filename)
struct llist_head *entry;
int fd;
void *tall_firm_ctx = 0;
+ int part = 0;
entry = talloc_zero(tall_firm_ctx, struct llist_head);
INIT_LLIST_HEAD(entry);
@@ -494,10 +547,6 @@ static void analyze_firmware(const char *filename)
}
ipaccess_analyze_file(fd, stat.st_size, 0, entry);
- if (close(fd) != 0) {
- perror("Close failed.\n");
- return;
- }
llist_for_each_entry(header, entry, entry) {
printf("Printing header information:\n");
@@ -523,11 +572,19 @@ static void analyze_firmware(const char *filename)
printf("\taddr1: 0x%x\n", ntohl(sub_entry->header_entry.addr1));
printf("\taddr2: 0x%x\n", ntohl(sub_entry->header_entry.addr2));
printf("\tstart: 0x%x\n", ntohl(sub_entry->header_entry.start));
+ printf("\tabs. offset: 0x%lx\n", sub_entry->absolute_offset);
printf("\n\n");
+
+ dump_entry(sub_entry, part++, fd);
}
printf("\n\n");
}
+ if (close(fd) != 0) {
+ perror("Close failed.\n");
+ return;
+ }
+
talloc_free(tall_firm_ctx);
}
@@ -547,6 +604,7 @@ static void print_help(void)
printf(" -s --stream-id ID\n");
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");
}
int main(int argc, char **argv)
@@ -580,9 +638,10 @@ int main(int argc, char **argv)
{ "stream-id", 1, 0, 's' },
{ "software", 1, 0, 'd' },
{ "firmware", 1, 0, 'f' },
+ { "write-firmware", 0, 0, 'w' },
};
- c = getopt_long(argc, argv, "u:o:rn:l:hs:d:f:", long_options,
+ c = getopt_long(argc, argv, "u:o:rn:l:hs:d:f:w", long_options,
&option_index);
if (c == -1)
@@ -615,11 +674,15 @@ int main(int argc, char **argv)
break;
case 'd':
software = strdup(optarg);
- find_sw_load_params(optarg);
+ if (find_sw_load_params(optarg) != 0)
+ exit(0);
break;
case 'f':
- analyze_firmware(optarg);
- exit(0);
+ firmware_analysis = optarg;
+ break;
+ case 'w':
+ dump_files = 1;
+ break;
case 'h':
print_usage();
print_help();
@@ -627,8 +690,13 @@ int main(int argc, char **argv)
}
};
+ if (firmware_analysis)
+ analyze_firmware(firmware_analysis);
+
if (optind >= argc) {
- fprintf(stderr, "you have to specify the IP address of the BTS. Use --help for more information\n");
+ /* only warn if we have not done anything else */
+ if (!firmware_analysis)
+ fprintf(stderr, "you have to specify the IP address of the BTS. Use --help for more information\n");
exit(2);
}
diff --git a/openbsc/src/ipaccess/ipaccess-firmware.c b/openbsc/src/ipaccess/ipaccess-firmware.c
index 8aba50978..bc40c1e47 100644
--- a/openbsc/src/ipaccess/ipaccess-firmware.c
+++ b/openbsc/src/ipaccess/ipaccess-firmware.c
@@ -31,7 +31,7 @@
#define PART_LENGTH 138
static_assert(sizeof(struct sdp_header_entry) == 138, right_entry);
-static_assert(sizeof(struct sdp_firmware) == 160, _right_header_length);
+static_assert(sizeof(struct sdp_firmware) == 158, _right_header_length);
/* more magic, the second "int" in the header */
static char more_magic[] = { 0x10, 0x02 };
@@ -42,6 +42,10 @@ int ipaccess_analyze_file(int fd, const unsigned int st_size, const unsigned int
struct sdp_header *header;
char buf[4096];
int rc, i;
+ u_int16_t table_size;
+ u_int16_t table_offset;
+ off_t table_start;
+
rc = read(fd, buf, sizeof(*firmware_header));
if (rc < 0) {
@@ -63,9 +67,6 @@ int ipaccess_analyze_file(int fd, const unsigned int st_size, const unsigned int
}
- if (!firmware_header)
- return -1;
-
if (ntohl(firmware_header->file_length) != st_size) {
fprintf(stderr, "The filesize and the header do not match.\n");
return -1;
@@ -77,20 +78,30 @@ int ipaccess_analyze_file(int fd, const unsigned int st_size, const unsigned int
INIT_LLIST_HEAD(&header->header_list);
llist_add(&header->entry, list);
- /* this semantic appears to be only the case for 0x0000 */
- if (firmware_header->more_more_magic != 0)
+ table_offset = ntohs(firmware_header->table_offset);
+ table_start = lseek(fd, table_offset, SEEK_CUR);
+ if (table_start == -1) {
+ fprintf(stderr, "Failed to seek to the rel position: 0x%x\n", table_offset);
+ return -1;
+ }
+
+ if (read(fd, &table_size, sizeof(table_size)) != sizeof(table_size)) {
+ fprintf(stderr, "The table size could not be read.\n");
return -1;
+ }
+
+ table_size = ntohs(table_size);
- if (ntohs(firmware_header->part_length) % PART_LENGTH != 0) {
- fprintf(stderr, "The part length seems to be wrong.\n");
+ if (table_size % PART_LENGTH != 0) {
+ fprintf(stderr, "The part length seems to be wrong: 0x%x\n", table_size);
return -1;
}
/* look into each firmware now */
- for (i = 0; i < ntohs(firmware_header->part_length) / PART_LENGTH; ++i) {
+ for (i = 0; i < table_size / PART_LENGTH; ++i) {
struct sdp_header_entry entry;
struct sdp_header_item *header_entry;
- unsigned int offset = base_offset + sizeof(struct sdp_firmware);
+ unsigned int offset = table_start + 2;
offset += i * 138;
if (lseek(fd, offset, SEEK_SET) != offset) {
@@ -104,6 +115,11 @@ int ipaccess_analyze_file(int fd, const unsigned int st_size, const unsigned int
return -1;
}
+ header_entry = talloc_zero(header, struct sdp_header_item);
+ header_entry->header_entry = entry;
+ header_entry->absolute_offset = base_offset;
+ llist_add(&header_entry->entry, &header->header_list);
+
/* now we need to find the SDP file... */
offset = ntohl(entry.start) + 4 + base_offset;
if (lseek(fd, offset, SEEK_SET) != offset) {
@@ -111,9 +127,6 @@ int ipaccess_analyze_file(int fd, const unsigned int st_size, const unsigned int
return -1;
}
- header_entry = talloc_zero(header, struct sdp_header_item);
- header_entry->header_entry = entry;
- llist_add(&header_entry->entry, &header->header_list);
ipaccess_analyze_file(fd, ntohl(entry.length), offset, list);
}
diff --git a/openbsc/src/mgcp/mgcp_main.c b/openbsc/src/mgcp/mgcp_main.c
index cea0ba427..e45a1e981 100644
--- a/openbsc/src/mgcp/mgcp_main.c
+++ b/openbsc/src/mgcp/mgcp_main.c
@@ -40,6 +40,8 @@
#include <openbsc/mgcp.h>
#include <openbsc/telnet_interface.h>
+#include "../../bscconfig.h"
+
/* this is here for the vty... it will never be called */
void subscr_put() { abort(); }
@@ -51,6 +53,14 @@ void subscr_put() { abort(); }
static struct bsc_fd bfd;
static int first_request = 1;
static struct mgcp_config *cfg;
+const char *openbsc_version = "OpenBSC MGCP " PACKAGE_VERSION;
+const char *openbsc_copyright =
+ "Copyright (C) 2009-2010 Holger Freyther and On-Waves\n"
+ "Contributions by Daniel Willmann, Jan Lübbe,Stefan Schmidt\n"
+ "Dieter Spaar, Andreas Eversberg, Harald Welte\n\n"
+ "License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>\n"
+ "This is free software: you are free to change and redistribute it.\n"
+ "There is NO WARRANTY, to the extent permitted by law.\n";
static char *config_file = "mgcp.cfg";
@@ -64,6 +74,12 @@ static void print_help()
printf(" -c --config-file filename The config file to use.\n");
}
+static void print_version()
+{
+ printf("%s\n\n", openbsc_version);
+ printf(openbsc_copyright);
+}
+
static void handle_options(int argc, char** argv)
{
while (1) {
@@ -71,10 +87,11 @@ static void handle_options(int argc, char** argv)
static struct option long_options[] = {
{"help", 0, 0, 'h'},
{"config-file", 1, 0, 'c'},
+ {"version", 0, 0, 'V'},
{0, 0, 0, 0},
};
- c = getopt_long(argc, argv, "hc:", long_options, &option_index);
+ c = getopt_long(argc, argv, "hc:V", long_options, &option_index);
if (c == -1)
break;
@@ -87,6 +104,10 @@ static void handle_options(int argc, char** argv)
case 'c':
config_file = talloc_strdup(tall_bsc_ctx, optarg);
break;
+ case 'V':
+ print_version();
+ exit(0);
+ break;
default:
/* ignore */
break;
diff --git a/openbsc/src/rest_octets.c b/openbsc/src/rest_octets.c
index a57e7dffe..16996cec2 100644
--- a/openbsc/src/rest_octets.c
+++ b/openbsc/src/rest_octets.c
@@ -350,7 +350,7 @@ int rest_octets_si13(u_int8_t *data, const struct gsm48_si13_info *si13)
bitvec_set_bit(&bv, H);
bitvec_set_uint(&bv, si13->bcch_change_mark, 3);
bitvec_set_uint(&bv, si13->si_change_field, 4);
- if (0) {
+ if (1) {
bitvec_set_bit(&bv, 0);
} else {
bitvec_set_bit(&bv, 1);
diff --git a/openbsc/src/system_information.c b/openbsc/src/system_information.c
index a9df0ba26..3f9d60954 100644
--- a/openbsc/src/system_information.c
+++ b/openbsc/src/system_information.c
@@ -249,7 +249,7 @@ static int generate_si2(u_int8_t *output, struct gsm_bts *bts)
return sizeof(*si2);
}
-struct gsm48_si_ro_info si_info = {
+static struct gsm48_si_ro_info si_info = {
.selection_params = {
.present = 0,
},
@@ -264,7 +264,7 @@ struct gsm48_si_ro_info si_info = {
.gprs_ind = {
.si13_position = 0,
.ra_colour = 0,
- .present = 0,
+ .present = 1,
},
.lsa_params = {
.present = 0,
@@ -398,9 +398,9 @@ static int generate_si6(u_int8_t *output, struct gsm_bts *bts)
static struct gsm48_si13_info si13_default = {
.cell_opts = {
.nmo = GPRS_NMO_III,
- .t3168 = 1000,
- .t3192 = 1000,
- .drx_timer_max = 1,
+ .t3168 = 1500,
+ .t3192 = 500,
+ .drx_timer_max = 3,
.bs_cv_max = 15,
},
.pwr_ctrl_pars = {
@@ -410,15 +410,15 @@ static struct gsm48_si13_info si13_default = {
.pc_meas_chan = 0, /* downling measured on CCCH */
.n_avg_i = 15,
},
- .bcch_change_mark = 0,
+ .bcch_change_mark = 1,
.si_change_field = 0,
.pbcch_present = 0,
{
.no_pbcch = {
- .rac = 0,
+ .rac = 0, /* needs to be patched */
.spgc_ccch_sup = 0,
.net_ctrl_ord = 0,
- .prio_acc_thr = 0,
+ .prio_acc_thr = 6,
},
},
};
@@ -435,6 +435,8 @@ static int generate_si13(u_int8_t *output, struct gsm_bts *bts)
si13->header.skip_indicator = 0;
si13->header.system_information = GSM48_MT_RR_SYSINFO_13;
+ si13_default.no_pbcch.rac = bts->gprs.rac;
+
ret = rest_octets_si13(si13->rest_octets, &si13_default);
if (ret < 0)
return ret;
@@ -446,6 +448,8 @@ static int generate_si13(u_int8_t *output, struct gsm_bts *bts)
int gsm_generate_si(u_int8_t *output, struct gsm_bts *bts, int type)
{
+ si_info.gprs_ind.present = bts->gprs.enabled;
+
switch (type) {
case RSL_SYSTEM_INFO_1:
return generate_si1(output, bts);
diff --git a/openbsc/src/telnet_interface.c b/openbsc/src/telnet_interface.c
index 805dd127d..aa119b464 100644
--- a/openbsc/src/telnet_interface.c
+++ b/openbsc/src/telnet_interface.c
@@ -98,21 +98,16 @@ void telnet_init(struct gsm_network *network, int port) {
bsc_register_fd(&server_socket);
}
+extern const char *openbsc_copyright;
+extern const char *openbsc_version;
+
static void print_welcome(int fd) {
int ret;
static char *msg =
- "Welcome to the OpenBSC Control interface\n"
- "Copyright (C) 2008-2010 Harald Welte\n"
- "Contributions by Daniel Willmann, Jan Lübbe, "
- "Stefan Schmidt, Holger Freyther, Andreas Eversberg\n\n"
- "License GPLv2+: GNU GPL version 2 or later "
- "<http://gnu.org/licenses/gpl.html>\n"
- "This is free software: you are free to change "
- "and redistribute it.\n"
- "There is NO WARRANTY, to the extent permitted "
- "by law.\nType \"help\" to get a short introduction.\n";
+ "Welcome to the OpenBSC Control interface\n";
ret = write(fd, msg, strlen(msg));
+ ret = write(fd, openbsc_copyright, strlen(openbsc_copyright));
}
int telnet_close_client(struct bsc_fd *fd) {
diff --git a/openbsc/src/vty/cardshell.h b/openbsc/src/vty/cardshell.h
index d963a3810..85164d2bd 100644
--- a/openbsc/src/vty/cardshell.h
+++ b/openbsc/src/vty/cardshell.h
@@ -1,5 +1,6 @@
-#define QUAGGA_PROGNAME "OpenBSC"
-#define QUAGGA_VERSION "0.01"
+#include "../../bscconfig.h"
+#define QUAGGA_PROGNAME PACKAGE_NAME
+#define QUAGGA_VERSION PACKAGE_VERSION
#define QUAGGA_COPYRIGHT "Harald Welte <laforge@gnumonks.org>"
#define CONFIGFILE_MASK 022
#define SYSCONFDIR "/usr/local/etc"
diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c
index c2488c3c4..09b95cac1 100644
--- a/openbsc/src/vty_interface.c
+++ b/openbsc/src/vty_interface.c
@@ -1,5 +1,5 @@
/* OpenBSC interface to quagga VTY */
-/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
+/* (C) 2009-2010 by Harald Welte <laforge@gnumonks.org>
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
@@ -285,6 +285,7 @@ static void config_write_trx_single(struct vty *vty, struct gsm_bts_trx *trx)
static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
{
struct gsm_bts_trx *trx;
+ int i;
vty_out(vty, " bts %u%s", bts->nr, VTY_NEWLINE);
vty_out(vty, " type %s%s", btstype2str(bts->type), VTY_NEWLINE);
@@ -320,6 +321,30 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
config_write_e1_link(vty, &bts->oml_e1_link, " oml ");
vty_out(vty, " oml e1 tei %u%s", bts->oml_tei, VTY_NEWLINE);
}
+ vty_out(vty, " gprs enabled %u%s", bts->gprs.enabled, VTY_NEWLINE);
+ if (bts->gprs.enabled) {
+ vty_out(vty, " gprs routing area %u%s", bts->gprs.rac,
+ VTY_NEWLINE);
+ vty_out(vty, " gprs cell bvci %u%s", bts->gprs.cell.bvci,
+ VTY_NEWLINE);
+ vty_out(vty, " gprs nsei %u%s", bts->gprs.nse.nsei,
+ VTY_NEWLINE);
+ for (i = 0; i < ARRAY_SIZE(bts->gprs.nsvc); i++) {
+ struct gsm_bts_gprs_nsvc *nsvc =
+ &bts->gprs.nsvc[i];
+ struct in_addr ia;
+
+ ia.s_addr = htonl(nsvc->remote_ip);
+ vty_out(vty, " gprs nsvc %u nsvci %u%s", i,
+ nsvc->nsvci, VTY_NEWLINE);
+ vty_out(vty, " gprs nsvc %u local udp port %u%s", i,
+ nsvc->local_port, VTY_NEWLINE);
+ vty_out(vty, " gprs nsvc %u remote udp port %u%s", i,
+ nsvc->remote_port, VTY_NEWLINE);
+ vty_out(vty, " gprs nsvc %u remote ip %s%s", i,
+ inet_ntoa(ia), VTY_NEWLINE);
+ }
+ }
llist_for_each_entry(trx, &bts->trx_list, list)
config_write_trx_single(vty, trx);
@@ -1752,6 +1777,136 @@ DEFUN(cfg_bts_per_loc_upd, cfg_bts_per_loc_upd_cmd,
return CMD_SUCCESS;
}
+DEFUN(cfg_bts_prs_bvci, cfg_bts_gprs_bvci_cmd,
+ "gprs cell bvci <0-65535>",
+ "GPRS BSSGP VC Identifier")
+{
+ struct gsm_bts *bts = vty->index;
+
+ if (!bts->gprs.enabled) {
+ vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ bts->gprs.cell.bvci = atoi(argv[0]);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bts_gprs_nsei, cfg_bts_gprs_nsei_cmd,
+ "gprs nsei <0-65535>",
+ "GPRS NS Entity Identifier")
+{
+ struct gsm_bts *bts = vty->index;
+
+ if (!bts->gprs.enabled) {
+ vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ bts->gprs.nse.nsei = atoi(argv[0]);
+
+ return CMD_SUCCESS;
+}
+
+
+DEFUN(cfg_bts_gprs_nsvci, cfg_bts_gprs_nsvci_cmd,
+ "gprs nsvc <0-1> nsvci <0-65535>",
+ "GPRS NS VC Identifier")
+{
+ struct gsm_bts *bts = vty->index;
+ int idx = atoi(argv[0]);
+
+ if (!bts->gprs.enabled) {
+ vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ bts->gprs.nsvc[idx].nsvci = atoi(argv[1]);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bts_gprs_nsvc_lport, cfg_bts_gprs_nsvc_lport_cmd,
+ "gprs nsvc <0-1> local udp port <0-65535>",
+ "GPRS NS Local UDP Port")
+{
+ struct gsm_bts *bts = vty->index;
+ int idx = atoi(argv[0]);
+
+ if (!bts->gprs.enabled) {
+ vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ bts->gprs.nsvc[idx].local_port = atoi(argv[1]);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bts_gprs_nsvc_rport, cfg_bts_gprs_nsvc_rport_cmd,
+ "gprs nsvc <0-1> remote udp port <0-65535>",
+ "GPRS NS Remote UDP Port")
+{
+ struct gsm_bts *bts = vty->index;
+ int idx = atoi(argv[0]);
+
+ if (!bts->gprs.enabled) {
+ vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ bts->gprs.nsvc[idx].remote_port = atoi(argv[1]);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bts_gprs_nsvc_rip, cfg_bts_gprs_nsvc_rip_cmd,
+ "gprs nsvc <0-1> remote ip A.B.C.D",
+ "GPRS NS Remote IP Address")
+{
+ struct gsm_bts *bts = vty->index;
+ int idx = atoi(argv[0]);
+ struct in_addr ia;
+
+ if (!bts->gprs.enabled) {
+ vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ inet_aton(argv[1], &ia);
+ bts->gprs.nsvc[idx].remote_ip = ntohl(ia.s_addr);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bts_gprs_rac, cfg_bts_gprs_rac_cmd,
+ "gprs routing area <0-255>",
+ "GPRS Routing Area Code")
+{
+ struct gsm_bts *bts = vty->index;
+
+ if (!bts->gprs.enabled) {
+ vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ bts->gprs.rac = atoi(argv[0]);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bts_gprs_enabled, cfg_bts_gprs_enabled_cmd,
+ "gprs enabled <0-1>",
+ "GPRS Enabled on this BTS")
+{
+ struct gsm_bts *bts = vty->index;
+
+ bts->gprs.enabled = atoi(argv[0]);
+
+ return CMD_SUCCESS;
+}
+
/* per TRX configuration */
DEFUN(cfg_trx,
@@ -2019,7 +2174,14 @@ int bsc_vty_init(struct gsm_network *net)
install_element(BTS_NODE, &cfg_bts_per_loc_upd_cmd);
install_element(BTS_NODE, &cfg_bts_cell_resel_hyst_cmd);
install_element(BTS_NODE, &cfg_bts_rxlev_acc_min_cmd);
-
+ install_element(BTS_NODE, &cfg_bts_gprs_enabled_cmd);
+ install_element(BTS_NODE, &cfg_bts_gprs_rac_cmd);
+ install_element(BTS_NODE, &cfg_bts_gprs_bvci_cmd);
+ install_element(BTS_NODE, &cfg_bts_gprs_nsei_cmd);
+ install_element(BTS_NODE, &cfg_bts_gprs_nsvci_cmd);
+ install_element(BTS_NODE, &cfg_bts_gprs_nsvc_lport_cmd);
+ install_element(BTS_NODE, &cfg_bts_gprs_nsvc_rport_cmd);
+ install_element(BTS_NODE, &cfg_bts_gprs_nsvc_rip_cmd);
install_element(BTS_NODE, &cfg_trx_cmd);
install_node(&trx_node, dummy_config_write);