<p>pespin <strong>submitted</strong> this change.</p><p><a href="https://gerrit.osmocom.org/c/osmo-hnodeb/+/26357">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Jenkins Builder: Verified
  laforge: Looks good to me, approved

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">Initial implementation of LowerLayer UD Socket<br><br>The LLSK socket is an interface allowing thid-parties to implement and<br>hook their RLC/MAC/RRC stack to osmo-hnodbe, which takes care of<br>interconnection with the rest of the RAN and core network (Iuh, RTP,<br>GTP-U, etc.).<br><br>Related: SYS#5516<br>Change-Id: Icaabb2206d6f141d4fba47dedf71f8ec37e6257d<br>---<br>A doc/hnodeb.msc<br>M include/osmocom/hnodeb/Makefile.am<br>A include/osmocom/hnodeb/hnb_prim.h<br>M include/osmocom/hnodeb/hnodeb.h<br>A include/osmocom/hnodeb/llsk.h<br>M include/osmocom/hnodeb/ranap.h<br>M include/osmocom/hnodeb/rua.h<br>M include/osmocom/hnodeb/vty.h<br>M src/osmo-hnodeb/Makefile.am<br>M src/osmo-hnodeb/debug.c<br>M src/osmo-hnodeb/hnb.c<br>M src/osmo-hnodeb/hnb_shutdown_fsm.c<br>M src/osmo-hnodeb/hnbap.c<br>A src/osmo-hnodeb/llsk.c<br>A src/osmo-hnodeb/llsk_iuh.c<br>M src/osmo-hnodeb/main.c<br>M src/osmo-hnodeb/ranap.c<br>M src/osmo-hnodeb/rua.c<br>M src/osmo-hnodeb/vty.c<br>19 files changed, 1,083 insertions(+), 40 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/doc/hnodeb.msc b/doc/hnodeb.msc</span><br><span>new file mode 100644</span><br><span>index 0000000..6ad6e7c</span><br><span>--- /dev/null</span><br><span>+++ b/doc/hnodeb.msc</span><br><span>@@ -0,0 +1,86 @@</span><br><span style="color: hsl(120, 100%, 40%);">+msc {</span><br><span style="color: hsl(120, 100%, 40%);">+        hscale="3";</span><br><span style="color: hsl(120, 100%, 40%);">+ ue [label="Customer"], trx [label="Lower Layer TRX"], hnodeb [label="osmo-hnodeb"], hnbgw [label="HNBGW"], ggsn [label="GGSN"], mgw [label="MGW"];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      |||;</span><br><span style="color: hsl(120, 100%, 40%);">+  ---  [ label = "hNodeB starts up" ];</span><br><span style="color: hsl(120, 100%, 40%);">+        hnodeb => hnbgw [label="HNBAP HnbRegisterRequest"];</span><br><span style="color: hsl(120, 100%, 40%);">+      hnodeb <= hnbgw [label="HNBAP HnbRegisterResponse"];</span><br><span 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%);">+  ---  [ label = "TRX starts up & connects to hNodeB" ];</span><br><span style="color: hsl(120, 100%, 40%);">+  trx => hnodeb [label="CTL-HELLO.req(SAPI=CTL, VERSION)"];</span><br><span style="color: hsl(120, 100%, 40%);">+        trx <= hnodeb [label="CTL-HELLO.cnf(SAPI=CTL, VERSION)"];</span><br><span style="color: hsl(120, 100%, 40%);">+        trx => hnodeb [label="CTL-HELLO.req(SAPI=IUH, VERSION)"];</span><br><span style="color: hsl(120, 100%, 40%);">+        trx <= hnodeb [label="CTL-HELLO.cnf(SAPI=IUH, VERSION)"];</span><br><span style="color: hsl(120, 100%, 40%);">+        trx => hnodeb [label="CTL-HELLO.req(SAPI=GTP, VERSION)"];</span><br><span style="color: hsl(120, 100%, 40%);">+        trx <= hnodeb [label="CTL-HELLO.cnf(SAPI=GTP, VERSION)"];</span><br><span style="color: hsl(120, 100%, 40%);">+        trx => hnodeb [label="CTL-HELLO.req(SAPI=AUDIO, VERSION)"];</span><br><span style="color: hsl(120, 100%, 40%);">+      trx <= hnodeb [label="CTL-HELLO.cnf(SAPI=AUDIO, VERSION)"];</span><br><span style="color: hsl(120, 100%, 40%);">+      trx <= hnodeb [label="IUH-CONFIGURE.ind(PLMN,LAC,SAC,RAC,CI,RNC_ID from HnbRegisterResponse)"];</span><br><span 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%);">+  ---  [ label = "Subscriber Paging" ];</span><br><span style="color: hsl(120, 100%, 40%);">+       hnodeb <= hnbgw [label="RUA-InitiatingMessage(RANAP Paging)"];</span><br><span style="color: hsl(120, 100%, 40%);">+   trx <= hnodeb [label="IUH-UNITDATA.ind[RANAP Paging]"];</span><br><span 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%);">+  ---  [ label = "Subscriber Sign Up" ];</span><br><span style="color: hsl(120, 100%, 40%);">+      ue => trx [label="CM Service Req"];</span><br><span style="color: hsl(120, 100%, 40%);">+      trx => hnodeb [label="IUH-CONN_ESTABLISH.req[RANAP CM ServiceReq]"];</span><br><span style="color: hsl(120, 100%, 40%);">+     hnodeb => hnbgw [label="HNBAP UE Register Req(IMSI?)"];</span><br><span style="color: hsl(120, 100%, 40%);">+  hnodeb <= hnbgw [label="HNBAP UE Register Acc(context_id)"];</span><br><span style="color: hsl(120, 100%, 40%);">+     hnodeb => hnbgw [label="RUA-Connect(RANAP-GMM ServiceRequest)"];</span><br><span style="color: hsl(120, 100%, 40%);">+ hnodeb <= hnbgw [label="RUA-DirectTransfer(RANAP GMM ServiceAccept)"];</span><br><span style="color: hsl(120, 100%, 40%);">+   trx <= hnodeb [label="IUH-CONN_ESTABLISH.cnf(context_id])"];</span><br><span style="color: hsl(120, 100%, 40%);">+     trx <= hnodeb [label="IUH-CONN_DATA.ind[context_id, RANAP GMM ServiceAccept]"];</span><br><span style="color: hsl(120, 100%, 40%);">+  ---  [ label = "Subscriber set up PS data:" ];</span><br><span style="color: hsl(120, 100%, 40%);">+      hnodeb <= hnbgw [label="RANAP RAB-Assignment Request(TEI, ADDR)"];</span><br><span style="color: hsl(120, 100%, 40%);">+       trx <= hnodeb [label="IUH-CONN_DATA.ind[RANAP RAB-Assignment Request(remote_ip, remote_port, remote_tei)]"];</span><br><span style="color: hsl(120, 100%, 40%);">+     trx => hnodeb [label="GTP-CONN_ESTABLISH.req(remote_ip,remote_port,remote_tei)"];</span><br><span style="color: hsl(120, 100%, 40%);">+        ...  [ label = "HnodeB sets up GTP-U connection" ];</span><br><span style="color: hsl(120, 100%, 40%);">+ trx <= hnodeb [label="GTP-CONN_ESTABLISH.cnf(local_ip,local_port,local_tei,remote_tei)"];</span><br><span 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%);">+  ---  [ label = "PS data transmission over GTP-U:" ];</span><br><span style="color: hsl(120, 100%, 40%);">+        ue => trx [label="..."];</span><br><span style="color: hsl(120, 100%, 40%);">+ trx => hnodeb [label="GTP-CONN_DATA.req[remote_tei,payload]"];</span><br><span style="color: hsl(120, 100%, 40%);">+   hnodeb => ggsn [label="GTP-U(remote_tei, local_addr, remote_addr, payload)"];</span><br><span style="color: hsl(120, 100%, 40%);">+    hnodeb <= ggsn [label="GTP-U(local_tei, remote_addr, local_addr, payload)"];</span><br><span style="color: hsl(120, 100%, 40%);">+     trx <= hnodeb [label="GTP-CONN_DATA.ind[local_tei,payload]"];</span><br><span style="color: hsl(120, 100%, 40%);">+    ue <= trx [label="..."];</span><br><span 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%);">+  ---  [ label = "MO/MT PS data Release:" ];</span><br><span style="color: hsl(120, 100%, 40%);">+  ue => trx [label="..."];</span><br><span style="color: hsl(120, 100%, 40%);">+ trx => hnodeb [label="IUH-CONN_DATA.req[RANAP IU Release Request]"];</span><br><span style="color: hsl(120, 100%, 40%);">+     hnodeb => hnbgw [label="RANAP IU Release Request"];</span><br><span style="color: hsl(120, 100%, 40%);">+      hnodeb <= hnbgw [label="RANAP IU Release Command"];</span><br><span style="color: hsl(120, 100%, 40%);">+      trx <= hnodeb [label="IUH-CONN_DATA.ind[RANAP IU Release Command]"];</span><br><span style="color: hsl(120, 100%, 40%);">+     ...;</span><br><span style="color: hsl(120, 100%, 40%);">+  trx => hnodeb [label="GTP-CONN_RELEASE.req(remote_tei)"];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      trx => hnodeb [label="IUH-CONN_RELEASE.req[RANAP IU Release Complete]"];</span><br><span style="color: hsl(120, 100%, 40%);">+ hnodeb => hnbgw [label="RUA-Disconnect(RANAP IU Release Complete)"];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   |||;</span><br><span style="color: hsl(120, 100%, 40%);">+  ...;</span><br><span style="color: hsl(120, 100%, 40%);">+  |||;</span><br><span style="color: hsl(120, 100%, 40%);">+  ---  [ label = "For voice call (CS): Similar to SAPI_GTP, but using SAPI_AUDIO and osmo-hnodeb sets up RTP stream" ];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   |||;</span><br><span style="color: hsl(120, 100%, 40%);">+  ...;</span><br><span style="color: hsl(120, 100%, 40%);">+  |||;</span><br><span style="color: hsl(120, 100%, 40%);">+  ---  [ label = "Iuh SCTP link goes down" ];</span><br><span style="color: hsl(120, 100%, 40%);">+ trx <= hnodeb [label="UD socket is closed, osmo-hnodeb cleans up state and attempts reconnect. lowerlayer can re-connect and wait for next CONFIGURE.req"];</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/include/osmocom/hnodeb/Makefile.am b/include/osmocom/hnodeb/Makefile.am</span><br><span>index 6fa587d..62af5bb 100644</span><br><span>--- a/include/osmocom/hnodeb/Makefile.am</span><br><span>+++ b/include/osmocom/hnodeb/Makefile.am</span><br><span>@@ -1,8 +1,10 @@</span><br><span> noinst_HEADERS = \</span><br><span>    hnb_shutdown_fsm.h \</span><br><span style="color: hsl(120, 100%, 40%);">+  hnb_prim.h \</span><br><span>         hnbap.h \</span><br><span>    hnodeb.h \</span><br><span>   iuh.h \</span><br><span style="color: hsl(120, 100%, 40%);">+       llsk.h \</span><br><span>     ranap.h \</span><br><span>    rua.h \</span><br><span>      vty.h \</span><br><span>diff --git a/include/osmocom/hnodeb/hnb_prim.h b/include/osmocom/hnodeb/hnb_prim.h</span><br><span>new file mode 100644</span><br><span>index 0000000..6d597c4</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/hnodeb/hnb_prim.h</span><br><span>@@ -0,0 +1,165 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ * Author: Pau Espin Pedrol <pespin@sysmocom.de></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%);">+ * 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 Affero General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 3 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 Affero General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU Affero General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+ * along with this program.  If not, see <http://www.gnu.org/lienses/>.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+/* This header includes information relative to protocol and message structure</span><br><span style="color: hsl(120, 100%, 40%);">+ * spoken between osmo-hnodeb, facing the HNBGW and other RAN/CN nodes, and a</span><br><span style="color: hsl(120, 100%, 40%);">+ * Lower Layer program (aka the TRX), implementing the RLC/MAC/RRC towards the</span><br><span style="color: hsl(120, 100%, 40%);">+ * UE in the Uu interface. This protocol is usually referenced as HNBLLIF. The</span><br><span style="color: hsl(120, 100%, 40%);">+ * protocol is primitive based and follows the concepts described in ITU-T</span><br><span style="color: hsl(120, 100%, 40%);">+ * X.210, with osmo-hnodeb taking the "service provider" role and the TRX taking</span><br><span style="color: hsl(120, 100%, 40%);">+ * the "user" role in this case.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</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 <inttypes.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <unistd.h></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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define HNB_PRIM_API_VERSION 0</span><br><span style="color: hsl(120, 100%, 40%);">+#define HNB_PRIM_UD_SOCK_DEFAULT "/tmp/hnb_prim_sock"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define HNB_PRIM_SAPI_IUH 1</span><br><span style="color: hsl(120, 100%, 40%);">+#define HNB_PRIM_SAPI_GTP 2</span><br><span style="color: hsl(120, 100%, 40%);">+#define HNB_PRIM_SAPI_AUDIO 3</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief HNB_IUH primitives */</span><br><span style="color: hsl(120, 100%, 40%);">+enum hnb_iuh_prim_type {</span><br><span style="color: hsl(120, 100%, 40%);">+        HNB_IUH_PRIM_CONFIGURE,</span><br><span style="color: hsl(120, 100%, 40%);">+       HNB_IUH_PRIM_CONN_ESTABLISH,</span><br><span style="color: hsl(120, 100%, 40%);">+  HNB_IUH_PRIM_CONN_RELEASE,</span><br><span style="color: hsl(120, 100%, 40%);">+    HNB_IUH_PRIM_CONN_DATA,</span><br><span style="color: hsl(120, 100%, 40%);">+       HNB_IUH_PRIM_UNITDATA,</span><br><span style="color: hsl(120, 100%, 40%);">+        _HNB_IUH_PRIM_MAX</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* HNB_IUH_PRIM_CONFIGURE.ind, DL */</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_iuh_configure_ind_param {</span><br><span style="color: hsl(120, 100%, 40%);">+   uint16_t mcc;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t mnc;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t cell_identity;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint16_t lac;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t rac;</span><br><span style="color: hsl(120, 100%, 40%);">+  uint8_t reserved;</span><br><span style="color: hsl(120, 100%, 40%);">+     uint16_t sac;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t rnc_id;</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%);">+/* HNB_HNB_IUH_PRIM_CONN_ESTABLISH.ind, DL */</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_iuh_conn_establish_ind_param {</span><br><span style="color: hsl(120, 100%, 40%);">+     uint32_t context_id;</span><br><span style="color: hsl(120, 100%, 40%);">+  uint8_t domain;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint8_t cause;</span><br><span style="color: hsl(120, 100%, 40%);">+        uint8_t csg_membership_status;</span><br><span style="color: hsl(120, 100%, 40%);">+        uint8_t spare1;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint32_t data_len; /* RANAP message length in bytes */</span><br><span style="color: hsl(120, 100%, 40%);">+        uint8_t data[0]; /* RANAP message */</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%);">+/* HNB_HNB_IUH_PRIM_CONN_ESTABLISH.req, UL */</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_iuh_conn_establish_req_param {</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t context_id;</span><br><span style="color: hsl(120, 100%, 40%);">+  uint8_t domain;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint8_t est_cause;</span><br><span style="color: hsl(120, 100%, 40%);">+    /* TODO: Check if we can copy it as an encoded buffer RRC <-> RUA</span><br><span style="color: hsl(120, 100%, 40%);">+        * RRC: 3GPP TS 25.331 10.3.1.6 Intra Domain NAS Node Selector</span><br><span style="color: hsl(120, 100%, 40%);">+         * RUA:  3GPP TS 25.468 9.2.4  */</span><br><span style="color: hsl(120, 100%, 40%);">+     uint16_t reserved; //uint16_t nas_node_selector_bitlen;</span><br><span style="color: hsl(120, 100%, 40%);">+       //uint8_t nas_node_selector[128]; /* TODO: check whether we can decrease this buffer size */</span><br><span style="color: hsl(120, 100%, 40%);">+  uint32_t data_len; /* RANAP message length in bytes */</span><br><span style="color: hsl(120, 100%, 40%);">+        uint8_t data[0]; /* RANAP message */</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%);">+/* HNB_HNB_IUH_PRIM_CONN_ESTABLISH.cnf, DL */</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_iuh_conn_establish_cnf_param {</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t context_id;</span><br><span style="color: hsl(120, 100%, 40%);">+  uint8_t domain;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint8_t cause; /* 0 = success, !0 = failure */</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%);">+/* HNB_IUH_PRIM_CONN_RELEASE.req, DL */</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_iuh_conn_release_req_param {</span><br><span style="color: hsl(120, 100%, 40%);">+       uint32_t context_id;</span><br><span style="color: hsl(120, 100%, 40%);">+  uint8_t domain;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint8_t spare1;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint8_t cause_type; /* 3GPP TS 25.468 9.2.7 Cause */</span><br><span style="color: hsl(120, 100%, 40%);">+  uint8_t cause; /* 3GPP TS 25.468 9.2.7 Cause */</span><br><span style="color: hsl(120, 100%, 40%);">+       uint32_t data_len; /* RANAP message length in bytes */</span><br><span style="color: hsl(120, 100%, 40%);">+        uint8_t data[0]; /* RANAP message */</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%);">+/* HNB_IUH_PRIM_CONN_RELEASE.ind, UL */</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_iuh_conn_release_ind_param {</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t context_id;</span><br><span style="color: hsl(120, 100%, 40%);">+  uint8_t domain;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint8_t spare1;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint8_t cause_type;</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t cause;</span><br><span style="color: hsl(120, 100%, 40%);">+        uint32_t data_len; /* RANAP message length in bytes */</span><br><span style="color: hsl(120, 100%, 40%);">+        uint8_t data[0]; /* RANAP message */</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%);">+/* HNB_IUH_PRIM_CONN_DATA.req, DL */</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_iuh_conn_data_req_param {</span><br><span style="color: hsl(120, 100%, 40%);">+       uint32_t context_id;</span><br><span style="color: hsl(120, 100%, 40%);">+  uint8_t domain;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint8_t spare1;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint16_t spare2;</span><br><span style="color: hsl(120, 100%, 40%);">+      uint32_t data_len; /* RANAP message length in bytes */</span><br><span style="color: hsl(120, 100%, 40%);">+        uint8_t data[0]; /* RANAP message */</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%);">+/* HNB_IUH_PRIM_CONN_DATA.ind, UL */</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_iuh_conn_data_ind_param {</span><br><span style="color: hsl(120, 100%, 40%);">+       uint32_t context_id;</span><br><span style="color: hsl(120, 100%, 40%);">+  uint8_t domain;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint8_t spare1;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint16_t spare2;</span><br><span style="color: hsl(120, 100%, 40%);">+      uint32_t data_len; /* RANAP message length in bytes */</span><br><span style="color: hsl(120, 100%, 40%);">+        uint8_t data[0]; /* RANAP message */</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%);">+/* HNB_IUH_PRIM_UNITDATA.req, UL */</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_iuh_unitdata_req_param {</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t data_len; /* RANAP message length in bytes */</span><br><span style="color: hsl(120, 100%, 40%);">+        uint8_t data[0]; /* RANAP message */</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%);">+/* HNB_IUH_PRIM_UNITDATA.ind, DL */</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_iuh_unitdata_ind_param {</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t data_len; /* RANAP message length in bytes */</span><br><span style="color: hsl(120, 100%, 40%);">+        uint8_t data[0]; /* RANAP message */</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%);">+struct hnb_iuh_prim {</span><br><span style="color: hsl(120, 100%, 40%);">+    struct osmo_prim_hdr hdr;</span><br><span style="color: hsl(120, 100%, 40%);">+     union {</span><br><span style="color: hsl(120, 100%, 40%);">+               struct hnb_iuh_configure_ind_param configure_ind;</span><br><span style="color: hsl(120, 100%, 40%);">+             struct hnb_iuh_conn_establish_req_param conn_establish_req;</span><br><span style="color: hsl(120, 100%, 40%);">+           struct hnb_iuh_conn_establish_ind_param conn_establish_ind;</span><br><span style="color: hsl(120, 100%, 40%);">+           struct hnb_iuh_conn_establish_cnf_param conn_establish_cnf;</span><br><span style="color: hsl(120, 100%, 40%);">+           struct hnb_iuh_conn_release_req_param conn_release_req;</span><br><span style="color: hsl(120, 100%, 40%);">+               struct hnb_iuh_conn_release_ind_param conn_release_ind;</span><br><span style="color: hsl(120, 100%, 40%);">+               struct hnb_iuh_conn_data_req_param conn_data_req;</span><br><span style="color: hsl(120, 100%, 40%);">+             struct hnb_iuh_conn_data_ind_param conn_data_ind;</span><br><span style="color: hsl(120, 100%, 40%);">+             struct hnb_iuh_unitdata_req_param unitdata_req;</span><br><span style="color: hsl(120, 100%, 40%);">+               struct hnb_iuh_unitdata_ind_param unitdata_ind;</span><br><span style="color: hsl(120, 100%, 40%);">+       } u;</span><br><span style="color: hsl(120, 100%, 40%);">+} __attribute__ ((packed));</span><br><span>diff --git a/include/osmocom/hnodeb/hnodeb.h b/include/osmocom/hnodeb/hnodeb.h</span><br><span>index a629b4e..fd7d1e9 100644</span><br><span>--- a/include/osmocom/hnodeb/hnodeb.h</span><br><span>+++ b/include/osmocom/hnodeb/hnodeb.h</span><br><span>@@ -19,29 +19,51 @@</span><br><span>  */</span><br><span> #pragma once</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdint.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdbool.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #include <asn1c/asn1helpers.h></span><br><span> </span><br><span> #include <osmocom/core/select.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/timer.h></span><br><span> #include <osmocom/core/linuxlist.h></span><br><span> #include <osmocom/core/write_queue.h></span><br><span> #include <osmocom/core/logging.h></span><br><span> #include <osmocom/gsm/gsm23003.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/protocol/gsm_23_003.h></span><br><span> #include <osmocom/netif/stream.h></span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hnodeb/llsk.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> enum {</span><br><span>   DMAIN,</span><br><span>       DHNBAP,</span><br><span>      DRUA,</span><br><span>        DRANAP,</span><br><span>      DSCTP,</span><br><span style="color: hsl(120, 100%, 40%);">+        DLLSK,</span><br><span> };</span><br><span> extern const struct log_info hnb_log_info;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-struct hnb_chan {</span><br><span style="color: hsl(0, 100%, 40%);">- int is_ps;</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_ue {</span><br><span style="color: hsl(120, 100%, 40%);">+    struct llist_head list; /* Item in struct hnb->ue_list */</span><br><span style="color: hsl(120, 100%, 40%);">+  struct hnb *hnb; /* backpointer */</span><br><span>   uint32_t conn_id;</span><br><span style="color: hsl(0, 100%, 40%);">-       char *imsi;</span><br><span style="color: hsl(120, 100%, 40%);">+   char imsi[OSMO_IMSI_BUF_SIZE];</span><br><span style="color: hsl(120, 100%, 40%);">+        struct hnb_ue_cs_ctx {</span><br><span style="color: hsl(120, 100%, 40%);">+                bool active; /* Is this chan in use? */</span><br><span style="color: hsl(120, 100%, 40%);">+               bool conn_est_cnf_pending; /* Did we send CONN_ESTABLISH_CNF to lower layers? */</span><br><span style="color: hsl(120, 100%, 40%);">+      } conn_cs;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct hnb_ue_ps_ctx {</span><br><span style="color: hsl(120, 100%, 40%);">+                bool active; /* Is this chan in use? */</span><br><span style="color: hsl(120, 100%, 40%);">+               bool conn_est_cnf_pending; /* Did we send CONN_ESTABLISH_CNF to lower layers? */</span><br><span style="color: hsl(120, 100%, 40%);">+      } conn_ps;</span><br><span> };</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_ue *hnb_ue_alloc(struct hnb *hnb, uint32_t conn_id);</span><br><span style="color: hsl(120, 100%, 40%);">+void hnb_ue_free(struct hnb_ue *ue);</span><br><span style="color: hsl(120, 100%, 40%);">+void hnb_ue_reset_chan(struct hnb_ue *ue, bool is_ps);</span><br><span> </span><br><span> struct hnb {</span><br><span>  char *identity; /* HNB-Identity */</span><br><span>@@ -58,20 +80,27 @@</span><br><span>             struct osmo_stream_cli *client;</span><br><span>      } iuh;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+    /* Lower Layer UD socket */</span><br><span style="color: hsl(120, 100%, 40%);">+   struct osmo_prim_srv_link *llsk_link;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_prim_srv *llsk;</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t llsk_valid_sapi_mask;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_timer_list llsk_defer_configure_ind_timer;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     uint16_t rnc_id;</span><br><span style="color: hsl(120, 100%, 40%);">+      bool registered; /* Set to true once HnbRegisterAccept was received from Iuh. rnc_id is valid iif registered==true */</span><br><span> </span><br><span>    uint32_t ctx_id;</span><br><span> </span><br><span>         struct osmo_fsm_inst *shutdown_fi; /* FSM instance to manage shutdown procedure during process exit */</span><br><span>       bool shutdown_fi_exit_proc; /* exit process when shutdown_fsm is finished? */</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       struct {</span><br><span style="color: hsl(0, 100%, 40%);">-                struct hnb_chan *chan;</span><br><span style="color: hsl(0, 100%, 40%);">-  } cs;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct llist_head ue_list; /* list of struct hnb_ue */</span><br><span> };</span><br><span> </span><br><span> struct hnb *hnb_alloc(void *tall_ctx);</span><br><span> void hnb_free(struct hnb *hnb);</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_ue *hnb_find_ue_by_id(const struct hnb *hnb, uint32_t conn_id);</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_ue *hnb_find_ue_by_imsi(const struct hnb *hnb, char *imsi);</span><br><span> </span><br><span> extern void *tall_hnb_ctx;</span><br><span> extern struct hnb *g_hnb;</span><br><span>diff --git a/include/osmocom/hnodeb/llsk.h b/include/osmocom/hnodeb/llsk.h</span><br><span>new file mode 100644</span><br><span>index 0000000..ab39439</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/hnodeb/llsk.h</span><br><span>@@ -0,0 +1,44 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ * Author: Pau Espin Pedrol <pespin@sysmocom.de></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%);">+ * 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 Affero General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 3 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 Affero General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU Affero General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+ * along with this program.  If not, see <http://www.gnu.org/lienses/>.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ */</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 <stdbool.h></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/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/netif/prim.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hnodeb/hnb_prim.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int hnb_llsk_alloc(struct hnb *hnb);</span><br><span style="color: hsl(120, 100%, 40%);">+bool hnb_llsk_connected(const struct hnb *hnb);</span><br><span style="color: hsl(120, 100%, 40%);">+bool hnb_llsk_can_be_configured(struct hnb *hnb);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+extern const struct value_string hnb_iuh_prim_type_names[];</span><br><span style="color: hsl(120, 100%, 40%);">+int llsk_rx_iuh(struct hnb *hnb, struct osmo_prim_hdr *oph);</span><br><span style="color: hsl(120, 100%, 40%);">+int llsk_iuh_tx_configure_ind(struct hnb *hnb);</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_iuh_prim *hnb_iuh_makeprim_conn_establish_cnf(uint32_t context_id, uint8_t domain,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                         uint8_t cause);</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_iuh_prim *hnb_iuh_makeprim_conn_data_ind(uint32_t context_id,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                uint8_t domain,</span><br><span style="color: hsl(120, 100%, 40%);">+                                               const uint8_t *data,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                  uint32_t data_len);</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_iuh_prim *hnb_iuh_makeprim_unitdata_ind(const uint8_t *data, uint32_t data_len);</span><br><span>diff --git a/include/osmocom/hnodeb/ranap.h b/include/osmocom/hnodeb/ranap.h</span><br><span>index 474de70..6e9c9b7 100644</span><br><span>--- a/include/osmocom/hnodeb/ranap.h</span><br><span>+++ b/include/osmocom/hnodeb/ranap.h</span><br><span>@@ -19,4 +19,6 @@</span><br><span>  */</span><br><span> #pragma once</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/msgb.h></span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb *hnb_ranap_msgb_alloc(void);</span><br><span>diff --git a/include/osmocom/hnodeb/rua.h b/include/osmocom/hnodeb/rua.h</span><br><span>index ea7e81c..e780207 100644</span><br><span>--- a/include/osmocom/hnodeb/rua.h</span><br><span>+++ b/include/osmocom/hnodeb/rua.h</span><br><span>@@ -22,6 +22,9 @@</span><br><span> #include <asn1c/ANY.h></span><br><span> </span><br><span> struct hnb;</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_ue;</span><br><span> struct msgb;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb *hnb_rua_msgb_alloc(void);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> int hnb_rua_rx(struct hnb *hnb, struct msgb *msg);</span><br><span>diff --git a/include/osmocom/hnodeb/vty.h b/include/osmocom/hnodeb/vty.h</span><br><span>index e30019e..627436d 100644</span><br><span>--- a/include/osmocom/hnodeb/vty.h</span><br><span>+++ b/include/osmocom/hnodeb/vty.h</span><br><span>@@ -27,6 +27,7 @@</span><br><span> enum hnb_vty_nodes {</span><br><span>        HNODEB_NODE = _LAST_OSMOVTY_NODE,</span><br><span>    IUH_NODE,</span><br><span style="color: hsl(120, 100%, 40%);">+     LLSK_NODE,</span><br><span> };</span><br><span> </span><br><span> void hnb_vty_init(void);</span><br><span>diff --git a/src/osmo-hnodeb/Makefile.am b/src/osmo-hnodeb/Makefile.am</span><br><span>index 82ccd37..b6d2d49 100644</span><br><span>--- a/src/osmo-hnodeb/Makefile.am</span><br><span>+++ b/src/osmo-hnodeb/Makefile.am</span><br><span>@@ -35,6 +35,8 @@</span><br><span>        hnb.c \</span><br><span>      hnb_shutdown_fsm.c \</span><br><span>         iuh.c \</span><br><span style="color: hsl(120, 100%, 40%);">+       llsk.c \</span><br><span style="color: hsl(120, 100%, 40%);">+      llsk_iuh.c \</span><br><span>         ranap.c \</span><br><span>    rua.c \</span><br><span>      vty.c \</span><br><span>diff --git a/src/osmo-hnodeb/debug.c b/src/osmo-hnodeb/debug.c</span><br><span>index 45ccc0c..f34851b 100644</span><br><span>--- a/src/osmo-hnodeb/debug.c</span><br><span>+++ b/src/osmo-hnodeb/debug.c</span><br><span>@@ -24,7 +24,7 @@</span><br><span> static const struct log_info_cat log_cat[] = {</span><br><span>       [DMAIN] = {</span><br><span>          .name = "DMAIN", .loglevel = LOGL_NOTICE, .enabled = 1,</span><br><span style="color: hsl(0, 100%, 40%);">-               .color = "",</span><br><span style="color: hsl(120, 100%, 40%);">+                .color = "\033[1;37m",</span><br><span>             .description = "Main program",</span><br><span>     },</span><br><span>   [DHNBAP] = {</span><br><span>@@ -47,6 +47,11 @@</span><br><span>            .color = "\033[1;36m",</span><br><span>             .description = "SCTP connection on the Iuh link",</span><br><span>  },</span><br><span style="color: hsl(120, 100%, 40%);">+    [DLLSK] = {</span><br><span style="color: hsl(120, 100%, 40%);">+           .name = "DLLSK", .loglevel = LOGL_NOTICE, .enabled = 1,</span><br><span style="color: hsl(120, 100%, 40%);">+             .color = "\033[1;31m",</span><br><span style="color: hsl(120, 100%, 40%);">+              .description = "Lower Layer Unix Domain Socket",</span><br><span style="color: hsl(120, 100%, 40%);">+    },</span><br><span> };</span><br><span> </span><br><span> const struct log_info hnb_log_info = {</span><br><span>diff --git a/src/osmo-hnodeb/hnb.c b/src/osmo-hnodeb/hnb.c</span><br><span>index b7be4ea..1ac2efc 100644</span><br><span>--- a/src/osmo-hnodeb/hnb.c</span><br><span>+++ b/src/osmo-hnodeb/hnb.c</span><br><span>@@ -23,10 +23,12 @@</span><br><span> #include <osmocom/core/socket.h></span><br><span> #include <osmocom/core/talloc.h></span><br><span> #include <osmocom/netif/stream.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/netif/prim.h></span><br><span> </span><br><span> #include <osmocom/hnodeb/hnodeb.h></span><br><span> #include <osmocom/hnodeb/iuh.h></span><br><span> #include <osmocom/hnodeb/hnb_shutdown_fsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hnodeb/hnb_prim.h></span><br><span> </span><br><span> </span><br><span> struct hnb *hnb_alloc(void *tall_ctx)</span><br><span>@@ -37,15 +39,18 @@</span><br><span>        if (!hnb)</span><br><span>            return NULL;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+      INIT_LLIST_HEAD(&hnb->ue_list);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     hnb->identity = talloc_strdup(hnb, "OsmoHNodeB");</span><br><span>       hnb->plmn = (struct osmo_plmn_id){</span><br><span>                .mcc = 1,</span><br><span>            .mnc = 1,</span><br><span>    };</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>   hnb->shutdown_fi = osmo_fsm_inst_alloc(&hnb_shutdown_fsm, hnb, hnb,</span><br><span>                                          LOGL_INFO, NULL);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+  hnb_llsk_alloc(hnb);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>       hnb_iuh_alloc(hnb);</span><br><span> </span><br><span>      return hnb;</span><br><span>@@ -53,10 +58,78 @@</span><br><span> </span><br><span> void hnb_free(struct hnb *hnb)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+  struct hnb_ue *ue, *ue_tmp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry_safe(ue, ue_tmp, &hnb->ue_list, list)</span><br><span style="color: hsl(120, 100%, 40%);">+             hnb_ue_free(ue);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>   if (hnb->shutdown_fi) {</span><br><span>           osmo_fsm_inst_free(hnb->shutdown_fi);</span><br><span>             hnb->shutdown_fi = NULL;</span><br><span>  }</span><br><span>    hnb_iuh_free(hnb);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  osmo_timer_del(&hnb->llsk_defer_configure_ind_timer);</span><br><span style="color: hsl(120, 100%, 40%);">+  osmo_prim_srv_link_free(hnb->llsk_link);</span><br><span style="color: hsl(120, 100%, 40%);">+   hnb->llsk_link = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  talloc_free(hnb);</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_ue *hnb_ue_alloc(struct hnb *hnb, uint32_t conn_id)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct hnb_ue *ue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  ue = talloc_zero(hnb, struct hnb_ue);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ue)</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%);">+        ue->hnb = hnb;</span><br><span style="color: hsl(120, 100%, 40%);">+     ue->conn_id = conn_id;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   llist_add(&ue->list, &hnb->ue_list);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  return ue;</span><br><span 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 hnb_ue_free(struct hnb_ue *ue)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       llist_del(&ue->list);</span><br><span style="color: hsl(120, 100%, 40%);">+  talloc_free(ue);</span><br><span 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 hnb_ue_reset_chan(struct hnb_ue *ue, bool is_ps)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       if (is_ps)</span><br><span style="color: hsl(120, 100%, 40%);">+            ue->conn_ps = (struct hnb_ue_ps_ctx){0};</span><br><span style="color: hsl(120, 100%, 40%);">+   else</span><br><span style="color: hsl(120, 100%, 40%);">+          ue->conn_cs = (struct hnb_ue_cs_ctx){0};</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_ue *hnb_find_ue_by_id(const struct hnb *hnb, uint32_t conn_id)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct hnb_ue *ue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  llist_for_each_entry(ue, &hnb->ue_list, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+                if (ue->conn_id != conn_id)</span><br><span style="color: hsl(120, 100%, 40%);">+                        continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             return ue;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</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%);">+struct hnb_ue *hnb_find_ue_by_imsi(const struct hnb *hnb, char *imsi)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct hnb_ue *ue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!imsi || imsi[0] == '\0')</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%);">+        llist_for_each_entry(ue, &hnb->ue_list, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+                if (ue->imsi[0] == '\0')</span><br><span style="color: hsl(120, 100%, 40%);">+                   continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             if (strncmp(&ue->imsi[0], imsi, ARRAY_SIZE(ue->imsi)) != 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                 continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             return ue;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+     return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/osmo-hnodeb/hnb_shutdown_fsm.c b/src/osmo-hnodeb/hnb_shutdown_fsm.c</span><br><span>index 55de64c..5583834 100644</span><br><span>--- a/src/osmo-hnodeb/hnb_shutdown_fsm.c</span><br><span>+++ b/src/osmo-hnodeb/hnb_shutdown_fsm.c</span><br><span>@@ -34,6 +34,11 @@</span><br><span> static void st_none_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)</span><br><span> {</span><br><span>        struct hnb *hnb = (struct hnb *)fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* Reset state: */</span><br><span style="color: hsl(120, 100%, 40%);">+    hnb->registered = false;</span><br><span style="color: hsl(120, 100%, 40%);">+   hnb->rnc_id = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>        hnb_iuh_connect(hnb); /* Start reconnect once we are done with shutdown and we didn't exit process */</span><br><span> }</span><br><span> </span><br><span>diff --git a/src/osmo-hnodeb/hnbap.c b/src/osmo-hnodeb/hnbap.c</span><br><span>index 3287eeb..ccd521e 100644</span><br><span>--- a/src/osmo-hnodeb/hnbap.c</span><br><span>+++ b/src/osmo-hnodeb/hnbap.c</span><br><span>@@ -33,7 +33,9 @@</span><br><span> #include <osmocom/hnodeb/hnbap.h></span><br><span> #include <osmocom/hnodeb/hnodeb.h></span><br><span> #include <osmocom/hnodeb/iuh.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hnodeb/hnb_prim.h></span><br><span> #include <osmocom/hnodeb/hnb_shutdown_fsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hnodeb/llsk.h></span><br><span> </span><br><span> static int hnb_rx_hnb_register_acc(struct hnb *hnb, ANY_t *in)</span><br><span> {</span><br><span>@@ -42,13 +44,19 @@</span><br><span> </span><br><span>       rc = hnbap_decode_hnbregisteraccepties(&accept, in);</span><br><span>     if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              hnb_shutdown(hnb, "Failed decoding HnbRegisterAccept IEs", false);</span><br><span style="color: hsl(120, 100%, 40%);">+          return rc;</span><br><span>   }</span><br><span> </span><br><span>        hnb->rnc_id = accept.rnc_id;</span><br><span style="color: hsl(120, 100%, 40%);">+       hnb->registered = true;</span><br><span>   LOGP(DHNBAP, LOGL_INFO, "Rx HNB Register accept with RNC ID %u\n", hnb->rnc_id);</span><br><span> </span><br><span>    hnbap_free_hnbregisteraccepties(&accept);</span><br><span style="color: hsl(0, 100%, 40%);">-   return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (hnb_llsk_can_be_configured(hnb))</span><br><span style="color: hsl(120, 100%, 40%);">+          llsk_iuh_tx_configure_ind(hnb);</span><br><span style="color: hsl(120, 100%, 40%);">+       return rc;</span><br><span> }</span><br><span> </span><br><span> static int hnb_rx_hnb_register_rej(struct hnb *hnb, ANY_t *in)</span><br><span>@@ -56,6 +64,8 @@</span><br><span>    int rc;</span><br><span>      HNBAP_HNBRegisterRejectIEs_t reject;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+      hnb->registered = false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>        rc = hnbap_decode_hnbregisterrejecties(&reject, in);</span><br><span>     if (rc < 0) {</span><br><span>             LOGP(DHNBAP, LOGL_NOTICE, "Rx HNB Register Reject: parse failure\n");</span><br><span>diff --git a/src/osmo-hnodeb/llsk.c b/src/osmo-hnodeb/llsk.c</span><br><span>new file mode 100644</span><br><span>index 0000000..5f0f9dc</span><br><span>--- /dev/null</span><br><span>+++ b/src/osmo-hnodeb/llsk.c</span><br><span>@@ -0,0 +1,134 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ * Author: Pau Espin Pedrol <pespin@sysmocom.de></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%);">+ * 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 Affero General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 3 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 Affero General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU Affero General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+ * along with this program.  If not, see <http://www.gnu.org/lienses/>.</span><br><span 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%);">+#include <errno.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/core/logging.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hnodeb/hnodeb.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hnodeb/llsk.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hnodeb/hnb_prim.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hnodeb/hnb_shutdown_fsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int llsk_opened_cb(struct osmo_prim_srv *srv)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct hnb *hnb = (struct hnb *)osmo_prim_srv_get_priv(srv);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (hnb->llsk) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGP(DLLSK, LOGL_ERROR, "New connection opened while one is already active, dropping it\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                osmo_prim_srv_close(srv);</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%);">+     LOGP(DLLSK, LOGL_NOTICE, "LLSK conn is UP\n");</span><br><span style="color: hsl(120, 100%, 40%);">+      hnb->llsk = srv;</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%);">+static int llsk_closed_cb(struct osmo_prim_srv *srv)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct hnb *hnb = (struct hnb *)osmo_prim_srv_get_priv(srv);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!hnb->llsk) {</span><br><span style="color: hsl(120, 100%, 40%);">+          LOGP(DLLSK, LOGL_ERROR, "closed_cb received but we have no active llsk conn!\n");</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%);">+     /* If a later conn different than active one is dropped (because we closed it): */</span><br><span style="color: hsl(120, 100%, 40%);">+    if (hnb->llsk != srv)</span><br><span style="color: hsl(120, 100%, 40%);">+              return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     LOGP(DLLSK, LOGL_NOTICE, "LLSK conn is DOWN\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  hnb->llsk = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  hnb->llsk_valid_sapi_mask = 0x0;</span><br><span style="color: hsl(120, 100%, 40%);">+   osmo_timer_del(&hnb->llsk_defer_configure_ind_timer);</span><br><span style="color: hsl(120, 100%, 40%);">+  hnb_shutdown(hnb, "LLSK conn dropped", false);</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%);">+bool hnb_llsk_connected(const struct hnb *hnb)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     return !!hnb->llsk;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+bool hnb_llsk_can_be_configured(struct hnb *hnb)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!hnb->registered)</span><br><span style="color: hsl(120, 100%, 40%);">+              return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!hnb->llsk)</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%);">+       if (hnb->llsk_valid_sapi_mask & (1 << HNB_PRIM_SAPI_IUH))</span><br><span style="color: hsl(120, 100%, 40%);">+                return true;</span><br><span style="color: hsl(120, 100%, 40%);">+  return false;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void llsk_defer_configure_ind_timer_cb(void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct hnb *hnb = (struct hnb *)data;</span><br><span style="color: hsl(120, 100%, 40%);">+ llsk_iuh_tx_configure_ind(hnb);</span><br><span 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 llsk_rx_sapi_version_cb(struct osmo_prim_srv *prim_srv, uint32_t sapi, uint16_t rem_version)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct hnb *hnb = (struct hnb *)osmo_prim_srv_get_priv(prim_srv);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (sapi > sizeof(hnb->llsk_valid_sapi_mask)*8 - 1)</span><br><span style="color: hsl(120, 100%, 40%);">+             return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    hnb->llsk_valid_sapi_mask |= (1 << sapi);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* Defer CONFIGURE.req after we have confirmed the versions */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (hnb_llsk_can_be_configured(hnb))</span><br><span style="color: hsl(120, 100%, 40%);">+          osmo_timer_schedule(&hnb->llsk_defer_configure_ind_timer, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     return rem_version;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int llsk_rx_cb(struct osmo_prim_srv *srv, struct osmo_prim_hdr *oph)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct hnb *hnb = (struct hnb *)osmo_prim_srv_get_priv(srv);</span><br><span style="color: hsl(120, 100%, 40%);">+  LOGP(DLLSK, LOGL_DEBUG, "llsk_rx_cb() SAP=%u (%u bytes): %s\n", oph->sap,</span><br><span style="color: hsl(120, 100%, 40%);">+             msgb_length(oph->msg), osmo_hexdump(msgb_data(oph->msg), msgb_length(oph->msg)));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     switch (oph->sap) {</span><br><span style="color: hsl(120, 100%, 40%);">+        case HNB_PRIM_SAPI_IUH:</span><br><span style="color: hsl(120, 100%, 40%);">+               return llsk_rx_iuh(hnb, oph);</span><br><span style="color: hsl(120, 100%, 40%);">+ case HNB_PRIM_SAPI_GTP:</span><br><span style="color: hsl(120, 100%, 40%);">+       case HNB_PRIM_SAPI_AUDIO:</span><br><span style="color: hsl(120, 100%, 40%);">+             LOGP(DLLSK, LOGL_ERROR, "Rx SAPI %u not yet implemented (len=%u)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                     oph->sap, msgb_length(oph->msg));</span><br><span style="color: hsl(120, 100%, 40%);">+          return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+       default:</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DLLSK, LOGL_ERROR, "Rx for unknwon SAPI %u (len=%u)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                     oph->sap, msgb_length(oph->msg));</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int hnb_llsk_alloc(struct hnb *hnb)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        hnb->llsk_link = osmo_prim_srv_link_alloc(hnb);</span><br><span style="color: hsl(120, 100%, 40%);">+    osmo_prim_srv_link_set_priv(hnb->llsk_link, hnb);</span><br><span style="color: hsl(120, 100%, 40%);">+  osmo_prim_srv_link_set_log_category(hnb->llsk_link, DLLSK);</span><br><span style="color: hsl(120, 100%, 40%);">+        osmo_prim_srv_link_set_addr(hnb->llsk_link, HNB_PRIM_UD_SOCK_DEFAULT);</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_prim_srv_link_set_opened_conn_cb(hnb->llsk_link, llsk_opened_cb);</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_prim_srv_link_set_closed_conn_cb(hnb->llsk_link, llsk_closed_cb);</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_prim_srv_link_set_rx_sapi_version_cb(hnb->llsk_link, llsk_rx_sapi_version_cb);</span><br><span style="color: hsl(120, 100%, 40%);">+        osmo_prim_srv_link_set_rx_cb(hnb->llsk_link, llsk_rx_cb);</span><br><span style="color: hsl(120, 100%, 40%);">+  osmo_timer_setup(&hnb->llsk_defer_configure_ind_timer, llsk_defer_configure_ind_timer_cb, hnb);</span><br><span style="color: hsl(120, 100%, 40%);">+        return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/osmo-hnodeb/llsk_iuh.c b/src/osmo-hnodeb/llsk_iuh.c</span><br><span>new file mode 100644</span><br><span>index 0000000..00c399a</span><br><span>--- /dev/null</span><br><span>+++ b/src/osmo-hnodeb/llsk_iuh.c</span><br><span>@@ -0,0 +1,347 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ * Author: Pau Espin Pedrol <pespin@sysmocom.de></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%);">+ * 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 Affero General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 3 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 Affero General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU Affero General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+ * along with this program.  If not, see <http://www.gnu.org/lienses/>.</span><br><span 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%);">+#include <stdio.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <unistd.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdlib.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <string.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <assert.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <sys/socket.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <sys/un.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/talloc.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/select.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/socket.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/rua/rua_msg_factory.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hnodeb/hnodeb.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hnodeb/llsk.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hnodeb/hnb_prim.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hnodeb/iuh.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hnodeb/ranap.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static size_t llsk_iuh_prim_size_tbl[4][_HNB_IUH_PRIM_MAX] = {</span><br><span style="color: hsl(120, 100%, 40%);">+  [PRIM_OP_REQUEST] = {</span><br><span style="color: hsl(120, 100%, 40%);">+         [HNB_IUH_PRIM_CONN_ESTABLISH] = sizeof(struct hnb_iuh_conn_establish_req_param),</span><br><span style="color: hsl(120, 100%, 40%);">+              [HNB_IUH_PRIM_CONN_RELEASE] = sizeof(struct hnb_iuh_conn_release_req_param),</span><br><span style="color: hsl(120, 100%, 40%);">+          [HNB_IUH_PRIM_CONN_DATA] = sizeof(struct hnb_iuh_conn_data_req_param),</span><br><span style="color: hsl(120, 100%, 40%);">+                [HNB_IUH_PRIM_UNITDATA] = sizeof(struct hnb_iuh_unitdata_req_param),</span><br><span style="color: hsl(120, 100%, 40%);">+  },</span><br><span style="color: hsl(120, 100%, 40%);">+    [PRIM_OP_RESPONSE] = {},</span><br><span style="color: hsl(120, 100%, 40%);">+      [PRIM_OP_INDICATION] = {</span><br><span style="color: hsl(120, 100%, 40%);">+              [HNB_IUH_PRIM_CONFIGURE] = sizeof(struct hnb_iuh_configure_ind_param),</span><br><span style="color: hsl(120, 100%, 40%);">+                [HNB_IUH_PRIM_CONN_DATA] = sizeof(struct hnb_iuh_conn_data_ind_param),</span><br><span style="color: hsl(120, 100%, 40%);">+                [HNB_IUH_PRIM_UNITDATA] = sizeof(struct hnb_iuh_unitdata_ind_param),</span><br><span style="color: hsl(120, 100%, 40%);">+  },</span><br><span style="color: hsl(120, 100%, 40%);">+    [PRIM_OP_CONFIRM] = {</span><br><span style="color: hsl(120, 100%, 40%);">+         [HNB_IUH_PRIM_CONN_ESTABLISH] = sizeof(struct hnb_iuh_conn_establish_cnf_param),</span><br><span 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 size_t llsk_iuh_prim_size(enum hnb_iuh_prim_type ptype, enum osmo_prim_operation op)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ size_t val = llsk_iuh_prim_size_tbl[op][ptype];</span><br><span style="color: hsl(120, 100%, 40%);">+       if (val == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+               LOGP(DLLSK, LOGL_FATAL, "Expected prim_size != 0 for ptype=%u op=%u\n", ptype, op);</span><br><span style="color: hsl(120, 100%, 40%);">+         osmo_panic("Expected prim_size != 0 for ptype=%u op=%u\n", ptype, op);</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+     return val;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+const struct value_string hnb_iuh_prim_type_names[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_VALUE_STRING(HNB_IUH_PRIM_CONFIGURE),</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_VALUE_STRING(HNB_IUH_PRIM_CONN_ESTABLISH),</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_VALUE_STRING(HNB_IUH_PRIM_CONN_RELEASE),</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_VALUE_STRING(HNB_IUH_PRIM_CONN_DATA),</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_iuh_prim *hnb_iuh_prim_alloc(enum hnb_iuh_prim_type ptype, enum osmo_prim_operation op, size_t extra_len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct osmo_prim_hdr *oph;</span><br><span style="color: hsl(120, 100%, 40%);">+    size_t len = llsk_iuh_prim_size(ptype, op);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ oph = osmo_prim_msgb_alloc(HNB_PRIM_SAPI_IUH, ptype, op, sizeof(*oph) + len + extra_len);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!oph)</span><br><span style="color: hsl(120, 100%, 40%);">+             return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  msgb_put(oph->msg, len);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return (struct hnb_iuh_prim *)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%);">+struct hnb_iuh_prim *hnb_iuh_makeprim_configure_ind(uint16_t mcc, uint16_t mnc,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                 uint16_t cell_identity,</span><br><span style="color: hsl(120, 100%, 40%);">+                                               uint16_t lac, uint8_t rac,</span><br><span style="color: hsl(120, 100%, 40%);">+                                            uint16_t sac, uint16_t rnc_id)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct hnb_iuh_prim *iuh_prim;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      iuh_prim = hnb_iuh_prim_alloc(HNB_IUH_PRIM_CONFIGURE, PRIM_OP_INDICATION, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ iuh_prim->u.configure_ind.mcc = mcc;</span><br><span style="color: hsl(120, 100%, 40%);">+       iuh_prim->u.configure_ind.mnc = mnc;</span><br><span style="color: hsl(120, 100%, 40%);">+       iuh_prim->u.configure_ind.cell_identity = cell_identity;</span><br><span style="color: hsl(120, 100%, 40%);">+   iuh_prim->u.configure_ind.lac = lac;</span><br><span style="color: hsl(120, 100%, 40%);">+       iuh_prim->u.configure_ind.rac = rac;</span><br><span style="color: hsl(120, 100%, 40%);">+       iuh_prim->u.configure_ind.sac = sac;</span><br><span style="color: hsl(120, 100%, 40%);">+       iuh_prim->u.configure_ind.rnc_id = rnc_id;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       return iuh_prim;</span><br><span 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 llsk_iuh_tx_configure_ind(struct hnb *hnb)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct hnb_iuh_prim *iuh_prim;</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%);">+     LOGP(DLLSK, LOGL_INFO, "Tx IUH-CONFIGURE.ind\n");</span><br><span style="color: hsl(120, 100%, 40%);">+   /* We are already registered, so configure the lower layers right now */</span><br><span style="color: hsl(120, 100%, 40%);">+      iuh_prim = hnb_iuh_makeprim_configure_ind(hnb->plmn.mcc, hnb->plmn.mnc,</span><br><span style="color: hsl(120, 100%, 40%);">+                                           hnb->cell_identity, hnb->lac,</span><br><span style="color: hsl(120, 100%, 40%);">+                                           hnb->rac, hnb->sac, hnb->rnc_id);</span><br><span style="color: hsl(120, 100%, 40%);">+  if ((rc = osmo_prim_srv_send(hnb->llsk, iuh_prim->hdr.msg)) < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+             LOGP(DLLSK, LOGL_ERROR, "Failed sending IUH-CONFIGURE.ind\n");</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 hnb_iuh_prim *hnb_iuh_makeprim_conn_establish_cnf(uint32_t context_id, uint8_t domain,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                 uint8_t cause)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct hnb_iuh_prim *iuh_prim;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      iuh_prim = hnb_iuh_prim_alloc(HNB_IUH_PRIM_CONN_ESTABLISH, PRIM_OP_CONFIRM, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+       iuh_prim->u.conn_establish_cnf.context_id = context_id;</span><br><span style="color: hsl(120, 100%, 40%);">+    iuh_prim->u.conn_establish_cnf.domain = domain;</span><br><span style="color: hsl(120, 100%, 40%);">+    iuh_prim->u.conn_establish_cnf.cause = cause;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    return iuh_prim;</span><br><span 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 hnb_iuh_prim *hnb_iuh_makeprim_conn_data_ind(uint32_t context_id,</span><br><span style="color: hsl(120, 100%, 40%);">+                                           uint8_t domain,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       const uint8_t *data,</span><br><span style="color: hsl(120, 100%, 40%);">+                                          uint32_t data_len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct hnb_iuh_prim *iuh_prim;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      iuh_prim = hnb_iuh_prim_alloc(HNB_IUH_PRIM_CONN_DATA, PRIM_OP_INDICATION, data_len);</span><br><span style="color: hsl(120, 100%, 40%);">+  iuh_prim->u.conn_data_ind.context_id = context_id;</span><br><span style="color: hsl(120, 100%, 40%);">+ iuh_prim->u.conn_data_ind.domain = domain;</span><br><span style="color: hsl(120, 100%, 40%);">+ iuh_prim->u.conn_data_ind.data_len = data_len;</span><br><span style="color: hsl(120, 100%, 40%);">+     if (data_len) {</span><br><span style="color: hsl(120, 100%, 40%);">+               msgb_put(iuh_prim->hdr.msg, data_len);</span><br><span style="color: hsl(120, 100%, 40%);">+             memcpy(iuh_prim->u.conn_data_ind.data, data, data_len);</span><br><span 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 iuh_prim;</span><br><span 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 hnb_iuh_prim *hnb_iuh_makeprim_unitdata_ind(const uint8_t *data, uint32_t data_len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct hnb_iuh_prim *iuh_prim;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      iuh_prim = hnb_iuh_prim_alloc(HNB_IUH_PRIM_UNITDATA, PRIM_OP_INDICATION, data_len);</span><br><span style="color: hsl(120, 100%, 40%);">+   iuh_prim->u.unitdata_ind.data_len = data_len;</span><br><span style="color: hsl(120, 100%, 40%);">+      if (data_len) {</span><br><span style="color: hsl(120, 100%, 40%);">+               msgb_put(iuh_prim->hdr.msg, data_len);</span><br><span style="color: hsl(120, 100%, 40%);">+             memcpy(iuh_prim->u.unitdata_ind.data, data, data_len);</span><br><span 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 iuh_prim;</span><br><span 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 llsk_rx_iuh_conn_establish_req(struct hnb *hnb, struct hnb_iuh_conn_establish_req_param *ce_req)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct hnb_ue *ue;</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%);">+ LOGP(DLLSK, LOGL_INFO, "Rx IUH-CONN_ESTABLISH.req ctx=%u is_ps=%u est_cause=%u data_len=%u\n",</span><br><span style="color: hsl(120, 100%, 40%);">+           ce_req->context_id, ce_req->domain, ce_req->est_cause, ce_req->data_len);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!hnb->registered) {</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGP(DLLSK, LOGL_NOTICE, "Ignoring Rx IUH-CONN_ESTABLISH.req: HNB not registered to HNBGW!\n");</span><br><span style="color: hsl(120, 100%, 40%);">+             /* TODO: NACK it to lower layers */</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%);">+   ue = hnb_find_ue_by_id(hnb, ce_req->context_id);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!ue) {</span><br><span style="color: hsl(120, 100%, 40%);">+            ue = hnb_ue_alloc(hnb, ce_req->context_id);</span><br><span style="color: hsl(120, 100%, 40%);">+                if (ce_req->domain) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      ue->conn_ps.active = true;</span><br><span style="color: hsl(120, 100%, 40%);">+                 ue->conn_ps.conn_est_cnf_pending = true; /* Set to false once we receive first DT from HNBGW and send CONN_EST.cnf */</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%);">+                      ue->conn_cs.active = true;</span><br><span style="color: hsl(120, 100%, 40%);">+                 ue->conn_cs.conn_est_cnf_pending = true; /* Set to false once we receive first DT from HNBGW and send CONN_EST.cnf */</span><br><span 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 (ce_req->data_len) {</span><br><span style="color: hsl(120, 100%, 40%);">+            struct msgb *rua_msg;</span><br><span style="color: hsl(120, 100%, 40%);">+         struct msgb *ranap_msg = hnb_ranap_msgb_alloc();</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DRUA, LOGL_DEBUG, "Tx RUA CONNECT ctx=%u is_ps=%u data_len=%u\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                   ce_req->context_id, ce_req->domain, ce_req->data_len);</span><br><span style="color: hsl(120, 100%, 40%);">+          memcpy(msgb_put(ranap_msg, ce_req->data_len), ce_req->data, ce_req->data_len);</span><br><span style="color: hsl(120, 100%, 40%);">+               rua_msg = rua_new_conn(ce_req->domain, ce_req->context_id, ranap_msg);</span><br><span style="color: hsl(120, 100%, 40%);">+          hnb_iuh_send(hnb, rua_msg);</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   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%);">+static int llsk_rx_iuh_conn_release_req(struct hnb *hnb, struct hnb_iuh_conn_release_req_param *rel_req)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct hnb_ue *ue;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct msgb *rua_msg;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct msgb *ranap_msg;</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%);">+ LOGP(DLLSK, LOGL_DEBUG, "Rx IUH-CONN_RELEASE.req ctx=%u is_ps=%u data_len=%u\n",</span><br><span style="color: hsl(120, 100%, 40%);">+         rel_req->context_id, rel_req->domain, rel_req->data_len);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!hnb->registered) {</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGP(DLLSK, LOGL_NOTICE, "Rx IUH-CONN_RELEASE.req: Ignoring, HNB not registered to HNBGW!\n");</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%);">+   ue = hnb_find_ue_by_id(hnb, rel_req->context_id);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!ue) {</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGP(DLLSK, LOGL_ERROR, "Rx IUH-CONN_RELEASE.req: conn unknown! ctx=%u is_ps=%u data_len=%u\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                  rel_req->context_id, rel_req->domain, rel_req->data_len);</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%);">+     hnb_ue_reset_chan(ue, !!rel_req->domain);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!ue->conn_cs.active && !ue->conn_ps.active) {</span><br><span style="color: hsl(120, 100%, 40%);">+               hnb_ue_free(ue);</span><br><span style="color: hsl(120, 100%, 40%);">+              ue = 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%);">+   LOGP(DRUA, LOGL_DEBUG, "Tx RUA DISC ctx=%u is_ps=%u data_len=%u\n",</span><br><span style="color: hsl(120, 100%, 40%);">+      rel_req->context_id, rel_req->domain, rel_req->data_len);</span><br><span style="color: hsl(120, 100%, 40%);">+       ranap_msg = hnb_ranap_msgb_alloc();</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rel_req->data_len)</span><br><span style="color: hsl(120, 100%, 40%);">+             memcpy(msgb_put(ranap_msg, rel_req->data_len), rel_req->data, rel_req->data_len);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  rua_msg = rua_new_disc(rel_req->domain, rel_req->context_id, ranap_msg);</span><br><span style="color: hsl(120, 100%, 40%);">+        hnb_iuh_send(hnb, rua_msg);</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%);">+static int llsk_rx_iuh_conn_data_req(struct hnb *hnb, struct hnb_iuh_conn_data_req_param *data_req)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct hnb_ue *ue;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct msgb *rua_msg;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct msgb *ranap_msg;</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%);">+ LOGP(DLLSK, LOGL_DEBUG, "Rx IUH-CONN_DATA.req ctx=%u is_ps=%u data_len=%u\n",</span><br><span style="color: hsl(120, 100%, 40%);">+            data_req->context_id, data_req->domain, data_req->data_len);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!hnb->registered) {</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGP(DLLSK, LOGL_NOTICE, "Rx IUH-CONN_DATA.req: Ignoring, HNB not registered to HNBGW!\n");</span><br><span style="color: hsl(120, 100%, 40%);">+         /* TODO: NACK it to lower layers */</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%);">+   ue = hnb_find_ue_by_id(hnb, data_req->context_id);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ue) {</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGP(DLLSK, LOGL_ERROR, "Rx IUH-CONN_DATA.req: conn unknown! ctx=%u is_ps=%u data_len=%u\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                     data_req->context_id, data_req->domain, data_req->data_len);</span><br><span style="color: hsl(120, 100%, 40%);">+            /* TODO: NACK it to lower layers */</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%);">+   LOGP(DRUA, LOGL_DEBUG, "Tx RUA DT ctx=%u is_ps=%u data_len=%u\n",</span><br><span style="color: hsl(120, 100%, 40%);">+        data_req->context_id, data_req->domain, data_req->data_len);</span><br><span style="color: hsl(120, 100%, 40%);">+    ranap_msg = hnb_ranap_msgb_alloc();</span><br><span style="color: hsl(120, 100%, 40%);">+   if (data_req->data_len)</span><br><span style="color: hsl(120, 100%, 40%);">+            memcpy(msgb_put(ranap_msg, data_req->data_len), data_req->data, data_req->data_len);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       rua_msg = rua_new_dt(data_req->domain, data_req->context_id, ranap_msg);</span><br><span style="color: hsl(120, 100%, 40%);">+        hnb_iuh_send(hnb, rua_msg);</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%);">+static int llsk_rx_iuh_unitdata_req(struct hnb *hnb, struct hnb_iuh_unitdata_req_param *ud_req)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct msgb *rua_msg;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct msgb *ranap_msg;</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%);">+ LOGP(DLLSK, LOGL_DEBUG, "Rx IUH-UNITDATA.req data_len=%u\n", ud_req->data_len);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!hnb->registered) {</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGP(DLLSK, LOGL_NOTICE, "Rx IUH-UNITDATA.req: Ignoring, HNB not registered to HNBGW!\n");</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%);">+   LOGP(DRUA, LOGL_DEBUG, "Tx RUA UDT data_len=%u\n", ud_req->data_len);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  ranap_msg = hnb_ranap_msgb_alloc();</span><br><span style="color: hsl(120, 100%, 40%);">+   if (ud_req->data_len)</span><br><span style="color: hsl(120, 100%, 40%);">+              memcpy(msgb_put(ranap_msg, ud_req->data_len), ud_req->data, ud_req->data_len);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     rua_msg = rua_new_udt(ranap_msg);</span><br><span style="color: hsl(120, 100%, 40%);">+     hnb_iuh_send(hnb, rua_msg);</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%);">+int llsk_rx_iuh(struct hnb *hnb, struct osmo_prim_hdr *oph)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       size_t prim_size = llsk_iuh_prim_size(oph->primitive, oph->operation);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (msgb_length(oph->msg) < prim_size) {</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGP(DLLSK, LOGL_ERROR, "Rx IUH-%s.%s with length %u < %zu\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                get_value_string(hnb_iuh_prim_type_names, oph->primitive),</span><br><span style="color: hsl(120, 100%, 40%);">+                 get_value_string(osmo_prim_op_names, oph->operation),</span><br><span style="color: hsl(120, 100%, 40%);">+                 msgb_length(oph->msg), prim_size);</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%);">+   switch (oph->operation) {</span><br><span style="color: hsl(120, 100%, 40%);">+  case PRIM_OP_REQUEST:</span><br><span style="color: hsl(120, 100%, 40%);">+         switch (oph->primitive) {</span><br><span style="color: hsl(120, 100%, 40%);">+          case HNB_IUH_PRIM_CONN_ESTABLISH:</span><br><span style="color: hsl(120, 100%, 40%);">+                     return llsk_rx_iuh_conn_establish_req(hnb, (struct hnb_iuh_conn_establish_req_param *)msgb_data(oph->msg));</span><br><span style="color: hsl(120, 100%, 40%);">+                case HNB_IUH_PRIM_CONN_RELEASE:</span><br><span style="color: hsl(120, 100%, 40%);">+                       return llsk_rx_iuh_conn_release_req(hnb, (struct hnb_iuh_conn_release_req_param *)msgb_data(oph->msg));</span><br><span style="color: hsl(120, 100%, 40%);">+            case HNB_IUH_PRIM_CONN_DATA:</span><br><span style="color: hsl(120, 100%, 40%);">+                  return llsk_rx_iuh_conn_data_req(hnb, (struct hnb_iuh_conn_data_req_param *)msgb_data(oph->msg));</span><br><span style="color: hsl(120, 100%, 40%);">+          case HNB_IUH_PRIM_UNITDATA:</span><br><span style="color: hsl(120, 100%, 40%);">+                   return llsk_rx_iuh_unitdata_req(hnb, (struct hnb_iuh_unitdata_req_param *)msgb_data(oph->msg));</span><br><span style="color: hsl(120, 100%, 40%);">+            default:</span><br><span style="color: hsl(120, 100%, 40%);">+                      LOGP(DLLSK, LOGL_ERROR, "Rx llsk-iuh unknown primitive %u (len=%u)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                           oph->primitive, msgb_length(oph->msg));</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%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      case PRIM_OP_RESPONSE:</span><br><span style="color: hsl(120, 100%, 40%);">+        case PRIM_OP_INDICATION:</span><br><span style="color: hsl(120, 100%, 40%);">+      case PRIM_OP_CONFIRM:</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DLLSK, LOGL_ERROR, "Rx llsk-iuh unexpected primitive operation %s::%s (len=%u)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                  get_value_string(hnb_iuh_prim_type_names, oph->primitive),</span><br><span style="color: hsl(120, 100%, 40%);">+                 get_value_string(osmo_prim_op_names, oph->operation),</span><br><span style="color: hsl(120, 100%, 40%);">+              msgb_length(oph->msg));</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>diff --git a/src/osmo-hnodeb/main.c b/src/osmo-hnodeb/main.c</span><br><span>index 12d98ff..6728a07 100644</span><br><span>--- a/src/osmo-hnodeb/main.c</span><br><span>+++ b/src/osmo-hnodeb/main.c</span><br><span>@@ -265,6 +265,13 @@</span><br><span>             exit(1);</span><br><span>     }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* Start listening on lower layer unix domain socket: */</span><br><span style="color: hsl(120, 100%, 40%);">+      rc = osmo_prim_srv_link_open(g_hnb->llsk_link);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              perror("Error opening lower layer socket");</span><br><span style="color: hsl(120, 100%, 40%);">+         exit(1);</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  rc = hnb_iuh_connect(g_hnb);</span><br><span>         if (rc < 0) {</span><br><span>             perror("Error connecting to Iuh port");</span><br><span>diff --git a/src/osmo-hnodeb/ranap.c b/src/osmo-hnodeb/ranap.c</span><br><span>index 99c4bab..3313f7b 100644</span><br><span>--- a/src/osmo-hnodeb/ranap.c</span><br><span>+++ b/src/osmo-hnodeb/ranap.c</span><br><span>@@ -27,3 +27,8 @@</span><br><span> </span><br><span> #include <osmocom/hnodeb/rua.h></span><br><span> #include <osmocom/hnodeb/ranap.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb *hnb_ranap_msgb_alloc(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  return msgb_alloc(1000, "ranap_tx");</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/osmo-hnodeb/rua.c b/src/osmo-hnodeb/rua.c</span><br><span>index 9bf5403..3a73f0c 100644</span><br><span>--- a/src/osmo-hnodeb/rua.c</span><br><span>+++ b/src/osmo-hnodeb/rua.c</span><br><span>@@ -32,10 +32,23 @@</span><br><span> #include <osmocom/hnodeb/iuh.h></span><br><span> #include <osmocom/hnodeb/hnodeb.h></span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb *hnb_rua_msgb_alloc(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ return msgb_alloc(1000, "rua_tx");</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static void hnb_rua_dt_handle(struct hnb *hnb, ANY_t *in)</span><br><span> {</span><br><span>  RUA_DirectTransferIEs_t ies;</span><br><span>         int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct hnb_ue *ue;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct hnb_iuh_prim *iuh_prim;</span><br><span style="color: hsl(120, 100%, 40%);">+        uint32_t context_id;</span><br><span style="color: hsl(120, 100%, 40%);">+  bool is_ps;</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t *ranap_buf;</span><br><span style="color: hsl(120, 100%, 40%);">+   size_t ranap_buf_len;</span><br><span style="color: hsl(120, 100%, 40%);">+ bool *conn_est_cnf_pending;</span><br><span> </span><br><span>      rc = rua_decode_directtransferies(&ies, in);</span><br><span>     if (rc < 0) {</span><br><span>@@ -43,7 +56,44 @@</span><br><span>                return;</span><br><span>      }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ context_id = asn1bitstr_to_u24(&ies.context_ID);</span><br><span style="color: hsl(120, 100%, 40%);">+  is_ps = (ies.cN_DomainIndicator == RUA_CN_DomainIndicator_ps_domain);</span><br><span style="color: hsl(120, 100%, 40%);">+ ranap_buf = ies.ranaP_Message.buf;</span><br><span style="color: hsl(120, 100%, 40%);">+    ranap_buf_len = ies.ranaP_Message.size;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+   LOGP(DRUA, LOGL_DEBUG, "Rx RUA DT context_id=%u is_ps=%u ranap_len=%zu\n",</span><br><span style="color: hsl(120, 100%, 40%);">+       context_id, is_ps, ranap_buf_len);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!(ue = hnb_find_ue_by_id(hnb, context_id))) {</span><br><span style="color: hsl(120, 100%, 40%);">+             LOGP(DRUA, LOGL_ERROR, "Rx RUA DT: Failed finding ue context_id=%u is_ps=%u\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                  context_id, is_ps);</span><br><span style="color: hsl(120, 100%, 40%);">+              goto free_ret;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   conn_est_cnf_pending = is_ps ? &ue->conn_ps.conn_est_cnf_pending :</span><br><span style="color: hsl(120, 100%, 40%);">+                                    &ue->conn_cs.conn_est_cnf_pending;</span><br><span style="color: hsl(120, 100%, 40%);">+      if (*conn_est_cnf_pending) {</span><br><span style="color: hsl(120, 100%, 40%);">+          *conn_est_cnf_pending = false;</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGP(DLLSK, LOGL_INFO, "Tx IUH-CONN_ESTABLISH.cnf context_id=%u is_ps=%u\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                     context_id, is_ps);</span><br><span style="color: hsl(120, 100%, 40%);">+              iuh_prim = hnb_iuh_makeprim_conn_establish_cnf(context_id, is_ps, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+         if ((rc = osmo_prim_srv_send(hnb->llsk, iuh_prim->hdr.msg)) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   LOGP(DRUA, LOGL_ERROR, "Failed sending IUH-CONN_ESTABLISH.cnf context_id=%u is_ps=%u\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                         context_id, is_ps);</span><br><span style="color: hsl(120, 100%, 40%);">+                      goto free_ret;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   LOGP(DLLSK, LOGL_DEBUG, "Tx IUH-CONN_DATA.ind context_id=%u is_ps=%u ranap_len=%zu\n",</span><br><span style="color: hsl(120, 100%, 40%);">+           context_id, is_ps, ranap_buf_len);</span><br><span style="color: hsl(120, 100%, 40%);">+       iuh_prim = hnb_iuh_makeprim_conn_data_ind(context_id, is_ps, ranap_buf, ranap_buf_len);</span><br><span style="color: hsl(120, 100%, 40%);">+       if ((rc = osmo_prim_srv_send(hnb->llsk, iuh_prim->hdr.msg)) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGP(DRUA, LOGL_ERROR, "Failed sending IUH-CONN_DATA.ind context_id=%u is_ps=%u ranap_len=%zu\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                context_id, is_ps, ranap_buf_len);</span><br><span style="color: hsl(120, 100%, 40%);">+               goto free_ret;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+free_ret:</span><br><span>       /* FIXME: what to do with the asn1c-allocated memory */</span><br><span>      rua_free_directtransferies(&ies);</span><br><span> }</span><br><span>@@ -52,18 +102,81 @@</span><br><span> {</span><br><span>       RUA_ConnectionlessTransferIEs_t ies;</span><br><span>         int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct hnb_iuh_prim *iuh_prim;</span><br><span style="color: hsl(120, 100%, 40%);">+        uint8_t *ranap_buf;</span><br><span style="color: hsl(120, 100%, 40%);">+   size_t ranap_buf_len;</span><br><span> </span><br><span>    rc = rua_decode_connectionlesstransferies(&ies, in);</span><br><span>     if (rc < 0) {</span><br><span>             LOGP(DRUA, LOGL_INFO, "failed to decode RUA CL IEs\n");</span><br><span>            return;</span><br><span>      }</span><br><span style="color: hsl(120, 100%, 40%);">+     ranap_buf = ies.ranaP_Message.buf;</span><br><span style="color: hsl(120, 100%, 40%);">+    ranap_buf_len = ies.ranaP_Message.size;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+   LOGP(DRUA, LOGL_DEBUG, "Rx RUA UDT ranap_len=%zu\n", ranap_buf_len);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+    LOGP(DLLSK, LOGL_DEBUG, "Tx IUH-UNITDATA.ind ranap_len=%zu\n", ranap_buf_len);</span><br><span style="color: hsl(120, 100%, 40%);">+      iuh_prim = hnb_iuh_makeprim_unitdata_ind(ranap_buf, ranap_buf_len);</span><br><span style="color: hsl(120, 100%, 40%);">+   if ((rc = osmo_prim_srv_send(hnb->llsk, iuh_prim->hdr.msg)) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGP(DRUA, LOGL_ERROR, "Failed sending IUH-CONN_DATA.ind ranap_len=%zu\n",</span><br><span style="color: hsl(120, 100%, 40%);">+               ranap_buf_len);</span><br><span style="color: hsl(120, 100%, 40%);">+          goto free_ret;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+free_ret:</span><br><span>       /* FIXME: what to do with the asn1c-allocated memory */</span><br><span>      rua_free_connectionlesstransferies(&ies);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int hnb_rua_rx_initiating(struct hnb *hnb, RUA_InitiatingMessage_t *init)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (init->procedureCode) {</span><br><span style="color: hsl(120, 100%, 40%);">+     case RUA_ProcedureCode_id_ConnectionlessTransfer:</span><br><span style="color: hsl(120, 100%, 40%);">+             LOGP(DRUA, LOGL_INFO, "RUA rx Initiating ConnectionlessTransfer\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                hnb_rua_cl_handle(hnb, &init->value);</span><br><span style="color: hsl(120, 100%, 40%);">+          break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case RUA_ProcedureCode_id_DirectTransfer:</span><br><span style="color: hsl(120, 100%, 40%);">+             LOGP(DRUA, LOGL_INFO, "RUA rx Initiating DirectTransfer\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                hnb_rua_dt_handle(hnb, &init->value);</span><br><span style="color: hsl(120, 100%, 40%);">+  default:</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DRUA, LOGL_INFO, "RUA rx unknown Initiating message\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%);">+     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%);">+static int hnb_rua_rx_successful(struct hnb *hnb, RUA_SuccessfulOutcome_t *success)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        switch (success->procedureCode) {</span><br><span style="color: hsl(120, 100%, 40%);">+  case RUA_ProcedureCode_id_ConnectionlessTransfer:</span><br><span style="color: hsl(120, 100%, 40%);">+             LOGP(DRUA, LOGL_INFO, "RUA rx SuccessfulOutcome ConnectionlessTransfer\n");</span><br><span style="color: hsl(120, 100%, 40%);">+         hnb_rua_cl_handle(hnb, &success->value);</span><br><span style="color: hsl(120, 100%, 40%);">+               break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case RUA_ProcedureCode_id_Connect:</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGP(DRUA, LOGL_INFO, "RUA rx SuccessfulOutcome Connect\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case RUA_ProcedureCode_id_DirectTransfer:</span><br><span style="color: hsl(120, 100%, 40%);">+             LOGP(DRUA, LOGL_INFO, "RUA rx SuccessfulOutcome DirectTransfer\n");</span><br><span style="color: hsl(120, 100%, 40%);">+         hnb_rua_dt_handle(hnb, &success->value);</span><br><span style="color: hsl(120, 100%, 40%);">+               break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case RUA_ProcedureCode_id_Disconnect:</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGP(DRUA, LOGL_INFO, "RUA rx SuccessfulOutcome Disconnect\n");</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case RUA_ProcedureCode_id_ErrorIndication:</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGP(DRUA, LOGL_INFO, "RUA rx SuccessfulOutcome ErrorIndication\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case RUA_ProcedureCode_id_privateMessage:</span><br><span style="color: hsl(120, 100%, 40%);">+             LOGP(DRUA, LOGL_INFO, "RUA rx SuccessfulOutcome privateMessage\n");</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%);">+              LOGP(DRUA, LOGL_INFO, "RUA rx unknown SuccessfulOutcome message\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%);">+     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> int hnb_rua_rx(struct hnb *hnb, struct msgb *msg)</span><br><span> {</span><br><span>     RUA_RUA_PDU_t _pdu, *pdu = &_pdu;</span><br><span>@@ -79,11 +192,9 @@</span><br><span> </span><br><span>      switch (pdu->present) {</span><br><span>   case RUA_RUA_PDU_PR_successfulOutcome:</span><br><span style="color: hsl(0, 100%, 40%);">-          LOGP(DRUA, LOGL_INFO, "RUA_RUA_PDU_PR_successfulOutcome\n");</span><br><span style="color: hsl(0, 100%, 40%);">-          break;</span><br><span style="color: hsl(120, 100%, 40%);">+                return hnb_rua_rx_successful(hnb, &pdu->choice.successfulOutcome);</span><br><span>    case RUA_RUA_PDU_PR_initiatingMessage:</span><br><span style="color: hsl(0, 100%, 40%);">-          LOGP(DRUA, LOGL_INFO, "RUA_RUA_PDU_PR_initiatingMessage\n");</span><br><span style="color: hsl(0, 100%, 40%);">-          break;</span><br><span style="color: hsl(120, 100%, 40%);">+                return hnb_rua_rx_initiating(hnb, &pdu->choice.initiatingMessage);</span><br><span>    case RUA_RUA_PDU_PR_NOTHING:</span><br><span>                 LOGP(DRUA, LOGL_INFO, "RUA_RUA_PDU_PR_NOTHING\n");</span><br><span>                 break;</span><br><span>@@ -95,31 +206,5 @@</span><br><span>                 break;</span><br><span>       }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   switch (pdu->choice.successfulOutcome.procedureCode) {</span><br><span style="color: hsl(0, 100%, 40%);">-       case RUA_ProcedureCode_id_ConnectionlessTransfer:</span><br><span style="color: hsl(0, 100%, 40%);">-               LOGP(DRUA, LOGL_INFO, "RUA rx Connectionless Transfer\n");</span><br><span style="color: hsl(0, 100%, 40%);">-            hnb_rua_cl_handle(hnb, &pdu->choice.successfulOutcome.value);</span><br><span style="color: hsl(0, 100%, 40%);">-            break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case RUA_ProcedureCode_id_Connect:</span><br><span style="color: hsl(0, 100%, 40%);">-              LOGP(DRUA, LOGL_INFO, "RUA rx Connect\n");</span><br><span style="color: hsl(0, 100%, 40%);">-            break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case RUA_ProcedureCode_id_DirectTransfer:</span><br><span style="color: hsl(0, 100%, 40%);">-               LOGP(DRUA, LOGL_INFO, "RUA rx DirectTransfer\n");</span><br><span style="color: hsl(0, 100%, 40%);">-             hnb_rua_dt_handle(hnb, &pdu->choice.successfulOutcome.value);</span><br><span style="color: hsl(0, 100%, 40%);">-            break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case RUA_ProcedureCode_id_Disconnect:</span><br><span style="color: hsl(0, 100%, 40%);">-           LOGP(DRUA, LOGL_INFO, "RUA rx Disconnect\n");</span><br><span style="color: hsl(0, 100%, 40%);">-         break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case RUA_ProcedureCode_id_ErrorIndication:</span><br><span style="color: hsl(0, 100%, 40%);">-              LOGP(DRUA, LOGL_INFO, "RUA rx ErrorIndication\n");</span><br><span style="color: hsl(0, 100%, 40%);">-            break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case RUA_ProcedureCode_id_privateMessage:</span><br><span style="color: hsl(0, 100%, 40%);">-               LOGP(DRUA, LOGL_INFO, "RUA rx privateMessage\n");</span><br><span style="color: hsl(0, 100%, 40%);">-             break;</span><br><span style="color: hsl(0, 100%, 40%);">-  default:</span><br><span style="color: hsl(0, 100%, 40%);">-                LOGP(DRUA, LOGL_INFO, "RUA rx unknown message\n");</span><br><span style="color: hsl(0, 100%, 40%);">-            break;</span><br><span style="color: hsl(0, 100%, 40%);">-  }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>    return 0;</span><br><span> }</span><br><span>diff --git a/src/osmo-hnodeb/vty.c b/src/osmo-hnodeb/vty.c</span><br><span>index 93ec25f..131dc6b 100644</span><br><span>--- a/src/osmo-hnodeb/vty.c</span><br><span>+++ b/src/osmo-hnodeb/vty.c</span><br><span>@@ -47,6 +47,10 @@</span><br><span>                 vty->node = HNODEB_NODE;</span><br><span>          vty->index = g_hnb;</span><br><span>               break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case LLSK_NODE:</span><br><span style="color: hsl(120, 100%, 40%);">+               vty->node = HNODEB_NODE;</span><br><span style="color: hsl(120, 100%, 40%);">+           vty->index = g_hnb;</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span>       case HNODEB_NODE:</span><br><span>            vty->node = CONFIG_NODE;</span><br><span>          vty->index = g_hnb;</span><br><span>@@ -247,6 +251,36 @@</span><br><span>        return CMD_SUCCESS;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static struct cmd_node llsk_node = {</span><br><span style="color: hsl(120, 100%, 40%);">+    LLSK_NODE,</span><br><span style="color: hsl(120, 100%, 40%);">+    "%s(config-ll-socket)# ",</span><br><span style="color: hsl(120, 100%, 40%);">+   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%);">+#define LLSK_STR "Configure the Lower Layer Unix Domain Socket\n"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_hnodeb_llsk,</span><br><span style="color: hsl(120, 100%, 40%);">+      cfg_hnodeb_llsk_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      "ll-socket", LLSK_STR)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(g_hnb);</span><br><span style="color: hsl(120, 100%, 40%);">+   vty->index = g_hnb;</span><br><span style="color: hsl(120, 100%, 40%);">+        vty->node = LLSK_NODE;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_hnodeb_llsk_path, cfg_hnodeb_llsk_path_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      "path PATH",</span><br><span style="color: hsl(120, 100%, 40%);">+      "Configure the Lower Layer Unix Domain Socket path\n"</span><br><span style="color: hsl(120, 100%, 40%);">+      "UNIX socket path\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        osmo_prim_srv_link_set_addr(g_hnb->llsk_link, argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* FIXME: re-open the interface? */</span><br><span style="color: hsl(120, 100%, 40%);">+   return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> </span><br><span> static int config_write_hnodeb(struct vty *vty)</span><br><span> {</span><br><span>@@ -266,10 +300,11 @@</span><br><span>                 vty_out(vty, "  local-port %u%s", g_hnb->iuh.local_port, VTY_NEWLINE);</span><br><span>  vty_out(vty, "  remote-ip %s%s", g_hnb->iuh.remote_addr, VTY_NEWLINE);</span><br><span>  vty_out(vty, "  remote-port %u%s", g_hnb->iuh.remote_port, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+ vty_out(vty, " ll-socket%s", VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+  vty_out(vty, "  path %s%s", osmo_prim_srv_link_get_addr(g_hnb->llsk_link), VTY_NEWLINE);</span><br><span>        return CMD_SUCCESS;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> #define RANAP_STR       "RANAP related commands\n"</span><br><span> #define CSPS_STR        "Circuit Switched\n" "Packet Switched\n"</span><br><span> </span><br><span>@@ -321,6 +356,9 @@</span><br><span>       install_element(IUH_NODE, &cfg_hnodeb_iuh_local_port_cmd);</span><br><span>       install_element(IUH_NODE, &cfg_hnodeb_iuh_remote_ip_cmd);</span><br><span>        install_element(IUH_NODE, &cfg_hnodeb_iuh_remote_port_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+       install_element(HNODEB_NODE, &cfg_hnodeb_llsk_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+       install_node(&llsk_node, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+   install_element(LLSK_NODE, &cfg_hnodeb_llsk_path_cmd);</span><br><span> </span><br><span>       install_element_ve(&asn_dbg_cmd);</span><br><span>        install_element_ve(&ranap_reset_cmd);</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-hnodeb/+/26357">change 26357</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/osmo-hnodeb/+/26357"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-hnodeb </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: Icaabb2206d6f141d4fba47dedf71f8ec37e6257d </div>
<div style="display:none"> Gerrit-Change-Number: 26357 </div>
<div style="display:none"> Gerrit-PatchSet: 13 </div>
<div style="display:none"> Gerrit-Owner: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder </div>
<div style="display:none"> Gerrit-Reviewer: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-Reviewer: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>