forked from acouzens/open5gs
[#568] Add GTP-U Error Indication Handling
So far, no operation was performed when Error Indication was received from eNodeB. For that reason, I solved #568 issues by controlling the MME to prevent this from happening. Now, when GTP-U Error Indication is received, MME and SGW are implemented to do what they have to do. I hope that the network can be restored by responding appropriately even if Error Indication occurs.
This commit is contained in:
parent
c244dcc5e9
commit
1bed0d5872
|
@ -339,13 +339,16 @@ static void cluster_free(ogs_pkbuf_pool_t *pool, ogs_cluster_t *cluster)
|
|||
ogs_pool_free(&pool->cluster_512, (ogs_cluster_512_t*)cluster->buffer);
|
||||
break;
|
||||
case OGS_CLUSTER_1024_SIZE:
|
||||
ogs_pool_free(&pool->cluster_1024, (ogs_cluster_1024_t*)cluster->buffer);
|
||||
ogs_pool_free(
|
||||
&pool->cluster_1024, (ogs_cluster_1024_t*)cluster->buffer);
|
||||
break;
|
||||
case OGS_CLUSTER_2048_SIZE:
|
||||
ogs_pool_free(&pool->cluster_2048, (ogs_cluster_2048_t*)cluster->buffer);
|
||||
ogs_pool_free(
|
||||
&pool->cluster_2048, (ogs_cluster_2048_t*)cluster->buffer);
|
||||
break;
|
||||
case OGS_CLUSTER_8192_SIZE:
|
||||
ogs_pool_free(&pool->cluster_8192, (ogs_cluster_8192_t*)cluster->buffer);
|
||||
ogs_pool_free(
|
||||
&pool->cluster_8192, (ogs_cluster_8192_t*)cluster->buffer);
|
||||
break;
|
||||
case OGS_CLUSTER_BIG_SIZE:
|
||||
ogs_pool_free(&pool->cluster_big, (ogs_cluster_big_t*)cluster->buffer);
|
||||
|
@ -356,4 +359,3 @@ static void cluster_free(ogs_pkbuf_pool_t *pool, ogs_cluster_t *cluster)
|
|||
|
||||
ogs_pool_free(&pool->cluster, cluster);
|
||||
}
|
||||
|
||||
|
|
|
@ -110,6 +110,20 @@ static ogs_inline void ogs_pkbuf_put_u8(ogs_pkbuf_t *pkbuf, uint8_t val)
|
|||
*(uint8_t *)ogs_pkbuf_put(pkbuf, 1) = val;
|
||||
}
|
||||
|
||||
static ogs_inline void ogs_pkbuf_put_u16(ogs_pkbuf_t *pkbuf, uint16_t val)
|
||||
{
|
||||
uint8_t *p = ogs_pkbuf_put(pkbuf, 2);
|
||||
uint16_t tmp = htobe16(val);
|
||||
memcpy(p, &tmp, 2);
|
||||
}
|
||||
|
||||
static ogs_inline void ogs_pkbuf_put_u32(ogs_pkbuf_t *pkbuf, uint32_t val)
|
||||
{
|
||||
uint8_t *p = ogs_pkbuf_put(pkbuf, 4);
|
||||
uint32_t tmp = htobe32(val);
|
||||
memcpy(p, &tmp, 4);
|
||||
}
|
||||
|
||||
static ogs_inline void *ogs_pkbuf_push(ogs_pkbuf_t *pkbuf, unsigned int len)
|
||||
{
|
||||
pkbuf->data -= len;
|
||||
|
|
|
@ -300,7 +300,7 @@ const char *ogs_inet_ntop(void *sa, char *buf, int buflen)
|
|||
ogs_assert(buflen >= OGS_ADDRSTRLEN);
|
||||
|
||||
family = sockaddr->ogs_sa_family;
|
||||
switch(family) {
|
||||
switch (family) {
|
||||
case AF_INET:
|
||||
return inet_ntop(family, &sockaddr->sin.sin_addr, buf,
|
||||
INET_ADDRSTRLEN);
|
||||
|
|
|
@ -56,3 +56,56 @@ ogs_pkbuf_t *ogs_gtp_build_echo_response(
|
|||
gtp_message.h.type = type;
|
||||
return ogs_gtp_build_msg(>p_message);
|
||||
}
|
||||
|
||||
ogs_pkbuf_t *ogs_gtp_build_error_indication(
|
||||
uint32_t teid, ogs_sockaddr_t *addr)
|
||||
{
|
||||
ogs_pkbuf_t *pkbuf = NULL;
|
||||
unsigned char *p = NULL;
|
||||
int family;
|
||||
|
||||
ogs_assert(addr);
|
||||
|
||||
pkbuf = ogs_pkbuf_alloc(
|
||||
NULL, 100 /* enough for Error Indiciation; use smaller buffer */);
|
||||
ogs_assert(pkbuf);
|
||||
ogs_pkbuf_reserve(pkbuf, OGS_GTPV1U_5GC_HEADER_LEN);
|
||||
|
||||
/*
|
||||
* 8.3 Tunnel Endpoint Identifier Data I
|
||||
*
|
||||
* Octet 1 : Type = 16 (Decimal)
|
||||
* Octet 2-5 : Tunnel Endpoint Identitifer Data I
|
||||
*/
|
||||
ogs_pkbuf_put_u8(pkbuf, 16);
|
||||
ogs_pkbuf_put_u32(pkbuf, teid);
|
||||
|
||||
/*
|
||||
* 8.4 GTP-U Peer Address
|
||||
*
|
||||
* Octet 1 : Type = 133 (Decimal)
|
||||
* Octet 2-3 : Length
|
||||
* Octet 4-n : IPv4 or IPv6 Address
|
||||
*/
|
||||
ogs_pkbuf_put_u8(pkbuf, 133);
|
||||
|
||||
family = addr->ogs_sa_family;
|
||||
switch(family) {
|
||||
case AF_INET:
|
||||
ogs_pkbuf_put_u16(pkbuf, OGS_IPV4_LEN);
|
||||
p = ogs_pkbuf_put(pkbuf, OGS_IPV4_LEN);
|
||||
memcpy(p, &addr->sin.sin_addr, OGS_IPV4_LEN);
|
||||
break;
|
||||
case AF_INET6:
|
||||
ogs_pkbuf_put_u16(pkbuf, OGS_IPV6_LEN);
|
||||
p = ogs_pkbuf_put(pkbuf, OGS_IPV6_LEN);
|
||||
memcpy(p, &addr->sin6.sin6_addr, OGS_IPV6_LEN);
|
||||
break;
|
||||
default:
|
||||
ogs_fatal("Unknown family(%d)", family);
|
||||
ogs_abort();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pkbuf;
|
||||
}
|
||||
|
|
|
@ -33,6 +33,9 @@ ogs_pkbuf_t *ogs_gtp_build_echo_request(
|
|||
ogs_pkbuf_t *ogs_gtp_build_echo_response(
|
||||
uint8_t type, uint8_t recovery, uint8_t features);
|
||||
|
||||
ogs_pkbuf_t *ogs_gtp_build_error_indication(
|
||||
uint32_t teid, ogs_sockaddr_t *addr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
/*******************************************************************************
|
||||
* This file had been created by gtp-tlv.py script v0.1.0
|
||||
* Please do not modify this file but regenerate it via script.
|
||||
* Created on: 2020-08-11 20:17:53.518172 by acetcom
|
||||
* Created on: 2020-10-14 13:48:14.476575 by acetcom
|
||||
* from 29274-g30.docx
|
||||
******************************************************************************/
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
/*******************************************************************************
|
||||
* This file had been created by gtp-tlv.py script v0.1.0
|
||||
* Please do not modify this file but regenerate it via script.
|
||||
* Created on: 2020-08-11 20:17:53.511069 by acetcom
|
||||
* Created on: 2020-10-14 13:48:14.468022 by acetcom
|
||||
* from 29274-g30.docx
|
||||
******************************************************************************/
|
||||
|
||||
|
@ -50,9 +50,11 @@ typedef struct ogs_gtp_header_s {
|
|||
uint8_t spare1:3;)
|
||||
};
|
||||
/* GTU-U flags */
|
||||
#define OGS_GTPU_FLAGS_PN 0x1
|
||||
#define OGS_GTPU_FLAGS_S 0x2
|
||||
#define OGS_GTPU_FLAGS_E 0x4
|
||||
#define OGS_GTPU_FLAGS_V 0x20
|
||||
#define OGS_GTPU_FLAGS_PT 0x10
|
||||
#define OGS_GTPU_FLAGS_E 0x04
|
||||
#define OGS_GTPU_FLAGS_S 0x02
|
||||
#define OGS_GTPU_FLAGS_PN 0x01
|
||||
uint8_t flags;
|
||||
};
|
||||
/* GTP-U message type, defined in 3GPP TS 29.281 Release 11 */
|
||||
|
|
108
lib/gtp/path.c
108
lib/gtp/path.c
|
@ -123,6 +123,114 @@ int ogs_gtp_sendto(ogs_gtp_node_t *gnode, ogs_pkbuf_t *pkbuf)
|
|||
return OGS_OK;
|
||||
}
|
||||
|
||||
int ogs_gtp_send_user_plane(
|
||||
ogs_gtp_node_t *gnode,
|
||||
ogs_gtp_header_t *gtp_hdesc, ogs_gtp_extension_header_t *ext_hdesc,
|
||||
ogs_pkbuf_t *pkbuf)
|
||||
{
|
||||
char buf[OGS_ADDRSTRLEN];
|
||||
int rv;
|
||||
|
||||
ogs_gtp_header_t *gtp_h = NULL;
|
||||
ogs_gtp_extension_header_t *ext_h = NULL;
|
||||
uint8_t flags;
|
||||
uint8_t gtp_hlen = 0;
|
||||
|
||||
ogs_assert(gnode);
|
||||
ogs_assert(gtp_hdesc);
|
||||
ogs_assert(ext_hdesc);
|
||||
ogs_assert(pkbuf);
|
||||
|
||||
/* 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;
|
||||
|
||||
/* 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;
|
||||
else
|
||||
gtp_hlen = OGS_GTPV1U_HEADER_LEN;
|
||||
|
||||
ogs_pkbuf_push(pkbuf, gtp_hlen);
|
||||
|
||||
/* Fill GTP Header */
|
||||
gtp_h = (ogs_gtp_header_t *)pkbuf->data;
|
||||
ogs_assert(gtp_h);
|
||||
memset(gtp_h, 0, gtp_hlen);
|
||||
|
||||
gtp_h->flags = flags;
|
||||
gtp_h->type = gtp_hdesc->type;
|
||||
|
||||
if (gtp_h->type == OGS_GTPU_MSGTYPE_ECHO_REQ ||
|
||||
gtp_h->type == OGS_GTPU_MSGTYPE_ECHO_RSP ||
|
||||
gtp_h->type == OGS_GTPU_MSGTYPE_ERR_IND) {
|
||||
/*
|
||||
* TS29.281 5.1 General format in GTP-U header
|
||||
*
|
||||
* - The Echo Request/Response and Supported Extension Headers
|
||||
* notification messages, where the Tunnel Endpoint Identifier
|
||||
* shall be set to all zeroes.
|
||||
* - The Error Indication message where the Tunnel Endpoint Identifier
|
||||
* shall be set to all zeros.
|
||||
*/
|
||||
ogs_assert(gtp_hdesc->teid == 0);
|
||||
}
|
||||
|
||||
gtp_h->teid = htobe32(gtp_hdesc->teid);
|
||||
|
||||
/*
|
||||
* TS29.281 5.1 General format in GTP-U header
|
||||
*
|
||||
* Length: This field indicates the length in octets of the payload,
|
||||
* i.e. the rest of the packet following the mandatory part of
|
||||
* the GTP header (that is the first 8 octets). The Sequence Number,
|
||||
* the N-PDU Number or any Extension headers shall be considered
|
||||
* to be part of the payload, i.e. included in the length count.
|
||||
*/
|
||||
gtp_h->length = htobe16(pkbuf->len - OGS_GTPV1U_HEADER_LEN);
|
||||
|
||||
/* Fill Extention Header */
|
||||
if (gtp_h->flags & OGS_GTPU_FLAGS_E) {
|
||||
ext_h = (ogs_gtp_extension_header_t *)
|
||||
(pkbuf->data + OGS_GTPV1U_HEADER_LEN);
|
||||
ogs_assert(ext_h);
|
||||
|
||||
if (ext_hdesc->qos_flow_identifier) {
|
||||
/* 5G Core */
|
||||
ext_h->type = OGS_GTP_EXTENSION_HEADER_TYPE_PDU_SESSION_CONTAINER;
|
||||
ext_h->len = 1;
|
||||
ext_h->pdu_type =
|
||||
OGS_GTP_EXTENSION_HEADER_PDU_TYPE_UL_PDU_SESSION_INFORMATION;
|
||||
ext_h->qos_flow_identifier = ext_hdesc->qos_flow_identifier;
|
||||
ext_h->next_type =
|
||||
OGS_GTP_EXTENSION_HEADER_TYPE_NO_MORE_EXTENSION_HEADERS;
|
||||
} else {
|
||||
/* EPC */
|
||||
ext_h->type = ext_hdesc->type;
|
||||
ext_h->len = 1;
|
||||
ext_h->next_type =
|
||||
OGS_GTP_EXTENSION_HEADER_TYPE_NO_MORE_EXTENSION_HEADERS;
|
||||
}
|
||||
}
|
||||
|
||||
ogs_debug("SEND GTP-U[%d] to Peer[%s] : TEID[0x%x]",
|
||||
gtp_hdesc->type, OGS_ADDR(&gnode->addr, buf), gtp_hdesc->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);
|
||||
}
|
||||
}
|
||||
|
||||
ogs_pkbuf_free(pkbuf);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
ogs_pkbuf_t *ogs_gtp_handle_echo_req(ogs_pkbuf_t *pkb)
|
||||
{
|
||||
ogs_gtp_header_t *gtph = NULL;
|
||||
|
|
|
@ -36,6 +36,11 @@ int ogs_gtp_connect(ogs_sock_t *ipv4, ogs_sock_t *ipv6, ogs_gtp_node_t *gnode);
|
|||
int ogs_gtp_send(ogs_gtp_node_t *gnode, ogs_pkbuf_t *pkbuf);
|
||||
int ogs_gtp_sendto(ogs_gtp_node_t *gnode, ogs_pkbuf_t *pkbuf);
|
||||
|
||||
int ogs_gtp_send_user_plane(
|
||||
ogs_gtp_node_t *gnode,
|
||||
ogs_gtp_header_t *gtp_hdesc, ogs_gtp_extension_header_t *ext_hdesc,
|
||||
ogs_pkbuf_t *pkbuf);
|
||||
|
||||
ogs_pkbuf_t *ogs_gtp_handle_echo_req(ogs_pkbuf_t *pkt);
|
||||
void ogs_gtp_send_error_message(
|
||||
ogs_gtp_xact_t *xact, uint32_t teid, uint8_t type, uint8_t cause_value);
|
||||
|
|
|
@ -411,9 +411,11 @@ typedef struct ogs_gtp_header_s {
|
|||
uint8_t spare1:3;)
|
||||
};
|
||||
/* GTU-U flags */
|
||||
#define OGS_GTPU_FLAGS_PN 0x1
|
||||
#define OGS_GTPU_FLAGS_S 0x2
|
||||
#define OGS_GTPU_FLAGS_E 0x4
|
||||
#define OGS_GTPU_FLAGS_V 0x20
|
||||
#define OGS_GTPU_FLAGS_PT 0x10
|
||||
#define OGS_GTPU_FLAGS_E 0x04
|
||||
#define OGS_GTPU_FLAGS_S 0x02
|
||||
#define OGS_GTPU_FLAGS_PN 0x01
|
||||
uint8_t flags;
|
||||
};
|
||||
/* GTP-U message type, defined in 3GPP TS 29.281 Release 11 */
|
||||
|
|
|
@ -51,6 +51,7 @@ extern "C" {
|
|||
|
||||
#define OGS_GTPV1U_EXTENSION_HEADER_LEN 4
|
||||
typedef struct ogs_gtp_extension_header_s {
|
||||
#define OGS_GTP_EXTENSION_HEADER_TYPE_UDP_PORT 0x40
|
||||
#define OGS_GTP_EXTENSION_HEADER_TYPE_PDU_SESSION_CONTAINER 0x85
|
||||
#define OGS_GTP_EXTENSION_HEADER_TYPE_NO_MORE_EXTENSION_HEADERS 0x0
|
||||
uint16_t sequence_number;
|
||||
|
@ -68,12 +69,13 @@ typedef struct ogs_gtp_extension_header_s {
|
|||
} __attribute__ ((packed)) ogs_gtp_extension_header_t;
|
||||
|
||||
/* 8.4 Cause */
|
||||
#define OGS_GTP_CAUSE_LOCAL_DETACH 2
|
||||
#define OGS_GTP_CAUSE_INVALID_VALUE 0
|
||||
#define OGS_GTP_CAUSE_LOCAL_DETACH 2
|
||||
#define OGS_GTP_CAUSE_COMPLETE_DETACH_3
|
||||
#define OGS_GTP_CAUSE_RAT_CHANGED_FROM_3GPP_TO_NON_3GPP 4
|
||||
#define OGS_GTP_CAUSE_ISR_DEACTIVATION 5
|
||||
#define OGS_GTP_CAUSE_ERROR_INDICATION_RECEIVED_FROM_RNC_ENODEB_S4_SGSN_MME 6
|
||||
#define OGS_GTP_CAUSE_IMSI_DETACH_ONLY 7
|
||||
#define OGS_GTP_CAUSE_ISR_DEACTIVATION 5
|
||||
#define OGS_GTP_CAUSE_ERROR_INDICATION_RECEIVED 6
|
||||
#define OGS_GTP_CAUSE_IMSI_DETACH_ONLY 7
|
||||
#define OGS_GTP_CAUSE_REACTIVATION_REQUESTED 8
|
||||
#define OGS_GTP_CAUSE_PDN_RECONNECTION_TO_THIS_APN_DISALLOWED 9
|
||||
#define OGS_GTP_CAUSE_ACCESS_CHANGED_FROM_NON_3GPP_TO_3GPP 10
|
||||
|
@ -81,7 +83,7 @@ typedef struct ogs_gtp_extension_header_s {
|
|||
#define OGS_GTP_CAUSE_PGW_NOT_RESPONDING 12
|
||||
#define OGS_GTP_CAUSE_NETWORK_FAILURE 13
|
||||
#define OGS_GTP_CAUSE_QOS_PARAMETER_MISMATCH 14
|
||||
#define OGS_GTP_CAUSE_REQUEST_ACCEPTED 16
|
||||
#define OGS_GTP_CAUSE_REQUEST_ACCEPTED 16
|
||||
#define OGS_GTP_CAUSE_REQUEST_ACCEPTED_PARTIALLY 17
|
||||
#define OGS_GTP_CAUSE_NEW_PDN_TYPE_DUE_TO_NETWORK_PREFERENCE 18
|
||||
#define OGS_GTP_CAUSE_NEW_PDN_TYPE_DUE_TO_SINGLE_ADDRESS_BEARER_ONLY 19
|
||||
|
@ -127,7 +129,7 @@ typedef struct ogs_gtp_extension_header_s {
|
|||
#define OGS_GTP_CAUSE_DATA_FORWARDING_NOT_SUPPORTED 106
|
||||
#define OGS_GTP_CAUSE_INVALID_REPLY_FROM_REMOTE_PEER 107
|
||||
#define OGS_GTP_CAUSE_FALLBACK_TO_GTPV1 108
|
||||
#define OGS_GTP_CAUSE_INVALID_PEER 109
|
||||
#define OGS_GTP_CAUSE_INVALID_PEER 109
|
||||
#define OGS_GTP_CAUSE_TEMPORARILY_REJECTED_DUE_TO_HANDOVER_IN_PROGRESS 110
|
||||
#define OGS_GTP_CAUSE_MODIFICATIONS_NOT_LIMITED_TO_S1_U_BEARERS 111
|
||||
#define OGS_GTP_CAUSE_REQUEST_REJECTED_FOR_A_PMIPV6_REASON 112
|
||||
|
|
|
@ -253,7 +253,6 @@ void ogs_pfcp_build_create_pdr(
|
|||
ogs_pfcp_tlv_create_pdr_t *message, int i, ogs_pfcp_pdr_t *pdr)
|
||||
{
|
||||
ogs_pfcp_far_t *far = NULL;
|
||||
ogs_pfcp_sess_t *pfcp_sess = NULL;
|
||||
ogs_pfcp_sdf_filter_t pfcp_sdf_filter[OGS_MAX_NUM_OF_RULE];
|
||||
int j = 0;
|
||||
int len = 0;
|
||||
|
@ -261,8 +260,6 @@ void ogs_pfcp_build_create_pdr(
|
|||
ogs_assert(message);
|
||||
|
||||
ogs_assert(pdr);
|
||||
pfcp_sess = pdr->sess;
|
||||
ogs_assert(pfcp_sess);
|
||||
|
||||
far = pdr->far;
|
||||
ogs_assert(far);
|
||||
|
@ -412,12 +409,8 @@ static struct {
|
|||
void ogs_pfcp_build_create_far(
|
||||
ogs_pfcp_tlv_create_far_t *message, int i, ogs_pfcp_far_t *far)
|
||||
{
|
||||
ogs_pfcp_sess_t *pfcp_sess = NULL;
|
||||
|
||||
ogs_assert(message);
|
||||
ogs_assert(far);
|
||||
pfcp_sess = far->sess;
|
||||
ogs_assert(pfcp_sess);
|
||||
|
||||
message->presence = 1;
|
||||
message->far_id.presence = 1;
|
||||
|
@ -637,6 +630,15 @@ ogs_pkbuf_t *ogs_pfcp_build_session_report_request(
|
|||
}
|
||||
}
|
||||
|
||||
if (report->error_indication.remote_f_teid_len) {
|
||||
req->error_indication_report.presence = 1;
|
||||
req->error_indication_report.remote_f_teid.presence = 1;
|
||||
req->error_indication_report.remote_f_teid.data =
|
||||
&report->error_indication.remote_f_teid;
|
||||
req->error_indication_report.remote_f_teid.len =
|
||||
report->error_indication.remote_f_teid_len;
|
||||
}
|
||||
|
||||
pfcp_message.h.type = type;
|
||||
return ogs_pfcp_build_msg(&pfcp_message);
|
||||
}
|
||||
|
|
|
@ -92,6 +92,7 @@ void ogs_pfcp_context_init(int num_of_gtpu_resource)
|
|||
ogs_pool_init(&ogs_pfcp_subnet_pool, OGS_MAX_NUM_OF_SUBNET);
|
||||
|
||||
self.pdr_hash = ogs_hash_make();
|
||||
self.far_hash = ogs_hash_make();
|
||||
|
||||
context_initialized = 1;
|
||||
}
|
||||
|
@ -102,6 +103,8 @@ void ogs_pfcp_context_final(void)
|
|||
|
||||
ogs_assert(self.pdr_hash);
|
||||
ogs_hash_destroy(self.pdr_hash);
|
||||
ogs_assert(self.far_hash);
|
||||
ogs_hash_destroy(self.far_hash);
|
||||
|
||||
ogs_pfcp_dev_remove_all();
|
||||
ogs_pfcp_subnet_remove_all();
|
||||
|
@ -857,32 +860,6 @@ ogs_pfcp_pdr_t *ogs_pfcp_pdr_find(
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static uint64_t pdr_hash_keygen(uint32_t teid, uint8_t qfi)
|
||||
{
|
||||
uint64_t hashkey = (teid << 8) + qfi;
|
||||
return hashkey;
|
||||
}
|
||||
|
||||
void ogs_pfcp_pdr_hash_set(ogs_pfcp_pdr_t *pdr)
|
||||
{
|
||||
ogs_assert(pdr);
|
||||
|
||||
if (pdr->hashkey)
|
||||
ogs_hash_set(ogs_pfcp_self()->pdr_hash, &pdr->hashkey,
|
||||
sizeof(pdr->hashkey), NULL);
|
||||
|
||||
pdr->hashkey = pdr_hash_keygen(pdr->f_teid.teid, pdr->qfi);
|
||||
ogs_hash_set(ogs_pfcp_self()->pdr_hash, &pdr->hashkey,
|
||||
sizeof(pdr->hashkey), pdr);
|
||||
}
|
||||
|
||||
ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_by_teid_and_qfi(uint32_t teid, uint8_t qfi)
|
||||
{
|
||||
uint64_t hashkey = pdr_hash_keygen(teid, qfi);
|
||||
return (ogs_pfcp_pdr_t *)ogs_hash_get(self.pdr_hash,
|
||||
&hashkey, sizeof(hashkey));
|
||||
}
|
||||
|
||||
ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_or_add(
|
||||
ogs_pfcp_sess_t *sess, ogs_pfcp_pdr_id_t id)
|
||||
{
|
||||
|
@ -900,6 +877,32 @@ ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_or_add(
|
|||
return pdr;
|
||||
}
|
||||
|
||||
static uint64_t pdr_hash_keygen(uint32_t teid, uint8_t qfi)
|
||||
{
|
||||
uint64_t hashkey = (teid << 8) + qfi;
|
||||
return hashkey;
|
||||
}
|
||||
|
||||
void ogs_pfcp_pdr_hash_set(ogs_pfcp_pdr_t *pdr)
|
||||
{
|
||||
ogs_assert(pdr);
|
||||
|
||||
if (pdr->hashkey)
|
||||
ogs_hash_set(ogs_pfcp_self()->pdr_hash,
|
||||
&pdr->hashkey, sizeof(pdr->hashkey), NULL);
|
||||
|
||||
pdr->hashkey = pdr_hash_keygen(pdr->f_teid.teid, pdr->qfi);
|
||||
ogs_hash_set(ogs_pfcp_self()->pdr_hash,
|
||||
&pdr->hashkey, sizeof(pdr->hashkey), pdr);
|
||||
}
|
||||
|
||||
ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_by_teid_and_qfi(uint32_t teid, uint8_t qfi)
|
||||
{
|
||||
uint64_t hashkey = pdr_hash_keygen(teid, qfi);
|
||||
return (ogs_pfcp_pdr_t *)ogs_hash_get(self.pdr_hash,
|
||||
&hashkey, sizeof(hashkey));
|
||||
}
|
||||
|
||||
void ogs_pfcp_pdr_reorder_by_precedence(
|
||||
ogs_pfcp_pdr_t *pdr, ogs_pfcp_precedence_t precedence)
|
||||
{
|
||||
|
@ -947,8 +950,8 @@ void ogs_pfcp_pdr_remove(ogs_pfcp_pdr_t *pdr)
|
|||
ogs_pfcp_rule_remove_all(pdr);
|
||||
|
||||
if (pdr->hashkey)
|
||||
ogs_hash_set(ogs_pfcp_self()->pdr_hash, &pdr->hashkey,
|
||||
sizeof(pdr->hashkey), NULL);
|
||||
ogs_hash_set(ogs_pfcp_self()->pdr_hash,
|
||||
&pdr->hashkey, sizeof(pdr->hashkey), NULL);
|
||||
if (pdr->dnn)
|
||||
ogs_free(pdr->dnn);
|
||||
|
||||
|
@ -1021,6 +1024,107 @@ ogs_pfcp_far_t *ogs_pfcp_far_find_or_add(
|
|||
return far;
|
||||
}
|
||||
|
||||
void ogs_pfcp_far_hash_set(ogs_pfcp_far_t *far)
|
||||
{
|
||||
int family;
|
||||
|
||||
ogs_gtp_node_t *gnode = NULL;
|
||||
ogs_sockaddr_t *addr = NULL;
|
||||
|
||||
ogs_assert(far);
|
||||
gnode = far->gnode;
|
||||
ogs_assert(gnode);
|
||||
addr = &gnode->addr;
|
||||
ogs_assert(addr);
|
||||
|
||||
if (far->hashkey_len)
|
||||
ogs_hash_set(ogs_pfcp_self()->far_hash,
|
||||
&far->hashkey, far->hashkey_len, NULL);
|
||||
|
||||
far->hashkey.teid = far->outer_header_creation.teid;
|
||||
far->hashkey_len = sizeof(far->hashkey.teid);
|
||||
|
||||
family = addr->ogs_sa_family;
|
||||
switch (family) {
|
||||
case AF_INET:
|
||||
memcpy(far->hashkey.addr, &addr->sin.sin_addr, OGS_IPV4_LEN);
|
||||
far->hashkey_len += OGS_IPV4_LEN;
|
||||
break;
|
||||
case AF_INET6:
|
||||
memcpy(far->hashkey.addr, &addr->sin6.sin6_addr, OGS_IPV6_LEN);
|
||||
far->hashkey_len += OGS_IPV6_LEN;
|
||||
break;
|
||||
default:
|
||||
ogs_fatal("Unknown family(%d)", family);
|
||||
ogs_abort();
|
||||
return;
|
||||
}
|
||||
|
||||
ogs_hash_set(ogs_pfcp_self()->far_hash,
|
||||
&far->hashkey, far->hashkey_len, far);
|
||||
}
|
||||
|
||||
ogs_pfcp_far_t *ogs_pfcp_far_find_by_error_indication(ogs_pkbuf_t *pkbuf)
|
||||
{
|
||||
ogs_pfcp_far_hashkey_t hashkey;
|
||||
int hashkey_len;
|
||||
|
||||
uint32_t teid;
|
||||
uint16_t len;
|
||||
unsigned char *p = NULL;
|
||||
|
||||
ogs_assert(pkbuf);
|
||||
|
||||
p = pkbuf->data;
|
||||
ogs_assert(p);
|
||||
|
||||
/*
|
||||
* 8.3 Tunnel Endpoint Identifier Data I
|
||||
*
|
||||
* Octet 1 : Type = 16 (Decimal)
|
||||
* Octet 2-5 : Tunnel Endpoint Identitifer Data I
|
||||
*/
|
||||
if (*p != 16) {
|
||||
ogs_error("Unknown Type [%d]", *p);
|
||||
return NULL;
|
||||
}
|
||||
p += 1;
|
||||
|
||||
memcpy(&teid, p, 4);
|
||||
teid = be32toh(teid);
|
||||
p += 4;
|
||||
|
||||
/*
|
||||
* 8.4 GTP-U Peer Address
|
||||
*
|
||||
* Octet 1 : Type = 133 (Decimal)
|
||||
* Octet 2-3 : Length
|
||||
* Octet 4-n : IPv4 or IPv6 Address
|
||||
*/
|
||||
if (*p != 133) {
|
||||
ogs_error("Unknown Type [%d]", *p);
|
||||
return NULL;
|
||||
}
|
||||
p += 1;
|
||||
|
||||
memcpy(&len, p, 2);
|
||||
len = be16toh(len);
|
||||
p += 2;
|
||||
|
||||
if (len == OGS_IPV4_LEN) {
|
||||
} else if (len == OGS_IPV6_LEN) {
|
||||
} else {
|
||||
ogs_error("Invalid Length [%d]", len);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hashkey.teid = teid;
|
||||
memcpy(hashkey.addr, p, len);
|
||||
hashkey_len = 4 + len;
|
||||
|
||||
return (ogs_pfcp_far_t *)ogs_hash_get(self.far_hash, &hashkey, hashkey_len);
|
||||
}
|
||||
|
||||
void ogs_pfcp_far_remove(ogs_pfcp_far_t *far)
|
||||
{
|
||||
int i;
|
||||
|
@ -1030,11 +1134,15 @@ void ogs_pfcp_far_remove(ogs_pfcp_far_t *far)
|
|||
sess = far->sess;
|
||||
ogs_assert(sess);
|
||||
|
||||
ogs_list_remove(&sess->far_list, far);
|
||||
|
||||
if (far->hashkey_len)
|
||||
ogs_hash_set(ogs_pfcp_self()->far_hash,
|
||||
&far->hashkey, far->hashkey_len, NULL);
|
||||
|
||||
for (i = 0; i < far->num_of_buffered_packet; i++)
|
||||
ogs_pkbuf_free(far->buffered_packet[i]);
|
||||
|
||||
ogs_list_remove(&sess->far_list, far);
|
||||
|
||||
if (far->id_node)
|
||||
ogs_pool_free(&far->sess->far_id_pool, far->id_node);
|
||||
|
||||
|
|
|
@ -60,7 +60,8 @@ typedef struct ogs_pfcp_context_s {
|
|||
ogs_list_t dev_list; /* Tun Device List */
|
||||
ogs_list_t subnet_list; /* UE Subnet List */
|
||||
|
||||
ogs_hash_t *pdr_hash; /* hash table (UPF-N3-TEID) */
|
||||
ogs_hash_t *pdr_hash; /* hash table for PDR(TEID+QFI) */
|
||||
ogs_hash_t *far_hash; /* hash table for FAR(TEID+ADDR) */
|
||||
} ogs_pfcp_context_t;
|
||||
|
||||
#define OGS_SETUP_PFCP_NODE(__cTX, __pNODE) \
|
||||
|
@ -152,10 +153,18 @@ typedef struct ogs_pfcp_pdr_s {
|
|||
ogs_pfcp_sess_t *sess;
|
||||
} ogs_pfcp_pdr_t;
|
||||
|
||||
typedef struct ogs_pfcp_far_hashkey_s {
|
||||
uint32_t teid;
|
||||
uint32_t addr[4];
|
||||
} ogs_pfcp_far_hashkey_t;
|
||||
|
||||
typedef struct ogs_pfcp_far_s {
|
||||
ogs_lnode_t lnode;
|
||||
uint32_t index;
|
||||
|
||||
int hashkey_len;
|
||||
ogs_pfcp_far_hashkey_t hashkey;
|
||||
|
||||
uint8_t *id_node; /* Pool-Node for ID */
|
||||
ogs_pfcp_far_id_t id;
|
||||
ogs_pfcp_apply_action_t apply_action;
|
||||
|
@ -166,7 +175,7 @@ typedef struct ogs_pfcp_far_s {
|
|||
ogs_pfcp_smreq_flags_t smreq_flags;
|
||||
|
||||
uint32_t num_of_buffered_packet;
|
||||
ogs_pkbuf_t* buffered_packet[OGS_MAX_NUM_OF_PACKET_BUFFER];
|
||||
ogs_pkbuf_t *buffered_packet[OGS_MAX_NUM_OF_PACKET_BUFFER];
|
||||
|
||||
/* Related Context */
|
||||
ogs_pfcp_sess_t *sess;
|
||||
|
@ -304,13 +313,14 @@ ogs_pfcp_pdr_t *ogs_pfcp_sess_default_pdr(
|
|||
void ogs_pfcp_sess_clear(ogs_pfcp_sess_t *sess);
|
||||
|
||||
ogs_pfcp_pdr_t *ogs_pfcp_pdr_add(ogs_pfcp_sess_t *sess);
|
||||
void ogs_pfcp_pdr_hash_set(ogs_pfcp_pdr_t *pdr);
|
||||
|
||||
ogs_pfcp_pdr_t *ogs_pfcp_pdr_find(
|
||||
ogs_pfcp_sess_t *sess, ogs_pfcp_pdr_id_t id);
|
||||
ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_by_teid_and_qfi(uint32_t teid, uint8_t qfi);
|
||||
ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_or_add(
|
||||
ogs_pfcp_sess_t *sess, ogs_pfcp_pdr_id_t id);
|
||||
|
||||
void ogs_pfcp_pdr_hash_set(ogs_pfcp_pdr_t *pdr);
|
||||
ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_by_teid_and_qfi(uint32_t teid, uint8_t qfi);
|
||||
|
||||
void ogs_pfcp_pdr_reorder_by_precedence(
|
||||
ogs_pfcp_pdr_t *pdr, ogs_pfcp_precedence_t precedence);
|
||||
void ogs_pfcp_pdr_associate_far(ogs_pfcp_pdr_t *pdr, ogs_pfcp_far_t *far);
|
||||
|
@ -324,6 +334,10 @@ ogs_pfcp_far_t *ogs_pfcp_far_find(
|
|||
ogs_pfcp_sess_t *sess, ogs_pfcp_far_id_t id);
|
||||
ogs_pfcp_far_t *ogs_pfcp_far_find_or_add(
|
||||
ogs_pfcp_sess_t *sess, ogs_pfcp_far_id_t id);
|
||||
|
||||
void ogs_pfcp_far_hash_set(ogs_pfcp_far_t *far);
|
||||
ogs_pfcp_far_t *ogs_pfcp_far_find_by_error_indication(ogs_pkbuf_t *pkbuf);
|
||||
|
||||
void ogs_pfcp_far_remove(ogs_pfcp_far_t *far);
|
||||
void ogs_pfcp_far_remove_all(ogs_pfcp_sess_t *sess);
|
||||
|
||||
|
|
|
@ -172,6 +172,38 @@ void ogs_pfcp_up_handle_pdr(
|
|||
}
|
||||
}
|
||||
|
||||
void ogs_pfcp_up_handle_error_indication(
|
||||
ogs_pfcp_far_t *far, ogs_pfcp_user_plane_report_t *report)
|
||||
{
|
||||
uint16_t len;
|
||||
|
||||
ogs_assert(far);
|
||||
ogs_assert(far->hashkey_len);
|
||||
|
||||
ogs_assert(report);
|
||||
|
||||
memset(report, 0, sizeof(*report));
|
||||
|
||||
len = far->hashkey_len - 4; /* Remove TEID size, Only use ADDR size */
|
||||
|
||||
report->error_indication.remote_f_teid_len = 5 + len;
|
||||
report->error_indication.remote_f_teid.teid = htobe32(far->hashkey.teid);
|
||||
if (len == OGS_IPV4_LEN) {
|
||||
report->error_indication.remote_f_teid.ipv4 = 1;
|
||||
memcpy(&report->error_indication.remote_f_teid.addr,
|
||||
far->hashkey.addr, len);
|
||||
} else if (len == OGS_IPV6_LEN) {
|
||||
report->error_indication.remote_f_teid.ipv6 = 1;
|
||||
memcpy(report->error_indication.remote_f_teid.addr6,
|
||||
far->hashkey.addr, len);
|
||||
} else {
|
||||
ogs_error("Invalid Length [%d]", len);
|
||||
return;
|
||||
}
|
||||
|
||||
report->type.error_indication_report = 1;
|
||||
}
|
||||
|
||||
ogs_pfcp_pdr_t *ogs_pfcp_handle_create_pdr(ogs_pfcp_sess_t *sess,
|
||||
ogs_pfcp_tlv_create_pdr_t *message,
|
||||
uint8_t *cause_value, uint8_t *offending_ie_value)
|
||||
|
|
|
@ -48,6 +48,8 @@ void ogs_pfcp_up_handle_association_setup_response(
|
|||
void ogs_pfcp_up_handle_pdr(
|
||||
ogs_pfcp_pdr_t *pdr, ogs_pkbuf_t *recvbuf,
|
||||
ogs_pfcp_user_plane_report_t *report);
|
||||
void ogs_pfcp_up_handle_error_indication(
|
||||
ogs_pfcp_far_t *far, ogs_pfcp_user_plane_report_t *report);
|
||||
|
||||
ogs_pfcp_pdr_t *ogs_pfcp_handle_create_pdr(ogs_pfcp_sess_t *sess,
|
||||
ogs_pfcp_tlv_create_pdr_t *message,
|
||||
|
|
140
lib/pfcp/path.c
140
lib/pfcp/path.c
|
@ -262,14 +262,11 @@ void ogs_pfcp_up_send_association_setup_response(ogs_pfcp_xact_t *xact,
|
|||
|
||||
void ogs_pfcp_send_g_pdu(ogs_pfcp_pdr_t *pdr, ogs_pkbuf_t *sendbuf)
|
||||
{
|
||||
char buf[OGS_ADDRSTRLEN];
|
||||
int rv;
|
||||
ogs_gtp_header_t *gtp_h = NULL;
|
||||
ogs_gtp_extension_header_t *ext_h = NULL;
|
||||
ogs_gtp_node_t *gnode = NULL;
|
||||
|
||||
ogs_pfcp_far_t *far = NULL;
|
||||
ogs_pfcp_qer_t *qer = NULL;
|
||||
|
||||
ogs_gtp_header_t gtp_hdesc;
|
||||
ogs_gtp_extension_header_t ext_hdesc;
|
||||
|
||||
ogs_assert(pdr);
|
||||
ogs_assert(sendbuf);
|
||||
|
@ -285,73 +282,26 @@ void ogs_pfcp_send_g_pdu(ogs_pfcp_pdr_t *pdr, ogs_pkbuf_t *sendbuf)
|
|||
ogs_assert(gnode);
|
||||
ogs_assert(gnode->sock);
|
||||
|
||||
qer = pdr->qer;
|
||||
memset(>p_hdesc, 0, sizeof(gtp_hdesc));
|
||||
memset(&ext_hdesc, 0, sizeof(ext_hdesc));
|
||||
|
||||
/* Add GTP-U header */
|
||||
if (qer && qer->qfi) {
|
||||
ogs_assert(ogs_pkbuf_push(sendbuf, OGS_GTPV1U_5GC_HEADER_LEN));
|
||||
gtp_h = (ogs_gtp_header_t *)sendbuf->data;
|
||||
/* Bits 8 7 6 5 4 3 2 1
|
||||
* +--+--+--+--+--+--+--+--+
|
||||
* |version |PT| 1| E| S|PN|
|
||||
* +--+--+--+--+--+--+--+--+
|
||||
* 0 0 1 1 0 1 0 0
|
||||
*/
|
||||
gtp_h->flags = 0x34;
|
||||
gtp_h->type = OGS_GTPU_MSGTYPE_GPDU;
|
||||
gtp_h->length = htobe16(sendbuf->len - OGS_GTPV1U_HEADER_LEN);
|
||||
gtp_h->teid = htobe32(far->outer_header_creation.teid);
|
||||
gtp_hdesc.type = OGS_GTPU_MSGTYPE_GPDU;
|
||||
gtp_hdesc.teid = far->outer_header_creation.teid;
|
||||
if (pdr->qer && pdr->qer->qfi)
|
||||
ext_hdesc.qos_flow_identifier = pdr->qer->qfi;
|
||||
|
||||
ext_h = (ogs_gtp_extension_header_t *)(
|
||||
sendbuf->data + OGS_GTPV1U_HEADER_LEN);
|
||||
ext_h->type = OGS_GTP_EXTENSION_HEADER_TYPE_PDU_SESSION_CONTAINER;
|
||||
ext_h->len = 1;
|
||||
ext_h->pdu_type =
|
||||
OGS_GTP_EXTENSION_HEADER_PDU_TYPE_DL_PDU_SESSION_INFORMATION;
|
||||
ext_h->qos_flow_identifier = qer->qfi;
|
||||
ext_h->next_type =
|
||||
OGS_GTP_EXTENSION_HEADER_TYPE_NO_MORE_EXTENSION_HEADERS;
|
||||
} else {
|
||||
ogs_assert(ogs_pkbuf_push(sendbuf, OGS_GTPV1U_HEADER_LEN));
|
||||
gtp_h = (ogs_gtp_header_t *)sendbuf->data;
|
||||
/* Bits 8 7 6 5 4 3 2 1
|
||||
* +--+--+--+--+--+--+--+--+
|
||||
* |version |PT| 1| E| S|PN|
|
||||
* +--+--+--+--+--+--+--+--+
|
||||
* 0 0 1 1 0 0 0 0
|
||||
*/
|
||||
gtp_h->flags = 0x30;
|
||||
gtp_h->type = OGS_GTPU_MSGTYPE_GPDU;
|
||||
gtp_h->length = htobe16(sendbuf->len - OGS_GTPV1U_HEADER_LEN);
|
||||
gtp_h->teid = htobe32(far->outer_header_creation.teid);
|
||||
}
|
||||
|
||||
/* Send G-PDU */
|
||||
ogs_debug("SEND G-PDU to Peer[%s] : TEID[0x%x]",
|
||||
OGS_ADDR(&gnode->addr, buf), far->outer_header_creation.teid);
|
||||
rv = ogs_gtp_sendto(gnode, sendbuf);
|
||||
if (rv != OGS_OK) {
|
||||
if (ogs_socket_errno != OGS_EAGAIN) {
|
||||
ogs_error("SEND G-PDU to Peer[%s] : TEID[0x%x]",
|
||||
OGS_ADDR(&gnode->addr, buf), far->outer_header_creation.teid);
|
||||
}
|
||||
}
|
||||
|
||||
ogs_pkbuf_free(sendbuf);
|
||||
ogs_gtp_send_user_plane(gnode, >p_hdesc, &ext_hdesc, sendbuf);
|
||||
}
|
||||
|
||||
void ogs_pfcp_send_end_marker(ogs_pfcp_pdr_t *pdr)
|
||||
{
|
||||
char buf[OGS_ADDRSTRLEN];
|
||||
int rv;
|
||||
ogs_gtp_node_t *gnode = NULL;
|
||||
ogs_pfcp_far_t *far = NULL;
|
||||
|
||||
ogs_pkbuf_t *sendbuf = NULL;
|
||||
|
||||
ogs_gtp_header_t *gtp_h = NULL;
|
||||
ogs_gtp_extension_header_t *ext_h = NULL;
|
||||
ogs_gtp_node_t *gnode = NULL;
|
||||
|
||||
ogs_pfcp_far_t *far = NULL;
|
||||
ogs_pfcp_qer_t *qer = NULL;
|
||||
ogs_gtp_header_t gtp_hdesc;
|
||||
ogs_gtp_extension_header_t ext_hdesc;
|
||||
|
||||
ogs_assert(pdr);
|
||||
far = pdr->far;
|
||||
|
@ -367,61 +317,19 @@ void ogs_pfcp_send_end_marker(ogs_pfcp_pdr_t *pdr)
|
|||
return;
|
||||
}
|
||||
|
||||
sendbuf = ogs_pkbuf_alloc(NULL,
|
||||
100 /* enough for END_MARKER; use smaller buffer */);
|
||||
sendbuf = ogs_pkbuf_alloc(NULL, OGS_GTPV1U_5GC_HEADER_LEN);
|
||||
ogs_assert(sendbuf);
|
||||
ogs_pkbuf_put(sendbuf, 100);
|
||||
memset(sendbuf->data, 0, sendbuf->len);
|
||||
ogs_pkbuf_reserve(sendbuf, OGS_GTPV1U_5GC_HEADER_LEN);
|
||||
|
||||
gtp_h = (ogs_gtp_header_t *)sendbuf->data;
|
||||
memset(>p_hdesc, 0, sizeof(gtp_hdesc));
|
||||
memset(&ext_hdesc, 0, sizeof(ext_hdesc));
|
||||
|
||||
qer = pdr->qer;
|
||||
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;
|
||||
|
||||
/* Add GTP-U header */
|
||||
if (qer && qer->qfi) {
|
||||
/* Bits 8 7 6 5 4 3 2 1
|
||||
* +--+--+--+--+--+--+--+--+
|
||||
* |version |PT| 1| E| S|PN|
|
||||
* +--+--+--+--+--+--+--+--+
|
||||
* 0 0 1 1 0 1 0 0
|
||||
*/
|
||||
gtp_h->flags = 0x34;
|
||||
gtp_h->type = OGS_GTPU_MSGTYPE_END_MARKER;
|
||||
gtp_h->teid = htobe32(far->outer_header_creation.teid);
|
||||
|
||||
ext_h = (ogs_gtp_extension_header_t *)(
|
||||
sendbuf->data + OGS_GTPV1U_HEADER_LEN);
|
||||
ext_h->type = OGS_GTP_EXTENSION_HEADER_TYPE_PDU_SESSION_CONTAINER;
|
||||
ext_h->len = 1;
|
||||
ext_h->pdu_type =
|
||||
OGS_GTP_EXTENSION_HEADER_PDU_TYPE_DL_PDU_SESSION_INFORMATION;
|
||||
ext_h->qos_flow_identifier = qer->qfi;
|
||||
ext_h->next_type =
|
||||
OGS_GTP_EXTENSION_HEADER_TYPE_NO_MORE_EXTENSION_HEADERS;
|
||||
} else {
|
||||
/* Bits 8 7 6 5 4 3 2 1
|
||||
* +--+--+--+--+--+--+--+--+
|
||||
* |version |PT| 1| E| S|PN|
|
||||
* +--+--+--+--+--+--+--+--+
|
||||
* 0 0 1 1 0 0 0 0
|
||||
*/
|
||||
gtp_h->flags = 0x30;
|
||||
gtp_h->type = OGS_GTPU_MSGTYPE_END_MARKER;
|
||||
gtp_h->teid = htobe32(far->outer_header_creation.teid);
|
||||
}
|
||||
|
||||
/* Send End Marker */
|
||||
ogs_debug("SEND End Marker to Peer[%s] : TEID[0x%x]",
|
||||
OGS_ADDR(&gnode->addr, buf), far->outer_header_creation.teid);
|
||||
rv = ogs_gtp_sendto(gnode, sendbuf);
|
||||
if (rv != OGS_OK) {
|
||||
if (ogs_socket_errno != OGS_EAGAIN) {
|
||||
ogs_error("SEND End Marker to Peer[%s] : TEID[0x%x]",
|
||||
OGS_ADDR(&gnode->addr, buf), far->outer_header_creation.teid);
|
||||
}
|
||||
}
|
||||
|
||||
ogs_pkbuf_free(sendbuf);
|
||||
ogs_gtp_send_user_plane(gnode, >p_hdesc, &ext_hdesc, sendbuf);
|
||||
}
|
||||
|
||||
void ogs_pfcp_send_buffered_packet(ogs_pfcp_pdr_t *pdr)
|
||||
|
|
|
@ -79,6 +79,7 @@ typedef struct ogs_pfcp_xact_s {
|
|||
#define OGS_PFCP_MODIFY_ACTIVATE ((uint64_t)1<<8)
|
||||
#define OGS_PFCP_MODIFY_DEACTIVATE ((uint64_t)1<<9)
|
||||
#define OGS_PFCP_MODIFY_END_MARKER ((uint64_t)1<<10)
|
||||
#define OGS_PFCP_MODIFY_ERROR_INDICATION ((uint64_t)1<<11)
|
||||
uint64_t modify_flags;
|
||||
|
||||
#define OGS_PFCP_DELETE_TRIGGER_UE_REQUESTED 1
|
||||
|
|
|
@ -34,11 +34,11 @@ libsctp_sources = files('''
|
|||
ogs-sctp.c
|
||||
'''.split())
|
||||
|
||||
libsctp_dep = cc.find_library('sctp', required : false)
|
||||
if libsctp_dep.found()
|
||||
sctp_dep = cc.find_library('sctp', required : false)
|
||||
if sctp_dep.found()
|
||||
libsctp_sources += files('ogs-lksctp.c')
|
||||
else
|
||||
libsctp_dep = dependency('usrsctp',
|
||||
sctp_dep = dependency('usrsctp',
|
||||
version: ['>=1.0.0', '<2'],
|
||||
fallback: ['usrsctp', 'usrsctp_dep'],
|
||||
default_options: [
|
||||
|
@ -59,10 +59,10 @@ libsctp = library('ogssctp',
|
|||
version : libogslib_version,
|
||||
c_args : '-DOGS_SCTP_COMPILATION',
|
||||
include_directories : [libsctp_inc, libinc],
|
||||
dependencies : [libcore_dep, libsctp_dep],
|
||||
dependencies : [libcore_dep, sctp_dep],
|
||||
install : true)
|
||||
|
||||
libsctp_dep = declare_dependency(
|
||||
link_with : libsctp,
|
||||
include_directories : [libsctp_inc, libinc],
|
||||
dependencies : [libcore_dep, libsctp_dep])
|
||||
dependencies : [libcore_dep, sctp_dep])
|
||||
|
|
|
@ -145,7 +145,10 @@ int esm_handle_information_response(mme_sess_t *sess,
|
|||
} else if (sess->pdn->paa.pdn_type == OGS_GTP_PDN_TYPE_IPV4V6) {
|
||||
/* Nothing */
|
||||
} else {
|
||||
ogs_error("Unknown PDN Type %u", sess->pdn->paa.pdn_type);
|
||||
ogs_error("Unknown PDN[%s] Type %u:%u",
|
||||
sess->pdn->apn,
|
||||
sess->pdn->pdn_type,
|
||||
sess->pdn->paa.pdn_type);
|
||||
nas_eps_send_pdn_connectivity_reject(
|
||||
sess, ESM_CAUSE_UNKNOWN_PDN_TYPE);
|
||||
return OGS_ERROR;
|
||||
|
|
|
@ -2533,8 +2533,8 @@ int mme_ue_set_imsi(mme_ue_t *mme_ue, char *imsi_bcd)
|
|||
ogs_warn("[%s] OLD UE Context Release", mme_ue->imsi_bcd);
|
||||
if (ECM_CONNECTED(old_mme_ue)) {
|
||||
/* Implcit S1 release */
|
||||
ogs_debug("[%s] Implicit S1 release", mme_ue->imsi_bcd);
|
||||
ogs_debug("[%s] ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]",
|
||||
ogs_info("[%s] Implicit S1 release", mme_ue->imsi_bcd);
|
||||
ogs_info("[%s] ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]",
|
||||
old_mme_ue->imsi_bcd,
|
||||
old_mme_ue->enb_ue->enb_ue_s1ap_id,
|
||||
old_mme_ue->enb_ue->mme_ue_s1ap_id);
|
||||
|
|
|
@ -264,6 +264,7 @@ struct enb_ue_s {
|
|||
#define S1AP_UE_CTX_REL_S1_REMOVE_AND_UNLINK 2
|
||||
#define S1AP_UE_CTX_REL_UE_CONTEXT_REMOVE 3
|
||||
#define S1AP_UE_CTX_REL_DELETE_INDIRECT_TUNNEL 4
|
||||
#define S1AP_UE_CTX_REL_S1_PAGING 5
|
||||
uint8_t ue_ctx_rel_action;
|
||||
|
||||
/* Related Context */
|
||||
|
|
|
@ -100,31 +100,14 @@ void mme_s11_handle_create_session_response(
|
|||
cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING;
|
||||
}
|
||||
|
||||
/* CHECK PDN_TYPE */
|
||||
if (rsp->pdn_address_allocation.presence) {
|
||||
ogs_paa_t paa;
|
||||
if (cause_value != OGS_GTP_CAUSE_REQUEST_ACCEPTED)
|
||||
ogs_warn("Cause[%d] : No Accepted", cause_value);
|
||||
|
||||
memcpy(&paa, rsp->pdn_address_allocation.data,
|
||||
ogs_min(sizeof(paa), rsp->pdn_address_allocation.len));
|
||||
if (paa.pdn_type == OGS_GTP_PDN_TYPE_IPV4) {
|
||||
/* Nothing */
|
||||
} else if (paa.pdn_type == OGS_GTP_PDN_TYPE_IPV6) {
|
||||
/* Nothing */
|
||||
} else if (paa.pdn_type == OGS_GTP_PDN_TYPE_IPV4V6) {
|
||||
/* Nothing */
|
||||
} else {
|
||||
ogs_error("Unknown PDN Type %u", paa.pdn_type);
|
||||
cause_value = OGS_GTP_CAUSE_MANDATORY_IE_INCORRECT;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (rsp->pdn_address_allocation.presence == 0) {
|
||||
ogs_error("No PDN Address Allocation");
|
||||
cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING;
|
||||
}
|
||||
|
||||
if (cause_value != OGS_GTP_CAUSE_REQUEST_ACCEPTED)
|
||||
ogs_warn("Cause[%d] : No Accepted", cause_value);
|
||||
|
||||
if (rsp->sender_f_teid_for_control_plane.presence == 0) {
|
||||
ogs_error("No S11 TEID");
|
||||
cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING;
|
||||
|
@ -728,7 +711,7 @@ void mme_s11_handle_downlink_data_notification(
|
|||
ogs_gtp_downlink_data_notification_t *noti)
|
||||
{
|
||||
int rv;
|
||||
ogs_gtp_cause_t cause;
|
||||
uint8_t cause_value = 0;
|
||||
ogs_gtp_header_t h;
|
||||
ogs_pkbuf_t *s11buf = NULL;
|
||||
|
||||
|
@ -737,21 +720,15 @@ void mme_s11_handle_downlink_data_notification(
|
|||
|
||||
ogs_debug("[MME] Downlink Data Notification");
|
||||
|
||||
memset(&cause, 0, sizeof(cause));
|
||||
cause.value = OGS_GTP_CAUSE_REQUEST_ACCEPTED;
|
||||
|
||||
if (!mme_ue) {
|
||||
ogs_warn("OGS_GTP_CAUSE_CONTEXT_NOT_FOUND");
|
||||
cause.value = OGS_GTP_CAUSE_CONTEXT_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (cause.value != OGS_GTP_CAUSE_REQUEST_ACCEPTED) {
|
||||
ogs_gtp_send_error_message(xact, mme_ue ? mme_ue->sgw_s11_teid : 0,
|
||||
OGS_GTP_DOWNLINK_DATA_NOTIFICATION_ACKNOWLEDGE_TYPE,
|
||||
cause.value);
|
||||
OGS_GTP_CAUSE_CONTEXT_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
ogs_assert(mme_ue);
|
||||
ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]",
|
||||
mme_ue->mme_s11_teid, mme_ue->sgw_s11_teid);
|
||||
|
||||
|
@ -768,6 +745,69 @@ void mme_s11_handle_downlink_data_notification(
|
|||
|
||||
rv = ogs_gtp_xact_commit(xact);
|
||||
ogs_expect(rv == OGS_OK);
|
||||
|
||||
if (noti->cause.presence) {
|
||||
ogs_gtp_cause_t *cause = noti->cause.data;
|
||||
ogs_assert(cause);
|
||||
|
||||
cause_value = cause->value;
|
||||
}
|
||||
/*
|
||||
* 5.3.4.2 in Spec 23.401
|
||||
* Under certain conditions, the current UE triggered Service Request
|
||||
* procedure can cause unnecessary Downlink Packet Notification messages
|
||||
* which increase the load of the MME.
|
||||
*
|
||||
* This can occur when uplink data sent in step 6 causes a response
|
||||
* on the downlink which arrives at the Serving GW before the Modify Bearer
|
||||
* Request message, step 8. This data cannot be forwarded from the Serving GW
|
||||
* to the eNodeB and hence it triggers a Downlink Data Notification message.
|
||||
*
|
||||
* If the MME receives a Downlink Data Notification after step 2 and
|
||||
* before step 9, the MME shall not send S1 interface paging messages
|
||||
*/
|
||||
if (ECM_IDLE(mme_ue)) {
|
||||
s1ap_send_paging(mme_ue, S1AP_CNDomain_ps);
|
||||
|
||||
} else if (ECM_CONNECTED(mme_ue)) {
|
||||
if (cause_value == OGS_GTP_CAUSE_ERROR_INDICATION_RECEIVED) {
|
||||
|
||||
/*
|
||||
* TS23.007 22. Downlink Data Notification Handling at MME/S4 SGSN
|
||||
*
|
||||
* If the MME/S4 SGSN receives a Downlink Data Notification message from
|
||||
* the SGW as a result of the SGW having received an Error Indication message
|
||||
* from the eNodeB/RNC or S4-SGSN over S4 User Plane, the MME/S4 SGSN should
|
||||
* perform the following:
|
||||
*
|
||||
* - If the UE is in IDLE state, upon receipt of the Downlink Data
|
||||
* Notification message, the MME/S4 SGSN shall perform the Network
|
||||
* Triggered Service Request procedure as specified in 3GPP TS 23.060[5]
|
||||
* and 3GPP TS 23.401 [15].
|
||||
* - If the UE is in CONNECTED state, upon receipt of the Downlink Data
|
||||
* Notification message, the MME shall perform S1 Release procedure and
|
||||
* perform Network Triggered Service Request procedure as specified
|
||||
* in 3GPP TS 23.401 [15].
|
||||
* - If the UE is in CONNECTED state, upon receipt of the Downlink Data
|
||||
* Notification message and Direct Tunnel is used, the S4-SGSN shall
|
||||
* perform Iu Release procedure and perform Network Triggered Service
|
||||
* Request procedure as specified in 3GPP TS 23.060 [5]
|
||||
* if the cause value included in Downlink Data Notification is
|
||||
* "Error Indication received from RNC/eNodeB/S4-SGSN",
|
||||
* - If the UE is in CONNECTED state, upon receipt of the Downlink Data
|
||||
* Notification message and Direct Tunnel is not used, the S4-SGSN should
|
||||
* re-establish all of the S4-U bearers of this UE if the cause value
|
||||
* included in Downlink Data Notification is "Error Indication received
|
||||
* from RNC/eNodeB/S4-SGSN"
|
||||
*/
|
||||
enb_ue_t *enb_ue = mme_ue->enb_ue;
|
||||
ogs_assert(enb_ue);
|
||||
|
||||
s1ap_send_ue_context_release_command(enb_ue,
|
||||
S1AP_Cause_PR_nas, S1AP_CauseNas_normal_release,
|
||||
S1AP_UE_CTX_REL_S1_PAGING, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mme_s11_handle_create_indirect_data_forwarding_tunnel_response(
|
||||
|
|
|
@ -609,23 +609,6 @@ void mme_state_operational(ogs_fsm_t *s, mme_event_t *e)
|
|||
}
|
||||
mme_s11_handle_downlink_data_notification(
|
||||
xact, mme_ue, >p_message.downlink_data_notification);
|
||||
|
||||
/*
|
||||
* 5.3.4.2 in Spec 23.401
|
||||
* Under certain conditions, the current UE triggered Service Request
|
||||
* procedure can cause unnecessary Downlink Packet Notification messages
|
||||
* which increase the load of the MME.
|
||||
*
|
||||
* This can occur when uplink data sent in step 6 causes a response
|
||||
* on the downlink which arrives at the Serving GW before the Modify Bearer
|
||||
* Request message, step 8. This data cannot be forwarded from the Serving GW
|
||||
* to the eNodeB and hence it triggers a Downlink Data Notification message.
|
||||
*
|
||||
* If the MME receives a Downlink Data Notification after step 2 and
|
||||
* before step 9, the MME shall not send S1 interface paging messages
|
||||
*/
|
||||
if (ECM_IDLE(mme_ue))
|
||||
s1ap_send_paging(mme_ue, S1AP_CNDomain_ps);
|
||||
break;
|
||||
case OGS_GTP_CREATE_INDIRECT_DATA_FORWARDING_TUNNEL_RESPONSE_TYPE:
|
||||
mme_s11_handle_create_indirect_data_forwarding_tunnel_response(
|
||||
|
|
|
@ -684,18 +684,7 @@ void s1ap_handle_initial_context_setup_failure(
|
|||
* may in principle be adopted. The eNB should ensure
|
||||
* that no hanging resources remain at the eNB.
|
||||
*/
|
||||
#if 0
|
||||
if (mme_ue && SESSION_CONTEXT_IS_AVAILABLE(mme_ue)) {
|
||||
mme_gtp_send_delete_all_sessions(mme_ue);
|
||||
} else {
|
||||
s1ap_send_ue_context_release_command(enb_ue,
|
||||
S1AP_Cause_PR_nas, S1AP_CauseNas_normal_release,
|
||||
S1AP_UE_CTX_REL_S1_CONTEXT_REMOVE, 0);
|
||||
}
|
||||
#else
|
||||
/* In Issues #568, v2.0.12 is not working. */
|
||||
mme_send_release_access_bearer_or_ue_context_release(enb_ue);
|
||||
#endif
|
||||
}
|
||||
|
||||
void s1ap_handle_ue_context_modification_response(
|
||||
|
@ -1166,6 +1155,14 @@ void s1ap_handle_ue_context_release_action(enb_ue_t *enb_ue)
|
|||
ogs_expect(rv == OGS_OK);
|
||||
}
|
||||
break;
|
||||
case S1AP_UE_CTX_REL_S1_PAGING:
|
||||
ogs_debug(" Action: S1 paging");
|
||||
enb_ue_remove(enb_ue);
|
||||
ogs_expect_or_return(mme_ue);
|
||||
mme_ue_deassociate(mme_ue);
|
||||
|
||||
s1ap_send_paging(mme_ue, S1AP_CNDomain_ps);
|
||||
break;
|
||||
default:
|
||||
ogs_error("Invalid Action[%d]", enb_ue->ue_ctx_rel_action);
|
||||
break;
|
||||
|
|
|
@ -677,6 +677,71 @@ sgwc_bearer_t *sgwc_bearer_find_by_ue_ebi(sgwc_ue_t *sgwc_ue, uint8_t ebi)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
sgwc_bearer_t *sgwc_bearer_find_by_error_indication_report(
|
||||
sgwc_sess_t *sess,
|
||||
ogs_pfcp_tlv_error_indication_report_t *error_indication_report)
|
||||
{
|
||||
ogs_pfcp_f_teid_t *remote_f_teid;
|
||||
sgwc_bearer_t *bearer = NULL;
|
||||
sgwc_tunnel_t *tunnel = NULL;
|
||||
|
||||
uint32_t teid;
|
||||
uint16_t len; /* OGS_IPV4_LEN or OGS_IPV6_LEN */
|
||||
uint32_t addr[4];
|
||||
|
||||
ogs_assert(sess);
|
||||
ogs_assert(error_indication_report);
|
||||
|
||||
if (error_indication_report->presence == 0) {
|
||||
ogs_error("No Error Indication Report");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (error_indication_report->remote_f_teid.presence == 0) {
|
||||
ogs_error("No Remote F-TEID");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
remote_f_teid = error_indication_report->remote_f_teid.data;
|
||||
ogs_assert(remote_f_teid);
|
||||
|
||||
teid = be32toh(remote_f_teid->teid);
|
||||
if (remote_f_teid->ipv4 && remote_f_teid->ipv6) {
|
||||
ogs_error("User plane should not set both IPv4 and IPv6");
|
||||
return NULL;
|
||||
} else if (remote_f_teid->ipv4) {
|
||||
len = OGS_IPV4_LEN;
|
||||
memcpy(addr, &remote_f_teid->addr, len);
|
||||
} else if (remote_f_teid->ipv6) {
|
||||
len = OGS_IPV6_LEN;
|
||||
memcpy(addr, remote_f_teid->addr6, len);
|
||||
} else {
|
||||
ogs_error("No IPv4 and IPv6");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ogs_list_for_each(&sess->bearer_list, bearer) {
|
||||
ogs_list_for_each(&bearer->tunnel_list, tunnel) {
|
||||
if (teid == tunnel->remote_teid) {
|
||||
if (len == OGS_IPV4_LEN && tunnel->remote_ip.ipv4 &&
|
||||
memcmp(addr, &tunnel->remote_ip.addr, len) == 0) {
|
||||
return bearer;
|
||||
} else if (len == OGS_IPV6_LEN && tunnel->remote_ip.ipv6 &&
|
||||
memcmp(addr, tunnel->remote_ip.addr6, len) == 0) {
|
||||
return bearer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ogs_error("Cannot find the bearer context "
|
||||
"[TEID:%d,LEN:%d,ADDR:%08x %08x %08x %08x]",
|
||||
teid, len, be32toh(addr[0]), be32toh(addr[1]),
|
||||
be32toh(addr[2]), be32toh(addr[3]));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sgwc_bearer_t *sgwc_default_bearer_in_sess(sgwc_sess_t *sess)
|
||||
{
|
||||
ogs_assert(sess);
|
||||
|
|
|
@ -185,6 +185,9 @@ sgwc_bearer_t *sgwc_bearer_find_by_sess_ebi(
|
|||
sgwc_sess_t *sess, uint8_t ebi);
|
||||
sgwc_bearer_t *sgwc_bearer_find_by_ue_ebi(
|
||||
sgwc_ue_t *sgwc_ue, uint8_t ebi);
|
||||
sgwc_bearer_t *sgwc_bearer_find_by_error_indication_report(
|
||||
sgwc_sess_t *sess,
|
||||
ogs_pfcp_tlv_error_indication_report_t *error_indication_report);
|
||||
sgwc_bearer_t *sgwc_default_bearer_in_sess(sgwc_sess_t *sess);
|
||||
|
||||
sgwc_tunnel_t *sgwc_tunnel_add(
|
||||
|
|
|
@ -140,7 +140,7 @@ void sgwc_gtp_close(void)
|
|||
}
|
||||
|
||||
void sgwc_gtp_send_downlink_data_notification(
|
||||
sgwc_bearer_t *bearer, ogs_pfcp_xact_t *pfcp_xact)
|
||||
uint8_t cause_value, sgwc_bearer_t *bearer)
|
||||
{
|
||||
int rv;
|
||||
|
||||
|
@ -153,7 +153,6 @@ void sgwc_gtp_send_downlink_data_notification(
|
|||
ogs_gtp_header_t h;
|
||||
|
||||
ogs_assert(bearer);
|
||||
ogs_assert(pfcp_xact);
|
||||
|
||||
sess = bearer->sess;
|
||||
ogs_assert(sess);
|
||||
|
@ -169,13 +168,11 @@ void sgwc_gtp_send_downlink_data_notification(
|
|||
h.type = OGS_GTP_DOWNLINK_DATA_NOTIFICATION_TYPE;
|
||||
h.teid = sgwc_ue->mme_s11_teid;
|
||||
|
||||
pkbuf = sgwc_s11_build_downlink_data_notification(bearer);
|
||||
pkbuf = sgwc_s11_build_downlink_data_notification(cause_value, bearer);
|
||||
ogs_expect_or_return(pkbuf);
|
||||
|
||||
gtp_xact = ogs_gtp_xact_local_create(
|
||||
sgwc_ue->gnode, &h, pkbuf, NULL, sess);
|
||||
gtp_xact = ogs_gtp_xact_local_create(sgwc_ue->gnode, &h, pkbuf, NULL, sess);
|
||||
ogs_expect_or_return(gtp_xact);
|
||||
gtp_xact->pfcp_xact = pfcp_xact;
|
||||
|
||||
rv = ogs_gtp_xact_commit(gtp_xact);
|
||||
ogs_expect(rv == OGS_OK);
|
||||
|
|
|
@ -30,7 +30,7 @@ int sgwc_gtp_open(void);
|
|||
void sgwc_gtp_close(void);
|
||||
|
||||
void sgwc_gtp_send_downlink_data_notification(
|
||||
sgwc_bearer_t *bearer, ogs_pfcp_xact_t *pfcp_xact);
|
||||
uint8_t cause_value, sgwc_bearer_t *bearer);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -18,9 +18,6 @@
|
|||
*/
|
||||
|
||||
#include "pfcp-path.h"
|
||||
#if 0
|
||||
#include "n4-build.h"
|
||||
#endif
|
||||
|
||||
static void pfcp_node_fsm_init(ogs_pfcp_node_t *node, bool try_to_assoicate)
|
||||
{
|
||||
|
|
|
@ -19,10 +19,12 @@
|
|||
|
||||
#include "s11-build.h"
|
||||
|
||||
ogs_pkbuf_t *sgwc_s11_build_downlink_data_notification(sgwc_bearer_t *bearer)
|
||||
ogs_pkbuf_t *sgwc_s11_build_downlink_data_notification(
|
||||
uint8_t cause_value, sgwc_bearer_t *bearer)
|
||||
{
|
||||
ogs_gtp_message_t message;
|
||||
ogs_gtp_downlink_data_notification_t *noti = NULL;
|
||||
ogs_gtp_cause_t cause;
|
||||
ogs_gtp_arp_t arp;
|
||||
sgwc_sess_t *sess = NULL;
|
||||
|
||||
|
@ -34,6 +36,20 @@ ogs_pkbuf_t *sgwc_s11_build_downlink_data_notification(sgwc_bearer_t *bearer)
|
|||
noti = &message.downlink_data_notification;
|
||||
memset(&message, 0, sizeof(ogs_gtp_message_t));
|
||||
|
||||
/*
|
||||
* TS29.274 8.4 Cause Value
|
||||
*
|
||||
* 0 : Reserved. Shall not be sent and
|
||||
* if received the Cause shall be treated as an invalid IE
|
||||
*/
|
||||
if (cause_value != OGS_GTP_CAUSE_INVALID_VALUE) {
|
||||
memset(&cause, 0, sizeof(cause));
|
||||
cause.value = cause_value;
|
||||
noti->cause.presence = 1;
|
||||
noti->cause.len = sizeof(cause);
|
||||
noti->cause.data = &cause;
|
||||
}
|
||||
|
||||
noti->eps_bearer_id.presence = 1;
|
||||
noti->eps_bearer_id.u8 = bearer->ebi;
|
||||
|
||||
|
|
|
@ -26,7 +26,8 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
ogs_pkbuf_t *sgwc_s11_build_downlink_data_notification(sgwc_bearer_t *bearer);
|
||||
ogs_pkbuf_t *sgwc_s11_build_downlink_data_notification(
|
||||
uint8_t cause_value, sgwc_bearer_t *bearer);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -39,6 +39,8 @@ static void timeout(ogs_gtp_xact_t *xact, void *data)
|
|||
sgwc_ue->imsi_bcd, type);
|
||||
}
|
||||
|
||||
/* This code was created in case it will be used later,
|
||||
* and is currently not being used. */
|
||||
static uint8_t pfcp_cause_from_gtp(uint8_t gtp_cause)
|
||||
{
|
||||
switch (gtp_cause) {
|
||||
|
@ -820,7 +822,6 @@ void sgwc_s11_handle_downlink_data_notification_ack(
|
|||
uint8_t cause_value;
|
||||
|
||||
sgwc_sess_t *sess = NULL;
|
||||
ogs_pfcp_xact_t *pfcp_xact;
|
||||
|
||||
ogs_gtp_downlink_data_notification_acknowledge_t *ack = NULL;
|
||||
|
||||
|
@ -829,8 +830,6 @@ void sgwc_s11_handle_downlink_data_notification_ack(
|
|||
ack = &message->downlink_data_notification_acknowledge;
|
||||
ogs_assert(ack);
|
||||
|
||||
pfcp_xact = s11_xact->pfcp_xact;
|
||||
ogs_assert(pfcp_xact);
|
||||
sess = s11_xact->data;
|
||||
ogs_assert(sess);
|
||||
sgwc_ue = sess->sgwc_ue;
|
||||
|
@ -844,24 +843,16 @@ void sgwc_s11_handle_downlink_data_notification_ack(
|
|||
ogs_assert(cause);
|
||||
|
||||
cause_value = cause->value;
|
||||
if (cause_value != OGS_GTP_CAUSE_REQUEST_ACCEPTED)
|
||||
ogs_warn("GTP Failed [CAUSE:%d] - PFCP_CAUSE[%d]",
|
||||
cause_value, pfcp_cause_from_gtp(cause_value));
|
||||
} else {
|
||||
ogs_error("No Cause");
|
||||
cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING;
|
||||
}
|
||||
|
||||
if (cause_value != OGS_GTP_CAUSE_REQUEST_ACCEPTED) {
|
||||
ogs_pfcp_send_error_message(pfcp_xact, sess ? sess->sgwu_sxa_seid : 0,
|
||||
OGS_PFCP_SESSION_REPORT_RESPONSE_TYPE,
|
||||
pfcp_cause_from_gtp(cause_value), 0);
|
||||
return;
|
||||
}
|
||||
|
||||
ogs_debug("Downlink Data Notification Acknowledge");
|
||||
ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]",
|
||||
sgwc_ue->mme_s11_teid, sgwc_ue->sgw_s11_teid);
|
||||
|
||||
sgwc_pfcp_send_session_report_response(
|
||||
pfcp_xact, sess, pfcp_cause_from_gtp(cause_value));
|
||||
}
|
||||
|
||||
void sgwc_s11_handle_create_indirect_data_forwarding_tunnel_request(
|
||||
|
|
|
@ -244,7 +244,6 @@ void sgwc_sxa_handle_session_modification_response(
|
|||
|
||||
ogs_assert(pfcp_xact);
|
||||
ogs_assert(pfcp_rsp);
|
||||
ogs_assert(recv_message);
|
||||
|
||||
flags = pfcp_xact->modify_flags;
|
||||
ogs_assert(flags);
|
||||
|
@ -343,6 +342,7 @@ void sgwc_sxa_handle_session_modification_response(
|
|||
s5c_xact = pfcp_xact->assoc_xact;
|
||||
ogs_assert(s5c_xact);
|
||||
|
||||
ogs_assert(recv_message);
|
||||
gtp_req = &recv_message->create_bearer_request;
|
||||
ogs_assert(gtp_req);
|
||||
|
||||
|
@ -384,6 +384,7 @@ void sgwc_sxa_handle_session_modification_response(
|
|||
s5c_xact = pfcp_xact->assoc_xact;
|
||||
ogs_assert(s5c_xact);
|
||||
|
||||
ogs_assert(recv_message);
|
||||
gtp_rsp = &recv_message->create_bearer_response;
|
||||
ogs_assert(gtp_rsp);
|
||||
|
||||
|
@ -451,6 +452,7 @@ void sgwc_sxa_handle_session_modification_response(
|
|||
ogs_gtp_f_teid_t rsp_dl_teid[OGS_GTP_MAX_INDIRECT_TUNNEL];
|
||||
ogs_gtp_f_teid_t rsp_ul_teid[OGS_GTP_MAX_INDIRECT_TUNNEL];
|
||||
|
||||
ogs_assert(recv_message);
|
||||
gtp_req = &recv_message->
|
||||
create_indirect_data_forwarding_tunnel_request;
|
||||
ogs_assert(gtp_req);
|
||||
|
@ -616,6 +618,7 @@ void sgwc_sxa_handle_session_modification_response(
|
|||
s5c_xact = pfcp_xact->assoc_xact;
|
||||
ogs_assert(s5c_xact);
|
||||
|
||||
ogs_assert(recv_message);
|
||||
recv_message->h.type = OGS_GTP_DELETE_BEARER_RESPONSE_TYPE;
|
||||
recv_message->h.teid = sess->pgw_s5c_teid;
|
||||
|
||||
|
@ -640,6 +643,7 @@ void sgwc_sxa_handle_session_modification_response(
|
|||
ogs_gtp_f_teid_t sgw_s11_teid;
|
||||
ogs_gtp_f_teid_t sgw_s1u_teid;
|
||||
|
||||
ogs_assert(recv_message);
|
||||
gtp_rsp = &recv_message->create_session_response;
|
||||
ogs_assert(gtp_rsp);
|
||||
|
||||
|
@ -684,6 +688,7 @@ void sgwc_sxa_handle_session_modification_response(
|
|||
ogs_gtp_modify_bearer_request_t *gtp_req = NULL;
|
||||
ogs_gtp_modify_bearer_response_t *gtp_rsp = NULL;
|
||||
|
||||
ogs_assert(recv_message);
|
||||
gtp_req = &recv_message->modify_bearer_request;
|
||||
ogs_assert(gtp_req);
|
||||
|
||||
|
@ -745,9 +750,6 @@ void sgwc_sxa_handle_session_modification_response(
|
|||
} else if (flags & OGS_PFCP_MODIFY_DEACTIVATE) {
|
||||
bool release_access_bearers_is_done;
|
||||
|
||||
s11_xact = pfcp_xact->assoc_xact;
|
||||
ogs_assert(s11_xact);
|
||||
|
||||
sess->state.release_access_bearers = true;
|
||||
|
||||
release_access_bearers_is_done = true;
|
||||
|
@ -757,31 +759,45 @@ void sgwc_sxa_handle_session_modification_response(
|
|||
}
|
||||
|
||||
if (release_access_bearers_is_done == true) {
|
||||
ogs_gtp_release_access_bearers_response_t *gtp_rsp = NULL;
|
||||
if (flags & OGS_PFCP_MODIFY_ERROR_INDICATION) {
|
||||
/* It's faked method for receiving `bearer` context */
|
||||
bearer = pfcp_xact->assoc_xact;
|
||||
ogs_assert(bearer);
|
||||
|
||||
gtp_rsp = &send_message.release_access_bearers_response;
|
||||
ogs_assert(gtp_rsp);
|
||||
sgwc_gtp_send_downlink_data_notification(
|
||||
OGS_GTP_CAUSE_ERROR_INDICATION_RECEIVED, bearer);
|
||||
|
||||
memset(&send_message, 0, sizeof(ogs_gtp_message_t));
|
||||
} else {
|
||||
ogs_gtp_release_access_bearers_response_t *gtp_rsp = NULL;
|
||||
|
||||
memset(&cause, 0, sizeof(cause));
|
||||
cause.value = OGS_GTP_CAUSE_REQUEST_ACCEPTED;
|
||||
s11_xact = pfcp_xact->assoc_xact;
|
||||
ogs_assert(s11_xact);
|
||||
|
||||
gtp_rsp->cause.presence = 1;
|
||||
gtp_rsp->cause.data = &cause;
|
||||
gtp_rsp->cause.len = sizeof(cause);
|
||||
gtp_rsp = &send_message.release_access_bearers_response;
|
||||
ogs_assert(gtp_rsp);
|
||||
|
||||
send_message.h.type = OGS_GTP_RELEASE_ACCESS_BEARERS_RESPONSE_TYPE;
|
||||
send_message.h.teid = sgwc_ue->mme_s11_teid;
|
||||
memset(&send_message, 0, sizeof(ogs_gtp_message_t));
|
||||
|
||||
pkbuf = ogs_gtp_build_msg(&send_message);
|
||||
ogs_expect_or_return(pkbuf);
|
||||
memset(&cause, 0, sizeof(cause));
|
||||
cause.value = OGS_GTP_CAUSE_REQUEST_ACCEPTED;
|
||||
|
||||
rv = ogs_gtp_xact_update_tx(s11_xact, &send_message.h, pkbuf);
|
||||
ogs_expect_or_return(rv == OGS_OK);
|
||||
gtp_rsp->cause.presence = 1;
|
||||
gtp_rsp->cause.data = &cause;
|
||||
gtp_rsp->cause.len = sizeof(cause);
|
||||
|
||||
rv = ogs_gtp_xact_commit(s11_xact);
|
||||
ogs_expect(rv == OGS_OK);
|
||||
send_message.h.type =
|
||||
OGS_GTP_RELEASE_ACCESS_BEARERS_RESPONSE_TYPE;
|
||||
send_message.h.teid = sgwc_ue->mme_s11_teid;
|
||||
|
||||
pkbuf = ogs_gtp_build_msg(&send_message);
|
||||
ogs_expect_or_return(pkbuf);
|
||||
|
||||
rv = ogs_gtp_xact_update_tx(s11_xact, &send_message.h, pkbuf);
|
||||
ogs_expect_or_return(rv == OGS_OK);
|
||||
|
||||
rv = ogs_gtp_xact_commit(s11_xact);
|
||||
ogs_expect(rv == OGS_OK);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ogs_fatal("Invalid modify_flags[0x%llx]", (long long)flags);
|
||||
|
@ -894,31 +910,65 @@ void sgwc_sxa_handle_session_report_request(
|
|||
sgwc_ue = sess->sgwc_ue;
|
||||
ogs_assert(sgwc_ue);
|
||||
|
||||
if (sgwc_ue->gnode) {
|
||||
report_type.value = pfcp_req->report_type.u8;
|
||||
if (report_type.downlink_data_report) {
|
||||
if (pfcp_req->downlink_data_report.presence &&
|
||||
pfcp_req->downlink_data_report.pdr_id.presence) {
|
||||
if (!sgwc_ue->gnode) {
|
||||
ogs_error("No SGWC-UE GTP Node");
|
||||
ogs_pfcp_send_error_message(pfcp_xact, sess ? sess->sgwu_sxa_seid : 0,
|
||||
OGS_PFCP_SESSION_REPORT_RESPONSE_TYPE,
|
||||
OGS_PFCP_CAUSE_SESSION_CONTEXT_NOT_FOUND, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
pdr_id = pfcp_req->downlink_data_report.pdr_id.u16;
|
||||
sgwc_pfcp_send_session_report_response(
|
||||
pfcp_xact, sess, OGS_PFCP_CAUSE_REQUEST_ACCEPTED);
|
||||
|
||||
ogs_list_for_each(&sess->bearer_list, bearer) {
|
||||
ogs_list_for_each(&bearer->tunnel_list, tunnel) {
|
||||
ogs_assert(tunnel->pdr);
|
||||
if (tunnel->pdr->id == pdr_id) {
|
||||
sgwc_gtp_send_downlink_data_notification(
|
||||
bearer, pfcp_xact);
|
||||
return;
|
||||
}
|
||||
}
|
||||
report_type.value = pfcp_req->report_type.u8;
|
||||
|
||||
if (report_type.downlink_data_report) {
|
||||
if (pfcp_req->downlink_data_report.presence == 0) {
|
||||
ogs_error("No Downlink Data Report");
|
||||
return;
|
||||
}
|
||||
|
||||
if (pfcp_req->downlink_data_report.pdr_id.presence == 0) {
|
||||
ogs_error("No PDR-ID");
|
||||
return;
|
||||
}
|
||||
|
||||
pdr_id = pfcp_req->downlink_data_report.pdr_id.u16;
|
||||
|
||||
ogs_list_for_each(&sess->bearer_list, bearer) {
|
||||
ogs_list_for_each(&bearer->tunnel_list, tunnel) {
|
||||
ogs_assert(tunnel->pdr);
|
||||
if (tunnel->pdr->id == pdr_id) {
|
||||
sgwc_gtp_send_downlink_data_notification(
|
||||
OGS_GTP_CAUSE_INVALID_VALUE, bearer);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ogs_error("Cannot find the PDR-ID[%d]", pdr_id);
|
||||
|
||||
} else if (report_type.error_indication_report) {
|
||||
bearer = sgwc_bearer_find_by_error_indication_report(
|
||||
sess, &pfcp_req->error_indication_report);
|
||||
|
||||
if (!bearer) return;
|
||||
|
||||
ogs_list_for_each(&sgwc_ue->sess_list, sess) {
|
||||
|
||||
sess->state.release_access_bearers = false;
|
||||
|
||||
sgwc_pfcp_send_sess_modification_request(sess,
|
||||
/* We only use the `assoc_xact` parameter temporarily here
|
||||
* to pass the `bearer` context. */
|
||||
(ogs_gtp_xact_t *)bearer,
|
||||
NULL,
|
||||
OGS_PFCP_MODIFY_DL_ONLY|OGS_PFCP_MODIFY_DEACTIVATE|
|
||||
OGS_PFCP_MODIFY_ERROR_INDICATION);
|
||||
}
|
||||
|
||||
} else {
|
||||
ogs_error("Not supported Report Type[%d]", report_type.value);
|
||||
}
|
||||
|
||||
ogs_error("No Bearer");
|
||||
ogs_pfcp_send_error_message(pfcp_xact, 0,
|
||||
OGS_PFCP_SESSION_REPORT_RESPONSE_TYPE,
|
||||
OGS_PFCP_CAUSE_SESSION_CONTEXT_NOT_FOUND, 0);
|
||||
|
||||
}
|
||||
|
|
|
@ -30,16 +30,16 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
|
|||
ssize_t size;
|
||||
char buf[OGS_ADDRSTRLEN];
|
||||
|
||||
sgwu_sess_t *sess = NULL;
|
||||
|
||||
ogs_pkbuf_t *pkbuf = NULL;
|
||||
ogs_sockaddr_t from;
|
||||
|
||||
ogs_gtp_header_t *gtp_h = NULL;
|
||||
struct ip *ip_h = NULL;
|
||||
ogs_pfcp_user_plane_report_t report;
|
||||
|
||||
uint32_t teid;
|
||||
uint8_t qfi;
|
||||
ogs_pfcp_pdr_t *pdr = NULL;
|
||||
ogs_pfcp_user_plane_report_t report;
|
||||
|
||||
ogs_assert(fd != INVALID_SOCKET);
|
||||
|
||||
|
@ -89,25 +89,8 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
|
|||
|
||||
teid = be32toh(gtp_h->teid);
|
||||
|
||||
if (gtp_h->type == OGS_GTPU_MSGTYPE_END_MARKER) {
|
||||
ogs_debug("[RECV] End Marker from [%s] : TEID[0x%x]",
|
||||
OGS_ADDR(&from, buf), teid);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (gtp_h->type == OGS_GTPU_MSGTYPE_ERR_IND) {
|
||||
ogs_warn("[RECV] Error Indication from [%s]", OGS_ADDR(&from, buf));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (gtp_h->type != OGS_GTPU_MSGTYPE_GPDU) {
|
||||
ogs_error("[DROP] Invalid GTPU Type [%d]", gtp_h->type);
|
||||
ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ogs_debug("[RECV] GPU-U from [%s] : TEID[0x%x]",
|
||||
OGS_ADDR(&from, buf), teid);
|
||||
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) {
|
||||
|
@ -142,31 +125,53 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
|
|||
}
|
||||
ogs_assert(ogs_pkbuf_pull(pkbuf, len));
|
||||
|
||||
ip_h = (struct ip *)pkbuf->data;
|
||||
ogs_assert(ip_h);
|
||||
if (gtp_h->type == OGS_GTPU_MSGTYPE_END_MARKER) {
|
||||
/* Nothing */
|
||||
|
||||
pdr = ogs_pfcp_pdr_find_by_teid_and_qfi(teid, qfi);
|
||||
if (!pdr) {
|
||||
#if 0 /* It's redundant log message */
|
||||
ogs_warn("[DROP] Cannot find PDR : TEID[0x%x] QFI[%d]",
|
||||
teid, qfi);
|
||||
#endif
|
||||
goto cleanup;
|
||||
}
|
||||
} else if (gtp_h->type == OGS_GTPU_MSGTYPE_ERR_IND) {
|
||||
ogs_pfcp_far_t *far = NULL;
|
||||
|
||||
ogs_pfcp_up_handle_pdr(pdr, pkbuf, &report);
|
||||
far = ogs_pfcp_far_find_by_error_indication(pkbuf);
|
||||
if (far) {
|
||||
ogs_pfcp_up_handle_error_indication(far, &report);
|
||||
|
||||
if (report.type.downlink_data_report) {
|
||||
sgwu_sess_t *sess = NULL;
|
||||
if (report.type.error_indication_report) {
|
||||
ogs_assert(far->sess);
|
||||
sess = SGWU_SESS(far->sess);
|
||||
ogs_assert(sess);
|
||||
|
||||
ogs_assert(pdr->sess);
|
||||
sess = SGWU_SESS(pdr->sess);
|
||||
ogs_assert(sess);
|
||||
sgwu_pfcp_send_session_report_request(sess, &report);
|
||||
}
|
||||
|
||||
report.downlink_data.pdr_id = pdr->id;
|
||||
report.downlink_data.qfi = qfi; /* for 5GC */
|
||||
} else {
|
||||
ogs_error("[DROP] Cannot decode Error-Indication");
|
||||
ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len);
|
||||
}
|
||||
} else if (gtp_h->type == OGS_GTPU_MSGTYPE_GPDU) {
|
||||
struct ip *ip_h = NULL;
|
||||
ogs_pfcp_pdr_t *pdr = NULL;
|
||||
|
||||
sgwu_pfcp_send_session_report_request(sess, &report);
|
||||
ip_h = (struct ip *)pkbuf->data;
|
||||
ogs_assert(ip_h);
|
||||
|
||||
pdr = ogs_pfcp_pdr_find_by_teid_and_qfi(teid, qfi);
|
||||
if (pdr) {
|
||||
ogs_pfcp_up_handle_pdr(pdr, pkbuf, &report);
|
||||
|
||||
if (report.type.downlink_data_report) {
|
||||
ogs_assert(pdr->sess);
|
||||
sess = SGWU_SESS(pdr->sess);
|
||||
ogs_assert(sess);
|
||||
|
||||
report.downlink_data.pdr_id = pdr->id;
|
||||
report.downlink_data.qfi = qfi; /* for 5GC */
|
||||
|
||||
sgwu_pfcp_send_session_report_request(sess, &report);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ogs_error("[DROP] Invalid GTPU Type [%d]", gtp_h->type);
|
||||
ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
|
|
|
@ -47,7 +47,10 @@ static void setup_gtp_node(ogs_pfcp_far_t *far)
|
|||
sgwu_self()->gtpu_sock, sgwu_self()->gtpu_sock6, gnode);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
}
|
||||
|
||||
OGS_SETUP_GTP_NODE(far, gnode);
|
||||
|
||||
ogs_pfcp_far_hash_set(far);
|
||||
}
|
||||
|
||||
void sgwu_sxa_handle_session_establishment_request(
|
||||
|
|
|
@ -85,7 +85,7 @@ static void _gtpv1_tun_recv_cb(short when, ogs_socket_t fd, void *data)
|
|||
|
||||
static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
|
||||
{
|
||||
int rv, len;
|
||||
int len;
|
||||
ssize_t size;
|
||||
char buf[OGS_ADDRSTRLEN];
|
||||
|
||||
|
@ -93,14 +93,12 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
|
|||
ogs_sockaddr_t from;
|
||||
|
||||
ogs_gtp_header_t *gtp_h = NULL;
|
||||
struct ip *ip_h = NULL;
|
||||
#if 0
|
||||
ogs_pfcp_user_plane_report_t report;
|
||||
#endif
|
||||
|
||||
uint32_t teid;
|
||||
uint8_t qfi;
|
||||
ogs_pfcp_pdr_t *pdr = NULL;
|
||||
upf_sess_t *sess = NULL;
|
||||
ogs_pfcp_subnet_t *subnet = NULL;
|
||||
ogs_pfcp_dev_t *dev = NULL;
|
||||
|
||||
ogs_assert(fd != INVALID_SOCKET);
|
||||
|
||||
|
@ -150,25 +148,8 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
|
|||
|
||||
teid = be32toh(gtp_h->teid);
|
||||
|
||||
if (gtp_h->type == OGS_GTPU_MSGTYPE_END_MARKER) {
|
||||
ogs_debug("[RECV] End Marker from [%s] : TEID[0x%x]",
|
||||
OGS_ADDR(&from, buf), teid);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (gtp_h->type == OGS_GTPU_MSGTYPE_ERR_IND) {
|
||||
ogs_warn("[RECV] Error Indication from [%s]", OGS_ADDR(&from, buf));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (gtp_h->type != OGS_GTPU_MSGTYPE_GPDU) {
|
||||
ogs_error("[DROP] Invalid GTPU Type [%d]", gtp_h->type);
|
||||
ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ogs_debug("[RECV] GPU-U from [%s] : TEID[0x%x]",
|
||||
OGS_ADDR(&from, buf), teid);
|
||||
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) {
|
||||
|
@ -203,48 +184,65 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
|
|||
}
|
||||
ogs_assert(ogs_pkbuf_pull(pkbuf, len));
|
||||
|
||||
ip_h = (struct ip *)pkbuf->data;
|
||||
ogs_assert(ip_h);
|
||||
if (gtp_h->type == OGS_GTPU_MSGTYPE_END_MARKER) {
|
||||
/* Nothing */
|
||||
|
||||
pdr = ogs_pfcp_pdr_find_by_teid_and_qfi(teid, qfi);
|
||||
if (!pdr) {
|
||||
#if 0 /* It's redundant log message */
|
||||
ogs_warn("[DROP] Cannot find PDR : UPF-N3-TEID[0x%x] QFI[%d]",
|
||||
teid, qfi);
|
||||
#endif
|
||||
goto cleanup;
|
||||
}
|
||||
ogs_assert(pdr->sess);
|
||||
sess = UPF_SESS(pdr->sess);
|
||||
ogs_assert(sess);
|
||||
} else if (gtp_h->type == OGS_GTPU_MSGTYPE_ERR_IND) {
|
||||
/* TODO */
|
||||
|
||||
if (ip_h->ip_v == 4 && sess->ipv4)
|
||||
subnet = sess->ipv4->subnet;
|
||||
else if (ip_h->ip_v == 6 && sess->ipv6)
|
||||
subnet = sess->ipv6->subnet;
|
||||
} else if (gtp_h->type == OGS_GTPU_MSGTYPE_GPDU) {
|
||||
int rv;
|
||||
|
||||
if (!subnet) {
|
||||
#if 0 /* It's redundant log message */
|
||||
ogs_error("[DROP] Cannot find subnet V:%d, IPv4:%p, IPv6:%p",
|
||||
ip_h->ip_v, sess->ipv4, sess->ipv6);
|
||||
ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len);
|
||||
#endif
|
||||
goto cleanup;
|
||||
}
|
||||
struct ip *ip_h = NULL;
|
||||
ogs_pfcp_pdr_t *pdr = NULL;
|
||||
|
||||
/* Check IPv6 */
|
||||
if (ogs_app()->parameter.no_slaac == 0 && ip_h->ip_v == 6) {
|
||||
rv = upf_gtp_handle_slaac(sess, pkbuf);
|
||||
if (rv == UPF_GTP_HANDLED) {
|
||||
upf_sess_t *sess = NULL;
|
||||
ogs_pfcp_subnet_t *subnet = NULL;
|
||||
ogs_pfcp_dev_t *dev = NULL;
|
||||
|
||||
ip_h = (struct ip *)pkbuf->data;
|
||||
ogs_assert(ip_h);
|
||||
|
||||
pdr = ogs_pfcp_pdr_find_by_teid_and_qfi(teid, qfi);
|
||||
if (!pdr) {
|
||||
/* TODO : Send Error Indication */
|
||||
goto cleanup;
|
||||
}
|
||||
ogs_assert(rv == OGS_OK);
|
||||
}
|
||||
ogs_assert(pdr->sess);
|
||||
sess = UPF_SESS(pdr->sess);
|
||||
ogs_assert(sess);
|
||||
|
||||
dev = subnet->dev;
|
||||
ogs_assert(dev);
|
||||
if (ogs_write(dev->fd, pkbuf->data, pkbuf->len) <= 0)
|
||||
ogs_error("ogs_write() failed");
|
||||
if (ip_h->ip_v == 4 && sess->ipv4)
|
||||
subnet = sess->ipv4->subnet;
|
||||
else if (ip_h->ip_v == 6 && sess->ipv6)
|
||||
subnet = sess->ipv6->subnet;
|
||||
|
||||
if (!subnet) {
|
||||
#if 0 /* It's redundant log message */
|
||||
ogs_error("[DROP] Cannot find subnet V:%d, IPv4:%p, IPv6:%p",
|
||||
ip_h->ip_v, sess->ipv4, sess->ipv6);
|
||||
ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len);
|
||||
#endif
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Check IPv6 */
|
||||
if (ogs_app()->parameter.no_slaac == 0 && ip_h->ip_v == 6) {
|
||||
rv = upf_gtp_handle_slaac(sess, pkbuf);
|
||||
if (rv == UPF_GTP_HANDLED) {
|
||||
goto cleanup;
|
||||
}
|
||||
ogs_assert(rv == OGS_OK);
|
||||
}
|
||||
|
||||
dev = subnet->dev;
|
||||
ogs_assert(dev);
|
||||
if (ogs_write(dev->fd, pkbuf->data, pkbuf->len) <= 0)
|
||||
ogs_error("ogs_write() failed");
|
||||
} else {
|
||||
ogs_error("[DROP] Invalid GTPU Type [%d]", gtp_h->type);
|
||||
ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
ogs_pkbuf_free(pkbuf);
|
||||
|
|
|
@ -48,7 +48,10 @@ static void setup_gtp_node(ogs_pfcp_far_t *far)
|
|||
upf_self()->gtpu_sock, upf_self()->gtpu_sock6, gnode);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
}
|
||||
|
||||
OGS_SETUP_GTP_NODE(far, gnode);
|
||||
|
||||
ogs_pfcp_far_hash_set(far);
|
||||
}
|
||||
|
||||
void upf_n4_handle_session_establishment_request(
|
||||
|
|
|
@ -95,6 +95,7 @@ void test_5gc_init(void)
|
|||
ogs_log_install_domain(&__ogs_ngap_domain, "ngap", OGS_LOG_ERROR);
|
||||
ogs_log_install_domain(&__ogs_dbi_domain, "dbi", OGS_LOG_ERROR);
|
||||
ogs_log_install_domain(&__ogs_nas_domain, "nas", OGS_LOG_ERROR);
|
||||
ogs_log_install_domain(&__ogs_gtp_domain, "gtp", OGS_LOG_ERROR);
|
||||
|
||||
ogs_sctp_init(ogs_app()->usrsctp.udp_port);
|
||||
ogs_assert(ogs_dbi_init(ogs_app()->db_uri) == OGS_OK);
|
||||
|
|
|
@ -119,6 +119,7 @@ void test_app_init(void)
|
|||
ogs_log_install_domain(&__ogs_diam_domain, "diam", OGS_LOG_ERROR);
|
||||
ogs_log_install_domain(&__ogs_dbi_domain, "dbi", OGS_LOG_ERROR);
|
||||
ogs_log_install_domain(&__ogs_nas_domain, "nas", OGS_LOG_ERROR);
|
||||
ogs_log_install_domain(&__ogs_gtp_domain, "gtp", OGS_LOG_ERROR);
|
||||
|
||||
ogs_sctp_init(ogs_app()->usrsctp.udp_port);
|
||||
ogs_assert(ogs_dbi_init(ogs_app()->db_uri) == OGS_OK);
|
||||
|
|
|
@ -100,6 +100,7 @@ void test_epc_init(void)
|
|||
ogs_log_install_domain(&__ogs_diam_domain, "diam", OGS_LOG_ERROR);
|
||||
ogs_log_install_domain(&__ogs_dbi_domain, "dbi", OGS_LOG_ERROR);
|
||||
ogs_log_install_domain(&__ogs_nas_domain, "nas", OGS_LOG_ERROR);
|
||||
ogs_log_install_domain(&__ogs_gtp_domain, "gtp", OGS_LOG_ERROR);
|
||||
|
||||
ogs_sctp_init(ogs_app()->usrsctp.udp_port);
|
||||
ogs_assert(ogs_dbi_init(ogs_app()->db_uri) == OGS_OK);
|
||||
|
|
|
@ -798,12 +798,458 @@ static void test2_func(abts_case *tc, void *data)
|
|||
test_ue_remove(test_ue);
|
||||
}
|
||||
|
||||
static void test3_func(abts_case *tc, void *data)
|
||||
{
|
||||
int rv;
|
||||
ogs_socknode_t *s1ap;
|
||||
ogs_socknode_t *gtpu;
|
||||
ogs_pkbuf_t *emmbuf;
|
||||
ogs_pkbuf_t *esmbuf;
|
||||
ogs_pkbuf_t *sendbuf;
|
||||
ogs_pkbuf_t *recvbuf;
|
||||
ogs_s1ap_message_t message;
|
||||
|
||||
ogs_nas_5gs_mobile_identity_suci_t mobile_identity_suci;
|
||||
test_ue_t *test_ue = NULL;
|
||||
test_sess_t *sess = NULL;
|
||||
test_bearer_t *bearer = NULL;
|
||||
|
||||
uint32_t enb_ue_s1ap_id;
|
||||
uint64_t mme_ue_s1ap_id;
|
||||
|
||||
const char *_k_string = "465b5ce8b199b49faa5f0a2ee238a6bc";
|
||||
uint8_t k[OGS_KEY_LEN];
|
||||
const char *_opc_string = "e8ed289deba952e4283b54e88e6183ca";
|
||||
uint8_t opc[OGS_KEY_LEN];
|
||||
|
||||
mongoc_collection_t *collection = NULL;
|
||||
bson_t *doc = NULL;
|
||||
int64_t count = 0;
|
||||
bson_error_t error;
|
||||
const char *json =
|
||||
"{"
|
||||
"\"_id\" : { \"$oid\" : \"310014158b8861d7605378c6\" }, "
|
||||
"\"imsi\" : \"901707364000060\", "
|
||||
"\"pdn\" : ["
|
||||
"{"
|
||||
"\"apn\" : \"internet\", "
|
||||
"\"_id\" : { \"$oid\" : \"310014158b8861d7605378c7\" }, "
|
||||
"\"ambr\" : {"
|
||||
"\"uplink\" : { \"$numberLong\" : \"1000000\" }, "
|
||||
"\"downlink\" : { \"$numberLong\" : \"1000000\" } "
|
||||
"},"
|
||||
"\"qos\" : { "
|
||||
"\"qci\" : 9, "
|
||||
"\"arp\" : { "
|
||||
"\"priority_level\" : 15,"
|
||||
"\"pre_emption_vulnerability\" : 1, "
|
||||
"\"pre_emption_capability\" : 1"
|
||||
"} "
|
||||
"}, "
|
||||
"\"type\" : 2"
|
||||
"}"
|
||||
"],"
|
||||
"\"ambr\" : { "
|
||||
"\"uplink\" : { \"$numberLong\" : \"1000000\" }, "
|
||||
"\"downlink\" : { \"$numberLong\" : \"1000000\" } "
|
||||
"},"
|
||||
"\"subscribed_rau_tau_timer\" : 12,"
|
||||
"\"network_access_mode\" : 2, "
|
||||
"\"subscriber_status\" : 0, "
|
||||
"\"access_restriction_data\" : 32, "
|
||||
"\"security\" : { "
|
||||
"\"k\" : \"465B5CE8 B199B49F AA5F0A2E E238A6BC\", "
|
||||
"\"opc\" : \"E8ED289D EBA952E4 283B54E8 8E6183CA\", "
|
||||
"\"amf\" : \"8000\", "
|
||||
"\"sqn\" : { \"$numberLong\" : \"64\" } "
|
||||
"}, "
|
||||
"\"__v\" : 0 "
|
||||
"}";
|
||||
|
||||
/* Setup Test UE & Session Context */
|
||||
memset(&mobile_identity_suci, 0, sizeof(mobile_identity_suci));
|
||||
|
||||
mobile_identity_suci.h.supi_format = OGS_NAS_5GS_SUPI_FORMAT_IMSI;
|
||||
mobile_identity_suci.h.type = OGS_NAS_5GS_MOBILE_IDENTITY_SUCI;
|
||||
mobile_identity_suci.routing_indicator1 = 0;
|
||||
mobile_identity_suci.routing_indicator2 = 0xf;
|
||||
mobile_identity_suci.routing_indicator3 = 0xf;
|
||||
mobile_identity_suci.routing_indicator4 = 0xf;
|
||||
mobile_identity_suci.protection_scheme_id = OGS_NAS_5GS_NULL_SCHEME;
|
||||
mobile_identity_suci.home_network_pki_value = 0;
|
||||
mobile_identity_suci.scheme_output[0] = 0x37;
|
||||
mobile_identity_suci.scheme_output[1] = 0x46;
|
||||
mobile_identity_suci.scheme_output[2] = 0;
|
||||
mobile_identity_suci.scheme_output[3] = 0;
|
||||
mobile_identity_suci.scheme_output[4] = 0x06;
|
||||
|
||||
test_ue = test_ue_add_by_suci(&mobile_identity_suci, 13);
|
||||
ogs_assert(test_ue);
|
||||
|
||||
test_ue->e_cgi.cell_id = 0x54f6401;
|
||||
test_ue->nas.ksi = OGS_NAS_KSI_NO_KEY_IS_AVAILABLE;
|
||||
test_ue->nas.value = OGS_NAS_ATTACH_TYPE_EPS_ATTACH;
|
||||
|
||||
OGS_HEX(_k_string, strlen(_k_string), test_ue->k);
|
||||
OGS_HEX(_opc_string, strlen(_opc_string), test_ue->opc);
|
||||
|
||||
sess = test_sess_add_by_apn(test_ue, "internet");
|
||||
ogs_assert(sess);
|
||||
|
||||
/* eNB connects to MME */
|
||||
s1ap = tests1ap_client(AF_INET);
|
||||
ABTS_PTR_NOTNULL(tc, s1ap);
|
||||
|
||||
/* eNB connects to SGW */
|
||||
gtpu = test_gtpu_server(1, AF_INET);
|
||||
ABTS_PTR_NOTNULL(tc, gtpu);
|
||||
|
||||
/* Send S1-Setup Reqeust */
|
||||
sendbuf = test_s1ap_build_s1_setup_request(
|
||||
S1AP_ENB_ID_PR_macroENB_ID, 0x54f64);
|
||||
ABTS_PTR_NOTNULL(tc, sendbuf);
|
||||
rv = testenb_s1ap_send(s1ap, sendbuf);
|
||||
ABTS_INT_EQUAL(tc, OGS_OK, rv);
|
||||
|
||||
/* Receive S1-Setup Response */
|
||||
recvbuf = testenb_s1ap_read(s1ap);
|
||||
ABTS_PTR_NOTNULL(tc, recvbuf);
|
||||
tests1ap_recv(NULL, recvbuf);
|
||||
|
||||
/********** Insert Subscriber in Database */
|
||||
collection = mongoc_client_get_collection(
|
||||
ogs_mongoc()->client, ogs_mongoc()->name, "subscribers");
|
||||
ABTS_PTR_NOTNULL(tc, collection);
|
||||
doc = BCON_NEW("imsi", BCON_UTF8(test_ue->imsi));
|
||||
ABTS_PTR_NOTNULL(tc, doc);
|
||||
|
||||
count = mongoc_collection_count (
|
||||
collection, MONGOC_QUERY_NONE, doc, 0, 0, NULL, &error);
|
||||
if (count) {
|
||||
ABTS_TRUE(tc, mongoc_collection_remove(collection,
|
||||
MONGOC_REMOVE_SINGLE_REMOVE, doc, NULL, &error))
|
||||
}
|
||||
bson_destroy(doc);
|
||||
|
||||
doc = bson_new_from_json((const uint8_t *)json, -1, &error);;
|
||||
ABTS_PTR_NOTNULL(tc, doc);
|
||||
ABTS_TRUE(tc, mongoc_collection_insert(collection,
|
||||
MONGOC_INSERT_NONE, doc, NULL, &error));
|
||||
bson_destroy(doc);
|
||||
|
||||
doc = BCON_NEW("imsi", BCON_UTF8(test_ue->imsi));
|
||||
ABTS_PTR_NOTNULL(tc, doc);
|
||||
do {
|
||||
count = mongoc_collection_count (
|
||||
collection, MONGOC_QUERY_NONE, doc, 0, 0, NULL, &error);
|
||||
} while (count == 0);
|
||||
bson_destroy(doc);
|
||||
|
||||
collection = mongoc_client_get_collection(
|
||||
ogs_mongoc()->client, ogs_mongoc()->name, "subscribers");
|
||||
ABTS_PTR_NOTNULL(tc, collection);
|
||||
|
||||
/* Send Attach Request */
|
||||
memset(&sess->pdn_connectivity_param,
|
||||
0, sizeof(sess->pdn_connectivity_param));
|
||||
sess->pdn_connectivity_param.eit = 1;
|
||||
sess->pdn_connectivity_param.pco = 1;
|
||||
esmbuf = testesm_build_pdn_connectivity_request(sess);
|
||||
ABTS_PTR_NOTNULL(tc, esmbuf);
|
||||
|
||||
memset(&test_ue->attach_request_param,
|
||||
0, sizeof(test_ue->attach_request_param));
|
||||
test_ue->attach_request_param.ms_network_feature_support = 1;
|
||||
emmbuf = testemm_build_attach_request(test_ue, esmbuf);
|
||||
ABTS_PTR_NOTNULL(tc, emmbuf);
|
||||
|
||||
memset(&test_ue->initial_ue_param, 0, sizeof(test_ue->initial_ue_param));
|
||||
sendbuf = test_s1ap_build_initial_ue_message(
|
||||
test_ue, emmbuf, S1AP_RRC_Establishment_Cause_mo_Signalling, false);
|
||||
ABTS_INT_EQUAL(tc, OGS_OK, rv);
|
||||
rv = testenb_s1ap_send(s1ap, sendbuf);
|
||||
ABTS_INT_EQUAL(tc, OGS_OK, rv);
|
||||
|
||||
/* Receive Authentication Request */
|
||||
recvbuf = testenb_s1ap_read(s1ap);
|
||||
ABTS_PTR_NOTNULL(tc, recvbuf);
|
||||
tests1ap_recv(test_ue, recvbuf);
|
||||
|
||||
/* Send Authentication response */
|
||||
emmbuf = testemm_build_authentication_response(test_ue);
|
||||
ABTS_PTR_NOTNULL(tc, emmbuf);
|
||||
sendbuf = test_s1ap_build_uplink_nas_transport(test_ue, emmbuf);
|
||||
ABTS_PTR_NOTNULL(tc, sendbuf);
|
||||
rv = testenb_s1ap_send(s1ap, sendbuf);
|
||||
ABTS_INT_EQUAL(tc, OGS_OK, rv);
|
||||
|
||||
/* Receive Security mode Command */
|
||||
recvbuf = testenb_s1ap_read(s1ap);
|
||||
ABTS_PTR_NOTNULL(tc, recvbuf);
|
||||
tests1ap_recv(test_ue, recvbuf);
|
||||
|
||||
/* Send Security mode complete */
|
||||
test_ue->mobile_identity_imeisv_presence = true;
|
||||
emmbuf = testemm_build_security_mode_complete(test_ue);
|
||||
ABTS_PTR_NOTNULL(tc, emmbuf);
|
||||
sendbuf = test_s1ap_build_uplink_nas_transport(test_ue, emmbuf);
|
||||
ABTS_PTR_NOTNULL(tc, sendbuf);
|
||||
rv = testenb_s1ap_send(s1ap, sendbuf);
|
||||
ABTS_INT_EQUAL(tc, OGS_OK, rv);
|
||||
|
||||
/* Receive ESM Information Request */
|
||||
recvbuf = testenb_s1ap_read(s1ap);
|
||||
ABTS_PTR_NOTNULL(tc, recvbuf);
|
||||
tests1ap_recv(test_ue, recvbuf);
|
||||
|
||||
/* Send ESM Information Response */
|
||||
esmbuf = testesm_build_esm_information_response(sess);
|
||||
ABTS_PTR_NOTNULL(tc, esmbuf);
|
||||
sendbuf = test_s1ap_build_uplink_nas_transport(test_ue, esmbuf);
|
||||
ABTS_PTR_NOTNULL(tc, sendbuf);
|
||||
rv = testenb_s1ap_send(s1ap, sendbuf);
|
||||
ABTS_INT_EQUAL(tc, OGS_OK, rv);
|
||||
|
||||
/* Receive Initial Context Setup Request +
|
||||
* Attach Accept +
|
||||
* Activate Default Bearer Context Request */
|
||||
recvbuf = testenb_s1ap_read(s1ap);
|
||||
ABTS_PTR_NOTNULL(tc, recvbuf);
|
||||
tests1ap_recv(test_ue, recvbuf);
|
||||
|
||||
/* Send UE Capability Info Indication */
|
||||
sendbuf = tests1ap_build_ue_radio_capability_info_indication(test_ue);
|
||||
ABTS_PTR_NOTNULL(tc, sendbuf);
|
||||
rv = testenb_s1ap_send(s1ap, sendbuf);
|
||||
ABTS_INT_EQUAL(tc, OGS_OK, rv);
|
||||
|
||||
/* Send Initial Context Setup Response */
|
||||
sendbuf = test_s1ap_build_initial_context_setup_response(test_ue);
|
||||
ABTS_PTR_NOTNULL(tc, sendbuf);
|
||||
rv = testenb_s1ap_send(s1ap, sendbuf);
|
||||
ABTS_INT_EQUAL(tc, OGS_OK, rv);
|
||||
|
||||
/* Send Attach Complete + Activate default EPS bearer cotext accept */
|
||||
test_ue->nr_cgi.cell_id = 0x1234502;
|
||||
bearer = test_bearer_find_by_ue_ebi(test_ue, 5);
|
||||
ogs_assert(bearer);
|
||||
esmbuf = testesm_build_activate_default_eps_bearer_context_accept(
|
||||
bearer, false);
|
||||
ABTS_PTR_NOTNULL(tc, esmbuf);
|
||||
emmbuf = testemm_build_attach_complete(test_ue, esmbuf);
|
||||
ABTS_PTR_NOTNULL(tc, emmbuf);
|
||||
sendbuf = test_s1ap_build_uplink_nas_transport(test_ue, emmbuf);
|
||||
ABTS_PTR_NOTNULL(tc, sendbuf);
|
||||
rv = testenb_s1ap_send(s1ap, sendbuf);
|
||||
ABTS_INT_EQUAL(tc, OGS_OK, rv);
|
||||
|
||||
/* Receive EMM information */
|
||||
recvbuf = testenb_s1ap_read(s1ap);
|
||||
ABTS_PTR_NOTNULL(tc, recvbuf);
|
||||
tests1ap_recv(test_ue, recvbuf);
|
||||
|
||||
/* Send UE Context Release Request */
|
||||
sendbuf = test_s1ap_build_ue_context_release_request(test_ue,
|
||||
S1AP_Cause_PR_radioNetwork, S1AP_CauseRadioNetwork_user_inactivity);
|
||||
ABTS_PTR_NOTNULL(tc, sendbuf);
|
||||
rv = testenb_s1ap_send(s1ap, sendbuf);
|
||||
ABTS_INT_EQUAL(tc, OGS_OK, rv);
|
||||
|
||||
/* Receive UE Context Release Command */
|
||||
recvbuf = testenb_s1ap_read(s1ap);
|
||||
ABTS_PTR_NOTNULL(tc, recvbuf);
|
||||
tests1ap_recv(test_ue, recvbuf);
|
||||
|
||||
/* Send UE Context Release Complete */
|
||||
sendbuf = test_s1ap_build_ue_context_release_complete(test_ue);
|
||||
ABTS_PTR_NOTNULL(tc, sendbuf);
|
||||
rv = testenb_s1ap_send(s1ap, sendbuf);
|
||||
ABTS_INT_EQUAL(tc, OGS_OK, rv);
|
||||
|
||||
/* Send GTP-U ICMP Packet */
|
||||
rv = test_gtpu_send_ping(gtpu, bearer, TEST_PING_IPV4);
|
||||
ABTS_INT_EQUAL(tc, OGS_OK, rv);
|
||||
|
||||
/* Receive S1-Paging */
|
||||
recvbuf = testenb_s1ap_read(s1ap);
|
||||
ABTS_PTR_NOTNULL(tc, recvbuf);
|
||||
tests1ap_recv(test_ue, recvbuf);
|
||||
|
||||
/* Send Service Request */
|
||||
emmbuf = testemm_build_service_request(test_ue);
|
||||
ABTS_PTR_NOTNULL(tc, emmbuf);
|
||||
sendbuf = test_s1ap_build_initial_ue_message(
|
||||
test_ue, emmbuf, S1AP_RRC_Establishment_Cause_mo_Data, true);
|
||||
ABTS_PTR_NOTNULL(tc, sendbuf);
|
||||
rv = testenb_s1ap_send(s1ap, sendbuf);
|
||||
ABTS_INT_EQUAL(tc, OGS_OK, rv);
|
||||
|
||||
/* Receive Initial Context Setup Request */
|
||||
recvbuf = testenb_s1ap_read(s1ap);
|
||||
ABTS_PTR_NOTNULL(tc, recvbuf);
|
||||
tests1ap_recv(test_ue, recvbuf);
|
||||
|
||||
/* Send Initial Context Setup Response */
|
||||
sendbuf = test_s1ap_build_initial_context_setup_response(test_ue);
|
||||
ABTS_PTR_NOTNULL(tc, sendbuf);
|
||||
rv = testenb_s1ap_send(s1ap, sendbuf);
|
||||
ABTS_INT_EQUAL(tc, OGS_OK, rv);
|
||||
|
||||
/* Receive GTP-U ICMP Packet */
|
||||
recvbuf = test_gtpu_read(gtpu);
|
||||
ABTS_PTR_NOTNULL(tc, recvbuf);
|
||||
ogs_pkbuf_free(recvbuf);
|
||||
|
||||
/* Send GTP-U ICMP Packet */
|
||||
rv = test_gtpu_send_ping(gtpu, bearer, TEST_PING_IPV4);
|
||||
ABTS_INT_EQUAL(tc, OGS_OK, rv);
|
||||
|
||||
/* Receive GTP-U ICMP Packet */
|
||||
recvbuf = test_gtpu_read(gtpu);
|
||||
ABTS_PTR_NOTNULL(tc, recvbuf);
|
||||
ogs_pkbuf_free(recvbuf);
|
||||
|
||||
/* Send Error Indication */
|
||||
rv = test_gtpu_send_error_indication(gtpu, bearer);
|
||||
ABTS_INT_EQUAL(tc, OGS_OK, rv);
|
||||
|
||||
/* Receive UE Context Release Command */
|
||||
recvbuf = testenb_s1ap_read(s1ap);
|
||||
ABTS_PTR_NOTNULL(tc, recvbuf);
|
||||
tests1ap_recv(test_ue, recvbuf);
|
||||
|
||||
/* Send UE Context Release Complete */
|
||||
sendbuf = test_s1ap_build_ue_context_release_complete(test_ue);
|
||||
ABTS_PTR_NOTNULL(tc, sendbuf);
|
||||
rv = testenb_s1ap_send(s1ap, sendbuf);
|
||||
ABTS_INT_EQUAL(tc, OGS_OK, rv);
|
||||
|
||||
/* Receive S1-Paging */
|
||||
recvbuf = testenb_s1ap_read(s1ap);
|
||||
ABTS_PTR_NOTNULL(tc, recvbuf);
|
||||
tests1ap_recv(test_ue, recvbuf);
|
||||
|
||||
/* Send Service Request */
|
||||
emmbuf = testemm_build_service_request(test_ue);
|
||||
ABTS_PTR_NOTNULL(tc, emmbuf);
|
||||
sendbuf = test_s1ap_build_initial_ue_message(
|
||||
test_ue, emmbuf, S1AP_RRC_Establishment_Cause_mo_Data, true);
|
||||
ABTS_PTR_NOTNULL(tc, sendbuf);
|
||||
rv = testenb_s1ap_send(s1ap, sendbuf);
|
||||
ABTS_INT_EQUAL(tc, OGS_OK, rv);
|
||||
|
||||
/* Receive Initial Context Setup Request */
|
||||
recvbuf = testenb_s1ap_read(s1ap);
|
||||
ABTS_PTR_NOTNULL(tc, recvbuf);
|
||||
tests1ap_recv(test_ue, recvbuf);
|
||||
|
||||
/* Send Initial Context Setup Response */
|
||||
sendbuf = test_s1ap_build_initial_context_setup_response(test_ue);
|
||||
ABTS_PTR_NOTNULL(tc, sendbuf);
|
||||
rv = testenb_s1ap_send(s1ap, sendbuf);
|
||||
ABTS_INT_EQUAL(tc, OGS_OK, rv);
|
||||
|
||||
/* Send UE Context Release Request */
|
||||
sendbuf = test_s1ap_build_ue_context_release_request(test_ue,
|
||||
S1AP_Cause_PR_radioNetwork, S1AP_CauseRadioNetwork_user_inactivity);
|
||||
ABTS_PTR_NOTNULL(tc, sendbuf);
|
||||
rv = testenb_s1ap_send(s1ap, sendbuf);
|
||||
ABTS_INT_EQUAL(tc, OGS_OK, rv);
|
||||
|
||||
/* Receive UE Context Release Command */
|
||||
recvbuf = testenb_s1ap_read(s1ap);
|
||||
ABTS_PTR_NOTNULL(tc, recvbuf);
|
||||
tests1ap_recv(test_ue, recvbuf);
|
||||
|
||||
/* Send UE Context Release Complete */
|
||||
sendbuf = test_s1ap_build_ue_context_release_complete(test_ue);
|
||||
ABTS_PTR_NOTNULL(tc, sendbuf);
|
||||
rv = testenb_s1ap_send(s1ap, sendbuf);
|
||||
ABTS_INT_EQUAL(tc, OGS_OK, rv);
|
||||
|
||||
/* Send Error Indication */
|
||||
rv = test_gtpu_send_error_indication(gtpu, bearer);
|
||||
ABTS_INT_EQUAL(tc, OGS_OK, rv);
|
||||
|
||||
/* Receive S1-Paging */
|
||||
recvbuf = testenb_s1ap_read(s1ap);
|
||||
ABTS_PTR_NOTNULL(tc, recvbuf);
|
||||
tests1ap_recv(test_ue, recvbuf);
|
||||
|
||||
/* Send Service Request */
|
||||
emmbuf = testemm_build_service_request(test_ue);
|
||||
ABTS_PTR_NOTNULL(tc, emmbuf);
|
||||
sendbuf = test_s1ap_build_initial_ue_message(
|
||||
test_ue, emmbuf, S1AP_RRC_Establishment_Cause_mo_Data, true);
|
||||
ABTS_PTR_NOTNULL(tc, sendbuf);
|
||||
rv = testenb_s1ap_send(s1ap, sendbuf);
|
||||
ABTS_INT_EQUAL(tc, OGS_OK, rv);
|
||||
|
||||
/* Receive Initial Context Setup Request */
|
||||
recvbuf = testenb_s1ap_read(s1ap);
|
||||
ABTS_PTR_NOTNULL(tc, recvbuf);
|
||||
tests1ap_recv(test_ue, recvbuf);
|
||||
|
||||
/* Send Initial Context Setup Response */
|
||||
sendbuf = test_s1ap_build_initial_context_setup_response(test_ue);
|
||||
ABTS_PTR_NOTNULL(tc, sendbuf);
|
||||
rv = testenb_s1ap_send(s1ap, sendbuf);
|
||||
ABTS_INT_EQUAL(tc, OGS_OK, rv);
|
||||
|
||||
/* Send GTP-U ICMP Packet */
|
||||
rv = test_gtpu_send_ping(gtpu, bearer, TEST_PING_IPV4);
|
||||
ABTS_INT_EQUAL(tc, OGS_OK, rv);
|
||||
|
||||
/* Receive GTP-U ICMP Packet */
|
||||
recvbuf = test_gtpu_read(gtpu);
|
||||
ABTS_PTR_NOTNULL(tc, recvbuf);
|
||||
ogs_pkbuf_free(recvbuf);
|
||||
|
||||
/* Send UE Context Release Request */
|
||||
sendbuf = test_s1ap_build_ue_context_release_request(test_ue,
|
||||
S1AP_Cause_PR_radioNetwork, S1AP_CauseRadioNetwork_user_inactivity);
|
||||
ABTS_PTR_NOTNULL(tc, sendbuf);
|
||||
rv = testenb_s1ap_send(s1ap, sendbuf);
|
||||
ABTS_INT_EQUAL(tc, OGS_OK, rv);
|
||||
|
||||
/* Receive UE Context Release Command */
|
||||
recvbuf = testenb_s1ap_read(s1ap);
|
||||
ABTS_PTR_NOTNULL(tc, recvbuf);
|
||||
tests1ap_recv(test_ue, recvbuf);
|
||||
|
||||
/* Send UE Context Release Complete */
|
||||
sendbuf = test_s1ap_build_ue_context_release_complete(test_ue);
|
||||
ABTS_PTR_NOTNULL(tc, sendbuf);
|
||||
rv = testenb_s1ap_send(s1ap, sendbuf);
|
||||
ABTS_INT_EQUAL(tc, OGS_OK, rv);
|
||||
|
||||
ogs_msleep(300);
|
||||
|
||||
/********** Remove Subscriber in Database */
|
||||
doc = BCON_NEW("imsi", BCON_UTF8(test_ue->imsi));
|
||||
ABTS_PTR_NOTNULL(tc, doc);
|
||||
ABTS_TRUE(tc, mongoc_collection_remove(collection,
|
||||
MONGOC_REMOVE_SINGLE_REMOVE, doc, NULL, &error))
|
||||
bson_destroy(doc);
|
||||
|
||||
mongoc_collection_destroy(collection);
|
||||
|
||||
/* eNB disonncect from MME */
|
||||
testenb_s1ap_close(s1ap);
|
||||
|
||||
/* eNB disonncect from SGW */
|
||||
test_gtpu_close(gtpu);
|
||||
|
||||
test_ue_remove(test_ue);
|
||||
}
|
||||
|
||||
abts_suite *test_idle(abts_suite *suite)
|
||||
{
|
||||
suite = ADD_SUITE(suite)
|
||||
|
||||
abts_run_test(suite, test1_func, NULL);
|
||||
abts_run_test(suite, test2_func, NULL);
|
||||
abts_run_test(suite, test3_func, NULL);
|
||||
|
||||
return suite;
|
||||
}
|
||||
|
|
|
@ -97,18 +97,62 @@ void test_gtpu_close(ogs_socknode_t *node)
|
|||
#include <netinet/icmp6.h>
|
||||
#endif
|
||||
|
||||
int test_gtpu_send(
|
||||
ogs_socknode_t *node, test_bearer_t *bearer,
|
||||
ogs_gtp_header_t *gtp_hdesc, ogs_gtp_extension_header_t *ext_hdesc,
|
||||
ogs_pkbuf_t *pkbuf)
|
||||
{
|
||||
ogs_gtp_node_t gnode;
|
||||
test_sess_t *sess = NULL;
|
||||
|
||||
ogs_assert(gtp_hdesc);
|
||||
ogs_assert(ext_hdesc);
|
||||
ogs_assert(pkbuf);
|
||||
|
||||
ogs_assert(bearer);
|
||||
sess = bearer->sess;
|
||||
ogs_assert(sess);
|
||||
|
||||
memset(&gnode, 0, sizeof(ogs_gtp_node_t));
|
||||
|
||||
gnode.addr.ogs_sin_port = htobe16(OGS_GTPV1_U_UDP_PORT);
|
||||
gnode.sock = node->sock;
|
||||
|
||||
if (bearer->qfi) {
|
||||
if (sess->upf_n3_ip.ipv4) {
|
||||
gnode.addr.ogs_sa_family = AF_INET;
|
||||
gnode.addr.sin.sin_addr.s_addr = sess->upf_n3_ip.addr;
|
||||
} else {
|
||||
ogs_fatal("Not implemented");
|
||||
ogs_assert_if_reached();
|
||||
}
|
||||
|
||||
} else if (bearer->ebi) {
|
||||
if (bearer->sgw_s1u_ip.ipv4) {
|
||||
gnode.addr.ogs_sa_family = AF_INET;
|
||||
gnode.addr.sin.sin_addr.s_addr = bearer->sgw_s1u_ip.addr;
|
||||
} else {
|
||||
ogs_fatal("Not implemented");
|
||||
ogs_assert_if_reached();
|
||||
}
|
||||
} else {
|
||||
ogs_fatal("No QFI[%d] and EBI[%d]", bearer->qfi, bearer->ebi);
|
||||
ogs_assert_if_reached();
|
||||
}
|
||||
|
||||
return ogs_gtp_send_user_plane(&gnode, gtp_hdesc, ext_hdesc, pkbuf);
|
||||
}
|
||||
|
||||
int test_gtpu_send_ping(
|
||||
ogs_socknode_t *node, test_bearer_t *bearer, const char *dst_ip)
|
||||
{
|
||||
int rv;
|
||||
ssize_t sent;
|
||||
|
||||
test_sess_t *sess = NULL;
|
||||
ogs_sockaddr_t upf;
|
||||
|
||||
ogs_gtp_header_t gtp_hdesc;
|
||||
ogs_gtp_extension_header_t ext_hdesc;
|
||||
|
||||
ogs_pkbuf_t *pkbuf = NULL;
|
||||
ogs_gtp_header_t *gtp_h = NULL;
|
||||
ogs_gtp_extension_header_t *ext_h = NULL;
|
||||
ogs_ipsubnet_t dst_ipsub;
|
||||
|
||||
ogs_assert(bearer);
|
||||
|
@ -119,79 +163,21 @@ int test_gtpu_send_ping(
|
|||
rv = ogs_ipsubnet(&dst_ipsub, dst_ip, NULL);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
|
||||
memset(&upf, 0, sizeof(ogs_sockaddr_t));
|
||||
upf.ogs_sin_port = htobe16(OGS_GTPV1_U_UDP_PORT);
|
||||
|
||||
pkbuf = ogs_pkbuf_alloc(
|
||||
NULL, 200 /* enough for ICMP; use smaller buffer */);
|
||||
ogs_assert(pkbuf);
|
||||
ogs_pkbuf_put(pkbuf, 200);
|
||||
ogs_pkbuf_reserve(pkbuf, OGS_GTPV1U_5GC_HEADER_LEN);
|
||||
ogs_pkbuf_put(pkbuf, 200-OGS_GTPV1U_5GC_HEADER_LEN);
|
||||
memset(pkbuf->data, 0, pkbuf->len);
|
||||
|
||||
gtp_h = (ogs_gtp_header_t *)pkbuf->data;
|
||||
if (bearer->qfi) {
|
||||
/* 5G Core */
|
||||
gtp_h->flags = 0x34;
|
||||
gtp_h->teid = htobe32(sess->upf_n3_teid);
|
||||
|
||||
if (sess->upf_n3_ip.ipv4) {
|
||||
upf.ogs_sa_family = AF_INET;
|
||||
upf.sin.sin_addr.s_addr = sess->upf_n3_ip.addr;
|
||||
} else {
|
||||
ogs_fatal("Not implemented");
|
||||
ogs_assert_if_reached();
|
||||
}
|
||||
|
||||
} else if (bearer->ebi) {
|
||||
/* EPC */
|
||||
gtp_h->flags = 0x30;
|
||||
gtp_h->teid = htobe32(bearer->sgw_s1u_teid);
|
||||
|
||||
if (bearer->sgw_s1u_ip.ipv4) {
|
||||
upf.ogs_sa_family = AF_INET;
|
||||
upf.sin.sin_addr.s_addr = bearer->sgw_s1u_ip.addr;
|
||||
} else {
|
||||
ogs_fatal("Not implemented");
|
||||
ogs_assert_if_reached();
|
||||
}
|
||||
} else {
|
||||
ogs_fatal("No QFI[%d] and EBI[%d]", bearer->qfi, bearer->ebi);
|
||||
ogs_assert_if_reached();
|
||||
}
|
||||
|
||||
gtp_h->type = OGS_GTPU_MSGTYPE_GPDU;
|
||||
|
||||
if (bearer->qfi) {
|
||||
ext_h = (ogs_gtp_extension_header_t *)
|
||||
(pkbuf->data + OGS_GTPV1U_HEADER_LEN);
|
||||
ext_h->type = OGS_GTP_EXTENSION_HEADER_TYPE_PDU_SESSION_CONTAINER;
|
||||
ext_h->len = 1;
|
||||
ext_h->pdu_type =
|
||||
OGS_GTP_EXTENSION_HEADER_PDU_TYPE_UL_PDU_SESSION_INFORMATION;
|
||||
ext_h->qos_flow_identifier = bearer->qfi;
|
||||
ext_h->next_type =
|
||||
OGS_GTP_EXTENSION_HEADER_TYPE_NO_MORE_EXTENSION_HEADERS;
|
||||
}
|
||||
|
||||
if (dst_ipsub.family == AF_INET) {
|
||||
struct ip *ip_h = NULL;
|
||||
struct icmp *icmp_h = NULL;
|
||||
|
||||
if (bearer->qfi) {
|
||||
gtp_h->length = htobe16(
|
||||
sizeof *ip_h + ICMP_MINLEN +
|
||||
OGS_GTPV1U_EXTENSION_HEADER_LEN + ext_h->len * 4);
|
||||
ogs_pkbuf_trim(pkbuf, sizeof *ip_h + ICMP_MINLEN);
|
||||
|
||||
ip_h = (struct ip *)(pkbuf->data +
|
||||
OGS_GTPV1U_HEADER_LEN +
|
||||
OGS_GTPV1U_EXTENSION_HEADER_LEN + ext_h->len * 4);
|
||||
icmp_h = (struct icmp *)((uint8_t *)ip_h + sizeof *ip_h);
|
||||
} else {
|
||||
gtp_h->length = htobe16(sizeof *ip_h + ICMP_MINLEN);
|
||||
|
||||
ip_h = (struct ip *)(pkbuf->data + OGS_GTPV1U_HEADER_LEN);
|
||||
icmp_h = (struct icmp *)((uint8_t *)ip_h + sizeof *ip_h);
|
||||
}
|
||||
ip_h = (struct ip *)pkbuf->data;
|
||||
icmp_h = (struct icmp *)((uint8_t *)ip_h + sizeof *ip_h);
|
||||
|
||||
ip_h->ip_v = 4;
|
||||
ip_h->ip_hl = 5;
|
||||
|
@ -217,15 +203,9 @@ int test_gtpu_send_ping(
|
|||
uint8_t nxt = 0;
|
||||
uint8_t *p = NULL;
|
||||
|
||||
if (bearer->qfi) {
|
||||
gtp_h->length = htobe16(sizeof *ip6_h + sizeof *icmp6_h) +
|
||||
OGS_GTPV1U_EXTENSION_HEADER_LEN + ext_h->len * 4;
|
||||
p = (uint8_t *)pkbuf->data + OGS_GTPV1U_HEADER_LEN +
|
||||
OGS_GTPV1U_EXTENSION_HEADER_LEN + ext_h->len * 4;
|
||||
} else {
|
||||
gtp_h->length = htobe16(sizeof *ip6_h + sizeof *icmp6_h);
|
||||
p = (uint8_t *)pkbuf->data + OGS_GTPV1U_HEADER_LEN;
|
||||
}
|
||||
ogs_pkbuf_trim(pkbuf, sizeof *ip6_h + sizeof *icmp6_h);
|
||||
|
||||
p = (uint8_t *)pkbuf->data;
|
||||
plen = htobe16(sizeof *icmp6_h);
|
||||
nxt = IPPROTO_ICMPV6;
|
||||
|
||||
|
@ -246,7 +226,7 @@ int test_gtpu_send_ping(
|
|||
icmp6_h->icmp6_cksum = ogs_in_cksum(
|
||||
(uint16_t *)ip6_h, sizeof *ip6_h + sizeof *icmp6_h);
|
||||
|
||||
ip6_h->ip6_flow = htonl(0x60000001);
|
||||
ip6_h->ip6_flow = htobe32(0x60000001);
|
||||
ip6_h->ip6_plen = plen;
|
||||
ip6_h->ip6_nxt = nxt;;
|
||||
ip6_h->ip6_hlim = 0xff;
|
||||
|
@ -258,117 +238,117 @@ int test_gtpu_send_ping(
|
|||
ogs_assert_if_reached();
|
||||
}
|
||||
|
||||
ogs_assert(node);
|
||||
ogs_assert(node->sock);
|
||||
memset(>p_hdesc, 0, sizeof(gtp_hdesc));
|
||||
memset(&ext_hdesc, 0, sizeof(ext_hdesc));
|
||||
|
||||
sent = ogs_sendto(node->sock->fd, pkbuf->data, pkbuf->len, 0, &upf);
|
||||
ogs_pkbuf_free(pkbuf);
|
||||
if (sent < 0 || sent != pkbuf->len)
|
||||
return OGS_ERROR;
|
||||
gtp_hdesc.type = OGS_GTPU_MSGTYPE_GPDU;
|
||||
|
||||
return OGS_OK;
|
||||
}
|
||||
|
||||
int test_gtpu_send_slacc_rs(ogs_socknode_t *node, test_bearer_t *bearer)
|
||||
{
|
||||
int rv;
|
||||
ssize_t sent;
|
||||
|
||||
test_sess_t *sess = NULL;
|
||||
ogs_sockaddr_t upf;
|
||||
|
||||
ogs_pkbuf_t *pkbuf = NULL;
|
||||
ogs_gtp_header_t *gtp_h = NULL;
|
||||
ogs_gtp_extension_header_t *ext_h = NULL;
|
||||
|
||||
unsigned char *ip_h = NULL;
|
||||
|
||||
const char *payload =
|
||||
"6000000000083aff fe80000000000000 0000000000000002"
|
||||
"ff02000000000000 0000000000000002 85007d3500000000";
|
||||
unsigned char tmp[OGS_MAX_SDU_LEN];
|
||||
|
||||
ogs_assert(bearer);
|
||||
sess = bearer->sess;
|
||||
ogs_assert(sess);
|
||||
|
||||
memset(&upf, 0, sizeof(ogs_sockaddr_t));
|
||||
upf.ogs_sin_port = htobe16(OGS_GTPV1_U_UDP_PORT);
|
||||
|
||||
pkbuf = ogs_pkbuf_alloc(
|
||||
NULL, 200 /* enough for ICMP; use smaller buffer */);
|
||||
ogs_assert(pkbuf);
|
||||
ogs_pkbuf_put(pkbuf, 200);
|
||||
memset(pkbuf->data, 0, pkbuf->len);
|
||||
|
||||
gtp_h = (ogs_gtp_header_t *)pkbuf->data;
|
||||
if (bearer->qfi) {
|
||||
/* 5G Core */
|
||||
gtp_h->flags = 0x36;
|
||||
gtp_h->teid = htobe32(sess->upf_n3_teid);
|
||||
|
||||
if (sess->upf_n3_ip.ipv4) {
|
||||
upf.ogs_sa_family = AF_INET;
|
||||
upf.sin.sin_addr.s_addr = sess->upf_n3_ip.addr;
|
||||
} else {
|
||||
ogs_fatal("Not implemented");
|
||||
ogs_assert_if_reached();
|
||||
}
|
||||
gtp_hdesc.teid = sess->upf_n3_teid;
|
||||
ext_hdesc.qos_flow_identifier = bearer->qfi;
|
||||
|
||||
} else if (bearer->ebi) {
|
||||
/* EPC */
|
||||
gtp_h->flags = 0x32;
|
||||
gtp_h->teid = htobe32(bearer->sgw_s1u_teid);
|
||||
gtp_hdesc.teid = bearer->sgw_s1u_teid;
|
||||
|
||||
if (bearer->sgw_s1u_ip.ipv4) {
|
||||
upf.ogs_sa_family = AF_INET;
|
||||
upf.sin.sin_addr.s_addr = bearer->sgw_s1u_ip.addr;
|
||||
} else {
|
||||
ogs_fatal("Not implemented");
|
||||
ogs_assert_if_reached();
|
||||
}
|
||||
} else {
|
||||
ogs_fatal("No QFI[%d] and EBI[%d]", bearer->qfi, bearer->ebi);
|
||||
ogs_assert_if_reached();
|
||||
}
|
||||
|
||||
gtp_h->type = OGS_GTPU_MSGTYPE_GPDU;
|
||||
return test_gtpu_send(node, bearer, >p_hdesc, &ext_hdesc, pkbuf);
|
||||
}
|
||||
|
||||
if (bearer->qfi) {
|
||||
ext_h = (ogs_gtp_extension_header_t *)
|
||||
(pkbuf->data + OGS_GTPV1U_HEADER_LEN);
|
||||
ext_h->type = OGS_GTP_EXTENSION_HEADER_TYPE_PDU_SESSION_CONTAINER;
|
||||
ext_h->len = 1;
|
||||
ext_h->pdu_type =
|
||||
OGS_GTP_EXTENSION_HEADER_PDU_TYPE_UL_PDU_SESSION_INFORMATION;
|
||||
ext_h->qos_flow_identifier = bearer->qfi;
|
||||
ext_h->next_type =
|
||||
OGS_GTP_EXTENSION_HEADER_TYPE_NO_MORE_EXTENSION_HEADERS;
|
||||
}
|
||||
int test_gtpu_send_slacc_rs(ogs_socknode_t *node, test_bearer_t *bearer)
|
||||
{
|
||||
test_sess_t *sess = NULL;
|
||||
|
||||
if (bearer->qfi) {
|
||||
gtp_h->length = htobe16(52 +
|
||||
OGS_GTPV1U_EXTENSION_HEADER_LEN + ext_h->len * 4);
|
||||
ogs_gtp_header_t gtp_hdesc;
|
||||
ogs_gtp_extension_header_t ext_hdesc;
|
||||
|
||||
ip_h = (pkbuf->data +
|
||||
OGS_GTPV1U_HEADER_LEN + 4 +
|
||||
OGS_GTPV1U_EXTENSION_HEADER_LEN + ext_h->len * 4);
|
||||
} else {
|
||||
gtp_h->length = htobe16(52);
|
||||
ogs_pkbuf_t *pkbuf = NULL;
|
||||
|
||||
ip_h = (pkbuf->data + OGS_GTPV1U_HEADER_LEN + 4);
|
||||
}
|
||||
const char *payload =
|
||||
"6000000000083aff fe80000000000000 0000000000000002"
|
||||
"ff02000000000000 0000000000000002 85007d3500000000";
|
||||
unsigned char tmp[OGS_MAX_SDU_LEN];
|
||||
int payload_len = 48;
|
||||
|
||||
ogs_assert(node);
|
||||
ogs_assert(node->sock);
|
||||
ogs_assert(bearer);
|
||||
sess = bearer->sess;
|
||||
ogs_assert(sess);
|
||||
|
||||
pkbuf = ogs_pkbuf_alloc(
|
||||
NULL, 200 /* enough for ICMP; use smaller buffer */);
|
||||
ogs_assert(pkbuf);
|
||||
ogs_pkbuf_reserve(pkbuf, OGS_GTPV1U_5GC_HEADER_LEN);
|
||||
ogs_pkbuf_put(pkbuf, 200-OGS_GTPV1U_5GC_HEADER_LEN);
|
||||
memset(pkbuf->data, 0, pkbuf->len);
|
||||
|
||||
OGS_HEX(payload, strlen(payload), tmp);
|
||||
memcpy(ip_h, tmp, 48);
|
||||
memcpy(pkbuf->data, tmp, payload_len);
|
||||
|
||||
sent = ogs_sendto(node->sock->fd, pkbuf->data, pkbuf->len, 0, &upf);
|
||||
ogs_pkbuf_free(pkbuf);
|
||||
if (sent < 0 || sent != pkbuf->len)
|
||||
return OGS_ERROR;
|
||||
ogs_pkbuf_trim(pkbuf, payload_len);
|
||||
|
||||
return OGS_OK;
|
||||
memset(>p_hdesc, 0, sizeof(gtp_hdesc));
|
||||
memset(&ext_hdesc, 0, sizeof(ext_hdesc));
|
||||
|
||||
gtp_hdesc.type = OGS_GTPU_MSGTYPE_GPDU;
|
||||
gtp_hdesc.flags = OGS_GTPU_FLAGS_S;
|
||||
|
||||
if (bearer->qfi) {
|
||||
gtp_hdesc.teid = sess->upf_n3_teid;
|
||||
ext_hdesc.qos_flow_identifier = bearer->qfi;
|
||||
|
||||
} else if (bearer->ebi) {
|
||||
gtp_hdesc.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);
|
||||
}
|
||||
|
||||
int test_gtpu_send_error_indication(
|
||||
ogs_socknode_t *node, test_bearer_t *bearer)
|
||||
{
|
||||
test_sess_t *sess = NULL;
|
||||
uint32_t teid = 0;
|
||||
|
||||
ogs_gtp_header_t gtp_hdesc;
|
||||
ogs_gtp_extension_header_t ext_hdesc;
|
||||
|
||||
ogs_pkbuf_t *pkbuf = NULL;
|
||||
|
||||
ogs_assert(bearer);
|
||||
sess = bearer->sess;
|
||||
ogs_assert(sess);
|
||||
|
||||
ogs_assert(bearer);
|
||||
|
||||
if (bearer->qfi) {
|
||||
/* 5GC */
|
||||
teid = sess->gnb_n3_teid;
|
||||
|
||||
} else if (bearer->ebi) {
|
||||
/* EPC */
|
||||
teid = bearer->enb_s1u_teid;
|
||||
|
||||
} else {
|
||||
ogs_fatal("No QFI[%d] and EBI[%d]", bearer->qfi, bearer->ebi);
|
||||
ogs_assert_if_reached();
|
||||
}
|
||||
|
||||
pkbuf = ogs_gtp_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_GTP_EXTENSION_HEADER_TYPE_UDP_PORT;
|
||||
|
||||
return test_gtpu_send(node, bearer, >p_hdesc, &ext_hdesc, pkbuf);
|
||||
}
|
||||
|
|
|
@ -31,9 +31,15 @@ ogs_socknode_t *test_gtpu_server(int index, int family);
|
|||
ogs_pkbuf_t *test_gtpu_read(ogs_socknode_t *node);
|
||||
void test_gtpu_close(ogs_socknode_t *node);
|
||||
|
||||
int test_gtpu_send(
|
||||
ogs_socknode_t *node, test_bearer_t *bearer,
|
||||
ogs_gtp_header_t *gtp_hdesc, ogs_gtp_extension_header_t *ext_hdesc,
|
||||
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);
|
||||
int test_gtpu_send_error_indication(
|
||||
ogs_socknode_t *node, test_bearer_t *bearer);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue