aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--openbsc/include/openbsc/abis_nm.h1
-rw-r--r--openbsc/include/openbsc/gsm_data.h13
-rw-r--r--openbsc/src/abis_nm.c22
-rw-r--r--openbsc/src/bsc_init.c131
-rw-r--r--openbsc/src/gsm_data.c46
-rw-r--r--openbsc/src/rest_octets.c2
-rw-r--r--openbsc/src/system_information.c32
-rw-r--r--openbsc/src/vty_interface.c45
8 files changed, 270 insertions, 22 deletions
diff --git a/openbsc/include/openbsc/abis_nm.h b/openbsc/include/openbsc/abis_nm.h
index cff91e0a..45307e3c 100644
--- a/openbsc/include/openbsc/abis_nm.h
+++ b/openbsc/include/openbsc/abis_nm.h
@@ -154,6 +154,7 @@ int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class,
u_int8_t *attr, u_int8_t attr_len);
int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
u_int32_t ip, u_int16_t port, u_int8_t stream);
+void abis_nm_ipaccess_cgi(u_int8_t *buf, struct gsm_bts *bts);
int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf);
const char *ipacc_testres_name(u_int8_t res);
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index db3eaff5..1c18c55d 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -374,6 +374,7 @@ struct gsm_envabtse {
struct gsm_bts_gprs_nsvc {
struct gsm_bts *bts;
int id;
+ u_int16_t nsvci;
struct gsm_nm_state nm_state;
};
@@ -467,8 +468,10 @@ struct gsm_bts {
} nse;
struct {
struct gsm_nm_state nm_state;
+ u_int16_t bvci;
} cell;
struct gsm_bts_gprs_nsvc nsvc[2];
+ u_int8_t rac;
} gprs;
/* transceivers */
@@ -681,6 +684,16 @@ const char *rrlp_mode_name(enum rrlp_mode mode);
void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked);
+/* A parsed GPRS routing area */
+struct gprs_ra_id {
+ u_int16_t mnc;
+ u_int16_t mcc;
+ u_int16_t lac;
+ u_int8_t rac;
+};
+
+int gsm48_ra_id_by_bts(u_int8_t *buf, struct gsm_bts *bts);
+void gprs_ra_id_by_bts(struct gprs_ra_id *raid, struct gsm_bts *bts);
struct gsm_meas_rep *lchan_next_meas_rep(struct gsm_lchan *lchan);
int gsm_bts_model_register(struct gsm_bts_model *model);
diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c
index 99d8dd62..1e5e1c87 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_init.c b/openbsc/src/bsc_init.c
index 57fc4b3e..3fc81844 100644
--- a/openbsc/src/bsc_init.c
+++ b/openbsc/src/bsc_init.c
@@ -20,6 +20,8 @@
*
*/
+#define GPRS
+
#include <openbsc/gsm_data.h>
#include <osmocore/gsm_utils.h>
#include <openbsc/gsm_04_08.h>
@@ -330,6 +332,8 @@ 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,
+ /* FIXME: do not hardcode the CGI */
+ NM_ATT_IPACC_CGI, 0, 7, 0x00, 0xf1, 0x10, 0x00, 0x01, 0x00, 0x00,
};
static unsigned char nanobts_attr_radio[] = {
@@ -337,6 +341,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 +408,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 */
@@ -397,6 +462,49 @@ 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;
+#ifdef GPRS
+ case NM_OC_GPRS_NSE:
+ bts = container_of(obj, struct gsm_bts, gprs.nse);
+ 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 (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;
+ /* 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);
+ }
+#endif
default:
break;
}
@@ -713,6 +821,10 @@ static int set_system_infos(struct gsm_bts_trx *trx)
DEBUGP(DRR, "SI%2u: %s\n", i, hexdump(si_tmp, rc));
rsl_sacch_filling(trx, RSL_SYSTEM_INFO_6, si_tmp, rc);
+#ifdef GPRS
+ rsl_ipacc_pdch_activate(&trx->ts[7].lchan[0]);
+#endif
+
return 0;
err_out:
LOGP(DRR, LOGL_ERROR, "Cannot generate SI %u for BTS %u, most likely "
@@ -745,11 +857,28 @@ 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 NSVCI */
+ nanobts_attr_nsvc0[3] = bts->gprs.nsvc[0].nsvci >> 8;
+ nanobts_attr_nsvc0[4] = bts->gprs.nsvc[0].nsvci & 0xff;
+
+ /* FIXME: patch our own IP address as SGSN IP */
+ //nanobts_attr_nsvc0[10] =
+
+ /* 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/gsm_data.c b/openbsc/src/gsm_data.c
index a951821f..5314d121 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>
@@ -459,6 +461,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/rest_octets.c b/openbsc/src/rest_octets.c
index a57e7dff..16996cec 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 a9df0ba2..7015b380 100644
--- a/openbsc/src/system_information.c
+++ b/openbsc/src/system_information.c
@@ -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,19 +410,31 @@ 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,
},
},
};
+static u_int8_t si13_template[] = {
+ 0x09, 0x06, 0x00,
+#if 0
+ /* This is what our system_information branch geneates */
+ 0x2a, 0x01, 0x00, 0x04, 0x00, 0xd8, 0xa5, 0xef, 0xff, 0xf7,
+#else
+ /* This is what Dieter has sent me as hand-coded example */
+ 0x90, 0x00, 0x58, 0x98, 0x6f, 0xc9, 0x70, 0x4a, 0x84, 0x10,
+#endif
+ 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b,
+};
+
static int generate_si13(u_int8_t *output, struct gsm_bts *bts)
{
struct gsm48_system_information_type_13 *si13 =
@@ -435,12 +447,18 @@ 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;
si13->header.l2_plen = ret & 0xff;
+ printf("SI13 template : %s\n", hexdump(si13_template, GSM_MACBLOCK_LEN));
+ printf("SI13 generated: %s\n", hexdump(si13, GSM_MACBLOCK_LEN));
+ //memcpy(si13, si13_template, sizeof(si13_template));
+
return sizeof (*si13) + ret;
}
diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c
index dc70e980..c789a154 100644
--- a/openbsc/src/vty_interface.c
+++ b/openbsc/src/vty_interface.c
@@ -278,6 +278,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);
@@ -313,6 +314,12 @@ 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 routing area %u%s", bts->gprs.rac, VTY_NEWLINE);
+ vty_out(vty, " gprs cell bvci %u%s", bts->gprs.cell.bvci,
+ VTY_NEWLINE);
+ for (i = 0; i < ARRAY_SIZE(bts->gprs.nsvc); i++)
+ vty_out(vty, " gprs nsvc %u nsvci %u%s", i,
+ bts->gprs.cell.bvci, VTY_NEWLINE);
llist_for_each_entry(trx, &bts->trx_list, list)
config_write_trx_single(vty, trx);
@@ -1604,6 +1611,40 @@ DEFUN(cfg_bts_per_loc_upd, cfg_bts_per_loc_upd_cmd,
return CMD_SUCCESS;
}
+DEFUN(cfg_bts_gprs_bvci, cfg_bts_gprs_bvci_cmd,
+ "gprs cell bvci <0-65535>",
+ "GPRS BSSGP VC Identifier")
+{
+ struct gsm_bts *bts = vty->index;
+
+ bts->gprs.cell.bvci = 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]);
+
+ bts->gprs.nsvc[idx].nsvci = atoi(argv[1]);
+
+ 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;
+
+ bts->gprs.rac = atoi(argv[0]);
+
+ return CMD_SUCCESS;
+}
+
/* per TRX configuration */
DEFUN(cfg_trx,
@@ -1865,7 +1906,9 @@ 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_rac_cmd);
+ install_element(BTS_NODE, &cfg_bts_gprs_bvci_cmd);
+ install_element(BTS_NODE, &cfg_bts_gprs_nsvci_cmd);
install_element(BTS_NODE, &cfg_trx_cmd);
install_node(&trx_node, dummy_config_write);