<p>pespin has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/osmo-hnodeb/+/26357">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">WIP<br><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/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_ctl.c<br>A src/osmo-hnodeb/llsk_iuh.c<br>M src/osmo-hnodeb/main.c<br>M src/osmo-hnodeb/vty.c<br>16 files changed, 1,041 insertions(+), 2 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/osmo-hnodeb refs/changes/57/26357/1</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..a5f7a86</span><br><span>--- /dev/null</span><br><span>+++ b/doc/hnodeb.msc</span><br><span>@@ -0,0 +1,62 @@</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%);">+     trx <= hnodeb [label="REQ(SAPI_IUH, HNB_IUH_PRIM_CONFIGURE)(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 Sign Up" ];</span><br><span style="color: hsl(120, 100%, 40%);">+      ue => trx [label="..."];</span><br><span style="color: hsl(120, 100%, 40%);">+ trx => hnodeb [label="IND(SAPI_IUH, CONN_ESTABLISH)[RANAP?]"];</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%);">+     trx <= hnodeb [label="CNF(SAPI_IUH, CONN_ESTABLISH)(context_id])"];</span><br><span style="color: hsl(120, 100%, 40%);">+      trx => hnodeb [label="IND(SAPI_IUH, CONN_DATA)[RANAP GMM ServiceRequest]"];</span><br><span style="color: hsl(120, 100%, 40%);">+      hnodeb => hnbgw [label="RANAP GMM ServiceRequest"];</span><br><span style="color: hsl(120, 100%, 40%);">+      hnodeb <= hnbgw [label="RANAP GMM ServiceAccept"];</span><br><span style="color: hsl(120, 100%, 40%);">+       trx <= hnodeb [label="REQ(SAPI_IUH, CONN_DATA)[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="REQ(SAPI_IUH, CONN_DATA)[RANAP RAB-Assignment Request(remote_ip, remote_port, remote_tei)]"];</span><br><span style="color: hsl(120, 100%, 40%);">+      trx => hnodeb [label="IND(SAPI_GTP, CONN_ESTABLISH)(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="CNF(SAPI_GTP, CONN_ESTABLISH)(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%);">+  ---  [ 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="IND(SAPI_GTP, CONN_DATA)[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="REQ(SAPI_GTP, CONN_DATA)[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="IND(SAPI_IUH, CONN_DATA)[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="REQ(SAPI_IUH, CONN_DATA)[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="IND(SAPI_GTP, CONN_RELEASE)(remote_tei)"];</span><br><span style="color: hsl(120, 100%, 40%);">+ trx <= hnodeb [label="CNF(SAPI_GTP, CONN_RELEASE)(remote_tei)"];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       trx => hnodeb [label="IND(SAPI_IUH, CONN_RELEASE)[RANAP IU Release Complete]"];</span><br><span style="color: hsl(120, 100%, 40%);">+  hnodeb => hnbgw [label="RANAP IU Release Complete"];</span><br><span style="color: hsl(120, 100%, 40%);">+     trx => hnodeb [label="CNF(SAPI_GTP, CONN_RELEASE)"];</span><br><span 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>diff --git a/include/osmocom/hnodeb/Makefile.am b/include/osmocom/hnodeb/Makefile.am</span><br><span>index b1acb7e..56d1033 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>     nas.h \</span><br><span>      ranap.h \</span><br><span>    rua.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..8cede29</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/hnodeb/hnb_prim.h</span><br><span>@@ -0,0 +1,271 @@</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 <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_CTL 0</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%);">+struct hnb_prim_hdr {</span><br><span style="color: hsl(120, 100%, 40%);">+  uint32_t sap;    /*!< Service Access Point Identifier */</span><br><span style="color: hsl(120, 100%, 40%);">+   uint32_t primitive;    /*!< Primitive number */</span><br><span style="color: hsl(120, 100%, 40%);">+    uint32_t operation; /*! Primitive Operation */</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%);">+/*! \brief HNB_CTL primitives */</span><br><span style="color: hsl(120, 100%, 40%);">+enum hnb_ctl_prim_type {</span><br><span style="color: hsl(120, 100%, 40%);">+     HNB_CTL_PRIM_HELLO,</span><br><span style="color: hsl(120, 100%, 40%);">+   _HNB_CTL_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_CTL_PRIM_HELLO, UL */</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_ctl_hello_ind_param {</span><br><span style="color: hsl(120, 100%, 40%);">+       uint16_t api_version; /* see HNB_PRIM_API_VERSION */</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_CTL_PRIM_HELLO, DL */</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_ctl_hello_cnf_param {</span><br><span style="color: hsl(120, 100%, 40%);">+   uint16_t api_version; /* see HNB_PRIM_API_VERSION */</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_ctl_prim {</span><br><span style="color: hsl(120, 100%, 40%);">+    struct hnb_prim_hdr hdr;</span><br><span style="color: hsl(120, 100%, 40%);">+      union {</span><br><span style="color: hsl(120, 100%, 40%);">+               struct hnb_ctl_hello_ind_param hello_ind;</span><br><span style="color: hsl(120, 100%, 40%);">+             struct hnb_ctl_hello_cnf_param hello_cnf;</span><br><span style="color: hsl(120, 100%, 40%);">+     } u;</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%);">+</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, DL */</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_iuh_configure_req_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_IUH_PRIM_CONN_ESTABLISH, DL */</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 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%);">+        char 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_ESTABLISH, UL */</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%);">+        /* 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 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%);">+        char 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, 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 cause;</span><br><span style="color: hsl(120, 100%, 40%);">+        uint16_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%);">+        char 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, 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 cause;</span><br><span style="color: hsl(120, 100%, 40%);">+        uint16_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%);">+        char 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, 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%);">+        char 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, 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%);">+        char 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, DL */</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_iuh_unitdata_req_param {</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%);">+        char 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, UL */</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_iuh_unitdata_ind_param {</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%);">+        char 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 hnb_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_req_param configure_req;</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_release_req_param conn_reelase_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 style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_iuh_prim *hnb_iuh_makeprim_conn_establish_req(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 *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_conn_release_req(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 *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_conn_data_req(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 *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_req(uint8_t domain,</span><br><span style="color: hsl(120, 100%, 40%);">+                                              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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief HNB_GTP primitives */</span><br><span style="color: hsl(120, 100%, 40%);">+enum hnb_gtp_prim_type {</span><br><span style="color: hsl(120, 100%, 40%);">+        HNB_GTP_PRIM_CONN_ESTABLISH,</span><br><span style="color: hsl(120, 100%, 40%);">+  HNB_GTP_PRIM_CONN_RELEASE,</span><br><span style="color: hsl(120, 100%, 40%);">+    HNB_GTP_PRIM_CONN_DATA</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+union u_addr {</span><br><span style="color: hsl(120, 100%, 40%);">+    struct in_addr v4;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct in6_addr v6;</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_GTP_PRIM_CONN_ESTABLISH, UL */</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_gtp_conn_establish_ind_param {</span><br><span style="color: hsl(120, 100%, 40%);">+  uint32_t remote_tei;</span><br><span style="color: hsl(120, 100%, 40%);">+  uint16_t remote_gtpu_port;</span><br><span style="color: hsl(120, 100%, 40%);">+    uint8_t remote_gtpu_address_type;</span><br><span style="color: hsl(120, 100%, 40%);">+     uint8_t spare1;</span><br><span style="color: hsl(120, 100%, 40%);">+       union u_addr remote_gtpu_addr;</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_GTP_PRIM_CONN_ESTABLISH, DL */</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_gtp_conn_establish_cnf_param {</span><br><span style="color: hsl(120, 100%, 40%);">+       uint32_t remote_tei;</span><br><span style="color: hsl(120, 100%, 40%);">+  uint32_t local_tei;</span><br><span style="color: hsl(120, 100%, 40%);">+   uint16_t local_gtpu_port;</span><br><span style="color: hsl(120, 100%, 40%);">+     uint8_t local_gtpu_address_type;</span><br><span style="color: hsl(120, 100%, 40%);">+      uint8_t spare1;</span><br><span style="color: hsl(120, 100%, 40%);">+       union u_addr remote_gtpu_addr;</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_GTP_PRIM_CONN_RELEASE, UL */</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_gtp_conn_release_ind_param {</span><br><span style="color: hsl(120, 100%, 40%);">+   uint32_t remote_tei;</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_GTP_PRIM_CONN_RELEASE, DL */</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_gtp_conn_release_cnf_param {</span><br><span style="color: hsl(120, 100%, 40%);">+     uint32_t remote_tei;</span><br><span style="color: hsl(120, 100%, 40%);">+} __attribute__ ((packed));</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_gtp_conn_release_req_param {</span><br><span style="color: hsl(120, 100%, 40%);">+    uint32_t remote_tei;</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_GTP_PRIM_CONN_DATA, DL */</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_gtp_conn_data_req_param {</span><br><span style="color: hsl(120, 100%, 40%);">+   uint32_t local_tei;</span><br><span style="color: hsl(120, 100%, 40%);">+   uint32_t data_len; /* GTP-U payload length in bytes */</span><br><span style="color: hsl(120, 100%, 40%);">+        char data[0]; /* GTP-U payload (aka IP packet) */</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_GTP_PRIM_CONN_DATA, UL */</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_gtp_conn_data_ind_param {</span><br><span style="color: hsl(120, 100%, 40%);">+      uint32_t remote_tei;</span><br><span style="color: hsl(120, 100%, 40%);">+  uint32_t data_len; /* GTP-U payload length in bytes */</span><br><span style="color: hsl(120, 100%, 40%);">+        char data[0]; /* GTP-U payload (aka IP packet) */</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_gtp_prim {</span><br><span style="color: hsl(120, 100%, 40%);">+       struct hnb_prim_hdr hdr;</span><br><span style="color: hsl(120, 100%, 40%);">+      union {</span><br><span style="color: hsl(120, 100%, 40%);">+               struct hnb_gtp_conn_establish_ind_param conn_establish_ind;</span><br><span style="color: hsl(120, 100%, 40%);">+           struct hnb_gtp_conn_establish_cnf_param conn_establish_cnf;</span><br><span style="color: hsl(120, 100%, 40%);">+           struct hnb_gtp_conn_data_req_param conn_data_req;</span><br><span style="color: hsl(120, 100%, 40%);">+             struct hnb_gtp_conn_data_ind_param conn_data_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 3bc2fb3..186798b 100644</span><br><span>--- a/include/osmocom/hnodeb/hnodeb.h</span><br><span>+++ b/include/osmocom/hnodeb/hnodeb.h</span><br><span>@@ -28,12 +28,15 @@</span><br><span> #include <osmocom/gsm/gsm23003.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>       DNAS,</span><br><span> };</span><br><span> extern const struct log_info hnb_log_info;</span><br><span>@@ -59,7 +62,14 @@</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 {</span><br><span style="color: hsl(120, 100%, 40%);">+              char *sock_path;</span><br><span style="color: hsl(120, 100%, 40%);">+              struct llsk_state *state;</span><br><span style="color: hsl(120, 100%, 40%);">+     } llsk;</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>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..a08c006</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/hnodeb/llsk.h</span><br><span>@@ -0,0 +1,56 @@</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/select.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/linuxlist.h></span><br><span style="color: hsl(120, 100%, 40%);">+</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%);">+struct msgb;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct llsk_state {</span><br><span style="color: hsl(120, 100%, 40%);">+   struct hnb *hnb;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_fd listen_bfd;      /* fd for listen socket */</span><br><span style="color: hsl(120, 100%, 40%);">+    struct osmo_fd conn_bfd;        /* fd for connection to lcr */</span><br><span style="color: hsl(120, 100%, 40%);">+        struct llist_head upqueue;      /* queue for sending messages */</span><br><span 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 llsk_state *llsk_alloc(struct hnb *hnb);</span><br><span style="color: hsl(120, 100%, 40%);">+int llsk_open(struct llsk_state *state, const char *path);</span><br><span style="color: hsl(120, 100%, 40%);">+void llsk_free(struct llsk_state *state);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int llsk_send(struct llsk_state *state, struct msgb *msg);</span><br><span style="color: hsl(120, 100%, 40%);">+bool llsk_connected(const struct llsk_state *state);</span><br><span 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_ctl_prim_type_names[];</span><br><span style="color: hsl(120, 100%, 40%);">+int llsk_rx_ctl(struct hnb *hnb, struct hnb_ctl_prim *ctl, unsigned 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%);">+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 hnb_iuh_prim *iuh, unsigned len);</span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb *hnb_iuh_makeprim_configure_req(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>diff --git a/include/osmocom/hnodeb/vty.h b/include/osmocom/hnodeb/vty.h</span><br><span>index 7144d3f..1624bfb 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>   CHAN_NODE,</span><br><span> };</span><br><span> </span><br><span>diff --git a/src/osmo-hnodeb/Makefile.am b/src/osmo-hnodeb/Makefile.am</span><br><span>index 7325728..0117f28 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,9 @@</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_ctl.c \</span><br><span style="color: hsl(120, 100%, 40%);">+  llsk_iuh.c \</span><br><span>         nas.c \</span><br><span>      ranap.c \</span><br><span>    rua.c \</span><br><span>diff --git a/src/osmo-hnodeb/debug.c b/src/osmo-hnodeb/debug.c</span><br><span>index 10d1655..e610ff0 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>   [DNAS] = {</span><br><span>           .name = "NAS", .loglevel = LOGL_NOTICE, .enabled = 1,</span><br><span>              .color = "\033[1;32m",</span><br><span>diff --git a/src/osmo-hnodeb/hnb.c b/src/osmo-hnodeb/hnb.c</span><br><span>index b7be4ea..d7cf886 100644</span><br><span>--- a/src/osmo-hnodeb/hnb.c</span><br><span>+++ b/src/osmo-hnodeb/hnb.c</span><br><span>@@ -27,6 +27,7 @@</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>@@ -43,6 +44,9 @@</span><br><span>            .mnc = 1,</span><br><span>    };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+        hnb->llsk.sock_path = talloc_strdup(hnb, HNB_PRIM_UD_SOCK_DEFAULT);</span><br><span style="color: hsl(120, 100%, 40%);">+        hnb->llsk.state = llsk_alloc(hnb);</span><br><span style="color: hsl(120, 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>@@ -58,5 +62,9 @@</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%);">+  llsk_free(hnb->llsk.state);</span><br><span style="color: hsl(120, 100%, 40%);">+        hnb->llsk.state = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         talloc_free(hnb);</span><br><span> }</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 7df591e..14e8b32 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 0495ce0..4ea1342 100644</span><br><span>--- a/src/osmo-hnodeb/hnbap.c</span><br><span>+++ b/src/osmo-hnodeb/hnbap.c</span><br><span>@@ -39,16 +39,31 @@</span><br><span> {</span><br><span>       int rc;</span><br><span>      HNBAP_HNBRegisterAcceptIEs_t accept;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct msgb *llsk_msg;</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 (llsk_connected(hnb->llsk.state)) {</span><br><span style="color: hsl(120, 100%, 40%);">+             /* We are attached to the HNBGW, configure lower layers: */</span><br><span style="color: hsl(120, 100%, 40%);">+           llsk_msg = hnb_iuh_makeprim_configure_req(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%);">+          rc = llsk_send(hnb->llsk.state, llsk_msg);</span><br><span style="color: hsl(120, 100%, 40%);">+         if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      LOGP(DHNBAP, LOGL_NOTICE, "Failed configuring lower layers after HnbRegisterAccept\n");</span><br><span 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> }</span><br><span> </span><br><span> static int hnb_rx_hnb_register_rej(struct hnb *hnb, ANY_t *in)</span><br><span>@@ -56,6 +71,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..dee7477</span><br><span>--- /dev/null</span><br><span>+++ b/src/osmo-hnodeb/llsk.c</span><br><span>@@ -0,0 +1,306 @@</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/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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void llsk_close(struct llsk_state *state);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct llsk_state *llsk_alloc(struct hnb *hnb)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct llsk_state *state;</span><br><span style="color: hsl(120, 100%, 40%);">+     state = talloc_zero(NULL, struct llsk_state);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!state)</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%);">+        INIT_LLIST_HEAD(&state->upqueue);</span><br><span style="color: hsl(120, 100%, 40%);">+      state->hnb = hnb;</span><br><span style="color: hsl(120, 100%, 40%);">+  state->conn_bfd.fd = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+   state->listen_bfd.fd = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ return state;</span><br><span 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 llsk_free(struct llsk_state *state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct osmo_fd *bfd, *conn_bfd;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!state)</span><br><span style="color: hsl(120, 100%, 40%);">+           return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     conn_bfd = &state->conn_bfd;</span><br><span style="color: hsl(120, 100%, 40%);">+   if (conn_bfd->fd > 0)</span><br><span style="color: hsl(120, 100%, 40%);">+           llsk_close(state);</span><br><span style="color: hsl(120, 100%, 40%);">+    bfd = &state->listen_bfd;</span><br><span style="color: hsl(120, 100%, 40%);">+      close(bfd->fd);</span><br><span style="color: hsl(120, 100%, 40%);">+    osmo_fd_unregister(bfd);</span><br><span style="color: hsl(120, 100%, 40%);">+      talloc_free(state);</span><br><span 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(struct hnb *hnb, struct hnb_prim_hdr *hdr, unsigned len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      switch (hdr->sap) {</span><br><span style="color: hsl(120, 100%, 40%);">+        case HNB_PRIM_SAPI_CTL:</span><br><span style="color: hsl(120, 100%, 40%);">+               return llsk_rx_ctl(hnb, ((struct hnb_ctl_prim *)hdr), len);</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, ((struct hnb_iuh_prim *)hdr), len);</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", hdr->sap, len);</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", hdr->sap, 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%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int llsk_read(struct osmo_fd *bfd)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct llsk_state *state = (struct llsk_state *)bfd->data;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct hnb_prim_hdr *hdr;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+     int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     msg = msgb_alloc(1000, "llsk_rx");</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!msg)</span><br><span style="color: hsl(120, 100%, 40%);">+             return -ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     hdr = (struct hnb_prim_hdr *) msg->tail;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = recv(bfd->fd, msg->tail, msgb_tailroom(msg), 0);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rc == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+          goto close;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (errno == EAGAIN) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+                       return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+             goto close;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rc < sizeof(struct hnb_prim_hdr)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGP(DLLSK, LOGL_ERROR, "Received %d bytes on PCU Socket, but primitive hdr size "</span><br><span style="color: hsl(120, 100%, 40%);">+               "is %zu, discarding\n", rc, sizeof(struct hnb_prim_hdr));</span><br><span style="color: hsl(120, 100%, 40%);">+              msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+               return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   rc = llsk_rx(state->hnb, hdr, rc);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* as we always synchronously process the message in llsk_rx() and</span><br><span style="color: hsl(120, 100%, 40%);">+     * its callbacks, we can free the message here. */</span><br><span style="color: hsl(120, 100%, 40%);">+    msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+close:</span><br><span style="color: hsl(120, 100%, 40%);">+  msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+       llsk_close(state);</span><br><span style="color: hsl(120, 100%, 40%);">+    return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int llsk_write(struct osmo_fd *bfd)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct llsk_state *state = bfd->data;</span><br><span style="color: hsl(120, 100%, 40%);">+      int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     while (!llist_empty(&state->upqueue)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                struct msgb *msg, *msg2;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            /* peek at the beginning of the queue */</span><br><span style="color: hsl(120, 100%, 40%);">+              msg = llist_entry(state->upqueue.next, struct msgb, list);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               osmo_fd_write_disable(bfd);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         if (!msgb_length(msg)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      LOGP(DLLSK, LOGL_ERROR, "message with ZERO "</span><br><span style="color: hsl(120, 100%, 40%);">+                                "bytes!\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                        goto dontsend;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           /* try to send it over the socket */</span><br><span style="color: hsl(120, 100%, 40%);">+          rc = write(bfd->fd, msgb_data(msg), msgb_length(msg));</span><br><span style="color: hsl(120, 100%, 40%);">+             if (rc == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                  goto close;</span><br><span style="color: hsl(120, 100%, 40%);">+           if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      if (errno == EAGAIN) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                osmo_fd_write_enable(bfd);</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%);">+                     goto close;</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+dontsend:</span><br><span style="color: hsl(120, 100%, 40%);">+                /* _after_ we send it, we can deueue */</span><br><span style="color: hsl(120, 100%, 40%);">+               msg2 = msgb_dequeue(&state->upqueue);</span><br><span style="color: hsl(120, 100%, 40%);">+          assert(msg == msg2);</span><br><span style="color: hsl(120, 100%, 40%);">+          msgb_free(msg);</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%);">+close:</span><br><span style="color: hsl(120, 100%, 40%);">+   llsk_close(state);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int llsk_bfd_cb(struct osmo_fd *bfd, unsigned int flags)</span><br><span style="color: hsl(120, 100%, 40%);">+{</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%);">+ if (flags & OSMO_FD_READ)</span><br><span style="color: hsl(120, 100%, 40%);">+         rc = llsk_read(bfd);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (flags & OSMO_FD_WRITE)</span><br><span style="color: hsl(120, 100%, 40%);">+                rc = llsk_write(bfd);</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%);">+/* accept connection coming from PCU */</span><br><span style="color: hsl(120, 100%, 40%);">+static int llsk_accept(struct osmo_fd *bfd, unsigned int flags)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct llsk_state *state = (struct llsk_state *)bfd->data;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_fd *conn_bfd = &state->conn_bfd;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct sockaddr_un un_addr;</span><br><span style="color: hsl(120, 100%, 40%);">+   socklen_t len;</span><br><span style="color: hsl(120, 100%, 40%);">+        int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     len = sizeof(un_addr);</span><br><span style="color: hsl(120, 100%, 40%);">+        rc = accept(bfd->fd, (struct sockaddr *) &un_addr, &len);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DLLSK, LOGL_ERROR, "Failed to accept a new connection\n");</span><br><span style="color: hsl(120, 100%, 40%);">+             return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (conn_bfd->fd >= 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGP(DLLSK, LOGL_NOTICE, "LL UD Socket connects but we already have "</span><br><span style="color: hsl(120, 100%, 40%);">+                    "another active connection ?!?\n");</span><br><span style="color: hsl(120, 100%, 40%);">+            /* We already have one LLSK connected, this is all we support */</span><br><span style="color: hsl(120, 100%, 40%);">+              state->listen_bfd.when &= ~OSMO_FD_READ;</span><br><span style="color: hsl(120, 100%, 40%);">+               close(rc);</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%);">+   osmo_fd_setup(conn_bfd, rc, OSMO_FD_READ, llsk_bfd_cb, state, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (osmo_fd_register(conn_bfd) != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGP(DLLSK, LOGL_ERROR, "Failed to register new connection fd\n");</span><br><span style="color: hsl(120, 100%, 40%);">+          close(conn_bfd->fd);</span><br><span style="color: hsl(120, 100%, 40%);">+               conn_bfd->fd = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+         return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   LOGP(DLLSK, LOGL_NOTICE, "LL UD socket connected\n");</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%);">+int llsk_open(struct llsk_state *state, const char *path)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct osmo_fd *bfd = &state->listen_bfd;</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%);">+     rc = osmo_sock_unix_init(SOCK_SEQPACKET, 0, path, OSMO_SOCK_F_BIND);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DLLSK, LOGL_ERROR, "Could not create %s unix socket: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                 path, strerror(errno));</span><br><span style="color: hsl(120, 100%, 40%);">+          return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   osmo_fd_setup(bfd, rc, OSMO_FD_READ, llsk_accept, state, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        rc = osmo_fd_register(bfd);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DLLSK, LOGL_ERROR, "Could not register listen fd: %d\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                       rc);</span><br><span style="color: hsl(120, 100%, 40%);">+          close(bfd->fd);</span><br><span style="color: hsl(120, 100%, 40%);">+            bfd->fd = -1;</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%);">+   LOGP(DLLSK, LOGL_INFO, "Started listening on Lower Layer Unix Domain Socket: %s\n", path);</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 void llsk_close(struct llsk_state *state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct osmo_fd *bfd = &state->conn_bfd;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      close(bfd->fd);</span><br><span style="color: hsl(120, 100%, 40%);">+    bfd->fd = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+      osmo_fd_unregister(bfd);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* re-enable the generation of ACCEPT for new connections */</span><br><span style="color: hsl(120, 100%, 40%);">+  osmo_fd_read_enable(&state->listen_bfd);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* flush the queue */</span><br><span style="color: hsl(120, 100%, 40%);">+ while (!llist_empty(&state->upqueue)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                struct msgb *msg = msgb_dequeue(&state->upqueue);</span><br><span style="color: hsl(120, 100%, 40%);">+              msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int llsk_send(struct llsk_state *state, struct msgb *msg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct osmo_fd *conn_bfd;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!state) {</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGP(DLLSK, LOGL_INFO, "LL UD socket not created, dropping message\n");</span><br><span style="color: hsl(120, 100%, 40%);">+             msgb_free(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%);">+     conn_bfd = &state->conn_bfd;</span><br><span style="color: hsl(120, 100%, 40%);">+   if (conn_bfd->fd <= 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGP(DLLSK, LOGL_NOTICE, "LL UD socket not connected, dropping message\n");</span><br><span style="color: hsl(120, 100%, 40%);">+         msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+               return -EIO;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+     msgb_enqueue(&state->upqueue, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+    osmo_fd_write_enable(conn_bfd);</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%);">+bool llsk_connected(const struct llsk_state *state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!state)</span><br><span style="color: hsl(120, 100%, 40%);">+           return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (state->conn_bfd.fd <= 0)</span><br><span style="color: hsl(120, 100%, 40%);">+            return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ return true;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/osmo-hnodeb/llsk_ctl.c b/src/osmo-hnodeb/llsk_ctl.c</span><br><span>new file mode 100644</span><br><span>index 0000000..c6b0f55</span><br><span>--- /dev/null</span><br><span>+++ b/src/osmo-hnodeb/llsk_ctl.c</span><br><span>@@ -0,0 +1,144 @@</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/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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static size_t llsk_ctl_prim_size_tbl[4][_HNB_CTL_PRIM_MAX] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ [PRIM_OP_REQUEST] = {},</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_CTL_PRIM_HELLO] = sizeof(struct hnb_ctl_hello_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_CTL_PRIM_HELLO] = sizeof(struct hnb_ctl_hello_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_ctl_prim_size(enum hnb_ctl_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%);">+ return llsk_ctl_prim_size_tbl[op][ptype];</span><br><span 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_ctl_prim_type_names[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_VALUE_STRING(HNB_CTL_PRIM_HELLO),</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%);">+struct msgb *llsk_ctl_msgb_alloc(enum hnb_ctl_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%);">+     struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct hnb_ctl_prim *ctl_prim;</span><br><span style="color: hsl(120, 100%, 40%);">+        size_t len = sizeof(ctl_prim->hdr) + llsk_ctl_prim_size(ptype, op);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      msg = msgb_alloc(len, "llsk_ctl_tx");</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!msg)</span><br><span style="color: hsl(120, 100%, 40%);">+             return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  msgb_put(msg, len);</span><br><span style="color: hsl(120, 100%, 40%);">+   ctl_prim = (struct hnb_ctl_prim *) msg->data;</span><br><span style="color: hsl(120, 100%, 40%);">+      ctl_prim->hdr.sap = HNB_PRIM_SAPI_CTL;</span><br><span style="color: hsl(120, 100%, 40%);">+     ctl_prim->hdr.primitive = ptype;</span><br><span style="color: hsl(120, 100%, 40%);">+   ctl_prim->hdr.operation = op;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    return msg;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct msgb *hnb_ctl_makeprim_hello_cnf(uint16_t api_version)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct hnb_ctl_prim *ctl_prim;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      msg = llsk_ctl_msgb_alloc(HNB_CTL_PRIM_HELLO, PRIM_OP_CONFIRM);</span><br><span style="color: hsl(120, 100%, 40%);">+       ctl_prim = (struct hnb_ctl_prim *)msgb_data(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+     ctl_prim->u.hello_cnf.api_version = api_version;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return msg;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int llsk_rx_ctl_hello_ind(struct hnb *hnb, struct hnb_ctl_hello_ind_param *hello_ind)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct msgb *llsk_msg;</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_NOTICE, "Rx CTL::HELLO.ind API_VERSION=%u\n", hello_ind->api_version);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        LOGP(DLLSK, LOGL_NOTICE, "Tx CTL::HELLO.cnf API_VERSION=%u\n", hello_ind->api_version);</span><br><span style="color: hsl(120, 100%, 40%);">+  llsk_msg = hnb_ctl_makeprim_hello_cnf(HNB_CTL_PRIM_HELLO);</span><br><span style="color: hsl(120, 100%, 40%);">+    if ((rc = llsk_send(hnb->llsk.state, llsk_msg)) < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGP(DHNBAP, LOGL_ERROR, "Failed sending CTL::HELLO.cnf\n");</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_INFO, "Tx CTL::CONFIGURE.req API_VERSION=%u\n", hello_ind->api_version);</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%);">+              llsk_msg = hnb_iuh_makeprim_configure_req(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 = llsk_send(hnb->llsk.state, llsk_msg)) < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                    LOGP(DHNBAP, LOGL_ERROR, "Failed sending IUH::CONFIGURE.req\n");</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%);">+int llsk_rx_ctl(struct hnb *hnb, struct hnb_ctl_prim *ctl, unsigned len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  size_t prim_size = sizeof(ctl->hdr) + llsk_ctl_prim_size(ctl->hdr.primitive, ctl->hdr.operation);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (len < prim_size) {</span><br><span style="color: hsl(120, 100%, 40%);">+             LOGP(DLLSK, LOGL_ERROR, "Rx llsk-ctl %s::%s with length %u < %zu\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                  get_value_string(hnb_iuh_prim_type_names, ctl->hdr.primitive),</span><br><span style="color: hsl(120, 100%, 40%);">+                     get_value_string(osmo_prim_op_names, ctl->hdr.operation),</span><br><span style="color: hsl(120, 100%, 40%);">+                     len, 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 (ctl->hdr.operation) {</span><br><span style="color: hsl(120, 100%, 40%);">+      case PRIM_OP_INDICATION:</span><br><span style="color: hsl(120, 100%, 40%);">+              switch (ctl->hdr.primitive) {</span><br><span style="color: hsl(120, 100%, 40%);">+              case HNB_CTL_PRIM_HELLO:</span><br><span style="color: hsl(120, 100%, 40%);">+                      return llsk_rx_ctl_hello_ind(hnb, &ctl->u.hello_ind);</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-ctl unknown primitive %u (len=%u)\n", ctl->hdr.primitive, 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%);">+             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_REQUEST:</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-ctl 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, ctl->hdr.primitive),</span><br><span style="color: hsl(120, 100%, 40%);">+                     get_value_string(osmo_prim_op_names, ctl->hdr.operation), 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%);">+}</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..b5c13d7</span><br><span>--- /dev/null</span><br><span>+++ b/src/osmo-hnodeb/llsk_iuh.c</span><br><span>@@ -0,0 +1,103 @@</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/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%);">+</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_CONFIGURE] = sizeof(struct hnb_iuh_configure_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%);">+    [PRIM_OP_CONFIRM] = {},</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%);">+    return llsk_iuh_prim_size_tbl[op][ptype];</span><br><span 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%);">+    { 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 msgb *llsk_iuh_msgb_alloc(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%);">+   struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct hnb_iuh_prim *iuh_prim;</span><br><span style="color: hsl(120, 100%, 40%);">+        size_t len = sizeof(iuh_prim->hdr) + llsk_iuh_prim_size(ptype, op);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      msg = msgb_alloc(len, "llsk_iuh_tx");</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!msg)</span><br><span style="color: hsl(120, 100%, 40%);">+             return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  msgb_put(msg, len);</span><br><span style="color: hsl(120, 100%, 40%);">+   iuh_prim = (struct hnb_iuh_prim *) msg->data;</span><br><span style="color: hsl(120, 100%, 40%);">+      iuh_prim->hdr.sap = HNB_PRIM_SAPI_IUH;</span><br><span style="color: hsl(120, 100%, 40%);">+     iuh_prim->hdr.primitive = ptype;</span><br><span style="color: hsl(120, 100%, 40%);">+   iuh_prim->hdr.operation = op;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    return msg;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb *hnb_iuh_makeprim_configure_req(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 msgb *msg;</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%);">+      msg = llsk_iuh_msgb_alloc(HNB_IUH_PRIM_CONFIGURE, PRIM_OP_REQUEST);</span><br><span style="color: hsl(120, 100%, 40%);">+   iuh_prim = (struct hnb_iuh_prim *)msgb_data(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+     iuh_prim->u.configure_req.mcc = mcc;</span><br><span style="color: hsl(120, 100%, 40%);">+       iuh_prim->u.configure_req.mnc = mnc;</span><br><span style="color: hsl(120, 100%, 40%);">+       iuh_prim->u.configure_req.cell_identity = cell_identity;</span><br><span style="color: hsl(120, 100%, 40%);">+   iuh_prim->u.configure_req.lac = lac;</span><br><span style="color: hsl(120, 100%, 40%);">+       iuh_prim->u.configure_req.rac = rac;</span><br><span style="color: hsl(120, 100%, 40%);">+       iuh_prim->u.configure_req.sac = sac;</span><br><span style="color: hsl(120, 100%, 40%);">+       iuh_prim->u.configure_req.rnc_id = rnc_id;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       return msg;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int llsk_rx_iuh(struct hnb *hnb, struct hnb_iuh_prim *iuh, unsigned len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (iuh->hdr.primitive) {</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", iuh->hdr.primitive, 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%);">+}</span><br><span>diff --git a/src/osmo-hnodeb/main.c b/src/osmo-hnodeb/main.c</span><br><span>index 12d98ff..b8a883b 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 = llsk_open(g_hnb->llsk.state, g_hnb->llsk.sock_path);</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/vty.c b/src/osmo-hnodeb/vty.c</span><br><span>index e11fc2d..1331e59 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_talloc_replace_string(g_hnb, &g_hnb->llsk.sock_path, 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,6 +300,8 @@</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", g_hnb->llsk.sock_path, VTY_NEWLINE);</span><br><span>        return CMD_SUCCESS;</span><br><span> }</span><br><span> </span><br><span>@@ -387,6 +423,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(&hnb_register_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: 1 </div>
<div style="display:none"> Gerrit-Owner: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>