Change in osmo-hnodeb[master]: First implementation of the LLSK audio SAPI

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

pespin gerrit-no-reply at lists.osmocom.org
Fri Dec 10 15:06:34 UTC 2021


pespin has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-hnodeb/+/26502 )


Change subject: First implementation of the LLSK audio SAPI
......................................................................

First implementation of the LLSK audio SAPI

Change-Id: I9909a7c054ddaabb1bb63d7d06331cc79f642b5d
---
M configure.ac
M include/osmocom/hnodeb/Makefile.am
M include/osmocom/hnodeb/hnb_prim.h
M include/osmocom/hnodeb/hnodeb.h
M include/osmocom/hnodeb/llsk.h
A include/osmocom/hnodeb/rtp.h
M src/osmo-hnodeb/Makefile.am
M src/osmo-hnodeb/debug.c
M src/osmo-hnodeb/hnb.c
M src/osmo-hnodeb/llsk.c
A src/osmo-hnodeb/llsk_audio.c
M src/osmo-hnodeb/main.c
A src/osmo-hnodeb/rtp.c
13 files changed, 668 insertions(+), 4 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/osmo-hnodeb refs/changes/02/26502/1

diff --git a/configure.ac b/configure.ac
index 8453bc4..e96a6a1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -61,6 +61,7 @@
 PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.6.0)
 PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.6.0)
 PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.2.0)
+PKG_CHECK_MODULES(LIBOSMOTRAU, libosmotrau >= 1.2.0)
 PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.1.0)
 PKG_CHECK_MODULES(LIBOSMOSIGTRAN, libosmo-sigtran >= 1.5.0)
 PKG_CHECK_MODULES(LIBOSMORUA, libosmo-rua >= 0.8.0)
diff --git a/include/osmocom/hnodeb/Makefile.am b/include/osmocom/hnodeb/Makefile.am
index 62af5bb..dcb3868 100644
--- a/include/osmocom/hnodeb/Makefile.am
+++ b/include/osmocom/hnodeb/Makefile.am
@@ -6,6 +6,7 @@
 	iuh.h \
 	llsk.h \
 	ranap.h \
+	rtp.h \
 	rua.h \
 	vty.h \
 	$(NULL)
diff --git a/include/osmocom/hnodeb/hnb_prim.h b/include/osmocom/hnodeb/hnb_prim.h
index a456667..8f9466d 100644
--- a/include/osmocom/hnodeb/hnb_prim.h
+++ b/include/osmocom/hnodeb/hnb_prim.h
@@ -31,6 +31,16 @@
 #define HNB_PRIM_SAPI_GTP 2
 #define HNB_PRIM_SAPI_AUDIO 3
 
+enum u_addr_type {
+	HNB_PRIM_ADDR_TYPE_UNSPEC,
+	HNB_PRIM_ADDR_TYPE_IPV4,
+	HNB_PRIM_ADDR_TYPE_IPV6
+};
+union u_addr {
+	struct in_addr v4;
+	struct in6_addr v6;
+} __attribute__ ((packed));
+
 /*! \brief HNB_IUH primitives */
 enum hnb_iuh_prim_type {
 	HNB_IUH_PRIM_CONFIGURE,
@@ -154,3 +164,62 @@
 		struct hnb_iuh_unitdata_ind_param unitdata_ind;
 	} u;
 } __attribute__ ((packed));
+
+/****************************
+ * AUDIO
+ ***************************/
+/*! \brief HNB_AUDIO primitives */
+enum hnb_audio_prim_type {
+	HNB_AUDIO_PRIM_CONN_ESTABLISH,
+	HNB_AUDIO_PRIM_CONN_RELEASE,
+	HNB_AUDIO_PRIM_CONN_DATA,
+	_HNB_AUDIO_PRIM_MAX
+};
+
+/* HNB_AUDIO_PRIM_CONN_ESTABLISH, UL */
+struct hnb_audio_conn_establish_req_param {
+	uint32_t context_id;
+	uint16_t remote_rtp_port;
+	uint8_t spare1;
+	uint8_t remote_rtp_address_type;  /* enum u_addr_type */
+	union u_addr remote_rtp_addr;
+} __attribute__ ((packed));
+
+/* HNB_AUDIO_PRIM_CONN_ESTABLISH, DL */
+struct hnb_audio_conn_establish_cnf_param {
+	uint32_t context_id;
+	uint16_t local_rtp_port;
+	uint8_t error_code; /* 0 = success, !0 = failure */
+	uint8_t local_rtp_address_type; /* enum u_addr_type */
+	union u_addr local_rtp_addr;
+} __attribute__ ((packed));
+
+/* HNB_AUDIO_PRIM_CONN_RELEASE, UL */
+struct hnb_audio_conn_release_req_param {
+	uint32_t context_id;
+} __attribute__ ((packed));
+
+/* HNB_AUDIO_PRIM_CONN_DATA, UL */
+struct hnb_audio_conn_data_req_param {
+	uint32_t context_id;
+	uint32_t data_len; /* RTP payload length in bytes */
+	char data[0]; /* RTP payload (aka IP packet) */
+} __attribute__ ((packed));
+
+/* HNB_AUDIO_PRIM_CONN_DATA, DL */
+struct hnb_audio_conn_data_ind_param {
+	uint32_t context_id;
+	uint32_t data_len; /* RTP payload length in bytes */
+	char data[0]; /* RTP payload (aka IP packet) */
+} __attribute__ ((packed));
+
+struct hnb_audio_prim {
+	struct osmo_prim_hdr hdr;
+	union {
+		struct hnb_audio_conn_establish_req_param conn_establish_req;
+		struct hnb_audio_conn_establish_cnf_param conn_establish_cnf;
+		struct hnb_audio_conn_release_req_param conn_release_req;
+		struct hnb_audio_conn_data_req_param conn_data_req;
+		struct hnb_audio_conn_data_ind_param conn_data_ind;
+	} u;
+} __attribute__ ((packed));
diff --git a/include/osmocom/hnodeb/hnodeb.h b/include/osmocom/hnodeb/hnodeb.h
index fd7d1e9..f3bf655 100644
--- a/include/osmocom/hnodeb/hnodeb.h
+++ b/include/osmocom/hnodeb/hnodeb.h
@@ -21,11 +21,13 @@
 
 #include <stdint.h>
 #include <stdbool.h>
