diff --git a/src/mme/mme_context.h b/src/mme/mme_context.h index 05c49531fa..de62971296 100644 --- a/src/mme/mme_context.h +++ b/src/mme/mme_context.h @@ -131,6 +131,9 @@ struct _enb_ue_t { tai_t tai; e_cgi_t e_cgi; + /* Handover Info */ + S1ap_HandoverType_t handover_type; + /* mme_ue_context */ mme_ue_t *mme_ue; @@ -376,6 +379,10 @@ typedef struct _mme_sess_t { bearer->enb_dl_addr = 0; \ bearer->enb_ul_teid = 0; \ bearer->enb_ul_addr = 0; \ + bearer->sgw_dl_teid = 0; \ + bearer->sgw_dl_addr = 0; \ + bearer->sgw_ul_teid = 0; \ + bearer->sgw_ul_addr = 0; \ bearer = mme_bearer_next(bearer); \ } \ sess = mme_sess_next(sess); \ @@ -398,6 +405,11 @@ typedef struct _mme_bearer_t { c_uint32_t enb_ul_teid; c_uint32_t enb_ul_addr; + c_uint32_t sgw_dl_teid; + c_uint32_t sgw_dl_addr; + c_uint32_t sgw_ul_teid; + c_uint32_t sgw_ul_addr; + qos_t qos; tlv_octet_t tft; /* Saved TFT */ diff --git a/src/mme/mme_s11_handler.c b/src/mme/mme_s11_handler.c index 4dbb9301bd..9b06a215e0 100644 --- a/src/mme/mme_s11_handler.c +++ b/src/mme/mme_s11_handler.c @@ -3,6 +3,7 @@ #include "core_debug.h" #include "gtp_types.h" +#include "gtp_conv.h" #include "mme_event.h" #include "mme_context.h" @@ -337,4 +338,67 @@ void mme_s11_handle_create_indirect_data_forwarding_tunnel_response( gtp_xact_t *xact, mme_ue_t *mme_ue, gtp_create_indirect_data_forwarding_tunnel_response_t *rsp) { + status_t rv; + enb_ue_t *enb_ue = NULL; + mme_bearer_t *bearer = NULL; + int i; + + tlv_bearer_context_t *bearers[GTP_MAX_NUM_OF_INDIRECT_TUNNEL]; + gtp_f_teid_t *teid = NULL; + + d_assert(xact, return, "Null param"); + d_assert(mme_ue, return, "Null param"); + d_assert(rsp, return, "Null param"); + + enb_ue = mme_ue->enb_ue; + d_assert(enb_ue, return, "Null param"); + + if (rsp->cause.presence == 0) + { + d_error("No Cause"); + return; + } + + d_trace(3, "[GTP] Create Indirect Data Forwarding Tunnel Response : " + "MME[%d] <-- SGW[%d]\n", mme_ue->mme_s11_teid, mme_ue->sgw_s11_teid); + + rv = gtp_xact_commit(xact); + d_assert(rv == CORE_OK, return, "xact_commit error"); + + gtp_bearers_in_create_indirect_tunnel_response(&bearers, rsp); + + for (i = 0; bearers[i]->presence; i++) + { + if (bearers[i]->eps_bearer_id.presence == 0) + { + d_error("No EBI"); + return; + } + + bearer = mme_bearer_find_by_ue_ebi(mme_ue, + bearers[i]->eps_bearer_id.u8); + d_assert(bearer, return, "No Bearer Context"); + + if (bearers[i]->s4_u_sgsn_f_teid.presence) + { + teid = bearers[i]->s4_u_sgsn_f_teid.data; + d_assert(teid, return,); + + bearer->sgw_dl_teid = ntohl(teid->teid); + bearer->sgw_dl_addr = teid->ipv4_addr; + } + else if (bearers[i]->s2b_u_epdg_f_teid_5.presence) + { + teid = bearers[i]->s2b_u_epdg_f_teid_5.data; + d_assert(teid, return,); + + bearer->sgw_ul_teid = ntohl(teid->teid); + bearer->sgw_ul_addr = teid->ipv4_addr; + } + else + d_assert(0, return, "Not Supported"); + } + + rv = s1ap_send_handover_command(enb_ue); + d_assert(rv == CORE_OK,, "s1ap send error"); } diff --git a/src/mme/s1ap_build.c b/src/mme/s1ap_build.c index 714707bc04..e4b09905bd 100644 --- a/src/mme/s1ap_build.c +++ b/src/mme/s1ap_build.c @@ -817,6 +817,83 @@ status_t s1ap_build_handover_request( return CORE_OK; } +status_t s1ap_build_handover_command(pkbuf_t **s1apbuf, enb_ue_t *enb_ue) +{ + char buf[INET_ADDRSTRLEN]; + + int encoded; + s1ap_message_t message; + S1ap_HandoverCommandIEs_t *ies = &message.s1ap_HandoverCommandIEs; + S1ap_E_RABDataForwardingItem_t *e_rab = NULL; + + mme_ue_t *mme_ue = NULL; + mme_sess_t *sess = NULL; + mme_bearer_t *bearer = NULL; + + d_assert(enb_ue, return CORE_ERROR, "Null param"); + mme_ue = enb_ue->mme_ue; + + memset(&message, 0, sizeof(s1ap_message_t)); + + ies->mme_ue_s1ap_id = enb_ue->mme_ue_s1ap_id; + ies->eNB_UE_S1AP_ID = enb_ue->enb_ue_s1ap_id; + ies->handoverType = enb_ue->handover_type; + + ies->presenceMask |= + S1AP_HANDOVERCOMMANDIES_E_RABDATAFORWARDINGLIST_PRESENT; + sess = mme_sess_first(mme_ue); + while(sess) + { + bearer = mme_bearer_first(sess); + while(bearer) + { + e_rab = (S1ap_E_RABDataForwardingItem_t *) + core_calloc(1, sizeof(S1ap_E_RABDataForwardingItem_t)); + e_rab->e_RAB_ID = bearer->ebi; + + /* + e_rab->dL_transportLayerAddress = (S1ap_TransportLayerAddress_t *) + core_calloc(1, sizeof(S1ap_TransportLayerAddress_t)); + e_rab->dL_transportLayerAddress->size = 4; + e_rab->dL_transportLayerAddress->buf = core_calloc( + e_rab->dL_transportLayerAddress->size, sizeof(c_uint8_t)); + memcpy(e_rab->dL_transportLayerAddress->buf, + &bearer->sgw_dl_addr, + e_rab->dL_transportLayerAddress->size); + + e_rab->dL_gTP_TEID = (S1ap_GTP_TEID_t *) + core_calloc(1, sizeof(S1ap_GTP_TEID_t)); + s1ap_uint32_to_OCTET_STRING( + bearer->sgw_dl_teid, e_rab->dL_gTP_TEID); + */ + + ASN_SEQUENCE_ADD(&ies->e_RABDataForwardingList, e_rab); + + bearer = mme_bearer_next(bearer); + } + sess = mme_sess_next(sess); + } + + s1ap_buffer_to_OCTET_STRING(mme_ue->container.buf, mme_ue->container.size, + &ies->target_ToSource_TransparentContainer); + S1AP_CLEAR_DATA(&mme_ue->container); + + message.procedureCode = S1ap_ProcedureCode_id_HandoverPreparation; + message.direction = S1AP_PDU_PR_successfulOutcome; + + encoded = s1ap_encode_pdu(s1apbuf, &message); + s1ap_free_pdu(&message); + + d_assert(s1apbuf && encoded >= 0,return CORE_ERROR,); + + d_trace(3, "[S1AP] Handover Command : ", + "UE[mME-UE-S1AP-ID(%d)] <-- eNB[%s:%d]\n", + enb_ue->mme_ue_s1ap_id, + INET_NTOP(&enb_ue->enb->s1ap_sock->remote.sin_addr.s_addr, buf), + enb_ue->enb->enb_id); + + return CORE_OK; +} static void s1ap_build_cause(S1ap_Cause_t *dst, S1ap_Cause_t *src) { diff --git a/src/mme/s1ap_build.h b/src/mme/s1ap_build.h index 7eb0d27ad2..e3a869a16c 100644 --- a/src/mme/s1ap_build.h +++ b/src/mme/s1ap_build.h @@ -31,6 +31,8 @@ CORE_DECLARE(status_t) s1ap_build_path_switch_failure(pkbuf_t **s1apbuf, CORE_DECLARE(status_t) s1ap_build_handover_request( pkbuf_t **s1apbuf, mme_ue_t *mme_ue, enb_ue_t *enb_ue, S1ap_HandoverRequiredIEs_t *required); +CORE_DECLARE(status_t) s1ap_build_handover_command( + pkbuf_t **s1apbuf, enb_ue_t *enb_ue); #ifdef __cplusplus } diff --git a/src/mme/s1ap_handler.c b/src/mme/s1ap_handler.c index 3db61bf835..fb1af16f3c 100644 --- a/src/mme/s1ap_handler.c +++ b/src/mme/s1ap_handler.c @@ -678,6 +678,8 @@ void s1ap_handle_handover_required(mme_enb_t *enb, s1ap_message_t *message) d_assert(0, return,); } + enb_ue->handover_type = ies->handoverType; + rv = s1ap_send_handover_request(mme_ue, ies); d_assert(rv == CORE_OK,, "s1ap send error"); diff --git a/src/mme/s1ap_path.c b/src/mme/s1ap_path.c index d5a2d65481..43245b71cd 100644 --- a/src/mme/s1ap_path.c +++ b/src/mme/s1ap_path.c @@ -475,3 +475,23 @@ status_t s1ap_send_handover_request( return rv; } + +status_t s1ap_send_handover_command(enb_ue_t *enb_ue) +{ + status_t rv; + pkbuf_t *s1apbuf = NULL; + + mme_enb_t *enb = NULL; + + d_assert(enb_ue, return CORE_ERROR,); + enb = enb_ue->enb; + d_assert(enb, return CORE_ERROR,); + + rv = s1ap_build_handover_command(&s1apbuf, enb_ue); + d_assert(rv == CORE_OK && s1apbuf, return CORE_ERROR, "s1ap build error"); + + rv = s1ap_send_to_enb(enb, s1apbuf); + d_assert(rv == CORE_OK,, "s1ap send error"); + + return rv; +} diff --git a/src/mme/s1ap_path.h b/src/mme/s1ap_path.h index 1c4e35a995..34fa5c401e 100644 --- a/src/mme/s1ap_path.h +++ b/src/mme/s1ap_path.h @@ -31,6 +31,7 @@ CORE_DECLARE(status_t) s1ap_send_path_switch_failure(mme_enb_t *enb, CORE_DECLARE(status_t) s1ap_send_handover_request( mme_ue_t *mme_ue, S1ap_HandoverRequiredIEs_t *required); +CORE_DECLARE(status_t) s1ap_send_handover_command(enb_ue_t *enb_ue); int _s1ap_recv_cb(net_sock_t *net_sock, void *data); diff --git a/src/sgw/sgw_s11_handler.c b/src/sgw/sgw_s11_handler.c index c7ae2a8f9a..04a5d6ce7f 100644 --- a/src/sgw/sgw_s11_handler.c +++ b/src/sgw/sgw_s11_handler.c @@ -542,7 +542,6 @@ void sgw_s11_handle_create_indirect_data_forwarding_tunnel_request( gtp_f_teid_t *req_teid = NULL; gtp_f_teid_t rsp_teid[GTP_MAX_NUM_OF_INDIRECT_TUNNEL]; - d_assert(sgw_ue, return, "Null param"); d_assert(s11_xact, return, "Null param"); d_assert(req, return, "Null param"); @@ -565,6 +564,7 @@ void sgw_s11_handle_create_indirect_data_forwarding_tunnel_request( if (req_bearers[i]->eps_bearer_id.presence == 0) { d_error("No EBI"); + return; } bearer = sgw_bearer_find_by_ue_ebi(sgw_ue, diff --git a/test/handover_test.c b/test/handover_test.c index 075425f6ba..b5910ebb51 100644 --- a/test/handover_test.c +++ b/test/handover_test.c @@ -576,7 +576,11 @@ static void handover_test2(abts_case *tc, void *data) rv = tests1ap_enb_send(sock2, sendbuf); ABTS_INT_EQUAL(tc, CORE_OK, rv); - core_sleep(time_from_msec(1000)); + /* Receive Handover Command */ + recvbuf = pkbuf_alloc(0, MAX_SDU_LEN); + rc = tests1ap_enb_read(sock1, recvbuf); + ABTS_INT_NEQUAL(tc, 0, rc); + pkbuf_free(recvbuf); /********** Remove Subscriber in Database */ doc = BCON_NEW("imsi", BCON_UTF8("001010123456815")); @@ -601,7 +605,7 @@ abts_suite *test_handover(abts_suite *suite) { suite = ADD_SUITE(suite) -#if 0 +#if 1 abts_run_test(suite, handover_test1, NULL); #else abts_run_test(suite, handover_test2, NULL);