From 7950e5d90cefb940ff0a08622ba26999b23b8a27 Mon Sep 17 00:00:00 2001 From: Pau Espin Pedrol Date: Thu, 31 Oct 2019 15:59:49 +0100 Subject: [PATCH] bsc: Adapt maximum MS Power Ctrl level based on band and MS Power class Related: OS#4244 Change-Id: I6bff440b7797e710bca5af94fae546e5d55e6972 --- include/osmocom/bsc/abis_rsl.h | 2 +- include/osmocom/bsc/gsm_data.h | 6 ++++ src/osmo-bsc/abis_rsl.c | 12 +------ src/osmo-bsc/gsm_08_08.c | 59 ++++++++++++++++++++++++++++++++ src/osmo-bsc/gsm_data.c | 62 ++++++++++++++++++++++++++++++++++ src/osmo-bsc/lchan_fsm.c | 6 ++-- 6 files changed, 133 insertions(+), 14 deletions(-) diff --git a/include/osmocom/bsc/abis_rsl.h b/include/osmocom/bsc/abis_rsl.h index f7db7790f..b43e3ae99 100644 --- a/include/osmocom/bsc/abis_rsl.h +++ b/include/osmocom/bsc/abis_rsl.h @@ -85,7 +85,7 @@ int rsl_sacch_info_modify(struct gsm_lchan *lchan, uint8_t type, const uint8_t *data, int len); int rsl_chan_bs_power_ctrl(struct gsm_lchan *lchan, unsigned int fpc, int db); -int rsl_chan_ms_power_ctrl(struct gsm_lchan *lchan, unsigned int fpc, int dbm); +int rsl_chan_ms_power_ctrl(struct gsm_lchan *lchan); /* SMSCB functionality */ int rsl_sms_cb_command(struct gsm_bts *bts, uint8_t chan_number, diff --git a/include/osmocom/bsc/gsm_data.h b/include/osmocom/bsc/gsm_data.h index fe626b163..040e36d79 100644 --- a/include/osmocom/bsc/gsm_data.h +++ b/include/osmocom/bsc/gsm_data.h @@ -309,6 +309,9 @@ struct gsm_subscriber_connection { /* pointer to "other" connection, if Call Leg Relocation was successful */ struct gsm_subscriber_connection *other; } lcls; + + /* MS Power Class, TS 05.05 sec 4.1.1 "Mobile station". 0 means unset. */ + uint8_t ms_power_class:3; }; @@ -1374,6 +1377,9 @@ static inline struct gsm_bts *conn_get_bts(struct gsm_subscriber_connection *con return conn->lchan->ts->trx->bts; } +void conn_update_ms_power_class(struct gsm_subscriber_connection *conn, uint8_t power_class); +void lchan_update_ms_power_ctrl_level(struct gsm_lchan *lchan, int ms_power_dbm); + enum { BTS_CTR_CHREQ_TOTAL, BTS_CTR_CHREQ_NO_CHANNEL, diff --git a/src/osmo-bsc/abis_rsl.c b/src/osmo-bsc/abis_rsl.c index 8df0e81a6..80f54b3d3 100644 --- a/src/osmo-bsc/abis_rsl.c +++ b/src/osmo-bsc/abis_rsl.c @@ -293,26 +293,16 @@ int rsl_chan_bs_power_ctrl(struct gsm_lchan *lchan, unsigned int fpc, int db) return abis_rsl_sendmsg(msg); } -int rsl_chan_ms_power_ctrl(struct gsm_lchan *lchan, unsigned int fpc, int dbm) +int rsl_chan_ms_power_ctrl(struct gsm_lchan *lchan) { struct gsm_bts_trx *trx = lchan->ts->trx; struct gsm_bts *bts = trx->bts; struct abis_rsl_dchan_hdr *dh; struct msgb *msg; uint8_t chan_nr = gsm_lchan2chan_nr(lchan); - int ctl_lvl; - - ctl_lvl = ms_pwr_ctl_lvl(bts->band, dbm); - if (ctl_lvl < 0) - return ctl_lvl; msg = rsl_msgb_alloc(); - lchan->ms_power = ctl_lvl; - - if (fpc) - lchan->ms_power |= 0x20; - dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh)); init_dchan_hdr(dh, RSL_MT_MS_POWER_CONTROL); dh->chan_nr = chan_nr; diff --git a/src/osmo-bsc/gsm_08_08.c b/src/osmo-bsc/gsm_08_08.c index ad67c3f49..3efc66581 100644 --- a/src/osmo-bsc/gsm_08_08.c +++ b/src/osmo-bsc/gsm_08_08.c @@ -395,12 +395,16 @@ static int handle_page_resp(struct gsm_subscriber_connection *conn, struct msgb return 0; } +/* TS 04.08 sec 9.2.15 "Location updating request" */ static void handle_lu_request(struct gsm_subscriber_connection *conn, struct msgb *msg) { struct gsm48_hdr *gh; struct gsm48_loc_upd_req *lu; struct gsm48_loc_area_id lai; + int8_t rc8; + struct gsm_bts *bts = conn_get_bts(conn); + if (msgb_l3len(msg) < sizeof(*gh) + sizeof(*lu)) { LOGP(DMSC, LOGL_ERROR, "LU too small to look at: %u\n", msgb_l3len(msg)); @@ -416,6 +420,47 @@ static void handle_lu_request(struct gsm_subscriber_connection *conn, LOGP(DMSC, LOGL_DEBUG, "Marking con for welcome USSD.\n"); conn->new_subscriber = 1; } + + rc8 = osmo_gsm48_rfpowercap2powerclass(bts->band, lu->classmark1.pwr_lev); + if (rc8 < 0) { + LOGP(DMSC, LOGL_NOTICE, + "Unable to decode RF power capability %x from classmark1 during LU.\n", + lu->classmark1.pwr_lev); + rc8 = 0; + } + conn_update_ms_power_class(conn, rc8); +} + + +/* TS 04.08 sec 9.2.15 "Location updating request" */ +static void handle_cm_serv_req(struct gsm_subscriber_connection *conn, + struct msgb *msg) +{ + struct gsm48_hdr *gh; + struct gsm48_service_request *serv_req; + struct gsm48_classmark2* cm2; + int8_t rc8; + struct gsm_bts *bts = conn_get_bts(conn); + + if (msgb_l3len(msg) < sizeof(*gh) + sizeof(*serv_req)) { + LOGP(DMSC, LOGL_ERROR, "CM Serv Req too small to look at: %u\n", msgb_l3len(msg)); + return; + } + + gh = msgb_l3(msg); + serv_req = (struct gsm48_service_request *) gh->data; + + cm2 = (struct gsm48_classmark2*)(((uint8_t*)&serv_req->classmark)+1); + /* FIXME: one classmark2 is available in libosmocore: + cm2 = &serv_req->classmark2; */ + rc8 = osmo_gsm48_rfpowercap2powerclass(bts->band, cm2->pwr_lev); + if (rc8 < 0) { + LOGP(DMSC, LOGL_NOTICE, + "Unable to decode RF power capability %x from classmark2 during CM Service Req.\n", + cm2->pwr_lev); + rc8 = 0; + } + conn_update_ms_power_class(conn, rc8); } int bsc_scan_bts_msg(struct gsm_subscriber_connection *conn, struct msgb *msg) @@ -427,6 +472,8 @@ int bsc_scan_bts_msg(struct gsm_subscriber_connection *conn, struct msgb *msg) if (pdisc == GSM48_PDISC_MM) { if (mtype == GSM48_MT_MM_LOC_UPD_REQUEST) handle_lu_request(conn, msg); + else if(mtype == GSM48_MT_MM_CM_SERV_REQ) + handle_cm_serv_req(conn, msg); } else if (pdisc == GSM48_PDISC_RR) { if (mtype == GSM48_MT_RR_PAG_RESP) handle_page_resp(conn, msg); @@ -677,8 +724,20 @@ void bsc_cm_update(struct gsm_subscriber_connection *conn, const uint8_t *cm2, uint8_t cm2_len, const uint8_t *cm3, uint8_t cm3_len) { + struct gsm48_classmark2 *cm2_parsed = (struct gsm48_classmark2 *)cm2; + int8_t rc8; int rc; struct msgb *resp; + struct gsm_bts *bts = conn_get_bts(conn); + + rc8 = osmo_gsm48_rfpowercap2powerclass(bts->band, cm2_parsed->pwr_lev); + if (rc8 < 0) { + LOGP(DMSC, LOGL_NOTICE, + "Unable to decode RF power capability %x from classmark1 during CM Update.\n", + cm2_parsed->pwr_lev); + rc8 = 0; + } + conn_update_ms_power_class(conn, rc8); if (!msc_connected(conn)) return; diff --git a/src/osmo-bsc/gsm_data.c b/src/osmo-bsc/gsm_data.c index 1c2c4d8e7..2a7783762 100644 --- a/src/osmo-bsc/gsm_data.c +++ b/src/osmo-bsc/gsm_data.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -1685,6 +1686,67 @@ bool ts_is_usable(const struct gsm_bts_trx_ts *ts) return true; } +void conn_update_ms_power_class(struct gsm_subscriber_connection *conn, uint8_t power_class) +{ + struct gsm_bts *bts = conn_get_bts(conn); + LOGP(DRLL, LOGL_DEBUG, "MS Power class update: %" PRIu8 " -> %" PRIu8 "\n", + conn->ms_power_class, power_class); + + conn->ms_power_class = power_class; + + /* If there's an associated lchan, attempt to update its max power to be + on track with band maximum values */ + if (conn->lchan) + 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; + + 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); + + lchan->ms_power = new_pwr; + /* FIXME: if chan is active and lchan->ms_power != new_pwr, consider + sending an MS Power Control message (RSL) towards BTS to announce the + new max ms power lvl, see rsl_chan_ms_power_ctrl() */ +} + const struct value_string lchan_activate_mode_names[] = { OSMO_VALUE_STRING(FOR_NONE), OSMO_VALUE_STRING(FOR_MS_CHANNEL_REQUEST), diff --git a/src/osmo-bsc/lchan_fsm.c b/src/osmo-bsc/lchan_fsm.c index f2fef9963..9ca73dfd5 100644 --- a/src/osmo-bsc/lchan_fsm.c +++ b/src/osmo-bsc/lchan_fsm.c @@ -511,6 +511,7 @@ static void lchan_fsm_wait_ts_ready_onenter(struct osmo_fsm_inst *fi, uint32_t p struct osmo_mgcpc_ep_ci *use_mgwep_ci; struct gsm_lchan *old_lchan = lchan->activate.info.re_use_mgw_endpoint_from_lchan; struct lchan_activate_info *info = &lchan->activate.info; + int ms_power_dbm; if (lchan->release.requested) { lchan_fail("Release requested while activating"); @@ -522,11 +523,12 @@ static void lchan_fsm_wait_ts_ready_onenter(struct osmo_fsm_inst *fi, uint32_t p /* If there is a previous lchan, and the new lchan is on the same cell as previous one, * take over power and TA values. Otherwise, use max power and zero TA. */ if (old_lchan && old_lchan->ts->trx->bts == bts) { - lchan->ms_power = old_lchan->ms_power; + ms_power_dbm = ms_pwr_dbm(bts->band, old_lchan->ms_power); + lchan_update_ms_power_ctrl_level(lchan, ms_power_dbm >= 0 ? ms_power_dbm : bts->ms_max_power); lchan->bs_power = old_lchan->bs_power; lchan->rqd_ta = old_lchan->rqd_ta; } else { - lchan->ms_power = ms_pwr_ctl_lvl(bts->band, bts->ms_max_power); + lchan_update_ms_power_ctrl_level(lchan, bts->ms_max_power); /* Upon last entering the UNUSED state, from lchan_reset(): * - bs_power is still zero, 0dB reduction, output power = Pn. * - TA is still zero, to be determined by RACH. */