<p>laforge <strong>submitted</strong> this change.</p><p><a href="https://gerrit.osmocom.org/c/libosmocore/+/6357">View Change</a></p><div style="white-space:pre-wrap">Approvals:
Jenkins Builder: Verified
osmith: Looks good to me, but someone else must approve
laforge: Looks good to me, approved
</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">Introduce CRC and FSM for IuUP (user plane) as used in 3G RTP data<br><br>Only support for SMpSDU mode is introduced in this commit.<br><br>Not supported explicit list:<br>- Transparent mode<br>- ATM/AAL2 based Transport layer<br>- GTP-U based Transport Layer<br>- Iu Rate Control procedure<br>- Time Alignment procedure<br><br>APIs are provided to allocate the primitives properly inside the related<br>msgb. This way primitives can be placed in the headroom, leaving the<br>data part of the msgb for the IuUP payload, hence allowing re-use of the<br>msgb and 0 copy of IuUP payload when forwarding data over RNL<->TNL.<br>Since RNL and TNL primitives relu struct osmo_prim_header, which is not<br>packed, they cannot be set to packed, and hence proper memory alignment<br>in the msgb must be done to avoid misaligned accesses (Asan errors about<br>it otherwise).<br><br>Related: SYS#5516<br>Change-Id: Ibe356fa7b1abaca0091e368db8478e79c09c6cb0<br>---<br>M include/Makefile.am<br>M include/osmocom/core/logging.h<br>A include/osmocom/gsm/iuup.h<br>M include/osmocom/gsm/prim.h<br>A include/osmocom/gsm/protocol/gsm_25_415.h<br>M src/gsm/Makefile.am<br>A src/gsm/iuup.c<br>M src/gsm/libosmogsm.map<br>M src/logging.c<br>M tests/Makefile.am<br>A tests/iuup/iuup_test.c<br>A tests/iuup/iuup_test.ok<br>M tests/logging/logging_vty_test.vty<br>M tests/testsuite.at<br>14 files changed, 1,980 insertions(+), 4 deletions(-)<br><br></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 e3246cf..eab0489 100644</span><br><span>--- a/include/Makefile.am</span><br><span>+++ b/include/Makefile.am</span><br><span>@@ -125,6 +125,7 @@</span><br><span> osmocom/gsm/gsup_sms.h \</span><br><span> osmocom/gsm/i460_mux.h \</span><br><span> osmocom/gsm/ipa.h \</span><br><span style="color: hsl(120, 100%, 40%);">+ osmocom/gsm/iuup.h \</span><br><span> osmocom/gsm/lapd_core.h \</span><br><span> osmocom/gsm/lapdm.h \</span><br><span> osmocom/gsm/meas_rep.h \</span><br><span>@@ -148,6 +149,7 @@</span><br><span> osmocom/gsm/protocol/gsm_12_21.h \</span><br><span> osmocom/gsm/protocol/gsm_23_003.h \</span><br><span> osmocom/gsm/protocol/gsm_23_041.h \</span><br><span style="color: hsl(120, 100%, 40%);">+ osmocom/gsm/protocol/gsm_25_415.h \</span><br><span> osmocom/gsm/protocol/gsm_29_118.h \</span><br><span> osmocom/gsm/protocol/gsm_44_004.h \</span><br><span> osmocom/gsm/protocol/gsm_44_318.h \</span><br><span>diff --git a/include/osmocom/core/logging.h b/include/osmocom/core/logging.h</span><br><span>index 18ad3ff..7907734 100644</span><br><span>--- a/include/osmocom/core/logging.h</span><br><span>+++ b/include/osmocom/core/logging.h</span><br><span>@@ -136,7 +136,8 @@</span><br><span> #define DLBSSGP -21 /*!< Osmocom BSSGP layer */</span><br><span> #define DLNSDATA -22 /*!< Osmocom NS layer data pdus */</span><br><span> #define DLNSSIGNAL -23 /*!< Osmocom NS layer signal pdus */</span><br><span style="color: hsl(0, 100%, 40%);">-#define OSMO_NUM_DLIB 23 /*!< Number of logging sub-systems in libraries */</span><br><span style="color: hsl(120, 100%, 40%);">+#define DLIUUP -24 /*!< Osmocom IuUP layer */</span><br><span style="color: hsl(120, 100%, 40%);">+#define OSMO_NUM_DLIB 24 /*!< Number of logging sub-systems in libraries */</span><br><span> </span><br><span> /* Colors that can be used in log_info_cat.color */</span><br><span> #define OSMO_LOGCOLOR_NORMAL NULL</span><br><span>diff --git a/include/osmocom/gsm/iuup.h b/include/osmocom/gsm/iuup.h</span><br><span>new file mode 100644</span><br><span>index 0000000..b1651c5</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/gsm/iuup.h</span><br><span>@@ -0,0 +1,122 @@</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/prim.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/protocol/gsm_25_415.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%);">+ * Primitives towards the lower layers (typically RTP transport)</span><br><span style="color: hsl(120, 100%, 40%);">+ ***********************************************************************/</span><br><span style="color: hsl(120, 100%, 40%);">+enum osmo_iuup_tnl_prim_type {</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_IUUP_TNL_UNITDATA,</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_iuup_tnl_prim {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_prim_hdr oph;</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%);">+ * Primitives towards the upper layers at the RNL SAP</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%);">+/* 3GPP TS 25.415 Section 7.2.1 */</span><br><span style="color: hsl(120, 100%, 40%);">+enum osmo_iuup_rnl_prim_type {</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_IUUP_RNL_CONFIG,</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_IUUP_RNL_DATA,</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_IUUP_RNL_STATUS,</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_IUUP_RNL_UNIT_DATA,</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%);">+/* TS 25.413 9.2.1.3*/</span><br><span style="color: hsl(120, 100%, 40%);">+#define IUUP_MAX_SUBFLOWS 7</span><br><span style="color: hsl(120, 100%, 40%);">+#define IUUP_MAX_RFCIS 64</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define IUUP_TIMER_INIT_T_DEFAULT 1000</span><br><span style="color: hsl(120, 100%, 40%);">+#define IUUP_TIMER_TA_T_DEFAULT 500</span><br><span style="color: hsl(120, 100%, 40%);">+#define IUUP_TIMER_RC_T_DEFAULT 500</span><br><span style="color: hsl(120, 100%, 40%);">+#define IUUP_TIMER_INIT_N_DEFAULT 3</span><br><span style="color: hsl(120, 100%, 40%);">+#define IUUP_TIMER_TA_N_DEFAULT 1</span><br><span style="color: hsl(120, 100%, 40%);">+#define IUUP_TIMER_RC_N_DEFAULT 1</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_iuup_rnl_config_timer {</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t t_ms; /* time in ms */</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t n_max; /* max number of repetitions */</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_iuup_rnl_config {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* transparent (true) or SMpSDU (false): */</span><br><span style="color: hsl(120, 100%, 40%);">+ bool transparent;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* should we actively transmit INIT in SmpSDU mode? */</span><br><span style="color: hsl(120, 100%, 40%);">+ bool active;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Currently Version 0 or 1: */</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t data_pdu_type;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Supported mode versions */</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t supported_versions_mask;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t num_rfci;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t num_subflows;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t subflow_sizes[IUUP_MAX_RFCIS][IUUP_MAX_SUBFLOWS];</span><br><span style="color: hsl(120, 100%, 40%);">+ bool IPTIs_present;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t IPTIs[IUUP_MAX_RFCIS]; /* values range 0-15, 4 bits */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* TODO: Indication of delivery of erroneous SDUs*/</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_rnl_config_timer t_init;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_rnl_config_timer t_ta;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_rnl_config_timer t_rc;</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_iuup_rnl_data {</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t rfci;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t frame_nr;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t fqc;</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_iuup_rnl_status {</span><br><span style="color: hsl(120, 100%, 40%);">+ enum iuup_procedure procedure;</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 iuup_error_cause cause;</span><br><span style="color: hsl(120, 100%, 40%);">+ enum iuup_error_distance distance;</span><br><span style="color: hsl(120, 100%, 40%);">+ } error_event;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct {</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t supported_versions_mask;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t num_subflows;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t num_rfci;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t subflow_sizes[IUUP_MAX_RFCIS][IUUP_MAX_SUBFLOWS];</span><br><span style="color: hsl(120, 100%, 40%);">+ bool IPTIs_present;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t IPTIs[IUUP_MAX_RFCIS]; /* values range 0-15, 4 bits */</span><br><span style="color: hsl(120, 100%, 40%);">+ } initialization;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct {</span><br><span style="color: hsl(120, 100%, 40%);">+ } rate_control;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct {</span><br><span style="color: hsl(120, 100%, 40%);">+ } time_alignment;</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%);">+/* SAP on the upper side of IuUP, towards the user */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_iuup_rnl_prim {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_prim_hdr oph;</span><br><span style="color: hsl(120, 100%, 40%);">+ union {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_rnl_config config;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_rnl_data data;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_rnl_status status;</span><br><span style="color: hsl(120, 100%, 40%);">+ //struct osmo_iuup_rnl_unitdata unitdata;</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 osmo_iuup_instance;</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_iuup_instance *osmo_iuup_instance_alloc(void *ctx, const char *id);</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_iuup_instance_free(struct osmo_iuup_instance *iui);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_iuup_instance_set_user_prim_cb(struct osmo_iuup_instance *iui, osmo_prim_cb func, void *priv);</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_iuup_instance_set_transport_prim_cb(struct osmo_iuup_instance *iui, osmo_prim_cb func, void *priv);</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_iuup_tnl_prim_up(struct osmo_iuup_instance *iui, struct osmo_iuup_tnl_prim *itp);</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_iuup_rnl_prim_down(struct osmo_iuup_instance *inst, struct osmo_iuup_rnl_prim *irp);</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%);">+int osmo_iuup_compute_header_crc(const uint8_t *iuup_pdu, unsigned int pdu_len);</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_iuup_compute_payload_crc(const uint8_t *iuup_pdu, unsigned int pdu_len);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_iuup_rnl_prim *osmo_iuup_rnl_prim_alloc(void *ctx, unsigned int primitive, unsigned int operation, unsigned int size);</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_iuup_tnl_prim *osmo_iuup_tnl_prim_alloc(void *ctx, unsigned int primitive, unsigned int operation, unsigned int size);</span><br><span>diff --git a/include/osmocom/gsm/prim.h b/include/osmocom/gsm/prim.h</span><br><span>index 045e353..73cd7f7 100644</span><br><span>--- a/include/osmocom/gsm/prim.h</span><br><span>+++ b/include/osmocom/gsm/prim.h</span><br><span>@@ -18,4 +18,7 @@</span><br><span> SAP_NS,</span><br><span> </span><br><span> SAP_BSSGP_RIM,</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ SAP_IUUP_TNL,</span><br><span style="color: hsl(120, 100%, 40%);">+ SAP_IUUP_RNL,</span><br><span> };</span><br><span>diff --git a/include/osmocom/gsm/protocol/gsm_25_415.h b/include/osmocom/gsm/protocol/gsm_25_415.h</span><br><span>new file mode 100644</span><br><span>index 0000000..5d90fd3</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/gsm/protocol/gsm_25_415.h</span><br><span>@@ -0,0 +1,222 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#pragma once</span><br><span style="color: hsl(120, 100%, 40%);">+/* Iu User Plane (IuUP) Definitions as per 3GPP TS 25.415 */</span><br><span style="color: hsl(120, 100%, 40%);">+/* (C) 2017 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%);">+ * SPDX-License-Identifier: GPL-2.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%);">+#include <stdint.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/endian.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* 3GPP TS 25.415 Section 6.6.2.1 */</span><br><span style="color: hsl(120, 100%, 40%);">+struct iuup_pdutype0_hdr {</span><br><span style="color: hsl(120, 100%, 40%);">+#if OSMO_IS_LITTLE_ENDIAN</span><br><span style="color: hsl(120, 100%, 40%);">+ /* control part */</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t frame_nr:4,</span><br><span style="color: hsl(120, 100%, 40%);">+ pdu_type:4;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t rfci:6,</span><br><span style="color: hsl(120, 100%, 40%);">+ fqc:2;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* checksum part */</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t payload_crc_hi:2, header_crc:6;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t payload_crc_lo;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* payload part */</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t payload[0];</span><br><span style="color: hsl(120, 100%, 40%);">+#elif OSMO_IS_BIG_ENDIAN</span><br><span style="color: hsl(120, 100%, 40%);">+/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t pdu_type:4, frame_nr:4;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t fqc:2, rfci:6;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t header_crc:6, payload_crc_hi:2;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t payload_crc_lo;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t payload[0];</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</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%);">+/* 3GPP TS 25.415 Section 6.6.2.2 */</span><br><span style="color: hsl(120, 100%, 40%);">+struct iuup_pdutype1_hdr {</span><br><span style="color: hsl(120, 100%, 40%);">+#if OSMO_IS_LITTLE_ENDIAN</span><br><span style="color: hsl(120, 100%, 40%);">+ /* control part */</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t frame_nr:4,</span><br><span style="color: hsl(120, 100%, 40%);">+ pdu_type:4;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t rfci:6,</span><br><span style="color: hsl(120, 100%, 40%);">+ fqc:2;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* checksum part */</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t spare:2,</span><br><span style="color: hsl(120, 100%, 40%);">+ header_crc:6;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* payload part */</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t payload[0];</span><br><span style="color: hsl(120, 100%, 40%);">+#elif OSMO_IS_BIG_ENDIAN</span><br><span style="color: hsl(120, 100%, 40%);">+/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t pdu_type:4, frame_nr:4;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t fqc:2, rfci:6;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t header_crc:6, spare:2;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t payload[0];</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</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%);">+/* 3GPP TS 25.415 Section 6.6.2.3 */</span><br><span style="color: hsl(120, 100%, 40%);">+struct iuup_pdutype14_hdr {</span><br><span style="color: hsl(120, 100%, 40%);">+#if OSMO_IS_LITTLE_ENDIAN</span><br><span style="color: hsl(120, 100%, 40%);">+ /* control part */</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t frame_nr:2,</span><br><span style="color: hsl(120, 100%, 40%);">+ ack_nack:2,</span><br><span style="color: hsl(120, 100%, 40%);">+ pdu_type:4;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t proc_ind:4,</span><br><span style="color: hsl(120, 100%, 40%);">+ mode_version:4;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* checksum part */</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t payload_crc_hi:2, header_crc:6;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t payload_crc_lo;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* payload part */</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t payload[0];</span><br><span style="color: hsl(120, 100%, 40%);">+#elif OSMO_IS_BIG_ENDIAN</span><br><span style="color: hsl(120, 100%, 40%);">+/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t pdu_type:4, ack_nack:2, frame_nr:2;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t mode_version:4, proc_ind:4;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t header_crc:6, payload_crc_hi:2;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t payload_crc_lo;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t payload[0];</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</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%);">+/* 3GPP TS 25.415 Section 6.6.2.3.4.1 */</span><br><span style="color: hsl(120, 100%, 40%);">+struct iuup_ctrl_init_rfci_hdr {</span><br><span style="color: hsl(120, 100%, 40%);">+#if OSMO_IS_LITTLE_ENDIAN</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t rfci:6,</span><br><span style="color: hsl(120, 100%, 40%);">+ li:1,</span><br><span style="color: hsl(120, 100%, 40%);">+ lri:1;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t subflow_length[0]; /* 1 or 2 bytes depending on li */</span><br><span style="color: hsl(120, 100%, 40%);">+#elif OSMO_IS_BIG_ENDIAN</span><br><span style="color: hsl(120, 100%, 40%);">+/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t lri:1, li:1, rfci:6;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t subflow_length[0];</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+} __attribute__((packed));</span><br><span style="color: hsl(120, 100%, 40%);">+struct iuup_ctrl_init_hdr {</span><br><span style="color: hsl(120, 100%, 40%);">+#if OSMO_IS_LITTLE_ENDIAN</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t chain_ind:1,</span><br><span style="color: hsl(120, 100%, 40%);">+ num_subflows_per_rfci:3,</span><br><span style="color: hsl(120, 100%, 40%);">+ ti:1,</span><br><span style="color: hsl(120, 100%, 40%);">+ spare:3;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t rfci_data[0]; /* struct iuup_ctrl_init_rfci_hdr* */</span><br><span style="color: hsl(120, 100%, 40%);">+#elif OSMO_IS_BIG_ENDIAN</span><br><span style="color: hsl(120, 100%, 40%);">+/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t spare:3, ti:1, num_subflows_per_rfci:3, chain_ind:1;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t rfci_data[0]; /* struct iuup_ctrl_init_rfci_hdr* */</span><br><span style="color: hsl(120, 100%, 40%);">+;</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+} __attribute__((packed));</span><br><span style="color: hsl(120, 100%, 40%);">+struct iuup_ctrl_init_tail {</span><br><span style="color: hsl(120, 100%, 40%);">+#if OSMO_IS_LITTLE_ENDIAN</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t versions_supported;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t spare:4,</span><br><span style="color: hsl(120, 100%, 40%);">+ data_pdu_type:4;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t spare_extension[0];</span><br><span style="color: hsl(120, 100%, 40%);">+#elif OSMO_IS_BIG_ENDIAN</span><br><span style="color: hsl(120, 100%, 40%);">+/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t versions_supported;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t data_pdu_type:4, spare:4;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t spare_extension[0];</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</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%);">+/* 3GPP TS 25.415 Section 6.6.2.3.4.4 */</span><br><span style="color: hsl(120, 100%, 40%);">+struct iuup_ctrl_error_event {</span><br><span style="color: hsl(120, 100%, 40%);">+#if OSMO_IS_LITTLE_ENDIAN</span><br><span style="color: hsl(120, 100%, 40%);">+ struct iuup_pdutype14_hdr hdr;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t error_cause:6,</span><br><span style="color: hsl(120, 100%, 40%);">+ error_distance:2;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t spare_extension[0];</span><br><span style="color: hsl(120, 100%, 40%);">+#elif OSMO_IS_BIG_ENDIAN</span><br><span style="color: hsl(120, 100%, 40%);">+/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct iuup_pdutype14_hdr hdr;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t error_distance:2, error_cause:6;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t spare_extension[0];</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</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%);">+/* 3GPP TS 25.415 Section 6.6.2.3.2 */</span><br><span style="color: hsl(120, 100%, 40%);">+struct iuup_ctrl_ack {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct iuup_pdutype14_hdr hdr;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t spare_extension[0];</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%);">+/* 3GPP TS 25.415 Section 6.6.2.3.3 */</span><br><span style="color: hsl(120, 100%, 40%);">+struct iuup_ctrl_nack {</span><br><span style="color: hsl(120, 100%, 40%);">+#if OSMO_IS_LITTLE_ENDIAN</span><br><span style="color: hsl(120, 100%, 40%);">+ struct iuup_pdutype14_hdr hdr;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t spare:2,</span><br><span style="color: hsl(120, 100%, 40%);">+ error_cause:6;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t spare_extension[0];</span><br><span style="color: hsl(120, 100%, 40%);">+#elif OSMO_IS_BIG_ENDIAN</span><br><span style="color: hsl(120, 100%, 40%);">+/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct iuup_pdutype14_hdr hdr;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t error_cause:6, spare:2;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t spare_extension[0];</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</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%);">+/* 3GPP TS 25.415 Section 6.6.2 + 6.6.3.1 */</span><br><span style="color: hsl(120, 100%, 40%);">+enum iuup_pdu_type {</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_PDU_T_DATA_CRC = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_PDU_T_DATA_NOCRC = 1,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_PDU_T_CONTROL = 14,</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%);">+/* 3GPP TS 25.415 Section 6.6.3.2 */</span><br><span style="color: hsl(120, 100%, 40%);">+enum iuup_ack_nack {</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_AN_PROCEDURE = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_AN_ACK = 1,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_AN_NACK = 2,</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%);">+/* 3GPP TS 25.415 Section 6.6.3.5 */</span><br><span style="color: hsl(120, 100%, 40%);">+enum iuup_fqc {</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_FQC_FRAME_GOOD = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_FQC_FRAME_BAD = 1,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_FQC_FRAME_BAD_RADIO = 2,</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%);">+/* 3GPP TS 25.415 Section 6.6.3.7 */</span><br><span style="color: hsl(120, 100%, 40%);">+enum iuup_procedure {</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_PROC_INIT = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_PROC_RATE_CTRL = 1,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_PROC_TIME_ALIGN = 2,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_PROC_ERR_EVENT = 3,</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%);">+/* 3GPP TS 25.415 Section 6.6.3.15 */</span><br><span style="color: hsl(120, 100%, 40%);">+enum iuup_error_distance {</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_ERR_DIST_LOCAL = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_ERR_DIST_FIRST_FWD = 1,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_ERR_DIST_SECOND_FWD = 2,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_ERR_DIST_RESERVED = 3,</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%);">+/* 3GPP TS 25.415 Section 6.6.3.16 */</span><br><span style="color: hsl(120, 100%, 40%);">+enum iuup_error_cause {</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_ERR_CAUSE_CRC_ERR_HDR = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_ERR_CAUSE_CRC_ERR_DATA = 1,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_ERR_CAUSE_UNEXPECTED_FN = 2,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_ERR_CAUSE_FRAME_LOSS = 3,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_ERR_CAUSE_UNKNOWN_PDUTYPE = 4,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_ERR_CAUSE_UNKNOWN_PROC = 5,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_ERR_CAUSE_UNKNNOWN_RES_VAL = 6,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_ERR_CAUSE_UNKNNOWN_FIELD = 7,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_ERR_CAUSE_FRAME_TOO_SHORT = 8,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_ERR_CAUSE_MISSING_FIELDS = 9,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_ERR_CAUSE_UNEXPECTED_PDU_T = 16,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_ERR_CAUSE_UNEXPECTED_PROC = 18,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_ERR_CAUSE_UNEXPECTED_RFCI = 19,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_ERR_CAUSE_UNEXPECTED_VALUE = 20,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_ERR_CAUSE_INIT_FAILURE = 42,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_ERR_CAUSE_INIT_FAILURE_NET_TMR = 43,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_ERR_CAUSE_INIT_FAILURE_REP_NACK = 44,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_ERR_CAUSE_RATE_CTRL_FAILURE = 45,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_ERR_CAUSE_ERR_EVENT_FAIL = 46,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_ERR_CAUSE_TIME_ALIGN_NOTSUPP = 47,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_ERR_CAUSE_REQ_TIME_ALIGN_NOTPOSS = 48,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_ERR_CAUSE_MODE_VERSION_NOT_SUPPORTED = 49,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span>diff --git a/src/gsm/Makefile.am b/src/gsm/Makefile.am</span><br><span>index 580e397..326efd2 100644</span><br><span>--- a/src/gsm/Makefile.am</span><br><span>+++ b/src/gsm/Makefile.am</span><br><span>@@ -33,7 +33,7 @@</span><br><span> gsup.c gsup_sms.c gprs_gea.c gsm0503_conv.c oap.c gsm0808_utils.c \</span><br><span> gsm23003.c gsm23236.c mncc.c bts_features.c oap_client.c \</span><br><span> gsm29118.c gsm48_rest_octets.c cbsp.c gsm48049.c i460_mux.c \</span><br><span style="color: hsl(0, 100%, 40%);">- gad.c bsslap.c bssmap_le.c kdf.c</span><br><span style="color: hsl(120, 100%, 40%);">+ gad.c bsslap.c bssmap_le.c kdf.c iuup.c</span><br><span> </span><br><span> libgsmint_la_LDFLAGS = -no-undefined</span><br><span> libgsmint_la_LIBADD = $(top_builddir)/src/libosmocore.la</span><br><span>diff --git a/src/gsm/iuup.c b/src/gsm/iuup.c</span><br><span>new file mode 100644</span><br><span>index 0000000..159e533</span><br><span>--- /dev/null</span><br><span>+++ b/src/gsm/iuup.c</span><br><span>@@ -0,0 +1,1007 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \file iu_up.c</span><br><span style="color: hsl(120, 100%, 40%);">+ * IuUP (Iu User Plane) according to 3GPP TS 25.415 */</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2017 by Harald Welte <laforge@gnumonks.org></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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <inttypes.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/crc8gen.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/crc16gen.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/fsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/prim.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/timer.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/logging.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/prim.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/protocol/gsm_25_415.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/iuup.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%);">+ * CRC Calculation</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%);">+/* Section 6.6.3.8 Header CRC */</span><br><span style="color: hsl(120, 100%, 40%);">+const struct osmo_crc8gen_code iuup_hdr_crc_code = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .bits = 6,</span><br><span style="color: hsl(120, 100%, 40%);">+ .poly = 47,</span><br><span style="color: hsl(120, 100%, 40%);">+ .init = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+ .remainder = 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%);">+/* Section 6.6.3.9 Payload CRC */</span><br><span style="color: hsl(120, 100%, 40%);">+const struct osmo_crc16gen_code iuup_data_crc_code = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .bits = 10,</span><br><span style="color: hsl(120, 100%, 40%);">+ .poly = 563,</span><br><span style="color: hsl(120, 100%, 40%);">+ .init = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+ .remainder = 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%);">+static int iuup_get_payload_offset(const uint8_t *iuup_pdu)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t pdu_type = iuup_pdu[0] >> 4;</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (pdu_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case 0:</span><br><span style="color: hsl(120, 100%, 40%);">+ case 14:</span><br><span style="color: hsl(120, 100%, 40%);">+ return 4;</span><br><span style="color: hsl(120, 100%, 40%);">+ case 1:</span><br><span style="color: hsl(120, 100%, 40%);">+ return 3;</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</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%);">+int osmo_iuup_compute_payload_crc(const uint8_t *iuup_pdu, unsigned int pdu_len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ ubit_t buf[1024*8];</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t pdu_type;</span><br><span style="color: hsl(120, 100%, 40%);">+ int offset, payload_len_bytes;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (pdu_len < 1)</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%);">+ pdu_type = iuup_pdu[0] >> 4;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Type 1 has no CRC */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (pdu_type == 1)</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%);">+ offset = iuup_get_payload_offset(iuup_pdu);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (offset < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ return offset;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (pdu_len < offset)</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%);">+ payload_len_bytes = pdu_len - offset;</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_pbit2ubit(buf, iuup_pdu+offset, payload_len_bytes*8);</span><br><span style="color: hsl(120, 100%, 40%);">+ return osmo_crc16gen_compute_bits(&iuup_data_crc_code, buf, payload_len_bytes*8);</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%);">+int osmo_iuup_compute_header_crc(const uint8_t *iuup_pdu, unsigned int pdu_len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ ubit_t buf[2*8];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (pdu_len < 2)</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%);">+ osmo_pbit2ubit(buf, iuup_pdu, 2*8);</span><br><span style="color: hsl(120, 100%, 40%);">+ return osmo_crc8gen_compute_bits(&iuup_hdr_crc_code, buf, 2*8);</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%);">+ * Internal State / FSM (Annex B)</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 S(x) (1 << (x))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define IUUP_TIMER_INIT 1</span><br><span style="color: hsl(120, 100%, 40%);">+#define IUUP_TIMER_TA 2</span><br><span style="color: hsl(120, 100%, 40%);">+#define IUUP_TIMER_RC 3</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_timer_nt {</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t n; /* number of repetitions */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_tnl_prim *retrans_itp;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_timer_list timer;</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_iuup_instance {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_rnl_config config;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_fsm_inst *fi;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t mode_version;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ struct {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_timer_nt init;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_timer_nt ta;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_timer_nt rc;</span><br><span style="color: hsl(120, 100%, 40%);">+ } timer;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* call-back function to pass primitives up to the user */</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_prim_cb user_prim_cb;</span><br><span style="color: hsl(120, 100%, 40%);">+ void *user_prim_priv;</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_prim_cb transport_prim_cb;</span><br><span style="color: hsl(120, 100%, 40%);">+ void *transport_prim_priv;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t type14_fn; /* 2 bits */</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum iuup_fsm_state {</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_FSM_ST_NULL,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_FSM_ST_INIT,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_FSM_ST_TrM_DATA_XFER_READY,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_FSM_ST_SMpSDU_DATA_XFER_READY,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum iuup_fsm_event {</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_FSM_EVT_IUUP_CONFIG_REQ,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_FSM_EVT_IUUP_DATA_REQ,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_FSM_EVT_IUUP_DATA_IND,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_FSM_EVT_IUUP_STATUS_REQ,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_FSM_EVT_IUUP_STATUS_IND,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_FSM_EVT_SSASAR_UNITDATA_REQ,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_FSM_EVT_SSASAR_UNITDATA_IND,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_FSM_EVT_IUUP_UNITDATA_REQ,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_FSM_EVT_IUUP_UNITDATA_IND,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_FSM_EVT_INIT,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_FSM_EVT_LAST_INIT_ACK,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_FSM_EVT_INIT_NACK,</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 const struct value_string iuup_fsm_event_names[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ { IUUP_FSM_EVT_IUUP_CONFIG_REQ, "IuUP-CONFIG.req" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { IUUP_FSM_EVT_IUUP_DATA_REQ, "IuUP-DATA.req" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { IUUP_FSM_EVT_IUUP_DATA_IND, "IuUP-DATA.ind" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { IUUP_FSM_EVT_IUUP_STATUS_REQ, "IuUP-STATUS.req" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { IUUP_FSM_EVT_IUUP_STATUS_IND, "IuUP-STATUS.ind" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { IUUP_FSM_EVT_SSASAR_UNITDATA_REQ, "SSSAR-UNITDATA.req" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { IUUP_FSM_EVT_SSASAR_UNITDATA_IND, "SSSAR-UNITDATA.ind" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { IUUP_FSM_EVT_IUUP_UNITDATA_REQ, "IuUP-UNITDATA.req" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { IUUP_FSM_EVT_IUUP_UNITDATA_IND, "IuUP-UNITDATA.ind" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { IUUP_FSM_EVT_INIT, "INIT" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { IUUP_FSM_EVT_LAST_INIT_ACK, "LAST_INIT_ACK" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { IUUP_FSM_EVT_INIT_NACK, "INIT_NACK" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { 0, NULL }</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static inline uint8_t iuup_get_pdu_type(const uint8_t *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ return data[0] >> 4;</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 inline uint8_t iuup_get_hdr_crc(const uint8_t *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ return data[2] >> 2;</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%);">+/* Helper functions to store non-packed structs in msgb so that pointers are properly aligned: */</span><br><span style="color: hsl(120, 100%, 40%);">+#define IUUP_MSGB_SIZE 4096</span><br><span style="color: hsl(120, 100%, 40%);">+#define PTR_ALIGNMENT_BYTES 8</span><br><span style="color: hsl(120, 100%, 40%);">+#define IUUP_MSGB_HEADROOM_MIN_REQUIRED (OSMO_MAX(sizeof(struct osmo_iuup_tnl_prim), sizeof(struct osmo_iuup_rnl_prim)) + (PTR_ALIGNMENT_BYTES - 1))</span><br><span style="color: hsl(120, 100%, 40%);">+static inline struct msgb *osmo_iuup_msgb_alloc_c(void *ctx, size_t size)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_static_assert(size > IUUP_MSGB_HEADROOM_MIN_REQUIRED, iuup_msgb_alloc_headroom_bigger);</span><br><span style="color: hsl(120, 100%, 40%);">+ return msgb_alloc_headroom_c(ctx, size, IUUP_MSGB_HEADROOM_MIN_REQUIRED, "iuup-msgb");</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 data so that the resulting pointer to write to is aligned to 8 byte */</span><br><span style="color: hsl(120, 100%, 40%);">+static inline __attribute__((assume_aligned(PTR_ALIGNMENT_BYTES)))</span><br><span style="color: hsl(120, 100%, 40%);">+unsigned char *aligned_msgb_push(struct msgb *msg, unsigned int len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t *ptr = (msgb_data(msg) - len);</span><br><span style="color: hsl(120, 100%, 40%);">+ size_t extra_size = ((uintptr_t)ptr & (PTR_ALIGNMENT_BYTES - 1));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return msgb_push(msg, len + extra_size);</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_iuup_rnl_prim *osmo_iuup_rnl_prim_alloc(void *ctx, unsigned int primitive, unsigned int operation, unsigned int size)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_rnl_prim *irp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ msg = osmo_iuup_msgb_alloc_c(ctx, size);</span><br><span style="color: hsl(120, 100%, 40%);">+ irp = (struct osmo_iuup_rnl_prim *)aligned_msgb_push(msg, sizeof(*irp));</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_prim_init(&irp->oph, SAP_IUUP_RNL, primitive, operation, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+ return irp;</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_iuup_tnl_prim *osmo_iuup_tnl_prim_alloc(void *ctx, unsigned int primitive, unsigned int operation, unsigned int size)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_tnl_prim *itp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ msg = osmo_iuup_msgb_alloc_c(ctx, size);</span><br><span style="color: hsl(120, 100%, 40%);">+ itp = (struct osmo_iuup_tnl_prim *) aligned_msgb_push(msg, sizeof(*itp));</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_prim_init(&itp->oph, SAP_IUUP_TNL, primitive, operation, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+ return itp;</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%);">+/* 6.6.2.3.2 */</span><br><span style="color: hsl(120, 100%, 40%);">+static struct osmo_iuup_tnl_prim *itp_ctrl_ack_alloc(struct osmo_iuup_instance *iui, enum iuup_procedure proc_ind, uint8_t fn)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_tnl_prim *itp;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct iuup_ctrl_ack *ack;</span><br><span style="color: hsl(120, 100%, 40%);">+ itp = osmo_iuup_tnl_prim_alloc(iui, OSMO_IUUP_TNL_UNITDATA, PRIM_OP_REQUEST, IUUP_MSGB_SIZE);</span><br><span style="color: hsl(120, 100%, 40%);">+ itp->oph.msg->l2h = msgb_put(itp->oph.msg, sizeof(struct iuup_ctrl_ack));</span><br><span style="color: hsl(120, 100%, 40%);">+ ack = (struct iuup_ctrl_ack *) msgb_l2(itp->oph.msg);</span><br><span style="color: hsl(120, 100%, 40%);">+ *ack = (struct iuup_ctrl_ack){</span><br><span style="color: hsl(120, 100%, 40%);">+ .hdr = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .frame_nr = fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ .ack_nack = IUUP_AN_ACK,</span><br><span style="color: hsl(120, 100%, 40%);">+ .pdu_type = IUUP_PDU_T_CONTROL,</span><br><span style="color: hsl(120, 100%, 40%);">+ .proc_ind = proc_ind,</span><br><span style="color: hsl(120, 100%, 40%);">+ .mode_version = iui->mode_version,</span><br><span style="color: hsl(120, 100%, 40%);">+ .payload_crc_hi = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+ .header_crc = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+ .payload_crc_lo = 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%);">+ ack->hdr.header_crc = osmo_iuup_compute_header_crc(msgb_l2(itp->oph.msg), msgb_l2len(itp->oph.msg));</span><br><span style="color: hsl(120, 100%, 40%);">+ return itp;</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%);">+/* 6.6.2.3.3 */</span><br><span style="color: hsl(120, 100%, 40%);">+static struct osmo_iuup_tnl_prim *tnp_ctrl_nack_alloc(struct osmo_iuup_instance *iui, enum iuup_procedure proc_ind, enum iuup_error_cause error_cause, uint8_t fn)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_tnl_prim *itp;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct iuup_ctrl_nack *nack;</span><br><span style="color: hsl(120, 100%, 40%);">+ itp = osmo_iuup_tnl_prim_alloc(iui, OSMO_IUUP_TNL_UNITDATA, PRIM_OP_REQUEST, IUUP_MSGB_SIZE);</span><br><span style="color: hsl(120, 100%, 40%);">+ itp->oph.msg->l2h = msgb_put(itp->oph.msg, sizeof(struct iuup_ctrl_nack));</span><br><span style="color: hsl(120, 100%, 40%);">+ nack = (struct iuup_ctrl_nack *) msgb_l2(itp->oph.msg);</span><br><span style="color: hsl(120, 100%, 40%);">+ *nack = (struct iuup_ctrl_nack){</span><br><span style="color: hsl(120, 100%, 40%);">+ .hdr = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .frame_nr = fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ .ack_nack = IUUP_AN_NACK,</span><br><span style="color: hsl(120, 100%, 40%);">+ .pdu_type = IUUP_PDU_T_CONTROL,</span><br><span style="color: hsl(120, 100%, 40%);">+ .proc_ind = proc_ind,</span><br><span style="color: hsl(120, 100%, 40%);">+ .mode_version = iui->mode_version,</span><br><span style="color: hsl(120, 100%, 40%);">+ .payload_crc_hi = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+ .header_crc = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+ .payload_crc_lo = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span style="color: hsl(120, 100%, 40%);">+ .spare = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+ .error_cause = error_cause,</span><br><span style="color: hsl(120, 100%, 40%);">+ };</span><br><span style="color: hsl(120, 100%, 40%);">+ nack->hdr.header_crc = osmo_iuup_compute_header_crc(msgb_l2(itp->oph.msg), msgb_l2len(itp->oph.msg));</span><br><span style="color: hsl(120, 100%, 40%);">+ return itp;</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%);">+/* 6.6.2.3.4.1 */</span><br><span style="color: hsl(120, 100%, 40%);">+static struct osmo_iuup_tnl_prim *tnp_ctrl_init_alloc(struct osmo_iuup_instance *iui)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_tnl_prim *itp;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct iuup_pdutype14_hdr *hdr;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct iuup_ctrl_init_hdr *ihdr;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct iuup_ctrl_init_rfci_hdr *ihdr_rfci;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct iuup_ctrl_init_tail *itail;</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int i, j;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t num_subflows, num_rfci;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t payload_crc;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ num_subflows = iui->config.num_subflows;</span><br><span style="color: hsl(120, 100%, 40%);">+ num_rfci = iui->config.num_rfci;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ itp = osmo_iuup_tnl_prim_alloc(iui, OSMO_IUUP_TNL_UNITDATA, PRIM_OP_REQUEST, IUUP_MSGB_SIZE);</span><br><span style="color: hsl(120, 100%, 40%);">+ msg = itp->oph.msg;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ msg->l2h = msgb_put(msg, sizeof(*hdr));</span><br><span style="color: hsl(120, 100%, 40%);">+ hdr = (struct iuup_pdutype14_hdr *)msgb_l2(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+ hdr->frame_nr = iui->type14_fn++;</span><br><span style="color: hsl(120, 100%, 40%);">+ hdr->ack_nack = IUUP_AN_PROCEDURE;</span><br><span style="color: hsl(120, 100%, 40%);">+ hdr->pdu_type = IUUP_PDU_T_CONTROL;</span><br><span style="color: hsl(120, 100%, 40%);">+ hdr->proc_ind = IUUP_PROC_INIT;</span><br><span style="color: hsl(120, 100%, 40%);">+ hdr->mode_version = 0; /* Use here the minimum version required to negotiate */</span><br><span style="color: hsl(120, 100%, 40%);">+ hdr->header_crc = osmo_iuup_compute_header_crc(msgb_l2(msg), msgb_l2len(msg));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ihdr = (struct iuup_ctrl_init_hdr *)msgb_put(msg, sizeof(*ihdr));</span><br><span style="color: hsl(120, 100%, 40%);">+ ihdr->chain_ind = 0; /* this frame is the last frame for the procedure. TODO: support several */</span><br><span style="color: hsl(120, 100%, 40%);">+ ihdr->num_subflows_per_rfci = num_subflows;</span><br><span style="color: hsl(120, 100%, 40%);">+ ihdr->ti = iui->config.IPTIs_present ? 1 : 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ ihdr->spare = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* RFCI + subflow size part: */</span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 0; i < num_rfci; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+ bool last = (i+1 == num_rfci);</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t len_size = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+ for (j = 0; j < num_subflows; j++) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (iui->config.subflow_sizes[i][j] > UINT8_MAX)</span><br><span style="color: hsl(120, 100%, 40%);">+ len_size = 2;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ ihdr_rfci = (struct iuup_ctrl_init_rfci_hdr *)msgb_put(msg, sizeof(*ihdr_rfci) + len_size * num_subflows);</span><br><span style="color: hsl(120, 100%, 40%);">+ ihdr_rfci->rfci = i;</span><br><span style="color: hsl(120, 100%, 40%);">+ ihdr_rfci->li = len_size - 1;</span><br><span style="color: hsl(120, 100%, 40%);">+ ihdr_rfci->lri = last;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (len_size == 2) {</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t *buf = (uint16_t *)&ihdr_rfci->subflow_length[0];</span><br><span style="color: hsl(120, 100%, 40%);">+ for (j = 0; j < num_subflows; j++)</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_store16be(iui->config.subflow_sizes[i][j], buf++);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ for (j = 0; j < num_subflows; j++)</span><br><span style="color: hsl(120, 100%, 40%);">+ ihdr_rfci->subflow_length[j] = iui->config.subflow_sizes[i][j];</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%);">+ if (iui->config.IPTIs_present) {</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t num_bytes = (num_rfci + 1) / 2;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t *buf = msgb_put(msg, num_bytes);</span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 0; i < num_bytes - 1; i++)</span><br><span style="color: hsl(120, 100%, 40%);">+ buf[i] = iui->config.IPTIs[i*2] << 4 |</span><br><span style="color: hsl(120, 100%, 40%);">+ (iui->config.IPTIs[i*2 + 1] & 0x0f);</span><br><span style="color: hsl(120, 100%, 40%);">+ buf[i] = iui->config.IPTIs[i*2] << 4;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!(num_rfci & 0x01)) /* is even: */</span><br><span style="color: hsl(120, 100%, 40%);">+ buf[i] |= (iui->config.IPTIs[i*2 + 1] & 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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ itail = (struct iuup_ctrl_init_tail *)msgb_put(msg, sizeof(*itail));</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_store16be(iui->config.supported_versions_mask, &itail->versions_supported);</span><br><span style="color: hsl(120, 100%, 40%);">+ itail->spare = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ itail->data_pdu_type = iui->config.data_pdu_type;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ payload_crc = osmo_iuup_compute_payload_crc(msgb_l2(msg), msgb_l2len(msg));</span><br><span style="color: hsl(120, 100%, 40%);">+ hdr->payload_crc_hi = (payload_crc >> 8) & 0x03;</span><br><span style="color: hsl(120, 100%, 40%);">+ hdr->payload_crc_lo = payload_crc & 0xff;</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 itp;</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%);">+/* transform a RNL data primitive into a TNL data primitive (down the stack) */</span><br><span style="color: hsl(120, 100%, 40%);">+static struct osmo_iuup_tnl_prim *rnl_to_tnl_data(struct osmo_iuup_instance *iui,</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_rnl_prim *irp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_tnl_prim *itp;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_rnl_data dt;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t payload_crc;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct iuup_pdutype0_hdr *h0;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct iuup_pdutype1_hdr *h1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(OSMO_PRIM_HDR(&irp->oph) == OSMO_PRIM(OSMO_IUUP_RNL_DATA, PRIM_OP_REQUEST));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ msg = irp->oph.msg;</span><br><span style="color: hsl(120, 100%, 40%);">+ dt = irp->u.data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* pull up to the IuUP payload and push a new primitive header in front */</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_pull_to_l3(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* push the PDU TYPE 0 / 1 header in front of the payload */</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (iui->config.data_pdu_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case 0:</span><br><span style="color: hsl(120, 100%, 40%);">+ msg->l2h = msgb_push(msg, sizeof(*h0));</span><br><span style="color: hsl(120, 100%, 40%);">+ h0 = (struct iuup_pdutype0_hdr *)msg->l2h;</span><br><span style="color: hsl(120, 100%, 40%);">+ h0->frame_nr = dt.frame_nr;</span><br><span style="color: hsl(120, 100%, 40%);">+ h0->pdu_type = IUUP_PDU_T_DATA_CRC;</span><br><span style="color: hsl(120, 100%, 40%);">+ h0->rfci = dt.rfci;</span><br><span style="color: hsl(120, 100%, 40%);">+ h0->fqc = dt.fqc;</span><br><span style="color: hsl(120, 100%, 40%);">+ h0->header_crc = osmo_iuup_compute_header_crc(msgb_l2(msg), msgb_l2len(msg));</span><br><span style="color: hsl(120, 100%, 40%);">+ payload_crc = osmo_iuup_compute_payload_crc(msgb_l2(msg), msgb_l2len(msg));</span><br><span style="color: hsl(120, 100%, 40%);">+ h0->payload_crc_hi = (payload_crc >> 8) & 0x03;</span><br><span style="color: hsl(120, 100%, 40%);">+ h0->payload_crc_lo = payload_crc & 0xff;</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case 1:</span><br><span style="color: hsl(120, 100%, 40%);">+ msg->l2h = msgb_push(msg, sizeof(*h1));</span><br><span style="color: hsl(120, 100%, 40%);">+ h1 = (struct iuup_pdutype1_hdr *)msg->l2h;</span><br><span style="color: hsl(120, 100%, 40%);">+ h1->frame_nr = dt.frame_nr;</span><br><span style="color: hsl(120, 100%, 40%);">+ h1->pdu_type = IUUP_PDU_T_DATA_NOCRC;</span><br><span style="color: hsl(120, 100%, 40%);">+ h1->rfci = dt.rfci;</span><br><span style="color: hsl(120, 100%, 40%);">+ h1->fqc = dt.fqc;</span><br><span style="color: hsl(120, 100%, 40%);">+ h1->header_crc = osmo_iuup_compute_header_crc(msgb_l2(msg), msgb_l2len(msg));</span><br><span style="color: hsl(120, 100%, 40%);">+ h1->spare = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(0);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Avoid allocating irp out of 8byte-aligned address, Asan is not happy with it */</span><br><span style="color: hsl(120, 100%, 40%);">+ itp = (struct osmo_iuup_tnl_prim *) aligned_msgb_push(msg, sizeof(*itp));</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_prim_init(&itp->oph, SAP_IUUP_TNL, OSMO_IUUP_TNL_UNITDATA, PRIM_OP_REQUEST, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return itp;</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%);">+/* transform a TNL primitive into a RNL primitive (up the stack) */</span><br><span style="color: hsl(120, 100%, 40%);">+static struct osmo_iuup_rnl_prim *tnl_to_rnl_data(struct osmo_iuup_tnl_prim *itp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct iuup_pdutype0_hdr *h0;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct iuup_pdutype1_hdr *h1;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_rnl_data dt;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_rnl_prim *irp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ msg = itp->oph.msg;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(OSMO_PRIM_HDR(&itp->oph) == OSMO_PRIM(OSMO_IUUP_TNL_UNITDATA, PRIM_OP_INDICATION));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (iuup_get_pdu_type(msgb_l2(msg))) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case IUUP_PDU_T_DATA_CRC:</span><br><span style="color: hsl(120, 100%, 40%);">+ h0 = (struct iuup_pdutype0_hdr *) msgb_l2(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+ dt.rfci = h0->rfci;</span><br><span style="color: hsl(120, 100%, 40%);">+ dt.frame_nr = h0->frame_nr;</span><br><span style="color: hsl(120, 100%, 40%);">+ dt.fqc = h0->fqc;</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case IUUP_PDU_T_DATA_NOCRC:</span><br><span style="color: hsl(120, 100%, 40%);">+ h1 = (struct iuup_pdutype1_hdr *) msgb_l2(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+ dt.rfci = h1->rfci;</span><br><span style="color: hsl(120, 100%, 40%);">+ dt.frame_nr = h1->frame_nr;</span><br><span style="color: hsl(120, 100%, 40%);">+ dt.fqc = h1->fqc;</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%);">+ /* pull up to the IuUP payload and push a new primitive header in front */</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_pull_to_l3(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Avoid allocating irp out of 8byte-aligned address, Asan is not happy with it */</span><br><span style="color: hsl(120, 100%, 40%);">+ irp = (struct osmo_iuup_rnl_prim *) aligned_msgb_push(msg, sizeof(*irp));</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_prim_init(&irp->oph, SAP_IUUP_RNL, OSMO_IUUP_RNL_DATA, PRIM_OP_INDICATION, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+ irp->u.data = dt;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return irp;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct osmo_iuup_rnl_prim *irp_error_event_alloc_c(void *ctx, enum iuup_error_cause cause, enum iuup_error_distance distance)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_rnl_prim *irp;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+ msg = msgb_alloc_c(ctx, sizeof(*irp), "iuup-tx");</span><br><span style="color: hsl(120, 100%, 40%);">+ irp = (struct osmo_iuup_rnl_prim *) msgb_put(msg, sizeof(*irp));</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_prim_init(&irp->oph, SAP_IUUP_RNL, OSMO_IUUP_RNL_STATUS, PRIM_OP_INDICATION, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+ irp->u.status.procedure = IUUP_PROC_ERR_EVENT;</span><br><span style="color: hsl(120, 100%, 40%);">+ irp->u.status.u.error_event.cause = cause;</span><br><span style="color: hsl(120, 100%, 40%);">+ irp->u.status.u.error_event.distance = distance;</span><br><span style="color: hsl(120, 100%, 40%);">+ return irp;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct osmo_iuup_tnl_prim *itp_copy_c(void *ctx, const struct osmo_iuup_tnl_prim *src_itp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_tnl_prim *dst_itp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ msg = msgb_copy_c(ctx, src_itp->oph.msg, "iuup-tx-retrans");</span><br><span style="color: hsl(120, 100%, 40%);">+ dst_itp = (struct osmo_iuup_tnl_prim *)msgb_data(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+ dst_itp->oph.msg = msg;</span><br><span style="color: hsl(120, 100%, 40%);">+ return dst_itp;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void retransmit_initialization(struct osmo_iuup_instance *iui)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_tnl_prim *itp;</span><br><span style="color: hsl(120, 100%, 40%);">+ iui->fi->T = IUUP_TIMER_INIT;</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_timer_schedule(&iui->fi->timer, iui->config.t_init.t_ms / 1000, (iui->config.t_init.t_ms % 1000) * 1000);</span><br><span style="color: hsl(120, 100%, 40%);">+ itp = itp_copy_c(iui, iui->timer.init.retrans_itp);</span><br><span style="color: hsl(120, 100%, 40%);">+ iui->transport_prim_cb(&itp->oph, iui->transport_prim_priv);</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: whether the last Init was Acked correctly and hence can transition to next state */</span><br><span style="color: hsl(120, 100%, 40%);">+static bool iuup_rx_initialization(struct osmo_iuup_instance *iui, struct osmo_iuup_tnl_prim *itp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct iuup_pdutype14_hdr *hdr;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct iuup_ctrl_init_hdr *ihdr;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct iuup_ctrl_init_rfci_hdr *ihdr_rfci;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct iuup_ctrl_init_tail *itail;</span><br><span style="color: hsl(120, 100%, 40%);">+ enum iuup_error_cause err_cause;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t num_rfci = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+ bool is_last;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t remote_mask, match_mask;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_tnl_prim *resp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* TODO: whenever we check message boundaries, length, etc. and we fail, send NACK */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ hdr = (struct iuup_pdutype14_hdr *)msgb_l2(itp->oph.msg);</span><br><span style="color: hsl(120, 100%, 40%);">+ ihdr = (struct iuup_ctrl_init_hdr *)hdr->payload;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ihdr->num_subflows_per_rfci == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGPFSML(iui->fi, LOGL_NOTICE, "Initialization: Unexpected num_subflows=0 received\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ err_cause = IUUP_ERR_CAUSE_UNEXPECTED_VALUE;</span><br><span style="color: hsl(120, 100%, 40%);">+ goto send_nack;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ ihdr_rfci = (struct iuup_ctrl_init_rfci_hdr *)ihdr->rfci_data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ do {</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t l_size_bytes = ihdr_rfci->li + 1;</span><br><span style="color: hsl(120, 100%, 40%);">+ is_last = ihdr_rfci->lri;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ihdr_rfci->rfci != num_rfci) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGPFSML(iui->fi, LOGL_NOTICE, "Initialization: Unexpected RFCI %u at position %u received\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ ihdr_rfci->rfci, num_rfci);</span><br><span style="color: hsl(120, 100%, 40%);">+ err_cause = IUUP_ERR_CAUSE_UNEXPECTED_RFCI;</span><br><span style="color: hsl(120, 100%, 40%);">+ goto send_nack;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ if (l_size_bytes == 2) {</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t *subflow_size = (uint16_t *)ihdr_rfci->subflow_length;</span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 0; i < ihdr->num_subflows_per_rfci; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+ iui->config.subflow_sizes[ihdr_rfci->rfci][i] = osmo_load16be(subflow_size);</span><br><span style="color: hsl(120, 100%, 40%);">+ subflow_size++;</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%);">+ uint8_t *subflow_size = ihdr_rfci->subflow_length;</span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 0; i < ihdr->num_subflows_per_rfci; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+ iui->config.subflow_sizes[ihdr_rfci->rfci][i] = osmo_load16be(subflow_size);</span><br><span style="color: hsl(120, 100%, 40%);">+ subflow_size++;</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%);">+ num_rfci++;</span><br><span style="color: hsl(120, 100%, 40%);">+ ihdr_rfci++;</span><br><span style="color: hsl(120, 100%, 40%);">+ ihdr_rfci = (struct iuup_ctrl_init_rfci_hdr *)(((uint8_t *)ihdr_rfci) + ihdr->num_subflows_per_rfci * l_size_bytes);</span><br><span style="color: hsl(120, 100%, 40%);">+ } while (!is_last);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ihdr->ti) { /* Timing information present */</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t *buf = (uint8_t *)ihdr_rfci;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t num_bytes = (num_rfci + 1) / 2;</span><br><span style="color: hsl(120, 100%, 40%);">+ iui->config.IPTIs_present = true;</span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 0; i < num_bytes - 1; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+ iui->config.IPTIs[i*2] = *buf >> 4;</span><br><span style="color: hsl(120, 100%, 40%);">+ iui->config.IPTIs[i*2 + 1] = *buf & 0x0f;</span><br><span style="color: hsl(120, 100%, 40%);">+ buf++;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ iui->config.IPTIs[i*2] = *buf >> 4;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!(num_rfci & 0x01)) /* is even: */</span><br><span style="color: hsl(120, 100%, 40%);">+ iui->config.IPTIs[i*2 + 1] = *buf & 0x0f;</span><br><span style="color: hsl(120, 100%, 40%);">+ buf++;</span><br><span style="color: hsl(120, 100%, 40%);">+ itail = (struct iuup_ctrl_init_tail *)buf;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ itail = (struct iuup_ctrl_init_tail *)ihdr_rfci;</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 (itail->data_pdu_type > 1) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGPFSML(iui->fi, LOGL_NOTICE, "Initialization: Unexpected Data PDU Type %u received\n", itail->data_pdu_type);</span><br><span style="color: hsl(120, 100%, 40%);">+ err_cause = IUUP_ERR_CAUSE_UNEXPECTED_VALUE;</span><br><span style="color: hsl(120, 100%, 40%);">+ goto send_nack;</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%);">+ remote_mask = osmo_load16be(&itail->versions_supported);</span><br><span style="color: hsl(120, 100%, 40%);">+ match_mask = (remote_mask & iui->config.supported_versions_mask);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (match_mask == 0x0000) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGPFSML(iui->fi, LOGL_NOTICE,</span><br><span style="color: hsl(120, 100%, 40%);">+ "Initialization: No match in supported versions local=0x%04x vs remote=0x%04x\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ iui->config.supported_versions_mask, remote_mask);</span><br><span style="color: hsl(120, 100%, 40%);">+ err_cause = IUUP_ERR_CAUSE_UNEXPECTED_VALUE;</span><br><span style="color: hsl(120, 100%, 40%);">+ goto send_nack;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 15; i >= 0; i--) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (match_mask & (1<<i)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ iui->mode_version = i;</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ iui->config.num_rfci = num_rfci;</span><br><span style="color: hsl(120, 100%, 40%);">+ iui->config.num_subflows = ihdr->num_subflows_per_rfci;</span><br><span style="color: hsl(120, 100%, 40%);">+ iui->config.data_pdu_type = itail->data_pdu_type;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGPFSML(iui->fi, LOGL_DEBUG, "Tx Initialization ACK\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ resp = itp_ctrl_ack_alloc(iui, IUUP_PROC_INIT, hdr->frame_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+ iui->transport_prim_cb(&resp->oph, iui->transport_prim_priv);</span><br><span style="color: hsl(120, 100%, 40%);">+ return ihdr->chain_ind == 0;</span><br><span style="color: hsl(120, 100%, 40%);">+send_nack:</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGPFSML(iui->fi, LOGL_NOTICE, "Tx Initialization NACK cause=%u orig_message=%s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ err_cause, osmo_hexdump((const unsigned char *) msgb_l2(itp->oph.msg), msgb_l2len(itp->oph.msg)));</span><br><span style="color: hsl(120, 100%, 40%);">+ resp = tnp_ctrl_nack_alloc(iui, IUUP_PROC_INIT, err_cause, hdr->frame_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+ iui->transport_prim_cb(&resp->oph, iui->transport_prim_priv);</span><br><span style="color: hsl(120, 100%, 40%);">+ return false;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/**********************</span><br><span style="color: hsl(120, 100%, 40%);">+ * FSM STATE FUNCTIONS</span><br><span style="color: hsl(120, 100%, 40%);">+ **********************/</span><br><span style="color: hsl(120, 100%, 40%);">+static void iuup_fsm_null(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_instance *iui = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_rnl_prim *user_prim = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (event) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case IUUP_FSM_EVT_IUUP_CONFIG_REQ:</span><br><span style="color: hsl(120, 100%, 40%);">+ user_prim = data;</span><br><span style="color: hsl(120, 100%, 40%);">+ iui->config = user_prim->u.config;</span><br><span style="color: hsl(120, 100%, 40%);">+ iui->config.supported_versions_mask &= 0x0003; /* We only support versions 1 and 2 ourselves */</span><br><span style="color: hsl(120, 100%, 40%);">+ //TODO: if supported_versions_mask == 0x0000,no supported versions, send error to upper layers</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (iui->config.transparent)</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fsm_inst_state_chg(fi, IUUP_FSM_ST_TrM_DATA_XFER_READY, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ else {</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fsm_inst_state_chg(fi, IUUP_FSM_ST_INIT, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</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%);">+/* transparent mode data transfer */</span><br><span style="color: hsl(120, 100%, 40%);">+static void iuup_fsm_trm_data(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ //struct osmo_iuup_instance *iui = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (event) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case IUUP_FSM_EVT_IUUP_CONFIG_REQ:</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fsm_inst_state_chg(fi, IUUP_FSM_ST_NULL, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case IUUP_FSM_EVT_IUUP_DATA_REQ:</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Data coming down from RNL (user) towards TNL (transport) */</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case IUUP_FSM_EVT_IUUP_DATA_IND:</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Data coming up from TNL (transport) towards RNL (user) */</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case IUUP_FSM_EVT_IUUP_UNITDATA_REQ:</span><br><span style="color: hsl(120, 100%, 40%);">+ case IUUP_FSM_EVT_IUUP_UNITDATA_IND:</span><br><span style="color: hsl(120, 100%, 40%);">+ case IUUP_FSM_EVT_SSASAR_UNITDATA_REQ:</span><br><span style="color: hsl(120, 100%, 40%);">+ case IUUP_FSM_EVT_SSASAR_UNITDATA_IND:</span><br><span style="color: hsl(120, 100%, 40%);">+ /* no state change */</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void iuup_fsm_init_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_instance *iui = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ iui->type14_fn = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (iui->config.active) {</span><br><span style="color: hsl(120, 100%, 40%);">+ iui->timer.init.n = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ iui->timer.init.retrans_itp = tnp_ctrl_init_alloc(iui);</span><br><span style="color: hsl(120, 100%, 40%);">+ retransmit_initialization(iui);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void iuup_fsm_init(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_instance *iui = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_rnl_prim *irp;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_tnl_prim *itp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (event) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case IUUP_FSM_EVT_IUUP_CONFIG_REQ:</span><br><span style="color: hsl(120, 100%, 40%);">+ /* the only permitted 'config req' type is the request to release the instance */</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fsm_inst_state_chg(fi, IUUP_FSM_ST_NULL, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case IUUP_FSM_EVT_INIT:</span><br><span style="color: hsl(120, 100%, 40%);">+ itp = data;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (iuup_rx_initialization(iui, itp))</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fsm_inst_state_chg(fi, IUUP_FSM_ST_SMpSDU_DATA_XFER_READY, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case IUUP_FSM_EVT_LAST_INIT_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+ /* last INIT ACK was received, transition to DATA_XFER_READY state */</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fsm_inst_state_chg(fi, IUUP_FSM_ST_SMpSDU_DATA_XFER_READY, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case IUUP_FSM_EVT_INIT_NACK:</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGPFSML(fi, LOGL_NOTICE, "Rx Initialization NACK N=%" PRIu32 "/%" PRIu32 "\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ iui->timer.init.n, iui->config.t_init.n_max);</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_timer_del(&fi->timer);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (iui->timer.init.n == iui->config.t_init.n_max) {</span><br><span style="color: hsl(120, 100%, 40%);">+ irp = irp_error_event_alloc_c(iui, IUUP_ERR_CAUSE_INIT_FAILURE_REP_NACK, IUUP_ERR_DIST_SECOND_FWD);</span><br><span style="color: hsl(120, 100%, 40%);">+ iui->user_prim_cb(&irp->oph, iui->user_prim_priv);</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ iui->timer.init.n++;</span><br><span style="color: hsl(120, 100%, 40%);">+ retransmit_initialization(iui);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(false);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void iuup_fsm_smpsdu_data(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_instance *iui = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_rnl_prim *irp = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_tnl_prim *itp = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (event) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case IUUP_FSM_EVT_IUUP_CONFIG_REQ:</span><br><span style="color: hsl(120, 100%, 40%);">+ irp = data;</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fsm_inst_state_chg(fi, IUUP_FSM_ST_NULL, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case IUUP_FSM_EVT_IUUP_DATA_REQ:</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Data coming down from RNL (user) towards TNL (transport) */</span><br><span style="color: hsl(120, 100%, 40%);">+ irp = data;</span><br><span style="color: hsl(120, 100%, 40%);">+ itp = rnl_to_tnl_data(iui, irp);</span><br><span style="color: hsl(120, 100%, 40%);">+ iui->transport_prim_cb(&itp->oph, iui->transport_prim_priv);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case IUUP_FSM_EVT_IUUP_DATA_IND:</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Data coming up from TNL (transport) towards RNL (user) */</span><br><span style="color: hsl(120, 100%, 40%);">+ itp = data;</span><br><span style="color: hsl(120, 100%, 40%);">+ irp = tnl_to_rnl_data(itp);</span><br><span style="color: hsl(120, 100%, 40%);">+ iui->user_prim_cb(&irp->oph, iui->user_prim_priv);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case IUUP_FSM_EVT_IUUP_UNITDATA_REQ:</span><br><span style="color: hsl(120, 100%, 40%);">+ case IUUP_FSM_EVT_IUUP_UNITDATA_IND:</span><br><span style="color: hsl(120, 100%, 40%);">+ case IUUP_FSM_EVT_SSASAR_UNITDATA_REQ:</span><br><span style="color: hsl(120, 100%, 40%);">+ case IUUP_FSM_EVT_SSASAR_UNITDATA_IND:</span><br><span style="color: hsl(120, 100%, 40%);">+ /* no state change */</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int iuup_fsm_timer_cb(struct osmo_fsm_inst *fi)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_instance *iui = fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_rnl_prim *irp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (fi->T) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case IUUP_TIMER_INIT:</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(fi->state == IUUP_FSM_ST_INIT);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (iui->timer.init.n == iui->config.t_init.n_max) {</span><br><span style="color: hsl(120, 100%, 40%);">+ irp = irp_error_event_alloc_c(iui, IUUP_ERR_CAUSE_INIT_FAILURE_NET_TMR, IUUP_ERR_DIST_LOCAL);</span><br><span style="color: hsl(120, 100%, 40%);">+ iui->user_prim_cb(&irp->oph, iui->user_prim_priv);</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%);">+ iui->timer.init.n++;</span><br><span style="color: hsl(120, 100%, 40%);">+ retransmit_initialization(iui);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case IUUP_TIMER_TA:</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case IUUP_TIMER_RC:</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(0);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ 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%);">+static const struct osmo_fsm_state iuup_fsm_states[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ [IUUP_FSM_ST_NULL] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .in_event_mask = S(IUUP_FSM_EVT_IUUP_CONFIG_REQ),</span><br><span style="color: hsl(120, 100%, 40%);">+ .out_state_mask = S(IUUP_FSM_ST_INIT) |</span><br><span style="color: hsl(120, 100%, 40%);">+ S(IUUP_FSM_ST_TrM_DATA_XFER_READY),</span><br><span style="color: hsl(120, 100%, 40%);">+ .name = "NULL",</span><br><span style="color: hsl(120, 100%, 40%);">+ .action = iuup_fsm_null,</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span style="color: hsl(120, 100%, 40%);">+ [IUUP_FSM_ST_TrM_DATA_XFER_READY] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .in_event_mask = S(IUUP_FSM_EVT_IUUP_CONFIG_REQ) |</span><br><span style="color: hsl(120, 100%, 40%);">+ S(IUUP_FSM_EVT_IUUP_STATUS_REQ) |</span><br><span style="color: hsl(120, 100%, 40%);">+ S(IUUP_FSM_EVT_IUUP_DATA_REQ) |</span><br><span style="color: hsl(120, 100%, 40%);">+ S(IUUP_FSM_EVT_IUUP_DATA_IND) |</span><br><span style="color: hsl(120, 100%, 40%);">+ S(IUUP_FSM_EVT_IUUP_UNITDATA_REQ) |</span><br><span style="color: hsl(120, 100%, 40%);">+ S(IUUP_FSM_EVT_IUUP_UNITDATA_IND) |</span><br><span style="color: hsl(120, 100%, 40%);">+ S(IUUP_FSM_EVT_SSASAR_UNITDATA_REQ) |</span><br><span style="color: hsl(120, 100%, 40%);">+ S(IUUP_FSM_EVT_SSASAR_UNITDATA_IND),</span><br><span style="color: hsl(120, 100%, 40%);">+ .out_state_mask = S(IUUP_FSM_ST_NULL),</span><br><span style="color: hsl(120, 100%, 40%);">+ .name = "TrM Data Transfer Ready",</span><br><span style="color: hsl(120, 100%, 40%);">+ .action = iuup_fsm_trm_data,</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span style="color: hsl(120, 100%, 40%);">+ [IUUP_FSM_ST_INIT] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .in_event_mask = S(IUUP_FSM_EVT_IUUP_CONFIG_REQ) |</span><br><span style="color: hsl(120, 100%, 40%);">+ S(IUUP_FSM_EVT_INIT) |</span><br><span style="color: hsl(120, 100%, 40%);">+ S(IUUP_FSM_EVT_LAST_INIT_ACK) |</span><br><span style="color: hsl(120, 100%, 40%);">+ S(IUUP_FSM_EVT_INIT_NACK),</span><br><span style="color: hsl(120, 100%, 40%);">+ .out_state_mask = S(IUUP_FSM_ST_NULL) |</span><br><span style="color: hsl(120, 100%, 40%);">+ S(IUUP_FSM_ST_SMpSDU_DATA_XFER_READY),</span><br><span style="color: hsl(120, 100%, 40%);">+ .name = "Initialisation",</span><br><span style="color: hsl(120, 100%, 40%);">+ .onenter = iuup_fsm_init_on_enter,</span><br><span style="color: hsl(120, 100%, 40%);">+ .action = iuup_fsm_init,</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span style="color: hsl(120, 100%, 40%);">+ [IUUP_FSM_ST_SMpSDU_DATA_XFER_READY] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .in_event_mask = S(IUUP_FSM_EVT_IUUP_DATA_REQ) |</span><br><span style="color: hsl(120, 100%, 40%);">+ S(IUUP_FSM_EVT_IUUP_DATA_IND),</span><br><span style="color: hsl(120, 100%, 40%);">+ .out_state_mask = S(IUUP_FSM_ST_NULL) |</span><br><span style="color: hsl(120, 100%, 40%);">+ S(IUUP_FSM_ST_INIT),</span><br><span style="color: hsl(120, 100%, 40%);">+ .name = "SMpSDU Data Transfer Ready",</span><br><span style="color: hsl(120, 100%, 40%);">+ .action = iuup_fsm_smpsdu_data,</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct osmo_fsm iuup_fsm = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .name = "IuUP",</span><br><span style="color: hsl(120, 100%, 40%);">+ .states = iuup_fsm_states,</span><br><span style="color: hsl(120, 100%, 40%);">+ .num_states = ARRAY_SIZE(iuup_fsm_states),</span><br><span style="color: hsl(120, 100%, 40%);">+ .timer_cb = iuup_fsm_timer_cb,</span><br><span style="color: hsl(120, 100%, 40%);">+ .log_subsys = DLIUUP,</span><br><span style="color: hsl(120, 100%, 40%);">+ .event_names = iuup_fsm_event_names,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int iuup_verify_pdu(const uint8_t *data, unsigned int len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ int header_crc_computed, payload_crc_computed;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t payload_crc;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t pdu_type = iuup_get_pdu_type(data);</span><br><span style="color: hsl(120, 100%, 40%);">+ struct iuup_pdutype0_hdr *t0h;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct iuup_pdutype14_hdr *t14h;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (len < 3)</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%);">+ header_crc_computed = osmo_iuup_compute_header_crc(data, len);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (iuup_get_hdr_crc(data) != header_crc_computed) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DLIUUP, LOGL_NOTICE, "Checksum error: rx 0x%02x vs exp 0x%02x\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ iuup_get_hdr_crc(data), header_crc_computed);</span><br><span style="color: hsl(120, 100%, 40%);">+ return -EIO;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (pdu_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case IUUP_PDU_T_DATA_NOCRC:</span><br><span style="color: hsl(120, 100%, 40%);">+ if (len < 4)</span><br><span style="color: hsl(120, 100%, 40%);">+ return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case IUUP_PDU_T_DATA_CRC:</span><br><span style="color: hsl(120, 100%, 40%);">+ t0h = (struct iuup_pdutype0_hdr *) data;</span><br><span style="color: hsl(120, 100%, 40%);">+ payload_crc = ((uint16_t)t0h->payload_crc_hi << 8) | t0h->payload_crc_lo;</span><br><span style="color: hsl(120, 100%, 40%);">+ payload_crc_computed = osmo_iuup_compute_payload_crc(data, len);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (payload_crc != payload_crc_computed)</span><br><span style="color: hsl(120, 100%, 40%);">+ return -EIO;</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case IUUP_PDU_T_CONTROL:</span><br><span style="color: hsl(120, 100%, 40%);">+ t14h = (struct iuup_pdutype14_hdr *) data;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (t14h->ack_nack == IUUP_AN_PROCEDURE) {</span><br><span style="color: hsl(120, 100%, 40%);">+ payload_crc = ((uint16_t)t14h->payload_crc_hi << 8) | t14h->payload_crc_lo;</span><br><span style="color: hsl(120, 100%, 40%);">+ payload_crc_computed = osmo_iuup_compute_payload_crc(data, len);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (payload_crc != payload_crc_computed)</span><br><span style="color: hsl(120, 100%, 40%);">+ return -EIO;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+ return -EINVAL;</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%);">+/* A IuUP TNL SAP primitive from transport (lower layer) */</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_iuup_tnl_prim_up(struct osmo_iuup_instance *inst, struct osmo_iuup_tnl_prim *itp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_prim_hdr *oph = &itp->oph;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct iuup_pdutype14_hdr *t14h;</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(oph->sap == SAP_IUUP_TNL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (OSMO_PRIM_HDR(oph)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case OSMO_PRIM(OSMO_IUUP_TNL_UNITDATA, PRIM_OP_INDICATION):</span><br><span style="color: hsl(120, 100%, 40%);">+ if (iuup_verify_pdu(msgb_l2(oph->msg), msgb_l2len(oph->msg)) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGPFSML(inst->fi, LOGL_NOTICE, "Discarding invalid IuUP PDU: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_hexdump((const unsigned char *) msgb_l2(oph->msg), msgb_l2len(oph->msg)));</span><br><span style="color: hsl(120, 100%, 40%);">+ /* don't return error as the caller is not responsible for the PDU which</span><br><span style="color: hsl(120, 100%, 40%);">+ * was transmitted from some remote peer */</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%);">+ switch (iuup_get_pdu_type(msgb_l2(oph->msg))) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case IUUP_PDU_T_DATA_CRC:</span><br><span style="color: hsl(120, 100%, 40%);">+ oph->msg->l3h = msgb_l2(oph->msg) + sizeof(struct iuup_pdutype0_hdr);</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = osmo_fsm_inst_dispatch(inst->fi, IUUP_FSM_EVT_IUUP_DATA_IND, itp);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case IUUP_PDU_T_DATA_NOCRC:</span><br><span style="color: hsl(120, 100%, 40%);">+ oph->msg->l3h = msgb_l2(oph->msg) + sizeof(struct iuup_pdutype1_hdr);</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = osmo_fsm_inst_dispatch(inst->fi, IUUP_FSM_EVT_IUUP_DATA_IND, itp);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case IUUP_PDU_T_CONTROL:</span><br><span style="color: hsl(120, 100%, 40%);">+ t14h = (struct iuup_pdutype14_hdr *) msgb_l2(oph->msg);</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (t14h->ack_nack) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case IUUP_AN_PROCEDURE:</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (t14h->proc_ind) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case IUUP_PROC_INIT:</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = osmo_fsm_inst_dispatch(inst->fi, IUUP_FSM_EVT_INIT, itp);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case IUUP_PROC_RATE_CTRL:</span><br><span style="color: hsl(120, 100%, 40%);">+ case IUUP_PROC_TIME_ALIGN:</span><br><span style="color: hsl(120, 100%, 40%);">+ case IUUP_PROC_ERR_EVENT:</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGPFSML(inst->fi, LOGL_NOTICE, "Received Request for "</span><br><span style="color: hsl(120, 100%, 40%);">+ "unsupported IuUP procedure %u\n", t14h->proc_ind);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGPFSML(inst->fi, LOGL_NOTICE, "Received Request for "</span><br><span style="color: hsl(120, 100%, 40%);">+ "unknown IuUP procedure %u\n", t14h->proc_ind);</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%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case IUUP_AN_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (t14h->proc_ind) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case IUUP_PROC_INIT:</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = osmo_fsm_inst_dispatch(inst->fi,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_FSM_EVT_LAST_INIT_ACK, itp);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGPFSML(inst->fi, LOGL_ERROR, "Received ACK for "</span><br><span style="color: hsl(120, 100%, 40%);">+ "unknown IuUP procedure %u\n", t14h->proc_ind);</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%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case IUUP_AN_NACK:</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (t14h->proc_ind) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case IUUP_PROC_INIT:</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = osmo_fsm_inst_dispatch(inst->fi,</span><br><span style="color: hsl(120, 100%, 40%);">+ IUUP_FSM_EVT_INIT_NACK, itp);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGPFSML(inst->fi, LOGL_ERROR, "Received NACK for "</span><br><span style="color: hsl(120, 100%, 40%);">+ "unknown IuUP procedure %u\n", t14h->proc_ind);</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%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGPFSML(inst->fi, LOGL_ERROR, "Received unknown IuUP ACK/NACK\n");</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%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGPFSML(inst->fi, LOGL_NOTICE, "Received unknown IuUP PDU type %u\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ iuup_get_pdu_type(msgb_l2(oph->msg)));</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%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+ /* exception: return an error code due to a wrong primitive */</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return rc;</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%);">+/* A IuUP RNL SAP primitive from user (higher layer) */</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_iuup_rnl_prim_down(struct osmo_iuup_instance *inst, struct osmo_iuup_rnl_prim *irp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_prim_hdr *oph = &irp->oph;</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%);">+ OSMO_ASSERT(oph->sap == SAP_IUUP_RNL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (OSMO_PRIM_HDR(oph)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case OSMO_PRIM(OSMO_IUUP_RNL_CONFIG, PRIM_OP_REQUEST):</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = osmo_fsm_inst_dispatch(inst->fi, IUUP_FSM_EVT_IUUP_CONFIG_REQ, irp);</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_free(irp->oph.msg);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case OSMO_PRIM(OSMO_IUUP_RNL_DATA, PRIM_OP_REQUEST):</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = osmo_fsm_inst_dispatch(inst->fi, IUUP_FSM_EVT_IUUP_DATA_REQ, irp);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc != 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_free(irp->oph.msg);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case OSMO_PRIM(OSMO_IUUP_RNL_STATUS, PRIM_OP_REQUEST):</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = osmo_fsm_inst_dispatch(inst->fi, IUUP_FSM_EVT_IUUP_STATUS_REQ, irp);</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_free(irp->oph.msg);</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 = -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_free(irp->oph.msg);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ return rc;</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_iuup_instance *osmo_iuup_instance_alloc(void *ctx, const char *id)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_instance *iui;</span><br><span style="color: hsl(120, 100%, 40%);">+ iui = talloc_zero(ctx, struct osmo_iuup_instance);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!iui)</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%);">+ iui->fi = osmo_fsm_inst_alloc(&iuup_fsm, NULL, iui, LOGL_DEBUG, id);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!iui->fi)</span><br><span style="color: hsl(120, 100%, 40%);">+ goto free_ret;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return iui;</span><br><span style="color: hsl(120, 100%, 40%);">+free_ret:</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(iui);</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%);">+void osmo_iuup_instance_free(struct osmo_iuup_instance *iui)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!iui)</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (iui->fi)</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fsm_inst_free(iui->fi);</span><br><span style="color: hsl(120, 100%, 40%);">+ iui->fi = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(iui);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_iuup_instance_set_user_prim_cb(struct osmo_iuup_instance *iui, osmo_prim_cb func, void *priv)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ iui->user_prim_cb = func;</span><br><span style="color: hsl(120, 100%, 40%);">+ iui->user_prim_priv = priv;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_iuup_instance_set_transport_prim_cb(struct osmo_iuup_instance *iui, osmo_prim_cb func, void *priv)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ iui->transport_prim_cb = func;</span><br><span style="color: hsl(120, 100%, 40%);">+ iui->transport_prim_priv = priv;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static __attribute__((constructor)) void on_dso_load_iuup_fsm(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(osmo_fsm_register(&iuup_fsm) == 0);</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 475ec02..b971ca0 100644</span><br><span>--- a/src/gsm/libosmogsm.map</span><br><span>+++ b/src/gsm/libosmogsm.map</span><br><span>@@ -771,5 +771,16 @@</span><br><span> osmo_gad_raw_write;</span><br><span> osmo_gad_type_names;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+osmo_iuup_compute_header_crc;</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_iuup_compute_payload_crc;</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_iuup_instance_alloc;</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_iuup_instance_free;</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_iuup_instance_set_user_prim_cb;</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_iuup_instance_set_transport_prim_cb;</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_iuup_tnl_prim_up;</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_iuup_rnl_prim_down;</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_iuup_rnl_prim_alloc;</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_iuup_tnl_prim_alloc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> local: *;</span><br><span> };</span><br><span>diff --git a/src/logging.c b/src/logging.c</span><br><span>index 9497f28..e5c66f2 100644</span><br><span>--- a/src/logging.c</span><br><span>+++ b/src/logging.c</span><br><span>@@ -294,6 +294,12 @@</span><br><span> .enabled = 1, .loglevel = LOGL_NOTICE,</span><br><span> .color = "\033[38;5;63m",</span><br><span> },</span><br><span style="color: hsl(120, 100%, 40%);">+ [INT2IDX(DLIUUP)] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .name = "DLIUUP",</span><br><span style="color: hsl(120, 100%, 40%);">+ .description = "Iu UP layer",</span><br><span style="color: hsl(120, 100%, 40%);">+ .enabled = 1, .loglevel = LOGL_NOTICE,</span><br><span style="color: hsl(120, 100%, 40%);">+ .color = "\033[38;5;65m",</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span> };</span><br><span> </span><br><span> void assert_loginfo(const char *src)</span><br><span>diff --git a/tests/Makefile.am b/tests/Makefile.am</span><br><span>index a6f6017..f54ce18 100644</span><br><span>--- a/tests/Makefile.am</span><br><span>+++ b/tests/Makefile.am</span><br><span>@@ -45,6 +45,7 @@</span><br><span> time_cc/time_cc_test \</span><br><span> gsm48/rest_octets_test \</span><br><span> base64/base64_test \</span><br><span style="color: hsl(120, 100%, 40%);">+ iuup/iuup_test \</span><br><span> $(NULL)</span><br><span> </span><br><span> if ENABLE_MSGFILE</span><br><span>@@ -328,6 +329,9 @@</span><br><span> time_cc_time_cc_test_SOURCES = time_cc/time_cc_test.c</span><br><span> time_cc_time_cc_test_LDADD = $(LDADD)</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+iuup_iuup_test_SOURCES = iuup/iuup_test.c</span><br><span style="color: hsl(120, 100%, 40%);">+iuup_iuup_test_LDADD = $(LDADD) $(top_builddir)/src/gsm/libosmogsm.la</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> # The `:;' works around a Bash 3.2 bug when the output is not writeable.</span><br><span> $(srcdir)/package.m4: $(top_srcdir)/configure.ac</span><br><span> :;{ \</span><br><span>@@ -420,6 +424,7 @@</span><br><span> time_cc/time_cc_test.ok \</span><br><span> gsm48/rest_octets_test.ok \</span><br><span> base64/base64_test.ok \</span><br><span style="color: hsl(120, 100%, 40%);">+ iuup/iuup_test.ok \</span><br><span> $(NULL)</span><br><span> </span><br><span> if ENABLE_LIBSCTP</span><br><span>@@ -616,6 +621,8 @@</span><br><span> >$(srcdir)/it_q/it_q_test.ok</span><br><span> time_cc/time_cc_test \</span><br><span> >$(srcdir)/time_cc/time_cc_test.ok</span><br><span style="color: hsl(120, 100%, 40%);">+ iuup/iuup_test \</span><br><span style="color: hsl(120, 100%, 40%);">+ >$(srcdir)/iuup/iuup_test.ok</span><br><span> </span><br><span> check-local: atconfig $(TESTSUITE)</span><br><span> [ -e /proc/cpuinfo ] && cat /proc/cpuinfo</span><br><span>diff --git a/tests/iuup/iuup_test.c b/tests/iuup/iuup_test.c</span><br><span>new file mode 100644</span><br><span>index 0000000..0c7dbff</span><br><span>--- /dev/null</span><br><span>+++ b/tests/iuup/iuup_test.c</span><br><span>@@ -0,0 +1,543 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdint.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdio.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/application.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/logging.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/msgb.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/fsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/select.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/prim.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/iuup.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void *iuup_test_ctx;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct osmo_iuup_rnl_config def_configure_req = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .transparent = false,</span><br><span style="color: hsl(120, 100%, 40%);">+ .active = true,</span><br><span style="color: hsl(120, 100%, 40%);">+ .supported_versions_mask = 0x0001,</span><br><span style="color: hsl(120, 100%, 40%);">+ .num_rfci = 3,</span><br><span style="color: hsl(120, 100%, 40%);">+ .num_subflows = 3,</span><br><span style="color: hsl(120, 100%, 40%);">+ .subflow_sizes = {</span><br><span style="color: hsl(120, 100%, 40%);">+ {81, 103, 60},</span><br><span style="color: hsl(120, 100%, 40%);">+ {39, 0, 0},</span><br><span style="color: hsl(120, 100%, 40%);">+ {0, 0, 0},</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span style="color: hsl(120, 100%, 40%);">+ /* .delivery_err_sdu = All set to 0 (YES) by default, */</span><br><span style="color: hsl(120, 100%, 40%);">+ .IPTIs_present = true,</span><br><span style="color: hsl(120, 100%, 40%);">+ .IPTIs = {1, 7, 1},</span><br><span style="color: hsl(120, 100%, 40%);">+ .t_init = { .t_ms = IUUP_TIMER_INIT_T_DEFAULT, .n_max = IUUP_TIMER_INIT_N_DEFAULT },</span><br><span style="color: hsl(120, 100%, 40%);">+ .t_ta = { .t_ms = IUUP_TIMER_TA_T_DEFAULT, .n_max = IUUP_TIMER_TA_N_DEFAULT },</span><br><span style="color: hsl(120, 100%, 40%);">+ .t_rc = { .t_ms = IUUP_TIMER_RC_T_DEFAULT, .n_max = IUUP_TIMER_RC_N_DEFAULT },</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%);">+/* Frame 33, "Initialization", OS#4744 3g_call_23112021.pcapng</span><br><span style="color: hsl(120, 100%, 40%);">+IuUP</span><br><span style="color: hsl(120, 100%, 40%);">+ 1110 .... = PDU Type: Control Procedure (14)</span><br><span style="color: hsl(120, 100%, 40%);">+ .... 00.. = Ack/Nack: Procedure (0)</span><br><span style="color: hsl(120, 100%, 40%);">+ .... ..00 = Frame Number: 0</span><br><span style="color: hsl(120, 100%, 40%);">+ 0000 .... = Mode Version: 0x0</span><br><span style="color: hsl(120, 100%, 40%);">+ .... 0000 = Procedure: Initialization (0)</span><br><span style="color: hsl(120, 100%, 40%);">+ 1101 11.. = Header CRC: 0x37 [correct]</span><br><span style="color: hsl(120, 100%, 40%);">+ .... ..11 1001 1001 = Payload CRC: 0x399</span><br><span style="color: hsl(120, 100%, 40%);">+ 000. .... = Spare: 0x0</span><br><span style="color: hsl(120, 100%, 40%);">+ ...1 .... = TI: IPTIs present in frame (1)</span><br><span style="color: hsl(120, 100%, 40%);">+ .... 011. = Subflows: 3</span><br><span style="color: hsl(120, 100%, 40%);">+ .... ...0 = Chain Indicator: this frame is the last frame for the procedure (0)</span><br><span style="color: hsl(120, 100%, 40%);">+ RFCI 0 Initialization</span><br><span style="color: hsl(120, 100%, 40%);">+ 0... .... = RFCI 0 LRI: Not last RFCI (0x0)</span><br><span style="color: hsl(120, 100%, 40%);">+ .0.. .... = RFCI 0 LI: one octet used (0x0)</span><br><span style="color: hsl(120, 100%, 40%);">+ ..00 0000 = RFCI 0: 0</span><br><span style="color: hsl(120, 100%, 40%);">+ RFCI 0 Flow 0 Len: 81</span><br><span style="color: hsl(120, 100%, 40%);">+ RFCI 0 Flow 1 Len: 103</span><br><span style="color: hsl(120, 100%, 40%);">+ RFCI 0 Flow 2 Len: 60</span><br><span style="color: hsl(120, 100%, 40%);">+ RFCI 1 Initialization</span><br><span style="color: hsl(120, 100%, 40%);">+ 0... .... = RFCI 1 LRI: Not last RFCI (0x0)</span><br><span style="color: hsl(120, 100%, 40%);">+ .0.. .... = RFCI 1 LI: one octet used (0x0)</span><br><span style="color: hsl(120, 100%, 40%);">+ ..00 0001 = RFCI 1: 1</span><br><span style="color: hsl(120, 100%, 40%);">+ RFCI 1 Flow 0 Len: 39</span><br><span style="color: hsl(120, 100%, 40%);">+ RFCI 1 Flow 1 Len: 0</span><br><span style="color: hsl(120, 100%, 40%);">+ RFCI 1 Flow 2 Len: 0</span><br><span style="color: hsl(120, 100%, 40%);">+ RFCI 2 Initialization</span><br><span style="color: hsl(120, 100%, 40%);">+ 1... .... = RFCI 2 LRI: Last RFCI in current frame (0x1)</span><br><span style="color: hsl(120, 100%, 40%);">+ .0.. .... = RFCI 2 LI: one octet used (0x0)</span><br><span style="color: hsl(120, 100%, 40%);">+ ..00 0010 = RFCI 2: 2</span><br><span style="color: hsl(120, 100%, 40%);">+ RFCI 2 Flow 0 Len: 0</span><br><span style="color: hsl(120, 100%, 40%);">+ RFCI 2 Flow 1 Len: 0</span><br><span style="color: hsl(120, 100%, 40%);">+ RFCI 2 Flow 2 Len: 0</span><br><span style="color: hsl(120, 100%, 40%);">+ IPTIs</span><br><span style="color: hsl(120, 100%, 40%);">+ 0001 .... = RFCI 0 IPTI: 0x1</span><br><span style="color: hsl(120, 100%, 40%);">+ .... 0111 = RFCI 1 IPTI: 0x7</span><br><span style="color: hsl(120, 100%, 40%);">+ 0001 .... = RFCI 2 IPTI: 0x1</span><br><span style="color: hsl(120, 100%, 40%);">+ Iu UP Mode Versions Supported: 0x0001</span><br><span style="color: hsl(120, 100%, 40%);">+ 0... .... .... .... = Version 16: not supported (0x0)</span><br><span style="color: hsl(120, 100%, 40%);">+ .0.. .... .... .... = Version 15: not supported (0x0)</span><br><span style="color: hsl(120, 100%, 40%);">+ ..0. .... .... .... = Version 14: not supported (0x0)</span><br><span style="color: hsl(120, 100%, 40%);">+ ...0 .... .... .... = Version 13: not supported (0x0)</span><br><span style="color: hsl(120, 100%, 40%);">+ .... 0... .... .... = Version 12: not supported (0x0)</span><br><span style="color: hsl(120, 100%, 40%);">+ .... .0.. .... .... = Version 11: not supported (0x0)</span><br><span style="color: hsl(120, 100%, 40%);">+ .... ..0. .... .... = Version 10: not supported (0x0)</span><br><span style="color: hsl(120, 100%, 40%);">+ .... ...0 .... .... = Version 9: not supported (0x0)</span><br><span style="color: hsl(120, 100%, 40%);">+ .... .... 0... .... = Version 8: not supported (0x0)</span><br><span style="color: hsl(120, 100%, 40%);">+ .... .... .0.. .... = Version 7: not supported (0x0)</span><br><span style="color: hsl(120, 100%, 40%);">+ .... .... ..0. .... = Version 6: not supported (0x0)</span><br><span style="color: hsl(120, 100%, 40%);">+ .... .... ...0 .... = Version 5: not supported (0x0)</span><br><span style="color: hsl(120, 100%, 40%);">+ .... .... .... 0... = Version 4: not supported (0x0)</span><br><span style="color: hsl(120, 100%, 40%);">+ .... .... .... .0.. = Version 3: not supported (0x0)</span><br><span style="color: hsl(120, 100%, 40%);">+ .... .... .... ..0. = Version 2: not supported (0x0)</span><br><span style="color: hsl(120, 100%, 40%);">+ .... .... .... ...1 = Version 1: supported (0x1)</span><br><span style="color: hsl(120, 100%, 40%);">+ 0000 .... = RFCI Data Pdu Type: PDU type 0 (0x0)</span><br><span style="color: hsl(120, 100%, 40%);">+*/</span><br><span style="color: hsl(120, 100%, 40%);">+static const uint8_t iuup_initialization[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ 0xe0, 0x00, 0xdf, 0x99, 0x16, 0x00, 0x51, 0x67, 0x3c, 0x01, 0x27, 0x00,</span><br><span style="color: hsl(120, 100%, 40%);">+ 0x00, 0x82, 0x00, 0x00, 0x00, 0x17, 0x10, 0x00, 0x01, 0x00</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%);">+/* Frame 87, "Data RFCI=0 FN = 1", OS#4744 3g_call_23112021.pcapng</span><br><span style="color: hsl(120, 100%, 40%);">+IuUP</span><br><span style="color: hsl(120, 100%, 40%);">+ 0000 .... = PDU Type: Data with CRC (0)</span><br><span style="color: hsl(120, 100%, 40%);">+ .... 0001 = Frame Number: 1</span><br><span style="color: hsl(120, 100%, 40%);">+ 00.. .... = FQC: Frame Good (0)</span><br><span style="color: hsl(120, 100%, 40%);">+ ..00 0000 = RFCI: 0x00</span><br><span style="color: hsl(120, 100%, 40%);">+ 1110 00.. = Header CRC: 0x38 [correct]</span><br><span style="color: hsl(120, 100%, 40%);">+ .... ..11 1111 1111 = Payload CRC: 0x3ff</span><br><span style="color: hsl(120, 100%, 40%);">+ Payload Data: 08556d944c71a1a081e7ead204244480000ecd82b81118000097c4794e7740</span><br><span style="color: hsl(120, 100%, 40%);">+*/</span><br><span style="color: hsl(120, 100%, 40%);">+static const uint8_t iuup_data[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ 0x01, 0x00, 0xe3, 0xff, /*payload starts here: */ 0x08, 0x55, 0x6d, 0x94, 0x4c, 0x71, 0xa1, 0xa0,</span><br><span style="color: hsl(120, 100%, 40%);">+ 0x81, 0xe7, 0xea, 0xd2, 0x04, 0x24, 0x44, 0x80, 0x00, 0x0e, 0xcd, 0x82,</span><br><span style="color: hsl(120, 100%, 40%);">+ 0xb8, 0x11, 0x18, 0x00, 0x00, 0x97, 0xc4, 0x79, 0x4e, 0x77, 0x40</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 IUUP_MSGB_SIZE 4096</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct osmo_iuup_tnl_prim *itp_ctrl_nack_alloc(enum iuup_procedure proc_ind, enum iuup_error_cause error_cause, uint8_t fn)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_tnl_prim *tnp;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct iuup_ctrl_nack *nack;</span><br><span style="color: hsl(120, 100%, 40%);">+ tnp = osmo_iuup_tnl_prim_alloc(iuup_test_ctx, OSMO_IUUP_TNL_UNITDATA, PRIM_OP_INDICATION, IUUP_MSGB_SIZE);</span><br><span style="color: hsl(120, 100%, 40%);">+ tnp->oph.msg->l2h = msgb_put(tnp->oph.msg, sizeof(struct iuup_ctrl_nack));</span><br><span style="color: hsl(120, 100%, 40%);">+ nack = (struct iuup_ctrl_nack *) msgb_l2(tnp->oph.msg);</span><br><span style="color: hsl(120, 100%, 40%);">+ *nack = (struct iuup_ctrl_nack){</span><br><span style="color: hsl(120, 100%, 40%);">+ .hdr = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .frame_nr = fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ .ack_nack = IUUP_AN_NACK,</span><br><span style="color: hsl(120, 100%, 40%);">+ .pdu_type = IUUP_PDU_T_CONTROL,</span><br><span style="color: hsl(120, 100%, 40%);">+ .proc_ind = proc_ind,</span><br><span style="color: hsl(120, 100%, 40%);">+ .mode_version = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+ .payload_crc_hi = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+ .header_crc = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+ .payload_crc_lo = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span style="color: hsl(120, 100%, 40%);">+ .spare = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+ .error_cause = error_cause,</span><br><span style="color: hsl(120, 100%, 40%);">+ };</span><br><span style="color: hsl(120, 100%, 40%);">+ nack->hdr.header_crc = osmo_iuup_compute_header_crc(msgb_l2(tnp->oph.msg), msgb_l2len(tnp->oph.msg));</span><br><span style="color: hsl(120, 100%, 40%);">+ return tnp;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct osmo_iuup_tnl_prim *itp_ctrl_ack_alloc(enum iuup_procedure proc_ind, uint8_t fn)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_tnl_prim *tnp;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct iuup_ctrl_ack *ack;</span><br><span style="color: hsl(120, 100%, 40%);">+ tnp = osmo_iuup_tnl_prim_alloc(iuup_test_ctx, OSMO_IUUP_TNL_UNITDATA, PRIM_OP_INDICATION, IUUP_MSGB_SIZE);</span><br><span style="color: hsl(120, 100%, 40%);">+ tnp->oph.msg->l2h = msgb_put(tnp->oph.msg, sizeof(struct iuup_ctrl_ack));</span><br><span style="color: hsl(120, 100%, 40%);">+ ack = (struct iuup_ctrl_ack *) msgb_l2(tnp->oph.msg);</span><br><span style="color: hsl(120, 100%, 40%);">+ *ack = (struct iuup_ctrl_ack){</span><br><span style="color: hsl(120, 100%, 40%);">+ .hdr = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .frame_nr = fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ .ack_nack = IUUP_AN_ACK,</span><br><span style="color: hsl(120, 100%, 40%);">+ .pdu_type = IUUP_PDU_T_CONTROL,</span><br><span style="color: hsl(120, 100%, 40%);">+ .proc_ind = proc_ind,</span><br><span style="color: hsl(120, 100%, 40%);">+ .mode_version = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+ .payload_crc_hi = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+ .header_crc = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+ .payload_crc_lo = 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%);">+ ack->hdr.header_crc = osmo_iuup_compute_header_crc(msgb_l2(tnp->oph.msg), msgb_l2len(tnp->oph.msg));</span><br><span style="color: hsl(120, 100%, 40%);">+ return tnp;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void clock_override_set(long sec, long usec)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_gettimeofday_override_time.tv_sec = sec + usec / (1000*1000);</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_gettimeofday_override_time.tv_usec = usec % (1000*1000);</span><br><span style="color: hsl(120, 100%, 40%);">+ printf("sys={%lu.%06lu}, %s\n", osmo_gettimeofday_override_time.tv_sec,</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_gettimeofday_override_time.tv_usec, __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void test_crc(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Frame 34, "Initialization ACK", OS#4744 3g_call_23112021.pcapng */</span><br><span style="color: hsl(120, 100%, 40%);">+ static const uint8_t iuup_initialization_ack[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ 0xe4, 0x00, 0xdf, 0x99, 0x16, 0x00, 0x51, 0x67, 0x3c, 0x01, 0x27, 0x00,</span><br><span style="color: hsl(120, 100%, 40%);">+ 0x00, 0x82, 0x00, 0x00, 0x00, 0x17, 0x10, 0x00, 0x01, 0x00</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%);">+ printf("=== start: %s ===\n", __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = osmo_iuup_compute_header_crc(iuup_initialization, sizeof(iuup_initialization));</span><br><span style="color: hsl(120, 100%, 40%);">+ printf("iuup_initialization: Header CRC = 0x%02x\n", rc);</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = osmo_iuup_compute_payload_crc(iuup_initialization, sizeof(iuup_initialization));</span><br><span style="color: hsl(120, 100%, 40%);">+ printf("iuup_initialization: Payload CRC = 0x%03x\n", rc);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = osmo_iuup_compute_header_crc(iuup_initialization_ack, sizeof(iuup_initialization_ack));</span><br><span style="color: hsl(120, 100%, 40%);">+ printf("iuup_initialization_ack: Header CRC = 0x%02x\n", rc);</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = osmo_iuup_compute_payload_crc(iuup_initialization_ack, sizeof(iuup_initialization_ack));</span><br><span style="color: hsl(120, 100%, 40%);">+ printf("iuup_initialization_ack: Payload CRC = 0x%03x\n", rc);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ printf("=== end: %s ===\n", __func__);</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%);">+ * test_tinit_timeout_retrans</span><br><span style="color: hsl(120, 100%, 40%);">+ ****************************/</span><br><span style="color: hsl(120, 100%, 40%);">+static unsigned int _tinit_timeout_retrans_user_rx_prim = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+static int _tinit_timeout_retrans_user_prim_cb(struct osmo_prim_hdr *oph, void *ctx)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_rnl_prim *irp = (struct osmo_iuup_rnl_prim *)oph;</span><br><span style="color: hsl(120, 100%, 40%);">+ printf("%s()\n", __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(OSMO_PRIM_HDR(&irp->oph) == OSMO_PRIM(OSMO_IUUP_RNL_STATUS, PRIM_OP_INDICATION));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(irp->u.status.procedure == IUUP_PROC_ERR_EVENT);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(irp->u.status.u.error_event.cause == IUUP_ERR_CAUSE_INIT_FAILURE_NET_TMR);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(irp->u.status.u.error_event.distance == IUUP_ERR_DIST_LOCAL);</span><br><span style="color: hsl(120, 100%, 40%);">+ _tinit_timeout_retrans_user_rx_prim++;</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_free(oph->msg);</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%);">+static unsigned int _tinit_timeout_retrans_transport_rx_prim = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+static int _tinit_timeout_retrans_transport_prim_cb(struct osmo_prim_hdr *oph, void *ctx)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_tnl_prim *itp = (struct osmo_iuup_tnl_prim *)oph;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct msgb *msg = oph->msg;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ printf("%s()\n", __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(OSMO_PRIM_HDR(&itp->oph) == OSMO_PRIM(OSMO_IUUP_TNL_UNITDATA, PRIM_OP_REQUEST));</span><br><span style="color: hsl(120, 100%, 40%);">+ printf("Transport: DL len=%u: %s\n", msgb_l2len(msg),</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_hexdump((const unsigned char *) msgb_l2(msg), msgb_l2len(msg)));</span><br><span style="color: hsl(120, 100%, 40%);">+ _tinit_timeout_retrans_transport_rx_prim++;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_free(msg);</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%);">+void test_tinit_timeout_retrans(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_instance *iui;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_rnl_prim *rnp;</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc, i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ iui = osmo_iuup_instance_alloc(iuup_test_ctx, __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(iui);</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_iuup_instance_set_user_prim_cb(iui, _tinit_timeout_retrans_user_prim_cb, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_iuup_instance_set_transport_prim_cb(iui, _tinit_timeout_retrans_transport_prim_cb, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ clock_override_set(0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Tx CONFIG.req */</span><br><span style="color: hsl(120, 100%, 40%);">+ rnp = osmo_iuup_rnl_prim_alloc(iuup_test_ctx, OSMO_IUUP_RNL_CONFIG, PRIM_OP_REQUEST, IUUP_MSGB_SIZE);</span><br><span style="color: hsl(120, 100%, 40%);">+ rnp->u.config = def_configure_req;</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT((rc = osmo_iuup_rnl_prim_down(iui, rnp)) == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* STATUS-INIT.req is transmitted automatically: */</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(_tinit_timeout_retrans_transport_rx_prim == 1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* After one sec, INITIALIZATION msg is retransmitted */</span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 1; i < IUUP_TIMER_INIT_N_DEFAULT + 1; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+ clock_override_set(0, IUUP_TIMER_INIT_T_DEFAULT*1000 * i);</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_select_main(0);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(_tinit_timeout_retrans_transport_rx_prim == i + 1);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Last one should send an error event: */</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(_tinit_timeout_retrans_user_rx_prim == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ clock_override_set(0, IUUP_TIMER_INIT_T_DEFAULT*1000 * i);</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_select_main(0);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(_tinit_timeout_retrans_transport_rx_prim == i);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(_tinit_timeout_retrans_user_rx_prim == 1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Nothing else is received afterwards. osmo_select_main() will block forever. */</span><br><span style="color: hsl(120, 100%, 40%);">+ /*clock_override_set(i + 1, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_select_main(0);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(_tinit_timeout_retrans_transport_rx_prim == i);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(_tinit_timeout_retrans_user_rx_prim == 1);*/</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_iuup_instance_free(iui);</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%);">+ * test_tinit_nack</span><br><span style="color: hsl(120, 100%, 40%);">+ ****************************/</span><br><span style="color: hsl(120, 100%, 40%);">+static unsigned int _init_nack_retrans_user_rx_prim = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+static int _init_nack_retrans_user_prim_cb(struct osmo_prim_hdr *oph, void *ctx)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_rnl_prim *irp = (struct osmo_iuup_rnl_prim *)oph;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ printf("%s()\n", __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(OSMO_PRIM_HDR(&irp->oph) == OSMO_PRIM(OSMO_IUUP_RNL_STATUS, PRIM_OP_INDICATION));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(irp->u.status.procedure == IUUP_PROC_ERR_EVENT);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(irp->u.status.u.error_event.cause == IUUP_ERR_CAUSE_INIT_FAILURE_REP_NACK);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(irp->u.status.u.error_event.distance == IUUP_ERR_DIST_SECOND_FWD);</span><br><span style="color: hsl(120, 100%, 40%);">+ _init_nack_retrans_user_rx_prim++;</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_free(oph->msg);</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%);">+static int _init_nack_retrans_transport_rx_prim = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+static int _init_nack_retrans_transport_prim_cb(struct osmo_prim_hdr *oph, void *ctx)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_tnl_prim *itp = (struct osmo_iuup_tnl_prim *)oph;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct msgb *msg = oph->msg;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ printf("%s()\n", __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(OSMO_PRIM_HDR(&itp->oph) == OSMO_PRIM(OSMO_IUUP_TNL_UNITDATA, PRIM_OP_REQUEST));</span><br><span style="color: hsl(120, 100%, 40%);">+ printf("Transport: DL len=%u: %s\n", msgb_l2len(msg),</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_hexdump((const unsigned char *) msgb_l2(msg), msgb_l2len(msg)));</span><br><span style="color: hsl(120, 100%, 40%);">+ _init_nack_retrans_transport_rx_prim++;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_free(msg);</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%);">+void test_init_nack_retrans(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_instance *iui;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_rnl_prim *rnp;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_tnl_prim *tnp;</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc, i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ iui = osmo_iuup_instance_alloc(iuup_test_ctx, __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(iui);</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_iuup_instance_set_user_prim_cb(iui, _init_nack_retrans_user_prim_cb, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_iuup_instance_set_transport_prim_cb(iui, _init_nack_retrans_transport_prim_cb, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ clock_override_set(0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Tx CONFIG.req */</span><br><span style="color: hsl(120, 100%, 40%);">+ rnp = osmo_iuup_rnl_prim_alloc(iuup_test_ctx, OSMO_IUUP_RNL_CONFIG, PRIM_OP_REQUEST, IUUP_MSGB_SIZE);</span><br><span style="color: hsl(120, 100%, 40%);">+ rnp->u.config = def_configure_req;</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT((rc = osmo_iuup_rnl_prim_down(iui, rnp)) == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* STATUS-INIT.req is transmitted automatically: */</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(_init_nack_retrans_transport_rx_prim == 1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* After one sec, INITIALIZATION msg is retransmitted */</span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 1; i < IUUP_TIMER_INIT_N_DEFAULT + 1; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Send NACK: */</span><br><span style="color: hsl(120, 100%, 40%);">+ tnp = itp_ctrl_nack_alloc(IUUP_PROC_INIT, IUUP_ERR_CAUSE_MODE_VERSION_NOT_SUPPORTED, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT((rc = osmo_iuup_tnl_prim_up(iui, tnp)) == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* A new INIT is retransmitted: */</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(_init_nack_retrans_transport_rx_prim == i + 1);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Last one should send an error event: */</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(_init_nack_retrans_user_rx_prim == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ tnp = itp_ctrl_nack_alloc(IUUP_PROC_INIT, IUUP_ERR_CAUSE_MODE_VERSION_NOT_SUPPORTED, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT((rc = osmo_iuup_tnl_prim_up(iui, tnp)) == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(_init_nack_retrans_transport_rx_prim == i);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(_init_nack_retrans_user_rx_prim == 1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Nothing else is received afterwards. osmo_select_main() will block forever. */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_iuup_instance_free(iui);</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%);">+ * test_init_ack</span><br><span style="color: hsl(120, 100%, 40%);">+ ****************************/</span><br><span style="color: hsl(120, 100%, 40%);">+static unsigned int _init_ack_user_rx_prim = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+static int _init_ack_user_prim_cb(struct osmo_prim_hdr *oph, void *ctx)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_rnl_prim *irp = (struct osmo_iuup_rnl_prim *)oph;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct msgb *msg = oph->msg;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ printf("%s()\n", __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(OSMO_PRIM_HDR(&irp->oph) == OSMO_PRIM(OSMO_IUUP_RNL_DATA, PRIM_OP_INDICATION));</span><br><span style="color: hsl(120, 100%, 40%);">+ printf("User: UL len=%u: %s\n", msgb_l3len(msg),</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_hexdump((const unsigned char *) msgb_l3(msg), msgb_l3len(msg)));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ _init_ack_user_rx_prim++;</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_free(oph->msg);</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%);">+static int _init_ack_transport_rx_prim = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+static int _init_ack_transport_prim_cb(struct osmo_prim_hdr *oph, void *ctx)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_tnl_prim *itp = (struct osmo_iuup_tnl_prim *)oph;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct msgb *msg = oph->msg;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ printf("%s()\n", __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(OSMO_PRIM_HDR(&itp->oph) == OSMO_PRIM(OSMO_IUUP_TNL_UNITDATA, PRIM_OP_REQUEST));</span><br><span style="color: hsl(120, 100%, 40%);">+ printf("Transport: DL len=%u: %s\n", msgb_l2len(msg),</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_hexdump((const unsigned char *) msgb_l2(msg), msgb_l2len(msg)));</span><br><span style="color: hsl(120, 100%, 40%);">+ _init_ack_transport_rx_prim++;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_free(msg);</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%);">+void test_init_ack(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_instance *iui;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_rnl_prim *rnp;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_tnl_prim *tnp;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct iuup_pdutype0_hdr *hdr0;</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%);">+ iui = osmo_iuup_instance_alloc(iuup_test_ctx, __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(iui);</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_iuup_instance_set_user_prim_cb(iui, _init_ack_user_prim_cb, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_iuup_instance_set_transport_prim_cb(iui, _init_ack_transport_prim_cb, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ clock_override_set(0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Tx CONFIG.req */</span><br><span style="color: hsl(120, 100%, 40%);">+ rnp = osmo_iuup_rnl_prim_alloc(iuup_test_ctx, OSMO_IUUP_RNL_CONFIG, PRIM_OP_REQUEST, IUUP_MSGB_SIZE);</span><br><span style="color: hsl(120, 100%, 40%);">+ rnp->u.config = def_configure_req;</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT((rc = osmo_iuup_rnl_prim_down(iui, rnp)) == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* STATUS-INIT.req is transmitted automatically: */</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(_init_ack_transport_rx_prim == 1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Send ACK: */</span><br><span style="color: hsl(120, 100%, 40%);">+ tnp = itp_ctrl_ack_alloc(IUUP_PROC_INIT, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT((rc = osmo_iuup_tnl_prim_up(iui, tnp)) == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(_init_ack_transport_rx_prim == 1); /* Make sure there's no retrans */</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(_init_ack_user_rx_prim == 0); /* Make sure there's no error event */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Send IuUP incoming data to the implementation: */</span><br><span style="color: hsl(120, 100%, 40%);">+ tnp = osmo_iuup_tnl_prim_alloc(iuup_test_ctx, OSMO_IUUP_TNL_UNITDATA, PRIM_OP_INDICATION, IUUP_MSGB_SIZE);</span><br><span style="color: hsl(120, 100%, 40%);">+ tnp->oph.msg->l2h = msgb_put(tnp->oph.msg, sizeof(iuup_data));</span><br><span style="color: hsl(120, 100%, 40%);">+ hdr0 = (struct iuup_pdutype0_hdr *)msgb_l2(tnp->oph.msg);</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(hdr0, iuup_data, sizeof(iuup_data));</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT((rc = osmo_iuup_tnl_prim_up(iui, tnp)) == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* We receive it in RNL: */</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(_init_ack_user_rx_prim == 1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Now in opposite direction, RNL->[IuuP]->TNL: */</span><br><span style="color: hsl(120, 100%, 40%);">+ rnp = osmo_iuup_rnl_prim_alloc(iuup_test_ctx, OSMO_IUUP_RNL_DATA, PRIM_OP_REQUEST, IUUP_MSGB_SIZE);</span><br><span style="color: hsl(120, 100%, 40%);">+ rnp->u.data.rfci = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ rnp->u.data.frame_nr = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+ rnp->u.data.fqc = IUUP_FQC_FRAME_GOOD;</span><br><span style="color: hsl(120, 100%, 40%);">+ rnp->oph.msg->l3h = msgb_put(rnp->oph.msg, sizeof(iuup_data) - 4);</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(rnp->oph.msg->l3h, iuup_data + 4, sizeof(iuup_data) - 4);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT((rc = osmo_iuup_rnl_prim_down(iui, rnp)) == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(_init_ack_transport_rx_prim == 2); /* We receive data in TNL */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_iuup_instance_free(iui);</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%);">+ * test_passive_init</span><br><span style="color: hsl(120, 100%, 40%);">+ ****************************/</span><br><span style="color: hsl(120, 100%, 40%);">+static unsigned int _passive_init_user_rx_prim = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+static int _passive_init_user_prim_cb(struct osmo_prim_hdr *oph, void *ctx)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_rnl_prim *irp = (struct osmo_iuup_rnl_prim *)oph;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct msgb *msg = oph->msg;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ printf("%s()\n", __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(OSMO_PRIM_HDR(&irp->oph) == OSMO_PRIM(OSMO_IUUP_RNL_DATA, PRIM_OP_INDICATION));</span><br><span style="color: hsl(120, 100%, 40%);">+ printf("User: UL len=%u: %s\n", msgb_l3len(msg),</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_hexdump((const unsigned char *) msgb_l3(msg), msgb_l3len(msg)));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ _passive_init_user_rx_prim++;</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_free(oph->msg);</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%);">+static int _passive_init_transport_rx_prim = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+static int _passive_init_transport_prim_cb(struct osmo_prim_hdr *oph, void *ctx)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_tnl_prim *itp = (struct osmo_iuup_tnl_prim *)oph;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ printf("%s()\n", __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+ msg = oph->msg;</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(OSMO_PRIM_HDR(&itp->oph) == OSMO_PRIM(OSMO_IUUP_TNL_UNITDATA, PRIM_OP_REQUEST));</span><br><span style="color: hsl(120, 100%, 40%);">+ printf("Transport: DL len=%u: %s\n", msgb_l2len(msg),</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_hexdump((const unsigned char *) msgb_l2(msg), msgb_l2len(msg)));</span><br><span style="color: hsl(120, 100%, 40%);">+ _passive_init_transport_rx_prim++;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_free(msg);</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%);">+void test_passive_init(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Here we check the passive INIT code path, aka receiving INIT and returning INIT_ACK/NACK */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_instance *iui;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_rnl_prim *rnp;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_iuup_tnl_prim *tnp;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct iuup_pdutype14_hdr *hdr14;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct iuup_pdutype0_hdr *hdr0;</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%);">+ iui = osmo_iuup_instance_alloc(iuup_test_ctx, __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(iui);</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_iuup_instance_set_user_prim_cb(iui, _passive_init_user_prim_cb, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_iuup_instance_set_transport_prim_cb(iui, _passive_init_transport_prim_cb, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ clock_override_set(0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Tx CONFIG.req */</span><br><span style="color: hsl(120, 100%, 40%);">+ rnp = osmo_iuup_rnl_prim_alloc(iuup_test_ctx, OSMO_IUUP_RNL_CONFIG, PRIM_OP_REQUEST, IUUP_MSGB_SIZE);</span><br><span style="color: hsl(120, 100%, 40%);">+ rnp->u.config = def_configure_req;</span><br><span style="color: hsl(120, 100%, 40%);">+ rnp->u.config.active = false;</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT((rc = osmo_iuup_rnl_prim_down(iui, rnp)) == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* STATUS-INIT.req is NOT transmitted automatically: */</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(_passive_init_transport_rx_prim == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Send Init: */</span><br><span style="color: hsl(120, 100%, 40%);">+ tnp = osmo_iuup_tnl_prim_alloc(iuup_test_ctx, OSMO_IUUP_TNL_UNITDATA, PRIM_OP_INDICATION, IUUP_MSGB_SIZE);</span><br><span style="color: hsl(120, 100%, 40%);">+ tnp->oph.msg->l2h = msgb_put(tnp->oph.msg, sizeof(iuup_initialization));</span><br><span style="color: hsl(120, 100%, 40%);">+ hdr14 = (struct iuup_pdutype14_hdr *)msgb_l2(tnp->oph.msg);</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(hdr14, iuup_initialization, sizeof(iuup_initialization));</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT((rc = osmo_iuup_tnl_prim_up(iui, tnp)) == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(_passive_init_transport_rx_prim == 1); /* We receive an Init ACK */</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(_passive_init_user_rx_prim == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Send IuUP incoming data to the implementation: */</span><br><span style="color: hsl(120, 100%, 40%);">+ tnp = osmo_iuup_tnl_prim_alloc(iuup_test_ctx, OSMO_IUUP_TNL_UNITDATA, PRIM_OP_INDICATION, IUUP_MSGB_SIZE);</span><br><span style="color: hsl(120, 100%, 40%);">+ tnp->oph.msg->l2h = msgb_put(tnp->oph.msg, sizeof(iuup_data));</span><br><span style="color: hsl(120, 100%, 40%);">+ hdr0 = (struct iuup_pdutype0_hdr *)msgb_l2(tnp->oph.msg);</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(hdr0, iuup_data, sizeof(iuup_data));</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT((rc = osmo_iuup_tnl_prim_up(iui, tnp)) == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* We receive it in RNL: */</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(_passive_init_user_rx_prim == 1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Now in opposite direction, RNL->[IuuP]->TNL: */</span><br><span style="color: hsl(120, 100%, 40%);">+ rnp = osmo_iuup_rnl_prim_alloc(iuup_test_ctx, OSMO_IUUP_RNL_DATA, PRIM_OP_REQUEST, IUUP_MSGB_SIZE);</span><br><span style="color: hsl(120, 100%, 40%);">+ rnp->u.data.rfci = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ rnp->u.data.frame_nr = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+ rnp->u.data.fqc = IUUP_FQC_FRAME_GOOD;</span><br><span style="color: hsl(120, 100%, 40%);">+ rnp->oph.msg->l3h = msgb_put(rnp->oph.msg, sizeof(iuup_data) - 4);</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(rnp->oph.msg->l3h, iuup_data + 4, sizeof(iuup_data) - 4);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT((rc = osmo_iuup_rnl_prim_down(iui, rnp)) == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(_passive_init_transport_rx_prim == 2); /* We receive data in TNL */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_iuup_instance_free(iui);</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%);">+int main(int argc, char **argv)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ iuup_test_ctx = talloc_named_const(NULL, 0, "iuup_test");</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_init_logging2(iuup_test_ctx, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE);</span><br><span style="color: hsl(120, 100%, 40%);">+ log_set_print_category(osmo_stderr_target, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+ log_set_print_category_hex(osmo_stderr_target, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ log_set_use_color(osmo_stderr_target, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ log_set_category_filter(osmo_stderr_target, DLIUUP, 1, LOGL_DEBUG);</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fsm_log_addr(false);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_gettimeofday_override = true;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ test_crc();</span><br><span style="color: hsl(120, 100%, 40%);">+ test_tinit_timeout_retrans();</span><br><span style="color: hsl(120, 100%, 40%);">+ test_init_nack_retrans();</span><br><span style="color: hsl(120, 100%, 40%);">+ test_init_ack();</span><br><span style="color: hsl(120, 100%, 40%);">+ test_passive_init();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ printf("OK.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/tests/iuup/iuup_test.ok b/tests/iuup/iuup_test.ok</span><br><span>new file mode 100644</span><br><span>index 0000000..5423096</span><br><span>--- /dev/null</span><br><span>+++ b/tests/iuup/iuup_test.ok</span><br><span>@@ -0,0 +1,45 @@</span><br><span style="color: hsl(120, 100%, 40%);">+=== start: test_crc ===</span><br><span style="color: hsl(120, 100%, 40%);">+iuup_initialization: Header CRC = 0x37</span><br><span style="color: hsl(120, 100%, 40%);">+iuup_initialization: Payload CRC = 0x399</span><br><span style="color: hsl(120, 100%, 40%);">+iuup_initialization_ack: Header CRC = 0x09</span><br><span style="color: hsl(120, 100%, 40%);">+iuup_initialization_ack: Payload CRC = 0x399</span><br><span style="color: hsl(120, 100%, 40%);">+=== end: test_crc ===</span><br><span style="color: hsl(120, 100%, 40%);">+sys={0.000000}, clock_override_set</span><br><span style="color: hsl(120, 100%, 40%);">+_tinit_timeout_retrans_transport_prim_cb()</span><br><span style="color: hsl(120, 100%, 40%);">+Transport: DL len=22: e0 00 df 99 16 00 51 67 3c 01 27 00 00 82 00 00 00 17 10 00 01 00 </span><br><span style="color: hsl(120, 100%, 40%);">+sys={1.000000}, clock_override_set</span><br><span style="color: hsl(120, 100%, 40%);">+_tinit_timeout_retrans_transport_prim_cb()</span><br><span style="color: hsl(120, 100%, 40%);">+Transport: DL len=22: e0 00 df 99 16 00 51 67 3c 01 27 00 00 82 00 00 00 17 10 00 01 00 </span><br><span style="color: hsl(120, 100%, 40%);">+sys={2.000000}, clock_override_set</span><br><span style="color: hsl(120, 100%, 40%);">+_tinit_timeout_retrans_transport_prim_cb()</span><br><span style="color: hsl(120, 100%, 40%);">+Transport: DL len=22: e0 00 df 99 16 00 51 67 3c 01 27 00 00 82 00 00 00 17 10 00 01 00 </span><br><span style="color: hsl(120, 100%, 40%);">+sys={3.000000}, clock_override_set</span><br><span style="color: hsl(120, 100%, 40%);">+_tinit_timeout_retrans_transport_prim_cb()</span><br><span style="color: hsl(120, 100%, 40%);">+Transport: DL len=22: e0 00 df 99 16 00 51 67 3c 01 27 00 00 82 00 00 00 17 10 00 01 00 </span><br><span style="color: hsl(120, 100%, 40%);">+sys={4.000000}, clock_override_set</span><br><span style="color: hsl(120, 100%, 40%);">+_tinit_timeout_retrans_user_prim_cb()</span><br><span style="color: hsl(120, 100%, 40%);">+sys={0.000000}, clock_override_set</span><br><span style="color: hsl(120, 100%, 40%);">+_init_nack_retrans_transport_prim_cb()</span><br><span style="color: hsl(120, 100%, 40%);">+Transport: DL len=22: e0 00 df 99 16 00 51 67 3c 01 27 00 00 82 00 00 00 17 10 00 01 00 </span><br><span style="color: hsl(120, 100%, 40%);">+_init_nack_retrans_transport_prim_cb()</span><br><span style="color: hsl(120, 100%, 40%);">+Transport: DL len=22: e0 00 df 99 16 00 51 67 3c 01 27 00 00 82 00 00 00 17 10 00 01 00 </span><br><span style="color: hsl(120, 100%, 40%);">+_init_nack_retrans_transport_prim_cb()</span><br><span style="color: hsl(120, 100%, 40%);">+Transport: DL len=22: e0 00 df 99 16 00 51 67 3c 01 27 00 00 82 00 00 00 17 10 00 01 00 </span><br><span style="color: hsl(120, 100%, 40%);">+_init_nack_retrans_transport_prim_cb()</span><br><span style="color: hsl(120, 100%, 40%);">+Transport: DL len=22: e0 00 df 99 16 00 51 67 3c 01 27 00 00 82 00 00 00 17 10 00 01 00 </span><br><span style="color: hsl(120, 100%, 40%);">+_init_nack_retrans_user_prim_cb()</span><br><span style="color: hsl(120, 100%, 40%);">+sys={0.000000}, clock_override_set</span><br><span style="color: hsl(120, 100%, 40%);">+_init_ack_transport_prim_cb()</span><br><span style="color: hsl(120, 100%, 40%);">+Transport: DL len=22: e0 00 df 99 16 00 51 67 3c 01 27 00 00 82 00 00 00 17 10 00 01 00 </span><br><span style="color: hsl(120, 100%, 40%);">+_init_ack_user_prim_cb()</span><br><span style="color: hsl(120, 100%, 40%);">+User: UL len=31: 08 55 6d 94 4c 71 a1 a0 81 e7 ea d2 04 24 44 80 00 0e cd 82 b8 11 18 00 00 97 c4 79 4e 77 40 </span><br><span style="color: hsl(120, 100%, 40%);">+_init_ack_transport_prim_cb()</span><br><span style="color: hsl(120, 100%, 40%);">+Transport: DL len=35: 01 00 e3 ff 08 55 6d 94 4c 71 a1 a0 81 e7 ea d2 04 24 44 80 00 0e cd 82 b8 11 18 00 00 97 c4 79 4e 77 40 </span><br><span style="color: hsl(120, 100%, 40%);">+sys={0.000000}, clock_override_set</span><br><span style="color: hsl(120, 100%, 40%);">+_passive_init_transport_prim_cb()</span><br><span style="color: hsl(120, 100%, 40%);">+Transport: DL len=4: e4 00 24 00 </span><br><span style="color: hsl(120, 100%, 40%);">+_passive_init_user_prim_cb()</span><br><span style="color: hsl(120, 100%, 40%);">+User: UL len=31: 08 55 6d 94 4c 71 a1 a0 81 e7 ea d2 04 24 44 80 00 0e cd 82 b8 11 18 00 00 97 c4 79 4e 77 40 </span><br><span style="color: hsl(120, 100%, 40%);">+_passive_init_transport_prim_cb()</span><br><span style="color: hsl(120, 100%, 40%);">+Transport: DL len=35: 01 00 e3 ff 08 55 6d 94 4c 71 a1 a0 81 e7 ea d2 04 24 44 80 00 0e cd 82 b8 11 18 00 00 97 c4 79 4e 77 40 </span><br><span style="color: hsl(120, 100%, 40%);">+OK.</span><br><span>diff --git a/tests/logging/logging_vty_test.vty b/tests/logging/logging_vty_test.vty</span><br><span>index 99e8781..c74accd 100644</span><br><span>--- a/tests/logging/logging_vty_test.vty</span><br><span>+++ b/tests/logging/logging_vty_test.vty</span><br><span>@@ -54,7 +54,7 @@</span><br><span> logging print level (0|1)</span><br><span> logging print file (0|1|basename) [last]</span><br><span> logging set-log-mask MASK</span><br><span style="color: hsl(0, 100%, 40%);">- logging level (aa|bb|ccc|dddd|eee|lglobal|llapd|linp|lmux|lmi|lmib|lsms|lctrl|lgtp|lstats|lgsup|loap|lss7|lsccp|lsua|lm3ua|lmgcp|ljibuf|lrspro|lns|lbssgp|lnsdata|lnssignal) (debug|info|notice|error|fatal)</span><br><span style="color: hsl(120, 100%, 40%);">+ logging level (aa|bb|ccc|dddd|eee|lglobal|llapd|linp|lmux|lmi|lmib|lsms|lctrl|lgtp|lstats|lgsup|loap|lss7|lsccp|lsua|lm3ua|lmgcp|ljibuf|lrspro|lns|lbssgp|lnsdata|lnssignal|liuup) (debug|info|notice|error|fatal)</span><br><span> logging level set-all (debug|info|notice|error|fatal)</span><br><span> logging level force-all (debug|info|notice|error|fatal)</span><br><span> no logging level force-all</span><br><span>@@ -472,7 +472,7 @@</span><br><span> </span><br><span> logging_vty_test# list</span><br><span> ...</span><br><span style="color: hsl(0, 100%, 40%);">- logp (aa|bb|ccc|dddd|eee|lglobal|llapd|linp|lmux|lmi|lmib|lsms|lctrl|lgtp|lstats|lgsup|loap|lss7|lsccp|lsua|lm3ua|lmgcp|ljibuf|lrspro|lns|lbssgp|lnsdata|lnssignal) (debug|info|notice|error|fatal) .LOGMESSAGE</span><br><span style="color: hsl(120, 100%, 40%);">+ logp (aa|bb|ccc|dddd|eee|lglobal|llapd|linp|lmux|lmi|lmib|lsms|lctrl|lgtp|lstats|lgsup|loap|lss7|lsccp|lsua|lm3ua|lmgcp|ljibuf|lrspro|lns|lbssgp|lnsdata|lnssignal|liuup) (debug|info|notice|error|fatal) .LOGMESSAGE</span><br><span> ...</span><br><span> </span><br><span> logging_vty_test# logp?</span><br><span>@@ -507,6 +507,7 @@</span><br><span> lbssgp GPRS BSSGP layer</span><br><span> lnsdata GPRS NS layer data PDU</span><br><span> lnssignal GPRS NS layer signal PDU</span><br><span style="color: hsl(120, 100%, 40%);">+ liuup Iu UP layer</span><br><span> </span><br><span> logging_vty_test# logp lglobal ?</span><br><span> debug Log debug messages and higher levels</span><br><span>diff --git a/tests/testsuite.at b/tests/testsuite.at</span><br><span>index 92c4e39..882203e 100644</span><br><span>--- a/tests/testsuite.at</span><br><span>+++ b/tests/testsuite.at</span><br><span>@@ -458,3 +458,9 @@</span><br><span> cat $abs_srcdir/time_cc/time_cc_test.ok > expout</span><br><span> AT_CHECK([$abs_top_builddir/tests/time_cc/time_cc_test], [0], [expout], [ignore])</span><br><span> AT_CLEANUP</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+AT_SETUP([iuup])</span><br><span style="color: hsl(120, 100%, 40%);">+AT_KEYWORDS([iuup])</span><br><span style="color: hsl(120, 100%, 40%);">+cat $abs_srcdir/iuup/iuup_test.ok > expout</span><br><span style="color: hsl(120, 100%, 40%);">+AT_CHECK([$abs_top_builddir/tests/iuup/iuup_test], [0], [expout], [ignore])</span><br><span style="color: hsl(120, 100%, 40%);">+AT_CLEANUP</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/libosmocore/+/6357">change 6357</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/+/6357"/><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: Ibe356fa7b1abaca0091e368db8478e79c09c6cb0 </div>
<div style="display:none"> Gerrit-Change-Number: 6357 </div>
<div style="display:none"> Gerrit-PatchSet: 7 </div>
<div style="display:none"> Gerrit-Owner: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-Reviewer: Hoernchen <ewild@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder </div>
<div style="display:none"> Gerrit-Reviewer: daniel <dwillmann@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: dexter <pmaier@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: fixeria <vyanitskiy@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: laforge <laforge@gnumonks.org> </div>
<div style="display:none"> Gerrit-Reviewer: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-Reviewer: lynxis lazus <lynxis@fe80.eu> </div>
<div style="display:none"> Gerrit-Reviewer: neels <nhofmeyr@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: osmith <osmith@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>