Skip to content

Commit

Permalink
WIP: Initial implementation of E-UTRAN to GERAN A/Gb mode Inter RAT h…
Browse files Browse the repository at this point in the history
…andover
  • Loading branch information
pespin committed Dec 11, 2023
1 parent 1041f37 commit 6d196de
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 2 deletions.
30 changes: 29 additions & 1 deletion src/mme/mme-gn-build.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,32 @@ ogs_pkbuf_t *mme_gn_build_ran_information_relay(

gtp1_message.h.type = type;
return ogs_gtp1_build_msg(&gtp1_message);
}
}

/* TS 29.060 7.5.6 Forward Relocation Request */
ogs_pkbuf_t *mme_gn_build_forward_relocation_request(
mme_ue_t *mme_ue, uint8_t type, const uint8_t *buf, size_t len)
{
ogs_gtp1_message_t gtp1_message;
ogs_gtp1_forward_relocation_request_t *req = NULL;
//ogs_session_t *sess = mme_default_session(mme_ue);

ogs_debug("[Gn] build RAN Information Relay");

//ogs_assert(sess);

req = &gtp1_message.forward_relocation_request;
memset(&gtp1_message, 0, sizeof(ogs_gtp1_message_t));

req->imsi.presence = mme_ue->imsi_len > 0;
req->imsi.data = mme_ue->imsi;
req->imsi.len = mme_ue->imsi_len;

req->tunnel_endpoint_identifier_control_plane.presence = 1;
req->tunnel_endpoint_identifier_control_plane.u32 = mme_ue->mme_s11_teid;

/* TODO: implement */

gtp1_message.h.type = type;
return ogs_gtp1_build_msg(&gtp1_message);
};
3 changes: 3 additions & 0 deletions src/mme/mme-gn-build.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,7 @@ ogs_pkbuf_t *mme_gn_build_ran_information_relay(
uint8_t type, const uint8_t *buf, size_t len,
const ogs_nas_rai_t *rai, uint16_t cell_id);

ogs_pkbuf_t *mme_gn_build_forward_relocation_request(
mme_ue_t *mme_ue, uint8_t type, const uint8_t *buf, size_t len);

#endif /* MME_S11_BUILD_H */
37 changes: 37 additions & 0 deletions src/mme/mme-gtp-path.c
Original file line number Diff line number Diff line change
Expand Up @@ -795,3 +795,40 @@ int mme_gtp1_send_ran_information_relay(

return rv;
}

/* TS 29.060 7.5.6 Forward Relocation Request */
int mme_gtp1_send_forward_relocation_request(
mme_sgsn_t *sgsn, mme_ue_t *mme_ue, const uint8_t *buf, size_t len)
{
int rv;
ogs_gtp1_header_t h;
ogs_pkbuf_t *pkbuf = NULL;
ogs_gtp_xact_t *xact = NULL;

ogs_assert(sgsn);
ogs_assert(buf);

memset(&h, 0, sizeof(ogs_gtp1_header_t));
h.type = OGS_GTP1_FORWARD_RELOCATION_REQUEST_TYPE;
h.teid = 0;

pkbuf = mme_gn_build_forward_relocation_request(mme_ue, h.type, buf, len);
if (!pkbuf) {
ogs_error("mme_gn_build_forward_relocation_request() failed");
return OGS_ERROR;
}

xact = ogs_gtp1_xact_local_create(&sgsn->gnode, &h, pkbuf, NULL, NULL);
if (!xact) {
ogs_error("ogs_gtp1_xact_local_create() failed");
return OGS_ERROR;
}
/* TS 29.060 8.2: "The Forward Relocation Request message, where the Tunnel
* Endpoint Identifier shall be set to all zeroes." */
xact->local_teid = 0;

rv = ogs_gtp_xact_commit(xact);
ogs_expect(rv == OGS_OK);

return rv;
}
3 changes: 3 additions & 0 deletions src/mme/mme-gtp-path.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ int mme_gtp1_send_ran_information_relay(
mme_sgsn_t *sgsn, const uint8_t *buf, size_t len,
const ogs_nas_rai_t *rai, uint16_t cell_id);

int mme_gtp1_send_forward_relocation_request(
mme_sgsn_t *sgsn, mme_ue_t *mme_ue, const uint8_t *buf, size_t len);

