<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>