+#include <inttypes.h>
 
 #include <asn1c/asn1helpers.h>
 
 #include <osmocom/core/select.h>
 #include <osmocom/core/timer.h>
+#include <osmocom/core/socket.h>
 #include <osmocom/core/linuxlist.h>
 #include <osmocom/core/write_queue.h>
 #include <osmocom/core/logging.h>
@@ -42,6 +44,7 @@
 	DRANAP,
 	DSCTP,
 	DLLSK,
+	DRTP,
 };
 extern const struct log_info hnb_log_info;
 
@@ -55,6 +58,9 @@
 	struct hnb_ue_cs_ctx {
 		bool active; /* Is this chan in use? */
 		bool conn_est_cnf_pending; /* Did we send CONN_ESTABLISH_CNF to lower layers? */
+		struct {
+			struct osmo_rtp_socket *socket;
+		} rtp;
 	} conn_cs;
 	struct hnb_ue_ps_ctx {
 		bool active; /* Is this chan in use? */
@@ -64,6 +70,7 @@
 struct hnb_ue *hnb_ue_alloc(struct hnb *hnb, uint32_t conn_id);
 void hnb_ue_free(struct hnb_ue *ue);
 void hnb_ue_reset_chan(struct hnb_ue *ue, bool is_ps);
+int hnb_ue_voicecall_setup(struct hnb_ue *ue, const struct osmo_sockaddr *rem_addr, struct osmo_sockaddr *loc_addr);
 
 struct hnb {
 	char *identity; /* HNB-Identity */
@@ -86,6 +93,17 @@
 	uint8_t llsk_valid_sapi_mask;
 	struct osmo_timer_list llsk_defer_configure_ind_timer;
 
+	struct {
+		unsigned int jitter_buf_ms;
+		bool jitter_adaptive;
+
+		uint16_t port_range_start;
+		uint16_t port_range_end;
+		uint16_t port_range_next;
+		int ip_dscp;
+		int priority;
+	} rtp;
+
 	uint16_t rnc_id;
 	bool registered; /* Set to true once HnbRegisterAccept was received from Iuh. rnc_id is valid iif registered==true */
 
@@ -104,3 +122,5 @@
 
 extern void *tall_hnb_ctx;
 extern struct hnb *g_hnb;
+
+#define LOGUE(ue, ss, lvl, fmt, args...) LOGP(ss, lvl, "UE(%" PRIu32 ") " fmt, (ue)->conn_id, ## args)
diff --git a/include/osmocom/hnodeb/llsk.h b/include/osmocom/hnodeb/llsk.h
index ab39439..081ee88 100644
--- a/include/osmocom/hnodeb/llsk.h
+++ b/include/osmocom/hnodeb/llsk.h
@@ -22,6 +22,7 @@
 #include <stdint.h>
 
 #include <osmocom/core/utils.h>
+#include <osmocom/core/socket.h>
 #include <osmocom/netif/prim.h>
 #include <osmocom/hnodeb/hnb_prim.h>
 
@@ -31,6 +32,11 @@
 bool hnb_llsk_connected(const struct hnb *hnb);
 bool hnb_llsk_can_be_configured(struct hnb *hnb);
 
+int ll_addr_type2af(enum u_addr_type t);
+int ll_addr2osa(enum u_addr_type t, const union u_addr *uaddr, uint16_t port, struct osmo_sockaddr *osa);
+enum u_addr_type osa2_ll_addr(const struct osmo_sockaddr *osa, union u_addr *uaddr, uint16_t *port);
+
+
 
 extern const struct value_string hnb_iuh_prim_type_names[];
 int llsk_rx_iuh(struct hnb *hnb, struct osmo_prim_hdr *oph);
@@ -42,3 +48,11 @@
 						    const uint8_t *data,
 						    uint32_t data_len);
 struct hnb_iuh_prim *hnb_iuh_makeprim_unitdata_ind(const uint8_t *data, uint32_t data_len);
+
+
+extern const struct value_string hnb_audio_prim_type_names[];
+int llsk_rx_audio(struct hnb *hnb, struct osmo_prim_hdr *oph);
+struct hnb_audio_prim *hnb_audio_makeprim_conn_data_ind(uint32_t context_id,
+							uint8_t domain,
+							const uint8_t *data,
+							uint32_t data_len);
diff --git a/include/osmocom/hnodeb/rtp.h b/include/osmocom/hnodeb/rtp.h
new file mode 100644
index 0000000..a3714fd
--- /dev/null
+++ b/include/osmocom/hnodeb/rtp.h
@@ -0,0 +1,32 @@
+/* (C) 2021 by sysmocom - s.f.m.c. GmbH <info at sysmocom.de>
+ * Author: Pau Espin Pedrol <pespin at sysmocom.de>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/lienses/>.
+ *
+ */
+#pragma once
+
+#include <osmocom/core/socket.h>
+#include <osmocom/trau/osmo_ortp.h>
+
+struct hnb;
+
+int rtp_get_bound_addr(struct osmo_rtp_socket *rs, struct osmo_sockaddr *osa);
+
+int rtp_bind(struct hnb *hnb, struct osmo_rtp_socket *rs, const char *ip);
+
+void rtp_rx_cb(struct osmo_rtp_socket *rs, const uint8_t *rtp_pl,
+	       unsigned int rtp_pl_len, uint16_t seq_number,
+	       uint32_t timestamp, bool marker);
diff --git a/src/osmo-hnodeb/Makefile.am b/src/osmo-hnodeb/Makefile.am
index b6d2d49..4182814 100644
--- a/src/osmo-hnodeb/Makefile.am
+++ b/src/osmo-hnodeb/Makefile.am
@@ -14,6 +14,7 @@
 	$(LIBOSMONETIF_CFLAGS) \
 	$(COVERAGE_CFLAGS) \
 	$(LIBOSMOABIS_CFLAGS) \
+	$(LIBOSMOTRAU_CFLAGS) \
 	$(LIBOSMOSIGTRAN_CFLAGS) \
 	$(LIBOSMORUA_CFLAGS) \
 	$(LIBOSMORANAP_CFLAGS) \
@@ -36,8 +37,10 @@
 	hnb_shutdown_fsm.c \
 	iuh.c \
 	llsk.c \
+	llsk_audio.c \
 	llsk_iuh.c \
 	ranap.c \
+	rtp.c \
 	rua.c \
 	vty.c \
 	$(NULL)
@@ -51,6 +54,7 @@
 	$(LIBOSMONETIF_LIBS) \
 	$(COVERAGE_LDFLAGS) \
 	$(LIBOSMOABIS_LIBS) \
+	$(LIBOSMOTRAU_LIBS) \
 	$(LIBOSMOSIGTRAN_LIBS) \
 	$(LIBOSMORUA_LIBS) \
 	$(LIBOSMORANAP_LIBS) \
diff --git a/src/osmo-hnodeb/debug.c b/src/osmo-hnodeb/debug.c
index f34851b..5d0dabd 100644
--- a/src/osmo-hnodeb/debug.c
+++ b/src/osmo-hnodeb/debug.c
@@ -52,6 +52,11 @@
 		.color = "\033[1;31m",
 		.description = "Lower Layer Unix Domain Socket",
 	},
+	[DRTP] = {
+		.name = "DRTP", .loglevel = LOGL_NOTICE, .enabled = 1,
+		.color = "\033[1;32m",
+		.description = "RTP Core Network side",
+	},
 };
 
 const struct log_info hnb_log_info = {
diff --git a/src/osmo-hnodeb/hnb.c b/src/osmo-hnodeb/hnb.c
index 1ac2efc..f8878bd 100644
--- a/src/osmo-hnodeb/hnb.c
+++ b/src/osmo-hnodeb/hnb.c
@@ -20,6 +20,8 @@
 
 #include "config.h"
 
+#include <errno.h>
+
 #include <osmocom/core/socket.h>
 #include <osmocom/core/talloc.h>
 #include <osmocom/netif/stream.h>
@@ -29,6 +31,7 @@
 #include <osmocom/hnodeb/iuh.h>
 #include <osmocom/hnodeb/hnb_shutdown_fsm.h>
 #include <osmocom/hnodeb/hnb_prim.h>
+#include <osmocom/hnodeb/rtp.h>
 
 
 struct hnb *hnb_alloc(void *tall_ctx)
@@ -46,6 +49,14 @@
 		.mcc = 1,
 		.mnc = 1,
 	};
+
+	hnb->rtp.jitter_adaptive = false;
+	hnb->rtp.port_range_start = 16384;
+	hnb->rtp.port_range_end = 17407;
+	hnb->rtp.port_range_next = hnb->rtp.port_range_start;
+	hnb->rtp.ip_dscp = -1;
+	hnb->rtp.priority = -1;
+
 	hnb->shutdown_fi = osmo_fsm_inst_alloc(&hnb_shutdown_fsm, hnb, hnb,
 					       LOGL_INFO, NULL);
 
