Skip to content

Commit

Permalink
[MME] Incorrect behavior of SGsAP+Dedicated-Bearer (open5gs#3072)
Browse files Browse the repository at this point in the history
First of all, it crashes when creating a Dedicated Bearer
on the default Session that is created for the first time.
This behavior should be possible, so the related ASSERT is removed.

Next, the InitialContextRequest is modified
during the Attach Request to include the first Bearer.

Finally, there was an issue where trying to create a Dedicated Bearer
with SGsAP enabled resulted in an InitialContextSetupRequest message
with a PTI of zero. This is because MME initializes the PTI to 0
upon receiving the Create Bearer Request while processing SGsAP.

All of these issues has been fixed.
  • Loading branch information
acetcom committed Apr 1, 2024
1 parent d32cc14 commit da5d424
Show file tree
Hide file tree
Showing 14 changed files with 622 additions and 107 deletions.
20 changes: 18 additions & 2 deletions src/mme/esm-build.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,6 @@ ogs_pkbuf_t *esm_build_activate_default_bearer_context_request(
ogs_assert(session->name);
bearer = mme_default_bearer_in_sess(sess);
ogs_assert(bearer);
ogs_assert(mme_bearer_next(bearer) == NULL);

ogs_debug("Activate default bearer context request");
ogs_debug(" IMSI[%s] PTI[%d] EBI[%d]",
Expand Down Expand Up @@ -254,6 +253,7 @@ ogs_pkbuf_t *esm_build_activate_dedicated_bearer_context_request(
mme_bearer_t *bearer)
{
mme_ue_t *mme_ue = NULL;
mme_sess_t *sess = NULL;
mme_bearer_t *linked_bearer = NULL;

ogs_nas_eps_message_t message;
Expand All @@ -269,6 +269,8 @@ ogs_pkbuf_t *esm_build_activate_dedicated_bearer_context_request(
&activate_dedicated_eps_bearer_context_request->tft;

ogs_assert(bearer);
sess = bearer->sess;
ogs_assert(sess);
mme_ue = bearer->mme_ue;
ogs_assert(mme_ue);
linked_bearer = mme_linked_bearer(bearer);
Expand All @@ -284,7 +286,21 @@ ogs_pkbuf_t *esm_build_activate_dedicated_bearer_context_request(
message.h.protocol_discriminator = OGS_NAS_PROTOCOL_DISCRIMINATOR_EMM;
message.esm.h.eps_bearer_identity = bearer->ebi;
message.esm.h.protocol_discriminator = OGS_NAS_PROTOCOL_DISCRIMINATOR_ESM;
message.esm.h.procedure_transaction_identity = 0;

/*
* Issue #3072
*
* PTI 0 is set here to prevent a InitialContextSetupRequest message
* with a PTI of 0 from being created when the Create Bearer Request occurs
* and InitialContextSetupRequest occurs.
*
* If you implement the creation of a dedicated bearer
* in the ESM procedure reqeusted by the UE,
* you will need to refactor the part that sets the PTI.
*/
message.esm.h.procedure_transaction_identity =
sess->pti = OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED;

message.esm.h.message_type =
OGS_NAS_EPS_ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST;

Expand Down
6 changes: 5 additions & 1 deletion src/mme/mme-context.c
Original file line number Diff line number Diff line change
Expand Up @@ -4287,7 +4287,8 @@ mme_bearer_t *mme_bearer_find_or_add_by_message(
}

if (pti == OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED) {
ogs_error("Both PTI[%d] and EBI[%d] are 0", pti, ebi);
ogs_error("ESM message type: %d, Both PTI[%d] and EBI[%d] are 0",
message->esm.h.message_type, pti, ebi);
r = nas_eps_send_attach_reject(mme_ue->enb_ue, mme_ue,
OGS_NAS_EMM_CAUSE_PROTOCOL_ERROR_UNSPECIFIED,
OGS_NAS_ESM_CAUSE_PROTOCOL_ERROR_UNSPECIFIED);
Expand Down Expand Up @@ -4373,6 +4374,9 @@ mme_bearer_t *mme_bearer_find_or_add_by_message(
sess = mme_sess_find_by_apn(mme_ue,
pdn_connectivity_request->access_point_name.apn);
if (sess && create_action != OGS_GTP_CREATE_IN_ATTACH_REQUEST) {

sess->pti = pti;

r = nas_eps_send_pdn_connectivity_reject(
sess,
OGS_NAS_ESM_CAUSE_MULTIPLE_PDN_CONNECTIONS_FOR_A_GIVEN_APN_NOT_ALLOWED,
Expand Down
15 changes: 14 additions & 1 deletion src/mme/mme-s11-handler.c
Original file line number Diff line number Diff line change
Expand Up @@ -793,7 +793,7 @@ void mme_s11_handle_create_bearer_request(
ogs_assert(xact);
ogs_assert(req);

ogs_debug("Create Bearer Response");
ogs_debug("Create Bearer Request");

/***********************
* Check MME-UE Context
Expand Down Expand Up @@ -877,12 +877,25 @@ void mme_s11_handle_create_bearer_request(
ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]",
mme_ue->mme_s11_teid, sgw_ue->sgw_s11_teid);

/*
* DEPRECATED : Issues #3072
*
* PTI 0 is set here to prevent a InitialContextSetupRequest message
* with a PTI of 0 from being created when the Create Bearer Request occurs
* and InitialContextSetupRequest occurs.
*
* If you implement the creation of a dedicated bearer
* in the ESM procedure reqeusted by the UE,
* you will need to refactor the part that sets the PTI.
*/
#if 0
/* Set PTI */
sess->pti = OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED;
if (req->procedure_transaction_id.presence) {
sess->pti = req->procedure_transaction_id.u8;
ogs_debug(" PTI[%d]", sess->pti);
}
#endif

/* Data Plane(UL) : SGW-S1U */
sgw_s1u_teid = req->bearer_contexts.s1_u_enodeb_f_teid.data;
Expand Down
9 changes: 4 additions & 5 deletions src/mme/nas-path.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@ int nas_eps_send_attach_accept(mme_ue_t *mme_ue)
{
int rv;
mme_sess_t *sess = NULL;
mme_bearer_t *bearer = NULL;
ogs_pkbuf_t *s1apbuf = NULL;
ogs_pkbuf_t *esmbuf = NULL, *emmbuf = NULL;

Expand All @@ -122,10 +121,10 @@ int nas_eps_send_attach_accept(mme_ue_t *mme_ue)

sess = mme_sess_first(mme_ue);
ogs_assert(sess);
ogs_assert(mme_sess_next(sess) == NULL);
bearer = mme_default_bearer_in_sess(sess);
ogs_assert(bearer);
ogs_assert(mme_bearer_next(bearer) == NULL);
if (mme_sess_next(sess)) {
ogs_error("There should only be one SESSION");
return OGS_ERROR;
}

ogs_debug("[%s] Attach accept", mme_ue->imsi_bcd);

Expand Down
240 changes: 143 additions & 97 deletions src/mme/s1ap-build.c
Original file line number Diff line number Diff line change
Expand Up @@ -343,11 +343,72 @@ ogs_pkbuf_t *s1ap_build_downlink_nas_transport(
return ogs_s1ap_encode(&pdu);
}

ogs_pkbuf_t *s1ap_build_initial_context_setup_request(
mme_ue_t *mme_ue, ogs_pkbuf_t *emmbuf)
static void fill_e_rab_to_be_setup(
S1AP_E_RABToBeSetupItemCtxtSUReq_t *e_rab, mme_bearer_t *bearer)
{
int rv;
S1AP_GBR_QosInformation_t *gbrQosInformation = NULL;

ogs_assert(e_rab);
ogs_assert(bearer);

e_rab->e_RAB_ID = bearer->ebi;
e_rab->e_RABlevelQoSParameters.qCI = bearer->qos.index;

ogs_debug(" EBI[%d] QCI[%d] SGW-S1U-TEID[%d]",
bearer->ebi, bearer->qos.index, bearer->sgw_s1u_teid);
ogs_debug(" ARP[%d:%d:%d]",
bearer->qos.arp.priority_level,
bearer->qos.arp.pre_emption_capability,
bearer->qos.arp.pre_emption_vulnerability);

e_rab->e_RABlevelQoSParameters.allocationRetentionPriority.
priorityLevel = bearer->qos.arp.priority_level;
e_rab->e_RABlevelQoSParameters.allocationRetentionPriority.
pre_emptionCapability =
!(bearer->qos.arp.pre_emption_capability);
e_rab->e_RABlevelQoSParameters.allocationRetentionPriority.
pre_emptionVulnerability =
!(bearer->qos.arp.pre_emption_vulnerability);

if (bearer->qos.mbr.downlink || bearer->qos.mbr.uplink ||
bearer->qos.gbr.downlink || bearer->qos.gbr.uplink) {
ogs_assert(bearer->qos.mbr.downlink);
ogs_assert(bearer->qos.mbr.uplink);
ogs_assert(bearer->qos.gbr.downlink);
ogs_assert(bearer->qos.gbr.uplink);

ogs_debug(" MBR[DL:%lld,UL:%lld]",
(long long)bearer->qos.mbr.downlink,
(long long)bearer->qos.mbr.uplink);
ogs_debug(" GBR[DL:%lld,UL:%lld]",
(long long)bearer->qos.gbr.downlink,
(long long)bearer->qos.gbr.uplink);

gbrQosInformation =
CALLOC(1, sizeof(struct S1AP_GBR_QosInformation));
asn_uint642INTEGER(&gbrQosInformation->e_RAB_MaximumBitrateDL,
bearer->qos.mbr.downlink);
asn_uint642INTEGER(&gbrQosInformation->e_RAB_MaximumBitrateUL,
bearer->qos.mbr.uplink);
asn_uint642INTEGER(&gbrQosInformation->
e_RAB_GuaranteedBitrateDL, bearer->qos.gbr.downlink);
asn_uint642INTEGER(&gbrQosInformation->
e_RAB_GuaranteedBitrateUL, bearer->qos.gbr.uplink);
e_rab->e_RABlevelQoSParameters.gbrQosInformation =
gbrQosInformation;
}

rv = ogs_asn_ip_to_BIT_STRING(
&bearer->sgw_s1u_ip, &e_rab->transportLayerAddress);
ogs_assert(rv == OGS_OK);
ogs_asn_uint32_to_OCTET_STRING(
bearer->sgw_s1u_teid, &e_rab->gTP_TEID);
}

ogs_pkbuf_t *s1ap_build_initial_context_setup_request(
mme_ue_t *mme_ue, ogs_pkbuf_t *emmbuf)
{
S1AP_S1AP_PDU_t pdu;
S1AP_InitiatingMessage_t *initiatingMessage = NULL;
S1AP_InitialContextSetupRequest_t *InitialContextSetupRequest = NULL;
Expand Down Expand Up @@ -443,50 +504,26 @@ ogs_pkbuf_t *s1ap_build_initial_context_setup_request(
&UEAggregateMaximumBitrate->uEaggregateMaximumBitRateDL,
mme_ue->ambr.downlink);

ogs_list_for_each(&mme_ue->sess_list, sess) {
ogs_list_for_each(&sess->bearer_list, bearer) {

S1AP_E_RABToBeSetupItemCtxtSUReqIEs_t *item = NULL;
S1AP_E_RABToBeSetupItemCtxtSUReq_t *e_rab = NULL;
S1AP_GBR_QosInformation_t *gbrQosInformation = NULL;
S1AP_NAS_PDU_t *nasPdu = NULL;

if (mme_ue->nas_eps.type == MME_EPS_TYPE_ATTACH_REQUEST) {
/*
* For Attach Request,
* Delete Session Request/Response removes ALL session/bearers.
*
* Since all bearers are INACTIVE,
* we should not check the bearer activation.
*/
} else if (OGS_FSM_CHECK(&bearer->sm, esm_state_inactive)) {
/*
* For Service Request/TAU Request/Extended Service Request,
* Only the active EPS bearer can be included.
*
* If MME received Create Bearer Request and
* if MME does not receive Activate EPS Bearer Context Accept,
* We should not include the INACTIVE bearer.
*
* For example,
* 1. SGW->MME : Create Bearer Request
* 2. MME->UE : S1 Paging
* 3. UE->MME : Service Request
* 4. MME->UE : Initial Context Setup Request
* (We should not include INACTIVE BEARER)
* 5. UE->MME : Initial Context Setup Response
* 6. MME->UE : Activate dedicated EPS Bearer Context Request
* 7. UE->MME : Activate dedicated EPS Bearer Context Accept
* 8. MME->SGW : Create Bearer Response
*/
ogs_warn("No active EPS bearer [%d]", bearer->ebi);
ogs_warn(" IMSI[%s] NAS-EPS Type[%d] "
"ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]",
mme_ue->imsi_bcd, mme_ue->nas_eps.type,
enb_ue->enb_ue_s1ap_id, enb_ue->mme_ue_s1ap_id);
continue;
}
S1AP_E_RABToBeSetupItemCtxtSUReqIEs_t *item = NULL;
S1AP_E_RABToBeSetupItemCtxtSUReq_t *e_rab = NULL;
S1AP_NAS_PDU_t *nasPdu = NULL;

if (mme_ue->nas_eps.type == MME_EPS_TYPE_ATTACH_REQUEST) {
/*
* For Attach Request,
* Delete Session Request/Response removes ALL session/bearers.
*
* Since all bearers are INACTIVE,
* we should not check the bearer activation.
*/
sess = ogs_list_first(&mme_ue->sess_list);
/*
* Issue #3072 : Only first Bearer should be included.
*/
if (sess)
bearer = ogs_list_first(&sess->bearer_list);

if (sess && bearer) {
item = CALLOC(1, sizeof(S1AP_E_RABToBeSetupItemCtxtSUReqIEs_t));
ASN_SEQUENCE_ADD(&E_RABToBeSetupListCtxtSUReq->list, item);

Expand All @@ -496,58 +533,7 @@ ogs_pkbuf_t *s1ap_build_initial_context_setup_request(

e_rab = &item->value.choice.E_RABToBeSetupItemCtxtSUReq;

e_rab->e_RAB_ID = bearer->ebi;
e_rab->e_RABlevelQoSParameters.qCI = bearer->qos.index;

ogs_debug(" EBI[%d] QCI[%d] SGW-S1U-TEID[%d]",
bearer->ebi, bearer->qos.index, bearer->sgw_s1u_teid);
ogs_debug(" ARP[%d:%d:%d]",
bearer->qos.arp.priority_level,
bearer->qos.arp.pre_emption_capability,
bearer->qos.arp.pre_emption_vulnerability);

e_rab->e_RABlevelQoSParameters.allocationRetentionPriority.
priorityLevel = bearer->qos.arp.priority_level;
e_rab->e_RABlevelQoSParameters.allocationRetentionPriority.
pre_emptionCapability =
!(bearer->qos.arp.pre_emption_capability);
e_rab->e_RABlevelQoSParameters.allocationRetentionPriority.
pre_emptionVulnerability =
!(bearer->qos.arp.pre_emption_vulnerability);

if (bearer->qos.mbr.downlink || bearer->qos.mbr.uplink ||
bearer->qos.gbr.downlink || bearer->qos.gbr.uplink) {
ogs_assert(bearer->qos.mbr.downlink);
ogs_assert(bearer->qos.mbr.uplink);
ogs_assert(bearer->qos.gbr.downlink);
ogs_assert(bearer->qos.gbr.uplink);

ogs_debug(" MBR[DL:%lld,UL:%lld]",
(long long)bearer->qos.mbr.downlink,
(long long)bearer->qos.mbr.uplink);
ogs_debug(" GBR[DL:%lld,UL:%lld]",
(long long)bearer->qos.gbr.downlink,
(long long)bearer->qos.gbr.uplink);

gbrQosInformation =
CALLOC(1, sizeof(struct S1AP_GBR_QosInformation));
asn_uint642INTEGER(&gbrQosInformation->e_RAB_MaximumBitrateDL,
bearer->qos.mbr.downlink);
asn_uint642INTEGER(&gbrQosInformation->e_RAB_MaximumBitrateUL,
bearer->qos.mbr.uplink);
asn_uint642INTEGER(&gbrQosInformation->
e_RAB_GuaranteedBitrateDL, bearer->qos.gbr.downlink);
asn_uint642INTEGER(&gbrQosInformation->
e_RAB_GuaranteedBitrateUL, bearer->qos.gbr.uplink);
e_rab->e_RABlevelQoSParameters.gbrQosInformation =
gbrQosInformation;
}

rv = ogs_asn_ip_to_BIT_STRING(
&bearer->sgw_s1u_ip, &e_rab->transportLayerAddress);
ogs_assert(rv == OGS_OK);
ogs_asn_uint32_to_OCTET_STRING(
bearer->sgw_s1u_teid, &e_rab->gTP_TEID);
fill_e_rab_to_be_setup(e_rab, bearer);

if (emmbuf && emmbuf->len) {
ogs_debug(" NASPdu[%p:%d]", emmbuf, emmbuf->len);
Expand All @@ -566,6 +552,66 @@ ogs_pkbuf_t *s1ap_build_initial_context_setup_request(
emmbuf = NULL;
}
}
} else {
/*
* For Service Request/TAU Request/Extended Service Request,
* Only the active EPS bearer can be included.
*
* If MME received Create Bearer Request and
* if MME does not receive Activate EPS Bearer Context Accept,
* We should not include the INACTIVE bearer.
*
* For example,
* 1. SGW->MME : Create Bearer Request
* 2. MME->UE : S1 Paging
* 3. UE->MME : Service Request
* 4. MME->UE : Initial Context Setup Request
* (We should not include INACTIVE BEARER)
* 5. UE->MME : Initial Context Setup Response
* 6. MME->UE : Activate dedicated EPS Bearer Context Request
* 7. UE->MME : Activate dedicated EPS Bearer Context Accept
* 8. MME->SGW : Create Bearer Response
*/
ogs_list_for_each(&mme_ue->sess_list, sess) {
ogs_list_for_each(&sess->bearer_list, bearer) {
if (OGS_FSM_CHECK(&bearer->sm, esm_state_inactive)) {
ogs_warn("No active EPS bearer [%d]", bearer->ebi);
ogs_warn(" IMSI[%s] NAS-EPS Type[%d] "
"ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]",
mme_ue->imsi_bcd, mme_ue->nas_eps.type,
enb_ue->enb_ue_s1ap_id, enb_ue->mme_ue_s1ap_id);
continue;
}

item = CALLOC(1, sizeof(S1AP_E_RABToBeSetupItemCtxtSUReqIEs_t));
ASN_SEQUENCE_ADD(&E_RABToBeSetupListCtxtSUReq->list, item);

item->id = S1AP_ProtocolIE_ID_id_E_RABToBeSetupItemCtxtSUReq;
item->criticality = S1AP_Criticality_reject;
item->value.present = S1AP_E_RABToBeSetupItemCtxtSUReqIEs__value_PR_E_RABToBeSetupItemCtxtSUReq;

e_rab = &item->value.choice.E_RABToBeSetupItemCtxtSUReq;

fill_e_rab_to_be_setup(e_rab, bearer);

if (emmbuf && emmbuf->len) {
ogs_debug(" NASPdu[%p:%d]", emmbuf, emmbuf->len);

nasPdu = (S1AP_NAS_PDU_t *)CALLOC(1, sizeof(S1AP_NAS_PDU_t));
nasPdu->size = emmbuf->len;
nasPdu->buf = CALLOC(nasPdu->size, sizeof(uint8_t));
memcpy(nasPdu->buf, emmbuf->data, nasPdu->size);
e_rab->nAS_PDU = nasPdu;
ogs_pkbuf_free(emmbuf);

ogs_log_hexdump(OGS_LOG_DEBUG, nasPdu->buf, nasPdu->size);

/* Since Tracking area update accept is used only once,
* set emmbuf to NULL as shown below */
emmbuf = NULL;
}
}
}
}

if (emmbuf && emmbuf->len) {
Expand Down
Loading

0 comments on commit da5d424

Please sign in to comment.