audio: Introduce SAPI v1 with unordered RFCI support

This commit introduces support for the new llsk_audio SAPI v1.
This new version is almost the same as v0, with the exception that
primitive <REQUEST,HNB_AUDIO_PRIM_CONN_ESTABLISH> wins an extra field
appended at the end:
"""
uint8_t rfci[HNB_MAX_RFCIS]; /* values range 6 bits */
"""

This allows lowerlayers to provide an unordered array of RFCIs, which
was seen may happen under some conditions. For instance:
"""
rfci[HNB_MAX_RFCIS] = { 2, 3, 1};
[0] RFCI 2
[1] RFCI 3
[2] RFCI 1
"""

OsmoHNodeB still supports v0 if the lowerlayer asks for it, and will
continue having the exact behavior as before in this case (using
position in the array as RFCI). Hence, no compatibility breakage occurs
in this patch. New clients, on the other hand, can provide the extra
information by announcing V1 support during version negotiation at
startup.

Related: SYS#5516
Change-Id: I860d18b80c1041bf63a1570d435e0568c0f6b01b
This commit is contained in:
Pau Espin 2022-06-08 18:33:17 +02:00
parent 780def0114
commit f320ac5841
5 changed files with 64 additions and 29 deletions

View File

@ -188,7 +188,7 @@ enum hnb_audio_prim_type {
/* HNB_AUDIO_PRIM_CONN_ESTABLISH, UL */ /* HNB_AUDIO_PRIM_CONN_ESTABLISH, UL */
#define HNB_MAX_RFCIS 64 #define HNB_MAX_RFCIS 64
#define HNB_MAX_SUBFLOWS 7 #define HNB_MAX_SUBFLOWS 7
struct hnb_audio_conn_establish_req_param { struct hnb_audio_conn_establish_req_param_v0 {
uint32_t context_id; uint32_t context_id;
uint16_t remote_rtp_port; uint16_t remote_rtp_port;
uint8_t spare1; uint8_t spare1;
@ -204,6 +204,16 @@ struct hnb_audio_conn_establish_req_param {
uint8_t IPTIs_present; /* 1=present; 0=not present */ uint8_t IPTIs_present; /* 1=present; 0=not present */
uint8_t IPTIs[HNB_MAX_RFCIS]; /* values range 0-15, 4 bits */ uint8_t IPTIs[HNB_MAX_RFCIS]; /* values range 0-15, 4 bits */
} __attribute__ ((packed)); } __attribute__ ((packed));
struct hnb_audio_conn_establish_req_param_v1 {
struct hnb_audio_conn_establish_req_param_v0 v0;
uint8_t rfci[HNB_MAX_RFCIS]; /* values range 6 bits */
} __attribute__ ((packed));
struct hnb_audio_conn_establish_req_param {
union {
struct hnb_audio_conn_establish_req_param_v0 v0;
struct hnb_audio_conn_establish_req_param_v1 v1;
} __attribute__ ((packed));
} __attribute__ ((packed));
/* HNB_AUDIO_PRIM_CONN_ESTABLISH, DL */ /* HNB_AUDIO_PRIM_CONN_ESTABLISH, DL */
struct hnb_audio_conn_establish_cnf_param { struct hnb_audio_conn_establish_cnf_param {

View File

@ -51,8 +51,9 @@ struct hnb_iuh_prim *hnb_iuh_makeprim_conn_data_ind(uint32_t context_id,
struct hnb_iuh_prim *hnb_iuh_makeprim_unitdata_ind(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);
#define LLSK_SAPI_AUDIO_VERSION_MIN 0 #define LLSK_SAPI_AUDIO_VERSION_MIN 0
#define LLSK_SAPI_AUDIO_VERSION_MAX 0 #define LLSK_SAPI_AUDIO_VERSION_MAX 1
extern const struct value_string hnb_audio_prim_type_names[]; extern const struct value_string hnb_audio_prim_type_names[];
int llsk_audio_sapi_version_confirmed(uint16_t sapi_version);
int llsk_rx_audio(struct hnb *hnb, struct osmo_prim_hdr *oph); int llsk_rx_audio(struct hnb *hnb, struct osmo_prim_hdr *oph);
int llsk_audio_tx_conn_data_ind(struct rtp_conn *conn, uint8_t frame_nr, uint8_t fqc, uint8_t rfci, 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); const uint8_t *payload, uint32_t len);

View File

@ -167,6 +167,8 @@ static int llsk_rx_sapi_version_cb(struct osmo_prim_srv *prim_srv, uint32_t sapi
return -1; return -1;
if (rem_version > LLSK_SAPI_AUDIO_VERSION_MAX) if (rem_version > LLSK_SAPI_AUDIO_VERSION_MAX)
return LLSK_SAPI_AUDIO_VERSION_MAX; return LLSK_SAPI_AUDIO_VERSION_MAX;
if (llsk_audio_sapi_version_confirmed(hnb->llsk.sapi_version_audio) < 0)
return -1;
hnb->llsk.sapi_version_audio = rem_version; hnb->llsk.sapi_version_audio = rem_version;
break; break;
default: default:

View File

@ -68,6 +68,24 @@ const struct value_string hnb_audio_prim_type_names[] = {
{ 0, NULL } { 0, NULL }
}; };
int llsk_audio_sapi_version_confirmed(uint16_t sapi_version)
{
/* Update primitive size expectancies based on SAPI version: */
switch (sapi_version) {
case 0:
llsk_audio_prim_size_tbl[PRIM_OP_REQUEST][HNB_AUDIO_PRIM_CONN_ESTABLISH] =
sizeof(struct hnb_audio_conn_establish_req_param_v0);
break;
case 1:
llsk_audio_prim_size_tbl[PRIM_OP_REQUEST][HNB_AUDIO_PRIM_CONN_ESTABLISH] =
sizeof(struct hnb_audio_conn_establish_req_param_v1);
break;
default:
return -1;
}
return 0;
}
static struct hnb_audio_prim *hnb_audio_prim_alloc(enum hnb_audio_prim_type ptype, enum osmo_prim_operation op, size_t extra_len) 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; struct osmo_prim_hdr *oph;
@ -159,34 +177,35 @@ static int llsk_rx_audio_conn_establish_req(struct hnb *hnb, struct hnb_audio_co
union u_addr loc_uaddr = {0}; union u_addr loc_uaddr = {0};
uint16_t loc_port = 0; uint16_t loc_port = 0;
struct rtp_conn *conn = NULL; struct rtp_conn *conn = NULL;
struct hnb_audio_conn_establish_req_param_v0 *v0 = &ce_req->v0;
rc = ll_addr2osa(ce_req->remote_rtp_address_type, &ce_req->remote_rtp_addr, ce_req->remote_rtp_port, &rem_osa); rc = ll_addr2osa(v0->remote_rtp_address_type, &v0->remote_rtp_addr, v0->remote_rtp_port, &rem_osa);
if (rc < 0) { if (rc < 0) {
LOGP(DLLSK, LOGL_ERROR, "Rx AUDIO-CONN_ESTABLISH.req: ctx=%u with unexpected address type %u\n", 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); v0->context_id, v0->remote_rtp_address_type);
return _send_conn_establish_cnf_failed(hnb, ce_req->context_id, 1); return _send_conn_establish_cnf_failed(hnb, v0->context_id, 1);
} }
osmo_sockaddr_to_str_buf(rem_addrstr, sizeof(rem_addrstr), &rem_osa); 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", LOGP(DLLSK, LOGL_INFO, "Rx AUDIO-CONN_ESTABLISH.req ctx=%u rem_addr=%s\n",
ce_req->context_id, rem_addrstr); v0->context_id, rem_addrstr);
if ((af = ll_addr_type2af(ce_req->remote_rtp_address_type)) < 0) { if ((af = ll_addr_type2af(v0->remote_rtp_address_type)) < 0) {
LOGP(DLLSK, LOGL_ERROR, "Rx AUDIO-CONN_ESTABLISH.req: ctx=%u with unexpected address type %u\n", 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); v0->context_id, v0->remote_rtp_address_type);
return _send_conn_establish_cnf_failed(hnb, ce_req->context_id, 1); return _send_conn_establish_cnf_failed(hnb, v0->context_id, 1);
} }
ue = hnb_find_ue_by_id(hnb, ce_req->context_id); ue = hnb_find_ue_by_id(hnb, v0->context_id);
if (!ue) { if (!ue) {
LOGP(DLLSK, LOGL_ERROR, "Rx AUDIO-CONN_ESTABLISH.req: UE not found! ctx=%u rem_addr=%s\n", LOGP(DLLSK, LOGL_ERROR, "Rx AUDIO-CONN_ESTABLISH.req: UE not found! ctx=%u rem_addr=%s\n",
ce_req->context_id, rem_addrstr); v0->context_id, rem_addrstr);
return _send_conn_establish_cnf_failed(hnb, ce_req->context_id, 2); return _send_conn_establish_cnf_failed(hnb, v0->context_id, 2);
} }
if (!ue->conn_cs.active) { if (!ue->conn_cs.active) {
LOGUE(ue, DLLSK, LOGL_ERROR, "Rx AUDIO-CONN_ESTABLISH.req: CS chan not active! rem_addr=%s\n", LOGUE(ue, DLLSK, LOGL_ERROR, "Rx AUDIO-CONN_ESTABLISH.req: CS chan not active! rem_addr=%s\n",
rem_addrstr); rem_addrstr);
return _send_conn_establish_cnf_failed(hnb, ce_req->context_id, 3); return _send_conn_establish_cnf_failed(hnb, v0->context_id, 3);
} }
/* Create the socket: */ /* Create the socket: */
@ -194,22 +213,22 @@ static int llsk_rx_audio_conn_establish_req(struct hnb *hnb, struct hnb_audio_co
if ((rc = rtp_conn_setup(conn, &rem_osa, ce_req)) < 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", LOGUE(ue, DLLSK, LOGL_ERROR, "Rx AUDIO-CONN_ESTABLISH.req: Failed to set up audio socket rem_addr=%s\n",
rem_addrstr); rem_addrstr);
return _send_conn_establish_cnf_failed(hnb, ce_req->context_id, 4); return _send_conn_establish_cnf_failed(hnb, v0->context_id, 4);
} }
/* Convert resulting local address back to LLSK format: */ /* Convert resulting local address back to LLSK format: */
if (osa2_ll_addr(&conn->loc_addr, &loc_uaddr, &loc_port) != ce_req->remote_rtp_address_type) { if (osa2_ll_addr(&conn->loc_addr, &loc_uaddr, &loc_port) != v0->remote_rtp_address_type) {
LOGUE(ue, DLLSK, LOGL_ERROR, "Rx AUDIO-CONN_ESTABLISH.req: Failed to provide proper local address rem_addr=%s\n", LOGUE(ue, DLLSK, LOGL_ERROR, "Rx AUDIO-CONN_ESTABLISH.req: Failed to provide proper local address rem_addr=%s\n",
rem_addrstr); rem_addrstr);
rc = _send_conn_establish_cnf_failed(hnb, ce_req->context_id, 4); rc = _send_conn_establish_cnf_failed(hnb, v0->context_id, 4);
goto release_sock; goto release_sock;
} }
/* Submit successful confirmation */ /* Submit successful confirmation */
LOGUE(ue, DLLSK, LOGL_INFO, "Tx AUDIO-CONN_ESTABLISH.cnf: error_code=0 rem_addr=%s loc_addr=%s\n", 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(&conn->loc_addr)); rem_addrstr, osmo_sockaddr_to_str(&conn->loc_addr));
audio_prim = hnb_audio_makeprim_conn_establish_cnf(ce_req->context_id, conn->id, 0, loc_port, audio_prim = hnb_audio_makeprim_conn_establish_cnf(v0->context_id, conn->id, 0, loc_port,
ce_req->remote_rtp_address_type, &loc_uaddr); v0->remote_rtp_address_type, &loc_uaddr);
if ((rc = osmo_prim_srv_send(hnb->llsk.srv, audio_prim->hdr.msg)) < 0) { if ((rc = osmo_prim_srv_send(hnb->llsk.srv, audio_prim->hdr.msg)) < 0) {
LOGUE(ue, DLLSK, LOGL_ERROR, "Failed sending AUDIO-CONN_ESTABLISH.cnf error_code=0\n"); LOGUE(ue, DLLSK, LOGL_ERROR, "Failed sending AUDIO-CONN_ESTABLISH.cnf error_code=0\n");
goto release_sock; goto release_sock;

View File

@ -31,30 +31,33 @@
#define HNB_IUUP_MSGB_SIZE 4096 #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) static struct osmo_iuup_rnl_prim *llsk_audio_ce_to_iuup_rnl_cfg(struct rtp_conn *conn, const struct hnb_audio_conn_establish_req_param *ce_req)
{ {
struct osmo_iuup_rnl_prim *irp; struct osmo_iuup_rnl_prim *irp;
struct osmo_iuup_rnl_config *cfg; struct osmo_iuup_rnl_config *cfg;
unsigned int i; unsigned int i;
const struct hnb_audio_conn_establish_req_param_v0 *v0 = &ce_req->v0;
const struct hnb *hnb = conn->ue->hnb;
irp = osmo_iuup_rnl_prim_alloc(ctx, OSMO_IUUP_RNL_CONFIG, PRIM_OP_REQUEST, HNB_IUUP_MSGB_SIZE); irp = osmo_iuup_rnl_prim_alloc(conn, OSMO_IUUP_RNL_CONFIG, PRIM_OP_REQUEST, HNB_IUUP_MSGB_SIZE);
cfg = &irp->u.config; cfg = &irp->u.config;
cfg->transparent = !!ce_req->transparent; cfg->transparent = !!v0->transparent;
cfg->active = true; cfg->active = true;
cfg->data_pdu_type = ce_req->data_pdu_type; cfg->data_pdu_type = v0->data_pdu_type;
cfg->supported_versions_mask = ce_req->supported_versions_mask; cfg->supported_versions_mask = v0->supported_versions_mask;
cfg->num_rfci = ce_req->num_rfci; cfg->num_rfci = v0->num_rfci;
cfg->num_subflows = ce_req->num_subflows; cfg->num_subflows = v0->num_subflows;
cfg->IPTIs_present = ce_req->IPTIs_present; cfg->IPTIs_present = v0->IPTIs_present;
OSMO_ASSERT(cfg->num_rfci <= ARRAY_SIZE(cfg->rfci)); OSMO_ASSERT(cfg->num_rfci <= ARRAY_SIZE(cfg->rfci));
OSMO_ASSERT(cfg->num_subflows <= ARRAY_SIZE(cfg->rfci[0].subflow_sizes)); OSMO_ASSERT(cfg->num_subflows <= ARRAY_SIZE(cfg->rfci[0].subflow_sizes));
for (i = 0; i < cfg->num_rfci; i++) { for (i = 0; i < cfg->num_rfci; i++) {
cfg->rfci[i].used = true; cfg->rfci[i].used = true;
cfg->rfci[i].id = i; /* Assume RFC ID from position, llsk_audio doesn't provide info */ /* llsk_audio v0 doesn't provide info, assume RFC ID from position: */
cfg->rfci[i].id = (hnb->llsk.sapi_version_audio > 0) ? ce_req->v1.rfci[i] : i;
if (cfg->IPTIs_present) if (cfg->IPTIs_present)
cfg->rfci[i].IPTI = ce_req->IPTIs[i]; cfg->rfci[i].IPTI = v0->IPTIs[i];
if (cfg->num_subflows > 0) if (cfg->num_subflows > 0)
memcpy(&cfg->rfci[i].subflow_sizes[0], &ce_req->subflow_sizes[i][0], cfg->num_subflows*sizeof(uint16_t)); memcpy(&cfg->rfci[i].subflow_sizes[0], &v0->subflow_sizes[i][0], cfg->num_subflows*sizeof(uint16_t));
} }
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_init = (struct osmo_iuup_rnl_config_timer){ .t_ms = IUUP_TIMER_INIT_T_DEFAULT, .n_max = IUUP_TIMER_INIT_N_DEFAULT };