forked from acouzens/open5gs
5GC UPF selection is added
This commit is contained in:
parent
9b3176ca4a
commit
661da4e034
|
@ -9,19 +9,21 @@ parameter:
|
|||
mme:
|
||||
freeDiameter: @sysconfdir@/freeDiameter/mme.conf
|
||||
s1ap:
|
||||
addr: 127.0.0.1
|
||||
gtpc:
|
||||
addr: 127.0.0.1
|
||||
sgsap:
|
||||
gummei:
|
||||
plmn_id:
|
||||
mcc: 001
|
||||
mnc: 01
|
||||
mcc: 901
|
||||
mnc: 70
|
||||
mme_gid: 2
|
||||
mme_code: 1
|
||||
tai:
|
||||
plmn_id:
|
||||
mcc: 001
|
||||
mnc: 01
|
||||
tac: 12345
|
||||
mcc: 901
|
||||
mnc: 70
|
||||
tac: 1
|
||||
|
||||
security:
|
||||
integrity_order : [ EIA1, EIA2, EIA0 ]
|
||||
|
@ -36,6 +38,7 @@ sgw:
|
|||
gtpc:
|
||||
addr: 127.0.0.2
|
||||
gtpu:
|
||||
addr: 127.0.0.2
|
||||
|
||||
pgw:
|
||||
freeDiameter: @sysconfdir@/freeDiameter/pgw.conf
|
||||
|
|
|
@ -204,18 +204,20 @@ logger:
|
|||
mme:
|
||||
freeDiameter: @sysconfdir@/freeDiameter/mme.conf
|
||||
s1ap:
|
||||
addr: 127.0.0.1
|
||||
gtpc:
|
||||
addr: 127.0.0.1
|
||||
gummei:
|
||||
plmn_id:
|
||||
mcc: 001
|
||||
mnc: 01
|
||||
mcc: 901
|
||||
mnc: 70
|
||||
mme_gid: 2
|
||||
mme_code: 1
|
||||
tai:
|
||||
plmn_id:
|
||||
mcc: 001
|
||||
mnc: 01
|
||||
tac: 12345
|
||||
mcc: 901
|
||||
mnc: 70
|
||||
tac: 1
|
||||
security:
|
||||
integrity_order : [ EIA1, EIA2, EIA0 ]
|
||||
ciphering_order : [ EEA0, EEA1, EEA2 ]
|
||||
|
|
|
@ -60,6 +60,7 @@ sgw:
|
|||
gtpc:
|
||||
addr: 127.0.0.2
|
||||
gtpu:
|
||||
addr: 127.0.0.2
|
||||
|
||||
#
|
||||
# parameter:
|
||||
|
|
|
@ -139,3 +139,29 @@ int ogs_gtp_ip_to_f_teid(ogs_ip_t *ip, ogs_gtp_f_teid_t *f_teid, int *len)
|
|||
|
||||
return OGS_OK;
|
||||
}
|
||||
|
||||
int ogs_gtp_paa_to_ip(ogs_paa_t *paa, ogs_ip_t *ip)
|
||||
{
|
||||
ogs_assert(paa);
|
||||
ogs_assert(ip);
|
||||
|
||||
memset(ip, 0, sizeof *ip);
|
||||
|
||||
if (paa->pdn_type == OGS_GTP_PDN_TYPE_IPV4V6) {
|
||||
ip->ipv4 = 1;
|
||||
ip->addr = paa->both.addr;
|
||||
ip->ipv6 = 1;
|
||||
memcpy(ip->addr6, paa->both.addr6, OGS_IPV6_LEN);
|
||||
} else if (paa->pdn_type == OGS_GTP_PDN_TYPE_IPV4) {
|
||||
ip->ipv4 = 1;
|
||||
ip->ipv6 = 0;
|
||||
ip->addr = paa->addr;
|
||||
} else if (paa->pdn_type == OGS_GTP_PDN_TYPE_IPV6) {
|
||||
ip->ipv4 = 0;
|
||||
ip->ipv6 = 1;
|
||||
memcpy(ip->addr6, paa->addr6, OGS_IPV6_LEN);
|
||||
} else
|
||||
ogs_assert_if_reached();
|
||||
|
||||
return OGS_OK;
|
||||
}
|
||||
|
|
|
@ -35,6 +35,8 @@ int ogs_gtp_sockaddr_to_f_teid(ogs_sockaddr_t *addr, ogs_sockaddr_t *addr6,
|
|||
int ogs_gtp_f_teid_to_ip(ogs_gtp_f_teid_t *f_teid, ogs_ip_t *ip);
|
||||
int ogs_gtp_ip_to_f_teid(ogs_ip_t *ip, ogs_gtp_f_teid_t *f_teid, int *len);
|
||||
|
||||
int ogs_gtp_paa_to_ip(ogs_paa_t *paa, ogs_ip_t *ip);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -868,9 +868,36 @@ ogs_pfcp_pdr_t *ogs_pfcp_pdr_find(
|
|||
return NULL;
|
||||
}
|
||||
|
||||
ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_by_teid(uint32_t teid)
|
||||
static uint64_t pdr_hash_keygen(uint32_t teid, uint8_t qfi)
|
||||
{
|
||||
return (ogs_pfcp_pdr_t *)ogs_hash_get(self.pdr_hash, &teid, sizeof(teid));
|
||||
uint64_t hashkey = (teid << 8) + qfi;
|
||||
return hashkey;
|
||||
}
|
||||
|
||||
void ogs_pfcp_pdr_hash_set(ogs_pfcp_pdr_t *pdr)
|
||||
{
|
||||
ogs_pfcp_qer_t *qer = NULL;
|
||||
uint8_t qfi = 0;
|
||||
|
||||
ogs_assert(pdr);
|
||||
|
||||
qer = pdr->qer;
|
||||
if (qer && qer->qfi) qfi = qer->qfi;
|
||||
|
||||
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, 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(
|
||||
|
@ -911,7 +938,6 @@ void ogs_pfcp_pdr_associate_far(ogs_pfcp_pdr_t *pdr, ogs_pfcp_far_t *far)
|
|||
ogs_assert(far);
|
||||
|
||||
pdr->far = far;
|
||||
far->pdr = pdr;
|
||||
}
|
||||
void ogs_pfcp_pdr_associate_urr(ogs_pfcp_pdr_t *pdr, ogs_pfcp_urr_t *urr)
|
||||
{
|
||||
|
@ -919,7 +945,6 @@ void ogs_pfcp_pdr_associate_urr(ogs_pfcp_pdr_t *pdr, ogs_pfcp_urr_t *urr)
|
|||
ogs_assert(urr);
|
||||
|
||||
pdr->urr = urr;
|
||||
urr->pdr = pdr;
|
||||
}
|
||||
void ogs_pfcp_pdr_associate_qer(ogs_pfcp_pdr_t *pdr, ogs_pfcp_qer_t *qer)
|
||||
{
|
||||
|
@ -927,7 +952,6 @@ void ogs_pfcp_pdr_associate_qer(ogs_pfcp_pdr_t *pdr, ogs_pfcp_qer_t *qer)
|
|||
ogs_assert(qer);
|
||||
|
||||
pdr->qer = qer;
|
||||
qer->pdr = pdr;
|
||||
}
|
||||
|
||||
void ogs_pfcp_pdr_remove(ogs_pfcp_pdr_t *pdr)
|
||||
|
@ -937,9 +961,9 @@ void ogs_pfcp_pdr_remove(ogs_pfcp_pdr_t *pdr)
|
|||
|
||||
ogs_list_remove(&pdr->sess->pdr_list, pdr);
|
||||
|
||||
if (pdr->f_teid.teid)
|
||||
ogs_hash_set(self.pdr_hash, &pdr->f_teid.teid,
|
||||
sizeof(pdr->f_teid.teid), NULL);
|
||||
if (pdr->hashkey)
|
||||
ogs_hash_set(ogs_pfcp_self()->pdr_hash, &pdr->hashkey,
|
||||
sizeof(pdr->hashkey), NULL);
|
||||
|
||||
ogs_pool_free(&ogs_pfcp_pdr_pool, pdr);
|
||||
}
|
||||
|
|
|
@ -115,11 +115,17 @@ typedef struct ogs_pfcp_sess_s {
|
|||
typedef struct ogs_pfcp_pdr_s {
|
||||
ogs_lnode_t lnode;
|
||||
|
||||
uint64_t hashkey;
|
||||
|
||||
ogs_pfcp_pdr_id_t id;
|
||||
ogs_pfcp_precedence_t precedence;
|
||||
ogs_pfcp_interface_t src_if;
|
||||
|
||||
ogs_pfcp_ue_ip_addr_t ue_ip_addr;
|
||||
int ue_ip_addr_len;
|
||||
|
||||
ogs_pfcp_f_teid_t f_teid;
|
||||
int f_teid_len;
|
||||
ogs_pfcp_outer_header_removal_t outer_header_removal;
|
||||
|
||||
ogs_pfcp_far_t *far;
|
||||
|
@ -149,7 +155,6 @@ typedef struct ogs_pfcp_far_s {
|
|||
/* Related Context */
|
||||
ogs_pfcp_sess_t *sess;
|
||||
void *gnode;
|
||||
ogs_pfcp_pdr_t *pdr;
|
||||
} ogs_pfcp_far_t;
|
||||
|
||||
typedef struct ogs_pfcp_urr_s {
|
||||
|
@ -157,7 +162,6 @@ typedef struct ogs_pfcp_urr_s {
|
|||
|
||||
ogs_pfcp_urr_id_t id;
|
||||
|
||||
ogs_pfcp_pdr_t *pdr;
|
||||
ogs_pfcp_sess_t *sess;
|
||||
} ogs_pfcp_urr_t;
|
||||
|
||||
|
@ -172,7 +176,6 @@ typedef struct ogs_pfcp_qer_s {
|
|||
|
||||
uint8_t qfi;
|
||||
|
||||
ogs_pfcp_pdr_t *pdr;
|
||||
ogs_pfcp_sess_t *sess;
|
||||
} ogs_pfcp_qer_t;
|
||||
|
||||
|
@ -256,9 +259,11 @@ ogs_pfcp_pdr_t *ogs_pfcp_sess_default_pdr(ogs_pfcp_sess_t *sess);
|
|||
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(uint32_t teid);
|
||||
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_reorder_by_precedence(
|
||||
|
|
|
@ -644,25 +644,38 @@ static ogs_pfcp_node_t *selected_upf_node(
|
|||
return next ? next : ogs_list_first(&ogs_pfcp_self()->n4_list);
|
||||
}
|
||||
|
||||
|
||||
smf_sess_t *smf_sess_add_by_apn(smf_ue_t *smf_ue, char *apn,
|
||||
uint8_t pdn_type, uint8_t ebi, ogs_paa_t *paa, ogs_gtp_uli_t *uli)
|
||||
void smf_sess_select_upf(smf_sess_t *sess)
|
||||
{
|
||||
char buf[OGS_ADDRSTRLEN];
|
||||
|
||||
ogs_assert(sess);
|
||||
|
||||
/*
|
||||
* When used for the first time, if last node is set,
|
||||
* the search is performed from the first SGW in a round-robin manner.
|
||||
*/
|
||||
if (ogs_pfcp_self()->node == NULL)
|
||||
ogs_pfcp_self()->node = ogs_list_last(&ogs_pfcp_self()->n4_list);
|
||||
|
||||
/* setup GTP session with selected UPF */
|
||||
ogs_pfcp_self()->node = selected_upf_node(ogs_pfcp_self()->node, sess);
|
||||
ogs_assert(ogs_pfcp_self()->node);
|
||||
OGS_SETUP_PFCP_NODE(sess, ogs_pfcp_self()->node);
|
||||
ogs_debug("UE using UPF on IP[%s]",
|
||||
OGS_ADDR(&ogs_pfcp_self()->node->addr, buf));
|
||||
|
||||
/* iterate to next UPF in list for next UE attach */
|
||||
ogs_pfcp_self()->node = ogs_list_next(ogs_pfcp_self()->node);
|
||||
}
|
||||
|
||||
smf_sess_t *smf_sess_add_by_apn(smf_ue_t *smf_ue, char *apn)
|
||||
{
|
||||
ogs_debug("smf_sess_add_by_apn");
|
||||
smf_event_t e;
|
||||
|
||||
char buf[OGS_ADDRSTRLEN];
|
||||
char buf1[OGS_ADDRSTRLEN];
|
||||
char buf2[OGS_ADDRSTRLEN];
|
||||
smf_sess_t *sess = NULL;
|
||||
smf_bearer_t *bearer = NULL;
|
||||
ogs_pfcp_pdr_t *pdr = NULL;
|
||||
ogs_pfcp_subnet_t *subnet6 = NULL;
|
||||
|
||||
ogs_assert(smf_ue);
|
||||
ogs_assert(apn);
|
||||
ogs_assert(paa);
|
||||
ogs_assert(uli);
|
||||
|
||||
ogs_pool_alloc(&smf_sess_pool, &sess);
|
||||
if (!sess) {
|
||||
|
@ -682,83 +695,6 @@ smf_sess_t *smf_sess_add_by_apn(smf_ue_t *smf_ue, char *apn,
|
|||
/* Set APN */
|
||||
ogs_cpystrn(sess->pdn.apn, apn, OGS_MAX_APN_LEN+1);
|
||||
|
||||
/* UE IP Address */
|
||||
sess->pdn.paa.pdn_type = pdn_type;
|
||||
ogs_expect(pdn_type == paa->pdn_type);
|
||||
|
||||
if (pdn_type == OGS_GTP_PDN_TYPE_IPV4) {
|
||||
sess->ipv4 = ogs_pfcp_ue_ip_alloc(
|
||||
AF_INET, apn, (uint8_t *)&(paa->addr));
|
||||
ogs_assert(sess->ipv4);
|
||||
sess->pdn.paa.addr = sess->ipv4->addr[0];
|
||||
ogs_hash_set(self.ipv4_hash, sess->ipv4->addr, OGS_IPV4_LEN, sess);
|
||||
} else if (pdn_type == OGS_GTP_PDN_TYPE_IPV6) {
|
||||
sess->ipv6 = ogs_pfcp_ue_ip_alloc(
|
||||
AF_INET6, apn, (paa->addr6));
|
||||
ogs_assert(sess->ipv6);
|
||||
|
||||
subnet6 = sess->ipv6->subnet;
|
||||
ogs_assert(subnet6);
|
||||
|
||||
sess->pdn.paa.len = subnet6->prefixlen;
|
||||
memcpy(sess->pdn.paa.addr6, sess->ipv6->addr, OGS_IPV6_LEN);
|
||||
ogs_hash_set(self.ipv6_hash, sess->ipv6->addr, OGS_IPV6_LEN, sess);
|
||||
} else if (pdn_type == OGS_GTP_PDN_TYPE_IPV4V6) {
|
||||
sess->ipv4 = ogs_pfcp_ue_ip_alloc(
|
||||
AF_INET, apn, (uint8_t *)&(paa->both.addr));
|
||||
ogs_assert(sess->ipv4);
|
||||
sess->ipv6 = ogs_pfcp_ue_ip_alloc(
|
||||
AF_INET6, apn, (paa->both.addr6));
|
||||
ogs_assert(sess->ipv6);
|
||||
|
||||
subnet6 = sess->ipv6->subnet;
|
||||
ogs_assert(subnet6);
|
||||
|
||||
sess->pdn.paa.both.addr = sess->ipv4->addr[0];
|
||||
sess->pdn.paa.both.len = subnet6->prefixlen;
|
||||
memcpy(sess->pdn.paa.both.addr6, sess->ipv6->addr, OGS_IPV6_LEN);
|
||||
ogs_hash_set(self.ipv4_hash, sess->ipv4->addr, OGS_IPV4_LEN, sess);
|
||||
ogs_hash_set(self.ipv6_hash, sess->ipv6->addr, OGS_IPV6_LEN, sess);
|
||||
} else
|
||||
ogs_assert_if_reached();
|
||||
|
||||
memcpy(&sess->e_tai, &uli->tai, sizeof(sess->e_tai));
|
||||
memcpy(&sess->e_cgi, &uli->e_cgi, sizeof(sess->e_cgi));
|
||||
|
||||
ogs_info("UE IMSI:[%s] APN:[%s] IPv4:[%s] IPv6:[%s]",
|
||||
sess->imsi_bcd, apn,
|
||||
sess->ipv4 ? OGS_INET_NTOP(&sess->ipv4->addr, buf1) : "",
|
||||
sess->ipv6 ? OGS_INET6_NTOP(&sess->ipv6->addr, buf2) : "");
|
||||
|
||||
/*
|
||||
* When used for the first time, if last node is set,
|
||||
* the search is performed from the first SGW in a round-robin manner.
|
||||
*/
|
||||
if (ogs_pfcp_self()->node == NULL)
|
||||
ogs_pfcp_self()->node = ogs_list_last(&ogs_pfcp_self()->n4_list);
|
||||
|
||||
/* setup GTP session with selected UPF */
|
||||
ogs_pfcp_self()->node = selected_upf_node(ogs_pfcp_self()->node, sess);
|
||||
ogs_assert(ogs_pfcp_self()->node);
|
||||
OGS_SETUP_PFCP_NODE(sess, ogs_pfcp_self()->node);
|
||||
ogs_debug("UE using UPF on IP[%s]",
|
||||
OGS_ADDR(&ogs_pfcp_self()->node->addr, buf));
|
||||
|
||||
/* iterate to next UPF in list for next UE attach */
|
||||
ogs_pfcp_self()->node = ogs_list_next(ogs_pfcp_self()->node);
|
||||
|
||||
/* Set Default Bearer */
|
||||
ogs_list_init(&sess->bearer_list);
|
||||
|
||||
bearer = smf_bearer_add(sess);
|
||||
ogs_assert(bearer);
|
||||
|
||||
bearer->ebi = ebi; /* EPC only */
|
||||
|
||||
/* Default PDRs is set to lowest precedence(highest precedence value). */
|
||||
ogs_list_for_each(&bearer->pfcp.pdr_list, pdr)
|
||||
pdr->precedence = 0xffffffff;
|
||||
|
||||
/* Setup SBI */
|
||||
sess->sbi.client_wait.timer = ogs_timer_add(
|
||||
self.timer_mgr, smf_timer_sbi_client_wait_expire, sess);
|
||||
|
@ -779,9 +715,7 @@ smf_sess_t *smf_sess_add_by_gtp_message(ogs_gtp_message_t *message)
|
|||
{
|
||||
smf_ue_t *smf_ue = NULL;
|
||||
smf_sess_t *sess = NULL;
|
||||
ogs_paa_t *paa = NULL;
|
||||
char apn[OGS_MAX_APN_LEN];
|
||||
ogs_gtp_uli_t uli;
|
||||
|
||||
ogs_gtp_create_session_request_t *req = &message->create_session_request;
|
||||
|
||||
|
@ -793,39 +727,11 @@ smf_sess_t *smf_sess_add_by_gtp_message(ogs_gtp_message_t *message)
|
|||
ogs_error("No APN");
|
||||
return NULL;
|
||||
}
|
||||
if (req->bearer_contexts_to_be_created.presence == 0) {
|
||||
ogs_error("No Bearer");
|
||||
return NULL;
|
||||
}
|
||||
if (req->bearer_contexts_to_be_created.eps_bearer_id.presence == 0) {
|
||||
ogs_error("No EPS Bearer ID");
|
||||
return NULL;
|
||||
}
|
||||
if (req->pdn_type.presence == 0) {
|
||||
ogs_error("No PDN Type");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (req->pdn_address_allocation.presence == 0) {
|
||||
ogs_error("No PAA");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (req->user_location_information.presence == 0) {
|
||||
ogs_error("No UE Location Information");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ogs_fqdn_parse(apn,
|
||||
req->access_point_name.data, req->access_point_name.len);
|
||||
|
||||
ogs_trace("smf_sess_add_by_message() [APN:%s, PDN:%d, EDI:%d]",
|
||||
apn, req->pdn_type.u8,
|
||||
req->bearer_contexts_to_be_created.eps_bearer_id.u8);
|
||||
|
||||
paa = (ogs_paa_t *)req->pdn_address_allocation.data;
|
||||
|
||||
ogs_gtp_parse_uli(&uli, &req->user_location_information);
|
||||
ogs_trace("smf_sess_add_by_message() [APN:%s]", apn);
|
||||
|
||||
/*
|
||||
* 7.2.1 in 3GPP TS 29.274 Release 15
|
||||
|
@ -859,20 +765,15 @@ smf_sess_t *smf_sess_add_by_gtp_message(ogs_gtp_message_t *message)
|
|||
smf_sess_remove(sess);
|
||||
}
|
||||
|
||||
sess = smf_sess_add_by_apn(smf_ue, apn, req->pdn_type.u8,
|
||||
req->bearer_contexts_to_be_created.eps_bearer_id.u8, paa, &uli);
|
||||
sess = smf_sess_add_by_apn(smf_ue, apn);
|
||||
return sess;
|
||||
}
|
||||
|
||||
smf_sess_t *smf_sess_add_by_psi(smf_ue_t *smf_ue, uint8_t psi)
|
||||
{
|
||||
ogs_debug("smf_sess_add_by_psi");
|
||||
|
||||
smf_event_t e;
|
||||
|
||||
smf_sess_t *sess = NULL;
|
||||
smf_bearer_t *bearer = NULL;
|
||||
ogs_pfcp_pdr_t *pdr = NULL;
|
||||
|
||||
ogs_assert(smf_ue);
|
||||
ogs_assert(psi != OGS_NAS_PDU_SESSION_IDENTITY_UNASSIGNED);
|
||||
|
@ -905,33 +806,6 @@ smf_sess_t *smf_sess_add_by_psi(smf_ue_t *smf_ue, uint8_t psi)
|
|||
sess->smf_n4_teid = sess->index;
|
||||
sess->smf_n4_seid = sess->index;
|
||||
|
||||
/* Select UPF with round-robin manner */
|
||||
if (ogs_pfcp_self()->node == NULL)
|
||||
ogs_pfcp_self()->node = ogs_list_first(&ogs_pfcp_self()->n4_list);
|
||||
|
||||
for (; ogs_pfcp_self()->node;
|
||||
ogs_pfcp_self()->node = ogs_list_next(ogs_pfcp_self()->node)) {
|
||||
if (OGS_FSM_CHECK(
|
||||
&ogs_pfcp_self()->node->sm, smf_pfcp_state_associated)) {
|
||||
OGS_SETUP_PFCP_NODE(sess, ogs_pfcp_self()->node);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set Default Bearer */
|
||||
ogs_list_init(&sess->bearer_list);
|
||||
|
||||
bearer = smf_bearer_add(sess);
|
||||
ogs_assert(bearer);
|
||||
|
||||
/* QFI is only used in 5GC */
|
||||
bearer->qfi = OGS_NEXT_ID(
|
||||
sess->qos_flow_identifier, 1, OGS_MAX_QOS_FLOW_ID+1);
|
||||
|
||||
/* Default PDRs is set to lowest precedence(highest precedence value). */
|
||||
ogs_list_for_each(&bearer->pfcp.pdr_list, pdr)
|
||||
pdr->precedence = 0xffffffff;
|
||||
|
||||
/* Setup SBI */
|
||||
sess->sbi.client_wait.timer = ogs_timer_add(
|
||||
self.timer_mgr, smf_timer_sbi_client_wait_expire, sess);
|
||||
|
@ -988,6 +862,70 @@ smf_sess_t *smf_sess_add_by_sbi_message(ogs_sbi_message_t *message)
|
|||
return sess;
|
||||
}
|
||||
|
||||
void smf_sess_set_ue_ip(smf_sess_t *sess)
|
||||
{
|
||||
ogs_pfcp_subnet_t *subnet6 = NULL;
|
||||
smf_ue_t *smf_ue = NULL;
|
||||
|
||||
ogs_assert(sess);
|
||||
smf_ue = sess->smf_ue;
|
||||
ogs_assert(smf_ue);
|
||||
|
||||
sess->pdn.paa.pdn_type = sess->pdn.pdn_type;
|
||||
ogs_assert(sess->pdn.pdn_type);
|
||||
|
||||
if (sess->ipv4) {
|
||||
ogs_hash_set(smf_self()->ipv4_hash,
|
||||
sess->ipv4->addr, OGS_IPV4_LEN, NULL);
|
||||
ogs_pfcp_ue_ip_free(sess->ipv4);
|
||||
}
|
||||
if (sess->ipv6) {
|
||||
ogs_hash_set(smf_self()->ipv6_hash,
|
||||
sess->ipv6->addr, OGS_IPV6_LEN, NULL);
|
||||
ogs_pfcp_ue_ip_free(sess->ipv6);
|
||||
}
|
||||
|
||||
if (sess->pdn.pdn_type == OGS_PDU_SESSION_TYPE_IPV4) {
|
||||
sess->ipv4 = ogs_pfcp_ue_ip_alloc(
|
||||
AF_INET, sess->pdn.apn, (uint8_t *)&sess->pdn.ue_ip.addr);
|
||||
ogs_assert(sess->ipv4);
|
||||
sess->pdn.paa.addr = sess->ipv4->addr[0];
|
||||
ogs_hash_set(smf_self()->ipv4_hash,
|
||||
sess->ipv4->addr, OGS_IPV4_LEN, sess);
|
||||
} else if (sess->pdn.pdn_type == OGS_PDU_SESSION_TYPE_IPV6) {
|
||||
sess->ipv6 = ogs_pfcp_ue_ip_alloc(
|
||||
AF_INET6, sess->pdn.apn, sess->pdn.ue_ip.addr6);
|
||||
ogs_assert(sess->ipv6);
|
||||
|
||||
subnet6 = sess->ipv6->subnet;
|
||||
ogs_assert(subnet6);
|
||||
|
||||
sess->pdn.paa.len = subnet6->prefixlen;
|
||||
memcpy(sess->pdn.paa.addr6, sess->ipv6->addr, OGS_IPV6_LEN);
|
||||
ogs_hash_set(smf_self()->ipv6_hash,
|
||||
sess->ipv6->addr, OGS_IPV6_LEN, sess);
|
||||
} else if (sess->pdn.pdn_type == OGS_PDU_SESSION_TYPE_IPV4V6) {
|
||||
sess->ipv4 = ogs_pfcp_ue_ip_alloc(
|
||||
AF_INET, sess->pdn.apn, (uint8_t *)&sess->pdn.ue_ip.addr);
|
||||
ogs_assert(sess->ipv4);
|
||||
sess->ipv6 = ogs_pfcp_ue_ip_alloc(
|
||||
AF_INET6, sess->pdn.apn, sess->pdn.ue_ip.addr6);
|
||||
ogs_assert(sess->ipv6);
|
||||
|
||||
subnet6 = sess->ipv6->subnet;
|
||||
ogs_assert(subnet6);
|
||||
|
||||
sess->pdn.paa.both.addr = sess->ipv4->addr[0];
|
||||
sess->pdn.paa.both.len = subnet6->prefixlen;
|
||||
memcpy(sess->pdn.paa.both.addr6, sess->ipv6->addr, OGS_IPV6_LEN);
|
||||
ogs_hash_set(smf_self()->ipv4_hash,
|
||||
sess->ipv4->addr, OGS_IPV4_LEN, sess);
|
||||
ogs_hash_set(smf_self()->ipv6_hash,
|
||||
sess->ipv6->addr, OGS_IPV6_LEN, sess);
|
||||
} else
|
||||
ogs_assert_if_reached();
|
||||
}
|
||||
|
||||
void smf_sess_remove(smf_sess_t *sess)
|
||||
{
|
||||
int i;
|
||||
|
@ -1035,6 +973,11 @@ void smf_sess_remove(smf_sess_t *sess)
|
|||
if (sess->dnn)
|
||||
ogs_free(sess->dnn);
|
||||
|
||||
if (sess->upf_n3_addr)
|
||||
ogs_freeaddrinfo(sess->upf_n3_addr);
|
||||
if (sess->upf_n3_addr6)
|
||||
ogs_freeaddrinfo(sess->upf_n3_addr6);
|
||||
|
||||
/* Free SBI object memory */
|
||||
ogs_sbi_object_free(&sess->sbi);
|
||||
ogs_timer_delete(sess->sbi.client_wait.timer);
|
||||
|
@ -1119,6 +1062,80 @@ smf_sess_t *smf_sess_find_by_ipv6(uint32_t *addr6)
|
|||
return (smf_sess_t *)ogs_hash_get(self.ipv6_hash, addr6, OGS_IPV6_LEN);
|
||||
}
|
||||
|
||||
smf_bearer_t *smf_qos_flow_add(smf_sess_t *sess)
|
||||
{
|
||||
smf_bearer_t *qos_flow = NULL;
|
||||
|
||||
ogs_pfcp_pdr_t *dl_pdr = NULL;
|
||||
ogs_pfcp_pdr_t *ul_pdr = NULL;
|
||||
ogs_pfcp_far_t *dl_far = NULL;
|
||||
ogs_pfcp_far_t *ul_far = NULL;
|
||||
ogs_pfcp_qer_t *qer = NULL;
|
||||
|
||||
ogs_assert(sess);
|
||||
|
||||
ogs_pool_alloc(&smf_bearer_pool, &qos_flow);
|
||||
ogs_assert(qos_flow);
|
||||
memset(qos_flow, 0, sizeof *qos_flow);
|
||||
|
||||
qos_flow->index = ogs_pool_index(&smf_bearer_pool, qos_flow);
|
||||
ogs_assert(qos_flow->index > 0 && qos_flow->index <=
|
||||
ogs_config()->pool.bearer);
|
||||
|
||||
ogs_list_init(&qos_flow->pf_list);
|
||||
|
||||
dl_pdr = ogs_pfcp_pdr_add(&qos_flow->pfcp);
|
||||
ogs_assert(dl_pdr);
|
||||
dl_pdr->id = OGS_NEXT_ID(sess->pdr_id, 1, OGS_MAX_NUM_OF_PDR+1);
|
||||
dl_pdr->src_if = OGS_PFCP_INTERFACE_CORE;
|
||||
|
||||
ul_pdr = ogs_pfcp_pdr_add(&qos_flow->pfcp);
|
||||
ogs_assert(ul_pdr);
|
||||
ul_pdr->id = OGS_NEXT_ID(sess->pdr_id, 1, OGS_MAX_NUM_OF_PDR+1);
|
||||
ul_pdr->src_if = OGS_PFCP_INTERFACE_ACCESS;
|
||||
|
||||
dl_far = ogs_pfcp_far_add(&qos_flow->pfcp);
|
||||
ogs_assert(dl_far);
|
||||
dl_far->id = OGS_NEXT_ID(sess->far_id, 1, OGS_MAX_NUM_OF_FAR+1);
|
||||
dl_far->dst_if = OGS_PFCP_INTERFACE_ACCESS;
|
||||
ogs_pfcp_pdr_associate_far(dl_pdr, dl_far);
|
||||
|
||||
ul_far = ogs_pfcp_far_add(&qos_flow->pfcp);
|
||||
ogs_assert(ul_far);
|
||||
ul_far->id = OGS_NEXT_ID(sess->far_id, 1, OGS_MAX_NUM_OF_FAR+1);
|
||||
ul_far->dst_if = OGS_PFCP_INTERFACE_CORE;
|
||||
ogs_pfcp_pdr_associate_far(ul_pdr, ul_far);
|
||||
|
||||
qer = ogs_pfcp_qer_add(&qos_flow->pfcp);
|
||||
ogs_assert(qer);
|
||||
qer->id = OGS_NEXT_ID(sess->qer_id, 1, OGS_MAX_NUM_OF_QER+1);
|
||||
ogs_pfcp_pdr_associate_qer(dl_pdr, qer);
|
||||
ogs_pfcp_pdr_associate_qer(ul_pdr, qer);
|
||||
|
||||
/* Allocate QFI */
|
||||
qer->qfi = OGS_NEXT_ID(sess->qos_flow_identifier, 1, OGS_MAX_QOS_FLOW_ID+1);
|
||||
qos_flow->qfi = qer->qfi;
|
||||
|
||||
qos_flow->sess = sess;
|
||||
|
||||
ogs_list_add(&sess->bearer_list, qos_flow);
|
||||
|
||||
return qos_flow;
|
||||
}
|
||||
|
||||
smf_bearer_t *smf_qos_flow_find_by_qfi(smf_sess_t *sess, uint8_t qfi)
|
||||
{
|
||||
smf_bearer_t *qos_flow = NULL;
|
||||
|
||||
ogs_assert(sess);
|
||||
ogs_list_for_each(&sess->bearer_list, qos_flow) {
|
||||
if (qos_flow->qfi == qfi)
|
||||
return qos_flow;
|
||||
}
|
||||
|
||||
return qos_flow;
|
||||
}
|
||||
|
||||
smf_bearer_t *smf_bearer_add(smf_sess_t *sess)
|
||||
{
|
||||
smf_bearer_t *bearer = NULL;
|
||||
|
@ -1169,26 +1186,30 @@ smf_bearer_t *smf_bearer_add(smf_sess_t *sess)
|
|||
sess->pdn.apn, OGS_PFCP_INTERFACE_ACCESS);
|
||||
if (resource) {
|
||||
ogs_pfcp_user_plane_ip_resource_info_to_sockaddr(&resource->info,
|
||||
&bearer->upf_addr, &bearer->upf_addr6);
|
||||
ogs_assert(bearer->upf_addr || bearer->upf_addr6);
|
||||
&bearer->upf_s5u_addr, &bearer->upf_s5u_addr6);
|
||||
ogs_assert(bearer->upf_s5u_addr || bearer->upf_s5u_addr6);
|
||||
if (resource->info.teidri)
|
||||
bearer->upf_n3_teid = UPF_S5U_INDEX_TO_TEID(
|
||||
bearer->upf_s5u_teid = UPF_GTPU_INDEX_TO_TEID(
|
||||
bearer->index, resource->info.teidri,
|
||||
resource->info.teid_range);
|
||||
else
|
||||
bearer->upf_n3_teid = bearer->index;
|
||||
bearer->upf_s5u_teid = bearer->index;
|
||||
} else {
|
||||
if (sess->pfcp_node->addr.ogs_sa_family == AF_INET)
|
||||
ogs_copyaddrinfo(&bearer->upf_addr, &sess->pfcp_node->addr);
|
||||
ogs_copyaddrinfo(&bearer->upf_s5u_addr, &sess->pfcp_node->addr);
|
||||
else if (sess->pfcp_node->addr.ogs_sa_family == AF_INET6)
|
||||
ogs_copyaddrinfo(&bearer->upf_addr6, &sess->pfcp_node->addr);
|
||||
ogs_copyaddrinfo(&bearer->upf_s5u_addr6, &sess->pfcp_node->addr);
|
||||
else
|
||||
ogs_assert_if_reached();
|
||||
ogs_assert(bearer->upf_addr || bearer->upf_addr6);
|
||||
ogs_assert(bearer->upf_s5u_addr || bearer->upf_s5u_addr6);
|
||||
|
||||
bearer->upf_n3_teid = bearer->index;
|
||||
bearer->upf_s5u_teid = bearer->index;
|
||||
}
|
||||
|
||||
ogs_pfcp_sockaddr_to_f_teid(bearer->upf_s5u_addr, bearer->upf_s5u_addr6,
|
||||
&ul_pdr->f_teid, &ul_pdr->f_teid_len);
|
||||
ul_pdr->f_teid.teid = bearer->upf_s5u_teid;
|
||||
|
||||
bearer->sess = sess;
|
||||
|
||||
ogs_list_add(&sess->bearer_list, bearer);
|
||||
|
@ -1206,10 +1227,10 @@ int smf_bearer_remove(smf_bearer_t *bearer)
|
|||
|
||||
if (bearer->name)
|
||||
ogs_free(bearer->name);
|
||||
if (bearer->upf_addr)
|
||||
ogs_freeaddrinfo(bearer->upf_addr);
|
||||
if (bearer->upf_addr6)
|
||||
ogs_freeaddrinfo(bearer->upf_addr6);
|
||||
if (bearer->upf_s5u_addr)
|
||||
ogs_freeaddrinfo(bearer->upf_s5u_addr);
|
||||
if (bearer->upf_s5u_addr6)
|
||||
ogs_freeaddrinfo(bearer->upf_s5u_addr6);
|
||||
|
||||
smf_pf_remove_all(bearer);
|
||||
|
||||
|
@ -1327,7 +1348,7 @@ bool smf_bearer_is_default(smf_bearer_t *bearer)
|
|||
default_bearer = smf_default_bearer_in_sess(sess);
|
||||
ogs_assert(default_bearer);
|
||||
|
||||
return bearer->ebi == default_bearer->ebi;
|
||||
return bearer == default_bearer;
|
||||
}
|
||||
|
||||
smf_bearer_t *smf_bearer_first(smf_sess_t *sess)
|
||||
|
@ -1566,4 +1587,3 @@ int smf_pco_build(uint8_t *pco_buf, uint8_t *buffer, int length)
|
|||
size = ogs_pco_build(pco_buf, OGS_MAX_PCO_LEN, &smf);
|
||||
return size;
|
||||
}
|
||||
|
||||
|
|
|
@ -143,7 +143,6 @@ typedef struct smf_sess_s {
|
|||
ogs_fsm_t sm; /* A state machine */
|
||||
|
||||
uint32_t smf_n4_teid; /* SMF-N4-TEID is derived from INDEX */
|
||||
#define SMF_5GC_SESS(__sESS) ((__sESS)->sgw_s5c_teid == 0)
|
||||
uint32_t sgw_s5c_teid; /* SGW-S5C-TEID is received from SGW */
|
||||
|
||||
#define SMF_SEID_TO_INDEX(__iNDEX) (__iNDEX & ~0x8000000000000000)
|
||||
|
@ -152,6 +151,21 @@ typedef struct smf_sess_s {
|
|||
uint64_t smf_n4_seid; /* SMF SEID is dervied from INDEX */
|
||||
uint64_t upf_n4_seid; /* UPF SEID is received from Peer */
|
||||
|
||||
/*
|
||||
* UPF-GTPU-TEID = INDEX | TEID_RANGE
|
||||
* INDEX = UPF-GTPU-TEID & ~TEID_RANGE
|
||||
*/
|
||||
#define UPF_GTPU_TEID_TO_INDEX(__tEID, __iND, __rANGE) \
|
||||
(__tEID & ~(__rANGE << (32 - __iND)))
|
||||
#define UPF_GTPU_INDEX_TO_TEID(__iNDEX, __iND, __rANGE) \
|
||||
(__iNDEX | (__rANGE << (32 - __iND)))
|
||||
uint32_t upf_n3_teid; /* UPF-N3 TEID */
|
||||
ogs_sockaddr_t *upf_n3_addr; /* UPF-N3 IPv4 */
|
||||
ogs_sockaddr_t *upf_n3_addr6; /* UPF-N3 IPv6 */
|
||||
|
||||
uint32_t gnb_n3_teid; /* gNB-N3 TEID */
|
||||
ogs_ip_t gnb_n3_ip; /* gNB-N3 IPv4/IPv6 */
|
||||
|
||||
char *gx_sid; /* Gx Session ID */
|
||||
|
||||
ogs_pfcp_pdr_id_t pdr_id; /* ID Generator(1~OGS_MAX_NUM_OF_PDR) */
|
||||
|
@ -162,11 +176,6 @@ typedef struct smf_sess_s {
|
|||
|
||||
uint8_t qos_flow_identifier; /* ID Generator(1~OGS_MAX_QOS_FLOW_ID) */
|
||||
|
||||
/* IMSI */
|
||||
uint8_t imsi[OGS_MAX_IMSI_LEN];
|
||||
int imsi_len;
|
||||
char imsi_bcd[OGS_MAX_IMSI_BCD_LEN+1];
|
||||
|
||||
char *sm_context_ref; /* smContextRef */
|
||||
uint8_t psi; /* PDU session identity */
|
||||
uint8_t pti; /* Procedure transaction identity */
|
||||
|
@ -227,6 +236,11 @@ typedef struct smf_sess_s {
|
|||
bool remove;
|
||||
} pfcp_5gc_modify;
|
||||
|
||||
struct {
|
||||
bool create_session_response_apn_ambr;
|
||||
bool create_session_response_bearer_qos;
|
||||
} gtp_5gc;;
|
||||
|
||||
/* UE session context is activated or not */
|
||||
OpenAPI_up_cnx_state_e ueUpCnxState;
|
||||
/* SMF session context is activated or not */
|
||||
|
@ -250,20 +264,12 @@ typedef struct smf_bearer_s {
|
|||
uint8_t qfi; /* 5GC */
|
||||
uint8_t ebi; /* EPC */
|
||||
|
||||
/*
|
||||
* UPF-S5U-TEID = INDEX | TEID_RANGE
|
||||
* INDEX = UPF-S5U-TEID & ~TEID_RANGE
|
||||
*/
|
||||
#define UPF_S5U_TEID_TO_INDEX(__tEID, __iND, __rANGE) \
|
||||
(__tEID & ~(__rANGE << (32 - __iND)))
|
||||
#define UPF_S5U_INDEX_TO_TEID(__iNDEX, __iND, __rANGE) \
|
||||
(__iNDEX | (__rANGE << (32 - __iND)))
|
||||
uint32_t upf_n3_teid; /* UPF_N3 TEID */
|
||||
ogs_sockaddr_t *upf_addr; /* UPF_N3 IPv4 */
|
||||
ogs_sockaddr_t *upf_addr6; /* UPF_N3 IPv6 */
|
||||
uint32_t upf_s5u_teid; /* UPF-S5U TEID */
|
||||
ogs_sockaddr_t *upf_s5u_addr; /* UPF-S5U IPv4 */
|
||||
ogs_sockaddr_t *upf_s5u_addr6; /* UPF-S5U IPv6 */
|
||||
|
||||
uint32_t gnb_n3_teid; /* gNB_N3 TEID */
|
||||
ogs_ip_t gnb_n3_ip; /* gNB_N3 IP */
|
||||
uint32_t sgw_s5u_teid; /* SGW-S5U TEID */
|
||||
ogs_ip_t sgw_s5u_ip; /* SGW-S5U IPv4/IPv6 */
|
||||
|
||||
char *name; /* PCC Rule Name */
|
||||
ogs_qos_t qos; /* QoS Infomration */
|
||||
|
@ -308,12 +314,14 @@ smf_ue_t *smf_ue_find_by_supi(char *supi);
|
|||
smf_ue_t *smf_ue_find_by_imsi(uint8_t *imsi, int imsi_len);
|
||||
|
||||
smf_sess_t *smf_sess_add_by_gtp_message(ogs_gtp_message_t *message);
|
||||
smf_sess_t *smf_sess_add_by_apn(smf_ue_t *smf_ue, char *apn,
|
||||
uint8_t pdn_type, uint8_t ebi, ogs_paa_t *paa, ogs_gtp_uli_t *uli);
|
||||
smf_sess_t *smf_sess_add_by_apn(smf_ue_t *smf_ue, char *apn);
|
||||
|
||||
smf_sess_t *smf_sess_add_by_sbi_message(ogs_sbi_message_t *message);
|
||||
smf_sess_t *smf_sess_add_by_psi(smf_ue_t *smf_ue, uint8_t psi);
|
||||
|
||||
void smf_sess_select_upf(smf_sess_t *sess);
|
||||
void smf_sess_set_ue_ip(smf_sess_t *sess);
|
||||
|
||||
void smf_sess_remove(smf_sess_t *sess);
|
||||
void smf_sess_remove_all(smf_ue_t *smf_ue);
|
||||
|
||||
|
@ -326,6 +334,9 @@ smf_sess_t *smf_sess_find_by_sm_context_ref(char *sm_context_ref);
|
|||
smf_sess_t *smf_sess_find_by_ipv4(uint32_t addr);
|
||||
smf_sess_t *smf_sess_find_by_ipv6(uint32_t *addr6);
|
||||
|
||||
smf_bearer_t *smf_qos_flow_add(smf_sess_t *sess);
|
||||
smf_bearer_t *smf_qos_flow_find_by_qfi(smf_sess_t *sess, uint8_t qfi);
|
||||
|
||||
smf_bearer_t *smf_bearer_add(smf_sess_t *sess);
|
||||
int smf_bearer_remove(smf_bearer_t *bearer);
|
||||
void smf_bearer_remove_all(smf_sess_t *sess);
|
||||
|
|
|
@ -73,6 +73,7 @@ void smf_gx_send_ccr(smf_sess_t *sess, ogs_gtp_xact_t *xact,
|
|||
uint32_t cc_request_type)
|
||||
{
|
||||
int ret;
|
||||
smf_ue_t *smf_ue = NULL;
|
||||
|
||||
struct msg *req = NULL;
|
||||
struct avp *avp;
|
||||
|
@ -85,6 +86,8 @@ void smf_gx_send_ccr(smf_sess_t *sess, ogs_gtp_xact_t *xact,
|
|||
|
||||
ogs_assert(sess);
|
||||
ogs_assert(sess->ipv4 || sess->ipv6);
|
||||
smf_ue = sess->smf_ue;
|
||||
ogs_assert(smf_ue);
|
||||
|
||||
ogs_debug("[Credit-Control-Request]");
|
||||
|
||||
|
@ -221,8 +224,8 @@ void smf_gx_send_ccr(smf_sess_t *sess, ogs_gtp_xact_t *xact,
|
|||
|
||||
ret = fd_msg_avp_new(ogs_diam_gx_subscription_id_data, 0, &avpch1);
|
||||
ogs_assert(ret == 0);
|
||||
val.os.data = (uint8_t *)sess->imsi_bcd;
|
||||
val.os.len = strlen(sess->imsi_bcd);
|
||||
val.os.data = (uint8_t *)smf_ue->imsi_bcd;
|
||||
val.os.len = strlen(smf_ue->imsi_bcd);
|
||||
ret = fd_msg_avp_setvalue (avpch1, &val);
|
||||
ogs_assert(ret == 0);
|
||||
ret = fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, avpch1);
|
||||
|
@ -352,7 +355,8 @@ void smf_gx_send_ccr(smf_sess_t *sess, ogs_gtp_xact_t *xact,
|
|||
ret = fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, avpch1);
|
||||
ogs_assert(ret == 0);
|
||||
|
||||
ret = fd_msg_avp_new(ogs_diam_gx_allocation_retention_priority, 0, &avpch1);
|
||||
ret = fd_msg_avp_new(
|
||||
ogs_diam_gx_allocation_retention_priority, 0, &avpch1);
|
||||
ogs_assert(ret == 0);
|
||||
|
||||
ret = fd_msg_avp_new(ogs_diam_gx_priority_level, 0, &avpch2);
|
||||
|
@ -615,14 +619,16 @@ static void smf_gx_cca_cb(void *data, struct msg **msg)
|
|||
ret = fd_msg_search_avp(*msg, ogs_diam_gx_qos_information, &avp);
|
||||
ogs_assert(ret == 0);
|
||||
if (avp) {
|
||||
ret = fd_avp_search_avp(avp, ogs_diam_gx_apn_aggregate_max_bitrate_ul, &avpch1);
|
||||
ret = fd_avp_search_avp(
|
||||
avp, ogs_diam_gx_apn_aggregate_max_bitrate_ul, &avpch1);
|
||||
ogs_assert(ret == 0);
|
||||
if (avpch1) {
|
||||
ret = fd_msg_avp_hdr(avpch1, &hdr);
|
||||
ogs_assert(ret == 0);
|
||||
gx_message->pdn.ambr.uplink = hdr->avp_value->u32;
|
||||
}
|
||||
ret = fd_avp_search_avp(avp, ogs_diam_gx_apn_aggregate_max_bitrate_dl, &avpch1);
|
||||
ret = fd_avp_search_avp(
|
||||
avp, ogs_diam_gx_apn_aggregate_max_bitrate_dl, &avpch1);
|
||||
ogs_assert(ret == 0);
|
||||
if (avpch1) {
|
||||
ret = fd_msg_avp_hdr(avpch1, &hdr);
|
||||
|
@ -642,10 +648,12 @@ static void smf_gx_cca_cb(void *data, struct msg **msg)
|
|||
gx_message->pdn.qos.qci = hdr->avp_value->u32;
|
||||
}
|
||||
|
||||
ret = fd_avp_search_avp(avp, ogs_diam_gx_allocation_retention_priority, &avpch1);
|
||||
ret = fd_avp_search_avp(
|
||||
avp, ogs_diam_gx_allocation_retention_priority, &avpch1);
|
||||
ogs_assert(ret == 0);
|
||||
if (avpch1) {
|
||||
ret = fd_avp_search_avp(avpch1, ogs_diam_gx_priority_level, &avpch2);
|
||||
ret = fd_avp_search_avp(
|
||||
avpch1, ogs_diam_gx_priority_level, &avpch2);
|
||||
ogs_assert(ret == 0);
|
||||
if (avpch2) {
|
||||
ret = fd_msg_avp_hdr(avpch2, &hdr);
|
||||
|
@ -653,7 +661,8 @@ static void smf_gx_cca_cb(void *data, struct msg **msg)
|
|||
gx_message->pdn.qos.arp.priority_level = hdr->avp_value->u32;
|
||||
}
|
||||
|
||||
ret = fd_avp_search_avp(avpch1, ogs_diam_gx_pre_emption_capability, &avpch2);
|
||||
ret = fd_avp_search_avp(
|
||||
avpch1, ogs_diam_gx_pre_emption_capability, &avpch2);
|
||||
ogs_assert(ret == 0);
|
||||
if (avpch2) {
|
||||
ret = fd_msg_avp_hdr(avpch2, &hdr);
|
||||
|
@ -791,7 +800,8 @@ out:
|
|||
ogs_debug(" CC-Request-Type[%d] Number[%d] in Session Data",
|
||||
sess_data->cc_request_type, sess_data->cc_request_number);
|
||||
ogs_debug(" Current CC-Request-Number[%d]", cc_request_number);
|
||||
if (sess_data->cc_request_type == OGS_DIAM_GX_CC_REQUEST_TYPE_TERMINATION_REQUEST &&
|
||||
if (sess_data->cc_request_type ==
|
||||
OGS_DIAM_GX_CC_REQUEST_TYPE_TERMINATION_REQUEST &&
|
||||
sess_data->cc_request_number <= cc_request_number) {
|
||||
ogs_debug(" [LAST] state_cleanup(): [%s]", sess_data->gx_sid);
|
||||
state_cleanup(sess_data, NULL, NULL);
|
||||
|
|
|
@ -87,18 +87,44 @@ ogs_pkbuf_t *gsm_build_pdu_session_establishment_accept(smf_sess_t *sess)
|
|||
selected_pdu_session_type->type = sess->pdn.ssc_mode;
|
||||
selected_pdu_session_type->value = sess->pdn.pdn_type;
|
||||
|
||||
/* Default QoS Rule */
|
||||
/*
|
||||
* TS23.501
|
||||
* 5.7.1.3 QoS Rules
|
||||
*
|
||||
* A default QoS rule is required to be sent to the UE for every PDU
|
||||
* Session establishment and it is associated with a QoS Flow. For IP type
|
||||
* PDU Session or Ethernet type PDU Session, the default QoS rule is
|
||||
* the only QoS rule of a PDU Session which may contain a Packet Filter
|
||||
* Set that allows all UL packets, and in this case, the highest
|
||||
* precedence value shall be used for the QoS rule.
|
||||
*
|
||||
* As long as the default QoS rule does not contain a Packet Filter Set or
|
||||
* contains a Packet Filter Set that allows all UL packets, Reflective QoS
|
||||
* should not be applied for the QoS Flow which the default QoS rule is
|
||||
* associated with and the RQA should not be sent for this QoS Flow.
|
||||
*/
|
||||
memset(qos_rule, 0, sizeof(qos_rule));
|
||||
qos_rule[0].identifier = 1;
|
||||
qos_rule[0].length = 6;
|
||||
qos_rule[0].code = OGS_NAS_QOS_CODE_CREATE_NEW_QOS_RULE;
|
||||
qos_rule[0].DQR_bit = 1;
|
||||
qos_rule[0].num_of_packet_filter = 1;
|
||||
|
||||
qos_rule[0].pf[0].direction = OGS_NAS_QOS_DIRECTION_UPLINK;
|
||||
qos_rule[0].pf[0].pf_identifier = 1;
|
||||
qos_rule[0].pf[0].length = 1;
|
||||
qos_rule[0].pf[0].num_of_component = 1;
|
||||
qos_rule[0].pf[0].component[0].type = OGS_PACKET_FILTER_MATCH_ALL;
|
||||
|
||||
/*
|
||||
* TS23.501
|
||||
* 5.7.1.9 Precedence Value
|
||||
*
|
||||
* The QoS rule precedence value and the PDR precedence value determine
|
||||
* the order in which a QoS rule or a PDR, respectively, shall be evaluated.
|
||||
* The evaluation of the QoS rules or PDRs is performed in increasing order
|
||||
* of their precedence value.
|
||||
*/
|
||||
qos_rule[0].precedence = 255; /* lowest precedence */
|
||||
qos_rule[0].flow.segregation = 0;
|
||||
qos_rule[0].flow.identifier = bearer->qfi;
|
||||
|
|
|
@ -261,8 +261,7 @@ void smf_gsm_state_released(ogs_fsm_t *s, smf_event_t *e)
|
|||
break;
|
||||
|
||||
default:
|
||||
ogs_error("[%s] Unknown event %s",
|
||||
sess->imsi_bcd, smf_event_get_name(e));
|
||||
ogs_error("Unknown event %s", smf_event_get_name(e));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -286,8 +285,7 @@ void smf_gsm_state_exception(ogs_fsm_t *s, smf_event_t *e)
|
|||
break;
|
||||
|
||||
default:
|
||||
ogs_error("[%s] Unknown event %s",
|
||||
sess->imsi_bcd, smf_event_get_name(e));
|
||||
ogs_error("Unknown event %s", smf_event_get_name(e));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,6 +46,12 @@ void smf_gx_handle_cca_initial_request(
|
|||
ogs_gtp_xact_t *gtp_xact)
|
||||
{
|
||||
int i;
|
||||
|
||||
smf_bearer_t *bearer = NULL;
|
||||
ogs_pfcp_pdr_t *pdr = NULL;
|
||||
ogs_pfcp_far_t *far = NULL;
|
||||
ogs_pfcp_qer_t *qer = NULL;
|
||||
|
||||
ogs_assert(sess);
|
||||
ogs_assert(gx_message);
|
||||
ogs_assert(gtp_xact);
|
||||
|
@ -63,12 +69,55 @@ void smf_gx_handle_cca_initial_request(
|
|||
return;
|
||||
}
|
||||
|
||||
if (sess->pdn.ambr.downlink || sess->pdn.ambr.uplink) {
|
||||
smf_bearer_t *bearer = smf_default_bearer_in_sess(sess);
|
||||
ogs_pfcp_pdr_t *pdr = NULL;
|
||||
ogs_pfcp_qer_t *qer = NULL;
|
||||
ogs_assert(bearer);
|
||||
sess->num_of_pcc_rule = gx_message->num_of_pcc_rule;
|
||||
for (i = 0; i < gx_message->num_of_pcc_rule; i++)
|
||||
OGS_STORE_PCC_RULE(&sess->pcc_rule[i], &gx_message->pcc_rule[i]);
|
||||
|
||||
/* APN-AMBR
|
||||
* if PCRF changes APN-AMBR, this should be included. */
|
||||
sess->gtp_5gc.create_session_response_apn_ambr = false;
|
||||
if ((gx_message->pdn.ambr.uplink &&
|
||||
(sess->pdn.ambr.uplink / 1000) !=
|
||||
(gx_message->pdn.ambr.uplink / 1000)) ||
|
||||
(gx_message->pdn.ambr.downlink &&
|
||||
(sess->pdn.ambr.downlink / 1000) !=
|
||||
(gx_message->pdn.ambr.downlink / 1000))) {
|
||||
|
||||
sess->pdn.ambr.downlink = gx_message->pdn.ambr.downlink;
|
||||
sess->pdn.ambr.uplink = gx_message->pdn.ambr.uplink;
|
||||
|
||||
sess->gtp_5gc.create_session_response_apn_ambr = true;
|
||||
}
|
||||
|
||||
/* Bearer QoS
|
||||
* if PCRF changes Bearer QoS, this should be included. */
|
||||
sess->gtp_5gc.create_session_response_bearer_qos = false;
|
||||
if ((gx_message->pdn.qos.qci &&
|
||||
sess->pdn.qos.qci != gx_message->pdn.qos.qci) ||
|
||||
(gx_message->pdn.qos.arp.priority_level &&
|
||||
sess->pdn.qos.arp.priority_level !=
|
||||
gx_message->pdn.qos.arp.priority_level) ||
|
||||
sess->pdn.qos.arp.pre_emption_capability !=
|
||||
gx_message->pdn.qos.arp.pre_emption_capability ||
|
||||
sess->pdn.qos.arp.pre_emption_vulnerability !=
|
||||
gx_message->pdn.qos.arp.pre_emption_vulnerability) {
|
||||
|
||||
sess->pdn.qos.qci = gx_message->pdn.qos.qci;
|
||||
sess->pdn.qos.arp.priority_level =
|
||||
gx_message->pdn.qos.arp.priority_level;
|
||||
sess->pdn.qos.arp.pre_emption_capability =
|
||||
gx_message->pdn.qos.arp.pre_emption_capability;
|
||||
sess->pdn.qos.arp.pre_emption_vulnerability =
|
||||
gx_message->pdn.qos.arp.pre_emption_vulnerability;
|
||||
|
||||
sess->gtp_5gc.create_session_response_bearer_qos = true;
|
||||
}
|
||||
|
||||
bearer = smf_default_bearer_in_sess(sess);
|
||||
ogs_assert(bearer);
|
||||
|
||||
/* Setup QER */
|
||||
if (sess->pdn.ambr.downlink || sess->pdn.ambr.uplink) {
|
||||
/* Only 1 QER is used per bearer */
|
||||
qer = ogs_list_first(&bearer->pfcp.qer_list);
|
||||
if (!qer) {
|
||||
|
@ -79,14 +128,35 @@ void smf_gx_handle_cca_initial_request(
|
|||
|
||||
qer->mbr.uplink = sess->pdn.ambr.uplink;
|
||||
qer->mbr.downlink = sess->pdn.ambr.downlink;
|
||||
|
||||
ogs_list_for_each(&bearer->pfcp.pdr_list, pdr)
|
||||
ogs_pfcp_pdr_associate_qer(pdr, qer);
|
||||
}
|
||||
|
||||
sess->num_of_pcc_rule = gx_message->num_of_pcc_rule;
|
||||
for (i = 0; i < gx_message->num_of_pcc_rule; i++)
|
||||
OGS_STORE_PCC_RULE(&sess->pcc_rule[i], &gx_message->pcc_rule[i]);
|
||||
/* Setup FAR */
|
||||
ogs_list_for_each(&bearer->pfcp.far_list, far) {
|
||||
|
||||
/* Set Outer Header Creation to the Default DL FAR */
|
||||
if (far->dst_if == OGS_PFCP_INTERFACE_ACCESS) {
|
||||
ogs_pfcp_ip_to_outer_header_creation(&bearer->sgw_s5u_ip,
|
||||
&far->outer_header_creation, &far->outer_header_creation_len);
|
||||
far->outer_header_creation.teid = bearer->sgw_s5u_teid;
|
||||
}
|
||||
}
|
||||
|
||||
/* Setup PDR */
|
||||
ogs_list_for_each(&bearer->pfcp.pdr_list, pdr) {
|
||||
|
||||
/* Set UE IP Address to the Default DL PDR */
|
||||
if (pdr->src_if == OGS_PFCP_INTERFACE_CORE) {
|
||||
ogs_pfcp_paa_to_ue_ip_addr(&sess->pdn.paa,
|
||||
&pdr->ue_ip_addr, &pdr->ue_ip_addr_len);
|
||||
pdr->ue_ip_addr.sd = OGS_PFCP_UE_IP_DST;
|
||||
}
|
||||
|
||||
/* Default PDRs is set to lowest precedence(highest precedence value) */
|
||||
pdr->precedence = 0xffffffff;
|
||||
|
||||
if (qer)
|
||||
ogs_pfcp_pdr_associate_qer(pdr, qer);
|
||||
}
|
||||
|
||||
smf_epc_pfcp_send_session_establishment_request(sess, gtp_xact);
|
||||
}
|
||||
|
|
|
@ -87,7 +87,6 @@ ogs_pkbuf_t *smf_n4_build_association_setup_response(uint8_t type,
|
|||
}
|
||||
|
||||
static struct {
|
||||
ogs_pfcp_ue_ip_addr_t addr;
|
||||
ogs_pfcp_outer_header_removal_t outer_header_removal;
|
||||
ogs_pfcp_f_teid_t f_teid;
|
||||
char dnn[OGS_MAX_DNN_LEN];
|
||||
|
@ -164,25 +163,21 @@ static void build_create_pdr(
|
|||
}
|
||||
|
||||
if (pdr->src_if == OGS_PFCP_INTERFACE_CORE) { /* Downlink */
|
||||
if (smf_bearer_is_default(bearer)) { /* Default Bearer */
|
||||
ogs_pfcp_paa_to_ue_ip_addr(&sess->pdn.paa,
|
||||
&pdrbuf[i].addr, &len);
|
||||
pdrbuf[i].addr.sd = OGS_PFCP_UE_IP_DST;
|
||||
|
||||
if (pdr->ue_ip_addr_len) {
|
||||
message->pdi.ue_ip_address.presence = 1;
|
||||
message->pdi.ue_ip_address.data = &pdrbuf[i].addr;
|
||||
message->pdi.ue_ip_address.len = len;
|
||||
message->pdi.ue_ip_address.data = &pdr->ue_ip_addr;
|
||||
message->pdi.ue_ip_address.len = pdr->ue_ip_addr_len;
|
||||
}
|
||||
|
||||
} else if (pdr->src_if == OGS_PFCP_INTERFACE_ACCESS) { /* Uplink */
|
||||
ogs_pfcp_sockaddr_to_f_teid(
|
||||
bearer->upf_addr, bearer->upf_addr6,
|
||||
&pdrbuf[i].f_teid, &len);
|
||||
pdrbuf[i].f_teid.teid = htobe32(bearer->upf_n3_teid);
|
||||
if (pdr->f_teid_len) {
|
||||
memcpy(&pdrbuf[i].f_teid, &pdr->f_teid, pdr->f_teid_len);
|
||||
pdrbuf[i].f_teid.teid = htobe32(pdr->f_teid.teid);
|
||||
|
||||
message->pdi.local_f_teid.presence = 1;
|
||||
message->pdi.local_f_teid.data = &pdrbuf[i].f_teid;
|
||||
message->pdi.local_f_teid.len = len;
|
||||
message->pdi.local_f_teid.presence = 1;
|
||||
message->pdi.local_f_teid.data = &pdrbuf[i].f_teid;
|
||||
message->pdi.local_f_teid.len = pdr->f_teid_len;
|
||||
}
|
||||
|
||||
if (sess->pdn.paa.pdn_type == OGS_GTP_PDN_TYPE_IPV4) {
|
||||
pdrbuf[i].outer_header_removal.description =
|
||||
|
@ -226,15 +221,11 @@ static void build_create_far(
|
|||
ogs_pfcp_tlv_create_far_t *message, int i, ogs_pfcp_far_t *far)
|
||||
{
|
||||
ogs_pfcp_sess_t *pfcp_sess = NULL;
|
||||
smf_bearer_t *bearer = NULL;
|
||||
int len;
|
||||
|
||||
ogs_assert(message);
|
||||
ogs_assert(far);
|
||||
pfcp_sess = far->sess;
|
||||
ogs_assert(pfcp_sess);
|
||||
bearer = SMF_BEARER(pfcp_sess);
|
||||
ogs_assert(bearer);
|
||||
|
||||
message->presence = 1;
|
||||
message->far_id.presence = 1;
|
||||
|
@ -249,16 +240,17 @@ static void build_create_far(
|
|||
far->dst_if;
|
||||
|
||||
if (far->dst_if == OGS_PFCP_INTERFACE_ACCESS) { /* Downlink */
|
||||
if (bearer->gnb_n3_ip.ipv4 || bearer->gnb_n3_ip.ipv6) {
|
||||
ogs_pfcp_ip_to_outer_header_creation(&bearer->gnb_n3_ip,
|
||||
&farbuf[i].outer_header_creation, &len);
|
||||
if (far->outer_header_creation_len) {
|
||||
memcpy(&farbuf[i].outer_header_creation,
|
||||
&far->outer_header_creation, far->outer_header_creation_len);
|
||||
farbuf[i].outer_header_creation.teid =
|
||||
htobe32(bearer->gnb_n3_teid);
|
||||
htobe32(far->outer_header_creation.teid);
|
||||
|
||||
message->forwarding_parameters.outer_header_creation.presence = 1;
|
||||
message->forwarding_parameters.outer_header_creation.data =
|
||||
&farbuf[i].outer_header_creation;
|
||||
message->forwarding_parameters.outer_header_creation.len = len;
|
||||
message->forwarding_parameters.outer_header_creation.len =
|
||||
far->outer_header_creation_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -339,19 +331,14 @@ static void build_update_far(smf_sess_t *sess,
|
|||
ogs_pfcp_tlv_update_far_t *message, int i, ogs_pfcp_far_t *far)
|
||||
{
|
||||
ogs_pfcp_sess_t *pfcp_sess = NULL;
|
||||
smf_bearer_t *bearer = NULL;
|
||||
int len;
|
||||
|
||||
ogs_assert(message);
|
||||
ogs_assert(far);
|
||||
pfcp_sess = far->sess;
|
||||
ogs_assert(pfcp_sess);
|
||||
bearer = SMF_BEARER(pfcp_sess);
|
||||
ogs_assert(bearer);
|
||||
ogs_assert(sess);
|
||||
|
||||
ogs_assert(far->dst_if == OGS_PFCP_INTERFACE_ACCESS);
|
||||
ogs_assert(bearer->gnb_n3_ip.ipv4 || bearer->gnb_n3_ip.ipv6);
|
||||
ogs_assert(far->outer_header_creation_len);
|
||||
|
||||
message->presence = 1;
|
||||
message->far_id.presence = 1;
|
||||
|
@ -359,10 +346,10 @@ static void build_update_far(smf_sess_t *sess,
|
|||
|
||||
if (sess->ueUpCnxState == OpenAPI_up_cnx_state_ACTIVATED) {
|
||||
if (sess->pfcp_5gc_modify.outer_header_creation_update) {
|
||||
ogs_pfcp_ip_to_outer_header_creation(&bearer->gnb_n3_ip,
|
||||
&farbuf[i].outer_header_creation, &len);
|
||||
memcpy(&farbuf[i].outer_header_creation,
|
||||
&far->outer_header_creation, far->outer_header_creation_len);
|
||||
farbuf[i].outer_header_creation.teid =
|
||||
htobe32(bearer->gnb_n3_teid);
|
||||
htobe32(far->outer_header_creation.teid);
|
||||
|
||||
message->update_forwarding_parameters.presence = 1;
|
||||
message->update_forwarding_parameters.
|
||||
|
@ -370,7 +357,7 @@ static void build_update_far(smf_sess_t *sess,
|
|||
message->update_forwarding_parameters.
|
||||
outer_header_creation.data = &farbuf[i].outer_header_creation;
|
||||
message->update_forwarding_parameters.
|
||||
outer_header_creation.len = len;
|
||||
outer_header_creation.len = far->outer_header_creation_len;
|
||||
}
|
||||
|
||||
if (far->apply_action != OGS_PFCP_APPLY_ACTION_FORW) {
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
ogs_pkbuf_t *ngap_build_pdu_session_resource_setup_request_transfer(
|
||||
smf_sess_t *sess)
|
||||
{
|
||||
smf_bearer_t *bearer = NULL;
|
||||
smf_bearer_t *qos_flow = NULL;
|
||||
ogs_ip_t upf_n3_ip;
|
||||
|
||||
NGAP_PDUSessionResourceSetupRequestTransfer_t message;
|
||||
|
@ -41,8 +41,8 @@ ogs_pkbuf_t *ngap_build_pdu_session_resource_setup_request_transfer(
|
|||
NGAP_AllocationAndRetentionPriority_t *allocationAndRetentionPriority;
|
||||
|
||||
ogs_assert(sess);
|
||||
bearer = smf_default_bearer_in_sess(sess);
|
||||
ogs_assert(bearer);
|
||||
qos_flow = smf_default_bearer_in_sess(sess);
|
||||
ogs_assert(qos_flow);
|
||||
|
||||
ogs_debug("PDUSessionResourceSetupRequestTransfer");
|
||||
memset(&message, 0, sizeof(NGAP_PDUSessionResourceSetupRequestTransfer_t));
|
||||
|
@ -79,9 +79,9 @@ ogs_pkbuf_t *ngap_build_pdu_session_resource_setup_request_transfer(
|
|||
NGAP_UPTransportLayerInformation_PR_gTPTunnel;
|
||||
UPTransportLayerInformation->choice.gTPTunnel = gTPTunnel;
|
||||
|
||||
ogs_sockaddr_to_ip(bearer->upf_addr, bearer->upf_addr6, &upf_n3_ip);
|
||||
ogs_sockaddr_to_ip(sess->upf_n3_addr, sess->upf_n3_addr6, &upf_n3_ip);
|
||||
ogs_asn_ip_to_BIT_STRING(&upf_n3_ip, &gTPTunnel->transportLayerAddress);
|
||||
ogs_asn_uint32_to_OCTET_STRING(bearer->upf_n3_teid, &gTPTunnel->gTP_TEID);
|
||||
ogs_asn_uint32_to_OCTET_STRING(sess->upf_n3_teid, &gTPTunnel->gTP_TEID);
|
||||
|
||||
ie = CALLOC(1, sizeof(NGAP_PDUSessionResourceSetupRequestTransferIEs_t));
|
||||
ASN_SEQUENCE_ADD(&message.protocolIEs, ie);
|
||||
|
@ -132,7 +132,7 @@ ogs_pkbuf_t *ngap_build_pdu_session_resource_setup_request_transfer(
|
|||
qosCharacteristics->choice.nonDynamic5QI = nonDynamic5QI;
|
||||
qosCharacteristics->present = NGAP_QosCharacteristics_PR_nonDynamic5QI;
|
||||
|
||||
*qosFlowIdentifier = bearer->qfi;
|
||||
*qosFlowIdentifier = qos_flow->qfi;
|
||||
|
||||
nonDynamic5QI->fiveQI = sess->pdn.qos.qci;
|
||||
|
||||
|
|
|
@ -26,11 +26,11 @@ int ngap_handle_pdu_session_resource_setup_response_transfer(
|
|||
{
|
||||
ogs_sbi_session_t *session = NULL;
|
||||
smf_ue_t *smf_ue = NULL;
|
||||
smf_bearer_t *bearer = NULL;
|
||||
smf_bearer_t *qos_flow = NULL;
|
||||
int rv, i;
|
||||
|
||||
uint32_t gnb_n3_teid;
|
||||
ogs_ip_t gnb_n3_ip;
|
||||
uint32_t upf_n3_teid;
|
||||
ogs_ip_t upf_n3_ip;
|
||||
|
||||
ogs_pfcp_far_t *far = NULL;
|
||||
bool far_update = false;
|
||||
|
@ -48,8 +48,6 @@ int ngap_handle_pdu_session_resource_setup_response_transfer(
|
|||
ogs_assert(sess);
|
||||
session = sess->sbi.session;
|
||||
ogs_assert(session);
|
||||
bearer = smf_default_bearer_in_sess(sess);
|
||||
ogs_assert(bearer);
|
||||
smf_ue = sess->smf_ue;
|
||||
ogs_assert(smf_ue);
|
||||
|
||||
|
@ -90,10 +88,19 @@ int ngap_handle_pdu_session_resource_setup_response_transfer(
|
|||
associatedQosFlowItem = (NGAP_AssociatedQosFlowItem_t *)
|
||||
associatedQosFlowList->list.array[i];
|
||||
if (associatedQosFlowItem) {
|
||||
/* TODO : associatedQosFlowItem->qosFlowIdentifier */
|
||||
qos_flow = smf_qos_flow_find_by_qfi(sess,
|
||||
associatedQosFlowItem->qosFlowIdentifier);
|
||||
}
|
||||
}
|
||||
|
||||
if (!qos_flow) {
|
||||
ogs_error("[%s:%d] No QoS flow", smf_ue->supi, sess->psi);
|
||||
smf_sbi_send_sm_context_update_error(session,
|
||||
OGS_SBI_HTTP_STATUS_BAD_REQUEST,
|
||||
"No QoS flow", smf_ue->supi, NULL, NULL);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
gTPTunnel = uPTransportLayerInformation->choice.gTPTunnel;
|
||||
if (!gTPTunnel) {
|
||||
ogs_error("[%s:%d] No GTPTunnel", smf_ue->supi, sess->psi);
|
||||
|
@ -104,20 +111,20 @@ int ngap_handle_pdu_session_resource_setup_response_transfer(
|
|||
}
|
||||
|
||||
ogs_asn_BIT_STRING_to_ip(
|
||||
&gTPTunnel->transportLayerAddress, &gnb_n3_ip);
|
||||
ogs_asn_OCTET_STRING_to_uint32(&gTPTunnel->gTP_TEID, &gnb_n3_teid);
|
||||
&gTPTunnel->transportLayerAddress, &upf_n3_ip);
|
||||
ogs_asn_OCTET_STRING_to_uint32(&gTPTunnel->gTP_TEID, &upf_n3_teid);
|
||||
|
||||
if (memcmp(&bearer->gnb_n3_ip, &gnb_n3_ip,
|
||||
sizeof(bearer->gnb_n3_ip)) != 0 ||
|
||||
bearer->gnb_n3_teid != gnb_n3_teid)
|
||||
if (memcmp(&sess->gnb_n3_ip, &upf_n3_ip, sizeof(sess->gnb_n3_ip)) != 0 ||
|
||||
sess->gnb_n3_teid != upf_n3_teid)
|
||||
sess->pfcp_5gc_modify.outer_header_creation_update = true;
|
||||
else
|
||||
sess->pfcp_5gc_modify.outer_header_creation_update = false;
|
||||
|
||||
memcpy(&bearer->gnb_n3_ip, &gnb_n3_ip, sizeof(bearer->gnb_n3_ip));
|
||||
bearer->gnb_n3_teid = gnb_n3_teid;
|
||||
memcpy(&sess->gnb_n3_ip, &upf_n3_ip, sizeof(sess->gnb_n3_ip));
|
||||
sess->gnb_n3_teid = upf_n3_teid;
|
||||
|
||||
ogs_list_for_each(&bearer->pfcp.far_list, far) {
|
||||
/* Need to Update? */
|
||||
ogs_list_for_each(&qos_flow->pfcp.far_list, far) {
|
||||
if (far->dst_if == OGS_PFCP_INTERFACE_ACCESS) {
|
||||
if (sess->ueUpCnxState == OpenAPI_up_cnx_state_ACTIVATED) {
|
||||
if (far->apply_action != OGS_PFCP_APPLY_ACTION_FORW) {
|
||||
|
@ -129,6 +136,15 @@ int ngap_handle_pdu_session_resource_setup_response_transfer(
|
|||
}
|
||||
}
|
||||
|
||||
/* Setup FAR */
|
||||
ogs_list_for_each(&qos_flow->pfcp.far_list, far) {
|
||||
if (far->dst_if == OGS_PFCP_INTERFACE_ACCESS) {
|
||||
ogs_pfcp_ip_to_outer_header_creation(&sess->gnb_n3_ip,
|
||||
&far->outer_header_creation, &far->outer_header_creation_len);
|
||||
far->outer_header_creation.teid = sess->gnb_n3_teid;
|
||||
}
|
||||
}
|
||||
|
||||
if (far_update || sess->pfcp_5gc_modify.outer_header_creation_update)
|
||||
smf_5gc_pfcp_send_session_modification_request(sess);
|
||||
else
|
||||
|
|
|
@ -26,9 +26,9 @@ bool smf_nudm_sdm_handle_get(smf_sess_t *sess, ogs_sbi_message_t *recvmsg)
|
|||
char buf2[OGS_ADDRSTRLEN];
|
||||
|
||||
smf_ue_t *smf_ue = NULL;
|
||||
ogs_pfcp_subnet_t *subnet6 = NULL;
|
||||
|
||||
smf_bearer_t *bearer = NULL;
|
||||
smf_bearer_t *qos_flow = NULL;
|
||||
ogs_pfcp_gtpu_resource_t *resource = NULL;
|
||||
ogs_pfcp_pdr_t *pdr = NULL;
|
||||
ogs_pfcp_qer_t *qer = NULL;
|
||||
|
||||
|
@ -225,6 +225,59 @@ bool smf_nudm_sdm_handle_get(smf_sess_t *sess, ogs_sbi_message_t *recvmsg)
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Select UPF based on UE Location Information */
|
||||
smf_sess_select_upf(sess);
|
||||
|
||||
/* Check if selected UPF is associated with SMF */
|
||||
ogs_assert(sess->pfcp_node);
|
||||
if (!OGS_FSM_CHECK(&sess->pfcp_node->sm, smf_pfcp_state_associated)) {
|
||||
ogs_error("[%s] No associated UPF", smf_ue->supi);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Setup GTP-U Tunnel */
|
||||
resource = ogs_pfcp_gtpu_resource_find(
|
||||
&sess->pfcp_node->gtpu_resource_list,
|
||||
sess->pdn.dnn, OGS_PFCP_INTERFACE_ACCESS);
|
||||
if (resource) {
|
||||
ogs_pfcp_user_plane_ip_resource_info_to_sockaddr(&resource->info,
|
||||
&sess->upf_n3_addr, &sess->upf_n3_addr6);
|
||||
ogs_assert(sess->upf_n3_addr || sess->upf_n3_addr6);
|
||||
if (resource->info.teidri)
|
||||
sess->upf_n3_teid = UPF_GTPU_INDEX_TO_TEID(
|
||||
sess->index, resource->info.teidri,
|
||||
resource->info.teid_range);
|
||||
else
|
||||
sess->upf_n3_teid = sess->index;
|
||||
} else {
|
||||
if (sess->pfcp_node->addr.ogs_sa_family == AF_INET)
|
||||
ogs_copyaddrinfo(&sess->upf_n3_addr, &sess->pfcp_node->addr);
|
||||
else if (sess->pfcp_node->addr.ogs_sa_family == AF_INET6)
|
||||
ogs_copyaddrinfo(&sess->upf_n3_addr6, &sess->pfcp_node->addr);
|
||||
else
|
||||
ogs_assert_if_reached();
|
||||
ogs_assert(sess->upf_n3_addr || sess->upf_n3_addr6);
|
||||
|
||||
sess->upf_n3_teid = sess->index;
|
||||
}
|
||||
|
||||
ogs_debug("UPF TEID:[0x%x], IPv4:[%s] IPv6:[%s]",
|
||||
sess->upf_n3_teid,
|
||||
sess->upf_n3_addr ? OGS_ADDR(sess->upf_n3_addr, buf1) : "",
|
||||
sess->upf_n3_addr6 ? OGS_ADDR(sess->upf_n3_addr6, buf2) : "");
|
||||
|
||||
/* UE IP Address */
|
||||
smf_sess_set_ue_ip(sess);
|
||||
|
||||
ogs_info("UE SUPI:[%s] DNN:[%s] IPv4:[%s] IPv6:[%s]",
|
||||
smf_ue->supi, sess->pdn.dnn,
|
||||
sess->ipv4 ? OGS_INET_NTOP(&sess->ipv4->addr, buf1) : "",
|
||||
sess->ipv6 ? OGS_INET6_NTOP(&sess->ipv6->addr, buf2) : "");
|
||||
|
||||
/*********************************************************************
|
||||
* Send HTTP_STATUS_CREATED(/nsmf-pdusession/v1/sm-context) to the AMF
|
||||
*********************************************************************/
|
||||
|
||||
memset(&SmContextCreatedData, 0, sizeof(SmContextCreatedData));
|
||||
|
||||
memset(&sendmsg, 0, sizeof(sendmsg));
|
||||
|
@ -246,84 +299,44 @@ bool smf_nudm_sdm_handle_get(smf_sess_t *sess, ogs_sbi_message_t *recvmsg)
|
|||
|
||||
ogs_free(sendmsg.http.location);
|
||||
|
||||
sess->pdn.paa.pdn_type = sess->pdn.pdn_type;
|
||||
ogs_assert(sess->pdn.pdn_type);
|
||||
|
||||
if (sess->ipv4) {
|
||||
ogs_hash_set(smf_self()->ipv4_hash,
|
||||
sess->ipv4->addr, OGS_IPV4_LEN, NULL);
|
||||
ogs_pfcp_ue_ip_free(sess->ipv4);
|
||||
}
|
||||
if (sess->ipv6) {
|
||||
ogs_hash_set(smf_self()->ipv6_hash,
|
||||
sess->ipv6->addr, OGS_IPV6_LEN, NULL);
|
||||
ogs_pfcp_ue_ip_free(sess->ipv6);
|
||||
/*********************************************************************
|
||||
* Send PFCP Session Establiashment Request to the UPF
|
||||
*********************************************************************/
|
||||
|
||||
/* Remove all previous QoS flow */
|
||||
smf_bearer_remove_all(sess);
|
||||
|
||||
/* Setup Default QoS flow */
|
||||
qos_flow = smf_qos_flow_add(sess);
|
||||
ogs_assert(qos_flow);
|
||||
|
||||
/* Setup QER */
|
||||
ogs_list_for_each(&qos_flow->pfcp.qer_list, qer) {
|
||||
qer->mbr.uplink = sess->pdn.ambr.uplink;
|
||||
qer->mbr.downlink = sess->pdn.ambr.downlink;
|
||||
}
|
||||
|
||||
if (sess->pdn.pdn_type == OGS_PDU_SESSION_TYPE_IPV4) {
|
||||
sess->ipv4 = ogs_pfcp_ue_ip_alloc(
|
||||
AF_INET, sess->pdn.apn, (uint8_t *)&sess->pdn.ue_ip.addr);
|
||||
ogs_assert(sess->ipv4);
|
||||
sess->pdn.paa.addr = sess->ipv4->addr[0];
|
||||
ogs_hash_set(smf_self()->ipv4_hash,
|
||||
sess->ipv4->addr, OGS_IPV4_LEN, sess);
|
||||
} else if (sess->pdn.pdn_type == OGS_PDU_SESSION_TYPE_IPV6) {
|
||||
sess->ipv6 = ogs_pfcp_ue_ip_alloc(
|
||||
AF_INET6, sess->pdn.apn, sess->pdn.ue_ip.addr6);
|
||||
ogs_assert(sess->ipv6);
|
||||
/* Setup PDR */
|
||||
ogs_list_for_each(&qos_flow->pfcp.pdr_list, pdr) {
|
||||
|
||||
subnet6 = sess->ipv6->subnet;
|
||||
ogs_assert(subnet6);
|
||||
/* Set UE IP Address to the Default DL PDR */
|
||||
if (pdr->src_if == OGS_PFCP_INTERFACE_CORE) {
|
||||
ogs_pfcp_paa_to_ue_ip_addr(&sess->pdn.paa,
|
||||
&pdr->ue_ip_addr, &pdr->ue_ip_addr_len);
|
||||
pdr->ue_ip_addr.sd = OGS_PFCP_UE_IP_DST;
|
||||
|
||||
sess->pdn.paa.len = subnet6->prefixlen;
|
||||
memcpy(sess->pdn.paa.addr6, sess->ipv6->addr, OGS_IPV6_LEN);
|
||||
ogs_hash_set(smf_self()->ipv6_hash,
|
||||
sess->ipv6->addr, OGS_IPV6_LEN, sess);
|
||||
} else if (sess->pdn.pdn_type == OGS_PDU_SESSION_TYPE_IPV4V6) {
|
||||
sess->ipv4 = ogs_pfcp_ue_ip_alloc(
|
||||
AF_INET, sess->pdn.apn, (uint8_t *)&sess->pdn.ue_ip.addr);
|
||||
ogs_assert(sess->ipv4);
|
||||
sess->ipv6 = ogs_pfcp_ue_ip_alloc(
|
||||
AF_INET6, sess->pdn.apn, sess->pdn.ue_ip.addr6);
|
||||
ogs_assert(sess->ipv6);
|
||||
/* Set UPF-N3 TEID & ADDR to the Default UL PDR */
|
||||
} else if (pdr->src_if == OGS_PFCP_INTERFACE_ACCESS) {
|
||||
ogs_pfcp_sockaddr_to_f_teid(sess->upf_n3_addr, sess->upf_n3_addr6,
|
||||
&pdr->f_teid, &pdr->f_teid_len);
|
||||
pdr->f_teid.teid = sess->upf_n3_teid;
|
||||
}
|
||||
|
||||
subnet6 = sess->ipv6->subnet;
|
||||
ogs_assert(subnet6);
|
||||
|
||||
sess->pdn.paa.both.addr = sess->ipv4->addr[0];
|
||||
sess->pdn.paa.both.len = subnet6->prefixlen;
|
||||
memcpy(sess->pdn.paa.both.addr6, sess->ipv6->addr, OGS_IPV6_LEN);
|
||||
ogs_hash_set(smf_self()->ipv4_hash,
|
||||
sess->ipv4->addr, OGS_IPV4_LEN, sess);
|
||||
ogs_hash_set(smf_self()->ipv6_hash,
|
||||
sess->ipv6->addr, OGS_IPV6_LEN, sess);
|
||||
} else
|
||||
ogs_assert_if_reached();
|
||||
|
||||
ogs_info("UE SUPI:[%s] DNN:[%s] IPv4:[%s] IPv6:[%s]",
|
||||
smf_ue->supi, sess->pdn.apn,
|
||||
sess->ipv4 ? OGS_INET_NTOP(&sess->ipv4->addr, buf1) : "",
|
||||
sess->ipv6 ? OGS_INET6_NTOP(&sess->ipv6->addr, buf2) : "");
|
||||
|
||||
bearer = smf_default_bearer_in_sess(sess);
|
||||
ogs_assert(bearer);
|
||||
|
||||
/* Only 1 QER is used per bearer */
|
||||
qer = ogs_list_first(&bearer->pfcp.qer_list);
|
||||
if (!qer) {
|
||||
qer = ogs_pfcp_qer_add(&bearer->pfcp);
|
||||
ogs_assert(qer);
|
||||
qer->id = OGS_NEXT_ID(sess->qer_id, 1, OGS_MAX_NUM_OF_QER+1);
|
||||
/* Default PDRs is set to lowest precedence(highest precedence value) */
|
||||
pdr->precedence = 0xffffffff;
|
||||
}
|
||||
|
||||
qer->mbr.uplink = sess->pdn.ambr.uplink;
|
||||
qer->mbr.downlink = sess->pdn.ambr.downlink;
|
||||
|
||||
qer->qfi = bearer->qfi;
|
||||
|
||||
ogs_list_for_each(&bearer->pfcp.pdr_list, pdr)
|
||||
ogs_pfcp_pdr_associate_qer(pdr, qer);
|
||||
|
||||
smf_5gc_pfcp_send_session_establishment_request(sess);
|
||||
|
||||
return true;
|
||||
|
|
|
@ -32,7 +32,10 @@ ogs_pkbuf_t *smf_s5c_build_create_session_response(
|
|||
ogs_gtp_create_session_response_t *rsp = NULL;
|
||||
|
||||
ogs_gtp_cause_t cause;
|
||||
ogs_gtp_f_teid_t smf_s5c_teid, upf_n3_teid;
|
||||
ogs_gtp_f_teid_t smf_s5c_teid, upf_s5u_teid;
|
||||
ogs_gtp_ambr_t ambr;
|
||||
ogs_gtp_bearer_qos_t bearer_qos;
|
||||
char bearer_qos_buf[GTP_BEARER_QOS_LEN];
|
||||
int len;
|
||||
uint8_t pco_buf[OGS_MAX_PCO_LEN];
|
||||
int16_t pco_len;
|
||||
|
@ -45,8 +48,8 @@ ogs_pkbuf_t *smf_s5c_build_create_session_response(
|
|||
|
||||
ogs_debug(" SGW_S5C_TEID[0x%x] SMF_N4_TEID[0x%x]",
|
||||
sess->sgw_s5c_teid, sess->smf_n4_teid);
|
||||
ogs_debug(" gNB_N3_TEID[0x%x] UPF_N3_TEID[0x%x]",
|
||||
bearer->gnb_n3_teid, bearer->upf_n3_teid);
|
||||
ogs_debug(" SGW_S5U_TEID[0x%x] UPF_S5U_TEID[0x%x]",
|
||||
bearer->sgw_s5u_teid, bearer->upf_s5u_teid);
|
||||
|
||||
rsp = >p_message.create_session_response;
|
||||
memset(>p_message, 0, sizeof(ogs_gtp_message_t));
|
||||
|
@ -88,8 +91,16 @@ ogs_pkbuf_t *smf_s5c_build_create_session_response(
|
|||
rsp->apn_restriction.presence = 1;
|
||||
rsp->apn_restriction.u8 = OGS_GTP_APN_NO_RESTRICTION;
|
||||
|
||||
/* TODO : APN-AMBR
|
||||
/* APN-AMBR
|
||||
* if PCRF changes APN-AMBR, this should be included. */
|
||||
if (sess->gtp_5gc.create_session_response_apn_ambr == true) {
|
||||
memset(&ambr, 0, sizeof(ogs_gtp_ambr_t));
|
||||
ambr.uplink = htobe32(sess->pdn.ambr.uplink / 1000);
|
||||
ambr.downlink = htobe32(sess->pdn.ambr.downlink / 1000);
|
||||
rsp->aggregate_maximum_bit_rate.presence = 1;
|
||||
rsp->aggregate_maximum_bit_rate.data = &ambr;
|
||||
rsp->aggregate_maximum_bit_rate.len = sizeof(ambr);
|
||||
}
|
||||
|
||||
/* PCO */
|
||||
if (sess->gtp.ue_pco.presence &&
|
||||
|
@ -112,18 +123,31 @@ ogs_pkbuf_t *smf_s5c_build_create_session_response(
|
|||
rsp->bearer_contexts_created.cause.len = sizeof(cause);
|
||||
rsp->bearer_contexts_created.cause.data = &cause;
|
||||
|
||||
/* TODO : Bearer QoS
|
||||
/* Bearer QoS
|
||||
* if PCRF changes Bearer QoS, this should be included. */
|
||||
if (sess->gtp_5gc.create_session_response_bearer_qos == true) {
|
||||
memset(&bearer_qos, 0, sizeof(bearer_qos));
|
||||
bearer_qos.qci = sess->pdn.qos.qci;
|
||||
bearer_qos.priority_level = sess->pdn.qos.arp.priority_level;
|
||||
bearer_qos.pre_emption_capability =
|
||||
sess->pdn.qos.arp.pre_emption_capability;
|
||||
bearer_qos.pre_emption_vulnerability =
|
||||
sess->pdn.qos.arp.pre_emption_vulnerability;
|
||||
|
||||
rsp->bearer_contexts_created.bearer_level_qos.presence = 1;
|
||||
ogs_gtp_build_bearer_qos(&rsp->bearer_contexts_created.bearer_level_qos,
|
||||
&bearer_qos, bearer_qos_buf, GTP_BEARER_QOS_LEN);
|
||||
}
|
||||
|
||||
/* Data Plane(UL) : SMF-S5U */
|
||||
memset(&upf_n3_teid, 0, sizeof(ogs_gtp_f_teid_t));
|
||||
upf_n3_teid.interface_type = OGS_GTP_F_TEID_S5_S8_PGW_GTP_U;
|
||||
upf_n3_teid.teid = htobe32(bearer->upf_n3_teid);
|
||||
memset(&upf_s5u_teid, 0, sizeof(ogs_gtp_f_teid_t));
|
||||
upf_s5u_teid.interface_type = OGS_GTP_F_TEID_S5_S8_PGW_GTP_U;
|
||||
upf_s5u_teid.teid = htobe32(bearer->upf_s5u_teid);
|
||||
rv = ogs_gtp_sockaddr_to_f_teid(
|
||||
bearer->upf_addr, bearer->upf_addr6, &upf_n3_teid, &len);
|
||||
bearer->upf_s5u_addr, bearer->upf_s5u_addr6, &upf_s5u_teid, &len);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
rsp->bearer_contexts_created.s5_s8_u_sgw_f_teid.presence = 1;
|
||||
rsp->bearer_contexts_created.s5_s8_u_sgw_f_teid.data = &upf_n3_teid;
|
||||
rsp->bearer_contexts_created.s5_s8_u_sgw_f_teid.data = &upf_s5u_teid;
|
||||
rsp->bearer_contexts_created.s5_s8_u_sgw_f_teid.len = len;
|
||||
|
||||
gtp_message.h.type = type;
|
||||
|
@ -182,7 +206,7 @@ ogs_pkbuf_t *smf_s5c_build_create_bearer_request(
|
|||
ogs_gtp_message_t gtp_message;
|
||||
ogs_gtp_create_bearer_request_t *req = NULL;
|
||||
|
||||
ogs_gtp_f_teid_t upf_n3_teid;
|
||||
ogs_gtp_f_teid_t upf_s5u_teid;
|
||||
ogs_gtp_bearer_qos_t bearer_qos;
|
||||
char bearer_qos_buf[GTP_BEARER_QOS_LEN];
|
||||
int len;
|
||||
|
@ -211,14 +235,14 @@ ogs_pkbuf_t *smf_s5c_build_create_bearer_request(
|
|||
req->bearer_contexts.eps_bearer_id.u8 = bearer->ebi;
|
||||
|
||||
/* Data Plane(UL) : SMF_S5U */
|
||||
memset(&upf_n3_teid, 0, sizeof(ogs_gtp_f_teid_t));
|
||||
upf_n3_teid.interface_type = OGS_GTP_F_TEID_S5_S8_PGW_GTP_U;
|
||||
upf_n3_teid.teid = htobe32(bearer->upf_n3_teid);
|
||||
memset(&upf_s5u_teid, 0, sizeof(ogs_gtp_f_teid_t));
|
||||
upf_s5u_teid.interface_type = OGS_GTP_F_TEID_S5_S8_PGW_GTP_U;
|
||||
upf_s5u_teid.teid = htobe32(bearer->upf_s5u_teid);
|
||||
rv = ogs_gtp_sockaddr_to_f_teid(
|
||||
bearer->upf_addr, bearer->upf_addr6, &upf_n3_teid, &len);
|
||||
bearer->upf_s5u_addr, bearer->upf_s5u_addr6, &upf_s5u_teid, &len);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
req->bearer_contexts.s5_s8_u_sgw_f_teid.presence = 1;
|
||||
req->bearer_contexts.s5_s8_u_sgw_f_teid.data = &upf_n3_teid;
|
||||
req->bearer_contexts.s5_s8_u_sgw_f_teid.data = &upf_s5u_teid;
|
||||
req->bearer_contexts.s5_s8_u_sgw_f_teid.len = len;
|
||||
|
||||
/* Bearer QoS */
|
||||
|
|
|
@ -49,9 +49,18 @@ void smf_s5c_handle_create_session_request(
|
|||
smf_sess_t *sess, ogs_gtp_xact_t *xact,
|
||||
ogs_gtp_create_session_request_t *req)
|
||||
{
|
||||
char buf1[OGS_ADDRSTRLEN];
|
||||
char buf2[OGS_ADDRSTRLEN];
|
||||
|
||||
int rv;
|
||||
uint8_t cause_value = 0;
|
||||
ogs_gtp_f_teid_t *sgw_s5c_teid, *gnb_n3_teid;
|
||||
|
||||
char apn[OGS_MAX_APN_LEN];
|
||||
ogs_gtp_uli_t uli;
|
||||
|
||||
smf_ue_t *smf_ue = NULL;
|
||||
|
||||
ogs_gtp_f_teid_t *sgw_s5c_teid, *sgw_s5u_teid;
|
||||
smf_bearer_t *bearer = NULL;
|
||||
ogs_gtp_bearer_qos_t bearer_qos;
|
||||
ogs_gtp_ambr_t *ambr = NULL;
|
||||
|
@ -64,12 +73,8 @@ void smf_s5c_handle_create_session_request(
|
|||
|
||||
cause_value = OGS_GTP_CAUSE_REQUEST_ACCEPTED;
|
||||
|
||||
if (sess) {
|
||||
bearer = smf_default_bearer_in_sess(sess);
|
||||
ogs_assert(bearer);
|
||||
}
|
||||
if (!bearer) {
|
||||
ogs_warn("No Context");
|
||||
if (!sess) {
|
||||
ogs_error("No Context");
|
||||
cause_value = OGS_GTP_CAUSE_CONTEXT_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
@ -85,6 +90,10 @@ void smf_s5c_handle_create_session_request(
|
|||
ogs_error("No Bearer");
|
||||
cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING;
|
||||
}
|
||||
if (req->bearer_contexts_to_be_created.eps_bearer_id.presence == 0) {
|
||||
ogs_error("No EPS Bearer ID");
|
||||
cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING;
|
||||
}
|
||||
if (req->bearer_contexts_to_be_created.bearer_level_qos.presence == 0) {
|
||||
ogs_error("No EPS Bearer QoS");
|
||||
cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING;
|
||||
|
@ -93,6 +102,18 @@ void smf_s5c_handle_create_session_request(
|
|||
ogs_error("No TEID");
|
||||
cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING;
|
||||
}
|
||||
if (req->pdn_type.presence == 0) {
|
||||
ogs_error("No PDN Type");
|
||||
cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING;
|
||||
}
|
||||
if (req->pdn_address_allocation.presence == 0) {
|
||||
ogs_error("No PAA");
|
||||
cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING;
|
||||
}
|
||||
if (req->user_location_information.presence == 0) {
|
||||
ogs_error("No UE Location Information");
|
||||
cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING;
|
||||
}
|
||||
|
||||
if (!ogs_diam_peer_connected()) {
|
||||
ogs_error("No Diameter Peer");
|
||||
|
@ -104,28 +125,67 @@ void smf_s5c_handle_create_session_request(
|
|||
OGS_GTP_CREATE_SESSION_RESPONSE_TYPE, cause_value);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set IMSI */
|
||||
sess->imsi_len = req->imsi.len;
|
||||
memcpy(sess->imsi, req->imsi.data, sess->imsi_len);
|
||||
ogs_buffer_to_bcd(sess->imsi, sess->imsi_len, sess->imsi_bcd);
|
||||
|
||||
ogs_assert(sess);
|
||||
smf_ue = sess->smf_ue;
|
||||
ogs_assert(smf_ue);
|
||||
|
||||
/* UE Location Inforamtion*/
|
||||
ogs_gtp_parse_uli(&uli, &req->user_location_information);
|
||||
memcpy(&sess->e_tai, &uli.tai, sizeof(sess->e_tai));
|
||||
memcpy(&sess->e_cgi, &uli.e_cgi, sizeof(sess->e_cgi));
|
||||
|
||||
/* Select UPF based on UE Location Information */
|
||||
smf_sess_select_upf(sess);
|
||||
|
||||
/* Check if selected UPF is associated with SMF */
|
||||
ogs_assert(sess->pfcp_node);
|
||||
if (!OGS_FSM_CHECK(&sess->pfcp_node->sm, smf_pfcp_state_associated)) {
|
||||
ogs_gtp_send_error_message(xact, sess ? sess->sgw_s5c_teid : 0,
|
||||
OGS_GTP_CREATE_SESSION_RESPONSE_TYPE,
|
||||
OGS_GTP_CAUSE_REMOTE_PEER_NOT_RESPONDING);
|
||||
return;
|
||||
}
|
||||
|
||||
/* UE IP Address */
|
||||
ogs_assert(req->pdn_address_allocation.data);
|
||||
sess->pdn.pdn_type = req->pdn_type.u8;
|
||||
ogs_gtp_paa_to_ip(
|
||||
(ogs_paa_t *)req->pdn_address_allocation.data, &sess->pdn.ue_ip);
|
||||
|
||||
smf_sess_set_ue_ip(sess);
|
||||
|
||||
ogs_info("UE IMSI:[%s] APN:[%s] IPv4:[%s] IPv6:[%s]",
|
||||
smf_ue->imsi_bcd, apn,
|
||||
sess->ipv4 ? OGS_INET_NTOP(&sess->ipv4->addr, buf1) : "",
|
||||
sess->ipv6 ? OGS_INET6_NTOP(&sess->ipv6->addr, buf2) : "");
|
||||
|
||||
/* Remove all previous bearer */
|
||||
smf_bearer_remove_all(sess);
|
||||
|
||||
/* Setup Default Bearer */
|
||||
bearer = smf_bearer_add(sess);
|
||||
ogs_assert(bearer);
|
||||
|
||||
/* Set Bearer EBI */
|
||||
bearer->ebi = req->bearer_contexts_to_be_created.eps_bearer_id.u8;
|
||||
|
||||
/* Control Plane(DL) : SGW-S5C */
|
||||
sgw_s5c_teid = req->sender_f_teid_for_control_plane.data;
|
||||
ogs_assert(sgw_s5c_teid);
|
||||
sess->sgw_s5c_teid = be32toh(sgw_s5c_teid->teid);
|
||||
|
||||
/* Data Plane(DL) : gNB-N3 */
|
||||
gnb_n3_teid = req->bearer_contexts_to_be_created.s5_s8_u_sgw_f_teid.data;
|
||||
ogs_assert(gnb_n3_teid);
|
||||
bearer->gnb_n3_teid = be32toh(gnb_n3_teid->teid);
|
||||
rv = ogs_gtp_f_teid_to_ip(gnb_n3_teid, &bearer->gnb_n3_ip);
|
||||
/* Data Plane(DL) : SGW-S5U */
|
||||
sgw_s5u_teid = req->bearer_contexts_to_be_created.s5_s8_u_sgw_f_teid.data;
|
||||
ogs_assert(sgw_s5u_teid);
|
||||
bearer->sgw_s5u_teid = be32toh(sgw_s5u_teid->teid);
|
||||
rv = ogs_gtp_f_teid_to_ip(sgw_s5u_teid, &bearer->sgw_s5u_ip);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
|
||||
ogs_debug(" SGW_S5C_TEID[0x%x] SMF_N4_TEID[0x%x]",
|
||||
sess->sgw_s5c_teid, sess->smf_n4_teid);
|
||||
ogs_debug(" gNB_N3_TEID[0x%x] UPF_N3_TEID[0x%x]",
|
||||
bearer->gnb_n3_teid, bearer->upf_n3_teid);
|
||||
ogs_debug(" SGW_S5U_TEID[0x%x] UPF_S5U_TEID[0x%x]",
|
||||
bearer->sgw_s5u_teid, bearer->upf_s5u_teid);
|
||||
|
||||
decoded = ogs_gtp_parse_bearer_qos(&bearer_qos,
|
||||
&req->bearer_contexts_to_be_created.bearer_level_qos);
|
||||
|
@ -168,7 +228,7 @@ void smf_s5c_handle_create_session_request(
|
|||
if (req->ue_time_zone.presence) {
|
||||
OGS_TLV_STORE_DATA(&sess->gtp.ue_timezone, &req->ue_time_zone);
|
||||
}
|
||||
|
||||
|
||||
smf_gx_send_ccr(sess, xact,
|
||||
OGS_DIAM_GX_CC_REQUEST_TYPE_INITIAL_REQUEST);
|
||||
}
|
||||
|
@ -214,8 +274,9 @@ void smf_s5c_handle_create_bearer_response(
|
|||
ogs_gtp_create_bearer_response_t *rsp)
|
||||
{
|
||||
int rv;
|
||||
ogs_gtp_f_teid_t *gnb_n3_teid, *smf_s5u_teid;
|
||||
ogs_gtp_f_teid_t *sgw_s5u_teid, *smf_s5u_teid;
|
||||
smf_bearer_t *bearer = NULL;
|
||||
ogs_pfcp_far_t *far = NULL;
|
||||
|
||||
ogs_assert(xact);
|
||||
ogs_assert(rsp);
|
||||
|
@ -271,16 +332,26 @@ void smf_s5c_handle_create_bearer_response(
|
|||
/* Set EBI */
|
||||
bearer->ebi = rsp->bearer_contexts.eps_bearer_id.u8;
|
||||
|
||||
/* Data Plane(DL) : gNB-N3 */
|
||||
gnb_n3_teid = rsp->bearer_contexts.s5_s8_u_sgw_f_teid.data;
|
||||
ogs_assert(gnb_n3_teid);
|
||||
bearer->gnb_n3_teid = be32toh(gnb_n3_teid->teid);
|
||||
rv = ogs_gtp_f_teid_to_ip(gnb_n3_teid, &bearer->gnb_n3_ip);
|
||||
/* Data Plane(DL) : SGW-S5U */
|
||||
sgw_s5u_teid = rsp->bearer_contexts.s5_s8_u_sgw_f_teid.data;
|
||||
ogs_assert(sgw_s5u_teid);
|
||||
bearer->sgw_s5u_teid = be32toh(sgw_s5u_teid->teid);
|
||||
rv = ogs_gtp_f_teid_to_ip(sgw_s5u_teid, &bearer->sgw_s5u_ip);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
|
||||
ogs_debug("[SMF] Create Bearer Response : SGW[0x%x] --> SMF[0x%x]",
|
||||
sess->sgw_s5c_teid, sess->smf_n4_teid);
|
||||
|
||||
/* Setup FAR */
|
||||
ogs_list_for_each(&bearer->pfcp.far_list, far) {
|
||||
if (far->dst_if == OGS_PFCP_INTERFACE_ACCESS) {
|
||||
ogs_pfcp_ip_to_outer_header_creation(&bearer->sgw_s5u_ip,
|
||||
&far->outer_header_creation, &far->outer_header_creation_len);
|
||||
far->outer_header_creation.teid = bearer->sgw_s5u_teid;
|
||||
}
|
||||
}
|
||||
|
||||
/* Setup QER */
|
||||
if (bearer->qos.mbr.downlink || bearer->qos.mbr.uplink ||
|
||||
bearer->qos.gbr.downlink || bearer->qos.gbr.uplink) {
|
||||
ogs_pfcp_pdr_t *pdr = NULL;
|
||||
|
|
|
@ -28,19 +28,6 @@ static OGS_POOL(upf_sdf_filter_pool, upf_sdf_filter_t);
|
|||
|
||||
static int context_initialized = 0;
|
||||
|
||||
int num_sessions = 0;
|
||||
void stats_add_session(void) {
|
||||
num_sessions = num_sessions + 1;
|
||||
ogs_info("Added a session. Number of active sessions is now %d",
|
||||
num_sessions);
|
||||
}
|
||||
|
||||
void stats_remove_session(void) {
|
||||
num_sessions = num_sessions - 1;
|
||||
ogs_info("Removed a session. Number of active sessions is now %d",
|
||||
num_sessions);
|
||||
}
|
||||
|
||||
void upf_context_init(void)
|
||||
{
|
||||
ogs_assert(context_initialized == 0);
|
||||
|
@ -457,7 +444,7 @@ upf_sess_t *upf_sess_add(ogs_pfcp_f_seid_t *cp_f_seid,
|
|||
OGS_SETUP_DEFAULT_PDR(&sess->pfcp,
|
||||
ogs_pfcp_pdr_find_or_add(&sess->pfcp, default_pdr_id));
|
||||
|
||||
ogs_info("UE F-SEID[CP:%ld,UP:%ld] "
|
||||
ogs_info("UE F-SEID[CP:0x%lx,UP:0x%lx] "
|
||||
"APN[%s] PDN-Type[%d] IPv4[%s] IPv6[%s], Default PDR ID[%d]",
|
||||
(long)sess->upf_n4_seid, (long)sess->smf_n4_seid,
|
||||
apn, pdn_type,
|
||||
|
@ -467,7 +454,8 @@ upf_sess_t *upf_sess_add(ogs_pfcp_f_seid_t *cp_f_seid,
|
|||
|
||||
ogs_list_add(&self.sess_list, sess);
|
||||
|
||||
stats_add_session();
|
||||
ogs_info("Added a session. Number of active sessions is now %d",
|
||||
ogs_list_count(&self.sess_list));
|
||||
|
||||
return sess;
|
||||
|
||||
|
@ -498,7 +486,8 @@ int upf_sess_remove(upf_sess_t *sess)
|
|||
|
||||
ogs_pool_free(&upf_sess_pool, sess);
|
||||
|
||||
stats_remove_session();
|
||||
ogs_info("Removed a session. Number of active sessions is now %d",
|
||||
ogs_list_count(&self.sess_list));
|
||||
|
||||
return OGS_OK;
|
||||
}
|
||||
|
|
|
@ -120,9 +120,6 @@ upf_sdf_filter_t *upf_sdf_filter_add(ogs_pfcp_pdr_t *pdr);
|
|||
void upf_sdf_filter_remove(upf_sdf_filter_t *sdf_filter);
|
||||
void upf_sdf_filter_remove_all(upf_sess_t *sess);
|
||||
|
||||
void stats_add_session(void);
|
||||
void stats_remove_session(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
|
||||
#define UPF_GTP_HANDLED 1
|
||||
|
||||
static void upf_gtp_send_to_gnb(ogs_pfcp_far_t *far, ogs_pkbuf_t *sendbuf);
|
||||
static void upf_gtp_send_to_gnb(ogs_pfcp_pdr_t *pdr, ogs_pkbuf_t *sendbuf);
|
||||
static int upf_gtp_handle_multicast(ogs_pkbuf_t *recvbuf);
|
||||
static int upf_gtp_handle_slaac(upf_sess_t *sess, ogs_pkbuf_t *recvbuf);
|
||||
static int upf_gtp_handle_pdr(ogs_pfcp_pdr_t *pdr, ogs_pkbuf_t *recvbuf);
|
||||
|
@ -94,6 +94,7 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
|
|||
struct ip *ip_h = NULL;
|
||||
|
||||
uint32_t teid;
|
||||
uint8_t qfi;
|
||||
ogs_pfcp_pdr_t *pdr = NULL;
|
||||
upf_sess_t *sess = NULL;
|
||||
ogs_pfcp_subnet_t *subnet = NULL;
|
||||
|
@ -166,6 +167,7 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
|
|||
ogs_debug("[RECV] GPU-U from [%s] : TEID[0x%x]",
|
||||
OGS_ADDR(&from, buf), teid);
|
||||
|
||||
qfi = 0;
|
||||
if (gtp_h->flags & OGS_GTPU_FLAGS_E) {
|
||||
/*
|
||||
* TS29.281
|
||||
|
@ -184,6 +186,7 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
|
|||
OGS_GTP_EXTENSION_HEADER_PDU_TYPE_UL_PDU_SESSION_INFORMATION) {
|
||||
ogs_debug(" QFI [0x%x]",
|
||||
extension_header->qos_flow_identifier);
|
||||
qfi = extension_header->qos_flow_identifier;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -200,9 +203,10 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data)
|
|||
ip_h = (struct ip *)pkbuf->data;
|
||||
ogs_assert(ip_h);
|
||||
|
||||
pdr = ogs_pfcp_pdr_find_by_teid(teid);
|
||||
pdr = ogs_pfcp_pdr_find_by_teid_and_qfi(teid, qfi);
|
||||
if (!pdr) {
|
||||
ogs_warn("[DROP] Cannot find PDR : UPF-N3-TEID[0x%x]", teid);
|
||||
ogs_warn("[DROP] Cannot find PDR : UPF-N3-TEID[0x%x] QFI[%d]",
|
||||
teid, qfi);
|
||||
goto cleanup;
|
||||
}
|
||||
ogs_assert(pdr->sess);
|
||||
|
@ -326,23 +330,25 @@ void upf_gtp_close(void)
|
|||
}
|
||||
}
|
||||
|
||||
void upf_gtp_send_buffered_packet(ogs_pfcp_far_t *far)
|
||||
void upf_gtp_send_buffered_packet(ogs_pfcp_pdr_t *pdr)
|
||||
{
|
||||
ogs_pfcp_far_t *far = NULL;
|
||||
int i;
|
||||
|
||||
ogs_assert(far);
|
||||
ogs_assert(pdr);
|
||||
far = pdr->far;
|
||||
|
||||
if (far->gnode) {
|
||||
if (far && far->gnode) {
|
||||
if (far->apply_action & OGS_PFCP_APPLY_ACTION_FORW) {
|
||||
for (i = 0; i < far->num_of_buffered_packet; i++) {
|
||||
upf_gtp_send_to_gnb(far, far->buffered_packet[i]);
|
||||
upf_gtp_send_to_gnb(pdr, far->buffered_packet[i]);
|
||||
}
|
||||
far->num_of_buffered_packet = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void upf_gtp_send_to_gnb(ogs_pfcp_far_t *far, ogs_pkbuf_t *sendbuf)
|
||||
static void upf_gtp_send_to_gnb(ogs_pfcp_pdr_t *pdr, ogs_pkbuf_t *sendbuf)
|
||||
{
|
||||
char buf[OGS_ADDRSTRLEN];
|
||||
int rv;
|
||||
|
@ -350,10 +356,16 @@ static void upf_gtp_send_to_gnb(ogs_pfcp_far_t *far, ogs_pkbuf_t *sendbuf)
|
|||
ogs_gtp_extension_header_t *ext_h = NULL;
|
||||
ogs_gtp_node_t *gnode = NULL;
|
||||
|
||||
ogs_pfcp_pdr_t *pdr = NULL;
|
||||
ogs_pfcp_far_t *far = NULL;
|
||||
ogs_pfcp_qer_t *qer = NULL;
|
||||
|
||||
ogs_assert(far);
|
||||
ogs_assert(pdr);
|
||||
|
||||
far = pdr->far;
|
||||
if (!far) {
|
||||
ogs_error("No FAR");
|
||||
return;
|
||||
}
|
||||
|
||||
if (far->dst_if != OGS_PFCP_INTERFACE_ACCESS) {
|
||||
ogs_error("FAR is NOT Downlink");
|
||||
|
@ -365,8 +377,6 @@ static void upf_gtp_send_to_gnb(ogs_pfcp_far_t *far, ogs_pkbuf_t *sendbuf)
|
|||
ogs_assert(gnode->sock);
|
||||
ogs_assert(sendbuf);
|
||||
|
||||
pdr = far->pdr;
|
||||
ogs_assert(pdr);
|
||||
qer = pdr->qer;
|
||||
|
||||
/* Add GTP-U header */
|
||||
|
@ -444,7 +454,7 @@ static int upf_gtp_handle_pdr(ogs_pfcp_pdr_t *pdr, ogs_pkbuf_t *recvbuf)
|
|||
}
|
||||
} else {
|
||||
if (far->apply_action & OGS_PFCP_APPLY_ACTION_FORW) {
|
||||
upf_gtp_send_to_gnb(far, sendbuf);
|
||||
upf_gtp_send_to_gnb(pdr, sendbuf);
|
||||
} else if (far->apply_action & OGS_PFCP_APPLY_ACTION_BUFF) {
|
||||
if (far->num_of_buffered_packet < MAX_NUM_OF_PACKET_BUFFER) {
|
||||
far->buffered_packet[far->num_of_buffered_packet++] = sendbuf;
|
||||
|
|
|
@ -30,7 +30,7 @@ extern "C" {
|
|||
int upf_gtp_open(void);
|
||||
void upf_gtp_close(void);
|
||||
|
||||
void upf_gtp_send_buffered_packet(ogs_pfcp_far_t *far);
|
||||
void upf_gtp_send_buffered_packet(ogs_pfcp_pdr_t *pdr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -58,6 +58,40 @@ void upf_n4_handle_heartbeat_response(
|
|||
upf_timer_cfg(UPF_TIMER_HEARTBEAT)->duration);
|
||||
}
|
||||
|
||||
static void setup_gtp_node(ogs_pfcp_far_t *far,
|
||||
ogs_pfcp_tlv_outer_header_creation_t *outer_header_creation)
|
||||
{
|
||||
int rv;
|
||||
ogs_ip_t ip;
|
||||
ogs_gtp_node_t *gnode = NULL;
|
||||
|
||||
ogs_assert(far);
|
||||
ogs_assert(outer_header_creation);
|
||||
ogs_assert(outer_header_creation->presence);
|
||||
|
||||
memcpy(&far->outer_header_creation,
|
||||
outer_header_creation->data, outer_header_creation->len);
|
||||
far->outer_header_creation.teid = be32toh(far->outer_header_creation.teid);
|
||||
|
||||
rv = ogs_pfcp_outer_header_creation_to_ip(&far->outer_header_creation, &ip);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
|
||||
gnode = ogs_gtp_node_find_by_ip(&upf_self()->gnb_n3_list, &ip);
|
||||
if (!gnode) {
|
||||
gnode = ogs_gtp_node_add_by_ip(
|
||||
&upf_self()->gnb_n3_list, &ip, upf_self()->gtpu_port,
|
||||
ogs_config()->parameter.no_ipv4,
|
||||
ogs_config()->parameter.no_ipv6,
|
||||
ogs_config()->parameter.prefer_ipv4);
|
||||
ogs_assert(gnode);
|
||||
|
||||
rv = ogs_gtp_connect(
|
||||
upf_self()->gtpu_sock, upf_self()->gtpu_sock6, gnode);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
}
|
||||
OGS_SETUP_GTP_NODE(far, gnode);
|
||||
}
|
||||
|
||||
static ogs_pfcp_pdr_t *handle_create_pdr(ogs_pfcp_sess_t *sess,
|
||||
ogs_pfcp_tlv_create_pdr_t *message,
|
||||
uint8_t *cause_value, uint8_t *offending_ie_value)
|
||||
|
@ -159,16 +193,13 @@ static ogs_pfcp_pdr_t *handle_create_pdr(ogs_pfcp_sess_t *sess,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(&pdr->f_teid, message->pdi.local_f_teid.data,
|
||||
message->pdi.local_f_teid.len);
|
||||
pdr->f_teid_len = message->pdi.local_f_teid.len;
|
||||
memcpy(&pdr->f_teid, message->pdi.local_f_teid.data, pdr->f_teid_len);
|
||||
pdr->f_teid.teid = be32toh(pdr->f_teid.teid);
|
||||
|
||||
memcpy(&pdr->outer_header_removal,
|
||||
message->outer_header_removal.data,
|
||||
message->outer_header_removal.len);
|
||||
|
||||
/* Setup UPF-N3-TEID */
|
||||
ogs_hash_set(ogs_pfcp_self()->pdr_hash, &pdr->f_teid.teid,
|
||||
sizeof(pdr->f_teid.teid), pdr);
|
||||
} else {
|
||||
ogs_error("Invalid Source Interface[%d] in PDR", pdr->src_if);
|
||||
*cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_INCORRECT;
|
||||
|
@ -264,40 +295,11 @@ static ogs_pfcp_far_t *handle_create_far(ogs_pfcp_sess_t *sess,
|
|||
far->dst_if = message->forwarding_parameters.destination_interface.u8;
|
||||
|
||||
if (far->dst_if == OGS_PFCP_INTERFACE_ACCESS) { /* Downlink */
|
||||
int rv;
|
||||
ogs_ip_t ip;
|
||||
ogs_gtp_node_t *gnode = NULL;
|
||||
|
||||
if (message->forwarding_parameters.outer_header_creation.presence) {
|
||||
memcpy(&far->outer_header_creation,
|
||||
message->forwarding_parameters.outer_header_creation.data,
|
||||
message->forwarding_parameters.outer_header_creation.len);
|
||||
far->outer_header_creation.teid =
|
||||
be32toh(far->outer_header_creation.teid);
|
||||
|
||||
/* Setup GTP Node */
|
||||
rv = ogs_pfcp_outer_header_creation_to_ip(
|
||||
&far->outer_header_creation, &ip);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
|
||||
gnode = ogs_gtp_node_find_by_ip(&upf_self()->gnb_n3_list, &ip);
|
||||
if (!gnode) {
|
||||
gnode = ogs_gtp_node_add_by_ip(
|
||||
&upf_self()->gnb_n3_list, &ip, upf_self()->gtpu_port,
|
||||
ogs_config()->parameter.no_ipv4,
|
||||
ogs_config()->parameter.no_ipv6,
|
||||
ogs_config()->parameter.prefer_ipv4);
|
||||
ogs_assert(gnode);
|
||||
|
||||
rv = ogs_gtp_connect(
|
||||
upf_self()->gtpu_sock, upf_self()->gtpu_sock6, gnode);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
}
|
||||
OGS_SETUP_GTP_NODE(far, gnode);
|
||||
setup_gtp_node(far,
|
||||
&message->forwarding_parameters.outer_header_creation);
|
||||
}
|
||||
|
||||
upf_gtp_send_buffered_packet(far);
|
||||
|
||||
} else if (far->dst_if == OGS_PFCP_INTERFACE_CORE) { /* Uplink */
|
||||
|
||||
/* Nothing */
|
||||
|
@ -348,43 +350,12 @@ static ogs_pfcp_far_t *handle_update_far(ogs_pfcp_sess_t *sess,
|
|||
destination_interface.u8;
|
||||
|
||||
if (far->dst_if == OGS_PFCP_INTERFACE_ACCESS) { /* Downlink */
|
||||
int rv;
|
||||
ogs_ip_t ip;
|
||||
ogs_gtp_node_t *gnode = NULL;
|
||||
|
||||
if (message->update_forwarding_parameters.
|
||||
outer_header_creation.presence) {
|
||||
memcpy(&far->outer_header_creation,
|
||||
message->update_forwarding_parameters.
|
||||
outer_header_creation.data,
|
||||
message->update_forwarding_parameters.
|
||||
outer_header_creation.len);
|
||||
far->outer_header_creation.teid =
|
||||
be32toh(far->outer_header_creation.teid);
|
||||
|
||||
/* Setup GTP Node */
|
||||
rv = ogs_pfcp_outer_header_creation_to_ip(
|
||||
&far->outer_header_creation, &ip);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
|
||||
gnode = ogs_gtp_node_find_by_ip(&upf_self()->gnb_n3_list, &ip);
|
||||
if (!gnode) {
|
||||
gnode = ogs_gtp_node_add_by_ip(
|
||||
&upf_self()->gnb_n3_list, &ip, upf_self()->gtpu_port,
|
||||
ogs_config()->parameter.no_ipv4,
|
||||
ogs_config()->parameter.no_ipv6,
|
||||
ogs_config()->parameter.prefer_ipv4);
|
||||
ogs_assert(gnode);
|
||||
|
||||
rv = ogs_gtp_connect(
|
||||
upf_self()->gtpu_sock, upf_self()->gtpu_sock6, gnode);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
}
|
||||
OGS_SETUP_GTP_NODE(far, gnode);
|
||||
setup_gtp_node(far,
|
||||
&message->update_forwarding_parameters.outer_header_creation);
|
||||
}
|
||||
|
||||
upf_gtp_send_buffered_packet(far);
|
||||
|
||||
} else if (far->dst_if == OGS_PFCP_INTERFACE_CORE) { /* Uplink */
|
||||
|
||||
/* Nothing */
|
||||
|
@ -547,6 +518,7 @@ void upf_n4_handle_session_establishment_request(
|
|||
upf_sess_t *sess, ogs_pfcp_xact_t *xact,
|
||||
ogs_pfcp_session_establishment_request_t *req)
|
||||
{
|
||||
ogs_pfcp_pdr_t *pdr = NULL;
|
||||
ogs_pfcp_pdr_t *created_pdr[OGS_MAX_NUM_OF_PDR];
|
||||
int num_of_created_pdr = 0;
|
||||
uint8_t cause_value = 0;
|
||||
|
@ -594,6 +566,24 @@ void upf_n4_handle_session_establishment_request(
|
|||
if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED)
|
||||
goto cleanup;
|
||||
|
||||
/* Setup UPF-N3-TEID & QFI Hash */
|
||||
for (i = 0; i < num_of_created_pdr; i++) {
|
||||
pdr = created_pdr[i];
|
||||
ogs_assert(pdr);
|
||||
|
||||
if (pdr->src_if == OGS_PFCP_INTERFACE_ACCESS) { /* Uplink */
|
||||
if (pdr->f_teid_len)
|
||||
ogs_pfcp_pdr_hash_set(pdr);
|
||||
}
|
||||
}
|
||||
|
||||
/* Send Buffered Packet to gNB/SGW */
|
||||
ogs_list_for_each(&sess->pfcp.pdr_list, pdr) {
|
||||
if (pdr->src_if == OGS_PFCP_INTERFACE_CORE) { /* Downlink */
|
||||
upf_gtp_send_buffered_packet(pdr);
|
||||
}
|
||||
}
|
||||
|
||||
upf_pfcp_send_session_establishment_response(
|
||||
xact, sess, created_pdr, num_of_created_pdr);
|
||||
return;
|
||||
|
@ -609,6 +599,7 @@ void upf_n4_handle_session_modification_request(
|
|||
upf_sess_t *sess, ogs_pfcp_xact_t *xact,
|
||||
ogs_pfcp_session_modification_request_t *req)
|
||||
{
|
||||
ogs_pfcp_pdr_t *pdr = NULL;
|
||||
ogs_pfcp_pdr_t *created_pdr[OGS_MAX_NUM_OF_PDR];
|
||||
int num_of_created_pdr = 0;
|
||||
uint8_t cause_value = 0;
|
||||
|
@ -696,6 +687,24 @@ void upf_n4_handle_session_modification_request(
|
|||
if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED)
|
||||
goto cleanup;
|
||||
|
||||
/* Setup UPF-N3-TEID & QFI Hash */
|
||||
for (i = 0; i < num_of_created_pdr; i++) {
|
||||
pdr = created_pdr[i];
|
||||
ogs_assert(pdr);
|
||||
|
||||
if (pdr->src_if == OGS_PFCP_INTERFACE_ACCESS) { /* Uplink */
|
||||
if (pdr->f_teid_len)
|
||||
ogs_pfcp_pdr_hash_set(pdr);
|
||||
}
|
||||
}
|
||||
|
||||
/* Send Buffered Packet to gNB/SGW */
|
||||
ogs_list_for_each(&sess->pfcp.pdr_list, pdr) {
|
||||
if (pdr->src_if == OGS_PFCP_INTERFACE_CORE) { /* Downlink */
|
||||
upf_gtp_send_buffered_packet(pdr);
|
||||
}
|
||||
}
|
||||
|
||||
upf_pfcp_send_session_modification_response(
|
||||
xact, sess, created_pdr, num_of_created_pdr);
|
||||
return;
|
||||
|
|
|
@ -205,6 +205,8 @@ typedef struct test_sess_s {
|
|||
ogs_ip_t gnb_n3_ip;
|
||||
uint32_t gnb_n3_teid;
|
||||
|
||||
uint8_t qfi;
|
||||
|
||||
test_ul_nas_transport_param_t ul_nas_transport_param;
|
||||
|
||||
test_ue_t *test_ue;
|
||||
|
|
|
@ -977,7 +977,7 @@ static ogs_pkbuf_t *testngap_build_pdu_session_resource_setup_response_trasfer(
|
|||
CALLOC(1, sizeof(struct NGAP_AssociatedQosFlowItem));
|
||||
ASN_SEQUENCE_ADD(&associatedQosFlowList->list, associatedQosFlowItem);
|
||||
|
||||
associatedQosFlowItem->qosFlowIdentifier = 1;
|
||||
associatedQosFlowItem->qosFlowIdentifier = sess->qfi;
|
||||
|
||||
return ogs_asn_encode(
|
||||
&asn_DEF_NGAP_PDUSessionResourceSetupResponseTransfer, &message);
|
||||
|
|
|
@ -158,7 +158,7 @@ void testngap_handle_pdu_session_resource_setup_request(
|
|||
test_ue_t *test_ue, ogs_ngap_message_t *message)
|
||||
{
|
||||
test_sess_t *sess = NULL;
|
||||
int rv, i, j, k;
|
||||
int rv, i, j, k, l;
|
||||
char buf[OGS_ADDRSTRLEN];
|
||||
|
||||
NGAP_NGAP_PDU_t pdu;
|
||||
|
@ -176,6 +176,8 @@ void testngap_handle_pdu_session_resource_setup_request(
|
|||
NGAP_UPTransportLayerInformation_t *UPTransportLayerInformation = NULL;
|
||||
NGAP_GTPTunnel_t *gTPTunnel = NULL;
|
||||
NGAP_PDUSessionType_t *PDUSessionType = NULL;
|
||||
NGAP_QosFlowSetupRequestList_t *QosFlowSetupRequestList = NULL;
|
||||
NGAP_QosFlowSetupRequestItem_t *QosFlowSetupRequestItem = NULL;
|
||||
OCTET_STRING_t *transfer = NULL;
|
||||
ogs_pkbuf_t *n2smbuf = NULL;
|
||||
|
||||
|
@ -219,6 +221,20 @@ void testngap_handle_pdu_session_resource_setup_request(
|
|||
for (k = 0; k < n2sm_message.protocolIEs.list.count; k++) {
|
||||
ie2 = n2sm_message.protocolIEs.list.array[k];
|
||||
switch (ie2->id) {
|
||||
case NGAP_ProtocolIE_ID_id_QosFlowSetupRequestList:
|
||||
QosFlowSetupRequestList =
|
||||
&ie2->value.choice.QosFlowSetupRequestList;
|
||||
ogs_assert(QosFlowSetupRequestList);
|
||||
for (l = 0;
|
||||
l < QosFlowSetupRequestList->list.count; l++) {
|
||||
QosFlowSetupRequestItem =
|
||||
(struct NGAP_QosFlowSetupRequestItem *)
|
||||
QosFlowSetupRequestList->list.array[l];
|
||||
ogs_assert(QosFlowSetupRequestItem);
|
||||
sess->qfi =
|
||||
QosFlowSetupRequestItem->qosFlowIdentifier;
|
||||
}
|
||||
break;
|
||||
case NGAP_ProtocolIE_ID_id_UL_NGU_UP_TNLInformation:
|
||||
UPTransportLayerInformation =
|
||||
&ie2->value.choice.UPTransportLayerInformation;
|
||||
|
@ -231,6 +247,7 @@ void testngap_handle_pdu_session_resource_setup_request(
|
|||
&sess->upf_n3_ip);
|
||||
ogs_asn_OCTET_STRING_to_uint32(
|
||||
&gTPTunnel->gTP_TEID, &sess->upf_n3_teid);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue