diff --git a/TODO-RELEASE b/TODO-RELEASE index 9e75c9a..d847efe 100644 --- a/TODO-RELEASE +++ b/TODO-RELEASE @@ -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 diff --git a/include/osmocom/hnodeb/hnb_prim.h b/include/osmocom/hnodeb/hnb_prim.h index 0b0a545..ba3223d 100644 --- a/include/osmocom/hnodeb/hnb_prim.h +++ b/include/osmocom/hnodeb/hnb_prim.h @@ -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)); diff --git a/include/osmocom/hnodeb/llsk.h b/include/osmocom/hnodeb/llsk.h index fe1dce1..78eb065 100644 --- a/include/osmocom/hnodeb/llsk.h +++ b/include/osmocom/hnodeb/llsk.h @@ -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); diff --git a/include/osmocom/hnodeb/rtp.h b/include/osmocom/hnodeb/rtp.h index 8035175..5eaec7b 100644 --- a/include/osmocom/hnodeb/rtp.h +++ b/include/osmocom/hnodeb/rtp.h @@ -18,8 +18,11 @@ */ #pragma once +#include + #include #include +#include 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); diff --git a/src/osmo-hnodeb/llsk_audio.c b/src/osmo-hnodeb/llsk_audio.c index a600c3c..da54d28 100644 --- a/src/osmo-hnodeb/llsk_audio.c +++ b/src/osmo-hnodeb/llsk_audio.c @@ -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; } diff --git a/src/osmo-hnodeb/rtp.c b/src/osmo-hnodeb/rtp.c index 41fb668..0435c81 100644 --- a/src/osmo-hnodeb/rtp.c +++ b/src/osmo-hnodeb/rtp.c @@ -22,14 +22,88 @@ #include #include +#include +#include #include #include #include +#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); +}