Update AUDIO and GTP SAPs to support multiple conns per UE

This is needed for instance:
* AUDIO: video calls
* GTP: secondary pdp contexts

For better abstraction, now both AUDIO and GTP conns use unique ID
namespaces, and one ID is used to identify each one. Each conn relate in
turn to a UE since a context_id is passed during connection
establishment.

Related: SYS#5516
Change-Id: Ib3f60d5ba21defe5259c25e2034fc2217c4d93df
This commit is contained in:
Pau Espin 2021-12-14 18:19:13 +01:00
parent ecc76ef69a
commit 7550ba3d05
11 changed files with 265 additions and 177 deletions

View File

@ -43,19 +43,19 @@ msc {
--- [ label = "Subscriber set up PS data:" ];
hnodeb <= hnbgw [label="RANAP RAB-Assignment Request(TEI, ADDR)"];
trx <= hnodeb [label="IUH-CONN_DATA.ind[RANAP RAB-Assignment Request(remote_ip, remote_port, remote_tei)]"];
trx => hnodeb [label="GTP-CONN_ESTABLISH.req(remote_ip,remote_port,remote_tei)"];
trx => hnodeb [label="GTP-CONN_ESTABLISH.req(context_id,remote_ip,remote_port,remote_tei)"];
... [ label = "HnodeB sets up GTP-U connection" ];
trx <= hnodeb [label="GTP-CONN_ESTABLISH.cnf(local_ip,local_port,local_tei,remote_tei)"];
trx <= hnodeb [label="GTP-CONN_ESTABLISH.cnf(context_id,gtp_conn_id,local_ip,local_port,local_tei)"];
|||;
...;
|||;
|||;
--- [ label = "PS data transmission over GTP-U:" ];
ue => trx [label="..."];
trx => hnodeb [label="GTP-CONN_DATA.req[remote_tei,payload]"];
trx => hnodeb [label="GTP-CONN_DATA.req[gtp_conn_id,payload]"];
hnodeb => ggsn [label="GTP-U(remote_tei, local_addr, remote_addr, payload)"];
hnodeb <= ggsn [label="GTP-U(local_tei, remote_addr, local_addr, payload)"];
trx <= hnodeb [label="GTP-CONN_DATA.ind[local_tei,payload]"];
trx <= hnodeb [label="GTP-CONN_DATA.ind[gtp_conn_id,payload]"];
ue <= trx [label="..."];
|||;
...;
@ -67,7 +67,7 @@ msc {
hnodeb <= hnbgw [label="RANAP IU Release Command"];
trx <= hnodeb [label="IUH-CONN_DATA.ind[RANAP IU Release Command]"];
...;
trx => hnodeb [label="GTP-CONN_RELEASE.req(remote_tei)"];
trx => hnodeb [label="GTP-CONN_RELEASE.req(gtp_conn_id)"];
trx => hnodeb [label="IUH-CONN_RELEASE.req[RANAP IU Release Complete]"];
hnodeb => hnbgw [label="RUA-Disconnect(RANAP IU Release Complete)"];

View File

@ -18,7 +18,11 @@
*/
#pragma once
#include <gtp.h>
#include <pdp.h>
#include <osmocom/core/socket.h>
#include <osmocom/core/linuxlist.h>
struct hnb;
struct hnb_ue;
@ -26,7 +30,19 @@ struct hnb_ue;
int hnb_gtp_bind(struct hnb *hnb);
void hnb_gtp_unbind(struct hnb *hnb);
int hnb_ue_gtp_bind(struct hnb_ue *ue, const struct osmo_sockaddr *rem_addr, uint32_t rem_tei,
struct osmo_sockaddr *loc_addr, uint32_t *loc_tei);
int hnb_ue_gtp_unbind(struct hnb_ue *ue);
int hnb_ue_gtp_tx(struct hnb_ue *ue, void *gtpu_payload, unsigned gtpu_payload_len);
struct gtp_conn {
struct llist_head list; /* Item in struct hnb->ue_list */
struct hnb_ue *ue; /* backpointer */
uint32_t id;
struct osmo_sockaddr loc_addr;
struct osmo_sockaddr rem_addr;
uint32_t loc_tei;
uint32_t rem_tei;
struct pdp_t *pdp_lib;
};
struct gtp_conn *gtp_conn_alloc(struct hnb_ue *ue);
void gtp_conn_free(struct gtp_conn *conn);
int gtp_conn_setup(struct gtp_conn *conn, const struct osmo_sockaddr *rem_addr, uint32_t rem_tei);
int gtp_conn_tx(struct gtp_conn *conn, void *gtpu_payload, unsigned gtpu_payload_len);

View File

@ -197,6 +197,7 @@ struct hnb_audio_conn_establish_req_param {
/* HNB_AUDIO_PRIM_CONN_ESTABLISH, DL */
struct hnb_audio_conn_establish_cnf_param {
uint32_t context_id;
uint32_t audio_conn_id;
uint16_t local_rtp_port;
uint8_t error_code; /* 0 = success, !0 = failure */
uint8_t local_rtp_address_type; /* enum u_addr_type */
@ -205,19 +206,19 @@ struct hnb_audio_conn_establish_cnf_param {
/* HNB_AUDIO_PRIM_CONN_RELEASE, UL */
struct hnb_audio_conn_release_req_param {
uint32_t context_id;
uint32_t audio_conn_id;
} __attribute__ ((packed));
/* HNB_AUDIO_PRIM_CONN_DATA, UL */
struct hnb_audio_conn_data_req_param {
uint32_t context_id;
uint32_t audio_conn_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 audio_conn_id;
uint32_t data_len; /* RTP payload length in bytes */
uint8_t data[0]; /* RTP payload (aka IP packet) */
} __attribute__ ((packed));
@ -256,6 +257,7 @@ struct hnb_gtp_conn_establish_req_param {
/* HNB_GTP_PRIM_CONN_ESTABLISH, DL */
struct hnb_gtp_conn_establish_cnf_param {
uint32_t context_id;
uint32_t gtp_conn_id;
uint32_t local_tei;
uint8_t error_code; /* 0 = success, !0 = failure */
uint8_t local_gtpu_address_type; /* enum u_addr_type */
@ -264,28 +266,19 @@ struct hnb_gtp_conn_establish_cnf_param {
/* HNB_GTP_PRIM_CONN_RELEASE, UL */
struct hnb_gtp_conn_release_req_param {
uint32_t context_id;
uint32_t remote_tei;
} __attribute__ ((packed));
/* HNB_GTP_PRIM_CONN_RELEASE, DL */
struct hnb_gtp_conn_release_ind_param {
uint32_t context_id;
uint32_t local_tei;
uint32_t gtp_conn_id;
} __attribute__ ((packed));
/* HNB_GTP_PRIM_CONN_DATA, DL */
struct hnb_gtp_conn_data_ind_param {
uint32_t context_id;
uint32_t local_tei;
uint32_t gtp_conn_id;
uint32_t data_len; /* GTP-U payload length in bytes */
uint8_t data[0]; /* GTP-U payload (aka IP packet) */
} __attribute__ ((packed));
/* HNB_GTP_PRIM_CONN_DATA, UL */
struct hnb_gtp_conn_data_req_param {
uint32_t context_id;
uint32_t remote_tei;
uint32_t gtp_conn_id;
uint32_t data_len; /* GTP-U payload length in bytes */
uint8_t data[0]; /* GTP-U payload (aka IP packet) */
} __attribute__ ((packed));

View File

@ -35,9 +35,6 @@
#include <osmocom/gsm/protocol/gsm_23_003.h>
#include <osmocom/netif/stream.h>
#include <gtp.h>
#include <pdp.h>
#include <osmocom/hnodeb/llsk.h>
enum {
@ -62,16 +59,12 @@ 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;
struct llist_head conn_list; /* list of struct rtp_conn */
} conn_cs;
struct hnb_ue_ps_ctx {
bool active; /* Is this chan in use? */
bool conn_est_cnf_pending; /* Did we send CONN_ESTABLISH_CNF to lower layers? */
uint32_t local_tei;
uint32_t remote_tei;
struct pdp_t *pdp_lib;
struct llist_head conn_list; /* list of struct gtp_conn */
} conn_ps;
};
struct hnb_ue *hnb_ue_alloc(struct hnb *hnb, uint32_t conn_id);
@ -132,9 +125,11 @@ struct hnb {
struct hnb *hnb_alloc(void *tall_ctx);
void hnb_free(struct hnb *hnb);
struct hnb_ue *hnb_find_ue_by_id(const struct hnb *hnb, uint32_t conn_id);
struct hnb_ue *hnb_find_ue_by_tei(const struct hnb *hnb, uint32_t tei, bool is_remote);
struct hnb_ue *hnb_find_ue_by_imsi(const struct hnb *hnb, char *imsi);
struct rtp_conn *hnb_find_rtp_conn_by_id(const struct hnb *hnb, uint32_t audio_conn_id);
struct gtp_conn *hnb_find_gtp_conn_by_id(const struct hnb *hnb, uint32_t gtp_conn_id);
extern void *tall_hnb_ctx;
extern struct hnb *g_hnb;

View File

@ -27,7 +27,7 @@
#include <osmocom/hnodeb/hnb_prim.h>
struct hnb;
struct hnb_ue;
struct rtp_conn;
int hnb_llsk_alloc(struct hnb *hnb);
bool hnb_llsk_connected(const struct hnb *hnb);
@ -53,9 +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 hnb_ue *ue, const uint8_t *payload, uint32_t len);
int llsk_audio_tx_conn_data_ind(struct rtp_conn *conn, 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);
struct hnb_gtp_prim *hnb_gtp_makeprim_conn_data_ind(uint32_t context_id, uint32_t local_tei,
const uint8_t *data, uint32_t data_len);
struct hnb_gtp_prim *hnb_gtp_makeprim_conn_data_ind(uint32_t gtp_conn_id, const uint8_t *data, uint32_t data_len);

View File

@ -19,9 +19,21 @@
#pragma once
#include <osmocom/core/socket.h>
#include <osmocom/core/linuxlist.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);
struct rtp_conn {
struct llist_head list; /* Item in struct hnb->ue_list */
struct hnb_ue *ue; /* backpointer */
uint32_t id;
struct osmo_rtp_socket *socket;
struct osmo_sockaddr loc_addr;
struct osmo_sockaddr rem_addr;
};
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);

View File

@ -27,8 +27,38 @@
#include <gtp.h>
#include <pdp.h>
static uint32_t next_gtp_conn_id = 0;
struct gtp_conn *gtp_conn_alloc(struct hnb_ue *ue)
{
struct gtp_conn *conn;
conn = talloc_zero(ue, struct gtp_conn);
if (!conn)
return NULL;
conn->ue = ue;
llist_add(&conn->list, &ue->conn_ps.conn_list);
return conn;
}
void gtp_conn_free(struct gtp_conn *conn)
{
if (!conn)
return;
if (conn->pdp_lib) {
pdp_freepdp(conn->pdp_lib);
conn->pdp_lib = NULL;
}
llist_del(&conn->list);
talloc_free(conn);
}
/* Get osa of locally bound GTP-U socket */
int sk_get_bound_addr(int fd, struct osmo_sockaddr *osa)
static int sk_get_bound_addr(int fd, struct osmo_sockaddr *osa)
{
int rc;
socklen_t alen = sizeof(*osa);
@ -44,19 +74,21 @@ int sk_get_bound_addr(int fd, struct osmo_sockaddr *osa)
static int hnb_gtp_cb_data_ind(struct pdp_t *lib, void *packet, unsigned int len)
{
struct hnb_gtp_prim *gtp_prim;
struct hnb_ue *ue = lib->priv;
struct gtp_conn *conn = lib->priv;
struct hnb_ue *ue;
struct hnb *hnb;
int rc;
if (!ue || !ue->conn_ps.active) {
LOGP(DGTP, LOGL_NOTICE, "Tx GTP-CONN_DATA.ind data=%p len=%u but UE conn_ps is not active!\n",
if (!conn || !conn->ue->conn_ps.active) {
LOGUE(conn->ue, DGTP, LOGL_NOTICE, "Tx GTP-CONN_DATA.ind data=%p len=%u but UE conn_ps is not active!\n",
packet, len);
return -EINVAL;
}
ue = conn->ue;
hnb = ue->hnb;
LOGUE(ue, DGTP, LOGL_DEBUG, "Tx GTP-CONN_DATA.ind data=%p len=%u\n", packet, len);
gtp_prim = hnb_gtp_makeprim_conn_data_ind(ue->conn_id, ue->conn_ps.local_tei, packet, len);
gtp_prim = hnb_gtp_makeprim_conn_data_ind(conn->id, packet, len);
if ((rc = osmo_prim_srv_send(hnb->llsk, gtp_prim->hdr.msg)) < 0) {
LOGUE(ue, DGTP, LOGL_ERROR, "Failed Tx GTP-CONN_DATA.ind data=%p len=%u\n",
packet, len);
@ -130,10 +162,10 @@ void hnb_gtp_unbind(struct hnb *hnb)
hnb->gtp.fd1u.fd = -1;
}
int hnb_ue_gtp_bind(struct hnb_ue *ue, const struct osmo_sockaddr *rem_addr, uint32_t rem_tei,
struct osmo_sockaddr *loc_addr, uint32_t *loc_tei)
int gtp_conn_setup(struct gtp_conn *conn, const struct osmo_sockaddr *rem_addr, uint32_t rem_tei)
{
int rc;
struct hnb_ue *ue = conn->ue;
struct hnb *hnb = ue->hnb;
struct pdp_t *pdp;
struct in_addr rem_in;
@ -147,15 +179,18 @@ int hnb_ue_gtp_bind(struct hnb_ue *ue, const struct osmo_sockaddr *rem_addr, uin
return -ENOTSUP;
}
conn->rem_addr = *rem_addr;
conn->rem_tei = rem_tei;
rem_in = rem_addr->u.sin.sin_addr;
conn->id = next_gtp_conn_id++; /* TODO: validate next one is not already taken due to wrap-around */
rc = gtp_pdp_newpdp(hnb->gtp.gsn, &pdp, ue->conn_id, 0 /* TODO: NSAPI? */, NULL);
rc = gtp_pdp_newpdp(hnb->gtp.gsn, &pdp, conn->id, 0 /* TODO: NSAPI? */, NULL);
if (rc < 0) {
LOGUE(ue, DGTP, LOGL_ERROR, "Failed creating PDP context: %s\n", strerror(-rc));
return rc;
}
pdp->priv = ue;
ue->conn_ps.pdp_lib = pdp;
pdp->priv = conn;
conn->pdp_lib = pdp;
pdp->teid_gn = rem_tei;
pdp->version = 1;
@ -170,40 +205,32 @@ int hnb_ue_gtp_bind(struct hnb_ue *ue, const struct osmo_sockaddr *rem_addr, uin
memcpy(pdp->gsnlu.v, &hnb->gtp.local_addr.u.sin.sin_addr,
sizeof(hnb->gtp.local_addr.u.sin.sin_addr));
*loc_addr = hnb->gtp.local_addr;
conn->loc_addr = hnb->gtp.local_addr;
//loc_addr->u.sin.sin_family = AF_INET;
//loc_addr->u.sin.sin_addr = hnb->gtp.gsn->gsnu;
//loc_addr->u.sin.sin_port = GTP1U_PORT;
*loc_tei = pdp->teid_own;
conn->loc_tei = pdp->teid_own;
return 0;
}
int hnb_ue_gtp_tx(struct hnb_ue *ue, void *gtpu_payload, unsigned gtpu_payload_len)
int gtp_conn_tx(struct gtp_conn *conn, void *gtpu_payload, unsigned gtpu_payload_len)
{
int rc;
struct hnb_ue *ue;
struct hnb *hnb;
if (!ue || !ue->conn_ps.pdp_lib) {
LOGUE(ue, DGTP, LOGL_ERROR, "Tx: UE PDP Ctx not available\n");
if (!conn || !conn->pdp_lib) {
LOGP(DGTP, LOGL_ERROR, "Tx: PDP Ctx not available\n");
return -EINVAL;
}
ue = conn->ue;
hnb = ue->hnb;
if (!hnb->gtp.gsn) {
LOGUE(ue, DGTP, LOGL_ERROR, "Tx: GTP socket not bound\n");
return -EINVAL;
}
rc = gtp_data_req(hnb->gtp.gsn, ue->conn_ps.pdp_lib, gtpu_payload, gtpu_payload_len);
rc = gtp_data_req(hnb->gtp.gsn, conn->pdp_lib, gtpu_payload, gtpu_payload_len);
return rc;
}
int hnb_ue_gtp_unbind(struct hnb_ue *ue)
{
if (!ue->conn_ps.pdp_lib)
return -EINVAL;
pdp_freepdp(ue->conn_ps.pdp_lib);
ue->conn_ps.pdp_lib = NULL;
return 0;
}

View File

@ -109,6 +109,9 @@ struct hnb_ue *hnb_ue_alloc(struct hnb *hnb, uint32_t conn_id)
ue->hnb = hnb;
ue->conn_id = conn_id;
INIT_LLIST_HEAD(&ue->conn_cs.conn_list);
INIT_LLIST_HEAD(&ue->conn_ps.conn_list);
llist_add(&ue->list, &hnb->ue_list);
return ue;
@ -125,11 +128,17 @@ void hnb_ue_free(struct hnb_ue *ue)
void hnb_ue_reset_chan(struct hnb_ue *ue, bool is_ps)
{
if (is_ps) {
hnb_ue_gtp_unbind(ue);
struct gtp_conn *conn, *conn_tmp;
llist_for_each_entry_safe(conn, conn_tmp, &ue->conn_ps.conn_list, list)
gtp_conn_free(conn);
ue->conn_ps = (struct hnb_ue_ps_ctx){0};
INIT_LLIST_HEAD(&ue->conn_ps.conn_list);
} else {
hnb_ue_voicecall_release(ue);
struct rtp_conn *conn, *conn_tmp;
llist_for_each_entry_safe(conn, conn_tmp, &ue->conn_cs.conn_list, list)
rtp_conn_free(conn);
ue->conn_cs = (struct hnb_ue_cs_ctx){0};
INIT_LLIST_HEAD(&ue->conn_cs.conn_list);
}
}
@ -145,21 +154,6 @@ struct hnb_ue *hnb_find_ue_by_id(const struct hnb *hnb, uint32_t conn_id)
return NULL;
}
struct hnb_ue *hnb_find_ue_by_tei(const struct hnb *hnb, uint32_t tei, bool is_remote)
{
struct hnb_ue *ue;
llist_for_each_entry(ue, &hnb->ue_list, list) {
if (!ue->conn_ps.active)
continue;
uint32_t ue_tei = is_remote ? ue->conn_ps.remote_tei : ue->conn_ps.local_tei;
if (tei != ue_tei)
continue;
return ue;
}
return NULL;
}
struct hnb_ue *hnb_find_ue_by_imsi(const struct hnb *hnb, char *imsi)
{
struct hnb_ue *ue;
@ -176,3 +170,35 @@ struct hnb_ue *hnb_find_ue_by_imsi(const struct hnb *hnb, char *imsi)
}
return NULL;
}
struct rtp_conn *hnb_find_rtp_conn_by_id(const struct hnb *hnb, uint32_t audio_conn_id)
{
struct hnb_ue *ue;
llist_for_each_entry(ue, &hnb->ue_list, list) {
struct rtp_conn *conn;
if (!ue->conn_cs.active)
continue;
llist_for_each_entry(conn, &ue->conn_cs.conn_list, list) {
if (conn->id == audio_conn_id)
return conn;
}
}
return NULL;
}
struct gtp_conn *hnb_find_gtp_conn_by_id(const struct hnb *hnb, uint32_t gtp_conn_id)
{
struct hnb_ue *ue;
llist_for_each_entry(ue, &hnb->ue_list, list) {
struct gtp_conn *conn;
if (!ue->conn_ps.active)
continue;
llist_for_each_entry(conn, &ue->conn_ps.conn_list, list) {
if (conn->id == gtp_conn_id)
return conn;
}
}
return NULL;
}

View File

@ -81,14 +81,16 @@ static struct hnb_audio_prim *hnb_audio_prim_alloc(enum hnb_audio_prim_type ptyp
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)
static struct hnb_audio_prim *hnb_audio_makeprim_conn_establish_cnf(uint32_t context_id, uint32_t audio_conn_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.audio_conn_id = audio_conn_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;
@ -98,15 +100,14 @@ static struct hnb_audio_prim *hnb_audio_makeprim_conn_establish_cnf(uint32_t con
return audio_prim;
}
static struct hnb_audio_prim *hnb_audio_makeprim_conn_data_ind(uint32_t context_id,
uint8_t domain,
static struct hnb_audio_prim *hnb_audio_makeprim_conn_data_ind(uint32_t audio_conn_id,
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.audio_conn_id = audio_conn_id;
audio_prim->u.conn_data_ind.data_len = data_len;
if (data_len) {
msgb_put(audio_prim->hdr.msg, data_len);
@ -116,15 +117,15 @@ static struct hnb_audio_prim *hnb_audio_makeprim_conn_data_ind(uint32_t context_
return audio_prim;
}
int llsk_audio_tx_conn_data_ind(struct hnb_ue *ue, const uint8_t *payload, uint32_t len)
int llsk_audio_tx_conn_data_ind(struct rtp_conn *conn, 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");
LOGUE(conn->ue, DLLSK, LOGL_INFO, "Tx AUDIO-CONN_DATA.ind\n");
audio_prim = hnb_audio_makeprim_conn_data_ind(conn->id, 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;
}
@ -134,7 +135,7 @@ static int _send_conn_establish_cnf_failed(struct hnb *hnb, uint32_t context_id,
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);
audio_prim = hnb_audio_makeprim_conn_establish_cnf(context_id, 0, 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);
@ -150,9 +151,9 @@ static int llsk_rx_audio_conn_establish_req(struct hnb *hnb, struct hnb_audio_co
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;
struct rtp_conn *conn = NULL;
rc = ll_addr2osa(ce_req->remote_rtp_address_type, &ce_req->remote_rtp_addr, ce_req->remote_rtp_port, &rem_osa);
if (rc < 0) {
@ -184,14 +185,15 @@ static int llsk_rx_audio_conn_establish_req(struct hnb *hnb, struct hnb_audio_co
}
/* Create the socket: */
if ((rc = hnb_ue_voicecall_setup(ue, &rem_osa, &loc_osa)) < 0) {
conn = rtp_conn_alloc(ue);
if ((rc = rtp_conn_setup(conn, &rem_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) {
if (osa2_ll_addr(&conn->loc_addr, &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);
@ -200,8 +202,8 @@ static int llsk_rx_audio_conn_establish_req(struct hnb *hnb, struct hnb_audio_co
/* 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,
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,
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");
@ -210,47 +212,49 @@ static int llsk_rx_audio_conn_establish_req(struct hnb *hnb, struct hnb_audio_co
return rc;
release_sock:
hnb_ue_voicecall_release(ue);
rtp_conn_free(conn);
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;
struct rtp_conn *conn;
LOGP(DLLSK, LOGL_DEBUG, "Rx AUDIO-CONN_RELEASE.req ctx=%u\n", rel_req->context_id);
LOGP(DLLSK, LOGL_DEBUG, "Rx AUDIO-CONN_RELEASE.req id=%u\n", rel_req->audio_conn_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);
conn = hnb_find_rtp_conn_by_id(hnb, rel_req->audio_conn_id);
if (!conn) {
LOGP(DLLSK, LOGL_ERROR, "Rx AUDIO-CONN_RELEASE.req: RTP conn not found! id=%u\n",
rel_req->audio_conn_id);
return -EINVAL;
}
/* Release RTP socket: */
return hnb_ue_voicecall_release(ue);
rtp_conn_free(conn);
return 0;
}
static int llsk_rx_audio_conn_data_req(struct hnb *hnb, struct hnb_audio_conn_data_req_param *data_req)
{
struct hnb_ue *ue;
struct rtp_conn *conn;
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);
LOGP(DLLSK, LOGL_DEBUG, "Rx AUDIO-CONN_DATA.req id=%u data_len=%u\n",
data_req->audio_conn_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);
conn = hnb_find_rtp_conn_by_id(hnb, data_req->audio_conn_id);
if (!conn) {
LOGP(DLLSK, LOGL_ERROR, "Rx AUDIO-CONN_DATA.req: RTP conn not found! id=%u data_len=%u\n",
data_req->audio_conn_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,
rc = osmo_rtp_send_frame_ext(conn->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);
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);
}
return rc;
}

View File

@ -79,14 +79,16 @@ static struct hnb_gtp_prim *hnb_gtp_prim_alloc(enum hnb_gtp_prim_type ptype, enu
return (struct hnb_gtp_prim *)oph;
}
static struct hnb_gtp_prim *hnb_gtp_makeprim_conn_establish_cnf(uint32_t context_id, uint8_t error_code,
uint32_t local_tei, uint8_t local_gtpu_address_type,
static struct hnb_gtp_prim *hnb_gtp_makeprim_conn_establish_cnf(uint32_t context_id, uint32_t gtp_conn_id,
uint8_t error_code, uint32_t local_tei,
uint8_t local_gtpu_address_type,
const union u_addr *local_gtpu_addr)
{
struct hnb_gtp_prim *gtp_prim;
gtp_prim = hnb_gtp_prim_alloc(HNB_GTP_PRIM_CONN_ESTABLISH, PRIM_OP_CONFIRM, 0);
gtp_prim->u.conn_establish_cnf.context_id = context_id;
gtp_prim->u.conn_establish_cnf.gtp_conn_id = gtp_conn_id;
gtp_prim->u.conn_establish_cnf.local_tei = local_tei;
gtp_prim->u.conn_establish_cnf.error_code = error_code;
gtp_prim->u.conn_establish_cnf.local_gtpu_address_type = local_gtpu_address_type;
@ -96,14 +98,12 @@ static struct hnb_gtp_prim *hnb_gtp_makeprim_conn_establish_cnf(uint32_t context
return gtp_prim;
}
struct hnb_gtp_prim *hnb_gtp_makeprim_conn_data_ind(uint32_t context_id, uint32_t local_tei,
const uint8_t *data, uint32_t data_len)
struct hnb_gtp_prim *hnb_gtp_makeprim_conn_data_ind(uint32_t gtp_conn_id, const uint8_t *data, uint32_t data_len)
{
struct hnb_gtp_prim *gtp_prim;
gtp_prim = hnb_gtp_prim_alloc(HNB_GTP_PRIM_CONN_DATA, PRIM_OP_INDICATION, data_len);
gtp_prim->u.conn_data_ind.context_id = context_id;
gtp_prim->u.conn_data_ind.local_tei = local_tei;
gtp_prim->u.conn_data_ind.gtp_conn_id = gtp_conn_id;
gtp_prim->u.conn_data_ind.data_len = data_len;
if (data_len) {
msgb_put(gtp_prim->hdr.msg, data_len);
@ -119,7 +119,7 @@ static int _send_conn_establish_cnf_failed(struct hnb *hnb, uint32_t context_id,
int rc;
LOGP(DLLSK, LOGL_ERROR, "Tx GTP-CONN_ESTABLISH.cnf: ctx=%u error_code=%u\n",
context_id, error_code);
gtp_prim = hnb_gtp_makeprim_conn_establish_cnf(context_id, error_code, 0, HNB_PRIM_ADDR_TYPE_UNSPEC, NULL);
gtp_prim = hnb_gtp_makeprim_conn_establish_cnf(context_id, 0, error_code, 0, HNB_PRIM_ADDR_TYPE_UNSPEC, NULL);
if ((rc = osmo_prim_srv_send(hnb->llsk, gtp_prim->hdr.msg)) < 0) {
LOGP(DLLSK, LOGL_ERROR, "Failed sending GTP-CONN_ESTABLISH.cnf context_id=%u error_code=%u\n",
context_id, error_code);
@ -135,9 +135,8 @@ static int llsk_rx_gtp_conn_establish_req(struct hnb *hnb, struct hnb_gtp_conn_e
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};
uint32_t loc_tei;
struct gtp_conn *conn = NULL;
rc = ll_addr2osa(ce_req->remote_gtpu_address_type, &ce_req->remote_gtpu_addr, GTP1U_PORT, &rem_osa);
if (rc < 0) {
@ -169,14 +168,15 @@ static int llsk_rx_gtp_conn_establish_req(struct hnb *hnb, struct hnb_gtp_conn_e
}
/* Create the socket: */
if ((rc = hnb_ue_gtp_bind(ue, &rem_osa, ce_req->remote_tei, &loc_osa, &loc_tei)) < 0) {
conn = gtp_conn_alloc(ue);
if ((rc = gtp_conn_setup(conn, &rem_osa, ce_req->remote_tei)) < 0) {
LOGUE(ue, DLLSK, LOGL_ERROR, "Rx GTP-CONN_ESTABLISH.req: Failed to set up gtp socket rem_tei=%u rem_addr=%s\n",
ce_req->remote_tei, 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, NULL) != ce_req->remote_gtpu_address_type) {
if (osa2_ll_addr(&conn->loc_addr, &loc_uaddr, NULL) != ce_req->remote_gtpu_address_type) {
LOGUE(ue, DLLSK, LOGL_ERROR, "Rx GTP-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);
@ -185,56 +185,53 @@ static int llsk_rx_gtp_conn_establish_req(struct hnb *hnb, struct hnb_gtp_conn_e
/* Submit successful confirmation */
LOGUE(ue, DLLSK, LOGL_INFO, "Tx GTP-CONN_ESTABLISH.cnf: error_code=0 rem_addr=%s rem_tei=%u loc_addr=%s local_tei=%u\n",
rem_addrstr, ce_req->remote_tei, osmo_sockaddr_to_str(&loc_osa), loc_tei);
gtp_prim = hnb_gtp_makeprim_conn_establish_cnf(ce_req->context_id, 0, loc_tei, ce_req->remote_gtpu_address_type, &loc_uaddr);
rem_addrstr, ce_req->remote_tei, osmo_sockaddr_to_str(&conn->loc_addr), conn->loc_tei);
gtp_prim = hnb_gtp_makeprim_conn_establish_cnf(ce_req->context_id, conn->id, 0, conn->loc_tei,
ce_req->remote_gtpu_address_type, &loc_uaddr);
if ((rc = osmo_prim_srv_send(hnb->llsk, gtp_prim->hdr.msg)) < 0) {
LOGUE(ue, DLLSK, LOGL_ERROR, "Failed sending GTP-CONN_ESTABLISH.cnf error_code=0\n");
goto release_sock;
}
ue->conn_ps.local_tei = loc_tei;
ue->conn_ps.remote_tei = ce_req->remote_tei;
return rc;
release_sock:
hnb_ue_gtp_unbind(ue);
gtp_conn_free(conn);
return rc;
}
static int llsk_rx_gtp_conn_release_req(struct hnb *hnb, struct hnb_gtp_conn_release_req_param *rel_req)
{
struct hnb_ue *ue;
struct gtp_conn *conn;
int rc = 0;
LOGP(DLLSK, LOGL_DEBUG, "Rx GTP-CONN_RELEASE.req ctx=%u\n", rel_req->context_id);
LOGP(DLLSK, LOGL_DEBUG, "Rx GTP-CONN_RELEASE.req id=%u\n", rel_req->gtp_conn_id);
ue = hnb_find_ue_by_id(hnb, rel_req->context_id);
if (!ue) {
LOGP(DLLSK, LOGL_ERROR, "Rx GTP-CONN_RELEASE.req: UE not found! ctx=%u\n",
rel_req->context_id);
conn = hnb_find_gtp_conn_by_id(hnb, rel_req->gtp_conn_id);
if (!conn) {
LOGP(DLLSK, LOGL_ERROR, "Rx GTP-CONN_RELEASE.req: GTP conn not found! id=%u\n",
rel_req->gtp_conn_id);
return -EINVAL;
}
/* release GTP pdp ctx: */
hnb_ue_gtp_unbind(ue);
gtp_conn_free(conn);
return rc;
}
static int llsk_rx_gtp_conn_data_req(struct hnb *hnb, struct hnb_gtp_conn_data_req_param *data_req)
{
struct hnb_ue *ue;
struct gtp_conn *conn;
int rc = 0;
LOGP(DLLSK, LOGL_DEBUG, "Rx GTP-CONN_DATA.req ctx=%u rem_tei=%u data_len=%u\n",
data_req->context_id, data_req->remote_tei, data_req->data_len);
LOGP(DLLSK, LOGL_DEBUG, "Rx GTP-CONN_DATA.req id=%u data_len=%u\n",
data_req->gtp_conn_id, data_req->data_len);
ue = hnb_find_ue_by_id(hnb, data_req->context_id);
if (!ue) {
LOGP(DLLSK, LOGL_ERROR, "Rx GTP-CONN_DATA.req: UE not found! ctx=%u data_len=%u\n",
data_req->context_id, data_req->data_len);
conn = hnb_find_gtp_conn_by_id(hnb, data_req->gtp_conn_id);
if (!conn) {
LOGP(DLLSK, LOGL_ERROR, "Rx GTP-CONN_DATA.req: GTP conn not found! id=%u data_len=%u\n",
data_req->gtp_conn_id, data_req->data_len);
return -EINVAL;
}
rc = hnb_ue_gtp_tx(ue, data_req->data, data_req->data_len);
rc = gtp_conn_tx(conn, data_req->data, data_req->data_len);
return rc;
}

View File

@ -27,6 +27,33 @@
#include <osmocom/hnodeb/rtp.h>
#include <osmocom/hnodeb/hnodeb.h>
struct rtp_conn *rtp_conn_alloc(struct hnb_ue *ue)
{
struct rtp_conn *conn;
conn = talloc_zero(ue, struct rtp_conn);
if (!conn)
return NULL;
conn->ue = ue;
llist_add(&conn->list, &ue->conn_cs.conn_list);
return conn;
}
void rtp_conn_free(struct rtp_conn *conn)
{
if (!conn)
return;
if (conn->socket) {
osmo_rtp_socket_free(conn->socket);
conn->socket = NULL;
}
llist_del(&conn->list);
talloc_free(conn);
}
/* 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)
@ -97,11 +124,13 @@ static int rtp_bind(struct hnb *hnb, struct osmo_rtp_socket *rs, const char *ip)
tries = (hnb->rtp.port_range_end - hnb->rtp.port_range_start) / 2;
for (i = 0; i < tries; i++) {
uint16_t port;
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);
port = hnb->rtp.port_range_next;
rc = osmo_rtp_socket_bind(rs, ip, port);
hnb->rtp.port_range_next += 2;
@ -118,7 +147,7 @@ static int rtp_bind(struct hnb *hnb, struct osmo_rtp_socket *rs, const char *ip)
LOGP(DRTP, LOGL_ERROR, "failed to set socket priority %d: %s\n",
hnb->rtp.priority, strerror(errno));
}
return 0;
return port;
}
return -1;
@ -128,14 +157,14 @@ 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;
struct rtp_conn *conn = (struct rtp_conn *)rs->priv;
LOGUE(ue, DRTP, LOGL_DEBUG, "Rx RTP seq=%u ts=%u M=%u pl=%p len=%u\n",
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(ue, rtp_pl, rtp_pl_len);
llsk_audio_tx_conn_data_ind(conn, 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 rtp_conn_setup(struct rtp_conn *conn, const struct osmo_sockaddr *rem_addr)
{
int rc;
char cname[256+4];
@ -144,6 +173,7 @@ int hnb_ue_voicecall_setup(struct hnb_ue *ue, const struct osmo_sockaddr *rem_ad
const char *local_wildcard_ipstr = "0.0.0.0";
char remote_ipstr[INET6_ADDRSTRLEN];
uint16_t remote_port;
struct hnb_ue *ue = conn->ue;
struct hnb *hnb = ue->hnb;
if (osmo_sockaddr_to_str_and_uint(remote_ipstr, sizeof(remote_ipstr), &remote_port, &rem_addr->u.sa) == 0) {
@ -151,12 +181,9 @@ int hnb_ue_voicecall_setup(struct hnb_ue *ue, const struct osmo_sockaddr *rem_ad
return -EINVAL;
}
if (ue->conn_cs.rtp.socket) {
LOGUE(ue, DRTP, LOGL_ERROR, "Setting up rtp socket but it already exists!\n");
return -EINVAL;
}
conn->rem_addr = *rem_addr;
rs = ue->conn_cs.rtp.socket = osmo_rtp_socket_create(ue, 0);
rs = conn->socket = osmo_rtp_socket_create(ue, 0);
rc = osmo_rtp_socket_set_param(rs,
hnb->rtp.jitter_adaptive ?
OSMO_RTP_P_JIT_ADAP :
@ -166,7 +193,7 @@ int hnb_ue_voicecall_setup(struct hnb_ue *ue, const struct osmo_sockaddr *rem_ad
LOGUE(ue, DRTP, LOGL_ERROR, "Failed to set RTP socket parameters: %s\n", strerror(-rc));
goto free_ret;
}
rs->priv = ue;
rs->priv = conn;
rs->rx_cb = &rtp_rx_cb;
rc = rtp_bind(hnb, rs, local_wildcard_ipstr);
@ -174,10 +201,11 @@ int hnb_ue_voicecall_setup(struct hnb_ue *ue, const struct osmo_sockaddr *rem_ad
LOGUE(ue, DRTP, LOGL_ERROR, "Failed to bind RTP/RTCP sockets\n");
goto free_ret;
}
conn->id = rc; /* We use local port as rtp conn ID */
/* 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);
snprintf(name, sizeof(name), "ue@%u-%u", conn->ue->conn_id, conn->id);
osmo_rtp_set_source_desc(rs, cname, name, NULL, NULL, NULL,
"OsmoHNodeB-" PACKAGE_VERSION, NULL);
@ -188,8 +216,8 @@ int hnb_ue_voicecall_setup(struct hnb_ue *ue, const struct osmo_sockaddr *rem_ad
}
/* 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);
//rc = rtp_get_bound_addr(rs, &conn->loc_addr);
rc = rtp_get_bound_addr(rs, rem_addr, &conn->loc_addr);
if (rc < 0) {
LOGUE(ue, DRTP, LOGL_ERROR, "Cannot obtain locally bound IP/port: %d\n", rc);
goto free_ret;
@ -197,16 +225,7 @@ int hnb_ue_voicecall_setup(struct hnb_ue *ue, const struct osmo_sockaddr *rem_ad
return rc;
free_ret:
osmo_rtp_socket_free(ue->conn_cs.rtp.socket);
ue->conn_cs.rtp.socket = NULL;
osmo_rtp_socket_free(conn->socket);
conn->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;
}