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