diff --git a/openbsc/include/openbsc/gsm_04_08.h b/openbsc/include/openbsc/gsm_04_08.h index 3fbc35f08..b855aa577 100644 --- a/openbsc/include/openbsc/gsm_04_08.h +++ b/openbsc/include/openbsc/gsm_04_08.h @@ -63,5 +63,7 @@ int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg); struct msgb *gsm48_create_mm_serv_rej(enum gsm48_reject_value value); struct msgb *gsm48_create_loc_upd_rej(uint8_t cause); +void gsm48_lchan2chan_desc(struct gsm48_chan_desc *cd, + const struct gsm_lchan *lchan); #endif diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index a1e881a81..107434476 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -338,8 +338,11 @@ struct gsm_bts_trx_ts { u_int8_t nm_chan_comb; struct { + int enabled; u_int8_t maio; u_int8_t hsn; + struct bitvec arfcns; + u_int8_t arfcns_data[1024/8]; } hopping; /* To which E1 subslot are we connected */ diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index 8c6f5189a..31302f1fd 100644 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -1976,11 +1976,23 @@ int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb) NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr); msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb); - if (ts->hopping.hsn) { + if (ts->hopping.enabled) { + unsigned int i; + uint8_t *len; + msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn); msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio); - /* FIXME: compute ARFCN list */ - msgb_tlv16_put(msg, NM_ATT_ARFCN_LIST, 1, &arfcn); + + /* build the ARFCN list */ + msgb_put_u8(msg, NM_ATT_ARFCN_LIST); + len = msgb_put(msg, 1); + *len = 0; + for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) { + if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) { + msgb_put_u16(msg, i); + *len += sizeof(uint16_t); + } + } } msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */ if (bts->type == GSM_BTS_TYPE_BS11) diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 451c80db2..f38735480 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1195,15 +1195,16 @@ static int rsl_rx_chan_rqd(struct msgb *msg) ia.proto_discr = GSM48_PDISC_RR; ia.msg_type = GSM48_MT_RR_IMM_ASS; ia.page_mode = GSM48_PM_SAME; - ia.chan_desc.chan_nr = lchan2chan_nr(lchan); - ia.chan_desc.h0.h = 0; - ia.chan_desc.h0.arfcn_high = arfcn >> 8; - ia.chan_desc.h0.arfcn_low = arfcn & 0xff; - ia.chan_desc.h0.tsc = bts->tsc; + gsm48_lchan2chan_desc(&ia.chan_desc, lchan); + /* use request reference extracted from CHAN_RQD */ memcpy(&ia.req_ref, rqd_ref, sizeof(ia.req_ref)); ia.timing_advance = rqd_ta; - ia.mob_alloc_len = 0; + if (!lchan->ts->hopping.enabled) { + ia.mob_alloc_len = 0; + } else { + /* FIXME: Mobile Allocation in case of hopping */ + } DEBUGP(DRSL, "%s Activating ARFCN(%u) SS(%u) lctype %s " "r=%s ra=0x%02x\n", gsm_lchan_name(lchan), arfcn, subch, diff --git a/openbsc/src/bsc_vty.c b/openbsc/src/bsc_vty.c index 51db0b14c..5eacb22af 100644 --- a/openbsc/src/bsc_vty.c +++ b/openbsc/src/bsc_vty.c @@ -305,13 +305,21 @@ static void config_write_ts_single(struct vty *vty, struct gsm_bts_trx_ts *ts) if (ts->pchan != GSM_PCHAN_NONE) vty_out(vty, " phys_chan_config %s%s", gsm_pchan_name(ts->pchan), VTY_NEWLINE); - if (ts->hopping.hsn) { - vty_out(vty, " hopping sequence number %u%s", + vty_out(vty, " hopping enabled %u%s", + ts->hopping.enabled, VTY_NEWLINE); + if (ts->hopping.enabled) { + unsigned int i; + vty_out(vty, " hopping sequence-number %u%s", ts->hopping.hsn, VTY_NEWLINE); - vty_out(vty, " hopping maio %u%s", + vty_out(vty, " hopping maio %u%s", ts->hopping.maio, VTY_NEWLINE); - /* FIXME: ARFCN list */ - } + for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) { + if (!bitvec_get_bit_pos(&ts->hopping.arfcns, i)) + continue; + vty_out(vty, " hopping arfcn add %u%s", + i, VTY_NEWLINE); + } + } else config_write_e1_link(vty, &ts->e1_link, " "); } @@ -1984,9 +1992,25 @@ DEFUN(cfg_ts_pchan, return CMD_SUCCESS; } +#define HOPPING_STR "Configure frequency hopping\n" + +DEFUN(cfg_ts_hopping, + cfg_ts_hopping_cmd, + "hopping enabled (0|1)", + HOPPING_STR "Enable or disable frequency hopping\n" + "Disable frequency hopping\n" "Enable frequency hopping\n") +{ + struct gsm_bts_trx_ts *ts = vty->index; + + ts->hopping.enabled = atoi(argv[0]); + + return CMD_SUCCESS; +} + DEFUN(cfg_ts_hsn, cfg_ts_hsn_cmd, - "hopping sequence number <0-63>", + "hopping sequence-number <0-63>", + HOPPING_STR "Which hopping sequence to use for this channel") { struct gsm_bts_trx_ts *ts = vty->index; @@ -1999,6 +2023,7 @@ DEFUN(cfg_ts_hsn, DEFUN(cfg_ts_maio, cfg_ts_maio_cmd, "hopping maio <0-63>", + HOPPING_STR "Which hopping MAIO to use for this channel") { struct gsm_bts_trx_ts *ts = vty->index; @@ -2011,24 +2036,28 @@ DEFUN(cfg_ts_maio, DEFUN(cfg_ts_arfcn_add, cfg_ts_arfcn_add_cmd, "hopping arfcn add <0-1023>", - "Add an entry to the hopping ARFCN list") + HOPPING_STR "Configure hopping ARFCN list\n" + "Add an entry to the hopping ARFCN list\n" "ARFCN\n") { struct gsm_bts_trx_ts *ts = vty->index; int arfcn = atoi(argv[0]); - /* FIXME */ + bitvec_set_bit_pos(&ts->hopping.arfcns, arfcn, 1); + return CMD_SUCCESS; } DEFUN(cfg_ts_arfcn_del, cfg_ts_arfcn_del_cmd, "hopping arfcn del <0-1023>", - "Delete an entry to the hopping ARFCN list") + HOPPING_STR "Configure hopping ARFCN list\n" + "Delete an entry to the hopping ARFCN list\n" "ARFCN\n") { struct gsm_bts_trx_ts *ts = vty->index; int arfcn = atoi(argv[0]); - /* FIXME */ + bitvec_set_bit_pos(&ts->hopping.arfcns, arfcn, 0); + return CMD_SUCCESS; } @@ -2193,6 +2222,7 @@ int bsc_vty_init(void) install_element(TS_NODE, &ournode_exit_cmd); install_element(TS_NODE, &ournode_end_cmd); install_element(TS_NODE, &cfg_ts_pchan_cmd); + install_element(TS_NODE, &cfg_ts_hopping_cmd); install_element(TS_NODE, &cfg_ts_hsn_cmd); install_element(TS_NODE, &cfg_ts_maio_cmd); install_element(TS_NODE, &cfg_ts_arfcn_add_cmd); diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c index 3776565eb..f517020f5 100644 --- a/openbsc/src/gsm_04_08_utils.c +++ b/openbsc/src/gsm_04_08_utils.c @@ -312,16 +312,24 @@ static void gsm48_cell_desc(struct gsm48_cell_desc *cd, cd->arfcn_lo = bts->c0->arfcn & 0xff; } -static void gsm48_chan_desc(struct gsm48_chan_desc *cd, - const struct gsm_lchan *lchan) +void gsm48_lchan2chan_desc(struct gsm48_chan_desc *cd, + const struct gsm_lchan *lchan) { u_int16_t arfcn = lchan->ts->trx->arfcn & 0x3ff; cd->chan_nr = lchan2chan_nr(lchan); - cd->h0.tsc = lchan->ts->trx->bts->tsc; - cd->h0.h = 0; - cd->h0.arfcn_high = arfcn >> 8; - cd->h0.arfcn_low = arfcn & 0xff; + if (!lchan->ts->hopping.enabled) { + cd->h0.tsc = lchan->ts->trx->bts->tsc; + cd->h0.h = 0; + cd->h0.arfcn_high = arfcn >> 8; + cd->h0.arfcn_low = arfcn & 0xff; + } else { + cd->h1.tsc = lchan->ts->trx->bts->tsc; + cd->h1.h = 1; + cd->h1.maio_high = lchan->ts->hopping.maio >> 2; + cd->h1.maio_low = lchan->ts->hopping.maio & 0x03; + cd->h1.hsn = lchan->ts->hopping.hsn; + } } /* Chapter 9.1.15: Handover Command */ @@ -339,7 +347,7 @@ int gsm48_send_ho_cmd(struct gsm_lchan *old_lchan, struct gsm_lchan *new_lchan, /* mandatory bits */ gsm48_cell_desc(&ho->cell_desc, new_lchan->ts->trx->bts); - gsm48_chan_desc(&ho->chan_desc, new_lchan); + gsm48_lchan2chan_desc(&ho->chan_desc, new_lchan); ho->ho_ref = ho_ref; ho->power_command = power_command; @@ -370,7 +378,7 @@ int gsm48_send_rr_ass_cmd(struct gsm_lchan *dest_lchan, struct gsm_lchan *lchan, * the chan_desc. But as long as multi-slot configurations * are not used we seem to be fine. */ - gsm48_chan_desc(&ass->chan_desc, lchan); + gsm48_lchan2chan_desc(&ass->chan_desc, lchan); ass->power_command = power_command; msgb_tv_put(msg, GSM48_IE_CHANMODE_1, lchan->tch_mode); @@ -409,11 +417,7 @@ int gsm48_tx_chan_mode_modify(struct gsm_lchan *lchan, u_int8_t mode) /* fill the channel information element, this code * should probably be shared with rsl_rx_chan_rqd() */ - cmm->chan_desc.chan_nr = lchan2chan_nr(lchan); - cmm->chan_desc.h0.tsc = lchan->ts->trx->bts->tsc; - cmm->chan_desc.h0.h = 0; - cmm->chan_desc.h0.arfcn_high = arfcn >> 8; - cmm->chan_desc.h0.arfcn_low = arfcn & 0xff; + gsm48_lchan2chan_desc(&cmm->chan_desc, lchan); cmm->mode = mode; /* in case of multi rate we need to attach a config */ diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index 9de4c1f3c..ede1c003d 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -154,6 +154,9 @@ struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts) ts->nr = k; ts->pchan = GSM_PCHAN_NONE; + ts->hopping.arfcns.data_len = sizeof(ts->hopping.arfcns_data); + ts->hopping.arfcns.data = ts->hopping.arfcns_data; + for (l = 0; l < TS_MAX_LCHAN; l++) { struct gsm_lchan *lchan; lchan = &ts->lchan[l]; diff --git a/openbsc/src/system_information.c b/openbsc/src/system_information.c index 337f756ce..508787d40 100644 --- a/openbsc/src/system_information.c +++ b/openbsc/src/system_information.c @@ -177,9 +177,23 @@ static int generate_cell_chan_list(u_int8_t *chan_list, struct gsm_bts *bts) struct gsm_bts_trx *trx; struct bitvec *bv = &bts->si_common.cell_alloc; + /* Zero-initialize the bit-vector */ + memset(&bv->data, 0, bv->data_len); + /* first we generate a bitvec of all TRX ARFCN's in our BTS */ - llist_for_each_entry(trx, &bts->trx_list, list) + llist_for_each_entry(trx, &bts->trx_list, list) { + unsigned int i, j; + /* Always add the TRX's ARFCN */ bitvec_set_bit_pos(bv, trx->arfcn, 1); + for (i = 0; i < ARRAY_SIZE(trx->ts); i++) { + struct gsm_bts_trx_ts *ts = &trx->ts[i]; + /* Add any ARFCNs present in hopping channels */ + for (j = 0; j < 1024; j++) { + if (bitvec_get_bit_pos(&ts->hopping.arfcns, j)) + bitvec_set_bit_pos(bv, j, 1); + } + } + } /* then we generate a GSM 04.08 frequency list from the bitvec */ return bitvec2freq_list(chan_list, bv, bts); @@ -191,6 +205,9 @@ static int generate_bcch_chan_list(u_int8_t *chan_list, struct gsm_bts *bts) struct gsm_bts *cur_bts; struct bitvec *bv = &bts->si_common.neigh_list; + /* Zero-initialize the bit-vector */ + memset(&bv->data, 0, bv->data_len); + /* first we generate a bitvec of the BCCH ARFCN's in our BSC */ llist_for_each_entry(cur_bts, &bts->network->bts_list, list) { if (cur_bts == bts)