First implementation of the LLSK audio SAPI
This first version can send and receive regular RTP, but does not talk IuUP. Support for IuUP will be added in a future patch. This way we can already test the whole LLSK<->RTP path. Change-Id: I9909a7c054ddaabb1bb63d7d06331cc79f642b5d
This commit is contained in:
parent
cd1baf0649
commit
b3af382157
|
@ -61,6 +61,7 @@ PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.6.0)
|
|||
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)
|
||||
|
|
|
@ -6,6 +6,7 @@ noinst_HEADERS = \
|
|||
iuh.h \
|
||||
llsk.h \
|
||||
ranap.h \
|
||||
rtp.h \
|
||||
rua.h \
|
||||
vty.h \
|
||||
$(NULL)
|
||||
|
|
|
@ -40,6 +40,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,
|
||||
|
@ -163,3 +173,62 @@ struct hnb_iuh_prim {
|
|||
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 */
|
||||
uint8_t 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 */
|
||||
uint8_t 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));
|
||||
|
|
|
@ -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 @@ enum {
|
|||
DRANAP,
|
||||
DSCTP,
|
||||
DLLSK,
|
||||
DRTP,
|
||||
};
|
||||
extern const struct log_info hnb_log_info;
|
||||
|
||||
|
@ -55,6 +58,9 @@ struct hnb_ue {
|
|||
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? */
|
||||
|
@ -86,6 +92,17 @@ struct hnb {
|
|||
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 +121,5 @@ struct hnb_ue *hnb_find_ue_by_imsi(const struct hnb *hnb, char *imsi);
|
|||
|
||||
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)
|
||||
|
|
|
@ -22,15 +22,22 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/core/socket.h>
|
||||
#include <osmocom/netif/prim.h>
|
||||
#include <osmocom/hnodeb/hnb_prim.h>
|
||||
|
||||
struct hnb;
|
||||
struct hnb_ue;
|
||||
|
||||
int hnb_llsk_alloc(struct hnb *hnb);
|
||||
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 +49,8 @@ struct hnb_iuh_prim *hnb_iuh_makeprim_conn_data_ind(uint32_t context_id,
|
|||
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);
|
||||
int llsk_audio_tx_conn_data_ind(struct hnb_ue *ue, const uint8_t *payload, uint32_t len);
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/* (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* Author: Pau Espin Pedrol <pespin@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>
|
||||
|
||||
struct hnb;
|
||||
struct hnb_ue;
|
||||
|
||||
int hnb_ue_voicecall_setup(struct hnb_ue *ue, const struct osmo_sockaddr *rem_addr, struct osmo_sockaddr *loc_addr);
|
||||
int hnb_ue_voicecall_release(struct hnb_ue *ue);
|
|
@ -14,6 +14,7 @@ AM_CFLAGS = \
|
|||
$(LIBOSMONETIF_CFLAGS) \
|
||||
$(COVERAGE_CFLAGS) \
|
||||
$(LIBOSMOABIS_CFLAGS) \
|
||||
$(LIBOSMOTRAU_CFLAGS) \
|
||||
$(LIBOSMOSIGTRAN_CFLAGS) \
|
||||
$(LIBOSMORUA_CFLAGS) \
|
||||
$(LIBOSMORANAP_CFLAGS) \
|
||||
|
@ -36,8 +37,10 @@ osmo_hnodeb_SOURCES = \
|
|||
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 @@ osmo_hnodeb_LDADD = \
|
|||
$(LIBOSMONETIF_LIBS) \
|
||||
$(COVERAGE_LDFLAGS) \
|
||||
$(LIBOSMOABIS_LIBS) \
|
||||
$(LIBOSMOTRAU_LIBS) \
|
||||
$(LIBOSMOSIGTRAN_LIBS) \
|
||||
$(LIBOSMORUA_LIBS) \
|
||||
$(LIBOSMORANAP_LIBS) \
|
||||
|
|
|
@ -52,6 +52,11 @@ static const struct log_info_cat log_cat[] = {
|
|||
.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 = {
|
||||
|
|
|
@ -20,15 +20,20 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <osmocom/core/socket.h>
|
||||
#include <osmocom/core/talloc.h>
|
||||
#include <osmocom/netif/stream.h>
|
||||
#include <osmocom/netif/prim.h>
|
||||
|
||||
#include <osmocom/trau/osmo_ortp.h>
|
||||
|
||||
#include <osmocom/hnodeb/hnodeb.h>
|
||||
#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 +51,14 @@ struct hnb *hnb_alloc(void *tall_ctx)
|
|||
.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 +107,20 @@ struct hnb_ue *hnb_ue_alloc(struct hnb *hnb, uint32_t conn_id)
|
|||
|
||||
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 {
|
||||
hnb_ue_voicecall_release(ue);
|
||||
ue->conn_cs = (struct hnb_ue_cs_ctx){0};
|
||||
}
|
||||
}
|
||||
|
||||
struct hnb_ue *hnb_find_ue_by_id(const struct hnb *hnb, uint32_t conn_id)
|
||||
|
|
|
@ -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_INET6:
|
||||
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_IPV6;
|
||||
case AF_INET:
|
||||
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_IPV4;
|
||||
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 @@ bool hnb_llsk_can_be_configured(struct hnb *hnb)
|
|||
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 @@ static int llsk_rx_cb(struct osmo_prim_srv *srv, struct osmo_prim_hdr *oph)
|
|||
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));
|
||||
|
|
|
@ -0,0 +1,296 @@
|
|||
/* (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* Author: Pau Espin Pedrol <pespin@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/trau/osmo_ortp.h>
|
||||
|
||||
#include <osmocom/hnodeb/hnodeb.h>
|
||||
#include <osmocom/hnodeb/llsk.h>
|
||||
#include <osmocom/hnodeb/hnb_prim.h>
|
||||
#include <osmocom/hnodeb/rtp.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;
|
||||
}
|
||||
|
||||
static 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;
|
||||
}
|
||||
|
||||
int llsk_audio_tx_conn_data_ind(struct hnb_ue *ue, const uint8_t *payload, uint32_t len)
|
||||
{
|
||||
struct hnb_audio_prim *audio_prim;
|
||||
int rc;
|
||||
|
||||
LOGUE(ue, DLLSK, LOGL_INFO, "Tx AUDIO-CONN_DATA.ind\n");
|
||||
audio_prim = hnb_audio_makeprim_conn_data_ind(ue->conn_id, 0 /* CS */, payload, len);
|
||||
if ((rc = osmo_prim_srv_send(ue->hnb->llsk, audio_prim->hdr.msg)) < 0)
|
||||
LOGUE(ue, DLLSK, LOGL_ERROR, "Failed sending AUDIO-CONN_DATA.ind\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
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) {
|
||||
LOGUE(ue, DLLSK, LOGL_ERROR, "Rx AUDIO-CONN_ESTABLISH.req: CS chan not active! rem_addr=%s\n",
|
||||
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) {
|
||||
LOGUE(ue, DLLSK, LOGL_ERROR, "Rx AUDIO-CONN_ESTABLISH.req: Failed to set up audio socket rem_addr=%s\n",
|
||||
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) {
|
||||
LOGUE(ue, DLLSK, LOGL_ERROR, "Rx AUDIO-CONN_ESTABLISH.req: Failed to provide proper local address rem_addr=%s\n",
|
||||
rem_addrstr);
|
||||
rc = _send_conn_establish_cnf_failed(hnb, ce_req->context_id, 4);
|
||||
goto release_sock;
|
||||
}
|
||||
|
||||
/* Submit successful confirmation */
|
||||
LOGUE(ue, DLLSK, LOGL_INFO, "Tx AUDIO-CONN_ESTABLISH.cnf: error_code=0 rem_addr=%s loc_addr=%s\n",
|
||||
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) {
|
||||
LOGUE(ue, DLLSK, LOGL_ERROR, "Failed sending AUDIO-CONN_ESTABLISH.cnf error_code=0\n");
|
||||
goto release_sock;
|
||||
}
|
||||
|
||||
return rc;
|
||||
release_sock:
|
||||
hnb_ue_voicecall_release(ue);
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
/* Release RTP socket: */
|
||||
return hnb_ue_voicecall_release(ue);
|
||||
}
|
||||
|
||||
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 */
|
||||
rc = osmo_rtp_send_frame_ext(ue->conn_cs.rtp.socket, data_req->data,
|
||||
data_req->data_len, GSM_RTP_DURATION, false);
|
||||
if (rc < 0) {
|
||||
LOGUE(ue, 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 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;
|
||||
}
|
||||
}
|
|
@ -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 @@ static void signal_handler(int signum)
|
|||
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 @@ int main(int argc, char **argv)
|
|||
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();
|
||||
|
||||
|
|
|
@ -0,0 +1,212 @@
|
|||
/* (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* Author: Pau Espin Pedrol <pespin@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 "config.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <osmocom/trau/osmo_ortp.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 */
|
||||
/*static int rtp_get_bound_addr(struct osmo_rtp_socket *rs, struct osmo_sockaddr *osa)
|
||||
{
|
||||
int rc;
|
||||
socklen_t alen = sizeof(*osa);
|
||||
|
||||
rc = getsockname(rs->rtp_bfd.fd, (struct sockaddr *)&osa->u.sa, &alen);
|
||||
if (rc < 0) {
|
||||
LOGP(DRTP, LOGL_ERROR, "getsockname(%d) failed: %s\n",
|
||||
rs->rtp_bfd.fd, strerror(errno));
|
||||
return rc;
|
||||
}
|
||||
LOGP(DRTP, LOGL_DEBUG, "rtp socket: %s\n", osmo_sock_get_name2(rs->rtp_bfd.fd));
|
||||
return 0;
|
||||
}*/
|
||||
|
||||
/* osmo_rtp_socket_connect() is broken, OS#5356 */
|
||||
static int rtp_get_bound_addr(struct osmo_rtp_socket *rs, const struct osmo_sockaddr *rem_addr, struct osmo_sockaddr *osa)
|
||||
{
|
||||
int rc;
|
||||
uint16_t port;
|
||||
socklen_t alen = sizeof(*osa);
|
||||
|
||||
/* First, retrieve bound port using getsockname: */
|
||||
rc = getsockname(rs->rtp_bfd.fd, (struct sockaddr *)&osa->u.sa, &alen);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
switch (osa->u.sa.sa_family) {
|
||||
case AF_INET6:
|
||||
port = ntohs(osa->u.sin6.sin6_port);
|
||||
break;
|
||||
case AF_INET:
|
||||
port = ntohs(osa->u.sin.sin_port);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* osmo_rtp_socket_connect() is broken, OS#5356, so we didn't connect()
|
||||
* and hence local_addr may still be unresolved (0.0.0.0) in the socket.
|
||||
* let's get it from OS regular routing: */
|
||||
rc = osmo_sockaddr_local_ip(osa, rem_addr);
|
||||
if (rc < 0) {
|
||||
LOGP(DRTP, LOGL_ERROR, "osmo_sockaddr_local_ip(%d) failed: err=%d\n",
|
||||
rs->rtp_bfd.fd, -rc);
|
||||
return rc;
|
||||
}
|
||||
/* Copy back the correct port to the returned address: */
|
||||
switch (osa->u.sa.sa_family) {
|
||||
case AF_INET6:
|
||||
osa->u.sin6.sin6_port = htons(port);
|
||||
break;
|
||||
case AF_INET:
|
||||
osa->u.sin.sin_port = htons(port);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static 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=%d: %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;
|
||||
}
|
||||
|
||||
static 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)
|
||||
{
|
||||
struct hnb_ue *ue = (struct hnb_ue *)rs->priv;
|
||||
|
||||
LOGUE(ue, DRTP, LOGL_DEBUG, "Rx RTP seq=%u ts=%u M=%u pl=%p len=%u\n",
|
||||
seq_number, timestamp, marker, rtp_pl, rtp_pl_len);
|
||||
llsk_audio_tx_conn_data_ind(ue, rtp_pl, rtp_pl_len);
|
||||
}
|
||||
|
||||
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, 0);
|
||||
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;
|
||||
}
|
||||
|
||||
/* osmo_rtp_socket_connect() is broken, OS#5356 */
|
||||
//rc = rtp_get_bound_addr(rs, loc_addr);
|
||||
rc = rtp_get_bound_addr(rs, rem_addr, 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;
|
||||
}
|
||||
|
||||
int hnb_ue_voicecall_release(struct hnb_ue *ue)
|
||||
{
|
||||
if (!ue->conn_cs.rtp.socket)
|
||||
return -EINVAL;
|
||||
osmo_rtp_socket_free(ue->conn_cs.rtp.socket);
|
||||
ue->conn_cs.rtp.socket = NULL;
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue