diff --git a/lib/gtp/util.c b/lib/gtp/util.c index c6c251365..d0b723bec 100644 --- a/lib/gtp/util.c +++ b/lib/gtp/util.c @@ -19,17 +19,28 @@ #include "ogs-gtp.h" -int ogs_gtpu_header_len(ogs_pkbuf_t *pkbuf) +int ogs_gtpu_parse_header( + ogs_gtp2_header_desc_t *header_desc, ogs_pkbuf_t *pkbuf) { ogs_gtp2_header_t *gtp_h = NULL; + ogs_gtp2_extension_header_t ext_hdesc; uint8_t *ext_h = NULL; uint16_t len = 0; + int i; ogs_assert(pkbuf); ogs_assert(pkbuf->data); gtp_h = (ogs_gtp2_header_t *)pkbuf->data; + if (header_desc) { + memset(header_desc, 0, sizeof(*header_desc)); + + header_desc->flags = gtp_h->flags; + header_desc->type = gtp_h->type; + header_desc->teid = be32toh(gtp_h->teid); + } + len = OGS_GTPV1U_HEADER_LEN; if (pkbuf->len < len) { ogs_error("the length of the packet is insufficient[%d:%d]", @@ -52,6 +63,8 @@ int ogs_gtpu_header_len(ogs_pkbuf_t *pkbuf) * * If no such Header follows, * then the value of the Next Extension Header Type shall be 0. */ + + i = 0; while (*(ext_h = (((uint8_t *)gtp_h) + len - 1))) { /* * The length of the Extension header shall be defined @@ -68,6 +81,42 @@ int ogs_gtpu_header_len(ogs_pkbuf_t *pkbuf) pkbuf->len, len); return -1; } + + if (!header_desc) /* Skip to extract header content */ + continue; + + /* Copy Header Content */ + memcpy(&ext_hdesc.array[i], ext_h-1, (*ext_h) * 4); + + switch (ext_hdesc.array[i].type) { + case OGS_GTP2_EXTENSION_HEADER_TYPE_PDU_SESSION_CONTAINER: + header_desc->pdu_type = ext_hdesc.array[i].pdu_type; + if (ext_hdesc.array[i].pdu_type == + OGS_GTP2_EXTENSION_HEADER_PDU_TYPE_UL_PDU_SESSION_INFORMATION) { + header_desc->qos_flow_identifier = + ext_hdesc.array[i].qos_flow_identifier; + ogs_trace(" QFI [0x%x]", + header_desc->qos_flow_identifier); + } + break; + case OGS_GTP2_EXTENSION_HEADER_TYPE_UDP_PORT: + header_desc->udp.presence = true; + header_desc->udp.port = be16toh(ext_hdesc.array[i].udp_port); + + ogs_trace(" UDP Port [%d]", header_desc->udp.port); + break; + case OGS_GTP2_EXTENSION_HEADER_TYPE_PDCP_NUMBER: + header_desc->pdcp_number_presence = true; + header_desc->pdcp_number = + be16toh(ext_hdesc.array[i].pdcp_number); + + ogs_trace(" PDCP Number [%d]", header_desc->pdcp_number); + break; + default: + break; + } + + i++; } } else if (gtp_h->flags & (OGS_GTPU_FLAGS_S|OGS_GTPU_FLAGS_PN)) { @@ -93,7 +142,6 @@ int ogs_gtpu_header_len(ogs_pkbuf_t *pkbuf) return len; } - uint16_t ogs_in_cksum(uint16_t *addr, int len) { int nleft = len; diff --git a/lib/gtp/util.h b/lib/gtp/util.h index 5497363e3..7fabdd7c6 100644 --- a/lib/gtp/util.h +++ b/lib/gtp/util.h @@ -28,7 +28,8 @@ extern "C" { #endif -int ogs_gtpu_header_len(ogs_pkbuf_t *pkbuf); +int ogs_gtpu_parse_header( + ogs_gtp2_header_desc_t *header_desc, ogs_pkbuf_t *pkbuf); uint16_t ogs_in_cksum(uint16_t *addr, int len); #ifdef __cplusplus diff --git a/lib/gtp/v2/build.c b/lib/gtp/v2/build.c index 90ce1e7c5..fcdedf6df 100644 --- a/lib/gtp/v2/build.c +++ b/lib/gtp/v2/build.c @@ -72,7 +72,11 @@ ogs_pkbuf_t *ogs_gtp1_build_error_indication( ogs_error("ogs_pkbuf_alloc() failed"); return NULL; } - ogs_pkbuf_reserve(pkbuf, OGS_GTPV1U_5GC_HEADER_LEN); + ogs_pkbuf_reserve(pkbuf, + OGS_GTPV1U_HEADER_LEN + /* 8 bytes */ + 4 + /* Seq Number(2) + N PDU Number(1) + Ext Header Type(1) */ + 4 + /* If 5GC, QFI Extension Header(4) */ + 4); /* UDP Port Extension Header(4) */ /* * 8.3 Tunnel Endpoint Identifier Data I @@ -118,9 +122,9 @@ void ogs_gtp2_fill_header( ogs_pkbuf_t *pkbuf) { ogs_gtp2_header_t *gtp_h = NULL; - ogs_gtp2_extension_header_t *ext_h = NULL; uint8_t flags; uint8_t gtp_hlen = 0; + int i; ogs_assert(gtp_hdesc); ogs_assert(ext_hdesc); @@ -129,13 +133,22 @@ void ogs_gtp2_fill_header( /* Processing GTP Flags */ flags = gtp_hdesc->flags; flags |= OGS_GTPU_FLAGS_V | OGS_GTPU_FLAGS_PT; - if (ext_hdesc->qos_flow_identifier) flags |= OGS_GTPU_FLAGS_E; + if (ext_hdesc->array[0].type && ext_hdesc->array[0].len) + flags |= OGS_GTPU_FLAGS_E; /* Define GTP Header Size */ - if (flags & OGS_GTPU_FLAGS_E) - gtp_hlen = OGS_GTPV1U_HEADER_LEN+8; - else if (flags & (OGS_GTPU_FLAGS_S|OGS_GTPU_FLAGS_PN)) - gtp_hlen = OGS_GTPV1U_HEADER_LEN+4; + if (flags & OGS_GTPU_FLAGS_E) { + + gtp_hlen = OGS_GTPV1U_HEADER_LEN+OGS_GTPV1U_EXTENSION_HEADER_LEN; + + i = 0; + while(ext_hdesc->array[i].len) { + gtp_hlen += (ext_hdesc->array[i].len*4); + i++; + } + + } else if (flags & (OGS_GTPU_FLAGS_S|OGS_GTPU_FLAGS_PN)) + gtp_hlen = OGS_GTPV1U_HEADER_LEN+OGS_GTPV1U_EXTENSION_HEADER_LEN; else gtp_hlen = OGS_GTPV1U_HEADER_LEN; @@ -179,24 +192,30 @@ void ogs_gtp2_fill_header( /* Fill Extention Header */ if (gtp_h->flags & OGS_GTPU_FLAGS_E) { - ext_h = (ogs_gtp2_extension_header_t *) - (pkbuf->data + OGS_GTPV1U_HEADER_LEN); + uint8_t *ext_h = (uint8_t *)(pkbuf->data + + OGS_GTPV1U_HEADER_LEN + OGS_GTPV1U_EXTENSION_HEADER_LEN); ogs_assert(ext_h); - if (ext_hdesc->qos_flow_identifier) { - /* 5G Core */ - ext_h->type = OGS_GTP2_EXTENSION_HEADER_TYPE_PDU_SESSION_CONTAINER; - ext_h->len = 1; - ext_h->pdu_type = ext_hdesc->pdu_type; - ext_h->qos_flow_identifier = ext_hdesc->qos_flow_identifier; - ext_h->next_type = - OGS_GTP2_EXTENSION_HEADER_TYPE_NO_MORE_EXTENSION_HEADERS; - } else { - /* EPC */ - ext_h->type = ext_hdesc->type; - ext_h->len = 1; - ext_h->next_type = - OGS_GTP2_EXTENSION_HEADER_TYPE_NO_MORE_EXTENSION_HEADERS; + /* Copy Header Type */ + *(ext_h-1) = ext_hdesc->array[0].type; + + i = 0; + while (i < OGS_GTP2_NUM_OF_EXTENSION_HEADER && + (ext_h - pkbuf->data) < gtp_hlen) { + int len = ext_hdesc->array[i].len*4; + + /* Copy Header Content */ + memcpy(ext_h, &ext_hdesc->array[i].len, len-1); + + /* Check if Next Header is Available */ + if (ext_hdesc->array[i+1].len) + ext_h[len-1] = ext_hdesc->array[i+1].type; + else + ext_h[len-1] = + OGS_GTP2_EXTENSION_HEADER_TYPE_NO_MORE_EXTENSION_HEADERS; + + ext_h += len; + i++; } } } diff --git a/lib/gtp/v2/path.c b/lib/gtp/v2/path.c index 790279ce9..26549ab81 100644 --- a/lib/gtp/v2/path.c +++ b/lib/gtp/v2/path.c @@ -21,22 +21,62 @@ int ogs_gtp2_send_user_plane( ogs_gtp_node_t *gnode, - ogs_gtp2_header_t *gtp_hdesc, ogs_gtp2_extension_header_t *ext_hdesc, + ogs_gtp2_header_desc_t *header_desc, ogs_pkbuf_t *pkbuf) { char buf[OGS_ADDRSTRLEN]; - int rv; + int rv, i; - ogs_gtp2_fill_header(gtp_hdesc, ext_hdesc, pkbuf); + ogs_gtp2_header_t gtp_hdesc; + ogs_gtp2_extension_header_t ext_hdesc; + + ogs_assert(header_desc); + + memset(>p_hdesc, 0, sizeof(gtp_hdesc)); + memset(&ext_hdesc, 0, sizeof(ext_hdesc)); + + gtp_hdesc.flags = header_desc->flags; + gtp_hdesc.type = header_desc->type; + gtp_hdesc.teid = header_desc->teid; + + i = 0; + + if (header_desc->qos_flow_identifier) { + ext_hdesc.array[i].type = + OGS_GTP2_EXTENSION_HEADER_TYPE_PDU_SESSION_CONTAINER; + ext_hdesc.array[i].len = 1; + ext_hdesc.array[i].pdu_type = header_desc->pdu_type; + ext_hdesc.array[i].qos_flow_identifier = + header_desc->qos_flow_identifier; + i++; + } + + if (header_desc->udp.presence == true) { + ext_hdesc.array[i].type = OGS_GTP2_EXTENSION_HEADER_TYPE_UDP_PORT; + ext_hdesc.array[i].len = 1; + ext_hdesc.array[i].udp_port = htobe16(header_desc->udp.port); + i++; + } + + if (header_desc->pdcp_number_presence == true) { + ext_hdesc.array[i].type = OGS_GTP2_EXTENSION_HEADER_TYPE_PDCP_NUMBER; + ext_hdesc.array[i].len = 1; + ext_hdesc.array[i].pdcp_number = htobe16(header_desc->pdcp_number); + i++; + } + + ogs_gtp2_fill_header(>p_hdesc, &ext_hdesc, pkbuf); ogs_trace("SEND GTP-U[%d] to Peer[%s] : TEID[0x%x]", - gtp_hdesc->type, OGS_ADDR(&gnode->addr, buf), gtp_hdesc->teid); + header_desc->type, + OGS_ADDR(&gnode->addr, buf), header_desc->teid); rv = ogs_gtp_sendto(gnode, pkbuf); if (rv != OGS_OK) { if (ogs_socket_errno != OGS_EAGAIN) { ogs_error("SEND GTP-U[%d] to Peer[%s] : TEID[0x%x]", - gtp_hdesc->type, OGS_ADDR(&gnode->addr, buf), gtp_hdesc->teid); + header_desc->type, + OGS_ADDR(&gnode->addr, buf), header_desc->teid); } } @@ -270,6 +310,7 @@ void ogs_gtp1_send_error_indication( ogs_gtp2_header_t gtp_hdesc; ogs_gtp2_extension_header_t ext_hdesc; + int i; ogs_assert(sock); ogs_assert(to); @@ -285,8 +326,20 @@ void ogs_gtp1_send_error_indication( gtp_hdesc.type = OGS_GTPU_MSGTYPE_ERR_IND; gtp_hdesc.flags = OGS_GTPU_FLAGS_S|OGS_GTPU_FLAGS_E; - ext_hdesc.type = OGS_GTP2_EXTENSION_HEADER_TYPE_UDP_PORT; - ext_hdesc.qos_flow_identifier = qfi; + + i = 0; + if (qfi) { + ext_hdesc.array[i].type = + OGS_GTP2_EXTENSION_HEADER_TYPE_PDU_SESSION_CONTAINER; + ext_hdesc.array[i].len = 1; + ext_hdesc.array[i].pdu_type = + OGS_GTP2_EXTENSION_HEADER_PDU_TYPE_DL_PDU_SESSION_INFORMATION; + ext_hdesc.array[i].qos_flow_identifier = qfi; + i++; + } + ext_hdesc.array[i].type = OGS_GTP2_EXTENSION_HEADER_TYPE_UDP_PORT; + ext_hdesc.array[i].len = 1; + ext_hdesc.array[i].udp_port = 0; ogs_gtp2_fill_header(>p_hdesc, &ext_hdesc, pkbuf); diff --git a/lib/gtp/v2/path.h b/lib/gtp/v2/path.h index 72e99bfbe..332fcaf25 100644 --- a/lib/gtp/v2/path.h +++ b/lib/gtp/v2/path.h @@ -32,7 +32,7 @@ typedef struct ogs_gtp_xact_s ogs_gtp_xact_t; int ogs_gtp2_send_user_plane( ogs_gtp_node_t *gnode, - ogs_gtp2_header_t *gtp_hdesc, ogs_gtp2_extension_header_t *ext_hdesc, + ogs_gtp2_header_desc_t *hdesc, ogs_pkbuf_t *pkbuf); ogs_pkbuf_t *ogs_gtp2_handle_echo_req(ogs_pkbuf_t *pkb); diff --git a/lib/gtp/v2/types.h b/lib/gtp/v2/types.h index ca3830d36..33b900a88 100644 --- a/lib/gtp/v2/types.h +++ b/lib/gtp/v2/types.h @@ -53,21 +53,44 @@ extern "C" { typedef struct ogs_gtp2_extension_header_s { #define OGS_GTP2_EXTENSION_HEADER_TYPE_UDP_PORT 0x40 #define OGS_GTP2_EXTENSION_HEADER_TYPE_PDU_SESSION_CONTAINER 0x85 +#define OGS_GTP2_EXTENSION_HEADER_TYPE_PDCP_NUMBER 0xc0 #define OGS_GTP2_EXTENSION_HEADER_TYPE_NO_MORE_EXTENSION_HEADERS 0x0 uint16_t sequence_number; uint8_t n_pdu_number; - uint8_t type; - uint8_t len; + struct { + uint8_t type; + uint8_t len; + union { + struct { #define OGS_GTP2_EXTENSION_HEADER_PDU_TYPE_DL_PDU_SESSION_INFORMATION 0 #define OGS_GTP2_EXTENSION_HEADER_PDU_TYPE_UL_PDU_SESSION_INFORMATION 1 - ED2(uint8_t pdu_type:4;, - uint8_t spare1:4;); - ED3(uint8_t paging_policy_presence:1;, - uint8_t reflective_qos_indicator:1;, - uint8_t qos_flow_identifier:6;); - uint8_t next_type; + ED2(uint8_t pdu_type:4;, + uint8_t spare1:4;); + ED3(uint8_t paging_policy_presence:1;, + uint8_t reflective_qos_indicator:1;, + uint8_t qos_flow_identifier:6;); + }; + uint16_t udp_port; + uint16_t pdcp_number; + }; +#define OGS_GTP2_NUM_OF_EXTENSION_HEADER 8 + } __attribute__ ((packed)) array[OGS_GTP2_NUM_OF_EXTENSION_HEADER]; } __attribute__ ((packed)) ogs_gtp2_extension_header_t; +typedef struct ogs_gtp2_header_desc_s { + /* GTP Header */ + uint8_t type; + uint8_t flags; + uint32_t teid; + + /* GTP Extension Header */ + uint8_t qos_flow_identifier; + uint8_t pdu_type; + ogs_port_t udp; + bool pdcp_number_presence; + uint16_t pdcp_number; +} ogs_gtp2_header_desc_t; + /* 8.4 Cause */ #define OGS_GTP2_CAUSE_UNDEFINED_VALUE 0 #define OGS_GTP2_CAUSE_LOCAL_DETACH 2 diff --git a/lib/pfcp/handler.c b/lib/pfcp/handler.c index 26377faa7..cf7052f12 100644 --- a/lib/pfcp/handler.c +++ b/lib/pfcp/handler.c @@ -218,7 +218,8 @@ bool ogs_pfcp_up_handle_association_setup_response( } bool ogs_pfcp_up_handle_pdr( - ogs_pfcp_pdr_t *pdr, uint8_t type, ogs_pkbuf_t *recvbuf, + ogs_pfcp_pdr_t *pdr, uint8_t type, + ogs_gtp2_header_desc_t *recvhdr, ogs_pkbuf_t *recvbuf, ogs_pfcp_user_plane_report_t *report) { ogs_pfcp_far_t *far = NULL; @@ -248,9 +249,27 @@ bool ogs_pfcp_up_handle_pdr( } else { if (far->apply_action & OGS_PFCP_APPLY_ACTION_FORW) { + ogs_gtp2_header_desc_t sendhdr; /* Forward packet */ - ogs_pfcp_send_g_pdu(pdr, type, sendbuf); + memset(&sendhdr, 0, sizeof(sendhdr)); + sendhdr.type = type; + + if (recvhdr) { + /* + * Issue #2584 + * Discussion #2477 + * + * Forward PDCP Number via Indirect Tunnel during Handover + */ + if (recvhdr->pdcp_number_presence == true) { + sendhdr.pdcp_number_presence = + recvhdr->pdcp_number_presence; + sendhdr.pdcp_number = recvhdr->pdcp_number; + } + } + + ogs_pfcp_send_g_pdu(pdr, &sendhdr, sendbuf); } else if (far->apply_action & OGS_PFCP_APPLY_ACTION_BUFF) { diff --git a/lib/pfcp/handler.h b/lib/pfcp/handler.h index 7ae62f30b..2e09edc1a 100644 --- a/lib/pfcp/handler.h +++ b/lib/pfcp/handler.h @@ -46,7 +46,8 @@ bool ogs_pfcp_up_handle_association_setup_response( ogs_pfcp_association_setup_response_t *req); bool ogs_pfcp_up_handle_pdr( - ogs_pfcp_pdr_t *pdr, uint8_t type, ogs_pkbuf_t *recvbuf, + ogs_pfcp_pdr_t *pdr, uint8_t type, + ogs_gtp2_header_desc_t *recvhdr, ogs_pkbuf_t *recvbuf, ogs_pfcp_user_plane_report_t *report); bool ogs_pfcp_up_handle_error_indication( ogs_pfcp_far_t *far, ogs_pfcp_user_plane_report_t *report); diff --git a/lib/pfcp/path.c b/lib/pfcp/path.c index 8719afde4..4605cd815 100644 --- a/lib/pfcp/path.c +++ b/lib/pfcp/path.c @@ -344,16 +344,16 @@ int ogs_pfcp_up_send_association_setup_response(ogs_pfcp_xact_t *xact, } void ogs_pfcp_send_g_pdu( - ogs_pfcp_pdr_t *pdr, uint8_t type, ogs_pkbuf_t *sendbuf) + ogs_pfcp_pdr_t *pdr, + ogs_gtp2_header_desc_t *sendhdr, ogs_pkbuf_t *sendbuf) { ogs_gtp_node_t *gnode = NULL; ogs_pfcp_far_t *far = NULL; - ogs_gtp2_header_t gtp_hdesc; - ogs_gtp2_extension_header_t ext_hdesc; + ogs_gtp2_header_desc_t header_desc; ogs_assert(pdr); - ogs_assert(type); + ogs_assert(sendhdr); ogs_assert(sendbuf); far = pdr->far; @@ -373,15 +373,28 @@ void ogs_pfcp_send_g_pdu( ogs_assert(gnode); ogs_assert(gnode->sock); - memset(>p_hdesc, 0, sizeof(gtp_hdesc)); - memset(&ext_hdesc, 0, sizeof(ext_hdesc)); + memset(&header_desc, 0, sizeof(header_desc)); - gtp_hdesc.type = type; - gtp_hdesc.teid = far->outer_header_creation.teid; - if (pdr->qer && pdr->qer->qfi) - ext_hdesc.qos_flow_identifier = pdr->qer->qfi; + header_desc.type = sendhdr->type; + header_desc.teid = far->outer_header_creation.teid; - ogs_gtp2_send_user_plane(gnode, >p_hdesc, &ext_hdesc, sendbuf); + if (pdr->qer && pdr->qer->qfi) { + header_desc.pdu_type = + OGS_GTP2_EXTENSION_HEADER_PDU_TYPE_DL_PDU_SESSION_INFORMATION; + header_desc.qos_flow_identifier = pdr->qer->qfi; + } + + if (sendhdr->udp.presence == true) { + header_desc.udp.presence = sendhdr->udp.presence; + header_desc.udp.port = sendhdr->udp.port; + } + + if (sendhdr->pdcp_number_presence == true) { + header_desc.pdcp_number_presence = sendhdr->pdcp_number_presence; + header_desc.pdcp_number = sendhdr->pdcp_number; + } + + ogs_gtp2_send_user_plane(gnode, &header_desc, sendbuf); } int ogs_pfcp_send_end_marker(ogs_pfcp_pdr_t *pdr) @@ -391,8 +404,7 @@ int ogs_pfcp_send_end_marker(ogs_pfcp_pdr_t *pdr) ogs_pkbuf_t *sendbuf = NULL; - ogs_gtp2_header_t gtp_hdesc; - ogs_gtp2_extension_header_t ext_hdesc; + ogs_gtp2_header_desc_t header_desc; ogs_assert(pdr); far = pdr->far; @@ -415,15 +427,18 @@ int ogs_pfcp_send_end_marker(ogs_pfcp_pdr_t *pdr) } ogs_pkbuf_reserve(sendbuf, OGS_GTPV1U_5GC_HEADER_LEN); - memset(>p_hdesc, 0, sizeof(gtp_hdesc)); - memset(&ext_hdesc, 0, sizeof(ext_hdesc)); + memset(&header_desc, 0, sizeof(header_desc)); - gtp_hdesc.type = OGS_GTPU_MSGTYPE_END_MARKER; - gtp_hdesc.teid = far->outer_header_creation.teid; - if (pdr->qer && pdr->qer->qfi) - ext_hdesc.qos_flow_identifier = pdr->qer->qfi; + header_desc.type = OGS_GTPU_MSGTYPE_END_MARKER; + header_desc.teid = far->outer_header_creation.teid; - ogs_gtp2_send_user_plane(gnode, >p_hdesc, &ext_hdesc, sendbuf); + if (pdr->qer && pdr->qer->qfi) { + header_desc.pdu_type = + OGS_GTP2_EXTENSION_HEADER_PDU_TYPE_DL_PDU_SESSION_INFORMATION; + header_desc.qos_flow_identifier = pdr->qer->qfi; + } + + ogs_gtp2_send_user_plane(gnode, &header_desc, sendbuf); return OGS_OK; } @@ -439,8 +454,13 @@ void ogs_pfcp_send_buffered_packet(ogs_pfcp_pdr_t *pdr) if (far && far->gnode) { if (far->apply_action & OGS_PFCP_APPLY_ACTION_FORW) { for (i = 0; i < far->num_of_buffered_packet; i++) { + ogs_gtp2_header_desc_t sendhdr; + + memset(&sendhdr, 0, sizeof(sendhdr)); + sendhdr.type = OGS_GTPU_MSGTYPE_GPDU; + ogs_pfcp_send_g_pdu( - pdr, OGS_GTPU_MSGTYPE_GPDU, far->buffered_packet[i]); + pdr, &sendhdr, far->buffered_packet[i]); } far->num_of_buffered_packet = 0; } diff --git a/lib/pfcp/path.h b/lib/pfcp/path.h index 689175c26..379e992eb 100644 --- a/lib/pfcp/path.h +++ b/lib/pfcp/path.h @@ -79,7 +79,8 @@ int ogs_pfcp_up_send_association_setup_response(ogs_pfcp_xact_t *xact, uint8_t cause); void ogs_pfcp_send_g_pdu( - ogs_pfcp_pdr_t *pdr, uint8_t type, ogs_pkbuf_t *sendbuf); + ogs_pfcp_pdr_t *pdr, + ogs_gtp2_header_desc_t *sendhdr, ogs_pkbuf_t *sendbuf); int ogs_pfcp_send_end_marker(ogs_pfcp_pdr_t *pdr); void ogs_pfcp_send_buffered_packet(ogs_pfcp_pdr_t *pdr); diff --git a/src/sgwu/gtp-path.c b/src/sgwu/gtp-path.c index b3868b49a..a08cf92a5 100644 --- a/src/sgwu/gtp-path.c +++ b/src/sgwu/gtp-path.c @@ -38,11 +38,9 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) ogs_sockaddr_t from; ogs_gtp2_header_t *gtp_h = NULL; + ogs_gtp2_header_desc_t header_desc; ogs_pfcp_user_plane_report_t report; - uint32_t teid; - uint8_t qfi; - ogs_assert(fd != INVALID_SOCKET); sock = data; ogs_assert(sock); @@ -70,7 +68,13 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) goto cleanup; } - if (gtp_h->type == OGS_GTPU_MSGTYPE_ECHO_REQ) { + len = ogs_gtpu_parse_header(&header_desc, pkbuf); + if (len < 0) { + ogs_error("[DROP] Cannot decode GTPU packet"); + ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len); + goto cleanup; + } + if (header_desc.type == OGS_GTPU_MSGTYPE_ECHO_REQ) { ogs_pkbuf_t *echo_rsp; ogs_debug("[RECV] Echo Request from [%s]", OGS_ADDR(&from, buf1)); @@ -91,57 +95,27 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) } goto cleanup; } - - teid = be32toh(gtp_h->teid); + if (header_desc.type != OGS_GTPU_MSGTYPE_END_MARKER && + pkbuf->len <= len) { + ogs_error("[DROP] Small GTPU packet(type:%d len:%d)", + header_desc.type, len); + ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len); + goto cleanup; + } ogs_trace("[RECV] GPU-U Type [%d] from [%s] : TEID[0x%x]", - gtp_h->type, OGS_ADDR(&from, buf1), teid); - - qfi = 0; - if (gtp_h->flags & OGS_GTPU_FLAGS_E) { - /* - * TS29.281 - * 5.2.1 General format of the GTP-U Extension Header - * Figure 5.2.1-3: Definition of Extension Header Type - * - * Note 4 : For a GTP-PDU with several Extension Headers, the PDU - * Session Container should be the first Extension Header - */ - ogs_gtp2_extension_header_t *extension_header = - (ogs_gtp2_extension_header_t *)(pkbuf->data+OGS_GTPV1U_HEADER_LEN); - ogs_assert(extension_header); - if (extension_header->type == - OGS_GTP2_EXTENSION_HEADER_TYPE_PDU_SESSION_CONTAINER) { - if (extension_header->pdu_type == - OGS_GTP2_EXTENSION_HEADER_PDU_TYPE_UL_PDU_SESSION_INFORMATION) { - ogs_trace(" QFI [0x%x]", - extension_header->qos_flow_identifier); - qfi = extension_header->qos_flow_identifier; - } - } - } + header_desc.type, OGS_ADDR(&from, buf1), header_desc.teid); /* Remove GTP header and send packets to peer NF */ - len = ogs_gtpu_header_len(pkbuf); - if (len < 0) { - ogs_error("[DROP] Cannot decode GTPU packet"); - ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len); - goto cleanup; - } - if (gtp_h->type != OGS_GTPU_MSGTYPE_END_MARKER && - pkbuf->len <= len) { - ogs_error("[DROP] Small GTPU packet(type:%d len:%d)", gtp_h->type, len); - ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len); - goto cleanup; - } ogs_assert(ogs_pkbuf_pull(pkbuf, len)); - if (gtp_h->type == OGS_GTPU_MSGTYPE_END_MARKER) { + if (header_desc.type == OGS_GTPU_MSGTYPE_END_MARKER) { ogs_pfcp_object_t *pfcp_object = NULL; ogs_pfcp_pdr_t *pdr = NULL; + ogs_gtp2_header_desc_t sendhdr; ogs_pkbuf_t *sendbuf = NULL; - pfcp_object = ogs_pfcp_object_find_by_teid(teid); + pfcp_object = ogs_pfcp_object_find_by_teid(header_desc.teid); if (!pfcp_object) { /* * Refer to the following 5G standard @@ -160,9 +134,10 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) ogs_app()->time.message.pfcp.association_interval))) { ogs_error("[%s] Send Error Indication [TEID:0x%x] to [%s]", OGS_ADDR(&sock->local_addr, buf1), - teid, + header_desc.teid, OGS_ADDR(&from, buf2)); - ogs_gtp1_send_error_indication(sock, teid, 0, &from); + ogs_gtp1_send_error_indication( + sock, header_desc.teid, 0, &from); } goto cleanup; } @@ -183,9 +158,12 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) ogs_assert(sendbuf); /* Forward packet */ - ogs_pfcp_send_g_pdu(pdr, gtp_h->type, sendbuf); + memset(&sendhdr, 0, sizeof(sendhdr)); + sendhdr.type = header_desc.type; - } else if (gtp_h->type == OGS_GTPU_MSGTYPE_ERR_IND) { + ogs_pfcp_send_g_pdu(pdr, &sendhdr, sendbuf); + + } else if (header_desc.type == OGS_GTPU_MSGTYPE_ERR_IND) { ogs_pfcp_far_t *far = NULL; far = ogs_pfcp_far_find_by_gtpu_error_indication(pkbuf); @@ -205,7 +183,7 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) ogs_error("[DROP] Cannot find FAR by Error-Indication"); ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len); } - } else if (gtp_h->type == OGS_GTPU_MSGTYPE_GPDU) { + } else if (header_desc.type == OGS_GTPU_MSGTYPE_GPDU) { struct ip *ip_h = NULL; ogs_pfcp_object_t *pfcp_object = NULL; ogs_pfcp_sess_t *pfcp_sess = NULL; @@ -214,7 +192,7 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) ip_h = (struct ip *)pkbuf->data; ogs_assert(ip_h); - pfcp_object = ogs_pfcp_object_find_by_teid(teid); + pfcp_object = ogs_pfcp_object_find_by_teid(header_desc.teid); if (!pfcp_object) { /* * Refer to the following 5G standard @@ -233,9 +211,10 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) ogs_app()->time.message.pfcp.association_interval))) { ogs_error("[%s] Send Error Indication [TEID:0x%x] to [%s]", OGS_ADDR(&sock->local_addr, buf1), - teid, + header_desc.teid, OGS_ADDR(&from, buf2)); - ogs_gtp1_send_error_indication(sock, teid, 0, &from); + ogs_gtp1_send_error_indication( + sock, header_desc.teid, 0, &from); } goto cleanup; } @@ -253,11 +232,12 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) ogs_list_for_each(&pfcp_sess->pdr_list, pdr) { /* Check if TEID */ - if (teid != pdr->f_teid.teid) + if (header_desc.teid != pdr->f_teid.teid) continue; /* Check if QFI */ - if (qfi && pdr->qfi != qfi) + if (header_desc.qos_flow_identifier && + pdr->qfi != header_desc.qos_flow_identifier) continue; /* Check if Rule List in PDR */ @@ -281,7 +261,7 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) ogs_assert(pdr); ogs_assert(true == ogs_pfcp_up_handle_pdr( - pdr, gtp_h->type, pkbuf, &report)); + pdr, header_desc.type, &header_desc, pkbuf, &report)); if (report.type.downlink_data_report) { ogs_assert(pdr->sess); @@ -290,13 +270,14 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) ogs_assert(sess); report.downlink_data.pdr_id = pdr->id; - report.downlink_data.qfi = qfi; /* for 5GC */ + report.downlink_data.qfi = + header_desc.qos_flow_identifier; /* for 5GC */ ogs_assert(OGS_OK == sgwu_pfcp_send_session_report_request(sess, &report)); } } else { - ogs_error("[DROP] Invalid GTPU Type [%d]", gtp_h->type); + ogs_error("[DROP] Invalid GTPU Type [%d]", header_desc.type); ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len); } diff --git a/src/smf/gtp-path.c b/src/smf/gtp-path.c index c11cb39dd..5c5368da8 100644 --- a/src/smf/gtp-path.c +++ b/src/smf/gtp-path.c @@ -122,9 +122,7 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) ogs_sockaddr_t from; ogs_gtp2_header_t *gtp_h = NULL; - - uint32_t teid; - uint8_t qfi; + ogs_gtp2_header_desc_t header_desc; ogs_assert(fd != INVALID_SOCKET); @@ -151,7 +149,13 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) goto cleanup; } - if (gtp_h->type == OGS_GTPU_MSGTYPE_ECHO_REQ) { + len = ogs_gtpu_parse_header(&header_desc, pkbuf); + if (len < 0) { + ogs_error("[DROP] Cannot decode GTPU packet"); + ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len); + goto cleanup; + } + if (header_desc.type == OGS_GTPU_MSGTYPE_ECHO_REQ) { ogs_pkbuf_t *echo_rsp; ogs_debug("[RECV] Echo Request from [%s]", OGS_ADDR(&from, buf)); @@ -172,58 +176,27 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) } goto cleanup; } - - teid = be32toh(gtp_h->teid); + if (header_desc.type != OGS_GTPU_MSGTYPE_END_MARKER && + pkbuf->len <= len) { + ogs_error("[DROP] Small GTPU packet(type:%d len:%d)", + header_desc.type, len); + ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len); + goto cleanup; + } ogs_debug("[RECV] GPU-U Type [%d] from [%s] : TEID[0x%x]", - gtp_h->type, OGS_ADDR(&from, buf), teid); - - qfi = 0; - if (gtp_h->flags & OGS_GTPU_FLAGS_E) { - /* - * TS29.281 - * 5.2.1 General format of the GTP-U Extension Header - * Figure 5.2.1-3: Definition of Extension Header Type - * - * Note 4 : For a GTP-PDU with several Extension Headers, the PDU - * Session Container should be the first Extension Header - */ - ogs_gtp2_extension_header_t *extension_header = - (ogs_gtp2_extension_header_t *)(pkbuf->data + OGS_GTPV1U_HEADER_LEN); - ogs_assert(extension_header); - if (extension_header->type == - OGS_GTP2_EXTENSION_HEADER_TYPE_PDU_SESSION_CONTAINER) { - if (extension_header->pdu_type == - OGS_GTP2_EXTENSION_HEADER_PDU_TYPE_UL_PDU_SESSION_INFORMATION) { - ogs_debug(" QFI [0x%x]", - extension_header->qos_flow_identifier); - qfi = extension_header->qos_flow_identifier; - } - } - } + header_desc.type, OGS_ADDR(&from, buf), header_desc.teid); /* Remove GTP header and send packets to TUN interface */ - len = ogs_gtpu_header_len(pkbuf); - if (len < 0) { - ogs_error("[DROP] Cannot decode GTPU packet"); - ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len); - goto cleanup; - } - if (gtp_h->type != OGS_GTPU_MSGTYPE_END_MARKER && - pkbuf->len <= len) { - ogs_error("[DROP] Small GTPU packet(type:%d len:%d)", gtp_h->type, len); - ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len); - goto cleanup; - } ogs_assert(ogs_pkbuf_pull(pkbuf, len)); - if (gtp_h->type == OGS_GTPU_MSGTYPE_GPDU) { + if (header_desc.type == OGS_GTPU_MSGTYPE_GPDU) { smf_sess_t *sess = NULL; ogs_pfcp_far_t *far = NULL; - far = ogs_pfcp_far_find_by_teid(teid); + far = ogs_pfcp_far_find_by_teid(header_desc.teid); if (!far) { - ogs_error("No FAR for TEID [%d]", teid); + ogs_error("No FAR for TEID [%d]", header_desc.teid); goto cleanup; } @@ -232,8 +205,8 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) goto cleanup; } - if (qfi) { - ogs_error("QFI[%d] Found", qfi); + if (header_desc.qos_flow_identifier) { + ogs_error("QFI[%d] Found", header_desc.qos_flow_identifier); goto cleanup; } @@ -247,7 +220,7 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) send_router_advertisement(sess, ip6_h->ip6_src.s6_addr); } } else { - ogs_error("[DROP] Invalid GTPU Type [%d]", gtp_h->type); + ogs_error("[DROP] Invalid GTPU Type [%d]", header_desc.type); ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len); } @@ -718,20 +691,18 @@ static void send_router_advertisement(smf_sess_t *sess, uint8_t *ip6_dst) ogs_list_for_each(&sess->pfcp.pdr_list, pdr) { if (pdr->src_if == OGS_PFCP_INTERFACE_CP_FUNCTION && pdr->gnode) { - ogs_gtp2_header_t gtp_hdesc; - ogs_gtp2_extension_header_t ext_hdesc; + ogs_gtp2_header_desc_t header_desc; ogs_pkbuf_t *newbuf = NULL; - memset(>p_hdesc, 0, sizeof(gtp_hdesc)); - memset(&ext_hdesc, 0, sizeof(ext_hdesc)); + memset(&header_desc, 0, sizeof(header_desc)); - gtp_hdesc.type = OGS_GTPU_MSGTYPE_GPDU; - gtp_hdesc.teid = pdr->f_teid.teid; + header_desc.type = OGS_GTPU_MSGTYPE_GPDU; + header_desc.teid = pdr->f_teid.teid; newbuf = ogs_pkbuf_copy(pkbuf); ogs_assert(newbuf); - ogs_gtp2_send_user_plane(pdr->gnode, >p_hdesc, &ext_hdesc, newbuf); + ogs_gtp2_send_user_plane(pdr->gnode, &header_desc, newbuf); ogs_debug(" Send Router Advertisement"); break; diff --git a/src/upf/gtp-path.c b/src/upf/gtp-path.c index c9cb44913..0d6e20d0e 100644 --- a/src/upf/gtp-path.c +++ b/src/upf/gtp-path.c @@ -214,7 +214,7 @@ static void _gtpv1_tun_recv_common_cb( upf_sess_urr_acc_add(sess, pdr->urr[i], recvbuf->len, false); ogs_assert(true == ogs_pfcp_up_handle_pdr( - pdr, OGS_GTPU_MSGTYPE_GPDU, recvbuf, &report)); + pdr, OGS_GTPU_MSGTYPE_GPDU, NULL, recvbuf, &report)); /* * Issue #2210, Discussion #2208, #2209 @@ -270,11 +270,9 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) ogs_sockaddr_t from; ogs_gtp2_header_t *gtp_h = NULL; + ogs_gtp2_header_desc_t header_desc; ogs_pfcp_user_plane_report_t report; - uint32_t teid; - uint8_t qfi; - ogs_assert(fd != INVALID_SOCKET); sock = data; ogs_assert(sock); @@ -303,7 +301,13 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) goto cleanup; } - if (gtp_h->type == OGS_GTPU_MSGTYPE_ECHO_REQ) { + len = ogs_gtpu_parse_header(&header_desc, pkbuf); + if (len < 0) { + ogs_error("[DROP] Cannot decode GTPU packet"); + ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len); + goto cleanup; + } + if (header_desc.type == OGS_GTPU_MSGTYPE_ECHO_REQ) { ogs_pkbuf_t *echo_rsp; ogs_debug("[RECV] Echo Request from [%s]", OGS_ADDR(&from, buf1)); @@ -324,55 +328,24 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) } goto cleanup; } - - teid = be32toh(gtp_h->teid); + if (header_desc.type != OGS_GTPU_MSGTYPE_END_MARKER && + pkbuf->len <= len) { + ogs_error("[DROP] Small GTPU packet(type:%d len:%d)", + header_desc.type, len); + ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len); + goto cleanup; + } ogs_trace("[RECV] GPU-U Type [%d] from [%s] : TEID[0x%x]", - gtp_h->type, OGS_ADDR(&from, buf1), teid); - - qfi = 0; - if (gtp_h->flags & OGS_GTPU_FLAGS_E) { - /* - * TS29.281 - * 5.2.1 General format of the GTP-U Extension Header - * Figure 5.2.1-3: Definition of Extension Header Type - * - * Note 4 : For a GTP-PDU with several Extension Headers, the PDU - * Session Container should be the first Extension Header - */ - ogs_gtp2_extension_header_t *extension_header = - (ogs_gtp2_extension_header_t *)(pkbuf->data+OGS_GTPV1U_HEADER_LEN); - ogs_assert(extension_header); - if (extension_header->type == - OGS_GTP2_EXTENSION_HEADER_TYPE_PDU_SESSION_CONTAINER) { - if (extension_header->pdu_type == - OGS_GTP2_EXTENSION_HEADER_PDU_TYPE_UL_PDU_SESSION_INFORMATION) { - ogs_trace(" QFI [0x%x]", - extension_header->qos_flow_identifier); - qfi = extension_header->qos_flow_identifier; - } - } - } + header_desc.type, OGS_ADDR(&from, buf1), header_desc.teid); /* Remove GTP header and send packets to TUN interface */ - len = ogs_gtpu_header_len(pkbuf); - if (len < 0) { - ogs_error("[DROP] Cannot decode GTPU packet"); - ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len); - goto cleanup; - } - if (gtp_h->type != OGS_GTPU_MSGTYPE_END_MARKER && - pkbuf->len <= len) { - ogs_error("[DROP] Small GTPU packet(type:%d len:%d)", gtp_h->type, len); - ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len); - goto cleanup; - } ogs_assert(ogs_pkbuf_pull(pkbuf, len)); - if (gtp_h->type == OGS_GTPU_MSGTYPE_END_MARKER) { + if (header_desc.type == OGS_GTPU_MSGTYPE_END_MARKER) { /* Nothing */ - } else if (gtp_h->type == OGS_GTPU_MSGTYPE_ERR_IND) { + } else if (header_desc.type == OGS_GTPU_MSGTYPE_ERR_IND) { ogs_pfcp_far_t *far = NULL; far = ogs_pfcp_far_find_by_gtpu_error_indication(pkbuf); @@ -394,7 +367,7 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len); } - } else if (gtp_h->type == OGS_GTPU_MSGTYPE_GPDU) { + } else if (header_desc.type == OGS_GTPU_MSGTYPE_GPDU) { uint16_t eth_type = 0; struct ip *ip_h = NULL; uint32_t *src_addr = NULL; @@ -419,11 +392,11 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) */ #if 0 upf_metrics_inst_global_inc(UPF_METR_GLOB_CTR_GTP_INDATAPKTN3UPF); - upf_metrics_inst_by_qfi_add(qfi, + upf_metrics_inst_by_qfi_add(header_desc.qos_flow_identifier, UPF_METR_CTR_GTP_INDATAVOLUMEQOSLEVELN3UPF, pkbuf->len); #endif - pfcp_object = ogs_pfcp_object_find_by_teid(teid); + pfcp_object = ogs_pfcp_object_find_by_teid(header_desc.teid); if (!pfcp_object) { /* * TS23.527 Restoration procedures @@ -440,9 +413,11 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) ogs_app()->time.message.pfcp.association_interval))) { ogs_error("[%s] Send Error Indication [TEID:0x%x] to [%s]", OGS_ADDR(&sock->local_addr, buf1), - teid, + header_desc.teid, OGS_ADDR(&from, buf2)); - ogs_gtp1_send_error_indication(sock, teid, qfi, &from); + ogs_gtp1_send_error_indication( + sock, header_desc.teid, + header_desc.qos_flow_identifier, &from); } goto cleanup; } @@ -466,11 +441,12 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) continue; /* Check if TEID */ - if (teid != pdr->f_teid.teid) + if (header_desc.teid != pdr->f_teid.teid) continue; /* Check if QFI */ - if (qfi && pdr->qfi != qfi) + if (header_desc.qos_flow_identifier && + pdr->qfi != header_desc.qos_flow_identifier) continue; /* Check if Rule List in PDR */ @@ -493,14 +469,16 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) */ if (ogs_time_ntp32_now() > (ogs_pfcp_self()->local_recovery + - ogs_time_sec( - ogs_app()->time.message.pfcp.association_interval))) { + ogs_time_sec(ogs_app()->time.message.pfcp. + association_interval))) { ogs_error( "[%s] Send Error Indication [TEID:0x%x] to [%s]", OGS_ADDR(&sock->local_addr, buf1), - teid, + header_desc.teid, OGS_ADDR(&from, buf2)); - ogs_gtp1_send_error_indication(sock, teid, qfi, &from); + ogs_gtp1_send_error_indication( + sock, header_desc.teid, + header_desc.qos_flow_identifier, &from); } goto cleanup; } @@ -540,7 +518,7 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) /* Or source IP address should match a framed route */ } else { ogs_error("[DROP] Source IP-%d Spoofing APN:%s SrcIf:%d DstIf:%d TEID:0x%x", - ip_h->ip_v, pdr->dnn, pdr->src_if, far->dst_if, teid); + ip_h->ip_v, pdr->dnn, pdr->src_if, far->dst_if, header_desc.teid); ogs_error(" SRC:%08X, UE:%08X", be32toh(src_addr[0]), be32toh(sess->ipv4->addr[0])); ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len); @@ -618,7 +596,7 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) /* Or source IP address should match a framed route */ } else { ogs_error("[DROP] Source IP-%d Spoofing APN:%s SrcIf:%d DstIf:%d TEID:0x%x", - ip_h->ip_v, pdr->dnn, pdr->src_if, far->dst_if, teid); + ip_h->ip_v, pdr->dnn, pdr->src_if, far->dst_if, header_desc.teid); ogs_error("SRC:%08x %08x %08x %08x", be32toh(src_addr[0]), be32toh(src_addr[1]), be32toh(src_addr[2]), be32toh(src_addr[3])); @@ -678,7 +656,7 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) } else if (far->dst_if == OGS_PFCP_INTERFACE_ACCESS) { ogs_assert(true == ogs_pfcp_up_handle_pdr( - pdr, gtp_h->type, pkbuf, &report)); + pdr, header_desc.type, &header_desc, pkbuf, &report)); if (report.type.downlink_data_report) { ogs_error("Indirect Data Fowarding Buffered"); @@ -705,7 +683,7 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) } ogs_assert(true == ogs_pfcp_up_handle_pdr( - pdr, gtp_h->type, pkbuf, &report)); + pdr, header_desc.type, &header_desc, pkbuf, &report)); ogs_assert(report.type.downlink_data_report == 0); @@ -714,7 +692,7 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) ogs_assert_if_reached(); } } else { - ogs_error("[DROP] Invalid GTPU Type [%d]", gtp_h->type); + ogs_error("[DROP] Invalid GTPU Type [%d]", header_desc.type); ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len); } @@ -895,8 +873,9 @@ static void upf_gtp_handle_multicast(ogs_pkbuf_t *recvbuf) ogs_list_for_each(&sess->pfcp.pdr_list, pdr) { if (pdr->src_if == OGS_PFCP_INTERFACE_CORE) { ogs_assert(true == - ogs_pfcp_up_handle_pdr(pdr, - OGS_GTPU_MSGTYPE_GPDU, recvbuf, &report)); + ogs_pfcp_up_handle_pdr( + pdr, OGS_GTPU_MSGTYPE_GPDU, + NULL, recvbuf, &report)); break; } } diff --git a/tests/common/gtpu.c b/tests/common/gtpu.c index 091e216db..18b07153b 100644 --- a/tests/common/gtpu.c +++ b/tests/common/gtpu.c @@ -61,7 +61,8 @@ ogs_pkbuf_t *test_gtpu_read(ogs_socknode_t *node) ogs_sockaddr_t from; ogs_pkbuf_t *recvbuf = ogs_pkbuf_alloc(NULL, OGS_MAX_SDU_LEN); ogs_assert(recvbuf); - ogs_pkbuf_put(recvbuf, OGS_MAX_SDU_LEN); + ogs_pkbuf_reserve(recvbuf, 4); /* For additional extension header */ + ogs_pkbuf_put(recvbuf, OGS_MAX_SDU_LEN-4); ogs_assert(node); ogs_assert(node->sock); @@ -149,7 +150,7 @@ void testgtpu_recv(test_ue_t *test_ue, ogs_pkbuf_t *pkbuf) found: ogs_assert(sess); - ip6_h = pkbuf->data + ogs_gtpu_header_len(pkbuf); + ip6_h = pkbuf->data + ogs_gtpu_parse_header(NULL, pkbuf); ogs_assert(ip6_h); if (ip6_h->ip6_nxt == IPPROTO_ICMPV6) { struct nd_router_advert *advert_h = (struct nd_router_advert *) @@ -172,14 +173,12 @@ found: int test_gtpu_send( ogs_socknode_t *node, test_bearer_t *bearer, - ogs_gtp2_header_t *gtp_hdesc, ogs_gtp2_extension_header_t *ext_hdesc, - ogs_pkbuf_t *pkbuf) + ogs_gtp2_header_desc_t *header_desc, ogs_pkbuf_t *pkbuf) { ogs_gtp_node_t gnode; test_sess_t *sess = NULL; - ogs_assert(gtp_hdesc); - ogs_assert(ext_hdesc); + ogs_assert(header_desc); ogs_assert(pkbuf); ogs_assert(bearer); @@ -221,10 +220,7 @@ int test_gtpu_send( ogs_assert_if_reached(); } - ext_hdesc->pdu_type = - OGS_GTP2_EXTENSION_HEADER_PDU_TYPE_UL_PDU_SESSION_INFORMATION; - - return ogs_gtp2_send_user_plane(&gnode, gtp_hdesc, ext_hdesc, pkbuf); + return ogs_gtp2_send_user_plane(&gnode, header_desc, pkbuf); } int test_gtpu_send_ping( @@ -233,8 +229,7 @@ int test_gtpu_send_ping( int rv; test_sess_t *sess = NULL; - ogs_gtp2_header_t gtp_hdesc; - ogs_gtp2_extension_header_t ext_hdesc; + ogs_gtp2_header_desc_t header_desc; ogs_pkbuf_t *pkbuf = NULL; ogs_ipsubnet_t dst_ipsub; @@ -322,32 +317,31 @@ int test_gtpu_send_ping( ogs_assert_if_reached(); } - memset(>p_hdesc, 0, sizeof(gtp_hdesc)); - memset(&ext_hdesc, 0, sizeof(ext_hdesc)); + memset(&header_desc, 0, sizeof(header_desc)); - gtp_hdesc.type = OGS_GTPU_MSGTYPE_GPDU; + header_desc.type = OGS_GTPU_MSGTYPE_GPDU; if (bearer->qfi) { - gtp_hdesc.teid = sess->upf_n3_teid; - ext_hdesc.qos_flow_identifier = bearer->qfi; - + header_desc.teid = sess->upf_n3_teid; + header_desc.pdu_type = + OGS_GTP2_EXTENSION_HEADER_PDU_TYPE_UL_PDU_SESSION_INFORMATION; + header_desc.qos_flow_identifier = bearer->qfi; } else if (bearer->ebi) { - gtp_hdesc.teid = bearer->sgw_s1u_teid; + header_desc.teid = bearer->sgw_s1u_teid; } else { ogs_fatal("No QFI[%d] and EBI[%d]", bearer->qfi, bearer->ebi); ogs_assert_if_reached(); } - return test_gtpu_send(node, bearer, >p_hdesc, &ext_hdesc, pkbuf); + return test_gtpu_send(node, bearer, &header_desc, pkbuf); } int test_gtpu_send_slacc_rs(ogs_socknode_t *node, test_bearer_t *bearer) { test_sess_t *sess = NULL; - ogs_gtp2_header_t gtp_hdesc; - ogs_gtp2_extension_header_t ext_hdesc; + ogs_gtp2_header_desc_t header_desc; ogs_pkbuf_t *pkbuf = NULL; struct ip6_hdr *ip6_h = NULL; @@ -383,30 +377,30 @@ int test_gtpu_send_slacc_rs(ogs_socknode_t *node, test_bearer_t *bearer) ogs_pkbuf_trim(pkbuf, payload_len); - memset(>p_hdesc, 0, sizeof(gtp_hdesc)); - memset(&ext_hdesc, 0, sizeof(ext_hdesc)); + memset(&header_desc, 0, sizeof(header_desc)); - gtp_hdesc.type = OGS_GTPU_MSGTYPE_GPDU; - gtp_hdesc.flags = OGS_GTPU_FLAGS_S; + header_desc.type = OGS_GTPU_MSGTYPE_GPDU; + header_desc.flags = OGS_GTPU_FLAGS_S; if (bearer->qfi) { - gtp_hdesc.teid = sess->upf_n3_teid; - /* * Discussion #1506 * Router Soliciation should include QFI in 5G Core */ - ext_hdesc.qos_flow_identifier = bearer->qfi; + header_desc.teid = sess->upf_n3_teid; + header_desc.pdu_type = + OGS_GTP2_EXTENSION_HEADER_PDU_TYPE_UL_PDU_SESSION_INFORMATION; + header_desc.qos_flow_identifier = bearer->qfi; } else if (bearer->ebi) { - gtp_hdesc.teid = bearer->sgw_s1u_teid; + header_desc.teid = bearer->sgw_s1u_teid; } else { ogs_fatal("No QFI[%d] and EBI[%d]", bearer->qfi, bearer->ebi); ogs_assert_if_reached(); } - return test_gtpu_send(node, bearer, >p_hdesc, &ext_hdesc, pkbuf); + return test_gtpu_send(node, bearer, &header_desc, pkbuf); } int test_gtpu_send_slacc_rs_with_unspecified_source_address( @@ -414,8 +408,7 @@ int test_gtpu_send_slacc_rs_with_unspecified_source_address( { test_sess_t *sess = NULL; - ogs_gtp2_header_t gtp_hdesc; - ogs_gtp2_extension_header_t ext_hdesc; + ogs_gtp2_header_desc_t header_desc; ogs_pkbuf_t *pkbuf = NULL; struct ip6_hdr *ip6_h = NULL; @@ -444,30 +437,31 @@ int test_gtpu_send_slacc_rs_with_unspecified_source_address( ogs_pkbuf_trim(pkbuf, payload_len); - memset(>p_hdesc, 0, sizeof(gtp_hdesc)); - memset(&ext_hdesc, 0, sizeof(ext_hdesc)); + memset(&header_desc, 0, sizeof(header_desc)); - gtp_hdesc.type = OGS_GTPU_MSGTYPE_GPDU; - gtp_hdesc.flags = OGS_GTPU_FLAGS_S; + header_desc.type = OGS_GTPU_MSGTYPE_GPDU; + header_desc.flags = OGS_GTPU_FLAGS_S; if (bearer->qfi) { - gtp_hdesc.teid = sess->upf_n3_teid; - + header_desc.teid = sess->upf_n3_teid; /* * Discussion #1506 * Router Soliciation should include QFI in 5G Core */ - ext_hdesc.qos_flow_identifier = bearer->qfi; + header_desc.teid = sess->upf_n3_teid; + header_desc.pdu_type = + OGS_GTP2_EXTENSION_HEADER_PDU_TYPE_UL_PDU_SESSION_INFORMATION; + header_desc.qos_flow_identifier = bearer->qfi; } else if (bearer->ebi) { - gtp_hdesc.teid = bearer->sgw_s1u_teid; + header_desc.teid = bearer->sgw_s1u_teid; } else { ogs_fatal("No QFI[%d] and EBI[%d]", bearer->qfi, bearer->ebi); ogs_assert_if_reached(); } - return test_gtpu_send(node, bearer, >p_hdesc, &ext_hdesc, pkbuf); + return test_gtpu_send(node, bearer, &header_desc, pkbuf); } @@ -477,8 +471,7 @@ int test_gtpu_send_error_indication( test_sess_t *sess = NULL; uint32_t teid = 0; - ogs_gtp2_header_t gtp_hdesc; - ogs_gtp2_extension_header_t ext_hdesc; + ogs_gtp2_header_desc_t header_desc; ogs_pkbuf_t *pkbuf = NULL; @@ -486,9 +479,19 @@ int test_gtpu_send_error_indication( sess = bearer->sess; ogs_assert(sess); + memset(&header_desc, 0, sizeof(header_desc)); + + header_desc.type = OGS_GTPU_MSGTYPE_ERR_IND; + header_desc.flags = OGS_GTPU_FLAGS_S|OGS_GTPU_FLAGS_E; + header_desc.udp.presence = true; + header_desc.udp.port = 0; + if (bearer->qfi) { /* 5GC */ teid = sess->gnb_n3_teid; + header_desc.pdu_type = + OGS_GTP2_EXTENSION_HEADER_PDU_TYPE_UL_PDU_SESSION_INFORMATION; + header_desc.qos_flow_identifier = bearer->qfi; } else if (bearer->ebi) { /* EPC */ @@ -502,14 +505,7 @@ int test_gtpu_send_error_indication( pkbuf = ogs_gtp1_build_error_indication(teid, node->addr); ogs_assert(pkbuf); - memset(>p_hdesc, 0, sizeof(gtp_hdesc)); - memset(&ext_hdesc, 0, sizeof(ext_hdesc)); - - gtp_hdesc.type = OGS_GTPU_MSGTYPE_ERR_IND; - gtp_hdesc.flags = OGS_GTPU_FLAGS_S|OGS_GTPU_FLAGS_E; - ext_hdesc.type = OGS_GTP2_EXTENSION_HEADER_TYPE_UDP_PORT; - - return test_gtpu_send(node, bearer, >p_hdesc, &ext_hdesc, pkbuf); + return test_gtpu_send(node, bearer, &header_desc, pkbuf); } int test_gtpu_send_indirect_data_forwarding( @@ -517,30 +513,33 @@ int test_gtpu_send_indirect_data_forwarding( { test_sess_t *sess = NULL; - ogs_gtp2_header_t gtp_hdesc; - ogs_gtp2_extension_header_t ext_hdesc; + ogs_gtp2_header_desc_t header_desc; ogs_assert(bearer); sess = bearer->sess; ogs_assert(sess); ogs_assert(pkbuf); - memset(>p_hdesc, 0, sizeof(gtp_hdesc)); - memset(&ext_hdesc, 0, sizeof(ext_hdesc)); + memset(&header_desc, 0, sizeof(header_desc)); - gtp_hdesc.type = OGS_GTPU_MSGTYPE_GPDU; + header_desc.type = OGS_GTPU_MSGTYPE_GPDU; if (bearer->qfi) { - gtp_hdesc.teid = sess->handover.upf_dl_teid; - ext_hdesc.qos_flow_identifier = bearer->qfi; + header_desc.teid = sess->handover.upf_dl_teid; + header_desc.pdu_type = + OGS_GTP2_EXTENSION_HEADER_PDU_TYPE_UL_PDU_SESSION_INFORMATION; + header_desc.qos_flow_identifier = bearer->qfi; } else if (bearer->ebi) { - gtp_hdesc.teid = bearer->handover.ul_teid; + header_desc.teid = bearer->handover.ul_teid; } else { ogs_fatal("No QFI[%d] and EBI[%d]", bearer->qfi, bearer->ebi); ogs_assert_if_reached(); } - return test_gtpu_send(node, bearer, >p_hdesc, &ext_hdesc, pkbuf); + header_desc.pdcp_number_presence = true; + header_desc.pdcp_number = 0x4567; + + return test_gtpu_send(node, bearer, &header_desc, pkbuf); } diff --git a/tests/common/gtpu.h b/tests/common/gtpu.h index 6db7b95b9..10066f04e 100644 --- a/tests/common/gtpu.h +++ b/tests/common/gtpu.h @@ -35,8 +35,7 @@ void testgtpu_recv(test_ue_t *test_ue, ogs_pkbuf_t *pkbuf); int test_gtpu_send( ogs_socknode_t *node, test_bearer_t *bearer, - ogs_gtp2_header_t *gtp_hdesc, ogs_gtp2_extension_header_t *ext_hdesc, - ogs_pkbuf_t *pkbuf); + ogs_gtp2_header_desc_t *header_desc, ogs_pkbuf_t *pkbuf); int test_gtpu_send_ping( ogs_socknode_t *node, test_bearer_t *bearer, const char *dst_ip); int test_gtpu_send_slacc_rs(ogs_socknode_t *node, test_bearer_t *bearer);