#ifdef __cplusplus
}
#endif
Expand Down
71 changes: 70 additions & 1 deletion src/mme/s1ap-handler.c
Original file line number Diff line number Diff line change
Expand Up @@ -2810,6 +2810,73 @@ static void s1ap_handle_handover_required_intralte(enb_ue_t *source_ue,
ogs_assert(r != OGS_ERROR);
}

/* 3GPP TS 23.401 "D.3.7 E-UTRAN to GERAN A/Gb mode Inter RAT handover" */
static void s1ap_handle_handover_required_ltetogeran(enb_ue_t *source_ue,
S1AP_Cause_t *Cause, S1AP_TargetID_t *TargetID,
S1AP_Source_ToTarget_TransparentContainer_t *Source_ToTarget_TransparentContainer)
{
struct S1AP_CGI *cGI = NULL;
ogs_plmn_id_t plmn_id;
ogs_nas_rai_t rai;
uint16_t cell_id;
mme_sgsn_t *target_sgsn = NULL;
mme_ue_t *mme_ue = NULL;
int r;

ogs_assert(source_ue);
ogs_assert(Cause);
ogs_assert(TargetID);
ogs_assert(Source_ToTarget_TransparentContainer);

if (TargetID->present != S1AP_TargetID_PR_cGI) {
ogs_error("Unexpected TargetID (%d)", TargetID->present);
r = s1ap_send_handover_preparation_failure(source_ue,
S1AP_Cause_PR_protocol, S1AP_CauseProtocol_semantic_error);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
return;
}
cGI = TargetID->choice.cGI;
ogs_assert(cGI);

memcpy(&plmn_id, cGI->pLMNidentity.buf, sizeof(plmn_id));
ogs_nas_from_plmn_id(&rai.lai.nas_plmn_id, &plmn_id);
memcpy(&rai.lai.lac, cGI->lAC.buf, sizeof(uint16_t));
rai.lai.lac = be16toh(rai.lai.lac);
if (cGI->rAC)
rai.rac = *cGI->rAC->buf;
else /* FIXME: what to do? how to search properly for target cell? */
rai.rac = 0xff;
memcpy(&cell_id, cGI->cI.buf, sizeof(uint16_t));
cell_id = be16toh(cell_id);
ogs_info(" RAI[MCC:%u MNC:%u LAC:%u RAC:%u] CI[%u]",
ogs_plmn_id_mcc(&plmn_id), ogs_plmn_id_mnc(&plmn_id),
rai.lai.lac, rai.rac, cell_id);

target_sgsn = mme_sgsn_find_by_routing_address(&rai, cell_id);
if (!target_sgsn) {
ogs_warn("No SGSN matching target cell! RAI[MCC:%u MNC:%u LAC:%u RAC:%u] CI[%u]",
ogs_plmn_id_mcc(&plmn_id), ogs_plmn_id_mnc(&plmn_id),
rai.lai.lac, rai.rac, cell_id);
return;
}

mme_ue = source_ue->mme_ue;
if (!mme_ue) {
ogs_error("No UE(mme-ue) context");
return;
}

source_ue->handover_type = S1AP_HandoverType_ltetogeran;

mme_gtp1_send_forward_relocation_request(target_sgsn, mme_ue,
Source_ToTarget_TransparentContainer->buf,
Source_ToTarget_TransparentContainer->size);
/* FIXME: we send HO Prep Failure because we don't fully support this yet... */
r = s1ap_send_handover_preparation_failure(source_ue,
S1AP_Cause_PR_protocol, S1AP_CauseProtocol_message_not_compatible_with_receiver_state);
}

void s1ap_handle_handover_required(mme_enb_t *enb, ogs_s1ap_message_t *message)
{
char buf[OGS_ADDRSTRLEN];
Expand Down Expand Up @@ -2951,8 +3018,10 @@ void s1ap_handle_handover_required(mme_enb_t *enb, ogs_s1ap_message_t *message)
case S1AP_HandoverType_intralte:
s1ap_handle_handover_required_intralte(source_ue, Cause, TargetID, Source_ToTarget_TransparentContainer);
break;
case S1AP_HandoverType_ltetoutran:
case S1AP_HandoverType_ltetogeran:
s1ap_handle_handover_required_ltetogeran(source_ue, Cause, TargetID, Source_ToTarget_TransparentContainer);
break;
case S1AP_HandoverType_ltetoutran:
case S1AP_HandoverType_utrantolte:
case S1AP_HandoverType_gerantolte:
case S1AP_HandoverType_eps_to_5gs:
Expand Down

0 comments on commit 6d196de

Please sign in to comment.