diff options
author | Holger Hans Peter Freyther <zecke@selfish.org> | 2010-03-24 10:28:43 +0100 |
---|---|---|
committer | Holger Hans Peter Freyther <zecke@selfish.org> | 2010-03-24 10:28:43 +0100 |
commit | b9c520f9b36fd97ae11c91f2bec394d684ac6749 (patch) | |
tree | e312d0d70579eafa9e1fdc9c9c3daaf5a21f03fe /openbsc/src | |
parent | 8a7ca57d3eec7376169661ea3cfcca4c3c2f33cf (diff) | |
parent | f99f0930fd02a5ef164c54fe8926a7e0b11acbdb (diff) |
Merge remote branch 'origin/master' into on-waves/bsc-master
Keep a static version as the shell script is not dealing well
with branch tags/names containing text.
Resolve merge conflict in the Makefile.am by adding both sides
to the list of sources for the libbsc.a
Conflicts:
openbsc/configure.in
openbsc/src/Makefile.am
Diffstat (limited to 'openbsc/src')
-rw-r--r-- | openbsc/src/Makefile.am | 4 | ||||
-rw-r--r-- | openbsc/src/abis_nm.c | 22 | ||||
-rw-r--r-- | openbsc/src/bsc_hack.c | 22 | ||||
-rw-r--r-- | openbsc/src/bsc_init.c | 153 | ||||
-rw-r--r-- | openbsc/src/bsc_version.c | 32 | ||||
-rw-r--r-- | openbsc/src/debug.c | 2 | ||||
-rw-r--r-- | openbsc/src/gsm_data.c | 46 | ||||
-rw-r--r-- | openbsc/src/input/ipaccess.c | 48 | ||||
-rw-r--r-- | openbsc/src/ipaccess/ipaccess-config.c | 94 | ||||
-rw-r--r-- | openbsc/src/ipaccess/ipaccess-firmware.c | 39 | ||||
-rw-r--r-- | openbsc/src/mgcp/mgcp_main.c | 23 | ||||
-rw-r--r-- | openbsc/src/rest_octets.c | 2 | ||||
-rw-r--r-- | openbsc/src/system_information.c | 20 | ||||
-rw-r--r-- | openbsc/src/telnet_interface.c | 15 | ||||
-rw-r--r-- | openbsc/src/vty/cardshell.h | 5 | ||||
-rw-r--r-- | openbsc/src/vty_interface.c | 166 |
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); |