Add initial support for IuUP RTP based Transport Layer

Use the recently introduced IuUP support in libosmocore to send and receive
proper IuUP over RTP instead of regular RTP.
The LLSK AUDIO primitives are updated to provide required information
back and forth.

Depends: libosmocore.git Change-Id Ibe356fa7b1abaca0091e368db8478e79c09c6cb0
Related: SYS#5516
Change-Id: Ie137809e1f91dfd702853c52be97ca79e8604eab
This commit is contained in:
Pau Espin 2021-12-16 12:36:38 +01:00
parent 387b892b1d
commit e4f127f1a3
6 changed files with 158 additions and 18 deletions

View File

@ -8,3 +8,4 @@
# If any interfaces have been removed or changed since the last public release: c:r:0.
#library what description / commit summary line
libosmo-netif >1.1.0 use of netif/sctp.h
libosmocore > 1.6.0 use of core/iuup.h

View File

@ -186,12 +186,23 @@ enum hnb_audio_prim_type {
};
/* HNB_AUDIO_PRIM_CONN_ESTABLISH, UL */
#define HNB_MAX_RFCIS 64
#define HNB_MAX_SUBFLOWS 7
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;
/* IuUP related: */
uint8_t transparent; /* 1=transparent; 0=SMpSDU */
uint8_t data_pdu_type;
uint16_t supported_versions_mask; /* host byte order */
uint8_t num_rfci;
uint8_t num_subflows;
uint16_t subflow_sizes[HNB_MAX_RFCIS][HNB_MAX_SUBFLOWS];
uint8_t IPTIs_present; /* 1=present; 0=not present */
uint8_t IPTIs[HNB_MAX_RFCIS]; /* values range 0-15, 4 bits */
} __attribute__ ((packed));
/* HNB_AUDIO_PRIM_CONN_ESTABLISH, DL */
@ -212,6 +223,10 @@ struct hnb_audio_conn_release_req_param {
/* HNB_AUDIO_PRIM_CONN_DATA, UL */
struct hnb_audio_conn_data_req_param {
uint32_t audio_conn_id;
uint8_t frame_nr;
uint8_t fqc;
uint8_t rfci;
uint8_t spare;
uint32_t data_len; /* RTP payload length in bytes */
uint8_t data[0]; /* RTP payload (aka IP packet) */
} __attribute__ ((packed));
@ -219,6 +234,10 @@ struct hnb_audio_conn_data_req_param {
/* HNB_AUDIO_PRIM_CONN_DATA, DL */
struct hnb_audio_conn_data_ind_param {
uint32_t audio_conn_id;
uint8_t frame_nr;
uint8_t fqc;
uint8_t rfci;
uint8_t spare;
uint32_t data_len; /* RTP payload length in bytes */
uint8_t data[0]; /* RTP payload (aka IP packet) */
} __attribute__ ((packed));

View File

@ -53,7 +53,8 @@ struct hnb_iuh_prim *hnb_iuh_makeprim_unitdata_ind(const uint8_t *data, uint32_t
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 rtp_conn *conn, const uint8_t *payload, uint32_t len);
int llsk_audio_tx_conn_data_ind(struct rtp_conn *conn, uint8_t frame_nr, uint8_t fqc, uint8_t rfci,
const uint8_t *payload, uint32_t len);
extern const struct value_string hnb_gtp_prim_type_names[];
int llsk_rx_gtp(struct hnb *hnb, struct osmo_prim_hdr *oph);

View File

@ -18,8 +18,11 @@
*/
#pragma once
#include <stdint.h>
#include <osmocom/core/socket.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/hnodeb/hnb_prim.h>
struct hnb;
struct hnb_ue;
@ -31,9 +34,11 @@ struct rtp_conn {
struct osmo_rtp_socket *socket;
struct osmo_sockaddr loc_addr;
struct osmo_sockaddr rem_addr;
struct osmo_iuup_instance *iui;
};
struct rtp_conn *rtp_conn_alloc(struct hnb_ue *ue);
void rtp_conn_free(struct rtp_conn *conn);
int rtp_conn_setup(struct rtp_conn *conn, const struct osmo_sockaddr *rem_addr);
int rtp_conn_setup(struct rtp_conn *conn, const struct osmo_sockaddr *rem_addr, const struct hnb_audio_conn_establish_req_param *ce_req);
int rtp_conn_tx_data(struct rtp_conn *conn, uint8_t frame_nr, uint8_t fqc, uint8_t rfci, const uint8_t *data, unsigned int data_len);

View File

@ -101,13 +101,16 @@ static struct hnb_audio_prim *hnb_audio_makeprim_conn_establish_cnf(uint32_t con
}
static struct hnb_audio_prim *hnb_audio_makeprim_conn_data_ind(uint32_t audio_conn_id,
const uint8_t *data,
uint32_t data_len)
uint8_t frame_nr, uint8_t fqc, uint8_t rfci,
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.audio_conn_id = audio_conn_id;
audio_prim->u.conn_data_ind.frame_nr = frame_nr;
audio_prim->u.conn_data_ind.fqc = fqc;
audio_prim->u.conn_data_ind.rfci = rfci;
audio_prim->u.conn_data_ind.data_len = data_len;
if (data_len) {
msgb_put(audio_prim->hdr.msg, data_len);
@ -117,13 +120,15 @@ static struct hnb_audio_prim *hnb_audio_makeprim_conn_data_ind(uint32_t audio_co
return audio_prim;
}
int llsk_audio_tx_conn_data_ind(struct rtp_conn *conn, const uint8_t *payload, uint32_t len)
int llsk_audio_tx_conn_data_ind(struct rtp_conn *conn, uint8_t frame_nr, uint8_t fqc, uint8_t rfci,
const uint8_t *payload, uint32_t len)
{
struct hnb_audio_prim *audio_prim;
int rc;
LOGUE(conn->ue, DLLSK, LOGL_INFO, "Tx AUDIO-CONN_DATA.ind\n");
audio_prim = hnb_audio_makeprim_conn_data_ind(conn->id, payload, len);
LOGUE(conn->ue, DLLSK, LOGL_DEBUG, "Tx AUDIO-CONN_DATA.ind conn_id=%u fn=%u fqc=%u rfci=%u data_len=%u\n",
conn->id, frame_nr, fqc, rfci, len);
audio_prim = hnb_audio_makeprim_conn_data_ind(conn->id, frame_nr, fqc, rfci, payload, len);
if ((rc = osmo_prim_srv_send(conn->ue->hnb->llsk, audio_prim->hdr.msg)) < 0)
LOGUE(conn->ue, DLLSK, LOGL_ERROR, "Failed sending AUDIO-CONN_DATA.ind\n");
return rc;
@ -186,7 +191,7 @@ static int llsk_rx_audio_conn_establish_req(struct hnb *hnb, struct hnb_audio_co
/* Create the socket: */
conn = rtp_conn_alloc(ue);
if ((rc = rtp_conn_setup(conn, &rem_osa)) < 0) {
if ((rc = rtp_conn_setup(conn, &rem_osa, ce_req)) < 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);
@ -248,14 +253,8 @@ static int llsk_rx_audio_conn_data_req(struct hnb *hnb, struct hnb_audio_conn_da
return -EINVAL;
}
/* TODO: transmit data_req->data through RTP/Iu-UP socket */
rc = osmo_rtp_send_frame_ext(conn->socket, data_req->data,
data_req->data_len, GSM_RTP_DURATION, false);
if (rc < 0) {
LOGUE(conn->ue, DLLSK, LOGL_ERROR,
"Rx AUDIO-CONN_DATA.req: Failed sending RTP frame! id=%u data_len=%u\n",
data_req->audio_conn_id, data_req->data_len);
}
/* Transmit data_req->data through RTP/Iu-UP socket */
rc = rtp_conn_tx_data(conn, data_req->frame_nr, data_req->fqc, data_req->rfci, data_req->data, data_req->data_len);
return rc;
}

View File

@ -22,14 +22,88 @@
#include <errno.h>
#include <sys/socket.h>
#include <osmocom/gsm/prim.h>
#include <osmocom/gsm/iuup.h>
#include <osmocom/trau/osmo_ortp.h>
#include <osmocom/hnodeb/rtp.h>
#include <osmocom/hnodeb/hnodeb.h>
#define HNB_IUUP_MSGB_SIZE 4096
static struct osmo_iuup_rnl_prim *llsk_audio_ce_to_iuup_rnl_cfg(void *ctx, const struct hnb_audio_conn_establish_req_param *ce_req)
{
struct osmo_iuup_rnl_prim *irp;
struct osmo_iuup_rnl_config *cfg;
unsigned int i;
irp = osmo_iuup_rnl_prim_alloc(ctx, OSMO_IUUP_RNL_CONFIG, PRIM_OP_REQUEST, HNB_IUUP_MSGB_SIZE);
cfg = &irp->u.config;
cfg->transparent = !!ce_req->transparent;
cfg->active = true;
cfg->data_pdu_type = ce_req->data_pdu_type;
cfg->supported_versions_mask = ce_req->supported_versions_mask;
cfg->num_rfci = ce_req->num_rfci;
cfg->num_subflows = ce_req->num_subflows;
OSMO_ASSERT(cfg->num_rfci <= ARRAY_SIZE(cfg->subflow_sizes));
OSMO_ASSERT(cfg->num_subflows <= ARRAY_SIZE(cfg->subflow_sizes[0]));
for (i = 0; i < cfg->num_rfci; i++)
memcpy(&cfg->subflow_sizes[i][0], &ce_req->subflow_sizes[i][0], cfg->num_subflows*sizeof(uint16_t));
cfg->IPTIs_present = ce_req->IPTIs_present;
if (cfg->IPTIs_present)
memcpy(cfg->IPTIs, ce_req->IPTIs, cfg->num_rfci);
cfg->t_init = (struct osmo_iuup_rnl_config_timer){ .t_ms = IUUP_TIMER_INIT_T_DEFAULT, .n_max = IUUP_TIMER_INIT_N_DEFAULT };
cfg->t_ta = (struct osmo_iuup_rnl_config_timer){ .t_ms = IUUP_TIMER_TA_T_DEFAULT, .n_max = IUUP_TIMER_TA_N_DEFAULT };
cfg->t_rc = (struct osmo_iuup_rnl_config_timer){ .t_ms = IUUP_TIMER_RC_T_DEFAULT, .n_max = IUUP_TIMER_RC_N_DEFAULT };
return irp;
}
static int _iuup_user_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
{
struct rtp_conn *conn = (struct rtp_conn *)ctx;
struct osmo_iuup_rnl_prim *irp = (struct osmo_iuup_rnl_prim *)oph;
struct msgb *msg = oph->msg;
int rc;
switch (OSMO_PRIM_HDR(&irp->oph)) {
case OSMO_PRIM(OSMO_IUUP_RNL_DATA, PRIM_OP_INDICATION):
rc = llsk_audio_tx_conn_data_ind(conn, irp->u.data.frame_nr, irp->u.data.fqc,
irp->u.data.rfci, msgb_l3(msg), msgb_l3len(msg));
break;
default:
LOGUE(conn->ue, DRTP, LOGL_NOTICE, "Rx Unknown prim=%u op=%u from IuUP layer",
irp->oph.primitive, irp->oph.operation);
rc = -1;
}
msgb_free(msg);
return rc;
}
static int _iuup_transport_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
{
struct rtp_conn *conn = (struct rtp_conn *)ctx;
struct msgb *msg = oph->msg;
int rc;
rc = osmo_rtp_send_frame_ext(conn->socket, msgb_l2(msg), msgb_l2len(msg),
GSM_RTP_DURATION, false);
if (rc < 0) {
LOGUE(conn->ue, DLLSK, LOGL_ERROR,
"Rx IuUP Transport UNITDATA.req: Failed sending RTP frame! id=%u data_len=%u\n",
conn->id, msgb_l2len(msg));
}
msgb_free(msg);
return rc;
}
struct rtp_conn *rtp_conn_alloc(struct hnb_ue *ue)
{
struct rtp_conn *conn;
char iuup_id[64];
conn = talloc_zero(ue, struct rtp_conn);
if (!conn)
@ -37,6 +111,11 @@ struct rtp_conn *rtp_conn_alloc(struct hnb_ue *ue)
conn->ue = ue;
snprintf(iuup_id, sizeof(iuup_id), "ue-%u", conn->ue->conn_id);
conn->iui = osmo_iuup_instance_alloc(conn, iuup_id);
osmo_iuup_instance_set_user_prim_cb(conn->iui, _iuup_user_prim_cb, conn);
osmo_iuup_instance_set_transport_prim_cb(conn->iui, _iuup_transport_prim_cb, conn);
llist_add(&conn->list, &ue->conn_cs.conn_list);
return conn;
@ -51,6 +130,10 @@ void rtp_conn_free(struct rtp_conn *conn)
osmo_rtp_socket_free(conn->socket);
conn->socket = NULL;
}
if (conn->iui) {
osmo_iuup_instance_free(conn->iui);
conn->iui = NULL;
}
llist_del(&conn->list);
talloc_free(conn);
}
@ -158,13 +241,23 @@ static void rtp_rx_cb(struct osmo_rtp_socket *rs, const uint8_t *rtp_pl,
uint32_t timestamp, bool marker)
{
struct rtp_conn *conn = (struct rtp_conn *)rs->priv;
struct osmo_iuup_tnl_prim *itp;
int rc;
LOGUE(conn->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(conn, rtp_pl, rtp_pl_len);
itp = osmo_iuup_tnl_prim_alloc(conn, OSMO_IUUP_TNL_UNITDATA, PRIM_OP_INDICATION, HNB_IUUP_MSGB_SIZE);
itp->oph.msg->l2h = msgb_put(itp->oph.msg, rtp_pl_len);
memcpy(itp->oph.msg->l2h, rtp_pl, rtp_pl_len);
rc = osmo_iuup_tnl_prim_up(conn->iui, itp);
if (rc < 0)
LOGUE(conn->ue, DRTP, LOGL_NOTICE,
"Failed passing rx rtp up to IuUP layer: %d\n", rc);
}
int rtp_conn_setup(struct rtp_conn *conn, const struct osmo_sockaddr *rem_addr)
int rtp_conn_setup(struct rtp_conn *conn, const struct osmo_sockaddr *rem_addr,
const struct hnb_audio_conn_establish_req_param *ce_req)
{
int rc;
char cname[256+4];
@ -173,6 +266,7 @@ int rtp_conn_setup(struct rtp_conn *conn, const struct osmo_sockaddr *rem_addr)
const char *local_wildcard_ipstr = "0.0.0.0";
char remote_ipstr[INET6_ADDRSTRLEN];
uint16_t remote_port;
struct osmo_iuup_rnl_prim *irp;
struct hnb_ue *ue = conn->ue;
struct hnb *hnb = ue->hnb;
@ -231,9 +325,30 @@ int rtp_conn_setup(struct rtp_conn *conn, const struct osmo_sockaddr *rem_addr)
goto free_ret;
}
/* Now configure the IuUP layer: */
irp = llsk_audio_ce_to_iuup_rnl_cfg(conn, ce_req);
rc = osmo_iuup_rnl_prim_down(conn->iui, irp);
if (rc < 0) {
LOGUE(ue, DRTP, LOGL_ERROR, "Failed setting up IuUP layer: %d\n", rc);
goto free_ret;
}
return rc;
free_ret:
osmo_rtp_socket_free(conn->socket);
conn->socket = NULL;
return rc;
}
int rtp_conn_tx_data(struct rtp_conn *conn, uint8_t frame_nr, uint8_t fqc, uint8_t rfci, const uint8_t *data, unsigned int data_len)
{
struct osmo_iuup_rnl_prim *irp;
irp = osmo_iuup_rnl_prim_alloc(conn, OSMO_IUUP_RNL_DATA, PRIM_OP_REQUEST, HNB_IUUP_MSGB_SIZE);
irp->u.data.rfci = rfci;
irp->u.data.frame_nr = frame_nr;
irp->u.data.fqc = fqc;
irp->oph.msg->l3h = msgb_put(irp->oph.msg, data_len);
memcpy(irp->oph.msg->l3h, data, data_len);
return osmo_iuup_rnl_prim_down(conn->iui, irp);
}