pespin has uploaded this change for review.
Validate session remote CP F-SEID and use it to transmit session requests
Change-Id: Ifccd4d2b8d500c9928778400bb096baaa12c9a31
---
M include/osmocom/upf/pfcp_entity_peer.h
M src/osmo-upf/pfcp_entity_peer.c
M src/osmo-upf/up_endpoint.c
M src/osmo-upf/up_session.c
4 files changed, 155 insertions(+), 34 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-upf refs/changes/82/41482/1
diff --git a/include/osmocom/upf/pfcp_entity_peer.h b/include/osmocom/upf/pfcp_entity_peer.h
index d2727e5..ae771eb 100644
--- a/include/osmocom/upf/pfcp_entity_peer.h
+++ b/include/osmocom/upf/pfcp_entity_peer.h
@@ -73,9 +73,12 @@
char *pfcp_entity_peer_remote_addr_str(struct pfcp_entity_peer *entity_peer);
-struct osmo_pfcp_msg *pfcp_entity_peer_init_tx(struct pfcp_entity_peer *entity_peer,
- struct osmo_pfcp_msg *in_reply_to,
- enum osmo_pfcp_message_type message_type);
+struct osmo_pfcp_msg *pfcp_entity_peer_init_tx_req(struct pfcp_entity_peer *peer,
+ const struct osmo_sockaddr *dst_addr,
+ enum osmo_pfcp_message_type message_type);
+struct osmo_pfcp_msg *pfcp_entity_peer_init_tx_resp(struct pfcp_entity_peer *peer,
+ struct osmo_pfcp_msg *in_reply_to,
+ enum osmo_pfcp_message_type message_type);
struct up_session *pfcp_entity_peer_find_up_session_by_up_seid(struct pfcp_entity_peer *entity_peer, uint64_t up_seid);
struct up_session *pfcp_entity_peer_find_up_session_by_cp_f_seid(struct pfcp_entity_peer *entity_peer, const struct osmo_pfcp_ie_f_seid *cp_f_seid);
diff --git a/src/osmo-upf/pfcp_entity_peer.c b/src/osmo-upf/pfcp_entity_peer.c
index db02f78..7b8c28d 100644
--- a/src/osmo-upf/pfcp_entity_peer.c
+++ b/src/osmo-upf/pfcp_entity_peer.c
@@ -194,15 +194,22 @@
m->ctx.peer_use_token = NULL;
}
-struct osmo_pfcp_msg *pfcp_entity_peer_init_tx(struct pfcp_entity_peer *peer,
- struct osmo_pfcp_msg *in_reply_to,
- enum osmo_pfcp_message_type message_type)
+struct osmo_pfcp_msg *pfcp_entity_peer_init_tx_req(struct pfcp_entity_peer *peer,
+ const struct osmo_sockaddr *dst_addr,
+ enum osmo_pfcp_message_type message_type)
{
struct osmo_pfcp_msg *tx;
- if (in_reply_to)
- tx = osmo_pfcp_msg_alloc_tx_resp(OTC_SELECT, in_reply_to, message_type);
- else
- tx = osmo_pfcp_msg_alloc_tx_req(OTC_SELECT, &peer->remote_addr, message_type);
+ tx = osmo_pfcp_msg_alloc_tx_req(OTC_SELECT, dst_addr, message_type);
+ pfcp_entity_peer_set_msg_ctx(peer, tx);
+ return tx;
+}
+
+struct osmo_pfcp_msg *pfcp_entity_peer_init_tx_resp(struct pfcp_entity_peer *peer,
+ struct osmo_pfcp_msg *in_reply_to,
+ enum osmo_pfcp_message_type message_type)
+{
+ struct osmo_pfcp_msg *tx;
+ tx = osmo_pfcp_msg_alloc_tx_resp(OTC_SELECT, in_reply_to, message_type);
pfcp_entity_peer_set_msg_ctx(peer, tx);
return tx;
}
@@ -211,7 +218,7 @@
{
struct osmo_pfcp_msg *resp;
- resp = pfcp_entity_peer_init_tx(entity_peer, m, OSMO_PFCP_MSGT_ASSOC_SETUP_RESP);
+ resp = pfcp_entity_peer_init_tx_resp(entity_peer, m, OSMO_PFCP_MSGT_ASSOC_SETUP_RESP);
resp->ies.assoc_setup_resp = (struct osmo_pfcp_msg_assoc_setup_resp) {
.cause = cause,
@@ -232,7 +239,7 @@
{
struct osmo_pfcp_msg *resp;
- resp = pfcp_entity_peer_init_tx(peer, m, OSMO_PFCP_MSGT_ASSOC_RELEASE_RESP);
+ resp = pfcp_entity_peer_init_tx_resp(peer, m, OSMO_PFCP_MSGT_ASSOC_RELEASE_RESP);
resp->ies.assoc_release_resp = (struct osmo_pfcp_msg_assoc_release_resp) {
.cause = cause,
@@ -307,7 +314,9 @@
{
enum osmo_pfcp_cause cause = OSMO_PFCP_CAUSE_REQUEST_ACCEPTED;
struct osmo_pfcp_msg *resp;
- struct up_session *session = pfcp_entity_peer_find_up_session_by_cp_f_seid(peer, &m->ies.session_est_req.cp_f_seid);
+ struct up_session *session;
+
+ session = pfcp_entity_peer_find_up_session_by_cp_f_seid(peer, &m->ies.session_est_req.cp_f_seid);
if (!session)
session = up_session_alloc(peer, &m->ies.session_est_req.cp_f_seid);
if (!session) {
@@ -324,7 +333,7 @@
return;
nack_response:
- resp = pfcp_entity_peer_init_tx(peer, m, OSMO_PFCP_MSGT_SESSION_EST_RESP);
+ resp = pfcp_entity_peer_init_tx_resp(peer, m, OSMO_PFCP_MSGT_SESSION_EST_RESP);
resp->h.seid = m->ies.session_est_req.cp_f_seid.seid;
resp->h.seid_present = true;
resp->ies.session_est_resp = (struct osmo_pfcp_msg_session_est_resp){
diff --git a/src/osmo-upf/up_endpoint.c b/src/osmo-upf/up_endpoint.c
index f53dc50..8161042 100644
--- a/src/osmo-upf/up_endpoint.c
+++ b/src/osmo-upf/up_endpoint.c
@@ -166,61 +166,137 @@
OSMO_PFCP_CAUSE_SERVICE_NOT_SUPPORTED);
}
+/* Validate received F-SEID IP address */
+static enum osmo_pfcp_cause up_ep_validate_cp_f_seid_addr(const struct up_endpoint *up_ep,
+ const struct osmo_pfcp_ie_f_seid *f_seid)
+{
+ const struct osmo_sockaddr *local_addr;
+
+ OSMO_ASSERT(up_ep);
+ OSMO_ASSERT(f_seid)
+
+ /* Validate the F-SEID contains an IP address we can send requests to later on: */
+ local_addr = osmo_pfcp_endpoint_get_local_addr(up_ep->pfcp_ep);
+ OSMO_ASSERT(local_addr);
+ switch (local_addr->u.sa.sa_family) {
+ case AF_INET:
+ if (!f_seid->ip_addr.v4_present)
+ return OSMO_PFCP_CAUSE_MANDATORY_IE_INCORRECT;
+ break;
+ case AF_INET6:
+ if (!f_seid->ip_addr.v4_present &&
+ !f_seid->ip_addr.v6_present)
+ return OSMO_PFCP_CAUSE_MANDATORY_IE_INCORRECT;
+ break;
+ default:
+ OSMO_ASSERT(0);
+ }
+ return OSMO_PFCP_CAUSE_REQUEST_ACCEPTED;
+}
+
static void up_ep_rx_session_est_req(struct up_endpoint *up_ep, const struct osmo_pfcp_msg *m)
{
- if (!m->ctx.peer_fi) {
- struct osmo_pfcp_msg *tx;
- OSMO_LOG_PFCP_MSG(m, LOGL_ERROR, "Peer is not associated, cannot establish session\n");
- tx = osmo_pfcp_msg_alloc_tx_resp(OTC_SELECT, m, OSMO_PFCP_MSGT_SESSION_EST_RESP);
- tx->ies.session_est_resp.cause = OSMO_PFCP_CAUSE_NO_ESTABLISHED_PFCP_ASSOC;
- osmo_pfcp_endpoint_tx(up_ep->pfcp_ep, tx);
- return;
+ struct osmo_pfcp_msg *resp;
+ enum osmo_pfcp_cause cause;
+
+ cause = up_ep_validate_cp_f_seid_addr(up_ep, &m->ies.session_est_req.cp_f_seid);
+ if (cause != OSMO_PFCP_CAUSE_REQUEST_ACCEPTED) {
+ OSMO_LOG_PFCP_MSG(m, LOGL_ERROR, "Remote CP F-SEID IP address invalid\n");
+ goto nack_response;
}
+
+ if (!m->ctx.peer_fi) {
+ OSMO_LOG_PFCP_MSG(m, LOGL_ERROR, "Peer is not associated, cannot establish session\n");
+ cause = OSMO_PFCP_CAUSE_NO_ESTABLISHED_PFCP_ASSOC;
+ goto nack_response;
+ }
+
osmo_fsm_inst_dispatch(m->ctx.peer_fi, PFCP_ENTITY_PEER_EV_RX_SESSION_EST_REQ, (void *)m);
+ return;
+
+nack_response:
+ resp = osmo_pfcp_msg_alloc_tx_resp(OTC_SELECT, m, OSMO_PFCP_MSGT_SESSION_EST_RESP);
+ resp->ies.session_est_resp.cause = cause;
+ osmo_pfcp_endpoint_tx(up_ep->pfcp_ep, resp);
}
static void up_ep_rx_session_mod_req(struct up_endpoint *up_ep, const struct osmo_pfcp_msg *m)
{
+ struct osmo_pfcp_msg *resp;
+ enum osmo_pfcp_cause cause;
+
+ if (m->ies.session_mod_req.cp_f_seid_present) {
+ cause = up_ep_validate_cp_f_seid_addr(up_ep, &m->ies.session_mod_req.cp_f_seid);
+ if (cause != OSMO_PFCP_CAUSE_REQUEST_ACCEPTED) {
+ OSMO_LOG_PFCP_MSG(m, LOGL_ERROR, "Remote CP F-SEID IP address invalid\n");
+ goto nack_response;
+ }
+ }
+
if (!m->ctx.session_fi) {
/* Session not found. */
- struct osmo_pfcp_msg *tx;
- tx = osmo_pfcp_msg_alloc_tx_resp(OTC_SELECT, m, OSMO_PFCP_MSGT_SESSION_MOD_RESP);
if (!m->ctx.peer_fi) {
/* Not even the peer is associated. */
OSMO_LOG_PFCP_MSG(m, LOGL_ERROR, "Peer is not associated, cannot modify session\n");
- tx->ies.session_mod_resp.cause = OSMO_PFCP_CAUSE_NO_ESTABLISHED_PFCP_ASSOC;
+ cause = OSMO_PFCP_CAUSE_NO_ESTABLISHED_PFCP_ASSOC;
+ goto nack_response;
} else {
OSMO_LOG_PFCP_MSG(m, LOGL_ERROR,
"No established session with SEID=0x%"PRIx64", cannot modify\n",
m->h.seid);
- tx->ies.session_mod_resp.cause = OSMO_PFCP_CAUSE_SESSION_CTX_NOT_FOUND;
+ cause = OSMO_PFCP_CAUSE_SESSION_CTX_NOT_FOUND;
+ goto nack_response;
}
- osmo_pfcp_endpoint_tx(up_ep->pfcp_ep, tx);
- return;
}
+
osmo_fsm_inst_dispatch(m->ctx.session_fi, UP_SESSION_EV_RX_SESSION_MOD_REQ, (void *)m);
+ return;
+
+nack_response:
+ resp = osmo_pfcp_msg_alloc_tx_resp(OTC_SELECT, m, OSMO_PFCP_MSGT_SESSION_MOD_RESP);
+ resp->ies.session_mod_resp.cause = cause;
+ osmo_pfcp_endpoint_tx(up_ep->pfcp_ep, resp);
}
static void up_ep_rx_session_del_req(struct up_endpoint *up_ep, const struct osmo_pfcp_msg *m)
{
+ struct osmo_pfcp_msg *resp;
+ enum osmo_pfcp_cause cause;
+
+#if 0
+ /* Can be enabled once libosmo-pfcp struct osmo_pfcp_msg_session_del_req supports the IE: */
+ if (m->ies.session_del_req.cp_f_seid_present) {
+ cause = up_ep_validate_cp_f_seid_addr(up_ep, &m->ies.session_mod_req.cp_f_seid);
+ if (cause != OSMO_PFCP_CAUSE_REQUEST_ACCEPTED) {
+ OSMO_LOG_PFCP_MSG(m, LOGL_ERROR, "Remote CP F-SEID IP address invalid\n");
+ goto nack_response;
+ }
+ }
+#endif
+
if (!m->ctx.session_fi) {
/* Session not found. */
- struct osmo_pfcp_msg *tx;
- tx = osmo_pfcp_msg_alloc_tx_resp(OTC_SELECT, m, OSMO_PFCP_MSGT_SESSION_DEL_RESP);
if (!m->ctx.peer_fi) {
/* Not even the peer is associated. */
OSMO_LOG_PFCP_MSG(m, LOGL_ERROR, "Peer is not associated, cannot delete session\n");
- tx->ies.session_del_resp.cause = OSMO_PFCP_CAUSE_NO_ESTABLISHED_PFCP_ASSOC;
+ cause = OSMO_PFCP_CAUSE_NO_ESTABLISHED_PFCP_ASSOC;
+ goto nack_response;
} else {
OSMO_LOG_PFCP_MSG(m, LOGL_ERROR,
"No established session with SEID=0x%"PRIx64", cannot delete\n",
m->h.seid);
- tx->ies.session_del_resp.cause = OSMO_PFCP_CAUSE_SESSION_CTX_NOT_FOUND;
+ cause = OSMO_PFCP_CAUSE_SESSION_CTX_NOT_FOUND;
+ goto nack_response;
}
- osmo_pfcp_endpoint_tx(up_ep->pfcp_ep, tx);
- return;
}
+
osmo_fsm_inst_dispatch(m->ctx.session_fi, UP_SESSION_EV_RX_SESSION_DEL_REQ, (void *)m);
+ return;
+
+nack_response:
+ resp = osmo_pfcp_msg_alloc_tx_resp(OTC_SELECT, m, OSMO_PFCP_MSGT_SESSION_DEL_RESP);
+ resp->ies.session_del_resp.cause = cause;
+ osmo_pfcp_endpoint_tx(up_ep->pfcp_ep, resp);
}
static void up_ep_rx_session_rep_req(struct up_endpoint *up_ep, const struct osmo_pfcp_msg *m)
diff --git a/src/osmo-upf/up_session.c b/src/osmo-upf/up_session.c
index 5f406d5..9693745 100644
--- a/src/osmo-upf/up_session.c
+++ b/src/osmo-upf/up_session.c
@@ -90,10 +90,43 @@
return 1;
}
+/* Return as dst IP address the IP address from remote's CP F-SEID that matches
+ * our local endpoint configuration.
+ * Asserts regarding cp_f_seid are validated during session establishment/modification/deletion,
+ * see pfcp_entityt_peer_validate_cp_f_seid(). */
+static const struct osmo_sockaddr *up_session_req_dst_addr(const struct up_session *session)
+{
+ const struct osmo_sockaddr *src_addr = osmo_pfcp_endpoint_get_local_addr(session->entity_peer->node_peer->up_endpoint->pfcp_ep);
+ switch (src_addr->u.sa.sa_family) {
+ case AF_INET:
+ OSMO_ASSERT(session->cp_f_seid.ip_addr.v4_present);
+ return &session->cp_f_seid.ip_addr.v4;
+ case AF_INET6:
+ if (session->cp_f_seid.ip_addr.v6_present)
+ return &session->cp_f_seid.ip_addr.v6;
+ if (session->cp_f_seid.ip_addr.v4_present)
+ return &session->cp_f_seid.ip_addr.v4;
+ OSMO_ASSERT(0);
+ break;
+ default:
+ OSMO_ASSERT(0);
+ break;
+ }
+ return NULL;
+}
+
struct osmo_pfcp_msg *up_session_init_tx(struct up_session *session, struct osmo_pfcp_msg *in_reply_to,
enum osmo_pfcp_message_type message_type)
{
- struct osmo_pfcp_msg *tx = pfcp_entity_peer_init_tx(session->entity_peer, in_reply_to, message_type);
+ struct osmo_pfcp_msg *tx;
+ if (in_reply_to) {
+ /* Use req src IP address as resp dst IP address: */
+ tx = pfcp_entity_peer_init_tx_resp(session->entity_peer, in_reply_to, message_type);
+ } else {
+ const struct osmo_sockaddr *dst_addr = up_session_req_dst_addr(session);
+ /* Use IP address from remote's CP F-SEID as dst IP address: */
+ tx = pfcp_entity_peer_init_tx_req(session->entity_peer, dst_addr, message_type);
+ }
tx->h.seid = session->cp_f_seid.seid;
tx->h.seid_present = true;
up_session_set_msg_ctx(session, tx);
To view, visit change 41482. To unsubscribe, or for help writing mail filters, visit settings.