@@ -94,16 +105,87 @@
 
 void hnb_ue_free(struct hnb_ue *ue)
 {
+	hnb_ue_reset_chan(ue, true);
+	hnb_ue_reset_chan(ue, false);
 	llist_del(&ue->list);
 	talloc_free(ue);
 }
 
 void hnb_ue_reset_chan(struct hnb_ue *ue, bool is_ps)
 {
-	if (is_ps)
+	if (is_ps) {
 		ue->conn_ps = (struct hnb_ue_ps_ctx){0};
-	else
+	} else {
+		if (ue->conn_cs.rtp.socket)
+			osmo_rtp_socket_free(ue->conn_cs.rtp.socket);
 		ue->conn_cs = (struct hnb_ue_cs_ctx){0};
+	}
+}
+
+int hnb_ue_voicecall_setup(struct hnb_ue *ue, const struct osmo_sockaddr *rem_addr, struct osmo_sockaddr *loc_addr)
+{
+	int rc;
+	char cname[256+4];
+	char name[32];
+	struct osmo_rtp_socket *rs;
+	const char *local_wildcard_ipstr = "0.0.0.0";
+	char remote_ipstr[INET6_ADDRSTRLEN];
+	uint16_t remote_port;
+	struct hnb *hnb = ue->hnb;
+
+	if (osmo_sockaddr_to_str_and_uint(remote_ipstr, sizeof(remote_ipstr), &remote_port, &rem_addr->u.sa) == 0) {
+		LOGUE(ue, DRTP, LOGL_ERROR, "Failed parsing remote address!\n");
+		return -EINVAL;
+	}
+
+	if (ue->conn_cs.rtp.socket) {
+		LOGUE(ue, DRTP, LOGL_ERROR, "Setting up rtp socket but it already exists!\n");
+		return -EINVAL;
+	}
+
+	rs = ue->conn_cs.rtp.socket = osmo_rtp_socket_create(ue, OSMO_RTP_F_POLL);
+	rc = osmo_rtp_socket_set_param(rs,
+				       hnb->rtp.jitter_adaptive ?
+				       OSMO_RTP_P_JIT_ADAP :
+				       OSMO_RTP_P_JITBUF,
+				       hnb->rtp.jitter_buf_ms);
+	if (rc < 0) {
+		LOGUE(ue, DRTP, LOGL_ERROR, "Failed to set RTP socket parameters: %s\n", strerror(-rc));
+		goto free_ret;
+	}
+	rs->priv = ue;
+	rs->rx_cb = &rtp_rx_cb;
+
+	rc = rtp_bind(hnb, rs, local_wildcard_ipstr);
+	if (rc < 0) {
+		LOGUE(ue, DRTP, LOGL_ERROR, "Failed to bind RTP/RTCP sockets\n");
+		goto free_ret;
+	}
+
+	/* Ensure RTCP SDES contains some useful information */
+	snprintf(cname, sizeof(cname), "hnb@%s", local_wildcard_ipstr);
+	snprintf(name, sizeof(name), "ue@%u", ue->conn_id);
+	osmo_rtp_set_source_desc(rs, cname, name, NULL, NULL, NULL,
+				 "OsmoHNodeB-" PACKAGE_VERSION, NULL);
+
+
+	rc = osmo_rtp_socket_connect(rs, remote_ipstr, remote_port);
+	if (rc < 0) {
+		LOGUE(ue, DRTP, LOGL_ERROR, "Failed to connect RTP/RTCP sockets\n");
+		goto free_ret;
+	}
+
+	rc = rtp_get_bound_addr(rs, loc_addr);
+	if (rc < 0) {
+		LOGUE(ue, DRTP, LOGL_ERROR, "Cannot obtain locally bound IP/port: %d\n", rc);
+		goto free_ret;
+	}
+
+	return rc;
+free_ret:
+	osmo_rtp_socket_free(ue->conn_cs.rtp.socket);
+	ue->conn_cs.rtp.socket = NULL;
+	return rc;
 }
 
 struct hnb_ue *hnb_find_ue_by_id(const struct hnb *hnb, uint32_t conn_id)
diff --git a/src/osmo-hnodeb/llsk.c b/src/osmo-hnodeb/llsk.c
index 5f0f9dc..121a3a8 100644
--- a/src/osmo-hnodeb/llsk.c
+++ b/src/osmo-hnodeb/llsk.c
@@ -18,6 +18,9 @@
  */
 
 #include <errno.h>
+#include <sys/socket.h>
+#include <inttypes.h>
+#include <arpa/inet.h>
 
 #include <osmocom/core/prim.h>
 #include <osmocom/core/logging.h>
@@ -27,6 +30,58 @@
 #include <osmocom/hnodeb/hnb_prim.h>
 #include <osmocom/hnodeb/hnb_shutdown_fsm.h>
 
+int ll_addr_type2af(enum u_addr_type t)
+{
+	switch (t) {
+	case HNB_PRIM_ADDR_TYPE_IPV4:
+		return AF_INET;
+	case HNB_PRIM_ADDR_TYPE_IPV6:
+		return AF_INET6;
+	default:
+		LOGP(DLLSK, LOGL_ERROR, "Rx Unknwon address type %u\n", (unsigned)t);
+		return -1;
+	}
+}
+
+int ll_addr2osa(enum u_addr_type t, const union u_addr *uaddr, uint16_t port, struct osmo_sockaddr *osa)
+{
+	int af = ll_addr_type2af(t);
+
+	osa->u.sa.sa_family = af;
+
+	switch (af) {
+	case AF_INET6:
+		memcpy(&osa->u.sin6.sin6_addr, &uaddr->v6, sizeof(osa->u.sin6.sin6_addr));
+		osa->u.sin6.sin6_port = htons(port);
+		break;
+	case AF_INET:
+		memcpy(&osa->u.sin.sin_addr, &uaddr->v4, sizeof(osa->u.sin.sin_addr));
+		osa->u.sin.sin_port = htons(port);
+		break;
+	default:
+		return -1;
+	}
+	return 0;
+}
+
+enum u_addr_type osa2_ll_addr(const struct osmo_sockaddr *osa, union u_addr *uaddr, uint16_t *port)
+{
+	switch (osa->u.sa.sa_family) {
+	case AF_INET:
+		memcpy(&uaddr->v6, &osa->u.sin6.sin6_addr, sizeof(osa->u.sin6.sin6_addr));
+		if (port)
+			*port = ntohs(osa->u.sin6.sin6_port);
+		return HNB_PRIM_ADDR_TYPE_IPV4;
+	case AF_INET6:
+		memcpy(&uaddr->v4, &osa->u.sin.sin_addr, sizeof(osa->u.sin.sin_addr));
+		if (port)
+			*port = ntohs(osa->u.sin.sin_port);
+		return HNB_PRIM_ADDR_TYPE_IPV6;
+	default:
+		return HNB_PRIM_ADDR_TYPE_UNSPEC;
+	}
+}
+
 static int llsk_opened_cb(struct osmo_prim_srv *srv)
 {
 	struct hnb *hnb = (struct hnb *)osmo_prim_srv_get_priv(srv);
@@ -73,7 +128,8 @@
 	if (!hnb->llsk)
 		return false;
 
-	if (hnb->llsk_valid_sapi_mask & (1 << HNB_PRIM_SAPI_IUH))
+	if (hnb->llsk_valid_sapi_mask & (1 << HNB_PRIM_SAPI_IUH) &&
+	    hnb->llsk_valid_sapi_mask & (1 << HNB_PRIM_SAPI_AUDIO))
 		return true;
 	return false;
 }
