From 97a282b037408438a876af81e2e9c5194c2bb69e Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 14 Mar 2010 15:37:43 +0800 Subject: Create new gprs-conf branch with the non-SGSN part of the gprs branch This new gprs-conf branch is intended to contain everything needed to configure GPRS in the nanoBTS, but without implementing the SGSN/GGSN functionality. The SGSN/GGSN development will happen in a branch based on this branch called "gprs-sgsn" --- openbsc/include/openbsc/abis_nm.h | 1 + openbsc/include/openbsc/gsm_data.h | 13 ++++ openbsc/src/abis_nm.c | 22 +++---- openbsc/src/bsc_init.c | 131 ++++++++++++++++++++++++++++++++++++- openbsc/src/gsm_data.c | 46 +++++++++++++ openbsc/src/rest_octets.c | 2 +- openbsc/src/system_information.c | 32 +++++++-- openbsc/src/vty_interface.c | 45 ++++++++++++- 8 files changed, 270 insertions(+), 22 deletions(-) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/abis_nm.h b/openbsc/include/openbsc/abis_nm.h index cff91e0a0..45307e3c8 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 db3eaff59..1c18c55d9 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 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_init.c b/openbsc/src/bsc_init.c index 57fc4b3e1..3fc818447 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -20,6 +20,8 @@ * */ +#define GPRS + #include #include #include @@ -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 a951821fe..5314d1212 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -25,6 +25,8 @@ #include #include +#include + #include #include #include @@ -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 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..7015b3806 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 dc70e980b..c789a154e 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); -- cgit v1.2.3