WIP: Support ANR procedures on MS with active TBF
TODO:
* General clean up
* Find out and fix why MS not resetting Neighbour List to BA(GPRS) when
empty NC_Frequency_List is sent in Packet Measurement Order.
* Fix MS most of the time not sending Neighbour report for cells not
present in SI2, probably due to waiting not enough time (increasing
NC_REPORTING_PERIOD_T may help, but then problem in previous point above
may show up more). Also maybe waiting for several reports before
continuing may also help.
* Configurable/dynamic chunk list size currently hardcoded to 5.
Improvements/optimizations:
* Use FREQUENCY_DIFF in Add_Frequency for NC_Frequency_List to make
it smaller and hence require less PAcketMeasurementOrder messages.
* Support Enchanced Packet Report message (need to signal support for it
too).
Related: SYS#5303
Change-Id: I051d4fa90fe4ccc44ea691f8a3a487e97868e52c
diff --git a/src/pcu_l1_if.cpp b/src/pcu_l1_if.cpp
index 5aa8849..dd51ef7 100644
--- a/src/pcu_l1_if.cpp
+++ b/src/pcu_l1_if.cpp
@@ -95,6 +95,7 @@
* PCU messages
*/
+/* Can be used to allocate message with non-variable size */
struct msgb *pcu_msgb_alloc(uint8_t msg_type, uint8_t bts_nr)
{
struct msgb *msg;
@@ -111,6 +112,21 @@
return msg;
}
+/* Allocate message with extra size, only reserve pcuif msg hdr */
+static struct msgb *pcu_msgb_alloc_ext_size(uint8_t msg_type, uint8_t bts_nr, size_t extra_size)
+{
+ struct msgb *msg;
+ struct gsm_pcu_if *pcu_prim;
+ msg = msgb_alloc(sizeof(struct gsm_pcu_if) + extra_size, "pcu_sock_tx");
+ /* Only header is filled, caller is responible for reserving + filling
+ * message type specific contents: */
+ msgb_put(msg, PCUIF_HDR_SIZE);
+ pcu_prim = (struct gsm_pcu_if *) msgb_data(msg);
+ pcu_prim->msg_type = msg_type;
+ pcu_prim->bts_nr = bts_nr;
+ return msg;
+}
+
const struct value_string gsm_pcu_if_text_type_names[] = {
OSMO_VALUE_STRING(PCU_VERSION),
OSMO_VALUE_STRING(PCU_OML_ALERT),
@@ -271,6 +287,49 @@
pcu_tx_data_req(bts, 0, 0, PCU_IF_SAPI_PCH, 0, 0, 0, data, PAGING_GROUP_LEN + GSM_MACBLOCK_LEN);
}
+
+static void _arfcn_bsic2cell_desc(struct gsm48_cell_desc *cd, uint16_t arfcn, uint8_t bsic)
+{
+ cd->ncc = (bsic >> 3 & 0x7);
+ cd->bcc = (bsic & 0x7);
+ cd->arfcn_hi = arfcn >> 8;
+ cd->arfcn_lo = arfcn & 0xff;
+}
+
+int pcu_tx_anr_cnf(struct gprs_rlcmac_bts *bts, const struct arfcn_bsic *cell_list,
+ const uint8_t *meas_list, unsigned int num_cells)
+{
+ struct msgb *msg;
+ struct gsm_pcu_if *pcu_prim;
+ struct gsm_pcu_if_anr_cnf *anr_cnf;
+
+ LOGP(DL1IF, LOGL_DEBUG, "(bts=%u) Sending ANR Confirmation: num_cells=%u\n",
+ bts->nr, num_cells);
+
+ msg = pcu_msgb_alloc_ext_size(PCU_IF_MSG_CONTAINER, bts->nr, sizeof(struct gsm_pcu_if_anr_cnf));
+ if (!msg)
+ return -ENOMEM;
+ pcu_prim = (struct gsm_pcu_if *) msgb_data(msg);
+ anr_cnf = (struct gsm_pcu_if_anr_cnf *)&pcu_prim->u.container.data[0];
+
+ msgb_put(msg, sizeof(pcu_prim->u.container) + sizeof(struct gsm_pcu_if_anr_cnf));
+ pcu_prim->u.container.msg_type = PCU_IF_MSG_ANR_CNF;
+ osmo_store16be(sizeof(struct gsm_pcu_if_anr_cnf), &pcu_prim->u.container.length);
+
+ OSMO_ASSERT(num_cells <= ARRAY_SIZE(anr_cnf->cell_list));
+ OSMO_ASSERT(num_cells <= ARRAY_SIZE(anr_cnf->rxlev_list));
+
+ anr_cnf->num_cells = num_cells;
+ if (num_cells) {
+ unsigned int i;
+ for (i = 0; i < num_cells; i++)
+ _arfcn_bsic2cell_desc((struct gsm48_cell_desc*)&anr_cnf->cell_list[i], cell_list[i].arfcn, cell_list[i].bsic);
+ memcpy(anr_cnf->rxlev_list, meas_list, num_cells);
+ }
+
+ return pcu_sock_send(msg);
+}
+
void pcu_rx_block_time(struct gprs_rlcmac_bts *bts, uint16_t arfcn, uint32_t fn, uint8_t ts_no)
{
bts_set_current_block_frame_number(bts, fn);
@@ -950,11 +1009,28 @@
return 0;
}
+static int pcu_rx_anr_req(struct gprs_rlcmac_bts *bts, struct gsm_pcu_if_anr_req *anr_req)
+{
+
+ LOGP(DL1IF, LOGL_INFO, "Automatic Neighbor Registration Request received: num_cells=%u cell_list=%s\n",
+ anr_req->num_cells,
+ osmo_hexdump((const uint8_t*)anr_req->cell_list, anr_req->num_cells * sizeof(*anr_req->cell_list)));
+ return osmo_fsm_inst_dispatch(bts->anr->fi, BTS_ANR_EV_RX_ANR_REQ, anr_req);
+}
+
static int pcu_rx_container(struct gprs_rlcmac_bts *bts, struct gsm_pcu_if_container *container)
{
int rc;
+ uint16_t data_length = osmo_load16be(&container->length);
switch (container->msg_type) {
+ case PCU_IF_MSG_ANR_REQ:
+ if (data_length < sizeof(struct gsm_pcu_if_anr_req)) {
+ LOGP(DL1IF, LOGL_ERROR, "Rx container(ANR_REQ) message too short\n");
+ return -EINVAL;
+ }
+ rc = pcu_rx_anr_req(bts, (struct gsm_pcu_if_anr_req*)&container->data);
+ break;
default:
LOGP(DL1IF, LOGL_NOTICE, "(bts=%d) Rx unexpected msg type (%u) inside container!\n",
bts->nr, container->msg_type);