@@ -108,10 +164,11 @@
 	case HNB_PRIM_SAPI_IUH:
 		return llsk_rx_iuh(hnb, oph);
 	case HNB_PRIM_SAPI_GTP:
-	case HNB_PRIM_SAPI_AUDIO:
 		LOGP(DLLSK, LOGL_ERROR, "Rx SAPI %u not yet implemented (len=%u)\n",
 		     oph->sap, msgb_length(oph->msg));
 		return -EINVAL;
+	case HNB_PRIM_SAPI_AUDIO:
+		return llsk_rx_audio(hnb, oph);
 	default:
 		LOGP(DLLSK, LOGL_ERROR, "Rx for unknwon SAPI %u (len=%u)\n",
 		     oph->sap, msgb_length(oph->msg));
diff --git a/src/osmo-hnodeb/llsk_audio.c b/src/osmo-hnodeb/llsk_audio.c
new file mode 100644
index 0000000..bf4b891
--- /dev/null
+++ b/src/osmo-hnodeb/llsk_audio.c
@@ -0,0 +1,275 @@
+/* (C) 2021 by sysmocom - s.f.m.c. GmbH <info at sysmocom.de>
+ * Author: Pau Espin Pedrol <pespin at sysmocom.de>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/lienses/>.
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <inttypes.h>
+#include <arpa/inet.h>
+
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/select.h>
+#include <osmocom/core/socket.h>
+
+#include <osmocom/hnodeb/hnodeb.h>
+#include <osmocom/hnodeb/llsk.h>
+#include <osmocom/hnodeb/hnb_prim.h>
+
+static size_t llsk_audio_prim_size_tbl[4][_HNB_AUDIO_PRIM_MAX] = {
+	[PRIM_OP_REQUEST] = {
+		[HNB_AUDIO_PRIM_CONN_ESTABLISH] = sizeof(struct hnb_audio_conn_establish_req_param),
+		[HNB_AUDIO_PRIM_CONN_RELEASE] = sizeof(struct hnb_audio_conn_release_req_param),
+		[HNB_AUDIO_PRIM_CONN_DATA] = sizeof(struct hnb_audio_conn_data_req_param),
+	},
+	[PRIM_OP_RESPONSE] = {},
+	[PRIM_OP_INDICATION] = {
+		[HNB_AUDIO_PRIM_CONN_DATA] = sizeof(struct hnb_audio_conn_data_ind_param),
+	},
+	[PRIM_OP_CONFIRM] = {
+		[HNB_AUDIO_PRIM_CONN_ESTABLISH] = sizeof(struct hnb_audio_conn_establish_cnf_param),
+	},
+};
+static inline size_t llsk_audio_prim_size(enum hnb_audio_prim_type ptype, enum osmo_prim_operation op)
+{
+	size_t val = llsk_audio_prim_size_tbl[op][ptype];
+	if (val == 0) {
+		LOGP(DLLSK, LOGL_FATAL, "Expected prim_size != 0 for ptype=%u op=%u\n", ptype, op);
+		osmo_panic("Expected prim_size != 0 for ptype=%u op=%u\n", ptype, op);
+	}
+	return val;
+}
+
+const struct value_string hnb_audio_prim_type_names[] = {
+	OSMO_VALUE_STRING(HNB_AUDIO_PRIM_CONN_ESTABLISH),
+	OSMO_VALUE_STRING(HNB_AUDIO_PRIM_CONN_RELEASE),
+	OSMO_VALUE_STRING(HNB_AUDIO_PRIM_CONN_DATA),
+	{ 0, NULL }
+};
+
+static struct hnb_audio_prim *hnb_audio_prim_alloc(enum hnb_audio_prim_type ptype, enum osmo_prim_operation op, size_t extra_len)
+{
+	struct osmo_prim_hdr *oph;
+	size_t len = llsk_audio_prim_size(ptype, op);
+
+	oph = osmo_prim_msgb_alloc(HNB_PRIM_SAPI_AUDIO, ptype, op, sizeof(*oph) + len + extra_len);
+	if (!oph)
+		return NULL;
+	msgb_put(oph->msg, len);
+
+	return (struct hnb_audio_prim *)oph;
+}
+
+static struct hnb_audio_prim *hnb_audio_makeprim_conn_establish_cnf(uint32_t context_id, uint8_t error_code,
+							     uint16_t local_rtp_port, uint8_t local_rtp_address_type,
+							     const union u_addr *local_rtp_addr)
+{
+	struct hnb_audio_prim *audio_prim;
+
+	audio_prim = hnb_audio_prim_alloc(HNB_AUDIO_PRIM_CONN_ESTABLISH, PRIM_OP_CONFIRM, 0);
+	audio_prim->u.conn_establish_cnf.context_id = context_id;
+	audio_prim->u.conn_establish_cnf.local_rtp_port = local_rtp_port;
+	audio_prim->u.conn_establish_cnf.error_code = error_code;
+	audio_prim->u.conn_establish_cnf.local_rtp_address_type = local_rtp_address_type;
+	if (local_rtp_addr)
+		audio_prim->u.conn_establish_cnf.local_rtp_addr = *local_rtp_addr;
+
+	return audio_prim;
+}
+
+struct hnb_audio_prim *hnb_audio_makeprim_conn_data_ind(uint32_t context_id,
+							uint8_t domain,
+							const uint8_t *data,
+							uint32_t data_len)
+{
+	struct hnb_audio_prim *audio_prim;
+
+	audio_prim = hnb_audio_prim_alloc(HNB_AUDIO_PRIM_CONN_DATA, PRIM_OP_INDICATION, data_len);
+	audio_prim->u.conn_data_ind.context_id = context_id;
+	audio_prim->u.conn_data_ind.data_len = data_len;
+	if (data_len) {
+		msgb_put(audio_prim->hdr.msg, data_len);
+		memcpy(audio_prim->u.conn_data_ind.data, data, data_len);
+	}
+
+	return audio_prim;
+}
+
+static int _send_conn_establish_cnf_failed(struct hnb *hnb, uint32_t context_id, uint8_t error_code)
+{
+	struct hnb_audio_prim *audio_prim;
+	int rc;
+	LOGP(DLLSK, LOGL_ERROR, "Tx AUDIO-CONN_ESTABLISH.cnf: ctx=%u error_code=%u\n",
+	     context_id, error_code);
+	audio_prim = hnb_audio_makeprim_conn_establish_cnf(context_id, error_code, 0, HNB_PRIM_ADDR_TYPE_UNSPEC, NULL);
+	if ((rc = osmo_prim_srv_send(hnb->llsk, audio_prim->hdr.msg)) < 0) {
+		LOGP(DLLSK, LOGL_ERROR, "Failed sending AUDIO-CONN_ESTABLISH.cnf context_id=%u error_code=%u\n",
+		     context_id, error_code);
+	}
+	return rc;
+}
+
+static int llsk_rx_audio_conn_establish_req(struct hnb *hnb, struct hnb_audio_conn_establish_req_param *ce_req)
+{
+	struct hnb_ue *ue;
+	int rc = 0;
+	struct hnb_audio_prim *audio_prim;
+	int af;
+	char rem_addrstr[INET6_ADDRSTRLEN+32];
+	struct osmo_sockaddr rem_osa = {0};
+	struct osmo_sockaddr loc_osa = {0};
+	union u_addr loc_uaddr = {0};
+	uint16_t loc_port;
+
+	rc = ll_addr2osa(ce_req->remote_rtp_address_type, &ce_req->remote_rtp_addr, ce_req->remote_rtp_port, &rem_osa);
+	if (rc < 0) {
+		LOGP(DLLSK, LOGL_ERROR, "Rx AUDIO-CONN_ESTABLISH.req: ctx=%u with unexpected address type %u\n",
+		     ce_req->context_id, ce_req->remote_rtp_address_type);
+		return _send_conn_establish_cnf_failed(hnb, ce_req->context_id, 1);
+	}
+	osmo_sockaddr_to_str_buf(rem_addrstr, sizeof(rem_addrstr), &rem_osa);
+
+	LOGP(DLLSK, LOGL_INFO, "Rx AUDIO-CONN_ESTABLISH.req ctx=%u rem_addr=%s\n",
+	     ce_req->context_id, rem_addrstr);
+
+	if ((af = ll_addr_type2af(ce_req->remote_rtp_address_type)) < 0) {
+		LOGP(DLLSK, LOGL_ERROR, "Rx AUDIO-CONN_ESTABLISH.req: ctx=%u with unexpected address type %u\n",
+		     ce_req->context_id, ce_req->remote_rtp_address_type);
+		return _send_conn_establish_cnf_failed(hnb, ce_req->context_id, 1);
+	}
+
+	ue = hnb_find_ue_by_id(hnb, ce_req->context_id);
+	if (!ue) {
+		LOGP(DLLSK, LOGL_ERROR, "Rx AUDIO-CONN_ESTABLISH.req: UE not found! ctx=%u rem_addr=%s\n",
+		     ce_req->context_id, rem_addrstr);
+		return _send_conn_establish_cnf_failed(hnb, ce_req->context_id, 2);
+	}
+	if (!ue->conn_cs.active) {
+		LOGP(DLLSK, LOGL_ERROR, "Rx AUDIO-CONN_ESTABLISH.req: CS chan not active! ctx=%u rem_addr=%s\n",
+		     ce_req->context_id, rem_addrstr);
+		return _send_conn_establish_cnf_failed(hnb, ce_req->context_id, 3);
+	}
+
+	/* Create the socket: */
+	if ((rc = hnb_ue_voicecall_setup(ue, &rem_osa, &loc_osa)) < 0) {
+		LOGP(DLLSK, LOGL_ERROR, "Rx AUDIO-CONN_ESTABLISH.req: Failed to set up audio socket ctx=%u rem_addr=%s\n",
+		     ce_req->context_id, rem_addrstr);
+		return _send_conn_establish_cnf_failed(hnb, ce_req->context_id, 4);
+	}
+
+	/* Convert resulting local address back to LLSK format: */
+	if (osa2_ll_addr(&loc_osa, &loc_uaddr,  &loc_port) != ce_req->remote_rtp_address_type) {
+		LOGP(DLLSK, LOGL_ERROR, "Rx AUDIO-CONN_ESTABLISH.req: Failed to provide proper local address ctx=%u rem_addr=%s\n",
+		     ce_req->context_id, rem_addrstr);
+		rc = _send_conn_establish_cnf_failed(hnb, ce_req->context_id, 4);
+		goto release_sock;
+	}
+
+	/* Submit successful confirmation */
+	LOGP(DLLSK, LOGL_INFO, "Tx AUDIO-CONN_ESTABLISH.cnf: ctx=%u error_code=0 rem_addr=%s loc_addr=%s\n",
+	     ce_req->context_id, rem_addrstr, osmo_sockaddr_to_str(&loc_osa));
+	audio_prim = hnb_audio_makeprim_conn_establish_cnf(ce_req->context_id, 0, loc_port, ce_req->remote_rtp_address_type, &loc_uaddr);
+	if ((rc = osmo_prim_srv_send(hnb->llsk, audio_prim->hdr.msg)) < 0) {
+		LOGP(DLLSK, LOGL_ERROR, "Failed sending AUDIO-CONN_ESTABLISH.cnf context_id=%u error_code=0\n",
+		     ce_req->context_id);
+		goto release_sock;
+	}
+
+	return rc;
+release_sock: /* TODO: release socket here */
+	return rc;
+}
+
+static int llsk_rx_audio_conn_release_req(struct hnb *hnb, struct hnb_audio_conn_release_req_param *rel_req)
+{
+	struct hnb_ue *ue;
+	int rc = 0;
+
+	LOGP(DLLSK, LOGL_DEBUG, "Rx AUDIO-CONN_RELEASE.req ctx=%u\n", rel_req->context_id);
+
+	ue = hnb_find_ue_by_id(hnb, rel_req->context_id);
+	if (!ue) {
+		LOGP(DLLSK, LOGL_ERROR, "Rx AUDIO-CONN_RELEASE.req: UE not found! ctx=%u\n",
+		     rel_req->context_id);
+		return -EINVAL;
+	}
+	/* TODO: release RTP socket */
+	return rc;
+}
+
+static int llsk_rx_audio_conn_data_req(struct hnb *hnb, struct hnb_audio_conn_data_req_param *data_req)
+{
+	struct hnb_ue *ue;
+	int rc = 0;
+
+	LOGP(DLLSK, LOGL_DEBUG, "Rx AUDIO-CONN_DATA.req ctx=%u data_len=%u\n",
+	     data_req->context_id, data_req->data_len);
+
+	ue = hnb_find_ue_by_id(hnb, data_req->context_id);
+	if (!ue) {
+		LOGP(DLLSK, LOGL_ERROR, "Rx AUDIO-CONN_DATA.req: UE not found! ctx=%u data_len=%u\n",
+		     data_req->context_id, data_req->data_len);
+		return -EINVAL;
+	}
+
+	/* TODO: transmit data_req->data through RTP/Iu-UP socket */
+	return rc;
+}
+
+int llsk_rx_audio(struct hnb *hnb, struct osmo_prim_hdr *oph)
+{
+	size_t prim_size = llsk_audio_prim_size(oph->primitive, oph->operation);
+
+	if (msgb_length(oph->msg) < prim_size) {
+		LOGP(DLLSK, LOGL_ERROR, "Rx AUDIO-%s.%s with length %u < %zu\n",
+		     get_value_string(hnb_audio_prim_type_names, oph->primitive),
+		     get_value_string(osmo_prim_op_names, oph->operation),
+		     msgb_length(oph->msg), prim_size);
+		return -EINVAL;
+	}
+
+	switch (oph->operation) {
+	case PRIM_OP_REQUEST:
+		switch (oph->primitive) {
+		case HNB_AUDIO_PRIM_CONN_ESTABLISH:
+			return llsk_rx_audio_conn_establish_req(hnb, (struct hnb_audio_conn_establish_req_param *)msgb_data(oph->msg));
+		case HNB_AUDIO_PRIM_CONN_RELEASE:
+			return llsk_rx_audio_conn_release_req(hnb, (struct hnb_audio_conn_release_req_param *)msgb_data(oph->msg));
+		case HNB_AUDIO_PRIM_CONN_DATA:
+			return llsk_rx_audio_conn_data_req(hnb, (struct hnb_audio_conn_data_req_param *)msgb_data(oph->msg));
+		default:
+			LOGP(DLLSK, LOGL_ERROR, "Rx llsk-audio unknown primitive %u (len=%u)\n",
+			     oph->primitive, msgb_length(oph->msg));
+			return -EINVAL;
+		}
+		break;
+
+	case PRIM_OP_RESPONSE:
+	case PRIM_OP_INDICATION:
+	case PRIM_OP_CONFIRM:
+	default:
+		LOGP(DLLSK, LOGL_ERROR, "Rx llsk-audio unexpected primitive operation %s::%s (len=%u)\n",
+		     get_value_string(hnb_audio_prim_type_names, oph->primitive),
+		     get_value_string(osmo_prim_op_names, oph->operation),
+		     msgb_length(oph->msg));
+		return -EINVAL;
+	}
+}
diff --git a/src/osmo-hnodeb/main.c b/src/osmo-hnodeb/main.c
index 6728a07..9af83ea 100644
--- a/src/osmo-hnodeb/main.c
+++ b/src/osmo-hnodeb/main.c
@@ -41,6 +41,8 @@
 #include <osmocom/vty/cpu_sched_vty.h>
 #include <osmocom/vty/ports.h>
 
