--- /dev/null
+/*****************************************************************************
+# *
+# Copyright 2019 AT&T Intellectual Property *
+# Copyright 2019 Nokia *
+# *
+# Licensed under the Apache License, Version 2.0 (the "License"); *
+# you may not use this file except in compliance with the License. *
+# You may obtain a copy of the License at *
+# *
+# http://www.apache.org/licenses/LICENSE-2.0 *
+# *
+# Unless required by applicable law or agreed to in writing, software *
+# distributed under the License is distributed on an "AS IS" BASIS, *
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
+# See the License for the specific language governing permissions and *
+# limitations under the License. *
+# *
+******************************************************************************/
+
+#include "asn_x2ap.hpp"
+#include "asn_x2ap_wrapper.hpp"
+
+/*-----------------------------------------------------------------------
+ COMMON ROUTINES
+-------------------------------------------------------------------------
+*/
+x2ap_pdu_t* new_x2ap_pdu(void)
+{
+ X2APpduWrapper* pduWrapper = new X2APpduWrapper();
+ return reinterpret_cast<x2ap_pdu_t*>(pduWrapper);
+}
+
+void x2ap_asn_print(x2ap_pdu_t* pdu, char* buf, size_t buf_size)
+{
+ X2APpduWrapper* pduWrapper = reinterpret_cast<X2APpduWrapper*>(pdu);
+
+ buf[0] = 0;
+
+ strncat(buf, asn::get_printed(pduWrapper->ref_pdu()).c_str(), buf_size - 1);
+}
+
+int x2ap_asn_per_encode(x2ap_pdu_t* pdu, unsigned char* buf, size_t buf_size,
+ char* err_buf, size_t err_buf_size)
+{
+ X2APpduWrapper* pduWrapper = reinterpret_cast<X2APpduWrapper*>(pdu);
+
+ asn::per::EncoderCtx ctx{ buf, buf_size };
+
+ if (!asn::per::pack(pduWrapper->ref_pdu(), ctx)) {
+ err_buf[0] = 0;
+ // strncat(err_buf, ctx.refErrorCtx().toString().c_str(), err_buf_size - 1);
+ return -1;
+ } else {
+ return static_cast<int>(ctx.refBuffer().getBytesUsed());
+ }
+
+}
+
+int x2ap_asn_per_decode(x2ap_pdu_t* pdu, unsigned char const* buf, size_t buf_size,
+ char* err_buf, size_t err_buf_size)
+{
+ X2APpduWrapper* pduWrapper = reinterpret_cast<X2APpduWrapper*>(pdu);
+
+ asn::per::DecoderCtx ctx{ buf,
+ buf_size,
+ pduWrapper->m_allocation_buffer,
+ pduWrapper->m_allocation_buffer_size };
+
+ if (!asn::per::unpack(pduWrapper->ref_pdu(), ctx)) {
+ err_buf[0] = 0;
+ // strncat(err_buf, ctx.refErrorCtx().toString().c_str(), err_buf_size - 1);
+ return -1;
+ }
+
+ return 0;
+
+}
+
+int x2ap_get_index(x2ap_pdu_t* pdu)
+{
+ X2APpduWrapper* pduWrapper = reinterpret_cast<X2APpduWrapper*>(pdu);
+
+ return pduWrapper->ref_pdu().get_index();
+}
+
+int x2ap_get_procedureCode(x2ap_pdu_t* pdu)
+{
+ X2APpduWrapper* pduWrapper = reinterpret_cast<X2APpduWrapper*>(pdu);
+
+ switch(pduWrapper->ref_pdu().get_index())
+ {
+ case 1:
+ return pduWrapper->ref_pdu().get_initiatingMessage()->ref_procedureCode().get();
+ break;
+
+ case 2:
+ return pduWrapper->ref_pdu().get_successfulOutcome()->ref_procedureCode().get();
+ break;
+
+ case 3:
+ return pduWrapper->ref_pdu().get_unsuccessfulOutcome()->ref_procedureCode().get();
+ break;
+
+ default:
+ return -1;
+ }
+
+}
+
+/*-----------------------------------------------------------------------
+ MESSAGE GENERATORS
+-------------------------------------------------------------------------
+*/
+//X2Setup
+bool x2ap_init_X2SetupRequest(x2ap_pdu_t* pdu)
+{
+ X2APpduWrapper* pduWrapper = reinterpret_cast<X2APpduWrapper*>(pdu);
+
+ //Initialization
+ pduWrapper->ref_pdu().select_initiatingMessage();
+ pduWrapper->ref_pdu().select_initiatingMessage().clear();
+ pduWrapper->ref_pdu().select_initiatingMessage().ref_procedureCode().select_id_x2Setup();
+ pduWrapper->ref_pdu().select_initiatingMessage().ref_criticality().select_id_x2Setup();
+ pduWrapper->ref_pdu().select_initiatingMessage().ref_value().select_id_x2Setup();
+
+ return true;
+}
+
+bool x2ap_create_X2SetupRequest(x2ap_pdu_t* pdu, eNB_config &cfg)
+{
+ X2APpduWrapper* pduWrapper = reinterpret_cast<X2APpduWrapper*>(pdu);
+
+ /* Initiaization */
+ pduWrapper->ref_pdu().select_initiatingMessage().ref_procedureCode().select_id_x2Setup();
+ pduWrapper->ref_pdu().select_initiatingMessage().ref_criticality().select_id_x2Setup();
+
+ X2SetupRequest* container =
+ &(pduWrapper->ref_pdu().select_initiatingMessage().ref_value().select_id_x2Setup());
+
+ using IE_value_t = X2SetupRequest::protocolIEs_t::value_type;
+
+ /* X2SetupRequest-IEs : GlobalENB-ID*/
+ IE_value_t* val_GlobalENB_ID = new IE_value_t;
+ container->ref_protocolIEs().push_back(*val_GlobalENB_ID);
+
+ val_GlobalENB_ID->ref_id().select_id_GlobalENB_ID();
+ val_GlobalENB_ID->ref_criticality().select_id_GlobalENB_ID();
+ val_GlobalENB_ID->ref_value().select_id_GlobalENB_ID().ref_pLMN_Identity()
+ .set(3, cfg.pLMN_Identity);
+
+ val_GlobalENB_ID->ref_value().select_id_GlobalENB_ID().ref_eNB_ID()
+ .select_macro_eNB_ID().set_buffer(20, cfg.macro_eNB_ID);
+
+ /* X2SetupRequest-IEs : ServedCells*/
+ IE_value_t* val_ServedCells = new IE_value_t;
+ container->ref_protocolIEs().push_back(*val_ServedCells);
+
+ val_ServedCells->ref_id().select_id_ServedCells();
+ val_ServedCells->ref_criticality().select_id_ServedCells();
+ val_ServedCells->ref_value().select_id_ServedCells();
+
+ //Add servedCellInfo
+ ServedCells::value_type* elm = new ServedCells::value_type();
+ ServedCell_Information* info = &(elm->ref_servedCellInfo());
+ {
+ //Set ServedCell-Information: pCI, cellId, tAC, broadcastPLMNs, eUTRA-Mode-Info
+ info->ref_pCI().set(cfg.pCI);
+ info->ref_cellId().ref_pLMN_Identity().set(3, cfg.pLMN_Identity);
+ info->ref_cellId().ref_eUTRANcellIdentifier().set_buffer(28, cfg.eUTRANcellIdentifier);
+ info->ref_tAC().set(2, cfg.tAC);
+
+ BroadcastPLMNs_Item::value_type* item = new BroadcastPLMNs_Item::value_type();
+ item->set(3, cfg.pLMN_Identity);
+ info->ref_broadcastPLMNs().push_back(*item);
+
+ info->ref_eUTRA_Mode_Info().select_fDD().ref_uL_EARFCN().set(cfg.uL_EARFCN);
+ info->ref_eUTRA_Mode_Info().select_fDD().ref_dL_EARFCN().set(cfg.dL_EARFCN);
+ info->ref_eUTRA_Mode_Info().select_fDD().ref_uL_Transmission_Bandwidth()
+ .set(static_cast<Transmission_Bandwidth::index_t>(cfg.uL_Bandwidth));
+ info->ref_eUTRA_Mode_Info().select_fDD().ref_dL_Transmission_Bandwidth()
+ .set(static_cast<Transmission_Bandwidth::index_t>(cfg.dL_Bandwidth));
+ }
+ val_ServedCells->ref_value().select_id_ServedCells().push_back(*elm);
+
+ return true;
+}
+
+bool x2ap_create_X2SetupResponse(x2ap_pdu_t* pdu, eNB_config &cfg)
+{
+ X2APpduWrapper* pduWrapper = reinterpret_cast<X2APpduWrapper*>(pdu);
+
+ /* Initiaization */
+ pduWrapper->ref_pdu().select_successfulOutcome().ref_procedureCode().select_id_x2Setup();
+ pduWrapper->ref_pdu().select_successfulOutcome().ref_criticality().select_id_x2Setup();
+
+ X2SetupResponse* container =
+ &(pduWrapper->ref_pdu().select_successfulOutcome().ref_value().select_id_x2Setup());
+
+ using IE_value_t = X2SetupResponse::protocolIEs_t::value_type;
+
+ /* X2SetupResponse-IEs : GlobalENB-ID*/
+ IE_value_t* val_GlobalENB_ID = new IE_value_t;
+ container->ref_protocolIEs().push_back(*val_GlobalENB_ID);
+
+ val_GlobalENB_ID->ref_id().select_id_GlobalENB_ID();
+ val_GlobalENB_ID->ref_criticality().select_id_GlobalENB_ID();
+ val_GlobalENB_ID->ref_value().select_id_GlobalENB_ID().ref_pLMN_Identity()
+ .set(3, cfg.pLMN_Identity);
+
+ val_GlobalENB_ID->ref_value().select_id_GlobalENB_ID().ref_eNB_ID()
+ .select_macro_eNB_ID().set_buffer(20, cfg.macro_eNB_ID);
+
+ /* X2SetupResponse-IEs : ServedCells*/
+ IE_value_t* val_ServedCells = new IE_value_t;
+ container->ref_protocolIEs().push_back(*val_ServedCells);
+
+ val_ServedCells->ref_id().select_id_ServedCells();
+ val_ServedCells->ref_criticality().select_id_ServedCells();
+ val_ServedCells->ref_value().select_id_ServedCells();
+
+ //Add servedCellInfo
+ ServedCells::value_type* elm = new ServedCells::value_type();
+ ServedCell_Information* info = &(elm->ref_servedCellInfo());
+ {
+ //Set ServedCell-Information: pCI, cellId, tAC, broadcastPLMNs, eUTRA-Mode-Info
+ info->ref_pCI().set(cfg.pCI);
+ info->ref_cellId().ref_pLMN_Identity().set(3, cfg.pLMN_Identity);
+ info->ref_cellId().ref_eUTRANcellIdentifier().set_buffer(28, cfg.eUTRANcellIdentifier);
+ info->ref_tAC().set(2, cfg.tAC);
+
+ BroadcastPLMNs_Item::value_type* item = new BroadcastPLMNs_Item::value_type();
+ item->set(3, cfg.pLMN_Identity);
+ info->ref_broadcastPLMNs().push_back(*item);
+
+ info->ref_eUTRA_Mode_Info().select_fDD().ref_uL_EARFCN().set(cfg.uL_EARFCN);
+ info->ref_eUTRA_Mode_Info().select_fDD().ref_dL_EARFCN().set(cfg.dL_EARFCN);
+ info->ref_eUTRA_Mode_Info().select_fDD().ref_uL_Transmission_Bandwidth()
+ .set(static_cast<Transmission_Bandwidth::index_t>(cfg.uL_Bandwidth));
+ info->ref_eUTRA_Mode_Info().select_fDD().ref_dL_Transmission_Bandwidth()
+ .set(static_cast<Transmission_Bandwidth::index_t>(cfg.dL_Bandwidth));
+ }
+ val_ServedCells->ref_value().select_id_ServedCells().push_back(*elm);
+
+ return true;
+}
+
+bool x2ap_create_X2SetupFailure(x2ap_pdu_t* pdu)
+{
+ X2APpduWrapper* pduWrapper = reinterpret_cast<X2APpduWrapper*>(pdu);
+
+ /* Initiaization */
+ pduWrapper->ref_pdu().select_unsuccessfulOutcome().ref_procedureCode().select_id_x2Setup();
+ pduWrapper->ref_pdu().select_unsuccessfulOutcome().ref_criticality().select_id_x2Setup();
+
+ X2SetupFailure* container =
+ &(pduWrapper->ref_pdu().select_unsuccessfulOutcome().ref_value().select_id_x2Setup());
+
+ using IE_value_t = X2SetupFailure::protocolIEs_t::value_type;
+
+ /* X2SetupFailure-IEs << id-Cause */
+ IE_value_t* val_cause = new IE_value_t;
+ container->ref_protocolIEs().push_back(*val_cause);
+
+ val_cause->ref_id().select_id_Cause();
+ val_cause->ref_criticality().select_id_Cause();
+
+ /* Cause << radioNetwork */
+ val_cause->ref_value().select_id_Cause().select_radioNetwork();
+
+ /* CauseRadioNetwork = ho-target-not-allowed (enum = 8)*/
+ val_cause->ref_value().select_id_Cause().select_radioNetwork()
+ .set(static_cast<CauseRadioNetwork::index_t>(8));
+
+ return true;
+}
+
+//ENDCX2Setup
+bool x2ap_create_ENDCX2SetupRequest(x2ap_pdu_t* pdu, eNB_config &cfg)
+{
+ X2APpduWrapper* pduWrapper = reinterpret_cast<X2APpduWrapper*>(pdu);
+
+ /* Initiaization */
+ pduWrapper->ref_pdu().select_initiatingMessage().ref_procedureCode().select_id_endcX2Setup();
+ pduWrapper->ref_pdu().select_initiatingMessage().ref_criticality().select_id_endcX2Setup();
+
+ ENDCX2SetupRequest* container =
+ &(pduWrapper->ref_pdu().select_initiatingMessage().ref_value().select_id_endcX2Setup());
+
+ using IE_value_t = ENDCX2SetupRequest::protocolIEs_t::value_type;
+
+ /* ENDCX2SetupRequest-IEs = id-InitiatingNodeType-EndcX2Setup */
+ IE_value_t* ie = new IE_value_t;
+ container->ref_protocolIEs().push_back(*ie);
+ ie->ref_id().select_id_InitiatingNodeType_EndcX2Setup();
+ ie->ref_criticality().select_id_InitiatingNodeType_EndcX2Setup();
+ ie->ref_value().select_id_InitiatingNodeType_EndcX2Setup();
+
+ /* InitiatingNodeType-EndcX2Setup = init-eNB {ENB-ENDCX2SetupReqIEs} */
+ ie->ref_value().select_id_InitiatingNodeType_EndcX2Setup().select_init_eNB();
+
+ using eNB_val_t = InitiatingNodeType_EndcX2Setup::init_eNB_t::value_type;
+
+ ProtocolIE_Container<ENB_ENDCX2SetupReqIEs>* eNB_node =
+ &(ie->ref_value().select_id_InitiatingNodeType_EndcX2Setup().select_init_eNB());
+
+ /* ENB-ENDCX2SetupReqIEs <-- id-GlobalENB-ID */
+ eNB_val_t* val_GlobalENB_ID = new eNB_val_t;
+ eNB_node->push_back(*val_GlobalENB_ID);
+
+ val_GlobalENB_ID->ref_id().select_id_GlobalENB_ID();
+ val_GlobalENB_ID->ref_criticality().select_id_GlobalENB_ID();
+ val_GlobalENB_ID->ref_value().select_id_GlobalENB_ID()
+ .ref_pLMN_Identity().set(3, cfg.pLMN_Identity);
+ val_GlobalENB_ID->ref_value().select_id_GlobalENB_ID().ref_eNB_ID()
+ .select_macro_eNB_ID().set_buffer(20, cfg.macro_eNB_ID);
+
+ /* ENB-ENDCX2SetupReqIEs <-- id-ServedEUTRAcellsENDCX2ManagementList */
+ eNB_val_t* val_EUTRAlist = new eNB_val_t;
+ eNB_node->push_back(*val_EUTRAlist);
+
+ val_EUTRAlist->ref_id().select_id_ServedEUTRAcellsENDCX2ManagementList();
+ val_EUTRAlist->ref_criticality().select_id_ServedEUTRAcellsENDCX2ManagementList();
+ val_EUTRAlist->ref_value().select_id_ServedEUTRAcellsENDCX2ManagementList();
+
+ /* ServedEUTRAcellsENDCX2ManagementList <-- servedEUTRACellInfo */
+ ServedEUTRAcellsENDCX2ManagementList::value_type* elm =
+ new ServedEUTRAcellsENDCX2ManagementList::value_type();
+ ServedCell_Information* info = &(elm->ref_servedEUTRACellInfo());
+ {
+ //Set ServedCell-Information: pCI, cellId, tAC, broadcastPLMNs, eUTRA-Mode-Info
+ info->ref_pCI().set(cfg.pCI);
+ info->ref_cellId().ref_pLMN_Identity().set(3, cfg.pLMN_Identity);
+ info->ref_cellId().ref_eUTRANcellIdentifier().set_buffer(28, cfg.eUTRANcellIdentifier);
+ info->ref_tAC().set(2, cfg.tAC);
+
+ BroadcastPLMNs_Item::value_type* item = new BroadcastPLMNs_Item::value_type();
+ item->set(3, cfg.pLMN_Identity);
+ info->ref_broadcastPLMNs().push_back(*item);
+
+ info->ref_eUTRA_Mode_Info().select_fDD().ref_uL_EARFCN().set(cfg.uL_EARFCN);
+ info->ref_eUTRA_Mode_Info().select_fDD().ref_dL_EARFCN().set(cfg.dL_EARFCN);
+ info->ref_eUTRA_Mode_Info().select_fDD().ref_uL_Transmission_Bandwidth()
+ .set(static_cast<Transmission_Bandwidth::index_t>(cfg.uL_Bandwidth));
+ info->ref_eUTRA_Mode_Info().select_fDD().ref_dL_Transmission_Bandwidth()
+ .set(static_cast<Transmission_Bandwidth::index_t>(cfg.dL_Bandwidth));
+ }
+ val_EUTRAlist->ref_value().select_id_ServedEUTRAcellsENDCX2ManagementList()
+ .push_back(*elm);
+
+ return true;
+}
+
+/*-----------------------------------------------------------------------
+ TESTS
+-------------------------------------------------------------------------
+*/
+void test_X2Setup_codec(void)
+{
+ x2ap_pdu_t* pdu = new_x2ap_pdu();
+
+ eNB_config cfg;
+ x2ap_create_X2SetupRequest(pdu, cfg);
+
+ char pdu_str[1024];
+ x2ap_asn_print(pdu, pdu_str, sizeof(pdu_str));
+ printf("%s\n", pdu_str);
+
+ //Test encode
+ unsigned char packed_buf[4096];
+ char err_buf[1024];
+
+ int packed_len = x2ap_asn_per_encode(pdu, packed_buf, sizeof(packed_buf),
+ err_buf, sizeof(err_buf));
+ if(packed_len != -1) {
+ printf("Encode successful, packed_len = %d\n", packed_len);
+ } else {
+ printf("Encode Error: %s\n", err_buf);
+ }
+
+ //Test encode error
+ x2ap_pdu_t* pdu1 = new_x2ap_pdu();
+ x2ap_init_X2SetupRequest(pdu1);
+
+ int packed_len1 = x2ap_asn_per_encode(pdu1, packed_buf, sizeof(packed_buf),
+ err_buf, sizeof(err_buf));
+ if(packed_len1 != -1) {
+ printf("Encode successful, packed_len = %d\n", packed_len1);
+ } else {
+ printf("Encode Error: %s\n", err_buf);
+ }
+
+ //Test decode
+ x2ap_pdu_t* pdu2 = new_x2ap_pdu();
+ int rc = x2ap_asn_per_decode(pdu2, packed_buf, packed_len, err_buf, sizeof(err_buf));
+ if(rc == -1) {
+ printf("Decode error: %s\n", err_buf);
+ } else {
+ printf("Decode successful\n");
+ }
+
+ x2ap_asn_print(pdu2, pdu_str, sizeof(pdu_str));
+ printf("%s\n", pdu_str);
+
+ printf("index = %d\n", x2ap_get_index(pdu2));
+ printf("procedureCode = %d\n", x2ap_get_procedureCode(pdu2));
+
+
+ //Test decode error
+ x2ap_pdu_t* pdu3 = new_x2ap_pdu();
+ int rc2 = x2ap_asn_per_decode(pdu3, packed_buf, 1, err_buf, sizeof(err_buf));
+ if(rc2 == -1) {
+ printf("Decode error: %s\n", err_buf);
+ } else {
+ printf("Decode successful\n");
+ }
+
+ //Test X2SetupResponse
+ x2ap_pdu_t* pdu_resp = new_x2ap_pdu();
+ x2ap_create_X2SetupResponse(pdu_resp, cfg);
+ x2ap_asn_print(pdu_resp, pdu_str, sizeof(pdu_str));
+ printf("%s\n", pdu_str);
+
+ //Test X2SetupFailure
+ x2ap_pdu_t* pdu_failure = new_x2ap_pdu();
+ x2ap_create_X2SetupFailure(pdu_failure);
+ x2ap_asn_print(pdu_failure, pdu_str, sizeof(pdu_str));
+ printf("%s \n", pdu_str);
+}