diff options
Diffstat (limited to 'src/osmo-bsc/gsm_data.c')
-rw-r--r-- | src/osmo-bsc/gsm_data.c | 341 |
1 files changed, 210 insertions, 131 deletions
diff --git a/src/osmo-bsc/gsm_data.c b/src/osmo-bsc/gsm_data.c index 1152783ae..1562ea8b6 100644 --- a/src/osmo-bsc/gsm_data.c +++ b/src/osmo-bsc/gsm_data.c @@ -62,16 +62,13 @@ void set_ts_e1link(struct gsm_bts_trx_ts *ts, uint8_t e1_nr, struct gsm_bts *gsm_bts_by_lac(struct gsm_network *net, unsigned int lac, struct gsm_bts *start_bts) { - int i; struct gsm_bts *bts; int skip = 0; if (start_bts) skip = 1; - for (i = 0; i < net->num_bts; i++) { - bts = gsm_bts_num(net, i); - + llist_for_each_entry(bts, &net->bts_list, list) { if (skip) { if (start_bts == bts) skip = 0; @@ -110,19 +107,21 @@ struct gsm_bts *gsm_bts_alloc_register(struct gsm_network *net, enum gsm_bts_typ uint8_t bsic) { struct gsm_bts_model *model = bts_model_find(type); + struct gsm_bts_sm *bts_sm; struct gsm_bts *bts; if (!model && type != GSM_BTS_TYPE_UNKNOWN) return NULL; - bts = gsm_bts_alloc(net, net->num_bts); - if (!bts) + bts_sm = gsm_bts_sm_alloc(net, net->num_bts); + if (!bts_sm) return NULL; + bts = bts_sm->bts[0]; net->num_bts++; bts->type = type; - bts->model = model; + gsm_set_bts_model(bts, model); bts->bsic = bsic; llist_add_tail(&bts->list, &net->bts_list); @@ -153,6 +152,7 @@ void gsm_abis_mo_reset(struct gsm_abis_mo *mo) { mo->nm_state.operational = NM_OPSTATE_NULL; mo->nm_state.availability = NM_AVSTATE_POWER_OFF; + mo->nm_state.administrative = NM_STATE_LOCKED; } void gsm_mo_init(struct gsm_abis_mo *mo, struct gsm_bts *bts, @@ -169,7 +169,7 @@ void gsm_mo_init(struct gsm_abis_mo *mo, struct gsm_bts *bts, const struct value_string gsm_chreq_descs[] = { { GSM_CHREQ_REASON_EMERG, "emergency call" }, { GSM_CHREQ_REASON_PAG, "answer to paging" }, - { GSM_CHREQ_REASON_CALL, "call re-establishment" }, + { GSM_CHREQ_REASON_CALL, "call (re-)establishment" }, { GSM_CHREQ_REASON_LOCATION_UPD,"Location updating" }, { GSM_CHREQ_REASON_PDCH, "one phase packet access" }, { GSM_CHREQ_REASON_OTHER, "other" }, @@ -188,7 +188,7 @@ const struct value_string gsm_pchant_names[] = { { GSM_PCHAN_UNKNOWN, "UNKNOWN" }, { GSM_PCHAN_CCCH_SDCCH4_CBCH, "CCCH+SDCCH4+CBCH" }, { GSM_PCHAN_SDCCH8_SACCH8C_CBCH, "SDCCH8+CBCH" }, - { GSM_PCHAN_TCH_F_TCH_H_PDCH, "TCH/F_TCH/H_PDCH" }, + { GSM_PCHAN_OSMO_DYN, "TCH/F_TCH/H_SDCCH8_PDCH" }, { 0, NULL } }; @@ -204,7 +204,7 @@ const struct value_string gsm_pchan_ids[] = { { GSM_PCHAN_UNKNOWN, "UNKNOWN" }, { GSM_PCHAN_CCCH_SDCCH4_CBCH, "CCCH_SDCCH4_CBCH" }, { GSM_PCHAN_SDCCH8_SACCH8C_CBCH, "SDCCH8_CBCH" }, - { GSM_PCHAN_TCH_F_TCH_H_PDCH, "TCH_F_TCH_H_PDCH" }, + { GSM_PCHAN_OSMO_DYN, "OSMO_DYN" }, { 0, NULL } }; @@ -221,7 +221,7 @@ const struct value_string gsm_pchant_descs[13] = { { GSM_PCHAN_UNKNOWN, "Unknown / Unsupported channel combination" }, { GSM_PCHAN_CCCH_SDCCH4_CBCH, "FCCH + SCH + BCCH + CCCH + CBCH + 3 SDCCH + 2 SACCH (Comb. V)" }, { GSM_PCHAN_SDCCH8_SACCH8C_CBCH, "7 SDCCH + 4 SACCH + CBCH (Comb. VII)" }, - { GSM_PCHAN_TCH_F_TCH_H_PDCH, "Dynamic TCH/F or TCH/H or GPRS PDCH" }, + { GSM_PCHAN_OSMO_DYN, "Dynamic TCH/F or TCH/H or SDCCH/8 or GPRS PDCH" }, { 0, NULL } }; @@ -235,12 +235,6 @@ enum gsm_phys_chan_config gsm_pchan_parse(const char *name) return get_string_value(gsm_pchant_names, name); } -/* TODO: move to libosmocore, next to gsm_chan_t_names? */ -const char *gsm_lchant_name(enum gsm_chan_t c) -{ - return get_value_string(gsm_chan_t_names, c); -} - static const struct value_string chreq_names[] = { { GSM_CHREQ_REASON_EMERG, "EMERGENCY" }, { GSM_CHREQ_REASON_PAG, "PAGING" }, @@ -331,16 +325,6 @@ char *gsm_ts_and_pchan_name(const struct gsm_bts_trx_ts *ts) return ts2str; } -char *gsm_lchan_name_compute(const struct gsm_lchan *lchan) -{ - struct gsm_bts_trx_ts *ts = lchan->ts; - - snprintf(ts2str, sizeof(ts2str), "(bts=%d,trx=%d,ts=%d,ss=%d)", - ts->trx->bts->nr, ts->trx->nr, ts->nr, lchan->nr); - - return ts2str; -} - /* obtain the MO structure for a given object instance */ static inline struct gsm_abis_mo * gsm_objclass2mo(struct gsm_bts *bts, uint8_t obj_class, @@ -377,7 +361,7 @@ gsm_objclass2mo(struct gsm_bts *bts, uint8_t obj_class, mo = &trx->ts[obj_inst->ts_nr].mo; break; case NM_OC_SITE_MANAGER: - mo = &bts->site_mgr.mo; + mo = &bts->site_mgr->mo; break; case NM_OC_BS11: switch (obj_inst->bts_nr) { @@ -409,15 +393,15 @@ gsm_objclass2mo(struct gsm_bts *bts, uint8_t obj_class, mo = &bts->bs11.envabtse[obj_inst->trx_nr].mo; break; case NM_OC_GPRS_NSE: - mo = &bts->gprs.nse.mo; + mo = &bts->site_mgr->gprs.nse.mo; break; case NM_OC_GPRS_CELL: mo = &bts->gprs.cell.mo; break; case NM_OC_GPRS_NSVC: - if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc)) + if (obj_inst->trx_nr >= ARRAY_SIZE(bts->site_mgr->gprs.nsvc)) return NULL; - mo = &bts->gprs.nsvc[obj_inst->trx_nr].mo; + mo = &bts->site_mgr->gprs.nsvc[obj_inst->trx_nr].mo; break; } return mo; @@ -473,43 +457,53 @@ gsm_objclass2obj(struct gsm_bts *bts, uint8_t obj_class, obj = &trx->ts[obj_inst->ts_nr]; break; case NM_OC_SITE_MANAGER: - obj = &bts->site_mgr; + obj = bts->site_mgr; break; case NM_OC_GPRS_NSE: - obj = &bts->gprs.nse; + obj = &bts->site_mgr->gprs.nse; break; case NM_OC_GPRS_CELL: obj = &bts->gprs.cell; break; case NM_OC_GPRS_NSVC: - if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc)) + if (obj_inst->trx_nr >= ARRAY_SIZE(bts->site_mgr->gprs.nsvc)) return NULL; - obj = &bts->gprs.nsvc[obj_inst->trx_nr]; + obj = &bts->site_mgr->gprs.nsvc[obj_inst->trx_nr]; break; } return obj; } /* See Table 10.5.25 of GSM04.08 */ -uint8_t gsm_pchan2chan_nr(enum gsm_phys_chan_config pchan, - uint8_t ts_nr, uint8_t lchan_nr) +int gsm_pchan2chan_nr(enum gsm_phys_chan_config pchan, + uint8_t ts_nr, uint8_t lchan_nr, bool vamos_is_secondary) { uint8_t cbits, chan_nr; switch (pchan) { case GSM_PCHAN_TCH_F: case GSM_PCHAN_TCH_F_PDCH: - OSMO_ASSERT(lchan_nr == 0); - cbits = 0x01; + if (lchan_nr != 0) + return -EINVAL; + if (vamos_is_secondary) + cbits = ABIS_RSL_CHAN_NR_CBITS_OSMO_VAMOS_Bm_ACCHs; + else + cbits = 0x01; break; case GSM_PCHAN_PDCH: - OSMO_ASSERT(lchan_nr == 0); + if (lchan_nr != 0) + return -EINVAL; cbits = RSL_CHAN_OSMO_PDCH >> 3; break; case GSM_PCHAN_TCH_H: - OSMO_ASSERT(lchan_nr < 2); - cbits = 0x02; - cbits += lchan_nr; + if (lchan_nr >= 2) + return -EINVAL; + if (vamos_is_secondary) + cbits = ABIS_RSL_CHAN_NR_CBITS_OSMO_VAMOS_Lm_ACCHs(lchan_nr); + else { + cbits = 0x02; + cbits += lchan_nr; + } break; case GSM_PCHAN_CCCH_SDCCH4: case GSM_PCHAN_CCCH_SDCCH4_CBCH: @@ -520,20 +514,22 @@ uint8_t gsm_pchan2chan_nr(enum gsm_phys_chan_config pchan, */ if (lchan_nr == CCCH_LCHAN) chan_nr = 0; - else - OSMO_ASSERT(lchan_nr < 4); + else if (lchan_nr >= 4) + return -EINVAL; cbits = 0x04; cbits += lchan_nr; break; case GSM_PCHAN_SDCCH8_SACCH8C: case GSM_PCHAN_SDCCH8_SACCH8C_CBCH: - OSMO_ASSERT(lchan_nr < 8); + if (lchan_nr >= 8) + return -EINVAL; cbits = 0x08; cbits += lchan_nr; break; default: case GSM_PCHAN_CCCH: - OSMO_ASSERT(lchan_nr == 0); + if (lchan_nr != 0) + return -EINVAL; cbits = 0x10; break; } @@ -543,11 +539,43 @@ uint8_t gsm_pchan2chan_nr(enum gsm_phys_chan_config pchan, return chan_nr; } -uint8_t gsm_lchan2chan_nr(const struct gsm_lchan *lchan) +/* For RSL, to talk to osmo-bts, we introduce Osmocom specific channel number cbits to indicate VAMOS secondary lchans. + * However, in RR, which is sent to the MS, these special cbits must not be sent, but their "normal" equivalent; for RR + * messages, pass allow_osmo_cbits = false. */ +int gsm_lchan_and_pchan2chan_nr(const struct gsm_lchan *lchan, enum gsm_phys_chan_config pchan, bool allow_osmo_cbits) +{ + int rc; + uint8_t lchan_nr = lchan->nr; + + /* Take care that we never send Osmocom specific cbits to non-Osmo BTS. */ + if (allow_osmo_cbits && lchan->vamos.is_secondary + && lchan->ts->trx->bts->model->type != GSM_BTS_TYPE_OSMOBTS) { + LOG_LCHAN(lchan, LOGL_ERROR, "Cannot address VAMOS shadow lchan on this BTS type: %s\n", + get_value_string(bts_type_names, lchan->ts->trx->bts->model->type)); + return -ENOTSUP; + } + if (allow_osmo_cbits && lchan->ts->trx->bts->model->type != GSM_BTS_TYPE_OSMOBTS) + allow_osmo_cbits = false; + + /* The VAMOS lchans are behind the primary ones in the ts->lchan[] array. They keep their lchan->nr as in the + * array, but on the wire they are the "shadow" lchans for the primary lchans. For example, for TCH/F, there is + * a primary ts->lchan[0] and a VAMOS ts->lchan[1]. Still, the VAMOS lchan should send chan_nr = 0. */ + if (lchan->vamos.is_secondary) + lchan_nr -= lchan->ts->max_primary_lchans; + rc = gsm_pchan2chan_nr(pchan, lchan->ts->nr, lchan_nr, + allow_osmo_cbits ? lchan->vamos.is_secondary : false); + /* Log an error so that we don't need to add logging to each caller of this function */ + if (rc < 0) + LOG_LCHAN(lchan, LOGL_ERROR, + "Error encoding Channel Number: pchan %s ts %u ss %u%s\n", + gsm_pchan_name(lchan->ts->pchan_from_config), lchan->ts->nr, lchan_nr, + lchan->vamos.is_secondary ? " (VAMOS shadow)" : ""); + return rc; +} + +int gsm_lchan2chan_nr(const struct gsm_lchan *lchan, bool allow_osmo_cbits) { - /* Note: non-standard Osmocom style dyn TS PDCH mode chan_nr is only used within - * rsl_tx_dyn_ts_pdch_act_deact(). */ - return gsm_pchan2chan_nr(lchan->ts->pchan_is, lchan->ts->nr, lchan->nr); + return gsm_lchan_and_pchan2chan_nr(lchan, lchan->ts->pchan_is, allow_osmo_cbits); } static const uint8_t subslots_per_pchan[] = { @@ -561,12 +589,12 @@ static const uint8_t subslots_per_pchan[] = { [GSM_PCHAN_CCCH_SDCCH4_CBCH] = 4, [GSM_PCHAN_SDCCH8_SACCH8C_CBCH] = 8, /* Dyn TS: maximum allowed subslots */ - [GSM_PCHAN_TCH_F_TCH_H_PDCH] = 2, + [GSM_PCHAN_OSMO_DYN] = 8, [GSM_PCHAN_TCH_F_PDCH] = 1, }; -/*! According to ts->pchan and possibly ts->dyn_pchan, return the number of - * logical channels available in the timeslot. */ +/*! Return the maximum number of logical channels that may be used in a timeslot of the given physical channel + * configuration. */ uint8_t pchan_subslots(enum gsm_phys_chan_config pchan) { if (pchan < 0 || pchan >= ARRAY_SIZE(subslots_per_pchan)) @@ -574,6 +602,30 @@ uint8_t pchan_subslots(enum gsm_phys_chan_config pchan) return subslots_per_pchan[pchan]; } +static const uint8_t subslots_per_pchan_vamos[] = { + [GSM_PCHAN_NONE] = 0, + [GSM_PCHAN_CCCH] = 0, + [GSM_PCHAN_PDCH] = 0, + [GSM_PCHAN_CCCH_SDCCH4] = 0, + /* VAMOS: on a TCH/F, there may be a TCH/H shadow */ + [GSM_PCHAN_TCH_F] = 2, + [GSM_PCHAN_TCH_H] = 2, + [GSM_PCHAN_SDCCH8_SACCH8C] = 0, + [GSM_PCHAN_CCCH_SDCCH4_CBCH] = 0, + [GSM_PCHAN_SDCCH8_SACCH8C_CBCH] = 0, + [GSM_PCHAN_OSMO_DYN] = 0, + [GSM_PCHAN_TCH_F_PDCH] = 2, +}; + +/* Return the maximum number of VAMOS secondary lchans that may be used in a timeslot of the given physical channel + * configuration. */ +uint8_t pchan_subslots_vamos(enum gsm_phys_chan_config pchan) +{ + if (pchan < 0 || pchan >= ARRAY_SIZE(subslots_per_pchan_vamos)) + return 0; + return subslots_per_pchan_vamos[pchan]; +} + static bool pchan_is_tch(enum gsm_phys_chan_config pchan) { switch (pchan) { @@ -596,17 +648,18 @@ struct gsm_bts *conn_get_bts(struct gsm_subscriber_connection *conn) { return conn->lchan->ts->trx->bts; } -static void _chan_desc_fill_tail(struct gsm48_chan_desc *cd, const struct gsm_lchan *lchan) +static void _chan_desc_fill_tail(struct gsm48_chan_desc *cd, const struct gsm_lchan *lchan, + uint8_t tsc) { if (!lchan->ts->hopping.enabled) { uint16_t arfcn = lchan->ts->trx->arfcn & 0x3ff; - cd->h0.tsc = gsm_ts_tsc(lchan->ts); + cd->h0.tsc = tsc; cd->h0.h = 0; cd->h0.spare = 0; cd->h0.arfcn_high = arfcn >> 8; cd->h0.arfcn_low = arfcn & 0xff; } else { - cd->h1.tsc = gsm_ts_tsc(lchan->ts); + cd->h1.tsc = tsc; cd->h1.h = 1; cd->h1.maio_high = lchan->ts->hopping.maio >> 2; cd->h1.maio_low = lchan->ts->hopping.maio & 0x03; @@ -614,21 +667,30 @@ static void _chan_desc_fill_tail(struct gsm48_chan_desc *cd, const struct gsm_lc } } -void gsm48_lchan2chan_desc(struct gsm48_chan_desc *cd, - const struct gsm_lchan *lchan) +int gsm48_lchan_and_pchan2chan_desc(struct gsm48_chan_desc *cd, + const struct gsm_lchan *lchan, + enum gsm_phys_chan_config pchan, + uint8_t tsc, bool allow_osmo_cbits) { - cd->chan_nr = gsm_lchan2chan_nr(lchan); - _chan_desc_fill_tail(cd, lchan); + int chan_nr = gsm_lchan_and_pchan2chan_nr(lchan, pchan, allow_osmo_cbits); + if (chan_nr < 0) { + /* Log an error so that we don't need to add logging to each caller of this function */ + LOG_LCHAN(lchan, LOGL_ERROR, + "Error encoding Channel Number: pchan %s ts %u ss %u%s (rc = %d)\n", + gsm_pchan_name(pchan), lchan->ts->nr, lchan->nr, + lchan->vamos.is_secondary ? " (VAMOS shadow)" : "", chan_nr); + return chan_nr; + } + cd->chan_nr = chan_nr; + _chan_desc_fill_tail(cd, lchan, tsc); + return 0; } -/* like gsm48_lchan2chan_desc() above, but use ts->pchan_from_config to - * return a channel description based on what is configured, rather than - * what the current state of the pchan type is */ -void gsm48_lchan2chan_desc_as_configured(struct gsm48_chan_desc *cd, - const struct gsm_lchan *lchan) +int gsm48_lchan2chan_desc(struct gsm48_chan_desc *cd, + const struct gsm_lchan *lchan, + uint8_t tsc, bool allow_osmo_cbits) { - cd->chan_nr = gsm_pchan2chan_nr(lchan->ts->pchan_from_config, lchan->ts->nr, lchan->nr); - _chan_desc_fill_tail(cd, lchan); + return gsm48_lchan_and_pchan2chan_desc(cd, lchan, lchan->ts->pchan_is, tsc, allow_osmo_cbits); } uint8_t gsm_ts_tsc(const struct gsm_bts_trx_ts *ts) @@ -642,7 +704,7 @@ uint8_t gsm_ts_tsc(const struct gsm_bts_trx_ts *ts) bool nm_is_running(const struct gsm_nm_state *s) { if (s->operational != NM_OPSTATE_ENABLED) return false; - if ((s->availability != NM_AVSTATE_OK) && (s->availability != 0xff)) + if (s->availability != NM_AVSTATE_OK) return false; if (s->administrative != NM_STATE_UNLOCKED) return false; @@ -674,6 +736,8 @@ enum gsm_phys_chan_config gsm_pchan_by_lchan_type(enum gsm_chan_t type) return GSM_PCHAN_TCH_F; case GSM_LCHAN_TCH_H: return GSM_PCHAN_TCH_H; + case GSM_LCHAN_SDCCH: + return GSM_PCHAN_SDCCH8_SACCH8C; case GSM_LCHAN_NONE: case GSM_LCHAN_PDTCH: /* TODO: so far lchan->type is NONE in PDCH mode. PDTCH is only @@ -685,6 +749,22 @@ enum gsm_phys_chan_config gsm_pchan_by_lchan_type(enum gsm_chan_t type) } } +enum channel_rate chan_t_to_chan_rate(enum gsm_chan_t chan_t) +{ + switch (chan_t) { + case GSM_LCHAN_SDCCH: + return CH_RATE_SDCCH; + case GSM_LCHAN_TCH_F: + return CH_RATE_FULL; + case GSM_LCHAN_TCH_H: + return CH_RATE_HALF; + default: + /* For other channel types, the channel_rate value is never used. It is fine to return an invalid value, + * and callers don't actually need to check for this. */ + return -1; + } +} + /* Can the timeslot in principle be used as this PCHAN kind? */ bool ts_is_capable_of_pchan(struct gsm_bts_trx_ts *ts, enum gsm_phys_chan_config pchan) { @@ -698,11 +778,12 @@ bool ts_is_capable_of_pchan(struct gsm_bts_trx_ts *ts, enum gsm_phys_chan_config return false; } - case GSM_PCHAN_TCH_F_TCH_H_PDCH: + case GSM_PCHAN_OSMO_DYN: switch (pchan) { case GSM_PCHAN_TCH_F: case GSM_PCHAN_TCH_H: case GSM_PCHAN_PDCH: + case GSM_PCHAN_SDCCH8_SACCH8C: return true; default: return false; @@ -770,11 +851,12 @@ bool ts_is_capable_of_lchant(struct gsm_bts_trx_ts *ts, enum gsm_chan_t type) return false; } - case GSM_PCHAN_TCH_F_TCH_H_PDCH: + case GSM_PCHAN_OSMO_DYN: switch (type) { case GSM_LCHAN_TCH_F: case GSM_LCHAN_TCH_H: case GSM_LCHAN_PDTCH: + case GSM_LCHAN_SDCCH: return true; default: return false; @@ -816,10 +898,8 @@ bool ts_is_capable_of_lchant(struct gsm_bts_trx_ts *ts, enum gsm_chan_t type) bool ts_is_usable(const struct gsm_bts_trx_ts *ts) { - if (!trx_is_usable(ts->trx)) { - LOGP(DRLL, LOGL_DEBUG, "%s not usable\n", gsm_trx_name(ts->trx)); + if (!trx_is_usable(ts->trx)) return false; - } if (!ts->fi) return false; @@ -838,6 +918,11 @@ bool ts_is_usable(const struct gsm_bts_trx_ts *ts) void conn_update_ms_power_class(struct gsm_subscriber_connection *conn, uint8_t power_class) { struct gsm_bts *bts = conn_get_bts(conn); + + /* MS Power class remains the same => do nothing */ + if (power_class == conn->ms_power_class) + return; + LOGP(DRLL, LOGL_DEBUG, "MS Power class update: %" PRIu8 " -> %" PRIu8 "\n", conn->ms_power_class, power_class); @@ -849,65 +934,27 @@ void conn_update_ms_power_class(struct gsm_subscriber_connection *conn, uint8_t lchan_update_ms_power_ctrl_level(conn->lchan, bts->ms_max_power); } -void lchan_update_ms_power_ctrl_level(struct gsm_lchan *lchan, int ms_power_dbm) -{ - struct gsm_bts *bts = lchan->ts->trx->bts; - struct gsm_subscriber_connection *conn = lchan->conn; - int max_pwr_dbm_pwclass, new_pwr; - bool send_pwr_ctrl_msg = false; - - LOG_LCHAN(lchan, LOGL_DEBUG, - "MS Power level update requested: %d dBm\n", ms_power_dbm); - - if (!conn) - goto ms_power_default; - - if (conn->ms_power_class == 0) - goto ms_power_default; - - if ((max_pwr_dbm_pwclass = (int)ms_class_gmsk_dbm(bts->band, conn->ms_power_class)) < 0) { - LOG_LCHAN(lchan, LOGL_INFO, - "Failed getting max ms power for power class %" PRIu8 - " on band %s, providing default max ms power\n", - conn->ms_power_class, gsm_band_name(bts->band)); - goto ms_power_default; - } - - /* Current configured max pwr is above maximum one allowed on - current band + ms power class, so use that one. */ - if (ms_power_dbm > max_pwr_dbm_pwclass) - ms_power_dbm = max_pwr_dbm_pwclass; - -ms_power_default: - if ((new_pwr = ms_pwr_ctl_lvl(bts->band, ms_power_dbm)) < 0) { - LOG_LCHAN(lchan, LOGL_INFO, - "Failed getting max ms power level %d on band %s," - " providing default max ms power\n", - ms_power_dbm, gsm_band_name(bts->band)); - return; - } - - LOG_LCHAN(lchan, LOGL_DEBUG, - "MS Power level update (power class %" PRIu8 "): %" PRIu8 " -> %d\n", - conn ? conn->ms_power_class : 0, lchan->ms_power, new_pwr); - - /* If chan was already activated and max ms_power changes (due to power - classmark received), send an MS Power Control message */ - if (lchan->activate.activ_ack && new_pwr != lchan->ms_power) - send_pwr_ctrl_msg = true; - - lchan->ms_power = new_pwr; +const struct value_string lchan_activate_mode_names[] = { + OSMO_VALUE_STRING(ACTIVATE_FOR_NONE), + OSMO_VALUE_STRING(ACTIVATE_FOR_MS_CHANNEL_REQUEST), + OSMO_VALUE_STRING(ACTIVATE_FOR_ASSIGNMENT), + OSMO_VALUE_STRING(ACTIVATE_FOR_HANDOVER), + OSMO_VALUE_STRING(ACTIVATE_FOR_VTY), + {} +}; - if (send_pwr_ctrl_msg) - rsl_chan_ms_power_ctrl(lchan); -} +const struct value_string lchan_modify_for_names[] = { + OSMO_VALUE_STRING(MODIFY_FOR_NONE), + OSMO_VALUE_STRING(MODIFY_FOR_ASSIGNMENT), + OSMO_VALUE_STRING(MODIFY_FOR_VTY), + {} +}; -const struct value_string lchan_activate_mode_names[] = { - OSMO_VALUE_STRING(FOR_NONE), - OSMO_VALUE_STRING(FOR_MS_CHANNEL_REQUEST), - OSMO_VALUE_STRING(FOR_ASSIGNMENT), - OSMO_VALUE_STRING(FOR_HANDOVER), - OSMO_VALUE_STRING(FOR_VTY), +const struct value_string assign_for_names[] = { + OSMO_VALUE_STRING(ASSIGN_FOR_NONE), + OSMO_VALUE_STRING(ASSIGN_FOR_BSSMAP_REQ), + OSMO_VALUE_STRING(ASSIGN_FOR_CONGESTION_RESOLUTION), + OSMO_VALUE_STRING(ASSIGN_FOR_VTY), {} }; @@ -963,3 +1010,35 @@ enum gsm48_rr_cause bsc_gsm48_rr_cause_from_rsl_cause(uint8_t c) return GSM48_RR_CAUSE_ABNORMAL_UNSPEC; } } + +/* Default Interference Measurement Parameters */ +const struct gsm_interf_meas_params interf_meas_params_def = { + .avg_period = 6, /* 6 SACCH periods */ + .bounds_dbm = { + 115, /* 0: -115 dBm */ + 109, /* X1: -109 dBm */ + 103, /* X2: -103 dBm */ + 97, /* X3: -97 dBm */ + 91, /* X4: -91 dBm */ + 85, /* X5: -85 dBm */ + }, +}; + +enum rsl_cmod_spd chan_mode_to_rsl_cmod_spd(enum gsm48_chan_mode chan_mode) +{ + switch (gsm48_chan_mode_to_non_vamos(chan_mode)) { + case GSM48_CMODE_SIGN: + return RSL_CMOD_SPD_SIGN; + case GSM48_CMODE_SPEECH_V1: + case GSM48_CMODE_SPEECH_EFR: + case GSM48_CMODE_SPEECH_AMR: + return RSL_CMOD_SPD_SPEECH; + case GSM48_CMODE_DATA_14k5: + case GSM48_CMODE_DATA_12k0: + case GSM48_CMODE_DATA_6k0: + case GSM48_CMODE_DATA_3k6: + return RSL_CMOD_SPD_DATA; + default: + return -EINVAL; + } +} |