+#include <osmocom/trau/osmo_ortp.h>
+
 #include <osmocom/ranap/ranap_common.h> /* ranap_set_log_area() */
 
 #include <osmocom/hnodeb/hnbap.h>
@@ -224,6 +226,7 @@
 int main(int argc, char **argv)
 {
 	int rc;
+	void *tall_rtp_ctx;
 
 	/* Track the use of talloc NULL memory contexts */
 	talloc_enable_null_tracking();
@@ -246,6 +249,11 @@
 	osmo_talloc_vty_add_cmds();
 	osmo_cpu_sched_vty_init(tall_hnb_ctx);
 
+	/* allocate a talloc pool for ORTP to ensure it doesn't have to go back
+	 * to the libc malloc all the time */
+	tall_rtp_ctx = talloc_pool(tall_hnb_ctx, 262144);
+	osmo_rtp_init(tall_rtp_ctx);
+
 	g_hnb = hnb_alloc(tall_hnb_ctx);
 	hnb_vty_init();
 
diff --git a/src/osmo-hnodeb/rtp.c b/src/osmo-hnodeb/rtp.c
new file mode 100644
index 0000000..076cab8
--- /dev/null
+++ b/src/osmo-hnodeb/rtp.c
@@ -0,0 +1,96 @@
+/* (C) 2021 by sysmocom - s.f.m.c. GmbH <info at sysmocom.de>
+ * Author: Pau Espin Pedrol <pespin at sysmocom.de>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/lienses/>.
+ *
+ */
+
+#include <errno.h>
+#include <sys/socket.h>
+
+#include <osmocom/hnodeb/rtp.h>
+#include <osmocom/hnodeb/hnodeb.h>
+
+
+/* Mixture between osmo_rtp_get_bound_addr and osmo_rtp_get_bound_ip_port using osmo_sockaddr */
+int rtp_get_bound_addr(struct osmo_rtp_socket *rs, struct osmo_sockaddr *osa)
+{
+	int rc;
+	//uint16_t port;
+	socklen_t alen = sizeof(*osa);
+
+	rc = getsockname(rs->rtp_bfd.fd, (struct sockaddr *)&osa->u.sa, &alen);
+	if (rc < 0)
+		return rc;
+
+	/* Is this really needed? or getsockname already gathers the port? */
+	/*port = rtp_session_get_local_port(rs->sess);
+	switch (osa->u.sa.sa_family) {
+	case AF_INET6:
+		osa->u.sin6.sin6_port = htons(port);
+	case AF_INET:
+		osa->u.sin.sin_port = htons(port);
+	default:
+		return -1;
+	}*/
+
+	return 0;
+}
+
+int rtp_bind(struct hnb *hnb, struct osmo_rtp_socket *rs, const char *ip)
+{
+	int rc;
+	unsigned int i;
+	unsigned int tries;
+
+	tries = (hnb->rtp.port_range_end - hnb->rtp.port_range_start) / 2;
+	for (i = 0; i < tries; i++) {
+
+		if (hnb->rtp.port_range_next >= hnb->rtp.port_range_end)
+			hnb->rtp.port_range_next = hnb->rtp.port_range_start;
+
+		rc = osmo_rtp_socket_bind(rs, ip, hnb->rtp.port_range_next);
+
+		hnb->rtp.port_range_next += 2;
+
+		if (rc != 0)
+			continue;
+
+		if (hnb->rtp.ip_dscp != -1) {
+			if (osmo_rtp_socket_set_dscp(rs, hnb->rtp.ip_dscp))
+				LOGP(DRTP, LOGL_ERROR, "failed to set DSCP=%i: %s\n",
+					hnb->rtp.ip_dscp, strerror(errno));
+		}
+		if (hnb->rtp.priority != -1) {
+			if (osmo_rtp_socket_set_priority(rs, hnb->rtp.priority))
+				LOGP(DRTP, LOGL_ERROR, "failed to set socket priority %d: %s\n",
+					hnb->rtp.priority, strerror(errno));
+		}
+		return 0;
+	}
+
+	return -1;
+}
+
+
+
+
+
+void rtp_rx_cb(struct osmo_rtp_socket *rs, const uint8_t *rtp_pl,
+	       unsigned int rtp_pl_len, uint16_t seq_number,
+	       uint32_t timestamp, bool marker)
+{
+	LOGP(DRTP, LOGL_DEBUG, "Rx RTP cb\n");
+}

-- 
To view, visit https://gerrit.osmocom.org/c/osmo-hnodeb/+/26502
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings

Gerrit-Project: osmo-hnodeb
Gerrit-Branch: master
Gerrit-Change-Id: I9909a7c054ddaabb1bb63d7d06331cc79f642b5d
Gerrit-Change-Number: 26502
Gerrit-PatchSet: 1
Gerrit-Owner: pespin <pespin at sysmocom.de>
Gerrit-MessageType: newchange
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20211210/cb299628/attachment.htm>


More information about the gerrit-log mailing list