<p>Harald Welte has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/libosmocore/+/14360">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">WIP: CBSP (3GPP TS 48.049) support<br><br>This introduces definitions as well as a parser/encoder for the<br>Cell Broadcast Service Protocol (CBSP) as specified in 3GPP TS 48.049.<br><br>CBSP is used on the interface between CBC and BSC.<br><br>Related: OS#3537<br>Change-Id: I5b7ae08f67e415967b60ac4b824db9e22ca00935<br>---<br>M include/Makefile.am<br>A include/osmocom/gsm/cbsp.h<br>A include/osmocom/gsm/protocol/gsm_48_049.h<br>M src/gsm/Makefile.am<br>A src/gsm/cbsp.c<br>A src/gsm/gsm48049.c<br>M src/gsm/libosmogsm.map<br>7 files changed, 1,697 insertions(+), 1 deletion(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/60/14360/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/Makefile.am b/include/Makefile.am</span><br><span>index 7b9e347..7835fab 100644</span><br><span>--- a/include/Makefile.am</span><br><span>+++ b/include/Makefile.am</span><br><span>@@ -72,6 +72,7 @@</span><br><span>                        osmocom/gsm/abis_nm.h \</span><br><span>                        osmocom/gsm/apn.h \</span><br><span>                        osmocom/gsm/bts_features.h \</span><br><span style="color: hsl(120, 100%, 40%);">+                       osmocom/gsm/cbsp.h \</span><br><span>                        osmocom/gsm/comp128.h \</span><br><span>                        osmocom/gsm/comp128v23.h \</span><br><span>                        osmocom/gsm/bitvec_gsm.h \</span><br><span>@@ -124,6 +125,7 @@</span><br><span>                 osmocom/gsm/protocol/gsm_23_003.h \</span><br><span>                  osmocom/gsm/protocol/gsm_29_118.h \</span><br><span>                        osmocom/gsm/protocol/gsm_44_318.h \</span><br><span style="color: hsl(120, 100%, 40%);">+                       osmocom/gsm/protocol/gsm_48_049.h \</span><br><span>                        osmocom/gsm/protocol/ipaccess.h \</span><br><span>                        osmocom/gsm/protocol/smpp34_osmocom.h \</span><br><span>                        osmocom/gsm/rsl.h \</span><br><span>diff --git a/include/osmocom/gsm/cbsp.h b/include/osmocom/gsm/cbsp.h</span><br><span>new file mode 100644</span><br><span>index 0000000..4a76d5a</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/gsm/cbsp.h</span><br><span>@@ -0,0 +1,262 @@</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 <stdint.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/linuxlist.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/protocol/gsm_48_049.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/gsm0808_utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Decoded 8.2.3 Message Content */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_cbsp_content {</span><br><span style="color: hsl(120, 100%, 40%);">+     struct llist_head list;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint8_t user_len;</span><br><span style="color: hsl(120, 100%, 40%);">+     uint8_t data[82];</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%);">+/* Decoded Entry in a 8.2.6 Cell List */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_cbsp_cell_ent {</span><br><span style="color: hsl(120, 100%, 40%);">+        struct llist_head list;</span><br><span style="color: hsl(120, 100%, 40%);">+       union gsm0808_cell_id_u cell_id;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_cbsp_cell_list {</span><br><span style="color: hsl(120, 100%, 40%);">+    enum CELL_IDENT id_discr;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct llist_head list;</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%);">+/* Decoded Entry in a 8.2.10 Completed List */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_cbsp_num_compl_ent {</span><br><span style="color: hsl(120, 100%, 40%);">+       struct llist_head list;</span><br><span style="color: hsl(120, 100%, 40%);">+       union gsm0808_cell_id_u cell_id;</span><br><span style="color: hsl(120, 100%, 40%);">+      uint16_t num_compl;</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t num_bcast_info;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_cbsp_num_compl_list {</span><br><span style="color: hsl(120, 100%, 40%);">+        enum CELL_IDENT id_discr;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct llist_head list; /* osmo_cbsp_num_compl_ent */</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%);">+/* Decoded Entry in a 8.2.12 Radio Resource Loading List */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_cbsp_loading_ent {</span><br><span style="color: hsl(120, 100%, 40%);">+      struct llist_head list;</span><br><span style="color: hsl(120, 100%, 40%);">+       union gsm0808_cell_id_u cell_id;</span><br><span style="color: hsl(120, 100%, 40%);">+      uint8_t load[2];</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_cbsp_loading_list {</span><br><span style="color: hsl(120, 100%, 40%);">+ enum CELL_IDENT id_discr;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct llist_head list;</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%);">+/* Decoded Entry in a 8.2.11 Failure List */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_cbsp_fail_ent {</span><br><span style="color: hsl(120, 100%, 40%);">+      struct llist_head list;</span><br><span style="color: hsl(120, 100%, 40%);">+       enum CELL_IDENT id_discr;</span><br><span style="color: hsl(120, 100%, 40%);">+     union gsm0808_cell_id_u cell_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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* 8.1.3.1 */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_cbsp_write_replace {</span><br><span style="color: hsl(120, 100%, 40%);">+     uint16_t msg_id;                /* 8.2.16 M */</span><br><span style="color: hsl(120, 100%, 40%);">+        uint16_t new_serial_nr;         /* 8.2.5 M */</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t *old_serial_nr;        /* 8.2.4 */</span><br><span style="color: hsl(120, 100%, 40%);">+   struct osmo_cbsp_cell_list cell_list;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       bool is_cbs;</span><br><span style="color: hsl(120, 100%, 40%);">+  union {</span><br><span style="color: hsl(120, 100%, 40%);">+               struct {</span><br><span style="color: hsl(120, 100%, 40%);">+                      enum cbsp_channel_ind channel_ind;</span><br><span style="color: hsl(120, 100%, 40%);">+                    enum cbsp_category category;</span><br><span style="color: hsl(120, 100%, 40%);">+                  uint16_t rep_period;</span><br><span style="color: hsl(120, 100%, 40%);">+                  uint16_t num_bcast_req;</span><br><span style="color: hsl(120, 100%, 40%);">+                       /* num_of_pages implicit as llist_count(msg_content) */</span><br><span style="color: hsl(120, 100%, 40%);">+                       uint8_t dcs;</span><br><span style="color: hsl(120, 100%, 40%);">+                  struct llist_head msg_content;</span><br><span style="color: hsl(120, 100%, 40%);">+                } cbs;</span><br><span style="color: hsl(120, 100%, 40%);">+                struct {</span><br><span style="color: hsl(120, 100%, 40%);">+                      uint8_t indicator;</span><br><span style="color: hsl(120, 100%, 40%);">+                    uint16_t warning_type;</span><br><span style="color: hsl(120, 100%, 40%);">+                        uint8_t warning_sec_info[50];</span><br><span style="color: hsl(120, 100%, 40%);">+                 uint32_t warning_period;        /* in seconds; 0xffffffff = unlimited */</span><br><span style="color: hsl(120, 100%, 40%);">+              } emergency;</span><br><span style="color: hsl(120, 100%, 40%);">+  } u;</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%);">+/* 8.1.3.2 */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_cbsp_write_replace_complete {</span><br><span style="color: hsl(120, 100%, 40%);">+  uint16_t msg_id;</span><br><span style="color: hsl(120, 100%, 40%);">+      uint16_t new_serial_nr;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint16_t *old_serial_nr;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_cbsp_num_compl_list num_compl_list;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct osmo_cbsp_cell_list cell_list;</span><br><span style="color: hsl(120, 100%, 40%);">+ enum cbsp_channel_ind *channel_ind;</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%);">+/* 8.1.3.3 */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_cbsp_write_replace_failure {</span><br><span style="color: hsl(120, 100%, 40%);">+    uint16_t msg_id;</span><br><span style="color: hsl(120, 100%, 40%);">+      uint16_t new_serial_nr;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint16_t *old_serial_nr;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct llist_head fail_list;            /* osmo_cbsp_fail_ent */</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_cbsp_num_compl_list num_compl_list;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct osmo_cbsp_cell_list cell_list;</span><br><span style="color: hsl(120, 100%, 40%);">+ enum cbsp_channel_ind *channel_ind;</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%);">+/* 8.1.3.4 */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_cbsp_kill {</span><br><span style="color: hsl(120, 100%, 40%);">+     uint16_t msg_id;</span><br><span style="color: hsl(120, 100%, 40%);">+      uint16_t old_serial_nr;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct osmo_cbsp_cell_list cell_list;</span><br><span style="color: hsl(120, 100%, 40%);">+ enum cbsp_channel_ind *channel_ind;</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%);">+/* 8.1.3.5 */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_cbsp_kill_complete {</span><br><span style="color: hsl(120, 100%, 40%);">+    uint16_t msg_id;</span><br><span style="color: hsl(120, 100%, 40%);">+      uint16_t old_serial_nr;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct osmo_cbsp_num_compl_list num_compl_list;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct osmo_cbsp_cell_list cell_list;</span><br><span style="color: hsl(120, 100%, 40%);">+ enum cbsp_channel_ind *channel_ind;</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%);">+/* 8.1.3.6 */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_cbsp_kill_failure {</span><br><span style="color: hsl(120, 100%, 40%);">+     uint16_t msg_id;</span><br><span style="color: hsl(120, 100%, 40%);">+      uint16_t old_serial_nr;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct llist_head fail_list;            /* osmo_cbsp_fail_ent */</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_cbsp_num_compl_list num_compl_list;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct osmo_cbsp_cell_list cell_list;</span><br><span style="color: hsl(120, 100%, 40%);">+ enum cbsp_channel_ind *channel_ind;</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%);">+/* 8.1.3.7 */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_cbsp_load_query {</span><br><span style="color: hsl(120, 100%, 40%);">+       struct osmo_cbsp_cell_list cell_list;</span><br><span style="color: hsl(120, 100%, 40%);">+ enum cbsp_channel_ind channel_ind;</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%);">+/* 8.1.3.8 */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_cbsp_load_query_complete {</span><br><span style="color: hsl(120, 100%, 40%);">+       struct osmo_cbsp_loading_list loading_list;</span><br><span style="color: hsl(120, 100%, 40%);">+   enum cbsp_channel_ind channel_ind;</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%);">+/* 8.1.3.9 */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_cbsp_load_query_failure {</span><br><span style="color: hsl(120, 100%, 40%);">+        struct llist_head fail_list;            /* osmo_cbsp_fail_ent */</span><br><span style="color: hsl(120, 100%, 40%);">+      enum cbsp_channel_ind channel_ind;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct osmo_cbsp_loading_list loading_list;</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%);">+/* 8.1.3.10 */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_cbsp_msg_status_query {</span><br><span style="color: hsl(120, 100%, 40%);">+        uint16_t msg_id;</span><br><span style="color: hsl(120, 100%, 40%);">+      uint16_t old_serial_nr;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct osmo_cbsp_cell_list cell_list;</span><br><span style="color: hsl(120, 100%, 40%);">+ enum cbsp_channel_ind channel_ind;</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%);">+/* 8.1.3.11 */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_cbsp_msg_status_query_complete {</span><br><span style="color: hsl(120, 100%, 40%);">+        uint16_t msg_id;</span><br><span style="color: hsl(120, 100%, 40%);">+      uint16_t old_serial_nr;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct osmo_cbsp_num_compl_list num_compl_list;</span><br><span style="color: hsl(120, 100%, 40%);">+       enum cbsp_channel_ind channel_ind;</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%);">+/* 8.1.3.12 */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_cbsp_msg_status_query_failure {</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t msg_id;</span><br><span style="color: hsl(120, 100%, 40%);">+      uint16_t old_serial_nr;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct llist_head fail_list;            /* osmo_cbsp_fail_ent */</span><br><span style="color: hsl(120, 100%, 40%);">+      enum cbsp_channel_ind channel_ind;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct osmo_cbsp_num_compl_list num_compl_list;</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%);">+/* 8.1.3.16 */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_cbsp_reset {</span><br><span style="color: hsl(120, 100%, 40%);">+       struct osmo_cbsp_cell_list cell_list;</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%);">+/* 8.1.3.17 */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_cbsp_reset_complete {</span><br><span style="color: hsl(120, 100%, 40%);">+        struct osmo_cbsp_cell_list cell_list;</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%);">+/* 8.1.3.18 */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_cbsp_reset_failure {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct llist_head fail_list;            /* osmo_cbsp_fail_ent */</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_cbsp_cell_list cell_list;</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%);">+/* 8.1.3.18a */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_cbsp_keep_alive {</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t repetition_period;</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%);">+/* 8.1.3.18b */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_cbsp_keep_alive_complete {</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%);">+/* 8.1.3.19 */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_cbsp_restart {</span><br><span style="color: hsl(120, 100%, 40%);">+   struct osmo_cbsp_cell_list cell_list;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t bcast_msg_type;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint8_t recovery_ind;</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%);">+/* 8.1.3.20 */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_cbsp_failure {</span><br><span style="color: hsl(120, 100%, 40%);">+       struct llist_head fail_list;            /* osmo_cbsp_fail_ent */</span><br><span style="color: hsl(120, 100%, 40%);">+      uint8_t bcast_msg_type;</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%);">+/* 8.1.3.21 */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_cbsp_error_ind {</span><br><span style="color: hsl(120, 100%, 40%);">+   enum cbsp_cell_id_cause cause;</span><br><span style="color: hsl(120, 100%, 40%);">+        uint16_t *msg_id;</span><br><span style="color: hsl(120, 100%, 40%);">+     uint16_t *new_serial_nr;</span><br><span style="color: hsl(120, 100%, 40%);">+      uint16_t *old_serial_nr;</span><br><span style="color: hsl(120, 100%, 40%);">+      enum cbsp_channel_ind *channel_ind;</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%);">+/* decoded CBSP message */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_cbsp_decoded {</span><br><span style="color: hsl(120, 100%, 40%);">+   enum cbsp_msg_type msg_type;</span><br><span style="color: hsl(120, 100%, 40%);">+  union {</span><br><span style="color: hsl(120, 100%, 40%);">+               struct osmo_cbsp_write_replace write_replace;</span><br><span style="color: hsl(120, 100%, 40%);">+         struct osmo_cbsp_write_replace_complete write_replace_compl;</span><br><span style="color: hsl(120, 100%, 40%);">+          struct osmo_cbsp_write_replace_failure write_replace_fail;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          struct osmo_cbsp_kill kill;</span><br><span style="color: hsl(120, 100%, 40%);">+           struct osmo_cbsp_kill_complete kill_compl;</span><br><span style="color: hsl(120, 100%, 40%);">+            struct osmo_cbsp_kill_failure kill_fail;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            struct osmo_cbsp_load_query load_query;</span><br><span style="color: hsl(120, 100%, 40%);">+               struct osmo_cbsp_load_query_complete load_query_compl;</span><br><span style="color: hsl(120, 100%, 40%);">+                struct osmo_cbsp_load_query_failure load_query_fail;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                struct osmo_cbsp_msg_status_query msg_status_query;</span><br><span style="color: hsl(120, 100%, 40%);">+           struct osmo_cbsp_msg_status_query_complete msg_status_query_compl;</span><br><span style="color: hsl(120, 100%, 40%);">+            struct osmo_cbsp_msg_status_query_failure msg_status_query_fail;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            /* set DRX */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               struct osmo_cbsp_reset reset;</span><br><span style="color: hsl(120, 100%, 40%);">+         struct osmo_cbsp_reset_complete reset_compl;</span><br><span style="color: hsl(120, 100%, 40%);">+          struct osmo_cbsp_reset_failure reset_fail;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          struct osmo_cbsp_restart restart;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           struct osmo_cbsp_failure failure;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           struct osmo_cbsp_error_ind error_ind;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               struct osmo_cbsp_keep_alive keep_alive;</span><br><span style="color: hsl(120, 100%, 40%);">+               struct osmo_cbsp_keep_alive_complete keep_alive_compl;</span><br><span style="color: hsl(120, 100%, 40%);">+        } u;</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 *osmo_cbsp_msgb_alloc(const char *name);</span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb *osmo_cbsp_encode(const struct osmo_cbsp_decoded *in);</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_cbsp_decoded *osmo_cbsp_decode(void *ctx, struct msgb *in);</span><br><span>diff --git a/include/osmocom/gsm/protocol/gsm_48_049.h b/include/osmocom/gsm/protocol/gsm_48_049.h</span><br><span>new file mode 100644</span><br><span>index 0000000..544febe</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/gsm/protocol/gsm_48_049.h</span><br><span>@@ -0,0 +1,125 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#pragma once</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdint.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* CBSP is an ETSI/3GPP standard protocol used between CBC (Cell Brodadcast Centre)</span><br><span style="color: hsl(120, 100%, 40%);">+ * and BSC (Base Station Controller0 in 2G/GSM/GERAN networks.  It is specified</span><br><span style="color: hsl(120, 100%, 40%);">+ * in 3GPP TS 48.049</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2019 by Harald Welte <laforge@gnumonks.org></span><br><span style="color: hsl(120, 100%, 40%);">+ * All rights reserved.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Released under the terms of the GNU General Public License, Version 2 or</span><br><span style="color: hsl(120, 100%, 40%);">+ * (at your option) any later version.</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%);">+#define CBSP_TCP_PORT 48049</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* 8.2.1 Information Element Identifiers */</span><br><span style="color: hsl(120, 100%, 40%);">+enum cbsp_iei {</span><br><span style="color: hsl(120, 100%, 40%);">+    CBSP_IEI_MSG_CONTENT            = 0x01,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_IEI_OLD_SERIAL_NR          = 0x02,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_IEI_NEW_SERIAL_NR          = 0x03,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_IEI_CELL_LIST              = 0x04,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_IEI_CATEGORY               = 0x05,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_IEI_REP_PERIOD             = 0x06,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_IEI_NUM_BCAST_REQ          = 0x07,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_IEI_NUM_BCAST_COMPL_LIST   = 0x08,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_IEI_FAILURE_LIST           = 0x09,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_IEI_RR_LOADING_LIST        = 0x0a,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_IEI_CAUSE                  = 0x0b,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_IEI_DCS                    = 0x0c,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_IEI_RECOVERY_IND           = 0x0d,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_IEI_MSG_ID                 = 0x0e,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_IEI_EMERG_IND              = 0x0f,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_IEI_WARN_TYPE              = 0x10,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_IEI_WARN_SEC_INFO          = 0x11,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_IEI_CHANNEL_IND            = 0x12,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_IEI_NUM_OF_PAGES           = 0x13,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_IEI_SCHEDULE_PERIOD        = 0x14,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_IEI_NUM_OF_RES_SLOTS       = 0x15,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_IEI_BCAST_MSG_TYPE         = 0x16,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_IEI_WARNING_PERIOD         = 0x17,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_IEI_KEEP_ALIVE_REP_PERIOD  = 0x18,</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%);">+/* 8.2.2 Message Type */</span><br><span style="color: hsl(120, 100%, 40%);">+enum cbsp_msg_type {</span><br><span style="color: hsl(120, 100%, 40%);">+ CBSP_MSGT_WRITE_REPLACE         = 0x01,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_MSGT_WRITE_REPLACE_COMPL   = 0x02,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_MSGT_WRITE_REPLACE_FAIL    = 0x03,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_MSGT_KILL                  = 0x04,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_MSGT_KILL_COMPL            = 0x05,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_MSGT_KILL_FAIL             = 0x06,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_MSGT_LOAD_QUERY            = 0x07,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_MSGT_LOAD_QUERY_COMPL      = 0x08,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_MSGT_LOAD_QUERY_FAIL       = 0x09,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_MSGT_MSG_STATUS_QUERY      = 0x0a,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_MSGT_MSG_STATUS_QUERY_COMPL= 0x0b,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_MSGT_MSG_STATUS_QUERY_FAIL = 0x0c,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_MSGT_SET_DRX               = 0x0d,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_MSGT_SET_DRX_COMPL         = 0x0e,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_MSGT_SET_DRX_FAIL          = 0x0f,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_MSGT_RESET                 = 0x10,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_MSGT_RESET_COMPL           = 0x11,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_MSGT_RESET_FAIL            = 0x12,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_MSGT_RESTART               = 0x13,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_MSGT_FAILURE               = 0x14,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_MSGT_ERROR_IND             = 0x15,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_MSGT_KEEP_ALIVE            = 0x16,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_MSGT_KEEP_ALIVE_COMPL      = 0x17,</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%);">+/* 8.2.7 Category */</span><br><span style="color: hsl(120, 100%, 40%);">+enum cbsp_category {</span><br><span style="color: hsl(120, 100%, 40%);">+     CBSP_CATEG_HIGH_PRIO            = 0x00,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_CATEG_BACKGROUND           = 0x01,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_CATEG_NORMAL               = 0x02,</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%);">+/* Cell ID Discriminator (8.2.11, ...) */</span><br><span style="color: hsl(120, 100%, 40%);">+enum cbsp_cell_id_disc {</span><br><span style="color: hsl(120, 100%, 40%);">+    CBSP_CIDD_WHOLE_CGI             = 0x0,</span><br><span style="color: hsl(120, 100%, 40%);">+        CBSP_CIDD_LAC_CI                = 0x1,</span><br><span style="color: hsl(120, 100%, 40%);">+        CBSP_CIDD_CI                    = 0x2,</span><br><span style="color: hsl(120, 100%, 40%);">+        CBSP_CIDD_LAI                   = 0x4,</span><br><span style="color: hsl(120, 100%, 40%);">+        CBSP_CIDD_LAC                   = 0x5,</span><br><span style="color: hsl(120, 100%, 40%);">+        CBSP_CIDD_ALL_IN_BSC            = 0x6,</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%);">+/* 8.2.13 Cause */</span><br><span style="color: hsl(120, 100%, 40%);">+enum cbsp_cell_id_cause {</span><br><span style="color: hsl(120, 100%, 40%);">+   CBSP_CAUSE_PARAM_NOT_RECOGNISED                 = 0x00,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_CAUSE_PARAM_VAL_INVALID                    = 0x01,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_CAUSE_MSG_REF_NOT_IDENTIFIED               = 0x02,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_CAUSE_CELL_ID_NOT_VALID                    = 0x03,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_CAUSE_UNRECOGNISED_MSG                     = 0x04,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_CAUSE_MISSING_MAND_IE                      = 0x05,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_CAUSE_BSC_CAPACITY_EXCEEDED                = 0x06,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_CAUSE_CELL_MEMORY_EXCEEDED                 = 0x07,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_CAUSE_BSC_MEMORY_EXCEEDED                  = 0x08,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_CAUSE_CB_NOT_SUPPORTED                     = 0x09,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_CAUSE_CB_NOT_OPERATIONAL                   = 0x0a,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_CAUSE_INCOMPATIBLE_DRX_PARAM               = 0x0b,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_CAUSE_EXT_CHAN_NOT_SUPPORTED               = 0x0c,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_CAUSE_MSG_REF_ALREADY_USED                 = 0x0d,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_CAUSE_UNSPECIFIED_ERROR                    = 0x0e,</span><br><span style="color: hsl(120, 100%, 40%);">+       CBSP_CAUSE_LAI_OR_LAC_NPT_VALID                 = 0x0f,</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%);">+/* 8.2.20 Chanel Indicator */</span><br><span style="color: hsl(120, 100%, 40%);">+enum cbsp_channel_ind {</span><br><span style="color: hsl(120, 100%, 40%);">+ CBSP_CHAN_IND_BASIC     = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+  CBSP_CHAN_IND_EXTENDED  = 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%);">+/* not explicitly specified, but every message starts with those mandatory eleemnts */</span><br><span style="color: hsl(120, 100%, 40%);">+struct cbsp_header {</span><br><span style="color: hsl(120, 100%, 40%);">+      uint8_t msg_type;</span><br><span style="color: hsl(120, 100%, 40%);">+     uint8_t len[3]; /* excluding the header */</span><br><span style="color: hsl(120, 100%, 40%);">+} __attribute__((packed));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+extern const struct value_string cbsp_msg_type_names[];</span><br><span style="color: hsl(120, 100%, 40%);">+extern const struct value_string cbsp_iei_names[];</span><br><span style="color: hsl(120, 100%, 40%);">+extern const struct value_string cbsp_category_names[];</span><br><span style="color: hsl(120, 100%, 40%);">+extern const struct tlv_definition cbsp_att_tlvdef;</span><br><span>diff --git a/src/gsm/Makefile.am b/src/gsm/Makefile.am</span><br><span>index 5740b67..5b33556 100644</span><br><span>--- a/src/gsm/Makefile.am</span><br><span>+++ b/src/gsm/Makefile.am</span><br><span>@@ -32,7 +32,7 @@</span><br><span>                     milenage/milenage.c gan.c ipa.c gsm0341.c apn.c \</span><br><span>                    gsup.c gsup_sms.c gprs_gea.c gsm0503_conv.c oap.c gsm0808_utils.c \</span><br><span>                  gsm23003.c mncc.c bts_features.c oap_client.c \</span><br><span style="color: hsl(0, 100%, 40%);">-                 gsm29118.c gsm48_rest_octets.c</span><br><span style="color: hsl(120, 100%, 40%);">+                        gsm29118.c gsm48_rest_octets.c cbsp.c</span><br><span> libgsmint_la_LDFLAGS = -no-undefined</span><br><span> libgsmint_la_LIBADD = $(top_builddir)/src/libosmocore.la</span><br><span> </span><br><span>diff --git a/src/gsm/cbsp.c b/src/gsm/cbsp.c</span><br><span>new file mode 100644</span><br><span>index 0000000..a9434c3</span><br><span>--- /dev/null</span><br><span>+++ b/src/gsm/cbsp.c</span><br><span>@@ -0,0 +1,1185 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright (C) 2019  Harald Welte <laforge@gnumonks.org></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * All Rights Reserved</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * SPDX-License-Identifier: GPL-2.0+</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 2 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ * (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU General Public License along</span><br><span style="color: hsl(120, 100%, 40%);">+ * with this program; if not, write to the Free Software Foundation, Inc.,</span><br><span style="color: hsl(120, 100%, 40%);">+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.</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%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/linuxlist.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/msgb.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/tlv.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/cbsp.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/gsm0808_utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb *osmo_cbsp_msgb_alloc(const char *name)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     /* make the messages rather large as the cell lists can be long! */</span><br><span style="color: hsl(120, 100%, 40%);">+   return msgb_alloc_headroom(65535, 16, name);</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%);">+ * IE Encoding</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%);">+/* 8.2.6 Cell List */</span><br><span style="color: hsl(120, 100%, 40%);">+static void msgb_put_cbsp_cell_list(struct msgb *msg, const struct osmo_cbsp_cell_list *cl)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       const struct osmo_cbsp_cell_ent *ent;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t *lenptr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* put tag; reserve space for length; put discriminator */</span><br><span style="color: hsl(120, 100%, 40%);">+    msgb_put_u8(msg, CBSP_IEI_CELL_LIST);</span><br><span style="color: hsl(120, 100%, 40%);">+ lenptr = msgb_put(msg, sizeof(uint16_t));</span><br><span style="color: hsl(120, 100%, 40%);">+     msgb_put_u8(msg, cl->id_discr);</span><br><span style="color: hsl(120, 100%, 40%);">+    /* put list elements */</span><br><span style="color: hsl(120, 100%, 40%);">+       llist_for_each_entry(ent, &cl->list, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+           gsm0808_msgb_put_cell_id_u(msg, cl->id_discr, &ent->cell_id);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     /* update IE length */</span><br><span style="color: hsl(120, 100%, 40%);">+        osmo_store16be(msg->tail - (lenptr+2), lenptr);</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%);">+/* 8.2.11 Failure List (discriminator per entry) */</span><br><span style="color: hsl(120, 100%, 40%);">+static void msgb_put_cbsp_fail_list(struct msgb *msg, const struct llist_head *fl)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   const struct osmo_cbsp_fail_ent *ent;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t *lenptr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* put tag; reserve space for length; put discriminator */</span><br><span style="color: hsl(120, 100%, 40%);">+    msgb_put_u8(msg, CBSP_IEI_FAILURE_LIST);</span><br><span style="color: hsl(120, 100%, 40%);">+      lenptr = msgb_put(msg, sizeof(uint16_t));</span><br><span style="color: hsl(120, 100%, 40%);">+     /* put list elements */</span><br><span style="color: hsl(120, 100%, 40%);">+       llist_for_each_entry(ent, fl, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+         msgb_put_u8(msg, ent->id_discr);</span><br><span style="color: hsl(120, 100%, 40%);">+           gsm0808_msgb_put_cell_id_u(msg, ent->id_discr, &ent->cell_id);</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+     /* update IE length */</span><br><span style="color: hsl(120, 100%, 40%);">+        osmo_store16be(msg->tail - (lenptr+2), lenptr);</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%);">+/* 8.2.12 Radio Resource Loading List */</span><br><span style="color: hsl(120, 100%, 40%);">+static void msgb_put_cbsp_loading_list(struct msgb *msg, const struct osmo_cbsp_loading_list *ll)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       const struct osmo_cbsp_loading_ent *ent;</span><br><span style="color: hsl(120, 100%, 40%);">+      uint8_t *lenptr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* put tag; reserve space for length; put discriminator */</span><br><span style="color: hsl(120, 100%, 40%);">+    msgb_put_u8(msg, CBSP_IEI_RR_LOADING_LIST);</span><br><span style="color: hsl(120, 100%, 40%);">+   lenptr = msgb_put(msg, sizeof(uint16_t));</span><br><span style="color: hsl(120, 100%, 40%);">+     msgb_put_u8(msg, ll->id_discr);</span><br><span style="color: hsl(120, 100%, 40%);">+    /* put list elements */</span><br><span style="color: hsl(120, 100%, 40%);">+       llist_for_each_entry(ent, &ll->list, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+           gsm0808_msgb_put_cell_id_u(msg, ll->id_discr, &ent->cell_id);</span><br><span style="color: hsl(120, 100%, 40%);">+               msgb_put_u8(msg, ent->load[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+            msgb_put_u8(msg, ent->load[1]);</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+     /* update IE length */</span><br><span style="color: hsl(120, 100%, 40%);">+        osmo_store16be(msg->tail - (lenptr+2), lenptr);</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%);">+/* 8.2.10 Completed List */</span><br><span style="color: hsl(120, 100%, 40%);">+static void msgb_put_cbsp_num_compl_list(struct msgb *msg, const struct osmo_cbsp_num_compl_list *cl)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        const struct osmo_cbsp_num_compl_ent *ent;</span><br><span style="color: hsl(120, 100%, 40%);">+    uint8_t *lenptr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* put tag; reserve space for length; put discriminator */</span><br><span style="color: hsl(120, 100%, 40%);">+    msgb_put_u8(msg, CBSP_IEI_NUM_BCAST_COMPL_LIST);</span><br><span style="color: hsl(120, 100%, 40%);">+      lenptr = msgb_put(msg, sizeof(uint16_t));</span><br><span style="color: hsl(120, 100%, 40%);">+     msgb_put_u8(msg, cl->id_discr);</span><br><span style="color: hsl(120, 100%, 40%);">+    /* put list elements */</span><br><span style="color: hsl(120, 100%, 40%);">+       llist_for_each_entry(ent, &cl->list, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+           gsm0808_msgb_put_cell_id_u(msg, cl->id_discr, &ent->cell_id);</span><br><span style="color: hsl(120, 100%, 40%);">+               msgb_put_u16(msg, ent->num_compl);</span><br><span style="color: hsl(120, 100%, 40%);">+         msgb_put_u8(msg, ent->num_bcast_info);</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     /* update IE length */</span><br><span style="color: hsl(120, 100%, 40%);">+        osmo_store16be(msg->tail - (lenptr+2), lenptr);</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 encode_wperiod(uint32_t secs)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  if (secs == 0xffffffff)</span><br><span style="color: hsl(120, 100%, 40%);">+               return 0; /* infinite */</span><br><span style="color: hsl(120, 100%, 40%);">+      if (secs <= 10)</span><br><span style="color: hsl(120, 100%, 40%);">+            return secs;</span><br><span style="color: hsl(120, 100%, 40%);">+  if (secs <= 30)</span><br><span style="color: hsl(120, 100%, 40%);">+            return (secs-10)/2;</span><br><span style="color: hsl(120, 100%, 40%);">+   if (secs <= 120)</span><br><span style="color: hsl(120, 100%, 40%);">+           return (secs-30)/5;</span><br><span style="color: hsl(120, 100%, 40%);">+   if (secs <= 600)</span><br><span style="color: hsl(120, 100%, 40%);">+           return (secs-120)/10;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (secs <= 60*60)</span><br><span style="color: hsl(120, 100%, 40%);">+         return (secs-600)/30;</span><br><span style="color: hsl(120, 100%, 40%);">+ return -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%);">+ * Message Encoding</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%);">+/* 8.1.3.1 WRITE REPLACE */</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_enc_write_repl(struct msgb *msg, const struct osmo_cbsp_write_replace *in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       msgb_tv16_put(msg, CBSP_IEI_MSG_ID, in->msg_id);</span><br><span style="color: hsl(120, 100%, 40%);">+   msgb_tv16_put(msg, CBSP_IEI_NEW_SERIAL_NR, in->new_serial_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (in->old_serial_nr)</span><br><span style="color: hsl(120, 100%, 40%);">+             msgb_tv16_put(msg, CBSP_IEI_OLD_SERIAL_NR, *in->old_serial_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+    msgb_put_cbsp_cell_list(msg, &in->cell_list);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (in->is_cbs) {</span><br><span style="color: hsl(120, 100%, 40%);">+          int num_of_pages = llist_count(&in->u.cbs.msg_content);</span><br><span style="color: hsl(120, 100%, 40%);">+                struct osmo_cbsp_content *ce;</span><br><span style="color: hsl(120, 100%, 40%);">+         if (num_of_pages == 0 || num_of_pages > 15)</span><br><span style="color: hsl(120, 100%, 40%);">+                        return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+               msgb_tv_put(msg, CBSP_IEI_CHANNEL_IND, in->u.cbs.channel_ind);</span><br><span style="color: hsl(120, 100%, 40%);">+             msgb_tv_put(msg, CBSP_IEI_CATEGORY, in->u.cbs.category);</span><br><span style="color: hsl(120, 100%, 40%);">+           msgb_tv16_put(msg, CBSP_IEI_REP_PERIOD, in->u.cbs.rep_period);</span><br><span style="color: hsl(120, 100%, 40%);">+             msgb_tv16_put(msg, CBSP_IEI_NUM_BCAST_REQ, in->u.cbs.num_bcast_req);</span><br><span style="color: hsl(120, 100%, 40%);">+               msgb_tv_put(msg, CBSP_IEI_NUM_OF_PAGES, num_of_pages);</span><br><span style="color: hsl(120, 100%, 40%);">+                msgb_tv_put(msg, CBSP_IEI_DCS, in->u.cbs.dcs);</span><br><span style="color: hsl(120, 100%, 40%);">+             llist_for_each_entry(ce, &in->u.cbs.msg_content, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       uint8_t *out;</span><br><span style="color: hsl(120, 100%, 40%);">+                 /* cannot use msgb_tlv_put() as 'len' isn't actually the length of</span><br><span style="color: hsl(120, 100%, 40%);">+                         * the data field */</span><br><span style="color: hsl(120, 100%, 40%);">+                  msgb_put_u8(msg, CBSP_IEI_MSG_CONTENT);</span><br><span style="color: hsl(120, 100%, 40%);">+                       msgb_put_u8(msg, ce->user_len);</span><br><span style="color: hsl(120, 100%, 40%);">+                    out = msgb_put(msg, sizeof(ce->data));</span><br><span style="color: hsl(120, 100%, 40%);">+                     memcpy(out, ce->data, sizeof(ce->data));</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+     } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              int wperiod = encode_wperiod(in->u.emergency.warning_period);</span><br><span style="color: hsl(120, 100%, 40%);">+              if (wperiod < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                   return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+               msgb_tv_put(msg, CBSP_IEI_EMERG_IND, in->u.emergency.indicator);</span><br><span style="color: hsl(120, 100%, 40%);">+           msgb_tv16_put(msg, CBSP_IEI_WARN_TYPE, in->u.emergency.warning_type);</span><br><span style="color: hsl(120, 100%, 40%);">+              msgb_tlv_put(msg, CBSP_IEI_WARN_SEC_INFO, sizeof(in->u.emergency.warning_sec_info),</span><br><span style="color: hsl(120, 100%, 40%);">+                             in->u.emergency.warning_sec_info);</span><br><span style="color: hsl(120, 100%, 40%);">+            msgb_tv_put(msg, CBSP_IEI_WARNING_PERIOD, wperiod);</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%);">+/* 8.1.3.2 WRITE REPLACE COMPLETE*/</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_enc_write_repl_compl(struct msgb *msg, const struct osmo_cbsp_write_replace_complete *in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     msgb_tv16_put(msg, CBSP_IEI_MSG_ID, in->msg_id);</span><br><span style="color: hsl(120, 100%, 40%);">+   msgb_tv16_put(msg, CBSP_IEI_NEW_SERIAL_NR, in->new_serial_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (in->old_serial_nr)</span><br><span style="color: hsl(120, 100%, 40%);">+             msgb_tv16_put(msg, CBSP_IEI_OLD_SERIAL_NR, *in->old_serial_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  msgb_put_cbsp_num_compl_list(msg, &in->num_compl_list);</span><br><span style="color: hsl(120, 100%, 40%);">+        msgb_put_cbsp_cell_list(msg, &in->cell_list);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (in->channel_ind)</span><br><span style="color: hsl(120, 100%, 40%);">+               msgb_tv_put(msg, CBSP_IEI_CHANNEL_IND, *in->channel_ind);</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%);">+/* 8.1.3.3 WRITE REPLACE FAILURE */</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_enc_write_repl_fail(struct msgb *msg, const struct osmo_cbsp_write_replace_failure *in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       msgb_tv16_put(msg, CBSP_IEI_MSG_ID, in->msg_id);</span><br><span style="color: hsl(120, 100%, 40%);">+   msgb_tv16_put(msg, CBSP_IEI_NEW_SERIAL_NR, in->new_serial_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (in->old_serial_nr)</span><br><span style="color: hsl(120, 100%, 40%);">+             msgb_tv16_put(msg, CBSP_IEI_OLD_SERIAL_NR, *in->old_serial_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  msgb_put_cbsp_fail_list(msg, &in->fail_list);</span><br><span style="color: hsl(120, 100%, 40%);">+  msgb_put_cbsp_num_compl_list(msg, &in->num_compl_list);</span><br><span style="color: hsl(120, 100%, 40%);">+        msgb_put_cbsp_cell_list(msg, &in->cell_list);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (in->channel_ind)</span><br><span style="color: hsl(120, 100%, 40%);">+               msgb_tv_put(msg, CBSP_IEI_CHANNEL_IND, *in->channel_ind);</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%);">+/* 8.1.3.4 KILL */</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_enc_kill(struct msgb *msg, const struct osmo_cbsp_kill *in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    msgb_tv16_put(msg, CBSP_IEI_MSG_ID, in->msg_id);</span><br><span style="color: hsl(120, 100%, 40%);">+   msgb_tv16_put(msg, CBSP_IEI_OLD_SERIAL_NR, in->old_serial_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+     msgb_put_cbsp_cell_list(msg, &in->cell_list);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (in->channel_ind)</span><br><span style="color: hsl(120, 100%, 40%);">+               msgb_tv_put(msg, CBSP_IEI_CHANNEL_IND, *in->channel_ind);</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%);">+/* 8.1.3.5 KILL COMPLETE */</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_enc_kill_compl(struct msgb *msg, const struct osmo_cbsp_kill_complete *in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    msgb_tv16_put(msg, CBSP_IEI_MSG_ID, in->msg_id);</span><br><span style="color: hsl(120, 100%, 40%);">+   msgb_tv16_put(msg, CBSP_IEI_OLD_SERIAL_NR, in->old_serial_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+     msgb_put_cbsp_num_compl_list(msg, &in->num_compl_list);</span><br><span style="color: hsl(120, 100%, 40%);">+        msgb_put_cbsp_cell_list(msg, &in->cell_list);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (in->channel_ind)</span><br><span style="color: hsl(120, 100%, 40%);">+               msgb_tv_put(msg, CBSP_IEI_CHANNEL_IND, *in->channel_ind);</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%);">+/* 8.1.3.6 KILL FAILURE */</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_enc_kill_fail(struct msgb *msg, const struct osmo_cbsp_kill_failure *in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       msgb_tv16_put(msg, CBSP_IEI_MSG_ID, in->msg_id);</span><br><span style="color: hsl(120, 100%, 40%);">+   msgb_tv16_put(msg, CBSP_IEI_OLD_SERIAL_NR, in->old_serial_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+     msgb_put_cbsp_fail_list(msg, &in->fail_list);</span><br><span style="color: hsl(120, 100%, 40%);">+  msgb_put_cbsp_num_compl_list(msg, &in->num_compl_list);</span><br><span style="color: hsl(120, 100%, 40%);">+        msgb_put_cbsp_cell_list(msg, &in->cell_list);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (in->channel_ind)</span><br><span style="color: hsl(120, 100%, 40%);">+               msgb_tv_put(msg, CBSP_IEI_CHANNEL_IND, *in->channel_ind);</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%);">+/* 8.1.3.7 LOAD QUERY */</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_enc_load_query(struct msgb *msg, const struct osmo_cbsp_load_query *in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  msgb_put_cbsp_cell_list(msg, &in->cell_list);</span><br><span style="color: hsl(120, 100%, 40%);">+  msgb_tv_put(msg, CBSP_IEI_CHANNEL_IND, in->channel_ind);</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%);">+/* 8.1.3.8 LOAD QUERY COMPLETE */</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_enc_load_query_compl(struct msgb *msg, const struct osmo_cbsp_load_query_complete *in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  msgb_put_cbsp_loading_list(msg, &in->loading_list);</span><br><span style="color: hsl(120, 100%, 40%);">+    msgb_tv_put(msg, CBSP_IEI_CHANNEL_IND, in->channel_ind);</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%);">+/* 8.1.3.9 LOAD QUERY FAILURE */</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_enc_load_query_fail(struct msgb *msg, const struct osmo_cbsp_load_query_failure *in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     msgb_put_cbsp_fail_list(msg, &in->fail_list);</span><br><span style="color: hsl(120, 100%, 40%);">+  msgb_tv_put(msg, CBSP_IEI_CHANNEL_IND, in->channel_ind);</span><br><span style="color: hsl(120, 100%, 40%);">+   msgb_put_cbsp_loading_list(msg, &in->loading_list);</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%);">+/* 8.1.3.10 STATUS QUERY */</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_enc_msg_status_query(struct msgb *msg, const struct osmo_cbsp_msg_status_query *in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   msgb_tv16_put(msg, CBSP_IEI_MSG_ID, in->msg_id);</span><br><span style="color: hsl(120, 100%, 40%);">+   msgb_tv16_put(msg, CBSP_IEI_OLD_SERIAL_NR, in->old_serial_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+     msgb_put_cbsp_cell_list(msg, &in->cell_list);</span><br><span style="color: hsl(120, 100%, 40%);">+  msgb_tv_put(msg, CBSP_IEI_CHANNEL_IND, in->channel_ind);</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%);">+/* 8.1.3.11 STATUS QUERY COMPLETE */</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_enc_msg_status_query_compl(struct msgb *msg,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       const struct osmo_cbsp_msg_status_query_complete *in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   msgb_tv16_put(msg, CBSP_IEI_MSG_ID, in->msg_id);</span><br><span style="color: hsl(120, 100%, 40%);">+   msgb_tv16_put(msg, CBSP_IEI_OLD_SERIAL_NR, in->old_serial_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+     msgb_put_cbsp_num_compl_list(msg, &in->num_compl_list);</span><br><span style="color: hsl(120, 100%, 40%);">+        msgb_tv_put(msg, CBSP_IEI_CHANNEL_IND, in->channel_ind);</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%);">+/* 8.1.3.12 STATUS QUERY FAILURE */</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_enc_msg_status_query_fail(struct msgb *msg,</span><br><span style="color: hsl(120, 100%, 40%);">+                                        const struct osmo_cbsp_msg_status_query_failure *in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     msgb_tv16_put(msg, CBSP_IEI_MSG_ID, in->msg_id);</span><br><span style="color: hsl(120, 100%, 40%);">+   msgb_tv16_put(msg, CBSP_IEI_OLD_SERIAL_NR, in->old_serial_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+     msgb_put_cbsp_fail_list(msg, &in->fail_list);</span><br><span style="color: hsl(120, 100%, 40%);">+  msgb_tv_put(msg, CBSP_IEI_CHANNEL_IND, in->channel_ind);</span><br><span style="color: hsl(120, 100%, 40%);">+   msgb_put_cbsp_num_compl_list(msg, &in->num_compl_list);</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%);">+/* 8.1.3.16 RESET */</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_enc_reset(struct msgb *msg, const struct osmo_cbsp_reset *in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        msgb_put_cbsp_cell_list(msg, &in->cell_list);</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%);">+/* 8.1.3.17 RESET COMPLETE */</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_enc_reset_compl(struct msgb *msg, const struct osmo_cbsp_reset_complete *in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        msgb_put_cbsp_cell_list(msg, &in->cell_list);</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%);">+/* 8.1.3.18 RESET FAILURE */</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_enc_reset_fail(struct msgb *msg, const struct osmo_cbsp_reset_failure *in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   msgb_put_cbsp_fail_list(msg, &in->fail_list);</span><br><span style="color: hsl(120, 100%, 40%);">+  msgb_put_cbsp_cell_list(msg, &in->cell_list);</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%);">+/* 8.1.3.18a KEEP ALIVE */</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_enc_keep_alive(struct msgb *msg, const struct osmo_cbsp_keep_alive *in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        msgb_tv_put(msg, CBSP_IEI_KEEP_ALIVE_REP_PERIOD, in->repetition_period);</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%);">+/* 8.1.3.18b KEEP ALIVE COMPLETE */</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_enc_keep_alive_compl(struct msgb *msg, const struct osmo_cbsp_keep_alive_complete *in)</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%);">+/* 8.1.3.19 RESTART */</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_enc_restart(struct msgb *msg, const struct osmo_cbsp_restart *in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  msgb_put_cbsp_cell_list(msg, &in->cell_list);</span><br><span style="color: hsl(120, 100%, 40%);">+  msgb_tv_put(msg, CBSP_IEI_BCAST_MSG_TYPE, in->bcast_msg_type);</span><br><span style="color: hsl(120, 100%, 40%);">+     msgb_tv_put(msg, CBSP_IEI_RECOVERY_IND, in->recovery_ind);</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%);">+/* 8.1.3.20 FAILURE */</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_enc_failure(struct msgb *msg, const struct osmo_cbsp_failure *in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  msgb_put_cbsp_fail_list(msg, &in->fail_list);</span><br><span style="color: hsl(120, 100%, 40%);">+  msgb_tv_put(msg, CBSP_IEI_BCAST_MSG_TYPE, in->bcast_msg_type);</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%);">+/* 8.1.3.21 ERROR INDICATION */</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_enc_error_ind(struct msgb *msg, const struct osmo_cbsp_error_ind *in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     msgb_tv_put(msg, CBSP_IEI_CAUSE, in->cause);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (in->msg_id)</span><br><span style="color: hsl(120, 100%, 40%);">+            msgb_tv16_put(msg, CBSP_IEI_MSG_ID, *in->msg_id);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (in->new_serial_nr)</span><br><span style="color: hsl(120, 100%, 40%);">+             msgb_tv16_put(msg, CBSP_IEI_NEW_SERIAL_NR, *in->new_serial_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (in->old_serial_nr)</span><br><span style="color: hsl(120, 100%, 40%);">+             msgb_tv16_put(msg, CBSP_IEI_OLD_SERIAL_NR, *in->old_serial_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (in->channel_ind)</span><br><span style="color: hsl(120, 100%, 40%);">+               msgb_tv_put(msg, CBSP_IEI_CHANNEL_IND, *in->channel_ind);</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 msgb *osmo_cbsp_encode(const struct osmo_cbsp_decoded *in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct msgb *msg = osmo_cbsp_msgb_alloc(__func__);</span><br><span style="color: hsl(120, 100%, 40%);">+    unsigned int len;</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 (!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%);">+        switch (in->msg_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+    case CBSP_MSGT_WRITE_REPLACE:</span><br><span style="color: hsl(120, 100%, 40%);">+         rc = cbsp_enc_write_repl(msg, &in->u.write_replace);</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CBSP_MSGT_WRITE_REPLACE_COMPL:</span><br><span style="color: hsl(120, 100%, 40%);">+           rc = cbsp_enc_write_repl_compl(msg, &in->u.write_replace_compl);</span><br><span style="color: hsl(120, 100%, 40%);">+               break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CBSP_MSGT_WRITE_REPLACE_FAIL:</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = cbsp_enc_write_repl_fail(msg, &in->u.write_replace_fail);</span><br><span style="color: hsl(120, 100%, 40%);">+         break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CBSP_MSGT_KILL:</span><br><span style="color: hsl(120, 100%, 40%);">+          rc = cbsp_enc_kill(msg, &in->u.kill);</span><br><span style="color: hsl(120, 100%, 40%);">+          break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CBSP_MSGT_KILL_COMPL:</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = cbsp_enc_kill_compl(msg, &in->u.kill_compl);</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CBSP_MSGT_KILL_FAIL:</span><br><span style="color: hsl(120, 100%, 40%);">+             rc = cbsp_enc_kill_fail(msg, &in->u.kill_fail);</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CBSP_MSGT_LOAD_QUERY:</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = cbsp_enc_load_query(msg, &in->u.load_query);</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CBSP_MSGT_LOAD_QUERY_COMPL:</span><br><span style="color: hsl(120, 100%, 40%);">+              rc = cbsp_enc_load_query_compl(msg, &in->u.load_query_compl);</span><br><span style="color: hsl(120, 100%, 40%);">+          break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CBSP_MSGT_LOAD_QUERY_FAIL:</span><br><span style="color: hsl(120, 100%, 40%);">+               rc = cbsp_enc_load_query_fail(msg, &in->u.load_query_fail);</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CBSP_MSGT_MSG_STATUS_QUERY:</span><br><span style="color: hsl(120, 100%, 40%);">+              rc = cbsp_enc_msg_status_query(msg, &in->u.msg_status_query);</span><br><span style="color: hsl(120, 100%, 40%);">+          break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CBSP_MSGT_MSG_STATUS_QUERY_COMPL:</span><br><span style="color: hsl(120, 100%, 40%);">+                rc = cbsp_enc_msg_status_query_compl(msg, &in->u.msg_status_query_compl);</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CBSP_MSGT_MSG_STATUS_QUERY_FAIL:</span><br><span style="color: hsl(120, 100%, 40%);">+         rc = cbsp_enc_msg_status_query_fail(msg, &in->u.msg_status_query_fail);</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CBSP_MSGT_RESET:</span><br><span style="color: hsl(120, 100%, 40%);">+         rc = cbsp_enc_reset(msg, &in->u.reset);</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CBSP_MSGT_RESET_COMPL:</span><br><span style="color: hsl(120, 100%, 40%);">+           rc = cbsp_enc_reset_compl(msg, &in->u.reset_compl);</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CBSP_MSGT_RESET_FAIL:</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = cbsp_enc_reset_fail(msg, &in->u.reset_fail);</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CBSP_MSGT_RESTART:</span><br><span style="color: hsl(120, 100%, 40%);">+               rc = cbsp_enc_restart(msg, &in->u.restart);</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CBSP_MSGT_FAILURE:</span><br><span style="color: hsl(120, 100%, 40%);">+               rc = cbsp_enc_failure(msg, &in->u.failure);</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CBSP_MSGT_ERROR_IND:</span><br><span style="color: hsl(120, 100%, 40%);">+             rc = cbsp_enc_error_ind(msg, &in->u.error_ind);</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CBSP_MSGT_KEEP_ALIVE:</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = cbsp_enc_keep_alive(msg, &in->u.keep_alive);</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CBSP_MSGT_KEEP_ALIVE_COMPL:</span><br><span style="color: hsl(120, 100%, 40%);">+              rc = cbsp_enc_keep_alive_compl(msg, &in->u.keep_alive_compl);</span><br><span style="color: hsl(120, 100%, 40%);">+          break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CBSP_MSGT_SET_DRX:</span><br><span style="color: hsl(120, 100%, 40%);">+       case CBSP_MSGT_SET_DRX_COMPL:</span><br><span style="color: hsl(120, 100%, 40%);">+ case CBSP_MSGT_SET_DRX_FAIL:</span><br><span style="color: hsl(120, 100%, 40%);">+          rc = -1;</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%);">+              rc = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</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 (rc < 0) {</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%);">+   /* push header in front */</span><br><span style="color: hsl(120, 100%, 40%);">+    len = msgb_length(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+       msgb_push_u8(msg, len & 0xff);</span><br><span style="color: hsl(120, 100%, 40%);">+    msgb_push_u8(msg, (len >> 8) & 0xff);</span><br><span style="color: hsl(120, 100%, 40%);">+       msgb_push_u8(msg, (len >> 16) & 0xff);</span><br><span style="color: hsl(120, 100%, 40%);">+      msgb_push_u8(msg, in->msg_type);</span><br><span style="color: hsl(120, 100%, 40%);">+</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/***********************************************************************</span><br><span style="color: hsl(120, 100%, 40%);">+ * IE Decoding</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%);">+/* 8.2.6 Cell List */</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_decode_cell_list(struct osmo_cbsp_cell_list *cl, void *ctx,</span><br><span style="color: hsl(120, 100%, 40%);">+                            const uint8_t *buf, unsigned int len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     const uint8_t *cur = buf;</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%);">+     cl->id_discr = *cur++;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   while (cur < buf + len) {</span><br><span style="color: hsl(120, 100%, 40%);">+          struct osmo_cbsp_cell_ent *ent = talloc_zero(ctx, struct osmo_cbsp_cell_ent);</span><br><span style="color: hsl(120, 100%, 40%);">+         unsigned int len_remain = len - (cur - buf);</span><br><span style="color: hsl(120, 100%, 40%);">+          OSMO_ASSERT(ent);</span><br><span style="color: hsl(120, 100%, 40%);">+             rc = gsm0808_decode_cell_id_u(&ent->cell_id, cl->id_discr, cur, len_remain);</span><br><span style="color: hsl(120, 100%, 40%);">+                if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                        return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+            cur += rc;</span><br><span style="color: hsl(120, 100%, 40%);">+            llist_add_tail(&ent->list, &cl->list);</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%);">+/* 8.2.11 Failure List (discriminator per entry) */</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_decode_fail_list(struct llist_head *fl, void *ctx,</span><br><span style="color: hsl(120, 100%, 40%);">+                                const uint8_t *buf, unsigned int len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     const uint8_t *cur = buf;</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%);">+     while (cur < buf + len) {</span><br><span style="color: hsl(120, 100%, 40%);">+          struct osmo_cbsp_fail_ent *ent = talloc_zero(ctx, struct osmo_cbsp_fail_ent);</span><br><span style="color: hsl(120, 100%, 40%);">+         unsigned int len_remain = len - (cur - buf);</span><br><span style="color: hsl(120, 100%, 40%);">+          OSMO_ASSERT(ent);</span><br><span style="color: hsl(120, 100%, 40%);">+             ent->id_discr = cur[0];</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = gsm0808_decode_cell_id_u(&ent->cell_id, ent->id_discr, cur+1, len_remain-1);</span><br><span style="color: hsl(120, 100%, 40%);">+           if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                        return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+            cur += rc;</span><br><span style="color: hsl(120, 100%, 40%);">+            llist_add_tail(&ent->list, fl);</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%);">+/* 8.2.12 Radio Resource Loading List */</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_decode_loading_list(struct osmo_cbsp_loading_list *ll, void *ctx,</span><br><span style="color: hsl(120, 100%, 40%);">+                               const uint8_t *buf, unsigned int len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  const uint8_t *cur = buf;</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%);">+     ll->id_discr = *cur++;</span><br><span style="color: hsl(120, 100%, 40%);">+     while (cur < buf + len) {</span><br><span style="color: hsl(120, 100%, 40%);">+          struct osmo_cbsp_loading_ent *ent = talloc_zero(ctx, struct osmo_cbsp_loading_ent);</span><br><span style="color: hsl(120, 100%, 40%);">+           unsigned int len_remain = len - (cur - buf);</span><br><span style="color: hsl(120, 100%, 40%);">+          OSMO_ASSERT(ent);</span><br><span style="color: hsl(120, 100%, 40%);">+             rc = gsm0808_decode_cell_id_u(&ent->cell_id, ll->id_discr, cur, len_remain);</span><br><span style="color: hsl(120, 100%, 40%);">+                if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                        return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+            cur += rc;</span><br><span style="color: hsl(120, 100%, 40%);">+            if (cur + 2 > buf + len) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 talloc_free(ent);</span><br><span style="color: hsl(120, 100%, 40%);">+                     return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span style="color: hsl(120, 100%, 40%);">+             ent->load[0] = *cur++;</span><br><span style="color: hsl(120, 100%, 40%);">+             ent->load[1] = *cur++;</span><br><span style="color: hsl(120, 100%, 40%);">+             llist_add_tail(&ent->list, &ll->list);</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%);">+/* 8.2.10 Completed List */</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_decode_num_compl_list(struct osmo_cbsp_num_compl_list *cl, void *ctx,</span><br><span style="color: hsl(120, 100%, 40%);">+                                    const uint8_t *buf, unsigned int len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      const uint8_t *cur = buf;</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%);">+     cl->id_discr = *cur++;</span><br><span style="color: hsl(120, 100%, 40%);">+     while (cur < buf + len) {</span><br><span style="color: hsl(120, 100%, 40%);">+          struct osmo_cbsp_num_compl_ent *ent = talloc_zero(ctx, struct osmo_cbsp_num_compl_ent);</span><br><span style="color: hsl(120, 100%, 40%);">+               unsigned int len_remain = len - (cur - buf);</span><br><span style="color: hsl(120, 100%, 40%);">+          OSMO_ASSERT(ent);</span><br><span style="color: hsl(120, 100%, 40%);">+             rc = gsm0808_decode_cell_id_u(&ent->cell_id, cl->id_discr, cur, len_remain);</span><br><span style="color: hsl(120, 100%, 40%);">+                if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                        return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+            cur += rc;</span><br><span style="color: hsl(120, 100%, 40%);">+            if (cur + 3 > buf + len) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 talloc_free(ent);</span><br><span style="color: hsl(120, 100%, 40%);">+                     return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span style="color: hsl(120, 100%, 40%);">+             ent->num_compl = osmo_load16be(cur); cur += 2;</span><br><span style="color: hsl(120, 100%, 40%);">+             ent->num_bcast_info = *cur++;</span><br><span style="color: hsl(120, 100%, 40%);">+              llist_add_tail(&ent->list, &cl->list);</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%);">+/* 8.2.25 */</span><br><span style="color: hsl(120, 100%, 40%);">+static uint32_t decode_wperiod(uint8_t in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   if (in == 0x00)</span><br><span style="color: hsl(120, 100%, 40%);">+               return 0xffffffff; /* infinite */</span><br><span style="color: hsl(120, 100%, 40%);">+     if (in <= 10)</span><br><span style="color: hsl(120, 100%, 40%);">+              return in;</span><br><span style="color: hsl(120, 100%, 40%);">+    if (in <= 20)</span><br><span style="color: hsl(120, 100%, 40%);">+              return 10 + (in - 10)*2;</span><br><span style="color: hsl(120, 100%, 40%);">+      if (in <= 38)</span><br><span style="color: hsl(120, 100%, 40%);">+              return 30 + (in - 20)*5;</span><br><span style="color: hsl(120, 100%, 40%);">+      if (in <= 86)</span><br><span style="color: hsl(120, 100%, 40%);">+              return 120 + (in - 38)*10;</span><br><span style="color: hsl(120, 100%, 40%);">+    if (in <= 186)</span><br><span style="color: hsl(120, 100%, 40%);">+             return 600 + (in - 86)*30;</span><br><span style="color: hsl(120, 100%, 40%);">+    else</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/***********************************************************************</span><br><span style="color: hsl(120, 100%, 40%);">+ * Message Decoding</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%);">+/* 8.1.3.1 WRITE REPLACE */</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_dec_write_repl(struct osmo_cbsp_write_replace *out, const struct tlv_parsed *tp,</span><br><span style="color: hsl(120, 100%, 40%);">+                           struct msgb *in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* check for mandatory IEs */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!TLVP_PRESENT(tp, CBSP_IEI_MSG_ID) ||</span><br><span style="color: hsl(120, 100%, 40%);">+         !TLVP_PRESENT(tp, CBSP_IEI_NEW_SERIAL_NR) ||</span><br><span style="color: hsl(120, 100%, 40%);">+          !TLVP_PRESENT(tp, CBSP_IEI_CELL_LIST))</span><br><span style="color: hsl(120, 100%, 40%);">+            return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     out->msg_id = tlvp_val16be(tp, CBSP_IEI_MSG_ID);</span><br><span style="color: hsl(120, 100%, 40%);">+   out->new_serial_nr = tlvp_val16be(tp, CBSP_IEI_NEW_SERIAL_NR);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (TLVP_PRESENT(tp, CBSP_IEI_OLD_SERIAL_NR)) {</span><br><span style="color: hsl(120, 100%, 40%);">+               out->old_serial_nr = talloc(out, uint16_t);</span><br><span style="color: hsl(120, 100%, 40%);">+                *out->old_serial_nr = tlvp_val16be(tp, CBSP_IEI_OLD_SERIAL_NR);</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%);">+   INIT_LLIST_HEAD(&out->cell_list.list);</span><br><span style="color: hsl(120, 100%, 40%);">+ cbsp_decode_cell_list(&out->cell_list, out, TLVP_VAL(tp, CBSP_IEI_CELL_LIST),</span><br><span style="color: hsl(120, 100%, 40%);">+                        TLVP_LEN(tp, CBSP_IEI_CELL_LIST));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (TLVP_PRESENT(tp, CBSP_IEI_CHANNEL_IND)) {</span><br><span style="color: hsl(120, 100%, 40%);">+         uint8_t num_of_pages;</span><br><span style="color: hsl(120, 100%, 40%);">+         INIT_LLIST_HEAD(&out->u.cbs.msg_content);</span><br><span style="color: hsl(120, 100%, 40%);">+              if (TLVP_PRESENT(tp, CBSP_IEI_EMERG_IND))</span><br><span style="color: hsl(120, 100%, 40%);">+                     return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+               if (!TLVP_PRESENT(tp, CBSP_IEI_CATEGORY) ||</span><br><span style="color: hsl(120, 100%, 40%);">+               !TLVP_PRESENT(tp, CBSP_IEI_REP_PERIOD) ||</span><br><span style="color: hsl(120, 100%, 40%);">+             !TLVP_PRESENT(tp, CBSP_IEI_NUM_BCAST_REQ) ||</span><br><span style="color: hsl(120, 100%, 40%);">+                  !TLVP_PRESENT(tp, CBSP_IEI_NUM_OF_PAGES) ||</span><br><span style="color: hsl(120, 100%, 40%);">+                   !TLVP_PRESENT(tp, CBSP_IEI_DCS))</span><br><span style="color: hsl(120, 100%, 40%);">+                  return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+               out->is_cbs = true;</span><br><span style="color: hsl(120, 100%, 40%);">+                out->u.cbs.channel_ind = *TLVP_VAL(tp, CBSP_IEI_CHANNEL_IND);</span><br><span style="color: hsl(120, 100%, 40%);">+              out->u.cbs.category = *TLVP_VAL(tp, CBSP_IEI_CATEGORY);</span><br><span style="color: hsl(120, 100%, 40%);">+            out->u.cbs.rep_period = tlvp_val16be(tp, CBSP_IEI_REP_PERIOD);</span><br><span style="color: hsl(120, 100%, 40%);">+             out->u.cbs.num_bcast_req = tlvp_val16be(tp, CBSP_IEI_NUM_BCAST_REQ);</span><br><span style="color: hsl(120, 100%, 40%);">+               num_of_pages = *TLVP_VAL(tp, CBSP_IEI_NUM_OF_PAGES);</span><br><span style="color: hsl(120, 100%, 40%);">+          if (num_of_pages < 1)</span><br><span style="color: hsl(120, 100%, 40%);">+                      return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+               /* parse pages */</span><br><span style="color: hsl(120, 100%, 40%);">+             for (i = 0; i < num_of_pages; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       const uint8_t *ie = TLVP_VAL(&tp[i], CBSP_IEI_MSG_CONTENT);</span><br><span style="color: hsl(120, 100%, 40%);">+                       struct osmo_cbsp_content *page;</span><br><span style="color: hsl(120, 100%, 40%);">+                       if (!ie)</span><br><span style="color: hsl(120, 100%, 40%);">+                              return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+                       page = talloc_zero(out, struct osmo_cbsp_content);</span><br><span style="color: hsl(120, 100%, 40%);">+                    OSMO_ASSERT(page);</span><br><span style="color: hsl(120, 100%, 40%);">+                    page->user_len = *(ie-1); /* length byte before payload */</span><br><span style="color: hsl(120, 100%, 40%);">+                 memcpy(page->data, ie, sizeof(page->data));</span><br><span style="color: hsl(120, 100%, 40%);">+                     llist_add_tail(&page->list, &out->u.cbs.msg_content);</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+     } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (!TLVP_PRES_LEN(tp, CBSP_IEI_EMERG_IND, 1) ||</span><br><span style="color: hsl(120, 100%, 40%);">+                  !TLVP_PRES_LEN(tp, CBSP_IEI_WARN_TYPE, 2) ||</span><br><span style="color: hsl(120, 100%, 40%);">+                  !TLVP_PRES_LEN(tp, CBSP_IEI_WARN_SEC_INFO, 50) ||</span><br><span style="color: hsl(120, 100%, 40%);">+             !TLVP_PRES_LEN(tp, CBSP_IEI_WARNING_PERIOD, 1))</span><br><span style="color: hsl(120, 100%, 40%);">+                   return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+               out->u.emergency.indicator = *TLVP_VAL(tp, CBSP_IEI_EMERG_IND);</span><br><span style="color: hsl(120, 100%, 40%);">+            out->u.emergency.warning_type = tlvp_val16be(tp, CBSP_IEI_WARN_TYPE);</span><br><span style="color: hsl(120, 100%, 40%);">+              memcpy(&out->u.emergency.warning_sec_info, TLVP_VAL(tp, CBSP_IEI_WARN_SEC_INFO),</span><br><span style="color: hsl(120, 100%, 40%);">+                       sizeof(out->u.emergency.warning_sec_info));</span><br><span style="color: hsl(120, 100%, 40%);">+                out->u.emergency.warning_period = decode_wperiod(*TLVP_VAL(tp, CBSP_IEI_WARNING_PERIOD));</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%);">+/* 8.1.3.2 WRITE REPLACE COMPLETE*/</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_dec_write_repl_compl(struct osmo_cbsp_write_replace_complete *out,</span><br><span style="color: hsl(120, 100%, 40%);">+                                    const struct tlv_parsed *tp, struct msgb *in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!TLVP_PRES_LEN(tp, CBSP_IEI_MSG_ID, 2) ||</span><br><span style="color: hsl(120, 100%, 40%);">+     !TLVP_PRES_LEN(tp, CBSP_IEI_NEW_SERIAL_NR, 2))</span><br><span style="color: hsl(120, 100%, 40%);">+            return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     out->msg_id = tlvp_val16be(tp, CBSP_IEI_MSG_ID);</span><br><span style="color: hsl(120, 100%, 40%);">+   out->new_serial_nr = tlvp_val16be(tp, CBSP_IEI_NEW_SERIAL_NR);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (TLVP_PRES_LEN(tp, CBSP_IEI_OLD_SERIAL_NR, 2)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           out->old_serial_nr = talloc(out, uint16_t);</span><br><span style="color: hsl(120, 100%, 40%);">+                *out->old_serial_nr = tlvp_val16be(tp, CBSP_IEI_OLD_SERIAL_NR);</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%);">+   INIT_LLIST_HEAD(&out->num_compl_list.list);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (TLVP_PRES_LEN(tp, CBSP_IEI_NUM_BCAST_COMPL_LIST, 7)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            cbsp_decode_num_compl_list(&out->num_compl_list, out,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     TLVP_VAL(tp, CBSP_IEI_NUM_BCAST_COMPL_LIST),</span><br><span style="color: hsl(120, 100%, 40%);">+                                          TLVP_LEN(tp, CBSP_IEI_NUM_BCAST_COMPL_LIST));</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%);">+   INIT_LLIST_HEAD(&out->cell_list.list);</span><br><span style="color: hsl(120, 100%, 40%);">+ cbsp_decode_cell_list(&out->cell_list, out, TLVP_VAL(tp, CBSP_IEI_CELL_LIST),</span><br><span style="color: hsl(120, 100%, 40%);">+                        TLVP_LEN(tp, CBSP_IEI_CELL_LIST));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (TLVP_PRES_LEN(tp, CBSP_IEI_CHANNEL_IND, 1)) {</span><br><span style="color: hsl(120, 100%, 40%);">+             out->channel_ind = talloc(out, enum cbsp_channel_ind);</span><br><span style="color: hsl(120, 100%, 40%);">+             *out->channel_ind = *TLVP_VAL(tp, CBSP_IEI_CHANNEL_IND);</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%);">+/* 8.1.3.3 WRITE REPLACE FAILURE */</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_dec_write_repl_fail(struct osmo_cbsp_write_replace_failure *out,</span><br><span style="color: hsl(120, 100%, 40%);">+                             const struct tlv_parsed *tp, struct msgb *in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!TLVP_PRES_LEN(tp, CBSP_IEI_MSG_ID, 2) ||</span><br><span style="color: hsl(120, 100%, 40%);">+     !TLVP_PRES_LEN(tp, CBSP_IEI_NEW_SERIAL_NR, 2) ||</span><br><span style="color: hsl(120, 100%, 40%);">+      !TLVP_PRES_LEN(tp, CBSP_IEI_FAILURE_LIST, 5))</span><br><span style="color: hsl(120, 100%, 40%);">+             return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     out->msg_id = tlvp_val16be(tp, CBSP_IEI_MSG_ID);</span><br><span style="color: hsl(120, 100%, 40%);">+   out->new_serial_nr = tlvp_val16be(tp, CBSP_IEI_NEW_SERIAL_NR);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (TLVP_PRES_LEN(tp, CBSP_IEI_OLD_SERIAL_NR, 2)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           out->old_serial_nr = talloc(out, uint16_t);</span><br><span style="color: hsl(120, 100%, 40%);">+                *out->old_serial_nr = tlvp_val16be(tp, CBSP_IEI_OLD_SERIAL_NR);</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%);">+   INIT_LLIST_HEAD(&out->fail_list);</span><br><span style="color: hsl(120, 100%, 40%);">+      cbsp_decode_fail_list(&out->fail_list, out,</span><br><span style="color: hsl(120, 100%, 40%);">+                          TLVP_VAL(tp, CBSP_IEI_FAILURE_LIST),</span><br><span style="color: hsl(120, 100%, 40%);">+                          TLVP_LEN(tp, CBSP_IEI_FAILURE_LIST));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ INIT_LLIST_HEAD(&out->num_compl_list.list);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (TLVP_PRES_LEN(tp, CBSP_IEI_NUM_BCAST_COMPL_LIST, 7)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            cbsp_decode_num_compl_list(&out->num_compl_list, out,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     TLVP_VAL(tp, CBSP_IEI_NUM_BCAST_COMPL_LIST),</span><br><span style="color: hsl(120, 100%, 40%);">+                                          TLVP_LEN(tp, CBSP_IEI_NUM_BCAST_COMPL_LIST));</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%);">+   INIT_LLIST_HEAD(&out->cell_list.list);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (TLVP_PRES_LEN(tp, CBSP_IEI_CELL_LIST, 1)) {</span><br><span style="color: hsl(120, 100%, 40%);">+               cbsp_decode_cell_list(&out->cell_list, out, TLVP_VAL(tp, CBSP_IEI_CELL_LIST),</span><br><span style="color: hsl(120, 100%, 40%);">+                                TLVP_LEN(tp, CBSP_IEI_CELL_LIST));</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 (TLVP_PRES_LEN(tp, CBSP_IEI_CHANNEL_IND, 1)) {</span><br><span style="color: hsl(120, 100%, 40%);">+             out->channel_ind = talloc(out, enum cbsp_channel_ind);</span><br><span style="color: hsl(120, 100%, 40%);">+             *out->channel_ind = *TLVP_VAL(tp, CBSP_IEI_CHANNEL_IND);</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%);">+/* 8.1.3.4 KILL */</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_dec_kill(struct osmo_cbsp_kill *out, const struct tlv_parsed *tp, struct msgb *in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!TLVP_PRES_LEN(tp, CBSP_IEI_MSG_ID, 2) ||</span><br><span style="color: hsl(120, 100%, 40%);">+     !TLVP_PRES_LEN(tp, CBSP_IEI_OLD_SERIAL_NR, 2) ||</span><br><span style="color: hsl(120, 100%, 40%);">+      !TLVP_PRES_LEN(tp, CBSP_IEI_CELL_LIST, 1))</span><br><span style="color: hsl(120, 100%, 40%);">+                return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+       out->msg_id = tlvp_val16be(tp, CBSP_IEI_MSG_ID);</span><br><span style="color: hsl(120, 100%, 40%);">+   out->old_serial_nr = tlvp_val16be(tp, CBSP_IEI_OLD_SERIAL_NR);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   INIT_LLIST_HEAD(&out->cell_list.list);</span><br><span style="color: hsl(120, 100%, 40%);">+ cbsp_decode_cell_list(&out->cell_list, out, TLVP_VAL(tp, CBSP_IEI_CELL_LIST),</span><br><span style="color: hsl(120, 100%, 40%);">+                        TLVP_LEN(tp, CBSP_IEI_CELL_LIST));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (TLVP_PRES_LEN(tp, CBSP_IEI_CHANNEL_IND, 1)) {</span><br><span style="color: hsl(120, 100%, 40%);">+             out->channel_ind = talloc(out, enum cbsp_channel_ind);</span><br><span style="color: hsl(120, 100%, 40%);">+             *out->channel_ind = *TLVP_VAL(tp, CBSP_IEI_CHANNEL_IND);</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%);">+/* 8.1.3.5 KILL COMPLETE */</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_dec_kill_compl(struct osmo_cbsp_kill_complete *out, const struct tlv_parsed *tp,</span><br><span style="color: hsl(120, 100%, 40%);">+                         struct msgb *in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!TLVP_PRES_LEN(tp, CBSP_IEI_MSG_ID, 2) ||</span><br><span style="color: hsl(120, 100%, 40%);">+     !TLVP_PRES_LEN(tp, CBSP_IEI_OLD_SERIAL_NR, 2) ||</span><br><span style="color: hsl(120, 100%, 40%);">+      !TLVP_PRES_LEN(tp, CBSP_IEI_CELL_LIST, 1))</span><br><span style="color: hsl(120, 100%, 40%);">+                return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     out->msg_id = tlvp_val16be(tp, CBSP_IEI_MSG_ID);</span><br><span style="color: hsl(120, 100%, 40%);">+   out->old_serial_nr = tlvp_val16be(tp, CBSP_IEI_OLD_SERIAL_NR);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   INIT_LLIST_HEAD(&out->num_compl_list.list);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (TLVP_PRES_LEN(tp, CBSP_IEI_NUM_BCAST_COMPL_LIST, 7)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            cbsp_decode_num_compl_list(&out->num_compl_list, out,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     TLVP_VAL(tp, CBSP_IEI_NUM_BCAST_COMPL_LIST),</span><br><span style="color: hsl(120, 100%, 40%);">+                                          TLVP_LEN(tp, CBSP_IEI_NUM_BCAST_COMPL_LIST));</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%);">+   INIT_LLIST_HEAD(&out->cell_list.list);</span><br><span style="color: hsl(120, 100%, 40%);">+ cbsp_decode_cell_list(&out->cell_list, out, TLVP_VAL(tp, CBSP_IEI_CELL_LIST),</span><br><span style="color: hsl(120, 100%, 40%);">+                        TLVP_LEN(tp, CBSP_IEI_CELL_LIST));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (TLVP_PRES_LEN(tp, CBSP_IEI_CHANNEL_IND, 1)) {</span><br><span style="color: hsl(120, 100%, 40%);">+             out->channel_ind = talloc(out, enum cbsp_channel_ind);</span><br><span style="color: hsl(120, 100%, 40%);">+             *out->channel_ind = *TLVP_VAL(tp, CBSP_IEI_CHANNEL_IND);</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%);">+/* 8.1.3.6 KILL FAILURE */</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_dec_kill_fail(struct osmo_cbsp_kill_failure *out, const struct tlv_parsed *tp,</span><br><span style="color: hsl(120, 100%, 40%);">+                          struct msgb *in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!TLVP_PRES_LEN(tp, CBSP_IEI_MSG_ID, 2) ||</span><br><span style="color: hsl(120, 100%, 40%);">+     !TLVP_PRES_LEN(tp, CBSP_IEI_OLD_SERIAL_NR, 2) ||</span><br><span style="color: hsl(120, 100%, 40%);">+      !TLVP_PRES_LEN(tp, CBSP_IEI_FAILURE_LIST, 5))</span><br><span style="color: hsl(120, 100%, 40%);">+             return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     out->msg_id = tlvp_val16be(tp, CBSP_IEI_MSG_ID);</span><br><span style="color: hsl(120, 100%, 40%);">+   out->old_serial_nr = tlvp_val16be(tp, CBSP_IEI_OLD_SERIAL_NR);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   INIT_LLIST_HEAD(&out->fail_list);</span><br><span style="color: hsl(120, 100%, 40%);">+      cbsp_decode_fail_list(&out->fail_list, out,</span><br><span style="color: hsl(120, 100%, 40%);">+                          TLVP_VAL(tp, CBSP_IEI_FAILURE_LIST),</span><br><span style="color: hsl(120, 100%, 40%);">+                          TLVP_LEN(tp, CBSP_IEI_FAILURE_LIST));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ INIT_LLIST_HEAD(&out->num_compl_list.list);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (TLVP_PRES_LEN(tp, CBSP_IEI_NUM_BCAST_COMPL_LIST, 7)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            cbsp_decode_num_compl_list(&out->num_compl_list, out,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     TLVP_VAL(tp, CBSP_IEI_NUM_BCAST_COMPL_LIST),</span><br><span style="color: hsl(120, 100%, 40%);">+                                          TLVP_LEN(tp, CBSP_IEI_NUM_BCAST_COMPL_LIST));</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%);">+   INIT_LLIST_HEAD(&out->cell_list.list);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (TLVP_PRES_LEN(tp, CBSP_IEI_CELL_LIST, 1)) {</span><br><span style="color: hsl(120, 100%, 40%);">+               cbsp_decode_cell_list(&out->cell_list, out, TLVP_VAL(tp, CBSP_IEI_CELL_LIST),</span><br><span style="color: hsl(120, 100%, 40%);">+                                TLVP_LEN(tp, CBSP_IEI_CELL_LIST));</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 (TLVP_PRES_LEN(tp, CBSP_IEI_CHANNEL_IND, 1)) {</span><br><span style="color: hsl(120, 100%, 40%);">+             out->channel_ind = talloc(out, enum cbsp_channel_ind);</span><br><span style="color: hsl(120, 100%, 40%);">+             *out->channel_ind = *TLVP_VAL(tp, CBSP_IEI_CHANNEL_IND);</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%);">+/* 8.1.3.7 LOAD QUERY */</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_dec_load_query(struct osmo_cbsp_load_query *out, const struct tlv_parsed *tp,</span><br><span style="color: hsl(120, 100%, 40%);">+                               struct msgb *in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!TLVP_PRES_LEN(tp, CBSP_IEI_CELL_LIST, 1) ||</span><br><span style="color: hsl(120, 100%, 40%);">+          !TLVP_PRES_LEN(tp, CBSP_IEI_CHANNEL_IND, 1))</span><br><span style="color: hsl(120, 100%, 40%);">+              return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     INIT_LLIST_HEAD(&out->cell_list.list);</span><br><span style="color: hsl(120, 100%, 40%);">+ cbsp_decode_cell_list(&out->cell_list, out, TLVP_VAL(tp, CBSP_IEI_CELL_LIST),</span><br><span style="color: hsl(120, 100%, 40%);">+                        TLVP_LEN(tp, CBSP_IEI_CELL_LIST));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    out->channel_ind = *TLVP_VAL(tp, CBSP_IEI_CHANNEL_IND);</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%);">+/* 8.1.3.8 LOAD QUERY COMPLETE */</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_dec_load_query_compl(struct osmo_cbsp_load_query_complete *out,</span><br><span style="color: hsl(120, 100%, 40%);">+                                 const struct tlv_parsed *tp, struct msgb *in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!TLVP_PRES_LEN(tp, CBSP_IEI_RR_LOADING_LIST, 6) ||</span><br><span style="color: hsl(120, 100%, 40%);">+            !TLVP_PRES_LEN(tp, CBSP_IEI_CHANNEL_IND, 1))</span><br><span style="color: hsl(120, 100%, 40%);">+              return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     INIT_LLIST_HEAD(&out->loading_list.list);</span><br><span style="color: hsl(120, 100%, 40%);">+      cbsp_decode_loading_list(&out->loading_list, out,</span><br><span style="color: hsl(120, 100%, 40%);">+                               TLVP_VAL(tp, CBSP_IEI_RR_LOADING_LIST),</span><br><span style="color: hsl(120, 100%, 40%);">+                               TLVP_LEN(tp, CBSP_IEI_RR_LOADING_LIST));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   out->channel_ind = *TLVP_VAL(tp, CBSP_IEI_CHANNEL_IND);</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%);">+/* 8.1.3.9 LOAD QUERY FAILURE */</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_dec_load_query_fail(struct osmo_cbsp_load_query_failure *out,</span><br><span style="color: hsl(120, 100%, 40%);">+                                   const struct tlv_parsed *tp, struct msgb *in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!TLVP_PRES_LEN(tp, CBSP_IEI_FAILURE_LIST, 5) ||</span><br><span style="color: hsl(120, 100%, 40%);">+       !TLVP_PRES_LEN(tp, CBSP_IEI_CHANNEL_IND, 1))</span><br><span style="color: hsl(120, 100%, 40%);">+              return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     INIT_LLIST_HEAD(&out->fail_list);</span><br><span style="color: hsl(120, 100%, 40%);">+      cbsp_decode_fail_list(&out->fail_list, out,</span><br><span style="color: hsl(120, 100%, 40%);">+                          TLVP_VAL(tp, CBSP_IEI_FAILURE_LIST),</span><br><span style="color: hsl(120, 100%, 40%);">+                          TLVP_LEN(tp, CBSP_IEI_FAILURE_LIST));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ out->channel_ind = *TLVP_VAL(tp, CBSP_IEI_CHANNEL_IND);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  INIT_LLIST_HEAD(&out->loading_list.list);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (TLVP_PRES_LEN(tp, CBSP_IEI_RR_LOADING_LIST, 6)) {</span><br><span style="color: hsl(120, 100%, 40%);">+         cbsp_decode_loading_list(&out->loading_list, out,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       TLVP_VAL(tp, CBSP_IEI_RR_LOADING_LIST),</span><br><span style="color: hsl(120, 100%, 40%);">+                                       TLVP_LEN(tp, CBSP_IEI_RR_LOADING_LIST));</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%);">+/* 8.1.3.10 STATUS QUERY */</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_dec_msg_status_query(struct osmo_cbsp_msg_status_query *out,</span><br><span style="color: hsl(120, 100%, 40%);">+                                  const struct tlv_parsed *tp, struct msgb *in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!TLVP_PRES_LEN(tp, CBSP_IEI_MSG_ID, 2) ||</span><br><span style="color: hsl(120, 100%, 40%);">+     !TLVP_PRES_LEN(tp, CBSP_IEI_OLD_SERIAL_NR, 2) ||</span><br><span style="color: hsl(120, 100%, 40%);">+      !TLVP_PRES_LEN(tp, CBSP_IEI_CELL_LIST, 1) ||</span><br><span style="color: hsl(120, 100%, 40%);">+          !TLVP_PRES_LEN(tp, CBSP_IEI_CHANNEL_IND, 1))</span><br><span style="color: hsl(120, 100%, 40%);">+              return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+       out->msg_id = tlvp_val16be(tp, CBSP_IEI_MSG_ID);</span><br><span style="color: hsl(120, 100%, 40%);">+   out->old_serial_nr = tlvp_val16be(tp, CBSP_IEI_OLD_SERIAL_NR);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   INIT_LLIST_HEAD(&out->cell_list.list);</span><br><span style="color: hsl(120, 100%, 40%);">+ cbsp_decode_cell_list(&out->cell_list, out, TLVP_VAL(tp, CBSP_IEI_CELL_LIST),</span><br><span style="color: hsl(120, 100%, 40%);">+                        TLVP_LEN(tp, CBSP_IEI_CELL_LIST));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    out->channel_ind = *TLVP_VAL(tp, CBSP_IEI_CHANNEL_IND);</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%);">+/* 8.1.3.11 STATUS QUERY COMPLETE */</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_dec_msg_status_query_compl(struct osmo_cbsp_msg_status_query_complete *out,</span><br><span style="color: hsl(120, 100%, 40%);">+                                        const struct tlv_parsed *tp, struct msgb *in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!TLVP_PRES_LEN(tp, CBSP_IEI_MSG_ID, 2) ||</span><br><span style="color: hsl(120, 100%, 40%);">+     !TLVP_PRES_LEN(tp, CBSP_IEI_OLD_SERIAL_NR, 2) ||</span><br><span style="color: hsl(120, 100%, 40%);">+      !TLVP_PRES_LEN(tp, CBSP_IEI_NUM_BCAST_COMPL_LIST, 7) ||</span><br><span style="color: hsl(120, 100%, 40%);">+       !TLVP_PRES_LEN(tp, CBSP_IEI_CHANNEL_IND, 1))</span><br><span style="color: hsl(120, 100%, 40%);">+              return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     out->msg_id = tlvp_val16be(tp, CBSP_IEI_MSG_ID);</span><br><span style="color: hsl(120, 100%, 40%);">+   out->old_serial_nr = tlvp_val16be(tp, CBSP_IEI_OLD_SERIAL_NR);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   INIT_LLIST_HEAD(&out->num_compl_list.list);</span><br><span style="color: hsl(120, 100%, 40%);">+    cbsp_decode_num_compl_list(&out->num_compl_list, out,</span><br><span style="color: hsl(120, 100%, 40%);">+                             TLVP_VAL(tp, CBSP_IEI_NUM_BCAST_COMPL_LIST),</span><br><span style="color: hsl(120, 100%, 40%);">+                                  TLVP_LEN(tp, CBSP_IEI_NUM_BCAST_COMPL_LIST));</span><br><span style="color: hsl(120, 100%, 40%);">+      out->channel_ind = *TLVP_VAL(tp, CBSP_IEI_CHANNEL_IND);</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%);">+/* 8.1.3.12 STATUS QUERY FAILURE */</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_dec_msg_status_query_fail(struct osmo_cbsp_msg_status_query_failure *out,</span><br><span style="color: hsl(120, 100%, 40%);">+                                          const struct tlv_parsed *tp, struct msgb *in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!TLVP_PRES_LEN(tp, CBSP_IEI_MSG_ID, 2) ||</span><br><span style="color: hsl(120, 100%, 40%);">+     !TLVP_PRES_LEN(tp, CBSP_IEI_OLD_SERIAL_NR, 2) ||</span><br><span style="color: hsl(120, 100%, 40%);">+      !TLVP_PRES_LEN(tp, CBSP_IEI_FAILURE_LIST, 5) ||</span><br><span style="color: hsl(120, 100%, 40%);">+       !TLVP_PRES_LEN(tp, CBSP_IEI_CHANNEL_IND, 1))</span><br><span style="color: hsl(120, 100%, 40%);">+              return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     out->msg_id = tlvp_val16be(tp, CBSP_IEI_MSG_ID);</span><br><span style="color: hsl(120, 100%, 40%);">+   out->old_serial_nr = tlvp_val16be(tp, CBSP_IEI_OLD_SERIAL_NR);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   INIT_LLIST_HEAD(&out->fail_list);</span><br><span style="color: hsl(120, 100%, 40%);">+      cbsp_decode_fail_list(&out->fail_list, out,</span><br><span style="color: hsl(120, 100%, 40%);">+                          TLVP_VAL(tp, CBSP_IEI_FAILURE_LIST),</span><br><span style="color: hsl(120, 100%, 40%);">+                          TLVP_LEN(tp, CBSP_IEI_FAILURE_LIST));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ out->channel_ind = *TLVP_VAL(tp, CBSP_IEI_CHANNEL_IND);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  INIT_LLIST_HEAD(&out->num_compl_list.list);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (TLVP_PRES_LEN(tp, CBSP_IEI_NUM_BCAST_COMPL_LIST, 7)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            cbsp_decode_num_compl_list(&out->num_compl_list, out,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     TLVP_VAL(tp, CBSP_IEI_NUM_BCAST_COMPL_LIST),</span><br><span style="color: hsl(120, 100%, 40%);">+                                          TLVP_LEN(tp, CBSP_IEI_NUM_BCAST_COMPL_LIST));</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%);">+/* 8.1.3.16 RESET */</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_dec_reset(struct osmo_cbsp_reset *out, const struct tlv_parsed *tp, struct msgb *in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!TLVP_PRES_LEN(tp, CBSP_IEI_CELL_LIST, 1))</span><br><span style="color: hsl(120, 100%, 40%);">+                return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     INIT_LLIST_HEAD(&out->cell_list.list);</span><br><span style="color: hsl(120, 100%, 40%);">+ cbsp_decode_cell_list(&out->cell_list, out, TLVP_VAL(tp, CBSP_IEI_CELL_LIST),</span><br><span style="color: hsl(120, 100%, 40%);">+                        TLVP_LEN(tp, CBSP_IEI_CELL_LIST));</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%);">+/* 8.1.3.17 RESET COMPLETE */</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_dec_reset_compl(struct osmo_cbsp_reset_complete *out, const struct tlv_parsed *tp,</span><br><span style="color: hsl(120, 100%, 40%);">+                             struct msgb *in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!TLVP_PRES_LEN(tp, CBSP_IEI_CELL_LIST, 1))</span><br><span style="color: hsl(120, 100%, 40%);">+                return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     INIT_LLIST_HEAD(&out->cell_list.list);</span><br><span style="color: hsl(120, 100%, 40%);">+ cbsp_decode_cell_list(&out->cell_list, out, TLVP_VAL(tp, CBSP_IEI_CELL_LIST),</span><br><span style="color: hsl(120, 100%, 40%);">+                        TLVP_LEN(tp, CBSP_IEI_CELL_LIST));</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%);">+/* 8.1.3.18 RESET FAILURE */</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_dec_reset_fail(struct osmo_cbsp_reset_failure *out, const struct tlv_parsed *tp,</span><br><span style="color: hsl(120, 100%, 40%);">+                                struct msgb *in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!TLVP_PRES_LEN(tp, CBSP_IEI_FAILURE_LIST, 5))</span><br><span style="color: hsl(120, 100%, 40%);">+             return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     INIT_LLIST_HEAD(&out->fail_list);</span><br><span style="color: hsl(120, 100%, 40%);">+      cbsp_decode_fail_list(&out->fail_list, out,</span><br><span style="color: hsl(120, 100%, 40%);">+                          TLVP_VAL(tp, CBSP_IEI_FAILURE_LIST),</span><br><span style="color: hsl(120, 100%, 40%);">+                          TLVP_LEN(tp, CBSP_IEI_FAILURE_LIST));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ INIT_LLIST_HEAD(&out->cell_list.list);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (TLVP_PRES_LEN(tp, CBSP_IEI_CELL_LIST, 1)) {</span><br><span style="color: hsl(120, 100%, 40%);">+               cbsp_decode_cell_list(&out->cell_list, out, TLVP_VAL(tp, CBSP_IEI_CELL_LIST),</span><br><span style="color: hsl(120, 100%, 40%);">+                                TLVP_LEN(tp, CBSP_IEI_CELL_LIST));</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%);">+/* 8.1.3.18a KEEP ALIVE */</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_dec_keep_alive(struct osmo_cbsp_keep_alive *out, const struct tlv_parsed *tp,</span><br><span style="color: hsl(120, 100%, 40%);">+                             struct msgb *in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!TLVP_PRES_LEN(tp, CBSP_IEI_KEEP_ALIVE_REP_PERIOD, 1))</span><br><span style="color: hsl(120, 100%, 40%);">+            return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     out->repetition_period = *TLVP_VAL(tp, CBSP_IEI_KEEP_ALIVE_REP_PERIOD);</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%);">+/* 8.1.3.18b KEEP ALIVE COMPLETE */</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_dec_keep_alive_compl(struct osmo_cbsp_keep_alive_complete *out,</span><br><span style="color: hsl(120, 100%, 40%);">+                               const struct tlv_parsed *tp, struct msgb *in)</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%);">+/* 8.1.3.19 RESTART */</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_dec_restart(struct osmo_cbsp_restart *out, const struct tlv_parsed *tp,</span><br><span style="color: hsl(120, 100%, 40%);">+                           struct msgb *in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!TLVP_PRES_LEN(tp, CBSP_IEI_CELL_LIST, 1) ||</span><br><span style="color: hsl(120, 100%, 40%);">+          !TLVP_PRES_LEN(tp, CBSP_IEI_BCAST_MSG_TYPE, 1) ||</span><br><span style="color: hsl(120, 100%, 40%);">+     !TLVP_PRES_LEN(tp, CBSP_IEI_RECOVERY_IND, 1))</span><br><span style="color: hsl(120, 100%, 40%);">+             return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     INIT_LLIST_HEAD(&out->cell_list.list);</span><br><span style="color: hsl(120, 100%, 40%);">+ cbsp_decode_cell_list(&out->cell_list, out, TLVP_VAL(tp, CBSP_IEI_CELL_LIST),</span><br><span style="color: hsl(120, 100%, 40%);">+                        TLVP_LEN(tp, CBSP_IEI_CELL_LIST));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    out->bcast_msg_type = *TLVP_VAL(tp, CBSP_IEI_BCAST_MSG_TYPE);</span><br><span style="color: hsl(120, 100%, 40%);">+      out->recovery_ind = *TLVP_VAL(tp, CBSP_IEI_RECOVERY_IND);</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%);">+/* 8.1.3.20 FAILURE */</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_dec_failure(struct osmo_cbsp_failure *out, const struct tlv_parsed *tp, struct msgb *in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!TLVP_PRES_LEN(tp, CBSP_IEI_FAILURE_LIST, 5) ||</span><br><span style="color: hsl(120, 100%, 40%);">+       !TLVP_PRES_LEN(tp, CBSP_IEI_BCAST_MSG_TYPE, 1))</span><br><span style="color: hsl(120, 100%, 40%);">+           return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     INIT_LLIST_HEAD(&out->fail_list);</span><br><span style="color: hsl(120, 100%, 40%);">+      cbsp_decode_fail_list(&out->fail_list, out,</span><br><span style="color: hsl(120, 100%, 40%);">+                          TLVP_VAL(tp, CBSP_IEI_FAILURE_LIST),</span><br><span style="color: hsl(120, 100%, 40%);">+                          TLVP_LEN(tp, CBSP_IEI_FAILURE_LIST));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ out->bcast_msg_type = *TLVP_VAL(tp, CBSP_IEI_BCAST_MSG_TYPE);</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%);">+/* 8.1.3.21 ERROR INDICATION */</span><br><span style="color: hsl(120, 100%, 40%);">+static int cbsp_dec_error_ind(struct osmo_cbsp_error_ind *out, const struct tlv_parsed *tp,</span><br><span style="color: hsl(120, 100%, 40%);">+                        struct msgb *in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!TLVP_PRES_LEN(tp, CBSP_IEI_CAUSE, 1))</span><br><span style="color: hsl(120, 100%, 40%);">+            return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     out->cause = *TLVP_VAL(tp, CBSP_IEI_CAUSE);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (TLVP_PRES_LEN(tp, CBSP_IEI_MSG_ID, 2)) {</span><br><span style="color: hsl(120, 100%, 40%);">+          out->msg_id = talloc(out, uint16_t);</span><br><span style="color: hsl(120, 100%, 40%);">+               *out->msg_id = tlvp_val16be(tp, CBSP_IEI_MSG_ID);</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (TLVP_PRES_LEN(tp, CBSP_IEI_NEW_SERIAL_NR, 2)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           out->new_serial_nr = talloc(out, uint16_t);</span><br><span style="color: hsl(120, 100%, 40%);">+                *out->new_serial_nr = tlvp_val16be(tp, CBSP_IEI_NEW_SERIAL_NR);</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (TLVP_PRES_LEN(tp, CBSP_IEI_OLD_SERIAL_NR, 2)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           out->old_serial_nr = talloc(out, uint16_t);</span><br><span style="color: hsl(120, 100%, 40%);">+                *out->old_serial_nr = tlvp_val16be(tp, CBSP_IEI_OLD_SERIAL_NR);</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (TLVP_PRES_LEN(tp, CBSP_IEI_CHANNEL_IND, 1)) {</span><br><span style="color: hsl(120, 100%, 40%);">+             out->channel_ind = talloc(out, enum cbsp_channel_ind);</span><br><span style="color: hsl(120, 100%, 40%);">+             *out->channel_ind = *TLVP_VAL(tp, CBSP_IEI_CHANNEL_IND);</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 osmo_cbsp_decoded *osmo_cbsp_decode(void *ctx, struct msgb *in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct osmo_cbsp_decoded *out = talloc_zero(ctx, struct osmo_cbsp_decoded);</span><br><span style="color: hsl(120, 100%, 40%);">+   const struct cbsp_header *h = msgb_l1(in);</span><br><span style="color: hsl(120, 100%, 40%);">+    struct tlv_parsed tp[16]; /* max. number of pages in a given CBS message */</span><br><span style="color: hsl(120, 100%, 40%);">+   unsigned int len;</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 (!out)</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%);">+        if (msgb_l1len(in) < sizeof(*h)) {</span><br><span style="color: hsl(120, 100%, 40%);">+         goto out_err;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+     len = h->len[0] << 16 | h->len[1] << 8 | h->len[2];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* discard messages where indicated length is more than we have */</span><br><span style="color: hsl(120, 100%, 40%);">+    if (len > msgb_l2len(in)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                goto out_err;</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%);">+   /* trim any messages with extra payload at the end */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (len < msgb_l2len(in))</span><br><span style="color: hsl(120, 100%, 40%);">+          msgb_trim(in, (in->l2h - in->data) + msgb_l2len(in));</span><br><span style="color: hsl(120, 100%, 40%);">+   out->msg_type = h->msg_type;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  rc = tlv_parse2(tp, ARRAY_SIZE(tp), &cbsp_att_tlvdef, msgb_l2(in), msgb_l2len(in), 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              goto out_err;</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%);">+   switch (h->msg_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+     case CBSP_MSGT_WRITE_REPLACE:</span><br><span style="color: hsl(120, 100%, 40%);">+         rc = cbsp_dec_write_repl(&out->u.write_replace, tp, in);</span><br><span style="color: hsl(120, 100%, 40%);">+               break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CBSP_MSGT_WRITE_REPLACE_COMPL:</span><br><span style="color: hsl(120, 100%, 40%);">+           rc = cbsp_dec_write_repl_compl(&out->u.write_replace_compl, tp, in);</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CBSP_MSGT_WRITE_REPLACE_FAIL:</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = cbsp_dec_write_repl_fail(&out->u.write_replace_fail, tp, in);</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CBSP_MSGT_KILL:</span><br><span style="color: hsl(120, 100%, 40%);">+          rc = cbsp_dec_kill(&out->u.kill, tp, in);</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CBSP_MSGT_KILL_COMPL:</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = cbsp_dec_kill_compl(&out->u.kill_compl, tp, in);</span><br><span style="color: hsl(120, 100%, 40%);">+          break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CBSP_MSGT_KILL_FAIL:</span><br><span style="color: hsl(120, 100%, 40%);">+             rc = cbsp_dec_kill_fail(&out->u.kill_fail, tp, in);</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CBSP_MSGT_LOAD_QUERY:</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = cbsp_dec_load_query(&out->u.load_query, tp, in);</span><br><span style="color: hsl(120, 100%, 40%);">+          break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CBSP_MSGT_LOAD_QUERY_COMPL:</span><br><span style="color: hsl(120, 100%, 40%);">+              rc = cbsp_dec_load_query_compl(&out->u.load_query_compl, tp, in);</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CBSP_MSGT_LOAD_QUERY_FAIL:</span><br><span style="color: hsl(120, 100%, 40%);">+               rc = cbsp_dec_load_query_fail(&out->u.load_query_fail, tp, in);</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CBSP_MSGT_MSG_STATUS_QUERY:</span><br><span style="color: hsl(120, 100%, 40%);">+              rc = cbsp_dec_msg_status_query(&out->u.msg_status_query, tp, in);</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CBSP_MSGT_MSG_STATUS_QUERY_COMPL:</span><br><span style="color: hsl(120, 100%, 40%);">+                rc = cbsp_dec_msg_status_query_compl(&out->u.msg_status_query_compl, tp, in);</span><br><span style="color: hsl(120, 100%, 40%);">+          break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CBSP_MSGT_MSG_STATUS_QUERY_FAIL:</span><br><span style="color: hsl(120, 100%, 40%);">+         rc = cbsp_dec_msg_status_query_fail(&out->u.msg_status_query_fail, tp, in);</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CBSP_MSGT_RESET:</span><br><span style="color: hsl(120, 100%, 40%);">+         rc = cbsp_dec_reset(&out->u.reset, tp, in);</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CBSP_MSGT_RESET_COMPL:</span><br><span style="color: hsl(120, 100%, 40%);">+           rc = cbsp_dec_reset_compl(&out->u.reset_compl, tp, in);</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CBSP_MSGT_RESET_FAIL:</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = cbsp_dec_reset_fail(&out->u.reset_fail, tp, in);</span><br><span style="color: hsl(120, 100%, 40%);">+          break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CBSP_MSGT_RESTART:</span><br><span style="color: hsl(120, 100%, 40%);">+               rc = cbsp_dec_restart(&out->u.restart, tp, in);</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CBSP_MSGT_FAILURE:</span><br><span style="color: hsl(120, 100%, 40%);">+               rc = cbsp_dec_failure(&out->u.failure, tp, in);</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CBSP_MSGT_ERROR_IND:</span><br><span style="color: hsl(120, 100%, 40%);">+             rc = cbsp_dec_error_ind(&out->u.error_ind, tp, in);</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CBSP_MSGT_KEEP_ALIVE:</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = cbsp_dec_keep_alive(&out->u.keep_alive, tp, in);</span><br><span style="color: hsl(120, 100%, 40%);">+          break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CBSP_MSGT_KEEP_ALIVE_COMPL:</span><br><span style="color: hsl(120, 100%, 40%);">+              rc = cbsp_dec_keep_alive_compl(&out->u.keep_alive_compl, tp, in);</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CBSP_MSGT_SET_DRX:</span><br><span style="color: hsl(120, 100%, 40%);">+       case CBSP_MSGT_SET_DRX_COMPL:</span><br><span style="color: hsl(120, 100%, 40%);">+ case CBSP_MSGT_SET_DRX_FAIL:</span><br><span style="color: hsl(120, 100%, 40%);">+          rc = -1;</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%);">+              rc = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</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 (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              goto out_err;</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 out;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+out_err:</span><br><span style="color: hsl(120, 100%, 40%);">+       talloc_free(out);</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/gsm/gsm48049.c b/src/gsm/gsm48049.c</span><br><span>new file mode 100644</span><br><span>index 0000000..bb204dc</span><br><span>--- /dev/null</span><br><span>+++ b/src/gsm/gsm48049.c</span><br><span>@@ -0,0 +1,114 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* CBSP is an ETSI/3GPP standard protocol used between CBC (Cell Brodadcast Centre)</span><br><span style="color: hsl(120, 100%, 40%);">+ * and BSC (Base Station Controller0 in 2G/GSM/GERAN networks.  It is specified</span><br><span style="color: hsl(120, 100%, 40%);">+ * in 3GPP TS 48.049</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2019 by Harald Welte <laforge@gnumonks.org></span><br><span style="color: hsl(120, 100%, 40%);">+ * All rights reserved.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Released under the terms of the GNU General Public License, Version 2 or</span><br><span style="color: hsl(120, 100%, 40%);">+ * (at your option) any later version.</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%);">+#include <stddef.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/tlv.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/protocol/gsm_48_049.h></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%);">+ * Protocol Definitions</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%);">+const struct value_string cbsp_msg_type_names[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+    { CBSP_MSGT_WRITE_REPLACE,              "WRITE-REPLACE" },</span><br><span style="color: hsl(120, 100%, 40%);">+  { CBSP_MSGT_WRITE_REPLACE_COMPL,        "WRITE-REPLACE COMPLETE" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { CBSP_MSGT_WRITE_REPLACE_FAIL,         "WRITE-REPLACE FAILURE" },</span><br><span style="color: hsl(120, 100%, 40%);">+  { CBSP_MSGT_KILL,                       "KILL" },</span><br><span style="color: hsl(120, 100%, 40%);">+   { CBSP_MSGT_KILL_COMPL,                 "KILL COMPLETE" },</span><br><span style="color: hsl(120, 100%, 40%);">+  { CBSP_MSGT_KILL_FAIL,                  "KILL FAILURE" },</span><br><span style="color: hsl(120, 100%, 40%);">+   { CBSP_MSGT_LOAD_QUERY,                 "LOAD QUERY" },</span><br><span style="color: hsl(120, 100%, 40%);">+     { CBSP_MSGT_LOAD_QUERY_COMPL,           "LOAD QUERY COMPLETE" },</span><br><span style="color: hsl(120, 100%, 40%);">+    { CBSP_MSGT_LOAD_QUERY_FAIL,            "LOAD QUERY FAILURE" },</span><br><span style="color: hsl(120, 100%, 40%);">+     { CBSP_MSGT_MSG_STATUS_QUERY,           "MESSAGE STATUS QUERY" },</span><br><span style="color: hsl(120, 100%, 40%);">+   { CBSP_MSGT_MSG_STATUS_QUERY_COMPL,     "MESSAGE STATUS QUERY COMPLETE" },</span><br><span style="color: hsl(120, 100%, 40%);">+  { CBSP_MSGT_MSG_STATUS_QUERY_FAIL,      "MESSAGE STATUS QUERY FAILURE" },</span><br><span style="color: hsl(120, 100%, 40%);">+   { CBSP_MSGT_SET_DRX,                    "SET-DRX" },</span><br><span style="color: hsl(120, 100%, 40%);">+        { CBSP_MSGT_SET_DRX_COMPL,              "SET-DRX COMPLETE" },</span><br><span style="color: hsl(120, 100%, 40%);">+       { CBSP_MSGT_SET_DRX_FAIL,               "SET-DRX FAILURE" },</span><br><span style="color: hsl(120, 100%, 40%);">+        { CBSP_MSGT_RESET,                      "RESET" },</span><br><span style="color: hsl(120, 100%, 40%);">+  { CBSP_MSGT_RESET_COMPL,                "RESET COMPLETE" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { CBSP_MSGT_RESET_FAIL,                 "RESET FAILURE" },</span><br><span style="color: hsl(120, 100%, 40%);">+  { CBSP_MSGT_RESTART,                    "RESTART" },</span><br><span style="color: hsl(120, 100%, 40%);">+        { CBSP_MSGT_FAILURE,                    "FAILURE" },</span><br><span style="color: hsl(120, 100%, 40%);">+        { CBSP_MSGT_ERROR_IND,                  "ERROR INDICATION" },</span><br><span style="color: hsl(120, 100%, 40%);">+       { CBSP_MSGT_KEEP_ALIVE,                 "KEEP-ALIVE" },</span><br><span style="color: hsl(120, 100%, 40%);">+     { CBSP_MSGT_KEEP_ALIVE_COMPL,           "KEEP-ALIVE COMPLETE" },</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%);">+const struct value_string cbsp_iei_names[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+     { CBSP_IEI_MSG_CONTENT,         "Message Content" },</span><br><span style="color: hsl(120, 100%, 40%);">+        { CBSP_IEI_OLD_SERIAL_NR,       "Old Serial Number" },</span><br><span style="color: hsl(120, 100%, 40%);">+      { CBSP_IEI_NEW_SERIAL_NR,       "New Serial Number" },</span><br><span style="color: hsl(120, 100%, 40%);">+      { CBSP_IEI_CELL_LIST,           "Cell List" },</span><br><span style="color: hsl(120, 100%, 40%);">+      { CBSP_IEI_CATEGORY,            "Category" },</span><br><span style="color: hsl(120, 100%, 40%);">+       { CBSP_IEI_REP_PERIOD,          "Repetition Period" },</span><br><span style="color: hsl(120, 100%, 40%);">+      { CBSP_IEI_NUM_BCAST_REQ,       "Number of Broadcasts Requested" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { CBSP_IEI_NUM_BCAST_COMPL_LIST,"Number of Broadcasts Completed List" },</span><br><span style="color: hsl(120, 100%, 40%);">+    { CBSP_IEI_FAILURE_LIST,        "Failure List" },</span><br><span style="color: hsl(120, 100%, 40%);">+   { CBSP_IEI_RR_LOADING_LIST,     "Radio Resource Loading List" },</span><br><span style="color: hsl(120, 100%, 40%);">+    { CBSP_IEI_CAUSE,               "Cause" },</span><br><span style="color: hsl(120, 100%, 40%);">+  { CBSP_IEI_DCS,                 "Data Coding Scheme" },</span><br><span style="color: hsl(120, 100%, 40%);">+     { CBSP_IEI_RECOVERY_IND,        "Recovery Indication" },</span><br><span style="color: hsl(120, 100%, 40%);">+    { CBSP_IEI_MSG_ID,              "Message Identifier" },</span><br><span style="color: hsl(120, 100%, 40%);">+     { CBSP_IEI_EMERG_IND,           "Emergency Indicator" },</span><br><span style="color: hsl(120, 100%, 40%);">+    { CBSP_IEI_WARN_TYPE,           "Warning Type" },</span><br><span style="color: hsl(120, 100%, 40%);">+   { CBSP_IEI_WARN_SEC_INFO,       "warning Security Information" },</span><br><span style="color: hsl(120, 100%, 40%);">+   { CBSP_IEI_CHANNEL_IND,         "Channel Indicator" },</span><br><span style="color: hsl(120, 100%, 40%);">+      { CBSP_IEI_NUM_OF_PAGES,        "Number of Pages" },</span><br><span style="color: hsl(120, 100%, 40%);">+        { CBSP_IEI_SCHEDULE_PERIOD,     "Schedule Period" },</span><br><span style="color: hsl(120, 100%, 40%);">+        { CBSP_IEI_NUM_OF_RES_SLOTS,    "Number of Reserved Slots" },</span><br><span style="color: hsl(120, 100%, 40%);">+       { CBSP_IEI_BCAST_MSG_TYPE,      "Broadcast Message Type" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { CBSP_IEI_WARNING_PERIOD,      "Waring Period" },</span><br><span style="color: hsl(120, 100%, 40%);">+  { CBSP_IEI_KEEP_ALIVE_REP_PERIOD, "Keep Alive Repetition Period" },</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%);">+const struct value_string cbsp_category_names[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+        { CBSP_CATEG_HIGH_PRIO,         "High Priority" },</span><br><span style="color: hsl(120, 100%, 40%);">+  { CBSP_CATEG_BACKGROUND,        "Background" },</span><br><span style="color: hsl(120, 100%, 40%);">+     { CBSP_CATEG_NORMAL,            "Normal" },</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%);">+const struct tlv_definition cbsp_att_tlvdef = {</span><br><span style="color: hsl(120, 100%, 40%);">+    .def = {</span><br><span style="color: hsl(120, 100%, 40%);">+              [CBSP_IEI_MSG_CONTENT] =                { TLV_TYPE_FIXED, 83 },</span><br><span style="color: hsl(120, 100%, 40%);">+               [CBSP_IEI_OLD_SERIAL_NR] =              { TLV_TYPE_FIXED, 2 },</span><br><span style="color: hsl(120, 100%, 40%);">+                [CBSP_IEI_NEW_SERIAL_NR] =              { TLV_TYPE_FIXED, 2 },</span><br><span style="color: hsl(120, 100%, 40%);">+                [CBSP_IEI_CELL_LIST] =                  { TLV_TYPE_TL16V },</span><br><span style="color: hsl(120, 100%, 40%);">+           [CBSP_IEI_CATEGORY] =                   { TLV_TYPE_TV },</span><br><span style="color: hsl(120, 100%, 40%);">+              [CBSP_IEI_REP_PERIOD] =                 { TLV_TYPE_FIXED, 2 },</span><br><span style="color: hsl(120, 100%, 40%);">+                [CBSP_IEI_NUM_BCAST_REQ] =              { TLV_TYPE_FIXED, 2 },</span><br><span style="color: hsl(120, 100%, 40%);">+                [CBSP_IEI_NUM_BCAST_COMPL_LIST] =       { TLV_TYPE_TL16V },</span><br><span style="color: hsl(120, 100%, 40%);">+           [CBSP_IEI_FAILURE_LIST] =               { TLV_TYPE_TL16V },</span><br><span style="color: hsl(120, 100%, 40%);">+           [CBSP_IEI_RR_LOADING_LIST] =            { TLV_TYPE_TL16V },</span><br><span style="color: hsl(120, 100%, 40%);">+           [CBSP_IEI_CAUSE] =                      { TLV_TYPE_TV },</span><br><span style="color: hsl(120, 100%, 40%);">+              [CBSP_IEI_DCS] =                        { TLV_TYPE_TV },</span><br><span style="color: hsl(120, 100%, 40%);">+              [CBSP_IEI_RECOVERY_IND]                 { TLV_TYPE_TV },</span><br><span style="color: hsl(120, 100%, 40%);">+              [CBSP_IEI_MSG_ID] =                     { TLV_TYPE_FIXED, 2 },</span><br><span style="color: hsl(120, 100%, 40%);">+                [CBSP_IEI_EMERG_IND] =                  { TLV_TYPE_TV },</span><br><span style="color: hsl(120, 100%, 40%);">+              [CBSP_IEI_WARN_TYPE] =                  { TLV_TYPE_FIXED, 2 },</span><br><span style="color: hsl(120, 100%, 40%);">+                [CBSP_IEI_WARN_SEC_INFO] =              { TLV_TYPE_FIXED, 50 },</span><br><span style="color: hsl(120, 100%, 40%);">+               [CBSP_IEI_CHANNEL_IND] =                { TLV_TYPE_TV },</span><br><span style="color: hsl(120, 100%, 40%);">+              [CBSP_IEI_NUM_OF_PAGES] =               { TLV_TYPE_TV },</span><br><span style="color: hsl(120, 100%, 40%);">+              [CBSP_IEI_SCHEDULE_PERIOD] =            { TLV_TYPE_TV },</span><br><span style="color: hsl(120, 100%, 40%);">+              [CBSP_IEI_NUM_OF_RES_SLOTS] =           { TLV_TYPE_TV },</span><br><span style="color: hsl(120, 100%, 40%);">+              [CBSP_IEI_BCAST_MSG_TYPE] =             { TLV_TYPE_TV },</span><br><span style="color: hsl(120, 100%, 40%);">+              [CBSP_IEI_WARNING_PERIOD] =             { TLV_TYPE_TV },</span><br><span style="color: hsl(120, 100%, 40%);">+              [CBSP_IEI_KEEP_ALIVE_REP_PERIOD] =      { TLV_TYPE_TV },</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%);">+ * Protocol Implementation</span><br><span style="color: hsl(120, 100%, 40%);">+ ***********************************************************************/</span><br><span>diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map</span><br><span>index 9aa9683..203591a 100644</span><br><span>--- a/src/gsm/libosmogsm.map</span><br><span>+++ b/src/gsm/libosmogsm.map</span><br><span>@@ -644,5 +644,13 @@</span><br><span> osmo_gsm48_classmark_a5_name_c;</span><br><span> osmo_gsm48_classmark_update;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+cbsp_msg_type_names;</span><br><span style="color: hsl(120, 100%, 40%);">+cbsp_iei_names;</span><br><span style="color: hsl(120, 100%, 40%);">+cbsp_category_names;</span><br><span style="color: hsl(120, 100%, 40%);">+cbsp_att_tlvdef;</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_cbsp_msgb_alloc;</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_cbsp_encode;</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_cbsp_decode;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> local: *;</span><br><span> };</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/libosmocore/+/14360">change 14360</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/libosmocore/+/14360"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: libosmocore </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: I5b7ae08f67e415967b60ac4b824db9e22ca00935 </div>
<div style="display:none"> Gerrit-Change-Number: 14360 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Harald Welte <laforge@gnumonks.org> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>