<p>pespin has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/osmo-pcu/+/22338">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">WIP: Introduce NACC support<br><br>Change-Id: Ife6e4a086d58d49676d12b6984f63079ec472e79<br>---<br>M configure.ac<br>M src/Makefile.am<br>M src/bts.cpp<br>M src/bts.h<br>M src/encoding.cpp<br>M src/encoding.h<br>M src/gprs_bssgp_pcu.c<br>M src/gprs_debug.cpp<br>M src/gprs_debug.h<br>M src/gprs_ms.c<br>M src/gprs_ms.h<br>M src/gprs_pcu.c<br>M src/gprs_pcu.h<br>M src/gprs_rlcmac_sched.cpp<br>A src/nacc_fsm.c<br>A src/nacc_fsm.h<br>M src/pcu_vty.c<br>M src/pdch.cpp<br>M src/pdch.h<br>M src/tbf.cpp<br>M src/tbf.h<br>M tests/Makefile.am<br>22 files changed, 826 insertions(+), 4 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/osmo-pcu refs/changes/38/22338/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/configure.ac b/configure.ac</span><br><span>index 2e99a15..11de328 100644</span><br><span>--- a/configure.ac</span><br><span>+++ b/configure.ac</span><br><span>@@ -84,6 +84,7 @@</span><br><span> dnl checks for libraries</span><br><span> PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.4.0)</span><br><span> PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.4.0)</span><br><span style="color: hsl(120, 100%, 40%);">+PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.4.0)</span><br><span> PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.4.0)</span><br><span> PKG_CHECK_MODULES(LIBOSMOGB, libosmogb >= 1.4.0)</span><br><span> </span><br><span>diff --git a/src/Makefile.am b/src/Makefile.am</span><br><span>index de924a6..2228aee 100644</span><br><span>--- a/src/Makefile.am</span><br><span>+++ b/src/Makefile.am</span><br><span>@@ -19,7 +19,7 @@</span><br><span> #</span><br><span> </span><br><span> AUTOMAKE_OPTIONS = subdir-objects</span><br><span style="color: hsl(0, 100%, 40%);">-AM_CPPFLAGS = -I$(top_srcdir)/include $(STD_DEFINES_AND_INCLUDES) $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGB_CFLAGS) $(LIBOSMOGSM_CFLAGS)</span><br><span style="color: hsl(120, 100%, 40%);">+AM_CPPFLAGS = -I$(top_srcdir)/include $(STD_DEFINES_AND_INCLUDES) $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGB_CFLAGS) $(LIBOSMOCTRL_CFLAGS) $(LIBOSMOGSM_CFLAGS)</span><br><span> </span><br><span> if ENABLE_SYSMODSP</span><br><span> AM_CPPFLAGS += -DENABLE_DIRECT_PHY</span><br><span>@@ -54,6 +54,7 @@</span><br><span> pcu_vty.c \</span><br><span> pcu_vty_functions.cpp \</span><br><span> mslot_class.c \</span><br><span style="color: hsl(120, 100%, 40%);">+ nacc_fsm.c \</span><br><span> tbf.cpp \</span><br><span> tbf_ul.cpp \</span><br><span> tbf_dl.cpp \</span><br><span>@@ -89,6 +90,7 @@</span><br><span> pcu_vty.h \</span><br><span> pcu_vty_functions.h \</span><br><span> mslot_class.h \</span><br><span style="color: hsl(120, 100%, 40%);">+ nacc_fsm.h \</span><br><span> tbf.h \</span><br><span> tbf_ul.h \</span><br><span> tbf_dl.h \</span><br><span>@@ -141,6 +143,7 @@</span><br><span> libgprs.la \</span><br><span> $(LIBOSMOGB_LIBS) \</span><br><span> $(LIBOSMOCORE_LIBS) \</span><br><span style="color: hsl(120, 100%, 40%);">+ $(LIBOSMOCTRL_LIBS) \</span><br><span> $(LIBOSMOGSM_LIBS) \</span><br><span> $(COMMON_LA)</span><br><span> endif</span><br><span>@@ -189,6 +192,7 @@</span><br><span> libgprs.la \</span><br><span> $(LIBOSMOGB_LIBS) \</span><br><span> $(LIBOSMOCORE_LIBS) \</span><br><span style="color: hsl(120, 100%, 40%);">+ $(LIBOSMOCTRL_LIBS) \</span><br><span> $(LIBOSMOGSM_LIBS) \</span><br><span> $(COMMON_LA)</span><br><span> </span><br><span>diff --git a/src/bts.cpp b/src/bts.cpp</span><br><span>index b5bb3a2..eb4bdd9 100644</span><br><span>--- a/src/bts.cpp</span><br><span>+++ b/src/bts.cpp</span><br><span>@@ -140,6 +140,9 @@</span><br><span> { "pkt:ul_assignment", "Packet UL Assignment "},</span><br><span> { "pkt:access_reject", "Packet Access Reject "},</span><br><span> { "pkt:dl_assignment", "Packet DL Assignment "},</span><br><span style="color: hsl(120, 100%, 40%);">+ { "pkt:cell_chg_notification", "Packet Cell Change Notification"},</span><br><span style="color: hsl(120, 100%, 40%);">+ { "pkt:cell_chg_continue", "Packet Cell Change Continue"},</span><br><span style="color: hsl(120, 100%, 40%);">+ { "pkt:neigh_cell_data", "Packet Neighbour Cell Data"},</span><br><span> { "ul:control", "UL control Block "},</span><br><span> { "ul:assignment_poll_timeout", "UL Assign Timeout "},</span><br><span> { "ul:assignment_failed", "UL Assign Failed "},</span><br><span>diff --git a/src/bts.h b/src/bts.h</span><br><span>index 7f437e3..cf16e66 100644</span><br><span>--- a/src/bts.h</span><br><span>+++ b/src/bts.h</span><br><span>@@ -2,6 +2,7 @@</span><br><span> *</span><br><span> * Copyright (C) 2012 Ivan Klyuchnikov</span><br><span> * Copyright (C) 2013 by Holger Hans Peter Freyther</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de</span><br><span> *</span><br><span> * This program is free software; you can redistribute it and/or</span><br><span> * modify it under the terms of the GNU General Public License</span><br><span>@@ -125,6 +126,9 @@</span><br><span> CTR_PKT_UL_ASSIGNMENT,</span><br><span> CTR_PKT_ACCESS_REJ,</span><br><span> CTR_PKT_DL_ASSIGNMENT,</span><br><span style="color: hsl(120, 100%, 40%);">+ CTR_PKT_CELL_CHG_NOTIFICATION,</span><br><span style="color: hsl(120, 100%, 40%);">+ CTR_PKT_CELL_CHG_CONTINUE,</span><br><span style="color: hsl(120, 100%, 40%);">+ CTR_PKT_NEIGH_CELL_DATA,</span><br><span> CTR_RLC_RECV_CONTROL,</span><br><span> CTR_PUA_POLL_TIMEDOUT,</span><br><span> CTR_PUA_POLL_FAILED,</span><br><span>diff --git a/src/encoding.cpp b/src/encoding.cpp</span><br><span>index f605ca2..24e1d68 100644</span><br><span>--- a/src/encoding.cpp</span><br><span>+++ b/src/encoding.cpp</span><br><span>@@ -1731,3 +1731,56 @@</span><br><span> bitvec_write_field(dest, &wp, 5, 8); // WAIT_INDICATION value</span><br><span> bitvec_write_field(dest, &wp, 0, 1); // WAIT_INDICATION size in seconds</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void write_packet_neighbour_cell_data(RlcMacDownlink_t *block,</span><br><span style="color: hsl(120, 100%, 40%);">+ bool tfi_is_dl, uint8_t tfi, uint8_t container_id,</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t container_idx, PNCDContainer_t *container)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ block->PAYLOAD_TYPE = 0x1; // RLC/MAC control block that does not include the optional octets of the RLC/MAC control header</span><br><span style="color: hsl(120, 100%, 40%);">+ block->RRBP = 0; // 0: N+13</span><br><span style="color: hsl(120, 100%, 40%);">+ block->SP = 0; // RRBP field is valid</span><br><span style="color: hsl(120, 100%, 40%);">+ block->USF = 0x0; // Uplink state flag</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ block->u.Packet_Neighbour_Cell_Data.MESSAGE_TYPE = MT_PACKET_NEIGHBOUR_CELL_DATA;</span><br><span style="color: hsl(120, 100%, 40%);">+ block->u.Packet_Neighbour_Cell_Data.PAGE_MODE = 0x0; // Normal Paging</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ block->u.Packet_Neighbour_Cell_Data.Global_TFI.UnionType = tfi_is_dl; // 0=UPLINK TFI, 1=DL TFI</span><br><span style="color: hsl(120, 100%, 40%);">+ if (tfi_is_dl) {</span><br><span style="color: hsl(120, 100%, 40%);">+ block->u.Packet_Neighbour_Cell_Data.Global_TFI.u.DOWNLINK_TFI = tfi;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ block->u.Packet_Neighbour_Cell_Data.Global_TFI.u.UPLINK_TFI = tfi;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ block->u.Packet_Neighbour_Cell_Data.CONTAINER_ID = container_id;</span><br><span style="color: hsl(120, 100%, 40%);">+ block->u.Packet_Neighbour_Cell_Data.spare = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ block->u.Packet_Neighbour_Cell_Data.CONTAINER_INDEX = container_idx;</span><br><span style="color: hsl(120, 100%, 40%);">+ block->u.Packet_Neighbour_Cell_Data.Container = *container;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void write_packet_cell_change_continue(RlcMacDownlink_t *block,</span><br><span style="color: hsl(120, 100%, 40%);">+ bool tfi_is_dl, uint8_t tfi, bool exist_id,</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t arfcn, uint8_t bsic, uint8_t container_id)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ block->PAYLOAD_TYPE = 0x1; // RLC/MAC control block that does not include the optional octets of the RLC/MAC control header</span><br><span style="color: hsl(120, 100%, 40%);">+ block->RRBP = 0; // 0: N+13</span><br><span style="color: hsl(120, 100%, 40%);">+ block->SP = 0; // RRBP field is valid</span><br><span style="color: hsl(120, 100%, 40%);">+ block->USF = 0x0; // Uplink state flag</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ block->u.Packet_Cell_Change_Continue.MESSAGE_TYPE = MT_PACKET_CELL_CHANGE_CONTINUE;</span><br><span style="color: hsl(120, 100%, 40%);">+ block->u.Packet_Cell_Change_Continue.PAGE_MODE = 0x0; // Normal Paging</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ block->u.Packet_Cell_Change_Continue.Global_TFI.UnionType = tfi_is_dl; // 0=UPLINK TFI, 1=DL TFI</span><br><span style="color: hsl(120, 100%, 40%);">+ if (tfi_is_dl) {</span><br><span style="color: hsl(120, 100%, 40%);">+ block->u.Packet_Cell_Change_Continue.Global_TFI.u.DOWNLINK_TFI = tfi;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ block->u.Packet_Cell_Change_Continue.Global_TFI.u.UPLINK_TFI = tfi;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ block->u.Packet_Cell_Change_Continue.Exist_ID = exist_id;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (exist_id) {</span><br><span style="color: hsl(120, 100%, 40%);">+ block->u.Packet_Cell_Change_Continue.ARFCN = arfcn;</span><br><span style="color: hsl(120, 100%, 40%);">+ block->u.Packet_Cell_Change_Continue.BSIC = bsic;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ block->u.Packet_Cell_Change_Continue.CONTAINER_ID = container_id;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/encoding.h b/src/encoding.h</span><br><span>index da63a61..4ebfa35 100644</span><br><span>--- a/src/encoding.h</span><br><span>+++ b/src/encoding.h</span><br><span>@@ -22,17 +22,22 @@</span><br><span> </span><br><span> #include <stdint.h></span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef __cplusplus</span><br><span> extern "C" {</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span> #include <osmocom/gsm/l1sap.h></span><br><span> #include "coding_scheme.h"</span><br><span> #include "gsm_rlcmac.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef __cplusplus</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span> </span><br><span> struct gprs_rlcmac_tbf;</span><br><span> struct bitvec;</span><br><span> struct gprs_llc;</span><br><span> struct gprs_rlc_data_block_info;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef __cplusplus</span><br><span> /**</span><br><span> * I help with encoding data into CSN1 messages.</span><br><span> * TODO: Nobody can remember a function signature like this. One should</span><br><span>@@ -108,3 +113,21 @@</span><br><span> const struct gprs_rlc_data_block_info *rdbi,</span><br><span> int *offset, int *num_chunks, uint8_t *data_block);</span><br><span> };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#endif /* ifdef __cplusplus */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef __cplusplus</span><br><span style="color: hsl(120, 100%, 40%);">+extern "C" {</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void write_packet_neighbour_cell_data(RlcMacDownlink_t *block,</span><br><span style="color: hsl(120, 100%, 40%);">+ bool tfi_is_dl, uint8_t tfi, uint8_t container_id,</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t container_idx, PNCDContainer_t *container);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void write_packet_cell_change_continue(RlcMacDownlink_t *block,</span><br><span style="color: hsl(120, 100%, 40%);">+ bool tfi_is_dl, uint8_t tfi, bool exist_id,</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t arfcn, uint8_t bsic, uint8_t container_id);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef __cplusplus</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span>diff --git a/src/gprs_bssgp_pcu.c b/src/gprs_bssgp_pcu.c</span><br><span>index 956fb66..9c05639 100644</span><br><span>--- a/src/gprs_bssgp_pcu.c</span><br><span>+++ b/src/gprs_bssgp_pcu.c</span><br><span>@@ -419,10 +419,22 @@</span><br><span> int rc = 0;</span><br><span> struct bssgp_bvc_ctx *bctx;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- if (pdu_type == BSSGP_PDUT_STATUS)</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (pdu_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case BSSGP_PDUT_STATUS:</span><br><span> /* Pass the message to the generic BSSGP parser, which handles</span><br><span> * STATUS and RESET messages in either direction. */</span><br><span style="color: hsl(120, 100%, 40%);">+ case BSSGP_PDUT_RAN_INFO:</span><br><span style="color: hsl(120, 100%, 40%);">+ case BSSGP_PDUT_RAN_INFO_REQ:</span><br><span style="color: hsl(120, 100%, 40%);">+ case BSSGP_PDUT_RAN_INFO_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+ case BSSGP_PDUT_RAN_INFO_ERROR:</span><br><span style="color: hsl(120, 100%, 40%);">+ case BSSGP_PDUT_RAN_INFO_APP_ERROR:</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Also pass all RIM related messages to the generic BSSGP</span><br><span style="color: hsl(120, 100%, 40%);">+ * parser so that it can deliver primitive to the RIM SAP</span><br><span style="color: hsl(120, 100%, 40%);">+ * (SAP_BSSGP_RIM) */</span><br><span> return bssgp_rcvmsg(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> </span><br><span> /* Identifiers from DOWN: NSEI, BVCI (both in msg->cb) */</span><br><span> </span><br><span>@@ -542,6 +554,15 @@</span><br><span> }</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static void handle_rim(struct osmo_bssgp_prim *bp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ /* TODO: handle RIM messages here. for RAN-INFORMATION answer, we</span><br><span style="color: hsl(120, 100%, 40%);">+ somehow need to match the RAN-INFORMATION-REQUEST that triggered it,</span><br><span style="color: hsl(120, 100%, 40%);">+ or feed it to all active FSMs and see if that matches internally and</span><br><span style="color: hsl(120, 100%, 40%);">+ can go forward. That's probably the best: fill into a cache and then</span><br><span style="color: hsl(120, 100%, 40%);">+ signal all existing NACC FSMs. */</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx)</span><br><span> {</span><br><span> struct osmo_bssgp_prim *bp;</span><br><span>@@ -551,6 +572,8 @@</span><br><span> case SAP_BSSGP_NM:</span><br><span> if (oph->primitive == PRIM_NM_STATUS)</span><br><span> handle_nm_status(bp);</span><br><span style="color: hsl(120, 100%, 40%);">+ case SAP_BSSGP_RIM:</span><br><span style="color: hsl(120, 100%, 40%);">+ handle_rim(bp);</span><br><span> break;</span><br><span> default:</span><br><span> break;</span><br><span>diff --git a/src/gprs_debug.cpp b/src/gprs_debug.cpp</span><br><span>index a790e3f..1cefa9b 100644</span><br><span>--- a/src/gprs_debug.cpp</span><br><span>+++ b/src/gprs_debug.cpp</span><br><span>@@ -119,6 +119,13 @@</span><br><span> .loglevel = LOGL_NOTICE,</span><br><span> .enabled = 1,</span><br><span> },</span><br><span style="color: hsl(120, 100%, 40%);">+ [DNACC] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .name = "DNACC",</span><br><span style="color: hsl(120, 100%, 40%);">+ .color = "\033[1;37m",</span><br><span style="color: hsl(120, 100%, 40%);">+ .description = "Network Assisted Cell Change (NACC)",</span><br><span style="color: hsl(120, 100%, 40%);">+ .loglevel = LOGL_NOTICE,</span><br><span style="color: hsl(120, 100%, 40%);">+ .enabled = 1,</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span> };</span><br><span> </span><br><span> static int filter_fn(const struct log_context *ctx,</span><br><span>diff --git a/src/gprs_debug.h b/src/gprs_debug.h</span><br><span>index 84a0a07..23ea44d 100644</span><br><span>--- a/src/gprs_debug.h</span><br><span>+++ b/src/gprs_debug.h</span><br><span>@@ -46,6 +46,7 @@</span><br><span> DTBFUL,</span><br><span> DNS,</span><br><span> DPCU,</span><br><span style="color: hsl(120, 100%, 40%);">+ DNACC,</span><br><span> aDebug_LastEntry</span><br><span> };</span><br><span> </span><br><span>diff --git a/src/gprs_ms.c b/src/gprs_ms.c</span><br><span>index ea497a3..5d7afa1 100644</span><br><span>--- a/src/gprs_ms.c</span><br><span>+++ b/src/gprs_ms.c</span><br><span>@@ -26,6 +26,7 @@</span><br><span> #include "gprs_debug.h"</span><br><span> #include "gprs_codel.h"</span><br><span> #include "pcu_utils.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "nacc_fsm.h"</span><br><span> </span><br><span> #include <time.h></span><br><span> </span><br><span>@@ -902,3 +903,36 @@</span><br><span> </span><br><span> return NULL;</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int ms_nacc_start(struct GprsMs *ms, Packet_Cell_Change_Notification_t *notif)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ms->nacc)</span><br><span style="color: hsl(120, 100%, 40%);">+ ms->nacc = nacc_fsm_alloc(ms);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ms->nacc)</span><br><span style="color: hsl(120, 100%, 40%);">+ return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+ return osmo_fsm_inst_dispatch(ms->nacc->fi, NACC_EV_CELL_CHG_NOTIFICATION, notif);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+bool ms_nacc_rts(const struct GprsMs *ms)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ms->nacc)</span><br><span style="color: hsl(120, 100%, 40%);">+ return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ms->nacc->fi->state == NACC_ST_TX_NEIGHBOUR_DATA ||</span><br><span style="color: hsl(120, 100%, 40%);">+ ms->nacc->fi->state == NACC_ST_TX_CELL_CHG_CONTINUE)</span><br><span style="color: hsl(120, 100%, 40%);">+ return true;</span><br><span style="color: hsl(120, 100%, 40%);">+ return false;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb *ms_nacc_create_rlcmac_msg(struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct nacc_ev_create_rlcmac_msg_ctx data_ctx;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ data_ctx.tbf = tbf;</span><br><span style="color: hsl(120, 100%, 40%);">+ data_ctx.msg = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = osmo_fsm_inst_dispatch(ms->nacc->fi, NACC_EV_CREATE_RLCMAC_MSG, &data_ctx);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc != 0 || !data_ctx.msg)</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ return data_ctx.msg;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/gprs_ms.h b/src/gprs_ms.h</span><br><span>index 12809f1..6587231 100644</span><br><span>--- a/src/gprs_ms.h</span><br><span>+++ b/src/gprs_ms.h</span><br><span>@@ -40,6 +40,7 @@</span><br><span> #include <osmocom/gsm/gsm48.h></span><br><span> </span><br><span> #include "coding_scheme.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include <gsm_rlcmac.h></span><br><span> </span><br><span> #include <stdint.h></span><br><span> #include <stddef.h></span><br><span>@@ -100,6 +101,7 @@</span><br><span> enum mcs_kind mode;</span><br><span> </span><br><span> struct rate_ctr_group *ctrs;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct nacc_fsm_ctx *nacc;</span><br><span> };</span><br><span> </span><br><span> struct GprsMs *ms_alloc(struct gprs_rlcmac_bts *bts, uint32_t tlli);</span><br><span>@@ -140,6 +142,10 @@</span><br><span> </span><br><span> void ms_set_callback(struct GprsMs *ms, struct gpr_ms_callback *cb);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+int ms_nacc_start(struct GprsMs *ms, Packet_Cell_Change_Notification_t *notif);</span><br><span style="color: hsl(120, 100%, 40%);">+bool ms_nacc_rts(const struct GprsMs *ms);</span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb *ms_nacc_create_rlcmac_msg(struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static inline bool ms_is_idle(const struct GprsMs *ms)</span><br><span> {</span><br><span> return !ms->ul_tbf && !ms->dl_tbf && !ms->ref && llist_empty(&ms->old_tbfs);</span><br><span>diff --git a/src/gprs_pcu.c b/src/gprs_pcu.c</span><br><span>index d291e71..19fbf7d 100644</span><br><span>--- a/src/gprs_pcu.c</span><br><span>+++ b/src/gprs_pcu.c</span><br><span>@@ -22,6 +22,7 @@</span><br><span> </span><br><span> #include <osmocom/core/utils.h></span><br><span> #include <osmocom/core/linuxlist.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/ctrl/ports.h></span><br><span> </span><br><span> #include "gprs_pcu.h"</span><br><span> #include "bts.h"</span><br><span>@@ -97,6 +98,8 @@</span><br><span> pcu->vty.ws_pdch = 0;</span><br><span> pcu->vty.llc_codel_interval_msec = LLC_CODEL_USE_DEFAULT;</span><br><span> pcu->vty.llc_idle_ack_csec = 10;</span><br><span style="color: hsl(120, 100%, 40%);">+ pcu->vty.neigh_ctrl_addr = talloc_strdup(pcu, "127.0.0.1");</span><br><span style="color: hsl(120, 100%, 40%);">+ pcu->vty.neigh_ctrl_port = OSMO_CTRL_PORT_BSC_NEIGH;</span><br><span> </span><br><span> pcu->T_defs = T_defs_pcu;</span><br><span> osmo_tdefs_reset(pcu->T_defs);</span><br><span>diff --git a/src/gprs_pcu.h b/src/gprs_pcu.h</span><br><span>index 058d102..f9f9893 100644</span><br><span>--- a/src/gprs_pcu.h</span><br><span>+++ b/src/gprs_pcu.h</span><br><span>@@ -102,6 +102,9 @@</span><br><span> uint32_t llc_discard_csec;</span><br><span> uint32_t llc_idle_ack_csec;</span><br><span> uint32_t llc_codel_interval_msec; /* 0=disabled, -1=use default interval */</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Remote BSS resolution sevice (CTRL iface) */</span><br><span style="color: hsl(120, 100%, 40%);">+ char *neigh_ctrl_addr;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t neigh_ctrl_port;</span><br><span> } vty;</span><br><span> </span><br><span> struct gsmtap_inst *gsmtap;</span><br><span>diff --git a/src/gprs_rlcmac_sched.cpp b/src/gprs_rlcmac_sched.cpp</span><br><span>index 5640158..66e9c6b 100644</span><br><span>--- a/src/gprs_rlcmac_sched.cpp</span><br><span>+++ b/src/gprs_rlcmac_sched.cpp</span><br><span>@@ -38,6 +38,7 @@</span><br><span> struct gprs_rlcmac_tbf *poll;</span><br><span> struct gprs_rlcmac_tbf *ul_ass;</span><br><span> struct gprs_rlcmac_tbf *dl_ass;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gprs_rlcmac_tbf *nacc;</span><br><span> struct gprs_rlcmac_ul_tbf *ul_ack;</span><br><span> };</span><br><span> </span><br><span>@@ -71,6 +72,9 @@</span><br><span> if (ul_tbf->ul_ass_state_is(GPRS_RLCMAC_UL_ASS_SEND_ASS)</span><br><span> || ul_tbf->ul_ass_state_is(GPRS_RLCMAC_UL_ASS_SEND_ASS_REJ))</span><br><span> tbf_cand->ul_ass = ul_tbf;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* NACC ready to send */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ms_nacc_rts(ul_tbf->ms()))</span><br><span style="color: hsl(120, 100%, 40%);">+ tbf_cand->nacc = ul_tbf;</span><br><span> /* FIXME: Is this supposed to be fair? The last TBF for each wins? Maybe use llist_add_tail and skip once we have all</span><br><span> states? */</span><br><span> }</span><br><span>@@ -88,6 +92,9 @@</span><br><span> if (dl_tbf->ul_ass_state_is(GPRS_RLCMAC_UL_ASS_SEND_ASS)</span><br><span> || dl_tbf->ul_ass_state_is(GPRS_RLCMAC_UL_ASS_SEND_ASS_REJ))</span><br><span> tbf_cand->ul_ass = dl_tbf;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* NACC ready to send */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ms_nacc_rts(dl_tbf->ms()))</span><br><span style="color: hsl(120, 100%, 40%);">+ tbf_cand->nacc = dl_tbf;</span><br><span> }</span><br><span> </span><br><span> return poll_fn;</span><br><span>@@ -166,7 +173,8 @@</span><br><span> struct gprs_rlcmac_tbf *tbf = NULL;</span><br><span> struct gprs_rlcmac_tbf *next_list[] = { tbfs->ul_ass,</span><br><span> tbfs->dl_ass,</span><br><span style="color: hsl(0, 100%, 40%);">- tbfs->ul_ack };</span><br><span style="color: hsl(120, 100%, 40%);">+ tbfs->ul_ack,</span><br><span style="color: hsl(120, 100%, 40%);">+ tbfs->nacc };</span><br><span> </span><br><span> /* Send Packet Application Information first (ETWS primary notifications) */</span><br><span> msg = sched_app_info(tbfs->dl_ass);</span><br><span>@@ -194,6 +202,9 @@</span><br><span> msg = tbfs->dl_ass->create_dl_ass(fn, ts);</span><br><span> else if (tbf == tbfs->ul_ack)</span><br><span> msg = tbfs->ul_ack->create_ul_ack(fn, ts);</span><br><span style="color: hsl(120, 100%, 40%);">+ else if (tbf == tbfs->nacc) {</span><br><span style="color: hsl(120, 100%, 40%);">+ msg = ms_nacc_create_rlcmac_msg(tbf->ms(), tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> /* else: if tbf/ms is pending to send tx_neigbhourData or tx_CellchangeContinue, send it */</span><br><span> </span><br><span> if (!msg) {</span><br><span>diff --git a/src/nacc_fsm.c b/src/nacc_fsm.c</span><br><span>new file mode 100644</span><br><span>index 0000000..1ae417d</span><br><span>--- /dev/null</span><br><span>+++ b/src/nacc_fsm.c</span><br><span>@@ -0,0 +1,538 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#include <unistd.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <talloc.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/rate_ctr.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/ctrl/control_cmd.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/ctrl/control_if.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/gsm48.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gprs/gprs_bssgp.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gprs/gprs_bssgp_rim.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <nacc_fsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <gprs_rlcmac.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <gprs_debug.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <gprs_ms.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <encoding.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <bts.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define X(s) (1 << (s))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define nacc_fsm_state_chg(fi, NEXT_STATE) \</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fsm_inst_state_chg(fi, NEXT_STATE, 0, 0)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+const struct value_string nacc_fsm_event_names[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ { NACC_EV_CELL_CHG_NOTIFICATION, "CELL_CHG_NOTIFICATION" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { NACC_EV_RX_RESOLVE_RAC_CI, "RX_RESOLVE_RAC_CI" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { NACC_EV_SI_INFO_RECEIVED, "SI_INFO_RECEIVED" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { NACC_EV_CREATE_RLCMAC_MSG, "CREATE_RLCMAC_MSG" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { 0, NULL }</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct msgb *create_packet_neighbour_cell_data(struct nacc_fsm_ctx *ctx, struct gprs_rlcmac_tbf *tbf)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+ RlcMacDownlink_t *mac_control_block;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct GprsMs *ms = tbf_ms(tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ msg = msgb_alloc(GSM_MACBLOCK_LEN, "neighbour_cell_data");</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!msg)</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Initialize a bit vector that uses allocated msgb as the data buffer. */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct bitvec bv = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .data = msgb_put(msg, GSM_MACBLOCK_LEN),</span><br><span style="color: hsl(120, 100%, 40%);">+ .data_len = GSM_MACBLOCK_LEN,</span><br><span style="color: hsl(120, 100%, 40%);">+ };</span><br><span style="color: hsl(120, 100%, 40%);">+ bitvec_unhex(&bv, DUMMY_VEC);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ mac_control_block = (RlcMacDownlink_t *)talloc_zero(ctx->ms, RlcMacDownlink_t);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(tbf_is_tfi_assigned(tbf));</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t tfi_is_dl = tbf_direction(tbf) == GPRS_RLCMAC_DL_TBF;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t tfi = tbf_tfi(tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t container_id = 0; /* FIXME: don't hardcode */</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t container_idx = 0; /* FIXME: don't hardcode */</span><br><span style="color: hsl(120, 100%, 40%);">+ PNCDContainer_t container;</span><br><span style="color: hsl(120, 100%, 40%);">+ memset(&container, 0, sizeof(container));</span><br><span style="color: hsl(120, 100%, 40%);">+ container.UnionType = 1; /* with ID */</span><br><span style="color: hsl(120, 100%, 40%);">+ container.u.PNCD_Container_With_ID.ARFCN = ctx->req_arfcn;</span><br><span style="color: hsl(120, 100%, 40%);">+ container.u.PNCD_Container_With_ID.BSIC = ctx->req_bsic;</span><br><span style="color: hsl(120, 100%, 40%);">+ write_packet_neighbour_cell_data(mac_control_block,</span><br><span style="color: hsl(120, 100%, 40%);">+ tfi_is_dl, tfi, container_id,</span><br><span style="color: hsl(120, 100%, 40%);">+ container_idx, &container);</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DNACC, LOGL_DEBUG, "+++++++++++++++++++++++++ TX : Packet Neighbour Cell Data +++++++++++++++++++++++++\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = encode_gsm_rlcmac_downlink(&bv, mac_control_block);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DTBF, LOGL_ERROR, "Encoding of Packet Neighbour Cell Data failed (%d)\n", rc);</span><br><span style="color: hsl(120, 100%, 40%);">+ goto free_ret;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DNACC, LOGL_DEBUG, "------------------------- TX : Packet Neighbour Cell Data -------------------------\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ rate_ctr_inc(&bts_rate_counters(ms->bts)->ctr[CTR_PKT_NEIGH_CELL_DATA]);</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(mac_control_block);</span><br><span style="color: hsl(120, 100%, 40%);">+ return msg;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+free_ret:</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(mac_control_block);</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct msgb *create_packet_cell_chg_continue(struct nacc_fsm_ctx *ctx, struct gprs_rlcmac_tbf *tbf)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+ RlcMacDownlink_t *mac_control_block;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct GprsMs *ms = tbf_ms(tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ msg = msgb_alloc(GSM_MACBLOCK_LEN, "pkt_cell_chg_continue");</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!msg)</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Initialize a bit vector that uses allocated msgb as the data buffer. */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct bitvec bv = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .data = msgb_put(msg, GSM_MACBLOCK_LEN),</span><br><span style="color: hsl(120, 100%, 40%);">+ .data_len = GSM_MACBLOCK_LEN,</span><br><span style="color: hsl(120, 100%, 40%);">+ };</span><br><span style="color: hsl(120, 100%, 40%);">+ bitvec_unhex(&bv, DUMMY_VEC);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ mac_control_block = (RlcMacDownlink_t *)talloc_zero(ctx->ms, RlcMacDownlink_t);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(tbf_is_tfi_assigned(tbf));</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t tfi_is_dl = tbf_direction(tbf) == GPRS_RLCMAC_DL_TBF;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t tfi = tbf_tfi(tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t container_id = 0; /* FIXME: don't hardcode */</span><br><span style="color: hsl(120, 100%, 40%);">+ write_packet_cell_change_continue(mac_control_block, tfi_is_dl, tfi, true,</span><br><span style="color: hsl(120, 100%, 40%);">+ ctx->req_arfcn, ctx->req_bsic, container_id);</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DNACC, LOGL_DEBUG, "+++++++++++++++++++++++++ TX : Packet Cell Change Continue +++++++++++++++++++++++++\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = encode_gsm_rlcmac_downlink(&bv, mac_control_block);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DTBF, LOGL_ERROR, "Encoding of Packet Cell Change Continue failed (%d)\n", rc);</span><br><span style="color: hsl(120, 100%, 40%);">+ goto free_ret;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DNACC, LOGL_DEBUG, "------------------------- TX : Packet Cell Change Continue -------------------------\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ rate_ctr_inc(&bts_rate_counters(ms->bts)->ctr[CTR_PKT_CELL_CHG_CONTINUE]);</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(mac_control_block);</span><br><span style="color: hsl(120, 100%, 40%);">+ return msg;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+free_ret:</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(mac_control_block);</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void st_initial(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct nacc_fsm_ctx *ctx = (struct nacc_fsm_ctx *)fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+ Packet_Cell_Change_Notification_t *notif;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (event) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case NACC_EV_CELL_CHG_NOTIFICATION:</span><br><span style="color: hsl(120, 100%, 40%);">+ notif = (Packet_Cell_Change_Notification_t *)data;</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (notif->Target_Cell.UnionType) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case 0: /* GSM */</span><br><span style="color: hsl(120, 100%, 40%);">+ ctx->req_arfcn = notif->Target_Cell.u.Target_Cell_GSM_Notif.ARFCN;</span><br><span style="color: hsl(120, 100%, 40%);">+ ctx->req_bsic = notif->Target_Cell.u.Target_Cell_GSM_Notif.BSIC;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* TODO: look up in resolution table whether we already have RAC+CI for ARFCN+BSIC */</span><br><span style="color: hsl(120, 100%, 40%);">+ nacc_fsm_state_chg(fi, NACC_ST_WAIT_RESOLVE_RAC_CI);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGPFSML(fi, LOGL_NOTICE, "TargetCell type=0x%x not supported\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ notif->Target_Cell.UnionType);</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(0);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void st_wait_resolve_rac_ci_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct nacc_fsm_ctx *ctx = (struct nacc_fsm_ctx *)fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gprs_rlcmac_bts *bts = ctx->ms->bts;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ctrl_cmd *cmd;</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ cmd = ctrl_cmd_create(ctx, CTRL_TYPE_GET);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!cmd) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGPFSML(fi, LOGL_ERROR, "CTRL msg creation failed\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ cmd->id = talloc_asprintf(cmd, "1");</span><br><span style="color: hsl(120, 100%, 40%);">+ cmd->variable = talloc_asprintf(cmd, "neighbor_resolve_cgi_ps_from_lac_ci.%d.%d.%d.%d",</span><br><span style="color: hsl(120, 100%, 40%);">+ bts->cgi_ps.rai.lac.lac, bts->cgi_ps.cell_identity,</span><br><span style="color: hsl(120, 100%, 40%);">+ ctx->req_arfcn, ctx->req_bsic);</span><br><span style="color: hsl(120, 100%, 40%);">+ //rep->value = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = ctrl_cmd_send(&ctx->neigh_ctrl_conn->write_queue, cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc)</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGPFSML(fi, LOGL_ERROR, "CTRL msg sent failed: %d\n", rc);</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void st_wait_resolve_rac_ci(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ //struct nacc_fsm_ctx *ctx = (struct nacc_fsm_ctx *)fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (event) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case NACC_EV_CELL_CHG_NOTIFICATION:</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case NACC_EV_RX_RESOLVE_RAC_CI:</span><br><span style="color: hsl(120, 100%, 40%);">+ nacc_fsm_state_chg(fi, NACC_ST_WAIT_REQUEST_SI);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(0);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int fill_rim_ran_info_req(struct nacc_fsm_ctx *ctx, struct bssgp_ran_information_pdu *pdu)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gprs_rlcmac_bts *bts = ctx->ms->bts;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ *pdu = (struct bssgp_ran_information_pdu){</span><br><span style="color: hsl(120, 100%, 40%);">+ .routing_info_dest = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .discr = BSSGP_RIM_ROUTING_INFO_GERAN,</span><br><span style="color: hsl(120, 100%, 40%);">+ .geran = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .raid = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .mcc = ctx->cgi_ps.rai.lac.plmn.mcc,</span><br><span style="color: hsl(120, 100%, 40%);">+ .mnc = ctx->cgi_ps.rai.lac.plmn.mnc,</span><br><span style="color: hsl(120, 100%, 40%);">+ .mnc_3_digits = ctx->cgi_ps.rai.lac.plmn.mnc_3_digits,</span><br><span style="color: hsl(120, 100%, 40%);">+ .lac = ctx->cgi_ps.rai.lac.lac,</span><br><span style="color: hsl(120, 100%, 40%);">+ .rac = ctx->cgi_ps.rai.rac,</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span style="color: hsl(120, 100%, 40%);">+ .cid = ctx->cgi_ps.cell_identity,</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span style="color: hsl(120, 100%, 40%);">+ .routing_info_src = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .discr = BSSGP_RIM_ROUTING_INFO_GERAN,</span><br><span style="color: hsl(120, 100%, 40%);">+ .geran = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .raid = { /* TODO: fill properly */</span><br><span style="color: hsl(120, 100%, 40%);">+ .mcc = bts->cgi_ps.rai.lac.plmn.mcc,</span><br><span style="color: hsl(120, 100%, 40%);">+ .mnc = bts->cgi_ps.rai.lac.plmn.mnc,</span><br><span style="color: hsl(120, 100%, 40%);">+ .mnc_3_digits = bts->cgi_ps.rai.lac.plmn.mnc_3_digits,</span><br><span style="color: hsl(120, 100%, 40%);">+ .lac = bts->cgi_ps.rai.lac.lac,</span><br><span style="color: hsl(120, 100%, 40%);">+ .rac = bts->cgi_ps.rai.rac,</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span style="color: hsl(120, 100%, 40%);">+ .cid = bts->cgi_ps.cell_identity,</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span style="color: hsl(120, 100%, 40%);">+ .rim_cont_iei = BSSGP_IE_RI_REQ_RIM_CONTAINER,</span><br><span style="color: hsl(120, 100%, 40%);">+ .decoded_present = true,</span><br><span style="color: hsl(120, 100%, 40%);">+ .decoded = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .req_rim_cont = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .app_id = BSSGP_RAN_INF_APP_ID_NACC,</span><br><span style="color: hsl(120, 100%, 40%);">+ .seq_num = 1,</span><br><span style="color: hsl(120, 100%, 40%);">+ .pdu_ind = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .ack_requested = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+ .pdu_type_ext = 1,</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span style="color: hsl(120, 100%, 40%);">+ .prot_ver = 1,</span><br><span style="color: hsl(120, 100%, 40%);">+ .son_trans_app_id = NULL,</span><br><span style="color: hsl(120, 100%, 40%);">+ .son_trans_app_id_len = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+ .u = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .app_cont_nacc = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .reprt_cell = ctx->cgi_ps,</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span style="color: hsl(120, 100%, 40%);">+ };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* At this point, we expect correct tgt cell info to be already in ctx->cgi_ps */</span><br><span style="color: hsl(120, 100%, 40%);">+static void st_wait_request_si_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct nacc_fsm_ctx *ctx = (struct nacc_fsm_ctx *)fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct bssgp_ran_information_pdu pdu;</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (fill_rim_ran_info_req(ctx, &pdu) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = bssgp_tx_rim(&pdu, gprs_ns2_nse_nsei(ctx->ms->bts->nse));</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGPFSML(fi, LOGL_ERROR, "Failed transmitting RIM PDU: %d\n", rc);</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fsm_inst_dispatch(fi, NACC_EV_SI_INFO_RECEIVED, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void st_wait_request_si(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ //struct nacc_fsm_ctx *ctx = (struct nacc_fsm_ctx *)fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (event) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case NACC_EV_SI_INFO_RECEIVED:</span><br><span style="color: hsl(120, 100%, 40%);">+ /* TODO: In here we'll parse RIM response */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Tell the PCU scheduler we are ready to go, from here one we</span><br><span style="color: hsl(120, 100%, 40%);">+ * are polled/driven by the scheduler */</span><br><span style="color: hsl(120, 100%, 40%);">+ nacc_fsm_state_chg(fi, NACC_ST_TX_NEIGHBOUR_DATA);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(0);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void st_tx_neighbour_data_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ /* At this point, we already received all required RIM messages or we</span><br><span style="color: hsl(120, 100%, 40%);">+ have them cached. We now wait for scheduler to ask us to construct</span><br><span style="color: hsl(120, 100%, 40%);">+ RLCMAC DL CTRL messages to move FSM states forward */</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void st_tx_neighbour_data(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct nacc_fsm_ctx *ctx = (struct nacc_fsm_ctx *)fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct nacc_ev_create_rlcmac_msg_ctx *data_ctx;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (event) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case NACC_EV_CREATE_RLCMAC_MSG:</span><br><span style="color: hsl(120, 100%, 40%);">+ data_ctx = (struct nacc_ev_create_rlcmac_msg_ctx *)data;</span><br><span style="color: hsl(120, 100%, 40%);">+ data_ctx->msg = create_packet_neighbour_cell_data(ctx, data_ctx->tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* TODO: logic if no more Neighbour cell data messages need to be send, then: */</span><br><span style="color: hsl(120, 100%, 40%);">+ nacc_fsm_state_chg(fi, NACC_ST_TX_CELL_CHG_CONTINUE);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(0);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void st_cell_cgh_continue_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ /* At this point, we already sent all Pkt Cell Neighbour Change rlcmac</span><br><span style="color: hsl(120, 100%, 40%);">+ blocks, and we only need to wait to be scheduled again to send PKT</span><br><span style="color: hsl(120, 100%, 40%);">+ CELL CHANGE NOTIFICATION */</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void st_cell_cgh_continue(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct nacc_fsm_ctx *ctx = (struct nacc_fsm_ctx *)fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct nacc_ev_create_rlcmac_msg_ctx *data_ctx;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (event) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case NACC_EV_CREATE_RLCMAC_MSG:</span><br><span style="color: hsl(120, 100%, 40%);">+ data_ctx = (struct nacc_ev_create_rlcmac_msg_ctx *)data;</span><br><span style="color: hsl(120, 100%, 40%);">+ data_ctx->msg = create_packet_cell_chg_continue(ctx, data_ctx->tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* TODO: logic if no more Neighbour cell data messages need to be send, then: */</span><br><span style="color: hsl(120, 100%, 40%);">+ nacc_fsm_state_chg(fi, NACC_ST_DONE);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(0);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void st_done_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void nacc_fsm_cleanup(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct nacc_fsm_ctx *ctx = (struct nacc_fsm_ctx *)fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* afte rcleanup() finishes, FSM termination calls osmo_fsm_inst_free,</span><br><span style="color: hsl(120, 100%, 40%);">+ so we need to avoid double-freeing it during ctx talloc free</span><br><span style="color: hsl(120, 100%, 40%);">+ destructor */</span><br><span style="color: hsl(120, 100%, 40%);">+ //talloc_reparent(ctx, ctx->ms, ctx->fi);</span><br><span style="color: hsl(120, 100%, 40%);">+ ctx->fi = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* remove references from owning MS and free entire ctx */</span><br><span style="color: hsl(120, 100%, 40%);">+ ctx->ms->nacc = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(ctx);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct osmo_fsm_state nacc_fsm_states[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ [NACC_ST_INITIAL] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .in_event_mask =</span><br><span style="color: hsl(120, 100%, 40%);">+ X(NACC_EV_CELL_CHG_NOTIFICATION),</span><br><span style="color: hsl(120, 100%, 40%);">+ .out_state_mask =</span><br><span style="color: hsl(120, 100%, 40%);">+ X(NACC_ST_WAIT_RESOLVE_RAC_CI) |</span><br><span style="color: hsl(120, 100%, 40%);">+ X(NACC_ST_WAIT_REQUEST_SI) |</span><br><span style="color: hsl(120, 100%, 40%);">+ X(NACC_ST_TX_NEIGHBOUR_DATA),</span><br><span style="color: hsl(120, 100%, 40%);">+ .name = "INITIAL",</span><br><span style="color: hsl(120, 100%, 40%);">+ //.onenter = st_initial_on_enter,</span><br><span style="color: hsl(120, 100%, 40%);">+ .action = st_initial,</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span style="color: hsl(120, 100%, 40%);">+ [NACC_ST_WAIT_RESOLVE_RAC_CI] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .in_event_mask =</span><br><span style="color: hsl(120, 100%, 40%);">+ X(NACC_EV_RX_RESOLVE_RAC_CI),</span><br><span style="color: hsl(120, 100%, 40%);">+ .out_state_mask =</span><br><span style="color: hsl(120, 100%, 40%);">+ X(NACC_ST_WAIT_REQUEST_SI) |</span><br><span style="color: hsl(120, 100%, 40%);">+ X(NACC_ST_TX_CELL_CHG_CONTINUE),</span><br><span style="color: hsl(120, 100%, 40%);">+ .name = "WAIT_RESOLVE_RAC_CI",</span><br><span style="color: hsl(120, 100%, 40%);">+ .onenter = st_wait_resolve_rac_ci_on_enter,</span><br><span style="color: hsl(120, 100%, 40%);">+ .action = st_wait_resolve_rac_ci,</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span style="color: hsl(120, 100%, 40%);">+ [NACC_ST_WAIT_REQUEST_SI] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .in_event_mask =</span><br><span style="color: hsl(120, 100%, 40%);">+ X(NACC_EV_CELL_CHG_NOTIFICATION) |</span><br><span style="color: hsl(120, 100%, 40%);">+ X(NACC_EV_SI_INFO_RECEIVED),</span><br><span style="color: hsl(120, 100%, 40%);">+ .out_state_mask =</span><br><span style="color: hsl(120, 100%, 40%);">+ X(NACC_ST_TX_NEIGHBOUR_DATA),</span><br><span style="color: hsl(120, 100%, 40%);">+ .name = "WAIT_REQUEST_SI",</span><br><span style="color: hsl(120, 100%, 40%);">+ .onenter = st_wait_request_si_on_enter,</span><br><span style="color: hsl(120, 100%, 40%);">+ .action = st_wait_request_si,</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span style="color: hsl(120, 100%, 40%);">+ [NACC_ST_TX_NEIGHBOUR_DATA] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .in_event_mask =</span><br><span style="color: hsl(120, 100%, 40%);">+ X(NACC_EV_CELL_CHG_NOTIFICATION) |</span><br><span style="color: hsl(120, 100%, 40%);">+ X(NACC_EV_SI_INFO_RECEIVED) |</span><br><span style="color: hsl(120, 100%, 40%);">+ X(NACC_EV_CREATE_RLCMAC_MSG),</span><br><span style="color: hsl(120, 100%, 40%);">+ .out_state_mask =</span><br><span style="color: hsl(120, 100%, 40%);">+ X(NACC_ST_TX_CELL_CHG_CONTINUE),</span><br><span style="color: hsl(120, 100%, 40%);">+ .name = "TX_NEIGHBOUR_DATA",</span><br><span style="color: hsl(120, 100%, 40%);">+ .onenter = st_tx_neighbour_data_on_enter,</span><br><span style="color: hsl(120, 100%, 40%);">+ .action = st_tx_neighbour_data,</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span style="color: hsl(120, 100%, 40%);">+ [NACC_ST_TX_CELL_CHG_CONTINUE] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .in_event_mask =</span><br><span style="color: hsl(120, 100%, 40%);">+ X(NACC_EV_CELL_CHG_NOTIFICATION) |</span><br><span style="color: hsl(120, 100%, 40%);">+ X(NACC_EV_SI_INFO_RECEIVED) |</span><br><span style="color: hsl(120, 100%, 40%);">+ X(NACC_EV_CREATE_RLCMAC_MSG),</span><br><span style="color: hsl(120, 100%, 40%);">+ .out_state_mask =</span><br><span style="color: hsl(120, 100%, 40%);">+ X(NACC_ST_DONE),</span><br><span style="color: hsl(120, 100%, 40%);">+ .name = "TX_CELL_CHG_CONTINUE",</span><br><span style="color: hsl(120, 100%, 40%);">+ .onenter = st_cell_cgh_continue_on_enter,</span><br><span style="color: hsl(120, 100%, 40%);">+ .action = st_cell_cgh_continue,</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span style="color: hsl(120, 100%, 40%);">+ [NACC_ST_DONE] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .in_event_mask = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+ .out_state_mask = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+ .name = "DONE",</span><br><span style="color: hsl(120, 100%, 40%);">+ .onenter = st_done_on_enter,</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct osmo_fsm nacc_fsm = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .name = "NACC",</span><br><span style="color: hsl(120, 100%, 40%);">+ .states = nacc_fsm_states,</span><br><span style="color: hsl(120, 100%, 40%);">+ .num_states = ARRAY_SIZE(nacc_fsm_states),</span><br><span style="color: hsl(120, 100%, 40%);">+ .cleanup = nacc_fsm_cleanup,</span><br><span style="color: hsl(120, 100%, 40%);">+ .log_subsys = DNACC,</span><br><span style="color: hsl(120, 100%, 40%);">+ .event_names = nacc_fsm_event_names,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static __attribute__((constructor)) void nacc_fsm_init(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(osmo_fsm_register(&nacc_fsm) == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void nacc_fsm_ctrl_reply_cb(struct ctrl_handle *ctrl, struct ctrl_cmd *cmd, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct nacc_fsm_ctx *ctx = (struct nacc_fsm_ctx *)data;</span><br><span style="color: hsl(120, 100%, 40%);">+ char *tmp = NULL, *tok, *saveptr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGPFSML(ctx->fi, LOGL_NOTICE, "Received CTRL message: type=%d %s: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ cmd->type, cmd->variable, osmo_escape_str(cmd->reply, -1));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (cmd->type != CTRL_TYPE_GET_REPLY || !cmd->reply) {</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fsm_inst_term(ctx->fi, OSMO_FSM_TERM_ERROR, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* TODO: Potentially validate cmd->variable contains same params as we</span><br><span style="color: hsl(120, 100%, 40%);">+ sent, and that cmd->id matches the original set. We may want to keep</span><br><span style="color: hsl(120, 100%, 40%);">+ the original cmd around by setting cmd->defer=1 when sending it. */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ tmp = talloc_strdup(cmd, cmd->reply);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!tmp)</span><br><span style="color: hsl(120, 100%, 40%);">+ goto free_ret;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!(tok = strtok_r(tmp, "-", &saveptr)))</span><br><span style="color: hsl(120, 100%, 40%);">+ goto free_ret;</span><br><span style="color: hsl(120, 100%, 40%);">+ ctx->cgi_ps.rai.lac.plmn.mcc = atoi(tok);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!(tok = strtok_r(NULL, "-", &saveptr)))</span><br><span style="color: hsl(120, 100%, 40%);">+ goto free_ret;</span><br><span style="color: hsl(120, 100%, 40%);">+ ctx->cgi_ps.rai.lac.plmn.mnc = atoi(tok);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!(tok = strtok_r(NULL, "-", &saveptr)))</span><br><span style="color: hsl(120, 100%, 40%);">+ goto free_ret;</span><br><span style="color: hsl(120, 100%, 40%);">+ ctx->cgi_ps.rai.lac.lac = atoi(tok);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!(tok = strtok_r(NULL, "-", &saveptr)))</span><br><span style="color: hsl(120, 100%, 40%);">+ goto free_ret;</span><br><span style="color: hsl(120, 100%, 40%);">+ ctx->cgi_ps.rai.rac = atoi(tok);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!(tok = strtok_r(NULL, "\0", &saveptr)))</span><br><span style="color: hsl(120, 100%, 40%);">+ goto free_ret;</span><br><span style="color: hsl(120, 100%, 40%);">+ ctx->cgi_ps.cell_identity = atoi(tok);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ // TODO: cache the cgi_ps so we can avoid requesting again same resolution</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fsm_inst_dispatch(ctx->fi, NACC_EV_RX_RESOLVE_RAC_CI, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+free_ret:</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(tmp);</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fsm_inst_term(ctx->fi, OSMO_FSM_TERM_ERROR, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int nacc_fsm_ctx_talloc_destructor(struct nacc_fsm_ctx *ctx)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ctx->fi) {</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fsm_inst_free(ctx->fi);</span><br><span style="color: hsl(120, 100%, 40%);">+ ctx->fi = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ctx->neigh_ctrl_conn) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ctx->neigh_ctrl_conn->write_queue.bfd.fd != -1) {</span><br><span style="color: hsl(120, 100%, 40%);">+ close(ctx->neigh_ctrl_conn->write_queue.bfd.fd);</span><br><span style="color: hsl(120, 100%, 40%);">+ ctx->neigh_ctrl_conn->write_queue.bfd.fd = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct nacc_fsm_ctx *nacc_fsm_alloc(struct GprsMs* ms)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gprs_rlcmac_bts *bts = ms->bts;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gprs_pcu *pcu = bts->pcu;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct nacc_fsm_ctx *ctx = talloc_zero(ms, struct nacc_fsm_ctx);</span><br><span style="color: hsl(120, 100%, 40%);">+ char buf[64];</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_set_destructor(ctx, nacc_fsm_ctx_talloc_destructor);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ctx->ms = ms;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ snprintf(buf, sizeof(buf), "TLLI-0x%08x", ms_tlli(ms));</span><br><span style="color: hsl(120, 100%, 40%);">+ ctx->fi = osmo_fsm_inst_alloc(&nacc_fsm, ctx, ctx, LOGL_INFO, buf);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ctx->fi)</span><br><span style="color: hsl(120, 100%, 40%);">+ goto free_ret;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ctx->neigh_ctrl = ctrl_handle_alloc(ctx, ctx, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ ctx->neigh_ctrl->reply_cb = nacc_fsm_ctrl_reply_cb;</span><br><span style="color: hsl(120, 100%, 40%);">+ ctx->neigh_ctrl_conn = osmo_ctrl_conn_alloc(ctx, ctx->neigh_ctrl);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ctx->neigh_ctrl_conn)</span><br><span style="color: hsl(120, 100%, 40%);">+ goto free_ret;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = osmo_sock_init2_ofd(&ctx->neigh_ctrl_conn->write_queue.bfd, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP,</span><br><span style="color: hsl(120, 100%, 40%);">+ NULL, 0, pcu->vty.neigh_ctrl_addr, pcu->vty.neigh_ctrl_port,</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_SOCK_F_CONNECT);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DNACC, LOGL_ERROR, "Can't connect to CTRL @ %s:%u\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ pcu->vty.neigh_ctrl_addr, pcu->vty.neigh_ctrl_port);</span><br><span style="color: hsl(120, 100%, 40%);">+ goto free_ret;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return ctx;</span><br><span style="color: hsl(120, 100%, 40%);">+free_ret:</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(ctx);</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/nacc_fsm.h b/src/nacc_fsm.h</span><br><span>new file mode 100644</span><br><span>index 0000000..21c22ce</span><br><span>--- /dev/null</span><br><span>+++ b/src/nacc_fsm.h</span><br><span>@@ -0,0 +1,41 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#pragma once</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/fsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/gsm23003.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct GprsMs;</span><br><span style="color: hsl(120, 100%, 40%);">+struct gprs_rlcmac_tbf;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum nacc_fsm_event {</span><br><span style="color: hsl(120, 100%, 40%);">+ NACC_EV_CELL_CHG_NOTIFICATION, /* data: Packet_Cell_Change_Notification_t* */</span><br><span style="color: hsl(120, 100%, 40%);">+ NACC_EV_RX_RESOLVE_RAC_CI, /* data: ctrl msg resp */</span><br><span style="color: hsl(120, 100%, 40%);">+ NACC_EV_SI_INFO_RECEIVED,</span><br><span style="color: hsl(120, 100%, 40%);">+ NACC_EV_CREATE_RLCMAC_MSG,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum nacc_fsm_states {</span><br><span style="color: hsl(120, 100%, 40%);">+ NACC_ST_INITIAL,</span><br><span style="color: hsl(120, 100%, 40%);">+ NACC_ST_WAIT_RESOLVE_RAC_CI,</span><br><span style="color: hsl(120, 100%, 40%);">+ NACC_ST_WAIT_REQUEST_SI,</span><br><span style="color: hsl(120, 100%, 40%);">+ NACC_ST_TX_NEIGHBOUR_DATA,</span><br><span style="color: hsl(120, 100%, 40%);">+ NACC_ST_TX_CELL_CHG_CONTINUE,</span><br><span style="color: hsl(120, 100%, 40%);">+ NACC_ST_DONE,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct nacc_fsm_ctx {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_fsm_inst *fi;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct GprsMs* ms; /* back pointer */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ctrl_handle *neigh_ctrl;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ctrl_connection *neigh_ctrl_conn;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t req_arfcn;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t req_bsic;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_cell_global_id_ps cgi_ps; /* target SGSN, resolved from req_{arfcn+bsic} */</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* passed as data in NACC_EV_CREATE_RLCMAC_MSG */</span><br><span style="color: hsl(120, 100%, 40%);">+struct nacc_ev_create_rlcmac_msg_ctx {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gprs_rlcmac_tbf *tbf; /* target tbf to create messages for */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct msgb *msg; /* to be filled by FSM duringe event processing */</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct nacc_fsm_ctx *nacc_fsm_alloc(struct GprsMs* ms);</span><br><span>diff --git a/src/pcu_vty.c b/src/pcu_vty.c</span><br><span>index 288f241..b7021c8 100644</span><br><span>--- a/src/pcu_vty.c</span><br><span>+++ b/src/pcu_vty.c</span><br><span>@@ -14,6 +14,7 @@</span><br><span> #include <osmocom/vty/misc.h></span><br><span> #include <osmocom/core/linuxlist.h></span><br><span> #include <osmocom/core/rate_ctr.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/ctrl/ports.h></span><br><span> #include <osmocom/pcu/pcuif_proto.h></span><br><span> #include <osmocom/gprs/gprs_ns2.h></span><br><span> #include "pcu_vty.h"</span><br><span>@@ -1018,6 +1019,22 @@</span><br><span> return CMD_SUCCESS;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_neighbor_resolution, cfg_neighbor_resolution_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+ "neighbor resolution " VTY_IPV46_CMD " [<0-65535>]",</span><br><span style="color: hsl(120, 100%, 40%);">+ "Manage local and remote-BSS neighbor cells\n"</span><br><span style="color: hsl(120, 100%, 40%);">+ "Connect to Neighbor Resolution Service (CTRL interface) to given ip and port\n"</span><br><span style="color: hsl(120, 100%, 40%);">+ "IPv4 address to connect to\n" "IPv6 address to connect to\n"</span><br><span style="color: hsl(120, 100%, 40%);">+ "Port to connect to (default 4248)\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_talloc_replace_string(the_pcu, &the_pcu->vty.neigh_ctrl_addr, argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (argc > 1)</span><br><span style="color: hsl(120, 100%, 40%);">+ the_pcu->vty.neigh_ctrl_port = atoi(argv[1]);</span><br><span style="color: hsl(120, 100%, 40%);">+ else</span><br><span style="color: hsl(120, 100%, 40%);">+ the_pcu->vty.neigh_ctrl_port = OSMO_CTRL_PORT_BSC_NEIGH;</span><br><span style="color: hsl(120, 100%, 40%);">+ return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> DEFUN(show_bts_timer, show_bts_timer_cmd,</span><br><span> "show bts-timer " OSMO_TDEF_VTY_ARG_T_OPTIONAL,</span><br><span> SHOW_STR "Show BTS controlled timers\n"</span><br><span>@@ -1220,6 +1237,7 @@</span><br><span> install_element(PCU_NODE, &cfg_pcu_no_gsmtap_categ_cmd);</span><br><span> install_element(PCU_NODE, &cfg_pcu_sock_cmd);</span><br><span> install_element(PCU_NODE, &cfg_pcu_gb_dialect_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+ install_element(PCU_NODE, &cfg_neighbor_resolution_cmd);</span><br><span> install_element(PCU_NODE, &cfg_pcu_timer_cmd);</span><br><span> </span><br><span> install_element_ve(&show_bts_stats_cmd);</span><br><span>diff --git a/src/pdch.cpp b/src/pdch.cpp</span><br><span>index 5a329f3..2028ba2 100644</span><br><span>--- a/src/pdch.cpp</span><br><span>+++ b/src/pdch.cpp</span><br><span>@@ -685,6 +685,33 @@</span><br><span> gprs_rlcmac_meas_rep(ms, report);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+void gprs_rlcmac_pdch::rcv_cell_change_notification(Packet_Cell_Change_Notification_t *notif,</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t fn, struct pcu_l1_meas *meas)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ GprsMs *ms;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ bts_do_rate_ctr_inc(bts(), CTR_PKT_CELL_CHG_NOTIFICATION);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (notif->Global_TFI.UnionType == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gprs_rlcmac_ul_tbf *ul_tbf = ul_tbf_by_tfi(notif->Global_TFI.u.UPLINK_TFI);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ul_tbf) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DRLCMAC, LOGL_NOTICE, "UL TBF TFI=0x%2x not found\n", notif->Global_TFI.u.UPLINK_TFI);</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ ms = ul_tbf->ms();</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (notif->Global_TFI.UnionType == 1) {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gprs_rlcmac_dl_tbf *dl_tbf = dl_tbf_by_tfi(notif->Global_TFI.u.DOWNLINK_TFI);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!dl_tbf) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DRLCMAC, LOGL_NOTICE, "DL TBF TFI=0x%2x not found\n", notif->Global_TFI.u.DOWNLINK_TFI);</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ ms = dl_tbf->ms();</span><br><span style="color: hsl(120, 100%, 40%);">+ } else { OSMO_ASSERT(0); }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ms_update_l1_meas(ms, meas);</span><br><span style="color: hsl(120, 100%, 40%);">+ ms_nacc_start(ms, notif);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* Received Uplink RLC control block. */</span><br><span> int gprs_rlcmac_pdch::rcv_control_block(const uint8_t *data, uint8_t data_len,</span><br><span> uint32_t fn, struct pcu_l1_meas *meas, enum CodingScheme cs)</span><br><span>@@ -734,6 +761,9 @@</span><br><span> case MT_PACKET_UPLINK_DUMMY_CONTROL_BLOCK:</span><br><span> /* ignoring it. change the SI to not force sending these? */</span><br><span> break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case MT_PACKET_CELL_CHANGE_NOTIFICATION:</span><br><span style="color: hsl(120, 100%, 40%);">+ rcv_cell_change_notification(&ul_control_block->u.Packet_Cell_Change_Notification, fn, meas);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span> default:</span><br><span> bts_do_rate_ctr_inc(bts(), CTR_DECODE_ERRORS);</span><br><span> LOGP(DRLCMAC, LOGL_NOTICE,</span><br><span>diff --git a/src/pdch.h b/src/pdch.h</span><br><span>index 8871986..d596531 100644</span><br><span>--- a/src/pdch.h</span><br><span>+++ b/src/pdch.h</span><br><span>@@ -139,6 +139,7 @@</span><br><span> void rcv_control_egprs_dl_ack_nack(EGPRS_PD_AckNack_t *, uint32_t fn, struct pcu_l1_meas *meas);</span><br><span> void rcv_resource_request(Packet_Resource_Request_t *t, uint32_t fn, struct pcu_l1_meas *meas);</span><br><span> void rcv_measurement_report(Packet_Measurement_Report_t *t, uint32_t fn);</span><br><span style="color: hsl(120, 100%, 40%);">+ void rcv_cell_change_notification(Packet_Cell_Change_Notification_t *, uint32_t fn, struct pcu_l1_meas *meas);</span><br><span> gprs_rlcmac_tbf *tbf_from_list_by_tfi(</span><br><span> LListHead<gprs_rlcmac_tbf> *tbf_list, uint8_t tfi,</span><br><span> enum gprs_rlcmac_tbf_direction dir);</span><br><span>diff --git a/src/tbf.cpp b/src/tbf.cpp</span><br><span>index 37af21f..5b2fe3d 100644</span><br><span>--- a/src/tbf.cpp</span><br><span>+++ b/src/tbf.cpp</span><br><span>@@ -1197,3 +1197,8 @@</span><br><span> {</span><br><span> return tbf->is_tfi_assigned();</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+uint8_t tbf_tfi(const struct gprs_rlcmac_tbf *tbf)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ return tbf->tfi();</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/tbf.h b/src/tbf.h</span><br><span>index d616076..815d254 100644</span><br><span>--- a/src/tbf.h</span><br><span>+++ b/src/tbf.h</span><br><span>@@ -204,6 +204,7 @@</span><br><span> uint8_t tbf_dl_slots(const struct gprs_rlcmac_tbf *tbf);</span><br><span> uint8_t tbf_ul_slots(const struct gprs_rlcmac_tbf *tbf);</span><br><span> bool tbf_is_tfi_assigned(const struct gprs_rlcmac_tbf *tbf);</span><br><span style="color: hsl(120, 100%, 40%);">+uint8_t tbf_tfi(const struct gprs_rlcmac_tbf *tbf);</span><br><span> int tbf_assign_control_ts(struct gprs_rlcmac_tbf *tbf);</span><br><span> #ifdef __cplusplus</span><br><span> }</span><br><span>diff --git a/tests/Makefile.am b/tests/Makefile.am</span><br><span>index c599636..a7771b9 100644</span><br><span>--- a/tests/Makefile.am</span><br><span>+++ b/tests/Makefile.am</span><br><span>@@ -1,4 +1,4 @@</span><br><span style="color: hsl(0, 100%, 40%);">-AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGB_CFLAGS) $(LIBOSMOGSM_CFLAGS) -I$(top_srcdir)/src/ -I$(top_srcdir)/include/</span><br><span style="color: hsl(120, 100%, 40%);">+AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(LIBOSMOCORE_CFLAGS) $(LIBOSMOCTRL_CFLAGS) $(LIBOSMOGB_CFLAGS) $(LIBOSMOGSM_CFLAGS) -I$(top_srcdir)/src/ -I$(top_srcdir)/include/</span><br><span> AM_LDFLAGS = -lrt -no-install</span><br><span> </span><br><span> check_PROGRAMS = rlcmac/RLCMACTest alloc/AllocTest alloc/MslotTest tbf/TbfTest types/TypesTest ms/MsTest llist/LListTest llc/LlcTest codel/codel_test edge/EdgeTest bitcomp/BitcompTest fn/FnTest app_info/AppInfoTest</span><br><span>@@ -15,6 +15,7 @@</span><br><span> $(top_builddir)/src/libgprs.la \</span><br><span> $(LIBOSMOGB_LIBS) \</span><br><span> $(LIBOSMOGSM_LIBS) \</span><br><span style="color: hsl(120, 100%, 40%);">+ $(LIBOSMOCTRL_LIBS) \</span><br><span> $(LIBOSMOCORE_LIBS) \</span><br><span> $(COMMON_LA)</span><br><span> </span><br><span>@@ -23,6 +24,7 @@</span><br><span> $(top_builddir)/src/libgprs.la \</span><br><span> $(LIBOSMOGB_LIBS) \</span><br><span> $(LIBOSMOGSM_LIBS) \</span><br><span style="color: hsl(120, 100%, 40%);">+ $(LIBOSMOCTRL_LIBS) \</span><br><span> $(LIBOSMOCORE_LIBS) \</span><br><span> $(COMMON_LA)</span><br><span> </span><br><span>@@ -31,6 +33,7 @@</span><br><span> $(top_builddir)/src/libgprs.la \</span><br><span> $(LIBOSMOGB_LIBS) \</span><br><span> $(LIBOSMOGSM_LIBS) \</span><br><span style="color: hsl(120, 100%, 40%);">+ $(LIBOSMOCTRL_LIBS) \</span><br><span> $(LIBOSMOCORE_LIBS) \</span><br><span> $(COMMON_LA)</span><br><span> tbf_TbfTest_LDFLAGS = -Wl,--wrap=pcu_sock_send</span><br><span>@@ -38,6 +41,7 @@</span><br><span> bitcomp_BitcompTest_SOURCES = bitcomp/BitcompTest.cpp ../src/egprs_rlc_compression.cpp</span><br><span> bitcomp_BitcompTest_LDADD = \</span><br><span> $(top_builddir)/src/libgprs.la \</span><br><span style="color: hsl(120, 100%, 40%);">+ $(LIBOSMOCTRL_LIBS) \</span><br><span> $(LIBOSMOCORE_LIBS) \</span><br><span> $(COMMON_LA)</span><br><span> </span><br><span>@@ -46,6 +50,7 @@</span><br><span> $(top_builddir)/src/libgprs.la \</span><br><span> $(LIBOSMOGB_LIBS) \</span><br><span> $(LIBOSMOGSM_LIBS) \</span><br><span style="color: hsl(120, 100%, 40%);">+ $(LIBOSMOCTRL_LIBS) \</span><br><span> $(LIBOSMOCORE_LIBS) \</span><br><span> $(COMMON_LA)</span><br><span> </span><br><span>@@ -56,6 +61,7 @@</span><br><span> $(top_builddir)/src/libgprs.la \</span><br><span> $(LIBOSMOGB_LIBS) \</span><br><span> $(LIBOSMOGSM_LIBS) \</span><br><span style="color: hsl(120, 100%, 40%);">+ $(LIBOSMOCTRL_LIBS) \</span><br><span> $(LIBOSMOCORE_LIBS) \</span><br><span> $(COMMON_LA)</span><br><span> </span><br><span>@@ -64,6 +70,7 @@</span><br><span> $(top_builddir)/src/libgprs.la \</span><br><span> $(LIBOSMOGB_LIBS) \</span><br><span> $(LIBOSMOGSM_LIBS) \</span><br><span style="color: hsl(120, 100%, 40%);">+ $(LIBOSMOCTRL_LIBS) \</span><br><span> $(LIBOSMOCORE_LIBS) \</span><br><span> $(COMMON_LA)</span><br><span> </span><br><span>@@ -72,6 +79,7 @@</span><br><span> $(top_builddir)/src/libgprs.la \</span><br><span> $(LIBOSMOGB_LIBS) \</span><br><span> $(LIBOSMOGSM_LIBS) \</span><br><span style="color: hsl(120, 100%, 40%);">+ $(LIBOSMOCTRL_LIBS) \</span><br><span> $(LIBOSMOCORE_LIBS) \</span><br><span> $(COMMON_LA)</span><br><span> </span><br><span>@@ -83,6 +91,7 @@</span><br><span> $(top_builddir)/src/libgprs.la \</span><br><span> $(LIBOSMOGB_LIBS) \</span><br><span> $(LIBOSMOGSM_LIBS) \</span><br><span style="color: hsl(120, 100%, 40%);">+ $(LIBOSMOCTRL_LIBS) \</span><br><span> $(LIBOSMOCORE_LIBS) \</span><br><span> $(COMMON_LA)</span><br><span> </span><br><span>@@ -97,6 +106,7 @@</span><br><span> codel_codel_test_SOURCES = codel/codel_test.c</span><br><span> codel_codel_test_LDADD = \</span><br><span> $(top_builddir)/src/libgprs.la \</span><br><span style="color: hsl(120, 100%, 40%);">+ $(LIBOSMOCTRL_LIBS) \</span><br><span> $(LIBOSMOCORE_LIBS) \</span><br><span> $(COMMON_LA)</span><br><span> </span><br><span>@@ -105,6 +115,7 @@</span><br><span> $(top_builddir)/src/libgprs.la \</span><br><span> $(LIBOSMOGB_LIBS) \</span><br><span> $(LIBOSMOGSM_LIBS) \</span><br><span style="color: hsl(120, 100%, 40%);">+ $(LIBOSMOCTRL_LIBS) \</span><br><span> $(LIBOSMOCORE_LIBS) \</span><br><span> $(COMMON_LA)</span><br><span> </span><br><span>@@ -113,6 +124,7 @@</span><br><span> $(top_builddir)/src/libgprs.la \</span><br><span> $(LIBOSMOGB_LIBS) \</span><br><span> $(LIBOSMOGSM_LIBS) \</span><br><span style="color: hsl(120, 100%, 40%);">+ $(LIBOSMOCTRL_LIBS) \</span><br><span> $(LIBOSMOCORE_LIBS) \</span><br><span> $(COMMON_LA)</span><br><span> </span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-pcu/+/22338">change 22338</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/osmo-pcu/+/22338"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: osmo-pcu </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: Ife6e4a086d58d49676d12b6984f63079ec472e79 </div>
<div style="display:none"> Gerrit-Change-Number: 22338 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>