207 lines
8.3 KiB
C
207 lines
8.3 KiB
C
/*
|
|
* SPDX-License-Identifier: LicenseRef-CSSL-1.0
|
|
*/
|
|
|
|
#include "f1ap_common.h"
|
|
#include "f1ap_du_interface_management.h"
|
|
#include "f1ap_du_ue_context_management.h"
|
|
#include "f1ap_du_rrc_message_transfer.h"
|
|
#include "lib/f1ap_rrc_message_transfer.h"
|
|
#include "lib/f1ap_interface_management.h"
|
|
#include "lib/f1ap_ue_context.h"
|
|
#include "f1ap_du_task.h"
|
|
#include <openair3/ocp-gtpu/gtp_itf.h>
|
|
|
|
//Fixme: Uniq dirty DU instance, by global var, datamodel need better management
|
|
instance_t DUuniqInstance=0;
|
|
|
|
static instance_t du_create_gtpu_instance_to_cu(const f1ap_net_config_t *nc)
|
|
{
|
|
openAddr_t tmp = {0};
|
|
strncpy(tmp.originHost, nc->DU_f1u_ip_address, sizeof(tmp.originHost) - 1);
|
|
strncpy(tmp.destinationHost, nc->CU_f1_ip_address, sizeof(tmp.destinationHost) - 1);
|
|
sprintf(tmp.originService, "%d", nc->DUport);
|
|
sprintf(tmp.destinationService, "%d", nc->CUport);
|
|
return gtpv1Init(tmp);
|
|
}
|
|
|
|
void du_task_send_sctp_association_req(instance_t instance, f1ap_net_config_t *nc)
|
|
{
|
|
DevAssert(nc != NULL);
|
|
MessageDef *message_p = NULL;
|
|
sctp_new_association_req_t *sctp_new_association_req_p = NULL;
|
|
message_p = itti_alloc_new_message(TASK_DU_F1, 0, SCTP_NEW_ASSOCIATION_REQ);
|
|
sctp_new_association_req_p = &message_p->ittiMsg.sctp_new_association_req;
|
|
sctp_new_association_req_p->ulp_cnx_id = instance;
|
|
sctp_new_association_req_p->port = F1AP_PORT_NUMBER;
|
|
sctp_new_association_req_p->ppid = F1AP_SCTP_PPID;
|
|
sctp_new_association_req_p->in_streams = 2; //du_inst->sctp_in_streams;
|
|
sctp_new_association_req_p->out_streams = 2; //du_inst->sctp_out_streams;
|
|
// remote
|
|
sctp_new_association_req_p->remote_address.ipv4 = 1;
|
|
strncpy(sctp_new_association_req_p->remote_address.ipv4_address,
|
|
nc->CU_f1_ip_address,
|
|
sizeof(sctp_new_association_req_p->remote_address.ipv4_address) - 1);
|
|
// local
|
|
sctp_new_association_req_p->local_address.ipv4 = 1;
|
|
strncpy(sctp_new_association_req_p->local_address.ipv4_address,
|
|
nc->DU_f1c_ip_address,
|
|
sizeof(sctp_new_association_req_p->local_address.ipv4_address) - 1);
|
|
LOG_D(F1AP,
|
|
"Local IPv4 Address: %s, Remote IPv4 Address: %s\n",
|
|
sctp_new_association_req_p->local_address.ipv4_address,
|
|
sctp_new_association_req_p->remote_address.ipv4_address);
|
|
|
|
// du_f1ap_register_to_sctp
|
|
itti_send_msg_to_task(TASK_SCTP, instance, message_p);
|
|
}
|
|
|
|
void du_task_handle_sctp_association_resp(instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp) {
|
|
DevAssert(sctp_new_association_resp != NULL);
|
|
f1ap_cudu_inst_t *f1ap_du_data = getCxt(instance);
|
|
DevAssert(f1ap_du_data != NULL);
|
|
|
|
if (sctp_new_association_resp->sctp_state != SCTP_STATE_ESTABLISHED) {
|
|
LOG_W(F1AP, "Received unsuccessful result for SCTP association (%u), instance %ld, cnx_id %u, retrying...\n",
|
|
sctp_new_association_resp->sctp_state,
|
|
instance,
|
|
sctp_new_association_resp->ulp_cnx_id);
|
|
sleep(3);
|
|
du_task_send_sctp_association_req(instance, &f1ap_du_data->net_config);
|
|
return; // exit -1 for debugging
|
|
}
|
|
|
|
// save the assoc id
|
|
f1ap_du_data->du.assoc_id = sctp_new_association_resp->assoc_id;
|
|
f1ap_du_data->sctp_in_streams = sctp_new_association_resp->in_streams;
|
|
f1ap_du_data->sctp_out_streams = sctp_new_association_resp->out_streams;
|
|
/* next transaction ID */
|
|
f1ap_du_data->setupReq.transaction_id = F1AP_get_next_transaction_identifier(0, 0);
|
|
/* setup parameters for F1U and start the server */
|
|
DU_send_F1_SETUP_REQUEST(f1ap_du_data->du.assoc_id, &f1ap_du_data->setupReq);
|
|
}
|
|
|
|
void du_task_handle_sctp_data_ind(instance_t instance, sctp_data_ind_t *sctp_data_ind) {
|
|
int result;
|
|
DevAssert(sctp_data_ind != NULL);
|
|
f1ap_handle_message(instance, sctp_data_ind->assoc_id, sctp_data_ind->stream,
|
|
sctp_data_ind->buffer, sctp_data_ind->buffer_length);
|
|
result = itti_free(TASK_UNKNOWN, sctp_data_ind->buffer);
|
|
AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
|
|
}
|
|
|
|
void *F1AP_DU_task(void *arg)
|
|
{
|
|
UNUSED(arg);
|
|
//sctp_cu_init();
|
|
LOG_I(F1AP, "Starting F1AP at DU\n");
|
|
itti_mark_task_ready(TASK_DU_F1);
|
|
|
|
// SCTP
|
|
while (1) {
|
|
MessageDef *msg = NULL;
|
|
itti_receive_msg(TASK_DU_F1, &msg);
|
|
instance_t myInstance=ITTI_MSG_DESTINATION_INSTANCE(msg);
|
|
sctp_assoc_t assoc_id = getCxt(0) != NULL ? getCxt(0)->du.assoc_id : 0;
|
|
LOG_D(F1AP, "DU Task Received %s for instance %ld: sending SCTP messages via assoc_id %d\n", ITTI_MSG_NAME(msg), myInstance, assoc_id);
|
|
switch (ITTI_MSG_ID(msg)) {
|
|
case F1AP_SETUP_REQ:
|
|
AssertFatal(false, "the F1AP_SETUP_REQ should not be received; use the F1AP_DU_REGISTER_REQ instead\n");
|
|
break;
|
|
|
|
case F1AP_DU_REGISTER_REQ: {
|
|
// this is not a true F1 message, but rather an ITTI message sent by gnb_app
|
|
// 1. save the itti msg so that you can use it to sen f1ap_setup_req, fill the f1ap_setup_req message,
|
|
// 2. store the message in f1ap context, that is also stored in RC
|
|
// 2. send a sctp_association req
|
|
f1ap_setup_req_t *msgSetup = &F1AP_DU_REGISTER_REQ(msg).setup_req;
|
|
f1ap_net_config_t *nc = &F1AP_DU_REGISTER_REQ(msg).net_config;
|
|
createF1inst(myInstance, msgSetup, nc);
|
|
du_task_send_sctp_association_req(myInstance, nc);
|
|
instance_t gtpInst = du_create_gtpu_instance_to_cu(nc);
|
|
AssertFatal(gtpInst > 0, "cannot create DU F1-U GTP module\n");
|
|
getCxt(myInstance)->gtpInst = gtpInst;
|
|
DUuniqInstance = gtpInst;
|
|
} break;
|
|
|
|
case F1AP_RESET_ACK:
|
|
DU_send_RESET_ACKNOWLEDGE(assoc_id, &F1AP_RESET_ACK(msg));
|
|
free_f1ap_reset_ack(&F1AP_RESET_ACK(msg));
|
|
break;
|
|
|
|
case F1AP_GNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE:
|
|
DU_send_gNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE(assoc_id,
|
|
&F1AP_GNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE(msg));
|
|
break;
|
|
|
|
case F1AP_GNB_CU_CONFIGURATION_UPDATE_FAILURE:
|
|
DU_send_gNB_CU_CONFIGURATION_UPDATE_FAILURE(assoc_id,
|
|
&F1AP_GNB_CU_CONFIGURATION_UPDATE_FAILURE(msg));
|
|
break;
|
|
|
|
case SCTP_NEW_ASSOCIATION_RESP:
|
|
// 1. store the respon
|
|
// 2. send the f1setup_req
|
|
du_task_handle_sctp_association_resp(myInstance,
|
|
&msg->ittiMsg.sctp_new_association_resp);
|
|
break;
|
|
|
|
case SCTP_DATA_IND:
|
|
// ex: any F1 incoming message for DU ends here
|
|
du_task_handle_sctp_data_ind(myInstance,
|
|
&msg->ittiMsg.sctp_data_ind);
|
|
break;
|
|
|
|
case F1AP_INITIAL_UL_RRC_MESSAGE: // from rrc
|
|
DU_send_INITIAL_UL_RRC_MESSAGE_TRANSFER(assoc_id, &F1AP_INITIAL_UL_RRC_MESSAGE(msg));
|
|
break;
|
|
|
|
case F1AP_UL_RRC_MESSAGE: // to rrc
|
|
DU_send_UL_NR_RRC_MESSAGE_TRANSFER(assoc_id, &F1AP_UL_RRC_MESSAGE(msg));
|
|
free_ul_rrc_message_transfer(&F1AP_UL_RRC_MESSAGE(msg));
|
|
break;
|
|
|
|
case F1AP_UE_CONTEXT_SETUP_RESP:
|
|
DU_send_UE_CONTEXT_SETUP_RESPONSE(assoc_id, &F1AP_UE_CONTEXT_SETUP_RESP(msg));
|
|
free_ue_context_setup_resp(&F1AP_UE_CONTEXT_SETUP_RESP(msg));
|
|
break;
|
|
|
|
case F1AP_UE_CONTEXT_MODIFICATION_RESP:
|
|
DU_send_UE_CONTEXT_MODIFICATION_RESPONSE(assoc_id, &F1AP_UE_CONTEXT_MODIFICATION_RESP(msg));
|
|
break;
|
|
|
|
case F1AP_UE_CONTEXT_RELEASE_REQ: // from MAC
|
|
DU_send_UE_CONTEXT_RELEASE_REQUEST(assoc_id,
|
|
&F1AP_UE_CONTEXT_RELEASE_REQ(msg));
|
|
break;
|
|
|
|
case F1AP_UE_CONTEXT_RELEASE_COMPLETE:
|
|
DU_send_UE_CONTEXT_RELEASE_COMPLETE(assoc_id, &F1AP_UE_CONTEXT_RELEASE_COMPLETE(msg));
|
|
break;
|
|
|
|
case F1AP_UE_CONTEXT_MODIFICATION_REQUIRED:
|
|
DU_send_UE_CONTEXT_MODIFICATION_REQUIRED(assoc_id, &F1AP_UE_CONTEXT_MODIFICATION_REQUIRED(msg));
|
|
break;
|
|
|
|
case F1AP_GNB_DU_CONFIGURATION_UPDATE:
|
|
DU_send_gNB_DU_CONFIGURATION_UPDATE(assoc_id, &F1AP_GNB_DU_CONFIGURATION_UPDATE(msg));
|
|
break;
|
|
|
|
case TERMINATE_MESSAGE:
|
|
LOG_W(F1AP, " *** Exiting F1AP thread\n");
|
|
itti_exit_task();
|
|
break;
|
|
|
|
default:
|
|
LOG_E(F1AP, "DU Received unhandled message: %d:%s\n",
|
|
ITTI_MSG_ID(msg), ITTI_MSG_NAME(msg));
|
|
break;
|
|
} // switch
|
|
|
|
int result = itti_free (ITTI_MSG_ORIGIN_ID(msg), msg);
|
|
AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
|
|
} // while
|
|
|
|
return NULL;
|
|
}
|