mirror of
https://gitlab.eurecom.fr/oai/openairinterface5g.git
synced 2026-07-16 06:00:28 +00:00
Compare commits
4 Commits
multipleam
...
ru-comment
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
09fea055f4 | ||
|
|
231dab91d9 | ||
|
|
9d5b0df464 | ||
|
|
2cf7ac7908 |
@@ -498,10 +498,10 @@ class Containerize():
|
||||
elif image != 'ran-build':
|
||||
cmd.run(f'sed -i -e "s#ran-build:latest#ran-build:{imageTag}#" docker/Dockerfile.{pattern}{self.dockerfileprefix}')
|
||||
if image == 'oai-gnb-aerial':
|
||||
cmd.run('cp -f /opt/nvidia-ipc/nvipc.src.2025.05.20.tar.gz .')
|
||||
cmd.run('cp -f /opt/nvidia-ipc/nvipc_src.*.tar.gz .')
|
||||
ret = cmd.run(f'{self.cli} build {self.cliBuildOptions} --target {image} --tag {name}:{imageTag} --file docker/Dockerfile.{pattern}{self.dockerfileprefix} {option} . > cmake_targets/log/{name}.log 2>&1', timeout=1200)
|
||||
if image == 'oai-gnb-aerial':
|
||||
cmd.run('rm -f nvipc.src.2025.05.20.tar.gz')
|
||||
cmd.run('rm -f nvipc_src.*.tar.gz')
|
||||
if image == 'ran-build' and ret.returncode == 0:
|
||||
cmd.run(f"docker run --name test-log -d {name}:{imageTag} /bin/true")
|
||||
cmd.run(f"docker cp test-log:/oai-ran/cmake_targets/log/ cmake_targets/log/{name}/")
|
||||
|
||||
@@ -23,7 +23,7 @@ services:
|
||||
- ../../../cmake_targets/share:/opt/cuBB/share
|
||||
userns_mode: host
|
||||
ipc: "shareable"
|
||||
image: cubb-build:25-1
|
||||
image: cubb-build:24-3
|
||||
environment:
|
||||
- cuBB_SDK=/opt/nvidia/cuBB
|
||||
command: bash -c "sudo rm -rf /tmp/phy.log && sudo chmod +x /opt/nvidia/cuBB/aerial_l1_entrypoint.sh && /opt/nvidia/cuBB/aerial_l1_entrypoint.sh"
|
||||
@@ -33,7 +33,7 @@ services:
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
oai-gnb-aerial:
|
||||
cpuset: "13-14"
|
||||
cpuset: "13-20"
|
||||
image: ${REGISTRY:-oaisoftwarealliance}/oai-gnb-aerial:${TAG:-develop}
|
||||
depends_on:
|
||||
nv-cubb:
|
||||
|
||||
@@ -45,14 +45,6 @@ typedef struct nr_guami_s {
|
||||
uint8_t amf_pointer;
|
||||
} nr_guami_t;
|
||||
|
||||
typedef enum {
|
||||
PDUSessionType_ipv4 = 0,
|
||||
PDUSessionType_ipv6 = 1,
|
||||
PDUSessionType_ipv4v6 = 2,
|
||||
PDUSessionType_ethernet = 3,
|
||||
PDUSessionType_unstructured = 4
|
||||
} pdu_session_type_t;
|
||||
|
||||
typedef enum { NON_DYNAMIC, DYNAMIC } fiveQI_t;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -218,27 +218,25 @@ typedef struct nr_lcid_rb_t {
|
||||
} nr_lcid_rb_t;
|
||||
|
||||
typedef struct transport_layer_addr_s {
|
||||
/** Transport Layer Address in bytes:
|
||||
* - 4 bytes for IPv4 (RFC 791), 16 bytes for IPv6 (RFC 2460),
|
||||
* - 20 bytes for both IPv4 and IPv6, with IPv4 in the first 4 bytes. */
|
||||
/**
|
||||
* Transport Layer Address as a bitstring:
|
||||
* - 32 bits for IPv4 (RFC 791),
|
||||
* - 128 bits for IPv6 (RFC 2460),
|
||||
* - 160 bits for both IPv4 and IPv6, with IPv4 in the first 32 bits.
|
||||
* The S1AP/NGAP layer forwards this address (bitstring<1..160>)
|
||||
* to S1-U/NG-U without interpreting it.
|
||||
*/
|
||||
uint8_t length;
|
||||
/// Buffer: address in network byte order
|
||||
uint8_t buffer[20];
|
||||
} transport_layer_addr_t;
|
||||
|
||||
/** @brief GTP tunnel configuration */
|
||||
typedef struct {
|
||||
// Tunnel endpoint identifier
|
||||
uint32_t teid;
|
||||
// Transport layer address
|
||||
transport_layer_addr_t addr;
|
||||
} gtpu_tunnel_t;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// GTPV1U TYPES
|
||||
//-----------------------------------------------------------------------------
|
||||
typedef uint32_t teid_t; // tunnel endpoint identifier
|
||||
typedef uint8_t ebi_t; // eps bearer id
|
||||
typedef uint8_t pdusessionid_t;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
@@ -123,10 +123,11 @@ void seq_arr_erase_it(seq_arr_t* arr, void* start_it, void* end_it, void (*free_
|
||||
return;
|
||||
|
||||
if (free_func != NULL) {
|
||||
void* it = start_it;
|
||||
while (it != end_it) {
|
||||
free_func(it);
|
||||
it = seq_arr_next(arr, it);
|
||||
void* start_it = seq_arr_front(arr);
|
||||
void* end_it = seq_arr_end(arr);
|
||||
while (start_it != end_it) {
|
||||
free_func(start_it);
|
||||
start_it = seq_arr_next(arr, start_it);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,13 +36,6 @@ static int compar(const void* m0, const void* m1)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int free_func_call_count = 0;
|
||||
|
||||
static void dummy_free_func(void* it)
|
||||
{
|
||||
++free_func_call_count;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
seq_arr_t arr = {0};
|
||||
@@ -90,19 +83,6 @@ int main()
|
||||
void* it = bsearch(&key, base, nmemb, size, compar);
|
||||
assert(seq_arr_dist(&arr, seq_arr_front(&arr), it) == 4);
|
||||
|
||||
// Regression test: erase a partial range only
|
||||
// Erase 92, 93, 94 (i.e., indices 1 to 3)
|
||||
int* start = seq_arr_at(&arr, 1);
|
||||
int* end = seq_arr_at(&arr, 4);
|
||||
seq_arr_erase_it(&arr, start, end, dummy_free_func);
|
||||
|
||||
// Now values should be: [91, 95, 96, 97, 98, 99]
|
||||
assert(free_func_call_count == 3);
|
||||
assert(seq_arr_size(&arr) == 6);
|
||||
assert(*(int*)seq_arr_at(&arr, 0) == 91);
|
||||
assert(*(int*)seq_arr_at(&arr, 1) == 95);
|
||||
assert(*(int*)seq_arr_at(&arr, 5) == 99);
|
||||
|
||||
// Free data structure
|
||||
seq_arr_free(&arr, NULL);
|
||||
|
||||
|
||||
@@ -52,6 +52,7 @@ typedef struct ShmTDIQChannel_s {
|
||||
char name[256];
|
||||
sample_t *tx_iq_data;
|
||||
sample_t *rx_iq_data;
|
||||
bool abort;
|
||||
} ShmTDIQChannel;
|
||||
|
||||
ShmTDIQChannel *shm_td_iq_channel_create(const char *name, int num_tx_ant, int num_rx_ant)
|
||||
@@ -228,9 +229,6 @@ IQChannelErrorType shm_td_iq_channel_rx(ShmTDIQChannel *channel,
|
||||
void shm_td_iq_channel_produce_samples(ShmTDIQChannel *channel, size_t num_samples)
|
||||
{
|
||||
ShmTDIQChannelData *data = channel->data;
|
||||
if (channel->type != IQ_CHANNEL_TYPE_SERVER) {
|
||||
return;
|
||||
}
|
||||
if (data->is_connected == false) {
|
||||
return;
|
||||
}
|
||||
@@ -240,10 +238,11 @@ void shm_td_iq_channel_produce_samples(ShmTDIQChannel *channel, size_t num_sampl
|
||||
mutexunlock(data->mutex);
|
||||
}
|
||||
|
||||
void shm_td_iq_channel_wait(ShmTDIQChannel *channel, uint64_t timestamp)
|
||||
void shm_td_iq_channel_wait(ShmTDIQChannel *channel, uint64_t timestamp, uint64_t timeout_uS)
|
||||
{
|
||||
ShmTDIQChannelData *data = channel->data;
|
||||
if (data->is_connected == false) {
|
||||
fprintf(stderr, "Error: Channel is not connected.\n");
|
||||
abort();
|
||||
return;
|
||||
}
|
||||
@@ -252,13 +251,41 @@ void shm_td_iq_channel_wait(ShmTDIQChannel *channel, uint64_t timestamp)
|
||||
if (current_timestamp >= timestamp) {
|
||||
return;
|
||||
}
|
||||
mutexlock(data->mutex);
|
||||
while (current_timestamp < timestamp) {
|
||||
condwait(data->cond, data->mutex);
|
||||
current_timestamp = data->timestamp;
|
||||
if (timeout_uS == 0) {
|
||||
mutexlock(data->mutex);
|
||||
while (current_timestamp < timestamp && !channel->abort) {
|
||||
condwait(data->cond, data->mutex);
|
||||
current_timestamp = data->timestamp;
|
||||
}
|
||||
mutexunlock(data->mutex);
|
||||
} else {
|
||||
struct timespec ts = {.tv_sec = 0, .tv_nsec = 0};
|
||||
if (clock_gettime(CLOCK_REALTIME, &ts) != 0) {
|
||||
fprintf(stderr, "Error: clock_gettime failed: %s\n", strerror(errno));
|
||||
channel->abort = true;
|
||||
return;
|
||||
}
|
||||
|
||||
ts.tv_sec += timeout_uS / 1000000; // Convert microseconds to seconds
|
||||
ts.tv_nsec += (timeout_uS % 1000000) * 1000; // Convert remaining microseconds to nanoseconds
|
||||
|
||||
mutexlock(data->mutex);
|
||||
while (current_timestamp < timestamp && !channel->abort) {
|
||||
int ret = pthread_cond_timedwait(&data->cond, &data->mutex, &ts);
|
||||
if (ret == ETIMEDOUT) {
|
||||
channel->abort = true;
|
||||
fprintf(stderr, "Error: Timed out waiting for samples. Aborting vrtsim\n");\
|
||||
break;
|
||||
} else if (ret != 0) {
|
||||
channel->abort = true;
|
||||
fprintf(stderr, "Error: pthread_cond_timedwait failed: %s\n", strerror(ret));
|
||||
break;
|
||||
} else {
|
||||
current_timestamp = data->timestamp;
|
||||
}
|
||||
}
|
||||
mutexunlock(data->mutex);
|
||||
}
|
||||
mutexunlock(data->mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t shm_td_iq_channel_get_current_sample(const ShmTDIQChannel *channel)
|
||||
@@ -272,15 +299,32 @@ bool shm_td_iq_channel_is_connected(const ShmTDIQChannel *channel)
|
||||
return channel->data->is_connected;
|
||||
}
|
||||
|
||||
void shm_td_iq_channel_abort(ShmTDIQChannel *channel)
|
||||
{
|
||||
ShmTDIQChannelData *data = channel->data;
|
||||
mutexlock(data->mutex);
|
||||
channel->abort = true;
|
||||
condbroadcast(data->cond);
|
||||
mutexunlock(data->mutex);
|
||||
}
|
||||
|
||||
bool shm_td_iq_channel_is_aborted(const ShmTDIQChannel *channel)
|
||||
{
|
||||
return channel->abort;
|
||||
}
|
||||
|
||||
void shm_td_iq_channel_destroy(ShmTDIQChannel *channel)
|
||||
{
|
||||
ShmTDIQChannelData *data = channel->data;
|
||||
size_t tx_buffer_size = CIRCULAR_BUFFER_SIZE * sizeof(sample_t) * data->num_antennas_tx;
|
||||
size_t rx_buffer_size = CIRCULAR_BUFFER_SIZE * sizeof(sample_t) * data->num_antennas_rx;
|
||||
size_t total_size = sizeof(ShmTDIQChannelData) + tx_buffer_size + rx_buffer_size;
|
||||
munmap(data, total_size);
|
||||
if (channel->type == IQ_CHANNEL_TYPE_SERVER) {
|
||||
data->is_connected = false;
|
||||
munmap(data, total_size);
|
||||
shm_unlink(channel->name);
|
||||
} else {
|
||||
munmap(data, total_size);
|
||||
}
|
||||
free(channel);
|
||||
}
|
||||
|
||||
@@ -118,8 +118,10 @@ void shm_td_iq_channel_produce_samples(ShmTDIQChannel *channel, uint64_t num_sam
|
||||
* @brief Wait until sample at the specified timestamp is available
|
||||
*
|
||||
* @param channel The ShmTDIQChannel structure.
|
||||
* @param timestamp The timestamp for which to wait.
|
||||
* @param timeout_uS The timeout in microseconds to wait for the sample. 0 means wait indefinitely.
|
||||
*/
|
||||
void shm_td_iq_channel_wait(ShmTDIQChannel *channel, uint64_t timestamp);
|
||||
void shm_td_iq_channel_wait(ShmTDIQChannel *channel, uint64_t timestamp, uint64_t timeout_uS);
|
||||
|
||||
/**
|
||||
* @brief Checks if the IQ channel is connected.
|
||||
@@ -129,6 +131,21 @@ void shm_td_iq_channel_wait(ShmTDIQChannel *channel, uint64_t timestamp);
|
||||
*/
|
||||
bool shm_td_iq_channel_is_connected(const ShmTDIQChannel *channel);
|
||||
|
||||
/**
|
||||
* @brief Aborts the IQ channel causing the wait to return immediately
|
||||
*
|
||||
* @param channel The ShmTDIQChannel structure.
|
||||
*/
|
||||
void shm_td_iq_channel_abort(ShmTDIQChannel *channel);
|
||||
|
||||
/**
|
||||
* @brief Checks if the IQ channel is aborted.
|
||||
*
|
||||
* @param channel The ShmTDIQChannel structure.
|
||||
* @return True if the channel is aborted, false otherwise.
|
||||
*/
|
||||
bool shm_td_iq_channel_is_aborted(const ShmTDIQChannel *channel);
|
||||
|
||||
/**
|
||||
* @brief Destroys the shared memory IQ channel.
|
||||
*
|
||||
|
||||
@@ -104,7 +104,7 @@ void server(void)
|
||||
uint64_t timestamp = 0;
|
||||
int iq_contents = 0;
|
||||
while (timestamp < num_samples_per_update * num_updates) {
|
||||
shm_td_iq_channel_wait(channel, timestamp + num_samples_per_update);
|
||||
shm_td_iq_channel_wait(channel, timestamp + num_samples_per_update, 0);
|
||||
uint64_t target_timestamp = timestamp + num_samples_per_update;
|
||||
timestamp += num_samples_per_update;
|
||||
uint32_t iq_data[num_samples_per_update];
|
||||
@@ -141,7 +141,7 @@ int client(void)
|
||||
int iq_contents = 0;
|
||||
|
||||
while (timestamp < num_samples_per_update * num_updates) {
|
||||
shm_td_iq_channel_wait(channel, timestamp + num_samples_per_update);
|
||||
shm_td_iq_channel_wait(channel, timestamp + num_samples_per_update, 0);
|
||||
// Server starts producing from second slot
|
||||
if (timestamp > num_samples_per_update) {
|
||||
uint64_t target_timestamp = timestamp - num_samples_per_update;
|
||||
|
||||
@@ -45,7 +45,7 @@ WORKDIR /oai-ran
|
||||
COPY . .
|
||||
|
||||
RUN /bin/sh oaienv && \
|
||||
tar -xvzf nvipc* && \
|
||||
tar -xvzf nvipc_src.*.tar.gz && \
|
||||
cd nvipc_src.* && \
|
||||
rm -rf build && mkdir build && cd build && \
|
||||
cmake .. -DNVIPC_DPDK_ENABLE=OFF -DNVIPC_DOCA_ENABLE=OFF -DNVIPC_CUDA_ENABLE=OFF -DENABLE_SLT_RSP=ON && \
|
||||
|
||||
@@ -45,7 +45,7 @@ WORKDIR /oai-ran
|
||||
COPY . .
|
||||
|
||||
RUN /bin/sh oaienv && \
|
||||
tar -xvzf nvipc* && \
|
||||
tar -xvzf nvipc_src.*.tar.gz && \
|
||||
cd nvipc_src.* && \
|
||||
rm -rf build && mkdir build && cd build && \
|
||||
cmake .. -DNVIPC_DPDK_ENABLE=OFF -DNVIPC_DOCA_ENABLE=OFF -DNVIPC_CUDA_ENABLE=OFF -DENABLE_SLT_RSP=ON && \
|
||||
|
||||
@@ -1252,6 +1252,7 @@ void *ru_thread(void *param)
|
||||
// synchronization on input FH interface, acquire signals/data and block
|
||||
LOG_D(PHY,"[RU_thread] read data: frame_rx = %d, tti_rx = %d\n", frame, slot);
|
||||
|
||||
/// BPODRYGAJLO: RU read IQ data. Get frame and slot from here every slot
|
||||
if (ru->fh_south_in) ru->fh_south_in(ru,&frame,&slot);
|
||||
else AssertFatal(1==0, "No fronthaul interface at south port");
|
||||
|
||||
@@ -1291,6 +1292,7 @@ void *ru_thread(void *param)
|
||||
if (!wait_free_rx_tti(&gNB->L1_rx_out, rx_tti_busy, proc->frame_rx, proc->tti_rx))
|
||||
break; // nothing to wait for: we have to stop
|
||||
if (ru->feprx) {
|
||||
/// BPODRYGAJLO: Front end processing (most likely dft)
|
||||
ru->feprx(ru,proc->tti_rx);
|
||||
LOG_D(NR_PHY, "Setting %d.%d (%d) to busy\n", proc->frame_rx, proc->tti_rx, proc->tti_rx % RU_RX_SLOT_DEPTH);
|
||||
//LOG_M("rxdata.m","rxs",ru->common.rxdata[0],1228800,1,1);
|
||||
@@ -1303,7 +1305,7 @@ void *ru_thread(void *param)
|
||||
gNB->frame_parms.samples_per_slot_wCP,
|
||||
proc->tti_rx * gNB->frame_parms.samples_per_slot_wCP);
|
||||
|
||||
// Do PRACH RU processing
|
||||
// Do PRACH RU processing BPODRYGAJLO: ONLY IF CONFIGURED
|
||||
int prach_id = find_nr_prach_ru(ru, proc->frame_rx, proc->tti_rx, SEARCH_EXIST);
|
||||
if (prach_id >= 0) {
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_RU_PRACH_RX, 1 );
|
||||
@@ -1337,6 +1339,7 @@ void *ru_thread(void *param)
|
||||
} // end if (ru->feprx)
|
||||
} // end if (slot_type == NR_UPLINK_SLOT || slot_type == NR_MIXED_SLOT) {
|
||||
|
||||
// BPODRYGAJLO: This is supposed to trigger TX eventually
|
||||
notifiedFIFO_elt_t *resTx = newNotifiedFIFO_elt(sizeof(processingData_L1tx_t), 0, &gNB->L1_tx_out, NULL);
|
||||
processingData_L1tx_t *syncMsgTx = NotifiedFifoData(resTx);
|
||||
syncMsgTx->gNB = gNB;
|
||||
|
||||
@@ -385,6 +385,8 @@ void nr_fep_tp(RU_t *ru, int slot) {
|
||||
feprx_cmd->endSymbol = ru->nr_frame_parms->symbols_per_slot - 1;
|
||||
|
||||
task_t t = {.func = nr_fep, .args = feprx_cmd};
|
||||
|
||||
// start thread BPODRYGAJLO: This is the thread pool for FEP RX
|
||||
pushTpool(ru->threadPool, t);
|
||||
|
||||
nbfeprx++;
|
||||
|
||||
@@ -77,6 +77,8 @@ typedef struct {
|
||||
struct complexd **a;
|
||||
///interpolated (sample-spaced) channel impulse response. size(ch) = (n_tx * n_rx) * channel_length. ATTENTION: the dimensions of ch are the transposed ones of a. This is to allow the use of BLAS when applying the correlation matrices to the state.
|
||||
struct complexd **ch;
|
||||
///Same as above but single precision
|
||||
struct complexf **ch_ps;
|
||||
///Sampled frequency response (90 kHz resolution)
|
||||
struct complexd **chF;
|
||||
///Maximum path delay in mus.
|
||||
|
||||
@@ -163,7 +163,7 @@ typedef struct gtpv1u_gnb_create_tunnel_req_s {
|
||||
int num_tunnels;
|
||||
teid_t outgoing_teid[NR_GTPV1U_MAX_BEARERS_PER_UE];
|
||||
int outgoing_qfi[NR_GTPV1U_MAX_BEARERS_PER_UE];
|
||||
int pdusession_id[NR_GTPV1U_MAX_BEARERS_PER_UE];
|
||||
pdusessionid_t pdusession_id[NR_GTPV1U_MAX_BEARERS_PER_UE];
|
||||
ebi_t incoming_rb_id[NR_GTPV1U_MAX_BEARERS_PER_UE];
|
||||
transport_layer_addr_t dst_addr[NR_GTPV1U_MAX_BEARERS_PER_UE];
|
||||
} gtpv1u_gnb_create_tunnel_req_t;
|
||||
@@ -173,13 +173,13 @@ typedef struct gtpv1u_gnb_create_tunnel_resp_s {
|
||||
ue_id_t ue_id;
|
||||
int num_tunnels;
|
||||
teid_t gnb_NGu_teid[NR_GTPV1U_MAX_BEARERS_PER_UE]; ///< Tunnel Endpoint Identifier
|
||||
int pdusession_id[NR_GTPV1U_MAX_BEARERS_PER_UE];
|
||||
pdusessionid_t pdusession_id[NR_GTPV1U_MAX_BEARERS_PER_UE];
|
||||
transport_layer_addr_t gnb_addr;
|
||||
} gtpv1u_gnb_create_tunnel_resp_t;
|
||||
typedef struct gtpv1u_gnb_delete_tunnel_req_s {
|
||||
ue_id_t ue_id;
|
||||
uint8_t num_pdusession;
|
||||
int pdusession_id[NR_GTPV1U_MAX_BEARERS_PER_UE];
|
||||
pdusessionid_t pdusession_id[NR_GTPV1U_MAX_BEARERS_PER_UE];
|
||||
} gtpv1u_gnb_delete_tunnel_req_t;
|
||||
|
||||
typedef struct gtpv1u_gnb_delete_tunnel_resp_s {
|
||||
@@ -192,7 +192,7 @@ typedef struct gtpv1u_gnb_delete_tunnel_resp_s {
|
||||
typedef struct gtpv1u_DU_buffer_report_req_s {
|
||||
uint32_t buffer_availability;
|
||||
ue_id_t ue_id;
|
||||
int pdusession_id;
|
||||
pdusessionid_t pdusession_id;
|
||||
} gtpv1u_DU_buffer_report_req_t;
|
||||
|
||||
#endif /* GTPV1_U_MESSAGES_TYPES_H_ */
|
||||
|
||||
@@ -71,6 +71,9 @@ MESSAGE_DEF(NGAP_UE_CTXT_MODIFICATION_FAIL , MESSAGE_PRIORITY_MED, ngap_ue_ctxt_
|
||||
MESSAGE_DEF(NGAP_PDUSESSION_SETUP_RESP , MESSAGE_PRIORITY_MED, ngap_pdusession_setup_resp_t , ngap_pdusession_setup_resp)
|
||||
MESSAGE_DEF(NGAP_PDUSESSION_MODIFY_RESP , MESSAGE_PRIORITY_MED, ngap_pdusession_modify_resp_t , ngap_pdusession_modify_resp)
|
||||
MESSAGE_DEF(NGAP_PDUSESSION_RELEASE_RESPONSE , MESSAGE_PRIORITY_MED, ngap_pdusession_release_resp_t , ngap_pdusession_release_resp)
|
||||
MESSAGE_DEF(NGAP_PATH_SWITCH_REQ , MESSAGE_PRIORITY_MED, ngap_path_switch_req_t , ngap_path_switch_req)
|
||||
MESSAGE_DEF(NGAP_PATH_SWITCH_REQ_ACK , MESSAGE_PRIORITY_MED, ngap_path_switch_req_ack_t , ngap_path_switch_req_ack)
|
||||
MESSAGE_DEF(NGAP_PDUSESSION_MODIFICATION_IND , MESSAGE_PRIORITY_MED, ngap_pdusession_modification_ind_t , ngap_pdusession_modification_ind)
|
||||
|
||||
/* NGAP -> RRC messages */
|
||||
MESSAGE_DEF(NGAP_DOWNLINK_NAS , MESSAGE_PRIORITY_MED, ngap_downlink_nas_t , ngap_downlink_nas )
|
||||
|
||||
@@ -231,6 +231,36 @@ typedef struct ngap_mobility_restriction_s{
|
||||
ngap_plmn_identity_t serving_plmn;
|
||||
}ngap_mobility_restriction_t;
|
||||
|
||||
typedef enum pdu_session_type_e {
|
||||
PDUSessionType_ipv4 = 0,
|
||||
PDUSessionType_ipv6 = 1,
|
||||
PDUSessionType_ipv4v6 = 2,
|
||||
PDUSessionType_ethernet = 3,
|
||||
PDUSessionType_unstructured = 4
|
||||
}pdu_session_type_t;
|
||||
|
||||
typedef struct pdusession_s {
|
||||
/* Unique pdusession_id for the UE. */
|
||||
int pdusession_id;
|
||||
byte_array_t nas_pdu;
|
||||
byte_array_t pdusessionTransfer;
|
||||
uint8_t nb_qos;
|
||||
/* Quality of service for this pdusession */
|
||||
pdusession_level_qos_parameter_t qos[QOSFLOW_MAX_VALUE];
|
||||
/* The transport layer address for the IP packets */
|
||||
pdu_session_type_t pdu_session_type;
|
||||
transport_layer_addr_t upf_addr;
|
||||
/* Outgoing (UL) NG-U Tunnel Endpoint Identifier (S-GW/UPF) */
|
||||
uint32_t gtp_teid;
|
||||
/* Incoming (DL) NG-U Tunnel Endpoint Identifier (S-GW/UPF) */
|
||||
uint32_t gNB_teid_N3;
|
||||
transport_layer_addr_t gNB_addr_N3;
|
||||
/* Incoming (DL) NG-U Tunnel Endpoint Identifier (S-GW/UPF) */
|
||||
uint32_t UPF_teid_N3;
|
||||
transport_layer_addr_t UPF_addr_N3;
|
||||
nssai_t nssai;
|
||||
} pdusession_t;
|
||||
|
||||
typedef enum pdusession_qosflow_mapping_ind_e{
|
||||
QOSFLOW_MAPPING_INDICATION_UL = 0,
|
||||
QOSFLOW_MAPPING_INDICATION_DL = 1,
|
||||
@@ -248,9 +278,10 @@ typedef struct pdusession_setup_s {
|
||||
|
||||
/* The transport layer address for the IP packets */
|
||||
uint8_t pdu_session_type;
|
||||
transport_layer_addr_t gNB_addr;
|
||||
|
||||
// NG-U (N3) Tunnel Endpoint on the RAN side
|
||||
gtpu_tunnel_t n3_outgoing;
|
||||
/* Incoming NG-U Tunnel Endpoint Identifier (S-GW/UPF) */
|
||||
uint32_t gtp_teid;
|
||||
|
||||
/* qos flow list number */
|
||||
uint8_t nb_of_qos_flow;
|
||||
@@ -259,6 +290,18 @@ typedef struct pdusession_setup_s {
|
||||
pdusession_associate_qosflow_t associated_qos_flows[QOSFLOW_MAX_VALUE];
|
||||
} pdusession_setup_t;
|
||||
|
||||
typedef struct pdusession_tobeswitched_s {
|
||||
/* Unique pdusession_id for the UE. */
|
||||
uint8_t pdusession_id;
|
||||
|
||||
/* The transport layer address for the IP packets */
|
||||
uint8_t pdu_session_type;
|
||||
transport_layer_addr_t upf_addr;
|
||||
|
||||
/* S-GW Tunnel endpoint identifier */
|
||||
uint32_t gtp_teid;
|
||||
} pdusession_tobeswitched_t;
|
||||
|
||||
typedef struct qos_flow_tobe_modified_s {
|
||||
uint8_t qfi; // 0~63
|
||||
} qos_flow_tobe_modified_t;
|
||||
@@ -537,22 +580,6 @@ typedef struct ngap_downlink_nas_s {
|
||||
byte_array_t nas_pdu;
|
||||
} ngap_downlink_nas_t;
|
||||
|
||||
/* PDU Session Resource Setup Request Transfer (9.3.4.1 3GPP TS 38.413) */
|
||||
typedef struct {
|
||||
uint8_t nb_qos;
|
||||
pdusession_level_qos_parameter_t qos[QOSFLOW_MAX_VALUE];
|
||||
pdu_session_type_t pdu_session_type;
|
||||
// UPF endpoint of the NG-U (N3) transport bearer
|
||||
gtpu_tunnel_t n3_incoming;
|
||||
} pdusession_transfer_t;
|
||||
|
||||
/* PDU Session Resource Setup/Modify Request Item */
|
||||
typedef struct {
|
||||
int pdusession_id;
|
||||
byte_array_t nas_pdu;
|
||||
nssai_t nssai;
|
||||
pdusession_transfer_t pdusessionTransfer;
|
||||
} pdusession_resource_item_t;
|
||||
|
||||
typedef struct ngap_initial_context_setup_req_s {
|
||||
/* UE id for initial connection to NGAP */
|
||||
@@ -578,8 +605,8 @@ typedef struct ngap_initial_context_setup_req_s {
|
||||
|
||||
/* Number of pdusession to be setup in the list */
|
||||
uint8_t nb_of_pdusessions;
|
||||
// PDU Session Resource Setup Request List
|
||||
pdusession_resource_item_t pdusession[NGAP_MAX_PDU_SESSION];
|
||||
/* list of pdusession to be setup by RRC layers */
|
||||
pdusession_t pdusession_param[NGAP_MAX_PDU_SESSION];
|
||||
|
||||
/* Mobility Restriction List */
|
||||
uint8_t mobility_restriction_flag;
|
||||
@@ -613,6 +640,13 @@ typedef struct ngap_paging_ind_s {
|
||||
ngap_paging_priority_t paging_priority;
|
||||
} ngap_paging_ind_t;
|
||||
|
||||
typedef struct {
|
||||
/* Unique pdusession_id for the UE. */
|
||||
int pdusession_id;
|
||||
byte_array_t nas_pdu;
|
||||
byte_array_t pdusessionTransfer;
|
||||
} pdusession_setup_req_t;
|
||||
|
||||
typedef struct ngap_pdusession_setup_req_s {
|
||||
/* UE id for initial connection to NGAP */
|
||||
uint32_t gNB_ue_ngap_id;
|
||||
@@ -627,8 +661,8 @@ typedef struct ngap_pdusession_setup_req_s {
|
||||
/* Number of pdusession to be setup in the list */
|
||||
uint8_t nb_pdusessions_tosetup;
|
||||
|
||||
// PDU Session Resource Setup Request List
|
||||
pdusession_resource_item_t pdusession[NGAP_MAX_PDU_SESSION];
|
||||
/* E RAB setup request */
|
||||
pdusession_t pdusession_setup_params[NGAP_MAX_PDU_SESSION];
|
||||
|
||||
/* UE Aggregated Max Bitrates */
|
||||
ngap_ambr_t ueAggMaxBitRate;
|
||||
@@ -648,6 +682,78 @@ typedef struct ngap_pdusession_setup_resp_s {
|
||||
pdusession_failed_t pdusessions_failed[NGAP_MAX_PDU_SESSION];
|
||||
} ngap_pdusession_setup_resp_t;
|
||||
|
||||
typedef struct ngap_path_switch_req_s {
|
||||
uint32_t gNB_ue_ngap_id;
|
||||
|
||||
/* Number of pdusession setup-ed in the list */
|
||||
uint8_t nb_of_pdusessions;
|
||||
|
||||
/* list of pdusession setup-ed by RRC layers */
|
||||
pdusession_setup_t pdusessions_tobeswitched[NGAP_MAX_PDU_SESSION];
|
||||
|
||||
/* AMF UE id */
|
||||
uint64_t amf_ue_ngap_id;
|
||||
|
||||
nr_guami_t ue_guami;
|
||||
|
||||
uint16_t ue_initial_id;
|
||||
/* Security algorithms */
|
||||
ngap_security_capabilities_t security_capabilities;
|
||||
|
||||
} ngap_path_switch_req_t;
|
||||
|
||||
typedef struct ngap_path_switch_req_ack_s {
|
||||
|
||||
/* UE id for initial connection to NGAP */
|
||||
uint16_t ue_initial_id;
|
||||
|
||||
uint32_t gNB_ue_ngap_id;
|
||||
|
||||
/* AMF UE id */
|
||||
uint64_t amf_ue_ngap_id;
|
||||
|
||||
/* UE aggregate maximum bitrate */
|
||||
ngap_ambr_t ue_ambr;
|
||||
|
||||
/* Number of pdusession setup-ed in the list */
|
||||
uint8_t nb_pdusessions_tobeswitched;
|
||||
|
||||
/* list of pdusession to be switched by RRC layers */
|
||||
pdusession_tobeswitched_t pdusessions_tobeswitched[NGAP_MAX_PDU_SESSION];
|
||||
|
||||
/* Number of pdusessions to be released by RRC */
|
||||
uint8_t nb_pdusessions_tobereleased;
|
||||
|
||||
/* list of pdusessions to be released */
|
||||
pdusession_failed_t pdusessions_tobereleased[NGAP_MAX_PDU_SESSION];
|
||||
|
||||
/* Security key */
|
||||
int next_hop_chain_count;
|
||||
uint8_t next_security_key[SECURITY_KEY_LENGTH];
|
||||
|
||||
} ngap_path_switch_req_ack_t;
|
||||
|
||||
typedef struct ngap_pdusession_modification_ind_s {
|
||||
|
||||
uint32_t gNB_ue_ngap_id;
|
||||
|
||||
/* AMF UE id */
|
||||
uint64_t amf_ue_ngap_id;
|
||||
|
||||
/* Number of pdusession setup-ed in the list */
|
||||
uint8_t nb_of_pdusessions_tobemodified;
|
||||
|
||||
uint8_t nb_of_pdusessions_nottobemodified;
|
||||
|
||||
/* list of pdusession setup-ed by RRC layers */
|
||||
pdusession_setup_t pdusessions_tobemodified[NGAP_MAX_PDU_SESSION];
|
||||
|
||||
pdusession_setup_t pdusessions_nottobemodified[NGAP_MAX_PDU_SESSION];
|
||||
|
||||
uint16_t ue_initial_id;
|
||||
|
||||
} ngap_pdusession_modification_ind_t;
|
||||
|
||||
// NGAP --> RRC messages
|
||||
typedef struct ngap_ue_release_command_s {
|
||||
|
||||
@@ -683,8 +789,8 @@ typedef struct ngap_pdusession_modify_req_s {
|
||||
/* Number of pdusession to be modify in the list */
|
||||
uint8_t nb_pdusessions_tomodify;
|
||||
|
||||
// PDU Session Resource Modify Request List
|
||||
pdusession_resource_item_t pdusession[NGAP_MAX_PDU_SESSION];
|
||||
/* pdu session modify request */
|
||||
pdusession_t pdusession_modify_params[NGAP_MAX_PDU_SESSION];
|
||||
} ngap_pdusession_modify_req_t;
|
||||
|
||||
typedef struct ngap_pdusession_modify_resp_s {
|
||||
|
||||
@@ -65,8 +65,8 @@ bool read_gtp_sm(void * data)
|
||||
int nb_pdu_session = ue_context_p->ue_context.nb_of_pdusessions;
|
||||
if (nb_pdu_session > 0) {
|
||||
int nb_pdu_idx = nb_pdu_session - 1;
|
||||
gtp->msg.ngut[i].teidgnb = ue_context_p->ue_context.pduSession[nb_pdu_idx].param.n3_outgoing.teid;
|
||||
gtp->msg.ngut[i].teidupf = ue_context_p->ue_context.pduSession[nb_pdu_idx].param.n3_incoming.teid;
|
||||
gtp->msg.ngut[i].teidgnb = ue_context_p->ue_context.pduSession[nb_pdu_idx].param.gNB_teid_N3;
|
||||
gtp->msg.ngut[i].teidupf = ue_context_p->ue_context.pduSession[nb_pdu_idx].param.UPF_teid_N3;
|
||||
// TODO: one PDU session has multiple QoS Flow
|
||||
int nb_qos_flow = ue_context_p->ue_context.pduSession[nb_pdu_idx].param.nb_qos;
|
||||
if (nb_qos_flow > 0) {
|
||||
|
||||
@@ -269,7 +269,7 @@ static rnti_t lcid_crnti_lookahead(uint8_t *pdu, uint32_t pdu_len)
|
||||
if (lcid == UL_SCH_LCID_C_RNTI) {
|
||||
// Extract C-RNTI value
|
||||
rnti_t crnti = ((pdu[1] & 0xFF) << 8) | (pdu[2] & 0xFF);
|
||||
LOG_A(NR_MAC, "Received a MAC CE for C-RNTI with %04x\n", crnti);
|
||||
LOG_D(NR_MAC, "Received a MAC CE for C-RNTI with %04x\n", crnti);
|
||||
return crnti;
|
||||
} else if (lcid == UL_SCH_LCID_PADDING) {
|
||||
// End of MAC PDU, can ignore the remaining bytes
|
||||
@@ -783,33 +783,26 @@ static void nr_rx_ra_sdu(const module_id_t mod_id,
|
||||
// Reset HARQ processes
|
||||
reset_dl_harq_list(&old_UE->UE_sched_ctrl);
|
||||
reset_ul_harq_list(&old_UE->UE_sched_ctrl);
|
||||
|
||||
// Only trigger RRCReconfiguration if UE is not performing RRCReestablishment
|
||||
// The RRCReconfiguration will be triggered by the RRCReestablishmentComplete
|
||||
if (!old_UE->reconfigSpCellConfig) {
|
||||
LOG_I(NR_MAC, "Received UL_SCH_LCID_C_RNTI with C-RNTI 0x%04x, triggering RRC Reconfiguration\n", crnti);
|
||||
// Trigger RRCReconfiguration
|
||||
nr_mac_trigger_reconfiguration(mac, old_UE);
|
||||
// we configure the UE using common search space with DCIX0 while waiting for a reconfiguration
|
||||
configure_UE_BWP(mac, scc, old_UE, false, NR_SearchSpace__searchSpaceType_PR_common, -1, -1);
|
||||
}
|
||||
// Trigger RRC Reconfiguration
|
||||
LOG_I(NR_MAC, "Received UL_SCH_LCID_C_RNTI with C-RNTI 0x%04x, triggering RRC Reconfiguration\n", crnti);
|
||||
nr_mac_trigger_reconfiguration(mac, old_UE);
|
||||
nr_release_ra_UE(mac, rnti);
|
||||
LOG_A(NR_MAC, "%4d.%2d RA with C-RNTI %04x complete\n", frame, slot, crnti);
|
||||
|
||||
// Decode the entire MAC PDU
|
||||
// It may have multiple MAC subPDUs, for example, a MAC subPDU with LCID 1 caring a RRCReestablishmentComplete
|
||||
LOG_A(NR_MAC, "%4d.%2d UE %04x: RA with C-RNTI complete\n", frame, slot, crnti);
|
||||
// we configure the UE using common search space with DCIX0 while waiting for a reconfiguration
|
||||
configure_UE_BWP(mac, scc, old_UE, false, NR_SearchSpace__searchSpaceType_PR_common, -1, -1);
|
||||
// TODO do we actually need to still process the PDU?
|
||||
nr_process_mac_pdu(mod_id, old_UE, CC_id, frame, slot, sdu, sdu_len, -1);
|
||||
return;
|
||||
} else {
|
||||
// UE Contention Resolution Identity
|
||||
// Store the first 48 bits belonging to the uplink CCCH SDU within Msg3 to fill in Msg4
|
||||
// First byte corresponds to R/LCID MAC sub-header
|
||||
memcpy(ra->cont_res_id, &sdu[1], sizeof(uint8_t) * 6);
|
||||
}
|
||||
|
||||
// UE Contention Resolution Identity
|
||||
// Store the first 48 bits belonging to the uplink CCCH SDU within Msg3 to fill in Msg4
|
||||
// First byte corresponds to R/LCID MAC sub-header
|
||||
memcpy(ra->cont_res_id, &sdu[1], sizeof(uint8_t) * 6);
|
||||
|
||||
// Decode MAC PDU
|
||||
// Decode MAC PDU for the correct UE, after checking for MAC CE for C-RNTI
|
||||
// harq_pid set a non valid value because it is not used in this call
|
||||
// the function is only called to decode the contention resolution sub-header
|
||||
// harq_pid set a non-valid value because it is not used in this call
|
||||
nr_process_mac_pdu(mod_id, UE, CC_id, frame, slot, sdu, sdu_len, -1);
|
||||
|
||||
LOG_I(NR_MAC,
|
||||
|
||||
@@ -136,10 +136,10 @@ static void nr_pdcp_entity_recv_pdu(nr_pdcp_entity_t *entity,
|
||||
}
|
||||
|
||||
if (entity->has_ciphering)
|
||||
entity->decipher(entity->security_context,
|
||||
buffer + header_size + sdap_header_size,
|
||||
size - (header_size + sdap_header_size),
|
||||
entity->rb_id, rcvd_count, entity->is_gnb ? 0 : 1);
|
||||
entity->cipher(entity->security_context,
|
||||
buffer + header_size + sdap_header_size,
|
||||
size - (header_size + sdap_header_size),
|
||||
entity->rb_id, rcvd_count, entity->is_gnb ? 0 : 1);
|
||||
|
||||
if (entity->has_integrity) {
|
||||
unsigned char integrity[PDCP_INTEGRITY_SIZE] = {0};
|
||||
@@ -380,12 +380,10 @@ static void nr_pdcp_entity_set_security(struct nr_pdcp_entity_t *entity,
|
||||
if (parameters->ciphering_algorithm == 2) {
|
||||
entity->security_context = nr_pdcp_security_nea2_init(entity->security_keys_and_algos.ciphering_key);
|
||||
entity->cipher = nr_pdcp_security_nea2_cipher;
|
||||
entity->decipher = nr_pdcp_security_nea2_cipher;
|
||||
entity->free_security = nr_pdcp_security_nea2_free_security;
|
||||
} else if (parameters->ciphering_algorithm == 1) {
|
||||
entity->security_context = nr_pdcp_security_nea1_init(entity->security_keys_and_algos.ciphering_key);
|
||||
entity->cipher = nr_pdcp_security_nea1_cipher;
|
||||
entity->decipher = nr_pdcp_security_nea1_cipher;
|
||||
entity->free_security = nr_pdcp_security_nea1_free_security;
|
||||
} else {
|
||||
LOG_E(PDCP, "FATAL: only nea1 and nea2 supported for the moment\n");
|
||||
|
||||
@@ -156,9 +156,6 @@ typedef struct nr_pdcp_entity_t {
|
||||
void (*cipher)(stream_security_context_t *security_context,
|
||||
unsigned char *buffer, int length,
|
||||
int bearer, uint32_t count, int direction);
|
||||
void (*decipher)(stream_security_context_t *security_context,
|
||||
unsigned char *buffer, int length,
|
||||
int bearer, uint32_t count, int direction);
|
||||
void (*free_security)(stream_security_context_t *security_context);
|
||||
stream_security_context_t *integrity_context;
|
||||
void (*integrity)(stream_security_context_t *integrity_context,
|
||||
|
||||
@@ -99,22 +99,6 @@ typedef enum pdu_session_satus_e {
|
||||
PDU_SESSION_STATUS_RELEASED
|
||||
} pdu_session_status_t;
|
||||
|
||||
typedef struct pdusession_s {
|
||||
/* Unique pdusession_id for the UE. */
|
||||
int pdusession_id;
|
||||
byte_array_t nas_pdu;
|
||||
uint8_t nb_qos;
|
||||
/* Quality of service for this pdusession */
|
||||
pdusession_level_qos_parameter_t qos[QOSFLOW_MAX_VALUE];
|
||||
/* The transport layer address for the IP packets */
|
||||
pdu_session_type_t pdu_session_type;
|
||||
// NG-RAN endpoint of the NG-U (N3) transport bearer
|
||||
gtpu_tunnel_t n3_outgoing;
|
||||
// UPF endpoint of the NG-U (N3) transport bearer
|
||||
gtpu_tunnel_t n3_incoming;
|
||||
nssai_t nssai;
|
||||
} pdusession_t;
|
||||
|
||||
typedef struct pdu_session_param_s {
|
||||
pdusession_t param;
|
||||
pdu_session_status_t status;
|
||||
@@ -122,6 +106,16 @@ typedef struct pdu_session_param_s {
|
||||
ngap_cause_t cause;
|
||||
} rrc_pdu_session_param_t;
|
||||
|
||||
/**
|
||||
* @brief F1-U tunnel configuration
|
||||
*/
|
||||
typedef struct f1u_tunnel_s {
|
||||
/* F1-U Tunnel Endpoint Identifier (on DU side) */
|
||||
uint32_t teid;
|
||||
/* Downlink F1-U Transport Layer (on DU side) */
|
||||
transport_layer_addr_t addr;
|
||||
} f1u_tunnel_t;
|
||||
|
||||
typedef struct drb_s {
|
||||
int status;
|
||||
int drb_id;
|
||||
@@ -151,9 +145,9 @@ typedef struct drb_s {
|
||||
} ext1;
|
||||
} pdcp_config;
|
||||
// F1-U Downlink Tunnel Config (on DU side)
|
||||
gtpu_tunnel_t du_tunnel_config;
|
||||
f1u_tunnel_t du_tunnel_config;
|
||||
// F1-U Uplink Tunnel Config (on CU-UP side)
|
||||
gtpu_tunnel_t cuup_tunnel_config;
|
||||
f1u_tunnel_t cuup_tunnel_config;
|
||||
} drb_t;
|
||||
|
||||
typedef enum {
|
||||
|
||||
@@ -2004,13 +2004,14 @@ static void fill_e1_bearer_modif(DRB_nGRAN_to_mod_t *drb_e1, const f1ap_drb_to_b
|
||||
drb_e1->DlUpParamList[0].tl_info.teId = drb_f1->up_dl_tnl[0].teid;
|
||||
}
|
||||
|
||||
static gtpu_tunnel_t f1u_gtp_update(uint32_t teid, const in_addr_t addr)
|
||||
/**
|
||||
* @brief Store F1-U DL TL and TEID in RRC
|
||||
*/
|
||||
static void f1u_dl_gtp_update(f1u_tunnel_t *f1u, const f1ap_up_tnl_t *p)
|
||||
{
|
||||
gtpu_tunnel_t out = {0};
|
||||
out.teid = teid;
|
||||
memcpy(&out.addr.buffer, &addr, 4);
|
||||
out.addr.length = sizeof(addr);
|
||||
return out;
|
||||
f1u->teid = p->teid;
|
||||
memcpy(&f1u->addr.buffer, &p->tl_address, sizeof(uint8_t) * 4);
|
||||
f1u->addr.length = sizeof(in_addr_t);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2023,10 +2024,20 @@ static void store_du_f1u_tunnel(const f1ap_drb_to_be_setup_t *drbs, int n, gNB_R
|
||||
AssertFatal(drb_f1->up_dl_tnl_length == 1, "can handle only one UP param\n");
|
||||
AssertFatal(drb_f1->drb_id < MAX_DRBS_PER_UE, "illegal DRB ID %ld\n", drb_f1->drb_id);
|
||||
drb_t *drb = get_drb(ue, drb_f1->drb_id);
|
||||
drb->du_tunnel_config = f1u_gtp_update(drb_f1->up_dl_tnl[0].teid, drb_f1->up_dl_tnl[0].tl_address);
|
||||
f1u_dl_gtp_update(&drb->du_tunnel_config, &drb_f1->up_dl_tnl[0]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Store F1-U UL TEID and address in RRC
|
||||
*/
|
||||
static void f1u_ul_gtp_update(f1u_tunnel_t *f1u, const up_params_t *p)
|
||||
{
|
||||
f1u->teid = p->tl_info.teId;
|
||||
memcpy(&f1u->addr.buffer, &p->tl_info.tlAddress, sizeof(uint8_t) * 4);
|
||||
f1u->addr.length = sizeof(in_addr_t);
|
||||
}
|
||||
|
||||
/* \brief use list of DRBs and send the corresponding bearer update message via
|
||||
* E1 to the CU of this UE. Also updates TEID info internally */
|
||||
static void e1_send_bearer_updates(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, f1ap_drb_to_be_setup_t *drbs)
|
||||
@@ -2449,7 +2460,9 @@ void rrc_gNB_process_e1_bearer_context_setup_resp(e1ap_bearer_setup_resp_t *resp
|
||||
LOG_W(RRC, "E1: received setup for PDU session %ld, but has not been requested\n", e1_pdu->id);
|
||||
continue;
|
||||
}
|
||||
rrc_pdu->param.n3_outgoing = f1u_gtp_update(e1_pdu->tl_info.teId, e1_pdu->tl_info.tlAddress);
|
||||
rrc_pdu->param.gNB_teid_N3 = e1_pdu->tl_info.teId;
|
||||
memcpy(&rrc_pdu->param.gNB_addr_N3.buffer, &e1_pdu->tl_info.tlAddress, sizeof(uint8_t) * 4);
|
||||
rrc_pdu->param.gNB_addr_N3.length = sizeof(in_addr_t);
|
||||
|
||||
// save the tunnel address for the DRBs
|
||||
for (int i = 0; i < e1_pdu->numDRBSetup; i++) {
|
||||
@@ -2457,8 +2470,7 @@ void rrc_gNB_process_e1_bearer_context_setup_resp(e1ap_bearer_setup_resp_t *resp
|
||||
// numUpParam only relevant in F1, but not monolithic
|
||||
AssertFatal(drb_config->numUpParam <= 1, "can only up to one UP param\n");
|
||||
drb_t *drb = get_drb(UE, drb_config->id);
|
||||
UP_TL_information_t *tl_info = &drb_config->UpParamList[0].tl_info;
|
||||
drb->cuup_tunnel_config = f1u_gtp_update(tl_info->teId, tl_info->tlAddress);
|
||||
f1u_ul_gtp_update(&drb->cuup_tunnel_config, &drb_config->UpParamList[0]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
#include "E1AP_ConfidentialityProtectionIndication.h"
|
||||
#include "E1AP_IntegrityProtectionIndication.h"
|
||||
#include "NGAP_CauseRadioNetwork.h"
|
||||
@@ -162,20 +161,6 @@ static nr_guami_t get_guami(const uint32_t amf_Id, const plmn_id_t plmn)
|
||||
return guami;
|
||||
}
|
||||
|
||||
/** @brief Copy NGAP PDU Session Resource item to RRC pdusession_t struct */
|
||||
static void cp_pdusession_resource_item_to_pdusession(pdusession_t *dst, const pdusession_resource_item_t *src)
|
||||
{
|
||||
dst->pdusession_id = src->pdusession_id;
|
||||
dst->nas_pdu = src->nas_pdu;
|
||||
dst->nb_qos = src->pdusessionTransfer.nb_qos;
|
||||
for (uint8_t i = 0; i < src->pdusessionTransfer.nb_qos && i < QOSFLOW_MAX_VALUE; ++i) {
|
||||
dst->qos[i] = src->pdusessionTransfer.qos[i];
|
||||
}
|
||||
dst->pdu_session_type = src->pdusessionTransfer.pdu_session_type;
|
||||
dst->n3_incoming = src->pdusessionTransfer.n3_incoming;
|
||||
dst->nssai = src->nssai;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Prepare the Initial UE Message (Uplink NAS) to be forwarded to the AMF over N2
|
||||
* extracts NAS PDU, Selected PLMN and Registered AMF from the RRCSetupComplete
|
||||
@@ -240,6 +225,114 @@ void rrc_gNB_send_NGAP_NAS_FIRST_REQ(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, NR_RRC
|
||||
itti_send_msg_to_task(TASK_NGAP, rrc->module_id, message_p);
|
||||
}
|
||||
|
||||
static void fill_qos(NGAP_QosFlowSetupRequestList_t *qos, pdusession_t *session)
|
||||
{
|
||||
DevAssert(qos->list.count > 0);
|
||||
DevAssert(qos->list.count <= NGAP_maxnoofQosFlows);
|
||||
for (int qosIdx = 0; qosIdx < qos->list.count; qosIdx++) {
|
||||
NGAP_QosFlowSetupRequestItem_t *qosFlowItem_p = qos->list.array[qosIdx];
|
||||
// Set the QOS informations
|
||||
session->qos[qosIdx].qfi = (uint8_t)qosFlowItem_p->qosFlowIdentifier;
|
||||
NGAP_QosCharacteristics_t *qosChar = &qosFlowItem_p->qosFlowLevelQosParameters.qosCharacteristics;
|
||||
AssertFatal(qosChar, "Qos characteristics are not available for qos flow index %d\n", qosIdx);
|
||||
if (qosChar->present == NGAP_QosCharacteristics_PR_nonDynamic5QI) {
|
||||
AssertFatal(qosChar->choice.dynamic5QI, "Non-Dynamic 5QI is NULL\n");
|
||||
session->qos[qosIdx].fiveQI_type = NON_DYNAMIC;
|
||||
session->qos[qosIdx].fiveQI = (uint64_t)qosChar->choice.nonDynamic5QI->fiveQI;
|
||||
} else {
|
||||
AssertFatal(qosChar->choice.dynamic5QI, "Dynamic 5QI is NULL\n");
|
||||
session->qos[qosIdx].fiveQI_type = DYNAMIC;
|
||||
session->qos[qosIdx].fiveQI = (uint64_t)(*qosChar->choice.dynamic5QI->fiveQI);
|
||||
}
|
||||
|
||||
ngap_allocation_retention_priority_t *tmp = &session->qos[qosIdx].allocation_retention_priority;
|
||||
NGAP_AllocationAndRetentionPriority_t *tmp2 = &qosFlowItem_p->qosFlowLevelQosParameters.allocationAndRetentionPriority;
|
||||
tmp->priority_level = tmp2->priorityLevelARP;
|
||||
tmp->pre_emp_capability = tmp2->pre_emptionCapability;
|
||||
tmp->pre_emp_vulnerability = tmp2->pre_emptionVulnerability;
|
||||
}
|
||||
session->nb_qos = qos->list.count;
|
||||
}
|
||||
|
||||
static int decodePDUSessionResourceSetup(pdusession_t *session)
|
||||
{
|
||||
NGAP_PDUSessionResourceSetupRequestTransfer_t *pdusessionTransfer = NULL;
|
||||
asn_codec_ctx_t st = {.max_stack_size = 100 * 1000};
|
||||
asn_dec_rval_t dec_rval = aper_decode(&st,
|
||||
&asn_DEF_NGAP_PDUSessionResourceSetupRequestTransfer,
|
||||
(void **)&pdusessionTransfer,
|
||||
session->pdusessionTransfer.buf,
|
||||
session->pdusessionTransfer.len,
|
||||
0,
|
||||
0);
|
||||
|
||||
if (dec_rval.code != RC_OK) {
|
||||
LOG_E(NR_RRC, "can not decode PDUSessionResourceSetupRequestTransfer\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < pdusessionTransfer->protocolIEs.list.count; i++) {
|
||||
NGAP_PDUSessionResourceSetupRequestTransferIEs_t *pdusessionTransfer_ies = pdusessionTransfer->protocolIEs.list.array[i];
|
||||
switch (pdusessionTransfer_ies->id) {
|
||||
/* optional PDUSessionAggregateMaximumBitRate */
|
||||
case NGAP_ProtocolIE_ID_id_PDUSessionAggregateMaximumBitRate:
|
||||
break;
|
||||
|
||||
/* mandatory UL-NGU-UP-TNLInformation */
|
||||
case NGAP_ProtocolIE_ID_id_UL_NGU_UP_TNLInformation: {
|
||||
NGAP_GTPTunnel_t *gTPTunnel_p = pdusessionTransfer_ies->value.choice.UPTransportLayerInformation.choice.gTPTunnel;
|
||||
|
||||
/* Set the transport layer address */
|
||||
memcpy(session->upf_addr.buffer, gTPTunnel_p->transportLayerAddress.buf, gTPTunnel_p->transportLayerAddress.size);
|
||||
|
||||
session->upf_addr.length = gTPTunnel_p->transportLayerAddress.size * 8 - gTPTunnel_p->transportLayerAddress.bits_unused;
|
||||
|
||||
/* GTP tunnel endpoint ID */
|
||||
OCTET_STRING_TO_INT32(&gTPTunnel_p->gTP_TEID, session->gtp_teid);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
/* optional AdditionalUL-NGU-UP-TNLInformation */
|
||||
case NGAP_ProtocolIE_ID_id_AdditionalUL_NGU_UP_TNLInformation:
|
||||
break;
|
||||
|
||||
/* optional DataForwardingNotPossible */
|
||||
case NGAP_ProtocolIE_ID_id_DataForwardingNotPossible:
|
||||
break;
|
||||
|
||||
/* mandatory PDUSessionType */
|
||||
case NGAP_ProtocolIE_ID_id_PDUSessionType:
|
||||
session->pdu_session_type = (uint8_t)pdusessionTransfer_ies->value.choice.PDUSessionType;
|
||||
break;
|
||||
|
||||
/* optional SecurityIndication */
|
||||
case NGAP_ProtocolIE_ID_id_SecurityIndication:
|
||||
break;
|
||||
|
||||
/* optional NetworkInstance */
|
||||
case NGAP_ProtocolIE_ID_id_NetworkInstance:
|
||||
break;
|
||||
|
||||
/* mandatory QosFlowSetupRequestList */
|
||||
case NGAP_ProtocolIE_ID_id_QosFlowSetupRequestList:
|
||||
fill_qos(&pdusessionTransfer_ies->value.choice.QosFlowSetupRequestList, session);
|
||||
break;
|
||||
|
||||
/* optional CommonNetworkInstance */
|
||||
case NGAP_ProtocolIE_ID_id_CommonNetworkInstance:
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_E(NR_RRC, "could not found protocolIEs id %ld\n", pdusessionTransfer_ies->id);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
ASN_STRUCT_FREE(asn_DEF_NGAP_PDUSessionResourceSetupRequestTransfer, pdusessionTransfer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Triggers bearer setup for the specified UE.
|
||||
*
|
||||
@@ -267,7 +360,13 @@ bool trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdusession
|
||||
for (int i = 0; i < n; i++) {
|
||||
rrc_pdu_session_param_t *pduSession = find_pduSession(UE, sessions[i].pdusession_id, true);
|
||||
pdusession_t *session = &pduSession->param;
|
||||
cp_pdusession(session, &sessions[i]);
|
||||
session->pdusession_id = sessions[i].pdusession_id;
|
||||
LOG_I(NR_RRC, "Adding pdusession %d, total nb of sessions %d\n", session->pdusession_id, UE->nb_of_pdusessions);
|
||||
session->pdu_session_type = sessions[i].pdu_session_type;
|
||||
session->nas_pdu = sessions[i].nas_pdu;
|
||||
session->pdusessionTransfer = sessions[i].pdusessionTransfer;
|
||||
session->nssai = sessions[i].nssai;
|
||||
decodePDUSessionResourceSetup(session);
|
||||
bearer_req.gNB_cu_cp_ue_id = UE->rrc_ue_id;
|
||||
security_information_t *secInfo = &bearer_req.secInfo;
|
||||
secInfo->cipheringAlgorithm = rrc->security.do_drb_ciphering ? UE->ciphering_algorithm : 0;
|
||||
@@ -287,12 +386,8 @@ bool trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdusession
|
||||
: SECURITY_NOT_NEEDED;
|
||||
sec->confidentialityProtectionIndication = rrc->security.do_drb_ciphering ? SECURITY_REQUIRED
|
||||
: SECURITY_NOT_NEEDED;
|
||||
gtpu_tunnel_t *n3_incoming = &session->n3_incoming;
|
||||
pdu->UP_TL_information.teId = n3_incoming->teid;
|
||||
memcpy(&pdu->UP_TL_information.tlAddress, n3_incoming->addr.buffer, sizeof(in_addr_t));
|
||||
char ip_str[INET_ADDRSTRLEN] = {0};
|
||||
inet_ntop(AF_INET, n3_incoming->addr.buffer, ip_str, sizeof(ip_str));
|
||||
LOG_I(NR_RRC, "Bearer Context Setup: PDU Session ID=%d, incoming TEID=0x%08x, Addr=%s\n", session->pdusession_id, n3_incoming->teid, ip_str);
|
||||
pdu->UP_TL_information.teId = session->gtp_teid;
|
||||
memcpy(&pdu->UP_TL_information.tlAddress, session->upf_addr.buffer, sizeof(in_addr_t));
|
||||
|
||||
/* we assume for the moment one DRB per PDU session. Activate the bearer,
|
||||
* and configure in RRC. */
|
||||
@@ -385,7 +480,7 @@ static void send_ngap_initial_context_setup_resp_fail(instance_t instance,
|
||||
resp->gNB_ue_ngap_id = msg->gNB_ue_ngap_id;
|
||||
|
||||
for (int i = 0; i < msg->nb_of_pdusessions; i++) {
|
||||
fill_pdu_session_resource_failed_to_setup_item(&resp->pdusessions_failed[i], msg->pdusession[i].pdusession_id, cause);
|
||||
fill_pdu_session_resource_failed_to_setup_item(&resp->pdusessions_failed[i], msg->pdusession_param[i].pdusession_id, cause);
|
||||
}
|
||||
resp->nb_of_pdusessions = 0;
|
||||
resp->nb_of_pdusessions_failed = msg->nb_of_pdusessions;
|
||||
@@ -424,9 +519,10 @@ int rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, instance_t
|
||||
/* if there are PDU sessions to setup, store them to be created once
|
||||
* security (and UE capabilities) are received */
|
||||
UE->n_initial_pdu = req->nb_of_pdusessions;
|
||||
UE->initial_pdus = calloc_or_fail(UE->n_initial_pdu, sizeof(*UE->initial_pdus));
|
||||
UE->initial_pdus = calloc(UE->n_initial_pdu, sizeof(*UE->initial_pdus));
|
||||
AssertFatal(UE->initial_pdus != NULL, "out of memory\n");
|
||||
for (int i = 0; i < UE->n_initial_pdu; ++i)
|
||||
cp_pdusession_resource_item_to_pdusession(&UE->initial_pdus[i], &req->pdusession[i]);
|
||||
UE->initial_pdus[i] = req->pdusession_param[i];
|
||||
}
|
||||
|
||||
/* security */
|
||||
@@ -471,15 +567,6 @@ int rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, instance_t
|
||||
return 0;
|
||||
}
|
||||
|
||||
static gtpu_tunnel_t cp_gtp_tunnel(const gtpu_tunnel_t in)
|
||||
{
|
||||
gtpu_tunnel_t out = {0};
|
||||
out.teid = in.teid;
|
||||
out.addr.length = in.addr.length;
|
||||
memcpy(out.addr.buffer, in.addr.buffer, out.addr.length);
|
||||
return out;
|
||||
}
|
||||
|
||||
void rrc_gNB_send_NGAP_INITIAL_CONTEXT_SETUP_RESP(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE)
|
||||
{
|
||||
MessageDef *msg_p = NULL;
|
||||
@@ -495,7 +582,11 @@ void rrc_gNB_send_NGAP_INITIAL_CONTEXT_SETUP_RESP(gNB_RRC_INST *rrc, gNB_RRC_UE_
|
||||
if (session->status == PDU_SESSION_STATUS_DONE) {
|
||||
pdu_sessions_done++;
|
||||
resp->pdusessions[pdusession].pdusession_id = session->param.pdusession_id;
|
||||
resp->pdusessions[pdusession].n3_outgoing = cp_gtp_tunnel(session->param.n3_outgoing);
|
||||
resp->pdusessions[pdusession].gtp_teid = session->param.gNB_teid_N3;
|
||||
memcpy(resp->pdusessions[pdusession].gNB_addr.buffer,
|
||||
session->param.gNB_addr_N3.buffer,
|
||||
sizeof(resp->pdusessions[pdusession].gNB_addr.buffer));
|
||||
resp->pdusessions[pdusession].gNB_addr.length = 4; // Fixme: IPv4 hard coded here
|
||||
resp->pdusessions[pdusession].nb_of_qos_flow = session->param.nb_qos;
|
||||
for (int qos_flow_index = 0; qos_flow_index < session->param.nb_qos; qos_flow_index++) {
|
||||
resp->pdusessions[pdusession].associated_qos_flows[qos_flow_index].qfi = session->param.qos[qos_flow_index].qfi;
|
||||
@@ -686,18 +777,25 @@ void rrc_gNB_send_NGAP_PDUSESSION_SETUP_RESP(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE
|
||||
pdusession_setup_t *tmp = &resp->pdusessions[pdu_sessions_done];
|
||||
tmp->pdusession_id = session->param.pdusession_id;
|
||||
tmp->nb_of_qos_flow = session->param.nb_qos;
|
||||
tmp->n3_outgoing = cp_gtp_tunnel(session->param.n3_outgoing);
|
||||
tmp->gtp_teid = session->param.gNB_teid_N3;
|
||||
tmp->pdu_session_type = session->param.pdu_session_type;
|
||||
|
||||
tmp->gNB_addr.length = session->param.gNB_addr_N3.length;
|
||||
memcpy(tmp->gNB_addr.buffer, session->param.gNB_addr_N3.buffer, tmp->gNB_addr.length);
|
||||
for (int qos_flow_index = 0; qos_flow_index < tmp->nb_of_qos_flow; qos_flow_index++) {
|
||||
tmp->associated_qos_flows[qos_flow_index].qfi = session->param.qos[qos_flow_index].qfi;
|
||||
tmp->associated_qos_flows[qos_flow_index].qos_flow_mapping_ind = QOSFLOW_MAPPING_INDICATION_DL;
|
||||
}
|
||||
|
||||
session->status = PDU_SESSION_STATUS_ESTABLISHED;
|
||||
char ip_str[INET_ADDRSTRLEN] = {0};
|
||||
inet_ntop(AF_INET, tmp->n3_outgoing.addr.buffer, ip_str, sizeof(ip_str));
|
||||
LOG_I(NR_RRC, "PDU Session Setup Response: ID=%d, outgoing TEID=0x%08x, Addr=%s\n", tmp->pdusession_id, tmp->n3_outgoing.teid, ip_str);
|
||||
LOG_I(NR_RRC,
|
||||
"msg index %d, pdu_sessions index %d, status %d, xid %d): nb_of_pdusessions %d, pdusession_id %d, teid: %u \n ",
|
||||
pdu_sessions_done,
|
||||
pdusession,
|
||||
session->status,
|
||||
xid,
|
||||
UE->nb_of_pdusessions,
|
||||
tmp->pdusession_id,
|
||||
tmp->gtp_teid);
|
||||
pdu_sessions_done++;
|
||||
} else if (session->status != PDU_SESSION_STATUS_ESTABLISHED) {
|
||||
session->status = PDU_SESSION_STATUS_FAILED;
|
||||
@@ -709,6 +807,10 @@ void rrc_gNB_send_NGAP_PDUSESSION_SETUP_RESP(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE
|
||||
}
|
||||
resp->nb_of_pdusessions = pdu_sessions_done;
|
||||
resp->nb_of_pdusessions_failed = pdu_sessions_failed;
|
||||
// } else {
|
||||
// LOG_D(NR_RRC,"xid does not corresponds (context pdu_sessions index %d, status %d, xid %d/%d) \n ",
|
||||
// pdusession, UE->pdusession[pdusession].status, xid, UE->pdusession[pdusession].xid);
|
||||
// }
|
||||
}
|
||||
|
||||
if ((pdu_sessions_done > 0 || pdu_sessions_failed)) {
|
||||
@@ -758,7 +860,9 @@ static void send_ngap_pdu_session_setup_resp_fail(instance_t instance, ngap_pdus
|
||||
resp->nb_of_pdusessions_failed = msg->nb_pdusessions_tosetup;
|
||||
resp->nb_of_pdusessions = 0;
|
||||
for (int i = 0; i < resp->nb_of_pdusessions_failed; ++i) {
|
||||
fill_pdu_session_resource_failed_to_setup_item(&resp->pdusessions_failed[i], msg->pdusession[i].pdusession_id, cause);
|
||||
fill_pdu_session_resource_failed_to_setup_item(&resp->pdusessions_failed[i],
|
||||
msg->pdusession_setup_params[i].pdusession_id,
|
||||
cause);
|
||||
}
|
||||
itti_send_msg_to_task(TASK_NGAP, instance, msg_resp);
|
||||
}
|
||||
@@ -804,7 +908,7 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins
|
||||
// At least one because marking one as existing, and setting up another, that
|
||||
// might be more work than is worth it. See 8.2.1.4 in 38.413
|
||||
for (int i = 0; i < msg->nb_pdusessions_tosetup; ++i) {
|
||||
const pdusession_resource_item_t *p = &msg->pdusession[i];
|
||||
const pdusession_t *p = &msg->pdusession_setup_params[i];
|
||||
rrc_pdu_session_param_t *exist = find_pduSession(UE, p->pdusession_id, false /* don't create */);
|
||||
if (exist) {
|
||||
LOG_E(NR_RRC, "UE %d: already has existing PDU session %d rejecting PDU Session Resource Setup Request\n", UE->rrc_ue_id, p->pdusession_id);
|
||||
@@ -837,11 +941,7 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins
|
||||
return;
|
||||
}
|
||||
|
||||
pdusession_t to_setup[NGAP_MAX_PDU_SESSION] = {0};
|
||||
for (int i = 0; i < msg->nb_pdusessions_tosetup; ++i)
|
||||
cp_pdusession_resource_item_to_pdusession(&to_setup[i], &msg->pdusession[i]);
|
||||
|
||||
if (!trigger_bearer_setup(rrc, UE, msg->nb_pdusessions_tosetup, to_setup, msg->ueAggMaxBitRate.br_dl)) {
|
||||
if (!trigger_bearer_setup(rrc, UE, msg->nb_pdusessions_tosetup, msg->pdusession_setup_params, msg->ueAggMaxBitRate.br_dl)) {
|
||||
// Reject PDU Session Resource setup if there's no CU-UP associated
|
||||
LOG_W(NR_RRC, "UE %d: reject PDU Session Setup in PDU Session Resource Setup Response\n", UE->rrc_ue_id);
|
||||
ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CAUSE_RADIO_NETWORK_RESOURCES_NOT_AVAILABLE_FOR_THE_SLICE};
|
||||
@@ -852,6 +952,104 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins
|
||||
}
|
||||
}
|
||||
|
||||
static void fill_qos2(NGAP_QosFlowAddOrModifyRequestList_t *qos, pdusession_t *session)
|
||||
{
|
||||
// we need to duplicate the function fill_qos because all data types are slightly different
|
||||
DevAssert(qos->list.count > 0);
|
||||
DevAssert(qos->list.count <= NGAP_maxnoofQosFlows);
|
||||
for (int qosIdx = 0; qosIdx < qos->list.count; qosIdx++) {
|
||||
NGAP_QosFlowAddOrModifyRequestItem_t *qosFlowItem_p = qos->list.array[qosIdx];
|
||||
// Set the QOS informations
|
||||
session->qos[qosIdx].qfi = (uint8_t)qosFlowItem_p->qosFlowIdentifier;
|
||||
NGAP_QosCharacteristics_t *qosChar = &qosFlowItem_p->qosFlowLevelQosParameters->qosCharacteristics;
|
||||
AssertFatal(qosChar, "Qos characteristics are not available for qos flow index %d\n", qosIdx);
|
||||
if (qosChar->present == NGAP_QosCharacteristics_PR_nonDynamic5QI) {
|
||||
AssertFatal(qosChar->choice.dynamic5QI, "Non-Dynamic 5QI is NULL\n");
|
||||
session->qos[qosIdx].fiveQI_type = NON_DYNAMIC;
|
||||
session->qos[qosIdx].fiveQI = (uint64_t)qosChar->choice.nonDynamic5QI->fiveQI;
|
||||
} else {
|
||||
AssertFatal(qosChar->choice.dynamic5QI, "Dynamic 5QI is NULL\n");
|
||||
session->qos[qosIdx].fiveQI_type = DYNAMIC;
|
||||
session->qos[qosIdx].fiveQI = (uint64_t)(*qosChar->choice.dynamic5QI->fiveQI);
|
||||
}
|
||||
|
||||
ngap_allocation_retention_priority_t *tmp = &session->qos[qosIdx].allocation_retention_priority;
|
||||
NGAP_AllocationAndRetentionPriority_t *tmp2 = &qosFlowItem_p->qosFlowLevelQosParameters->allocationAndRetentionPriority;
|
||||
tmp->priority_level = tmp2->priorityLevelARP;
|
||||
tmp->pre_emp_capability = tmp2->pre_emptionCapability;
|
||||
tmp->pre_emp_vulnerability = tmp2->pre_emptionVulnerability;
|
||||
}
|
||||
session->nb_qos = qos->list.count;
|
||||
}
|
||||
|
||||
static void decodePDUSessionResourceModify(pdusession_t *param, const byte_array_t pdu)
|
||||
{
|
||||
NGAP_PDUSessionResourceModifyRequestTransfer_t *pdusessionTransfer = NULL;
|
||||
asn_dec_rval_t dec_rval = aper_decode(NULL,
|
||||
&asn_DEF_NGAP_PDUSessionResourceModifyRequestTransfer,
|
||||
(void **)&pdusessionTransfer,
|
||||
pdu.buf,
|
||||
pdu.len,
|
||||
0,
|
||||
0);
|
||||
|
||||
if (dec_rval.code != RC_OK) {
|
||||
LOG_E(NR_RRC, "could not decode PDUSessionResourceModifyRequestTransfer\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (int j = 0; j < pdusessionTransfer->protocolIEs.list.count; j++) {
|
||||
NGAP_PDUSessionResourceModifyRequestTransferIEs_t *pdusessionTransfer_ies = pdusessionTransfer->protocolIEs.list.array[j];
|
||||
switch (pdusessionTransfer_ies->id) {
|
||||
/* optional PDUSessionAggregateMaximumBitRate */
|
||||
case NGAP_ProtocolIE_ID_id_PDUSessionAggregateMaximumBitRate:
|
||||
// TODO
|
||||
LOG_E(NR_RRC, "Cant' handle NGAP_ProtocolIE_ID_id_PDUSessionAggregateMaximumBitRate\n");
|
||||
break;
|
||||
|
||||
/* optional UL-NGU-UP-TNLModifyList */
|
||||
case NGAP_ProtocolIE_ID_id_UL_NGU_UP_TNLModifyList:
|
||||
// TODO
|
||||
LOG_E(NR_RRC, "Cant' handle NGAP_ProtocolIE_ID_id_UL_NGU_UP_TNLModifyList\n");
|
||||
break;
|
||||
|
||||
/* optional NetworkInstance */
|
||||
case NGAP_ProtocolIE_ID_id_NetworkInstance:
|
||||
// TODO
|
||||
LOG_E(NR_RRC, "Cant' handle NGAP_ProtocolIE_ID_id_NetworkInstance\n");
|
||||
break;
|
||||
|
||||
/* optional QosFlowAddOrModifyRequestList */
|
||||
case NGAP_ProtocolIE_ID_id_QosFlowAddOrModifyRequestList:
|
||||
fill_qos2(&pdusessionTransfer_ies->value.choice.QosFlowAddOrModifyRequestList, param);
|
||||
break;
|
||||
|
||||
/* optional QosFlowToReleaseList */
|
||||
case NGAP_ProtocolIE_ID_id_QosFlowToReleaseList:
|
||||
// TODO
|
||||
LOG_E(NR_RRC, "Can't handle NGAP_ProtocolIE_ID_id_QosFlowToReleaseList\n");
|
||||
break;
|
||||
|
||||
/* optional AdditionalUL-NGU-UP-TNLInformation */
|
||||
case NGAP_ProtocolIE_ID_id_AdditionalUL_NGU_UP_TNLInformation:
|
||||
// TODO
|
||||
LOG_E(NR_RRC, "Cant' handle NGAP_ProtocolIE_ID_id_AdditionalUL_NGU_UP_TNLInformation\n");
|
||||
break;
|
||||
|
||||
/* optional CommonNetworkInstance */
|
||||
case NGAP_ProtocolIE_ID_id_CommonNetworkInstance:
|
||||
// TODO
|
||||
LOG_E(NR_RRC, "Cant' handle NGAP_ProtocolIE_ID_id_CommonNetworkInstance\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_E(NR_RRC, "could not found protocolIEs id %ld\n", pdusessionTransfer_ies->id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
ASN_STRUCT_FREE(asn_DEF_NGAP_PDUSessionResourceModifyRequestTransfer,pdusessionTransfer );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
int rrc_gNB_process_NGAP_PDUSESSION_MODIFY_REQ(MessageDef *msg_p, instance_t instance)
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -871,7 +1069,7 @@ int rrc_gNB_process_NGAP_PDUSESSION_MODIFY_REQ(MessageDef *msg_p, instance_t ins
|
||||
bool all_failed = true;
|
||||
for (int i = 0; i < req->nb_pdusessions_tomodify; i++) {
|
||||
rrc_pdu_session_param_t *sess;
|
||||
const pdusession_resource_item_t *sessMod = req->pdusession + i;
|
||||
const pdusession_t *sessMod = req->pdusession_modify_params + i;
|
||||
for (sess = UE->pduSession; sess < UE->pduSession + UE->nb_of_pdusessions; sess++)
|
||||
if (sess->param.pdusession_id == sessMod->pdusession_id)
|
||||
break;
|
||||
@@ -895,8 +1093,10 @@ int rrc_gNB_process_NGAP_PDUSESSION_MODIFY_REQ(MessageDef *msg_p, instance_t ins
|
||||
if (sessMod->nas_pdu.buf != NULL) {
|
||||
UE->pduSession[i].param.nas_pdu = sessMod->nas_pdu;
|
||||
}
|
||||
for (int i = 0; i < req->nb_pdusessions_tomodify; ++i)
|
||||
cp_pdusession_resource_item_to_pdusession(&UE->pduSession[i].param, &req->pdusession[i]);
|
||||
// Save new pdu session parameters, qos, upf addr, teid
|
||||
decodePDUSessionResourceModify(&sess->param, UE->pduSession[i].param.pdusessionTransfer);
|
||||
sess->param.UPF_addr_N3 = sessMod->upf_addr;
|
||||
sess->param.UPF_teid_N3 = sessMod->gtp_teid;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1257,6 +1457,16 @@ int rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND(MessageDef *msg_p, instance_
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nr_rrc_rx_tx(void) {
|
||||
// check timers
|
||||
|
||||
// check if UEs are lost, to remove them from upper layers
|
||||
|
||||
//
|
||||
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
int rrc_gNB_process_PAGING_IND(MessageDef *msg_p, instance_t instance)
|
||||
{
|
||||
for (uint16_t tai_size = 0; tai_size < NGAP_PAGING_IND(msg_p).tai_size; tai_size++) {
|
||||
|
||||
@@ -96,22 +96,11 @@ static int du_compare(const nr_rrc_du_container_t *a, const nr_rrc_du_container_
|
||||
/* Tree management functions */
|
||||
RB_GENERATE/*_STATIC*/(rrc_du_tree, nr_rrc_du_container_t, entries, du_compare);
|
||||
|
||||
//static bool rrc_gNB_plmn_matches(const gNB_RRC_INST *rrc, const f1ap_served_cell_info_t *info)
|
||||
//{
|
||||
// const gNB_RrcConfigurationReq *conf = &rrc->configuration;
|
||||
// return conf->num_plmn == 1 // F1 supports only one
|
||||
// && conf->plmn[0].mcc == info->plmn.mcc && conf->plmn[0].mnc == info->plmn.mnc;
|
||||
//}
|
||||
static bool rrc_gNB_plmn_matches(const gNB_RRC_INST *rrc, const f1ap_served_cell_info_t *info)
|
||||
{
|
||||
const gNB_RrcConfigurationReq *conf = &rrc->configuration;
|
||||
for (int i = 0; i < conf->num_plmn; ++i) {
|
||||
if (conf->plmn[i].mcc == info->plmn.mcc &&
|
||||
conf->plmn[i].mnc == info->plmn.mnc) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return conf->num_plmn == 1 // F1 supports only one
|
||||
&& conf->plmn[0].mcc == info->plmn.mcc && conf->plmn[0].mnc == info->plmn.mnc;
|
||||
}
|
||||
|
||||
static bool extract_sys_info(const f1ap_gnb_du_system_info_t *sys_info, NR_MIB_t **mib, NR_SIB1_t **sib1)
|
||||
|
||||
@@ -32,15 +32,6 @@
|
||||
#include "oai_asn1.h"
|
||||
#include "openair2/LAYER2/nr_pdcp/nr_pdcp_asn1_utils.h"
|
||||
|
||||
/** @brief Deep copy pdusession_t */
|
||||
void cp_pdusession(pdusession_t *dst, const pdusession_t *src)
|
||||
{
|
||||
// Shallow copy
|
||||
*dst = *src;
|
||||
// nas_pdu
|
||||
dst->nas_pdu = copy_byte_array(src->nas_pdu);
|
||||
}
|
||||
|
||||
rrc_pdu_session_param_t *find_pduSession(gNB_RRC_UE_t *ue, int id, bool create)
|
||||
{
|
||||
int j;
|
||||
@@ -217,3 +208,11 @@ int get_number_active_drbs(gNB_RRC_UE_t *ue)
|
||||
n++;
|
||||
return n;
|
||||
}
|
||||
|
||||
bool drb_is_active(gNB_RRC_UE_t *ue, uint8_t drb_id)
|
||||
{
|
||||
drb_t *drb = get_drb(ue, drb_id);
|
||||
if (drb == NULL)
|
||||
return DRB_INACTIVE;
|
||||
return drb->status != DRB_INACTIVE;
|
||||
}
|
||||
|
||||
@@ -65,6 +65,9 @@ uint8_t get_next_available_drb_id(gNB_RRC_UE_t *ue);
|
||||
/// @brief returns the number of active DRBs for this UE
|
||||
int get_number_active_drbs(gNB_RRC_UE_t *ue);
|
||||
|
||||
/// @brief check if DRB with ID drb_id of UE ue is active
|
||||
bool drb_is_active(gNB_RRC_UE_t *ue, uint8_t drb_id);
|
||||
|
||||
/// @brief retrieve PDU session of UE ue with ID id, optionally creating it if
|
||||
/// create is true
|
||||
rrc_pdu_session_param_t *find_pduSession(gNB_RRC_UE_t *ue, int id, bool create);
|
||||
@@ -78,7 +81,4 @@ void get_pduSession_array(gNB_RRC_UE_t *ue, uint32_t pdu_sessions[NGAP_MAX_PDU_S
|
||||
/// @brief set PDCP configuration in a bearer context management message
|
||||
void set_bearer_context_pdcp_config(bearer_context_pdcp_config_t *pdcp_config, drb_t *rrc_drb, bool um_on_default_drb);
|
||||
|
||||
/// @brief Deep copy an instance of struct pdusession_t
|
||||
void cp_pdusession(pdusession_t *dst, const pdusession_t *src);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -14,7 +14,6 @@ add_library(fgs_5gmm_lib OBJECT
|
||||
FGSUplinkNasTransport.c
|
||||
FGSDeregistrationRequestUEOriginating.c
|
||||
fgmm_authentication_failure.c
|
||||
fgmm_authentication_reject.c
|
||||
)
|
||||
|
||||
target_link_libraries(fgs_5gmm_lib PUBLIC fgs_5gmm_ies_lib)
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (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.openairinterface.org/?page_id=698
|
||||
*
|
||||
* 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.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#include "fgmm_authentication_reject.h"
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h> // For htons and ntohs
|
||||
#include <stdlib.h> // For malloc and free
|
||||
#include "fgmm_lib.h"
|
||||
|
||||
#define MIN_AUTH_REJECT_LEN 3
|
||||
|
||||
/** @brief Encode Authentication Reject (8.2.5 of 3GPP TS 24.501) */
|
||||
int encode_fgmm_auth_reject(byte_array_t *buffer, const fgmm_auth_reject_msg_t *msg)
|
||||
{
|
||||
uint32_t encoded = 0;
|
||||
|
||||
const byte_array_t *eap_msg = &msg->eap_msg;
|
||||
if (eap_msg->len > 0) {
|
||||
return encode_eap_msg_ie(buffer, eap_msg);
|
||||
}
|
||||
return encoded;
|
||||
}
|
||||
|
||||
/** @brief Decode Authentication Reject (8.2.5 of 3GPP TS 24.501)
|
||||
* the message contains only optional IEIs (EAP MSG) */
|
||||
int decode_fgmm_auth_reject(fgmm_auth_reject_msg_t *msg, const byte_array_t *buffer)
|
||||
{
|
||||
if (buffer->len < MIN_AUTH_REJECT_LEN) {
|
||||
// No optional IEIs present
|
||||
return 0;
|
||||
}
|
||||
byte_array_t ba = *buffer; // Local copy of buffer
|
||||
uint32_t decoded = 0;
|
||||
// Decode the IEI
|
||||
uint8_t iei = buffer->buf[decoded++];
|
||||
UPDATE_BYTE_ARRAY(ba, decoded);
|
||||
if (iei == IEI_EAPMSG) {
|
||||
return (decoded + decode_eap_msg_ie(&msg->eap_msg, &ba));
|
||||
}
|
||||
PRINT_NAS_ERROR("Expected EAP MSG but it is not present");
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool eq_auth_reject(fgmm_auth_reject_msg_t *a, fgmm_auth_reject_msg_t *b)
|
||||
{
|
||||
_NAS_EQ_CHECK_LONG(a->eap_msg.len, b->eap_msg.len);
|
||||
if (a->eap_msg.len > 0) {
|
||||
return !memcmp(a->eap_msg.buf, b->eap_msg.buf, a->eap_msg.len);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -25,11 +25,8 @@
|
||||
#include <stdlib.h> // For malloc and free
|
||||
#include "common/utils/ds/byte_array.h"
|
||||
|
||||
#define IEI_LEN 1
|
||||
#define GPRS_TIMER_LENGTH 3 // octets
|
||||
#define FGS_NAS_CAUSE_LENGTH 1
|
||||
#define MIN_EAP_MSG_LEN 7
|
||||
#define MIN_EAP_CONTENTS_LEN 4
|
||||
|
||||
/**
|
||||
* Encode PDU Session Status and PDU session reactivation result (optional IEs)
|
||||
@@ -155,72 +152,12 @@ bool eq_gprs_timer(const gprs_timer_t *a, const gprs_timer_t *b)
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @brief Encode EAP message IE (3GPP TS 24.501 9.11.2.2) */
|
||||
int encode_eap_msg_ie(byte_array_t *buffer, const byte_array_t *msg)
|
||||
/* Decode EAP Message (todo) */
|
||||
int decode_eap_msg_ie(const byte_array_t *buffer)
|
||||
{
|
||||
int encoded = 0;
|
||||
|
||||
// Sanity check on buffer length
|
||||
if (buffer->len < MIN_EAP_MSG_LEN) {
|
||||
PRINT_NAS_ERROR("Invalid buffer length %ld", buffer->len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Sanity check on input length
|
||||
if (msg->len < MIN_EAP_CONTENTS_LEN || msg->len > MAX_EAP_CONTENTS_LEN) {
|
||||
PRINT_NAS_ERROR("Invalid EAP message length %ld", msg->len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Encode IEI
|
||||
buffer->buf[encoded++] = IEI_EAPMSG;
|
||||
|
||||
// Encode length of EAP message content
|
||||
uint16_t len = htons(msg->len);
|
||||
memcpy(&buffer->buf[encoded], &len, sizeof(len));
|
||||
encoded += sizeof(len);
|
||||
|
||||
// Encode EAP message content
|
||||
memcpy(&buffer->buf[encoded], msg->buf, msg->len);
|
||||
encoded += msg->len;
|
||||
|
||||
return encoded;
|
||||
}
|
||||
|
||||
/** @brief Decode EAP message IE (3GPP TS 24.501 9.11.2.2):
|
||||
length of contents and message payload */
|
||||
int decode_eap_msg_ie(byte_array_t *eap_msg, const byte_array_t *buffer)
|
||||
{
|
||||
int decoded = 0;
|
||||
int min_len_to_decode = MIN_EAP_MSG_LEN - IEI_LEN;
|
||||
|
||||
// Check buffer length validity
|
||||
if (buffer->len < min_len_to_decode) {
|
||||
PRINT_NAS_ERROR("Invalid buffer for decoding EAP message IE");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Decode length IE
|
||||
eap_msg->len = (buffer->buf[decoded] << 8) | buffer->buf[decoded + 1];
|
||||
decoded += 2;
|
||||
|
||||
// Check payload length validity
|
||||
if (eap_msg->len < MIN_EAP_CONTENTS_LEN || eap_msg->len > MAX_EAP_CONTENTS_LEN) {
|
||||
PRINT_NAS_ERROR("Invalid EAP message length %ld", eap_msg->len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Check for buffer overflow
|
||||
if (buffer->len < decoded + eap_msg->len) {
|
||||
PRINT_NAS_ERROR("Buffer too short for EAP message: %ld < %ld", buffer->len, decoded + eap_msg->len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Copy EAP payload
|
||||
memcpy(eap_msg->buf, &buffer->buf[decoded], eap_msg->len);
|
||||
decoded += eap_msg->len;
|
||||
|
||||
return decoded;
|
||||
int eap_msg_len = (buffer->buf[0] << 8) | buffer->buf[1];
|
||||
PRINT_NAS_ERROR("EAP message IE in NAS Service Reject is not handled\n");
|
||||
return eap_msg_len + 2; // content length + 2 octets for the length IE
|
||||
}
|
||||
|
||||
int encode_fgs_nas_cause(byte_array_t *buffer, const cause_id_t *cause)
|
||||
|
||||
@@ -39,7 +39,6 @@ both PDU Session Status and PDU session Reactivation Result IEs */
|
||||
#define MAX_PDU_SESSION_CONTENTS_LEN 32
|
||||
#define MAX_NUM_PSI 16
|
||||
#define MAX_NUM_PDU_ERRORS 256
|
||||
#define MAX_EAP_CONTENTS_LEN 1500
|
||||
|
||||
/* This macro updates the local copy of
|
||||
a byte_array_t pointer used for enc/dec */
|
||||
@@ -165,8 +164,7 @@ int decode_pdu_session_ie(uint8_t *psi, const byte_array_t *buffer);
|
||||
int encode_gprs_timer_ie(byte_array_t *buffer, nas_service_IEI_t iei, const gprs_timer_t *timer);
|
||||
int decode_gprs_timer_ie(gprs_timer_t *timer, const byte_array_t *buffer);
|
||||
bool eq_gprs_timer(const gprs_timer_t *a, const gprs_timer_t *b);
|
||||
int decode_eap_msg_ie(byte_array_t *eap_msg, const byte_array_t *buffer);
|
||||
int encode_eap_msg_ie(byte_array_t *buffer, const byte_array_t *msg);
|
||||
int decode_eap_msg_ie(const byte_array_t *buffer);
|
||||
int encode_fgs_nas_cause(byte_array_t *buffer, const cause_id_t *cause);
|
||||
int decode_fgs_nas_cause(cause_id_t *cause, const byte_array_t *buffer);
|
||||
|
||||
|
||||
@@ -133,7 +133,7 @@ int decode_fgs_service_accept(fgs_service_accept_msg_t *msg, const byte_array_t
|
||||
break;
|
||||
|
||||
case IEI_EAPMSG:
|
||||
DECODE_NAS_IE(ba, decode_eap_msg_ie(&msg->eap_msg, &ba), decoded);
|
||||
DECODE_NAS_IE(ba, decode_eap_msg_ie(&ba), decoded);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -47,9 +47,6 @@ typedef struct {
|
||||
|
||||
// T3448 Value (Optional)
|
||||
gprs_timer_t *t3448;
|
||||
|
||||
// EAP Message (Optional)
|
||||
byte_array_t eap_msg;
|
||||
} fgs_service_accept_msg_t;
|
||||
|
||||
int decode_fgs_service_accept(fgs_service_accept_msg_t *msg, const byte_array_t *buffer);
|
||||
|
||||
@@ -59,11 +59,6 @@ int encode_fgs_service_reject(byte_array_t *buffer, const fgs_service_reject_msg
|
||||
ENCODE_NAS_IE(ba, encode_gprs_timer_ie(&ba, IEI_T3448_VALUE, msg->t3448), encoded);
|
||||
}
|
||||
|
||||
// EAP message (Optional)
|
||||
if (msg->eap_msg) {
|
||||
ENCODE_NAS_IE(ba, encode_eap_msg_ie(&ba, msg->eap_msg), encoded);
|
||||
}
|
||||
|
||||
return encoded;
|
||||
}
|
||||
|
||||
@@ -104,7 +99,7 @@ int decode_fgs_service_reject(fgs_service_reject_msg_t *msg, const byte_array_t
|
||||
break;
|
||||
|
||||
case IEI_EAPMSG:
|
||||
DECODE_NAS_IE(ba, decode_eap_msg_ie(msg->eap_msg, &ba), decoded);
|
||||
DECODE_NAS_IE(ba, decode_eap_msg_ie((const byte_array_t *)&ba), decoded);
|
||||
break;
|
||||
|
||||
case IEI_CAG_INFO_LIST: {
|
||||
|
||||
@@ -35,8 +35,6 @@ typedef struct {
|
||||
bool has_psi_status;
|
||||
// T3448 Value (Optional)
|
||||
gprs_timer_t *t3448;
|
||||
// EAP message (optional)
|
||||
byte_array_t *eap_msg;
|
||||
} fgs_service_reject_msg_t;
|
||||
|
||||
int decode_fgs_service_reject(fgs_service_reject_msg_t *msg, const byte_array_t *buffer);
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include "fgmm_service_reject.h"
|
||||
#include "fgmm_authentication_failure.h"
|
||||
#include "FGSNASSecurityModeReject.h"
|
||||
#include "fgmm_authentication_reject.h"
|
||||
#include "nr_nas_msg.h"
|
||||
|
||||
void exit_function(const char *file, const char *function, const int line, const char *s, const int assert)
|
||||
@@ -299,44 +298,6 @@ static void test_security_mode_reject(void)
|
||||
AssertFatal(eq_sec_mode_reject(&orig, &dec), "test_sec_mode_reject() failed: original and decoded messages do not match\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test NAS Authentication Reject enc/dec
|
||||
*/
|
||||
static void test_auth_reject(void)
|
||||
{
|
||||
// Dummy NAS Authentication Reject message
|
||||
uint8_t dummy_eap_msg[] = {0x12, 0x34, 0x56, 0x78, 0x91, 0x01, 0x23}; // Example EAP message
|
||||
fgmm_auth_reject_msg_t orig = {
|
||||
.eap_msg.len = sizeof(dummy_eap_msg),
|
||||
};
|
||||
orig.eap_msg.buf = dummy_eap_msg;
|
||||
|
||||
// Expected encoded data
|
||||
uint8_t expected_enc[] = {0x78, 0x00, 0x07, 0x12, 0x34, 0x56, 0x78, 0x91, 0x01, 0x23};
|
||||
|
||||
// Buffer
|
||||
uint8_t buf[10] = {0};
|
||||
byte_array_t buffer = {.buf = buf, .len = sizeof(buf)};
|
||||
|
||||
// Encode
|
||||
int encoded_length = encode_fgmm_auth_reject(&buffer, &orig);
|
||||
AssertFatal(encoded_length >= 0, "encode_fgmm_auth_reject() failed\n");
|
||||
|
||||
// Compare the raw encoded buffer with expected encoded data
|
||||
AssertFatal(encoded_length == sizeof(expected_enc), "Encoded length mismatch %d != %ld \n", encoded_length, sizeof(expected_enc));
|
||||
AssertFatal(memcmp(buffer.buf, expected_enc, encoded_length) == 0, "Encoding mismatch!\n");
|
||||
|
||||
// Decode
|
||||
fgmm_auth_reject_msg_t dec = {0};
|
||||
uint8_t eap_msg[1500] = {0};
|
||||
dec.eap_msg.buf = eap_msg;
|
||||
int decoded_length = decode_fgmm_auth_reject(&dec, &buffer);
|
||||
AssertFatal(decoded_length >= 0, "decode_fgmm_auth_reject() failed\n");
|
||||
|
||||
// Compare original and decoded messages
|
||||
AssertFatal(eq_auth_reject(&orig, &dec), "test_auth_reject() failed: original and decoded messages do not match\n");
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_regression_registration_accept();
|
||||
@@ -344,7 +305,6 @@ int main()
|
||||
test_service_accept();
|
||||
test_service_reject();
|
||||
test_auth_failure();
|
||||
test_auth_reject();
|
||||
test_security_mode_reject();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -71,7 +71,6 @@
|
||||
#include "fgs_nas_utils.h"
|
||||
#include "fgmm_service_accept.h"
|
||||
#include "fgmm_service_reject.h"
|
||||
#include "fgmm_authentication_reject.h"
|
||||
#include "ds/byte_array.h"
|
||||
#include "key_nas_deriver.h"
|
||||
|
||||
@@ -1064,33 +1063,6 @@ static void handle_fgmm_authentication_request(nr_ue_nas_t *nas, as_nas_info_t *
|
||||
generateAuthenticationResp(nas, initialNasMsg, buffer->buf);
|
||||
}
|
||||
|
||||
/** @brief Handle authentication not accepted by the network
|
||||
* This function assumes the message is not integrity protected, processes the received
|
||||
* NAS message and logs whether a EAP-failure is enclosed. The UE enters state: 5GMM-DEREGISTERED.
|
||||
* @todo The UE shall performs actions as per 5.4.1.3.5 of 3GPP TS 24.501, including
|
||||
* (1) Abort any ongoing 5GMM procedure (2) Stop all active timers: T3510, T3516, T3517,
|
||||
* T3519, T3520, T3521 (3) Delete stored SUCI. (4) handle EAP-failure message. */
|
||||
static void handle_authentication_reject(nr_ue_nas_t *nas, as_nas_info_t *initialNasMsg, uint8_t *pdu, int pdu_length)
|
||||
{
|
||||
LOG_E(NAS, "Received Authentication Reject message from the network\n");
|
||||
uint8_t eap_msg[MAX_EAP_CONTENTS_LEN] = {0};
|
||||
fgmm_auth_reject_msg_t msg = {.eap_msg.buf = eap_msg};
|
||||
|
||||
byte_array_t ba = {.buf = pdu + 3 /* skip header */, .len = pdu_length};
|
||||
if (decode_fgmm_auth_reject(&msg, &ba) < 0) {
|
||||
LOG_E(NAS, "Could not decode Authentication Reject\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg.eap_msg.len > 0) {
|
||||
/** @todo UE handling EAP-failure message (5.4.1.2.2.11 of 3GPP TS 24.501) */
|
||||
LOG_W(NAS, "NAS Authentication Reject contains an EAP message: handling is not implemented\n");
|
||||
log_hex_buffer("EAP-Failure", msg.eap_msg.buf, msg.eap_msg.len);
|
||||
}
|
||||
|
||||
nas->fiveGMM_state = FGS_DEREGISTERED;
|
||||
}
|
||||
|
||||
int nas_itti_kgnb_refresh_req(instance_t instance, const uint8_t kgnb[32])
|
||||
{
|
||||
MessageDef *message_p;
|
||||
@@ -2092,9 +2064,6 @@ void *nas_nrue(void *args_p)
|
||||
case FGS_AUTHENTICATION_REQUEST:
|
||||
handle_fgmm_authentication_request(nas, &initialNasMsg, &buffer);
|
||||
break;
|
||||
case FGS_AUTHENTICATION_REJECT:
|
||||
handle_authentication_reject(nas, &initialNasMsg, pdu_buffer, pdu_length);
|
||||
break;
|
||||
case FGS_SECURITY_MODE_COMMAND:
|
||||
handle_security_mode_command(nas, &initialNasMsg, pdu_buffer, pdu_length);
|
||||
break;
|
||||
|
||||
@@ -344,6 +344,14 @@ void *ngap_gNB_process_itti_msg(void *notUsed) {
|
||||
ngap_gNB_nas_non_delivery_ind(instance, &NGAP_NAS_NON_DELIVERY_IND(received_msg));
|
||||
break;
|
||||
|
||||
case NGAP_PATH_SWITCH_REQ:
|
||||
ngap_gNB_path_switch_req(instance, &NGAP_PATH_SWITCH_REQ(received_msg));
|
||||
break;
|
||||
|
||||
case NGAP_PDUSESSION_MODIFICATION_IND:
|
||||
ngap_gNB_generate_PDUSESSION_Modification_Indication(instance, &NGAP_PDUSESSION_MODIFICATION_IND(received_msg));
|
||||
break;
|
||||
|
||||
case NGAP_UE_CONTEXT_RELEASE_COMPLETE:
|
||||
ngap_ue_context_release_complete(instance, &NGAP_UE_CONTEXT_RELEASE_COMPLETE(received_msg));
|
||||
break;
|
||||
|
||||
@@ -694,99 +694,6 @@ static int ngap_gNB_handle_error_indication(sctp_assoc_t assoc_id, uint32_t stre
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *decode_pdusession_transfer(const asn_TYPE_descriptor_t *td, const OCTET_STRING_t buf)
|
||||
{
|
||||
void *decoded = NULL;
|
||||
asn_codec_ctx_t ctx = {.max_stack_size = 100 * 1000};
|
||||
asn_dec_rval_t rval = aper_decode(&ctx, td, &decoded, buf.buf, buf.size, 0, 0);
|
||||
if (rval.code != RC_OK) {
|
||||
NGAP_ERROR("Decoding failed for %s\n", td->name);
|
||||
return NULL;
|
||||
}
|
||||
return decoded;
|
||||
}
|
||||
|
||||
static pdusession_level_qos_parameter_t fill_qos(uint8_t qfi, const NGAP_QosFlowLevelQosParameters_t *params)
|
||||
{
|
||||
pdusession_level_qos_parameter_t out = {0};
|
||||
// QFI
|
||||
out.qfi = qfi;
|
||||
AssertFatal(params != NULL, "QoS parameters are NULL\n");
|
||||
// QosCharacteristics
|
||||
const NGAP_QosCharacteristics_t *qosChar = ¶ms->qosCharacteristics;
|
||||
AssertFatal(qosChar != NULL, "QoS characteristics are NULL\n");
|
||||
if (qosChar->present == NGAP_QosCharacteristics_PR_nonDynamic5QI) {
|
||||
AssertFatal(qosChar->choice.nonDynamic5QI != NULL, "nonDynamic5QI is NULL\n");
|
||||
out.fiveQI_type = NON_DYNAMIC;
|
||||
out.fiveQI = qosChar->choice.nonDynamic5QI->fiveQI;
|
||||
} else if (qosChar->present == NGAP_QosCharacteristics_PR_dynamic5QI) {
|
||||
AssertFatal(qosChar->choice.dynamic5QI != NULL, "dynamic5QI is NULL\n");
|
||||
out.fiveQI_type = DYNAMIC;
|
||||
out.fiveQI = *qosChar->choice.dynamic5QI->fiveQI;
|
||||
} else {
|
||||
AssertFatal(0, "Unsupported QoS Characteristics present value: %d\n", qosChar->present);
|
||||
}
|
||||
// Allocation and Retention Priority
|
||||
const NGAP_AllocationAndRetentionPriority_t *arp = ¶ms->allocationAndRetentionPriority;
|
||||
out.allocation_retention_priority.priority_level = arp->priorityLevelARP;
|
||||
out.allocation_retention_priority.pre_emp_capability = arp->pre_emptionCapability;
|
||||
out.allocation_retention_priority.pre_emp_vulnerability = arp->pre_emptionVulnerability;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static gtpu_tunnel_t decode_TNLInformation(const NGAP_GTPTunnel_t *gTPTunnel_p)
|
||||
{
|
||||
gtpu_tunnel_t out = {0};
|
||||
// Transport layer address
|
||||
memcpy(out.addr.buffer, gTPTunnel_p->transportLayerAddress.buf, gTPTunnel_p->transportLayerAddress.size);
|
||||
out.addr.length = gTPTunnel_p->transportLayerAddress.size - gTPTunnel_p->transportLayerAddress.bits_unused;
|
||||
// GTP tunnel endpoint ID
|
||||
OCTET_STRING_TO_INT32(&gTPTunnel_p->gTP_TEID, out.teid);
|
||||
return out;
|
||||
}
|
||||
|
||||
/** @brief Decode PDU Session Resource Setup Request Transfer (9.3.4.1 3GPP TS 38.413) */
|
||||
static bool decodePDUSessionResourceSetup(pdusession_transfer_t *out, const OCTET_STRING_t in)
|
||||
{
|
||||
void *decoded = decode_pdusession_transfer(&asn_DEF_NGAP_PDUSessionResourceSetupRequestTransfer, in);
|
||||
if (!decoded) {
|
||||
LOG_E(NR_RRC, "Failed to decode PDUSessionResourceSetupRequestTransfer\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
NGAP_PDUSessionResourceSetupRequestTransfer_t *pdusessionTransfer = (NGAP_PDUSessionResourceSetupRequestTransfer_t *)decoded;
|
||||
for (int i = 0; i < pdusessionTransfer->protocolIEs.list.count; i++) {
|
||||
NGAP_PDUSessionResourceSetupRequestTransferIEs_t *pdusessionTransfer_ies = pdusessionTransfer->protocolIEs.list.array[i];
|
||||
switch (pdusessionTransfer_ies->id) {
|
||||
// UL NG-U UP TNL Information (Mandatory)
|
||||
case NGAP_ProtocolIE_ID_id_UL_NGU_UP_TNLInformation:
|
||||
out->n3_incoming = decode_TNLInformation(pdusessionTransfer_ies->value.choice.UPTransportLayerInformation.choice.gTPTunnel);
|
||||
break;
|
||||
|
||||
// PDU Session Type (Mandatory)
|
||||
case NGAP_ProtocolIE_ID_id_PDUSessionType:
|
||||
out->pdu_session_type = pdusessionTransfer_ies->value.choice.PDUSessionType;
|
||||
break;
|
||||
|
||||
// QoS Flow Setup Request List (Mandatory)
|
||||
case NGAP_ProtocolIE_ID_id_QosFlowSetupRequestList:
|
||||
out->nb_qos = pdusessionTransfer_ies->value.choice.QosFlowSetupRequestList.list.count;
|
||||
for (int i = 0; i < out->nb_qos; i++) {
|
||||
NGAP_QosFlowSetupRequestItem_t *item = pdusessionTransfer_ies->value.choice.QosFlowSetupRequestList.list.array[i];
|
||||
out->qos[i] = fill_qos(item->qosFlowIdentifier, &item->qosFlowLevelQosParameters);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_D(NR_RRC, "Unhandled optional IE %ld\n", pdusessionTransfer_ies->id);
|
||||
}
|
||||
}
|
||||
ASN_STRUCT_FREE(asn_DEF_NGAP_PDUSessionResourceSetupRequestTransfer, pdusessionTransfer);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int ngap_gNB_handle_initial_context_request(sctp_assoc_t assoc_id, uint32_t stream, NGAP_NGAP_PDU_t *pdu)
|
||||
{
|
||||
int i;
|
||||
@@ -855,16 +762,13 @@ static int ngap_gNB_handle_initial_context_request(sctp_assoc_t assoc_id, uint32
|
||||
|
||||
for (i = 0; i < ie->value.choice.PDUSessionResourceSetupListCxtReq.list.count; i++) {
|
||||
NGAP_PDUSessionResourceSetupItemCxtReq_t *item_p = ie->value.choice.PDUSessionResourceSetupListCxtReq.list.array[i];
|
||||
msg->pdusession[i].pdusession_id = item_p->pDUSessionID;
|
||||
msg->pdusession[i].nssai = decode_ngap_nssai(&item_p->s_NSSAI);
|
||||
msg->pdusession_param[i].pdusession_id = item_p->pDUSessionID;
|
||||
msg->pdusession_param[i].nssai = decode_ngap_nssai(&item_p->s_NSSAI);
|
||||
if (item_p->nAS_PDU) {
|
||||
msg->pdusession[i].nas_pdu = create_byte_array(item_p->nAS_PDU->size, item_p->nAS_PDU->buf);
|
||||
}
|
||||
bool ret = decodePDUSessionResourceSetup(&msg->pdusession[i].pdusessionTransfer, item_p->pDUSessionResourceSetupRequestTransfer);
|
||||
if (!ret) {
|
||||
NGAP_ERROR("Failed to decode pDUSessionResourceSetupRequestTransfer in NG Initial Context Setup Request\n");
|
||||
return -1;
|
||||
msg->pdusession_param[i].nas_pdu = create_byte_array(item_p->nAS_PDU->size, item_p->nAS_PDU->buf);
|
||||
}
|
||||
OCTET_STRING_t *transfer = &item_p->pDUSessionResourceSetupRequestTransfer;
|
||||
msg->pdusession_param[i].pdusessionTransfer = create_byte_array(transfer->size, transfer->buf);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1032,19 +936,16 @@ static int ngap_gNB_handle_pdusession_setup_request(sctp_assoc_t assoc_id, uint3
|
||||
|
||||
for (int i = 0; i < ie->value.choice.PDUSessionResourceSetupListSUReq.list.count; i++) {
|
||||
NGAP_PDUSessionResourceSetupItemSUReq_t *item_p = ie->value.choice.PDUSessionResourceSetupListSUReq.list.array[i];
|
||||
msg->pdusession[i].pdusession_id = item_p->pDUSessionID;
|
||||
msg->pdusession_setup_params[i].pdusession_id = item_p->pDUSessionID;
|
||||
|
||||
// S-NSSAI
|
||||
msg->pdusession[i].nssai = decode_ngap_nssai(&item_p->s_NSSAI);
|
||||
msg->pdusession_setup_params[i].nssai = decode_ngap_nssai(&item_p->s_NSSAI);
|
||||
|
||||
msg->pdusession[i].nas_pdu = create_byte_array(item_p->pDUSessionNAS_PDU->size, item_p->pDUSessionNAS_PDU->buf);
|
||||
bool ret = decodePDUSessionResourceSetup(&msg->pdusession[i].pdusessionTransfer, item_p->pDUSessionResourceSetupRequestTransfer);
|
||||
if (!ret) {
|
||||
NGAP_ERROR("Failed to decode pDUSessionResourceSetupRequestTransfer in NG Setup Request\n");
|
||||
return -1;
|
||||
}
|
||||
OCTET_STRING_t *transfer = &item_p->pDUSessionResourceSetupRequestTransfer;
|
||||
msg->pdusession_setup_params[i].nas_pdu = create_byte_array(item_p->pDUSessionNAS_PDU->size, item_p->pDUSessionNAS_PDU->buf);
|
||||
msg->pdusession_setup_params[i].pdusessionTransfer = create_byte_array(transfer->size, transfer->buf);
|
||||
}
|
||||
itti_send_msg_to_task(TASK_RRC_GNB, ue_desc_p->gNB_instance->instance, message_p);
|
||||
itti_send_msg_to_task(TASK_RRC_GNB, ue_desc_p->gNB_instance->instance, message_p);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1138,37 +1039,6 @@ static int ngap_gNB_handle_paging(sctp_assoc_t assoc_id, uint32_t stream, NGAP_N
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool decodePDUSessionResourceModify(pdusession_transfer_t *out, const OCTET_STRING_t in)
|
||||
{
|
||||
void *decoded = decode_pdusession_transfer(&asn_DEF_NGAP_PDUSessionResourceModifyRequestTransfer, in);
|
||||
if (!decoded) {
|
||||
LOG_E(NR_RRC, "Failed to decode PDUSessionResourceModifyRequestTransfer\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
NGAP_PDUSessionResourceModifyRequestTransfer_t *pdusessionTransfer = (NGAP_PDUSessionResourceModifyRequestTransfer_t *)decoded;
|
||||
for (int j = 0; j < pdusessionTransfer->protocolIEs.list.count; j++) {
|
||||
NGAP_PDUSessionResourceModifyRequestTransferIEs_t *pdusessionTransfer_ies = pdusessionTransfer->protocolIEs.list.array[j];
|
||||
switch (pdusessionTransfer_ies->id) {
|
||||
/* optional QosFlowAddOrModifyRequestList */
|
||||
case NGAP_ProtocolIE_ID_id_QosFlowAddOrModifyRequestList:
|
||||
out->nb_qos = pdusessionTransfer_ies->value.choice.QosFlowAddOrModifyRequestList.list.count;
|
||||
for (int i = 0; i < out->nb_qos; i++) {
|
||||
NGAP_QosFlowAddOrModifyRequestItem_t *item =
|
||||
pdusessionTransfer_ies->value.choice.QosFlowAddOrModifyRequestList.list.array[i];
|
||||
out->qos[i] = fill_qos(item->qosFlowIdentifier, item->qosFlowLevelQosParameters);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_E(NR_RRC, "Unhandled optional IE %ld\n", pdusessionTransfer_ies->id);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
ASN_STRUCT_FREE(asn_DEF_NGAP_PDUSessionResourceModifyRequestTransfer, pdusessionTransfer);
|
||||
return true;
|
||||
}
|
||||
|
||||
static int ngap_gNB_handle_pdusession_modify_request(sctp_assoc_t assoc_id, uint32_t stream, NGAP_NGAP_PDU_t *pdu)
|
||||
{
|
||||
ngap_gNB_amf_data_t *amf_desc_p = NULL;
|
||||
@@ -1246,15 +1116,13 @@ static int ngap_gNB_handle_pdusession_modify_request(sctp_assoc_t assoc_id, uint
|
||||
for (int i = 0; i < ie->value.choice.PDUSessionResourceModifyListModReq.list.count; i++) {
|
||||
NGAP_PDUSessionResourceModifyItemModReq_t *item_p = ie->value.choice.PDUSessionResourceModifyListModReq.list.array[i];
|
||||
|
||||
msg->pdusession[i].pdusession_id = item_p->pDUSessionID;
|
||||
msg->pdusession_modify_params[i].pdusession_id = item_p->pDUSessionID;
|
||||
|
||||
// check for the NAS PDU
|
||||
if (item_p->nAS_PDU != NULL && item_p->nAS_PDU->size > 0) {
|
||||
msg->pdusession[i].nas_pdu = create_byte_array(item_p->nAS_PDU->size, item_p->nAS_PDU->buf);
|
||||
if (!decodePDUSessionResourceModify(&msg->pdusession[i].pdusessionTransfer, item_p->pDUSessionResourceModifyRequestTransfer)) {
|
||||
NGAP_ERROR("Failed to decode pDUSessionResourceModifyRequestTransfer\n");
|
||||
return -1;
|
||||
}
|
||||
msg->pdusession_modify_params[i].nas_pdu = create_byte_array(item_p->nAS_PDU->size, item_p->nAS_PDU->buf);
|
||||
OCTET_STRING_t *transfer = &item_p->pDUSessionResourceModifyRequestTransfer;
|
||||
msg->pdusession_modify_params[i].pdusessionTransfer = create_byte_array(transfer->size, transfer->buf);
|
||||
} else {
|
||||
LOG_W(NGAP, "received pdu session modify with void content for UE %u, pdu session %lu\n", msg->gNB_ue_ngap_id, item_p->pDUSessionID);
|
||||
continue;
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
#include "BIT_STRING.h"
|
||||
#include "INTEGER.h"
|
||||
#include "ngap_msg_includes.h"
|
||||
@@ -58,7 +57,6 @@
|
||||
#include "oai_asn1.h"
|
||||
#include "s1ap_messages_types.h"
|
||||
#include "xer_encoder.h"
|
||||
#include "ds/byte_array.h"
|
||||
|
||||
/** @brief Selects the AMF instance for a given UE based on identity information.
|
||||
* It attempts to select an AMF using the following prioritized criteria:
|
||||
@@ -539,46 +537,6 @@ int ngap_gNB_nas_non_delivery_ind(instance_t instance,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @brief PDU Session Resource Setup Response Transfer encoding (9.3.4.2 3GPP TS 38.413) */
|
||||
static byte_array_t encode_ngap_pdusession_setup_response_transfer(const pdusession_setup_t *pdusession)
|
||||
{
|
||||
NGAP_PDUSessionResourceSetupResponseTransfer_t pdusessionTransfer = {0};
|
||||
byte_array_t out = {0};
|
||||
|
||||
// DL QoS Flow per TNL Information (Mandatory)
|
||||
NGAP_QosFlowPerTNLInformation_t *dLQosFlowPerTNLInformation = &pdusessionTransfer.dLQosFlowPerTNLInformation;
|
||||
|
||||
// UP Transport Layer Information (Mandatory)
|
||||
dLQosFlowPerTNLInformation->uPTransportLayerInformation.present = NGAP_UPTransportLayerInformation_PR_gTPTunnel;
|
||||
asn1cCalloc(dLQosFlowPerTNLInformation->uPTransportLayerInformation.choice.gTPTunnel, gtp);
|
||||
GTP_TEID_TO_ASN1(pdusession->n3_outgoing.teid, >p->gTP_TEID);
|
||||
tnl_to_bitstring(>p->transportLayerAddress, pdusession->n3_outgoing.addr);
|
||||
char ip_str[INET_ADDRSTRLEN] = {0};
|
||||
inet_ntop(AF_INET, gtp->transportLayerAddress.buf, ip_str, sizeof(ip_str));
|
||||
NGAP_DEBUG("Encoded PDU Session Transfer (%d): TEID=0x%08x, Addr=%s\n",
|
||||
pdusession->pdusession_id,
|
||||
pdusession->n3_outgoing.teid,
|
||||
ip_str);
|
||||
|
||||
// Associated QoS Flow List (Mandatory)
|
||||
for (int j = 0; j < pdusession->nb_of_qos_flow; j++) {
|
||||
asn1cSequenceAdd(dLQosFlowPerTNLInformation->associatedQosFlowList.list, NGAP_AssociatedQosFlowItem_t, qos_item);
|
||||
// QoS Flow Identifier (Mandatory)
|
||||
qos_item->qosFlowIdentifier = pdusession->associated_qos_flows[j].qfi;
|
||||
}
|
||||
|
||||
// Encode
|
||||
asn_encode_to_new_buffer_result_t res = asn_encode_to_new_buffer(NULL,
|
||||
ATS_ALIGNED_CANONICAL_PER,
|
||||
&asn_DEF_NGAP_PDUSessionResourceSetupResponseTransfer,
|
||||
&pdusessionTransfer);
|
||||
AssertFatal(res.buffer, "ASN1 message encoding failed (%s, %lu)!\n", res.result.failed_type->name, res.result.encoded);
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_PDUSessionResourceSetupResponseTransfer, &pdusessionTransfer);
|
||||
out.buf = res.buffer;
|
||||
out.len = res.result.encoded;
|
||||
return out;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
int ngap_gNB_initial_ctxt_resp(instance_t instance, ngap_initial_context_setup_resp_t *initial_ctxt_resp_p)
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -648,10 +606,39 @@ int ngap_gNB_initial_ctxt_resp(instance_t instance, ngap_initial_context_setup_r
|
||||
asn1cSequenceAdd(ie->value.choice.PDUSessionResourceSetupListCxtRes.list, NGAP_PDUSessionResourceSetupItemCxtRes_t, item);
|
||||
/* pDUSessionID */
|
||||
item->pDUSessionID = initial_ctxt_resp_p->pdusessions[i].pdusession_id;
|
||||
// PDU Session Resource Setup Response Transfer (Mandatory)
|
||||
byte_array_t ba = encode_ngap_pdusession_setup_response_transfer(&initial_ctxt_resp_p->pdusessions[i]);
|
||||
item->pDUSessionResourceSetupResponseTransfer.buf = ba.buf;
|
||||
item->pDUSessionResourceSetupResponseTransfer.size = ba.len;
|
||||
|
||||
/* dLQosFlowPerTNLInformation */
|
||||
NGAP_PDUSessionResourceSetupResponseTransfer_t pdusessionTransfer = {0};
|
||||
|
||||
pdusessionTransfer.dLQosFlowPerTNLInformation.uPTransportLayerInformation.present = NGAP_UPTransportLayerInformation_PR_gTPTunnel;
|
||||
|
||||
asn1cCalloc(pdusessionTransfer.dLQosFlowPerTNLInformation.uPTransportLayerInformation.choice.gTPTunnel, tmp);
|
||||
GTP_TEID_TO_ASN1(initial_ctxt_resp_p->pdusessions[i].gtp_teid, &tmp->gTP_TEID);
|
||||
tnl_to_bitstring(&tmp->transportLayerAddress, initial_ctxt_resp_p->pdusessions[i].gNB_addr);
|
||||
|
||||
NGAP_DEBUG("initial_ctxt_resp_p: pdusession ID %ld, gnb_addr %d.%d.%d.%d, SIZE %ld, TEID %u\n",
|
||||
item->pDUSessionID,
|
||||
tmp->transportLayerAddress.buf[0],
|
||||
tmp->transportLayerAddress.buf[1],
|
||||
tmp->transportLayerAddress.buf[2],
|
||||
tmp->transportLayerAddress.buf[3],
|
||||
tmp->transportLayerAddress.size,
|
||||
initial_ctxt_resp_p->pdusessions[i].gtp_teid);
|
||||
|
||||
/* associatedQosFlowList. number of 1? */
|
||||
for(int j=0; j < initial_ctxt_resp_p->pdusessions[i].nb_of_qos_flow; j++) {
|
||||
asn1cSequenceAdd(pdusessionTransfer.dLQosFlowPerTNLInformation.associatedQosFlowList.list, NGAP_AssociatedQosFlowItem_t, ass_qos_item_p);
|
||||
/* qosFlowIdentifier */
|
||||
ass_qos_item_p->qosFlowIdentifier = initial_ctxt_resp_p->pdusessions[i].associated_qos_flows[j].qfi;
|
||||
}
|
||||
|
||||
void *pdusessionTransfer_buffer;
|
||||
ssize_t encoded = aper_encode_to_new_buffer(&asn_DEF_NGAP_PDUSessionResourceSetupResponseTransfer, NULL, &pdusessionTransfer, &pdusessionTransfer_buffer);
|
||||
AssertFatal(encoded > 0, "ASN1 message encoding failed !\n");
|
||||
item->pDUSessionResourceSetupResponseTransfer.buf = pdusessionTransfer_buffer;
|
||||
item->pDUSessionResourceSetupResponseTransfer.size = encoded;
|
||||
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_PDUSessionResourceSetupResponseTransfer, &pdusessionTransfer);
|
||||
}
|
||||
}
|
||||
/* optional */
|
||||
@@ -937,10 +924,40 @@ int ngap_gNB_pdusession_setup_resp(instance_t instance, ngap_pdusession_setup_re
|
||||
/* pDUSessionID */
|
||||
item->pDUSessionID = pdusession->pdusession_id;
|
||||
|
||||
// PDU Session Resource Setup Response Transfer (Mandatory)
|
||||
byte_array_t ba = encode_ngap_pdusession_setup_response_transfer(pdusession);
|
||||
item->pDUSessionResourceSetupResponseTransfer.buf = ba.buf;
|
||||
item->pDUSessionResourceSetupResponseTransfer.size = ba.len;
|
||||
/* dLQosFlowPerTNLInformation */
|
||||
NGAP_PDUSessionResourceSetupResponseTransfer_t pdusessionTransfer = {0};
|
||||
pdusessionTransfer.dLQosFlowPerTNLInformation.uPTransportLayerInformation.present = NGAP_UPTransportLayerInformation_PR_gTPTunnel;
|
||||
asn1cCalloc(pdusessionTransfer.dLQosFlowPerTNLInformation.uPTransportLayerInformation.choice.gTPTunnel, tmp);
|
||||
GTP_TEID_TO_ASN1(pdusession->gtp_teid, &tmp->gTP_TEID);
|
||||
tnl_to_bitstring(&tmp->transportLayerAddress, pdusession->gNB_addr);
|
||||
NGAP_DEBUG("pdusession_setup_resp_p: pdusession ID %ld, gnb_addr %d.%d.%d.%d, SIZE %ld, TEID %u\n",
|
||||
item->pDUSessionID,
|
||||
tmp->transportLayerAddress.buf[0],
|
||||
tmp->transportLayerAddress.buf[1],
|
||||
tmp->transportLayerAddress.buf[2],
|
||||
tmp->transportLayerAddress.buf[3],
|
||||
tmp->transportLayerAddress.size,
|
||||
pdusession->gtp_teid);
|
||||
/* associatedQosFlowList. number of 1? */
|
||||
for(int j=0; j < pdusession_setup_resp_p->pdusessions[i].nb_of_qos_flow; j++) {
|
||||
asn1cSequenceAdd(pdusessionTransfer.dLQosFlowPerTNLInformation.associatedQosFlowList.list, NGAP_AssociatedQosFlowItem_t, ass_qos_item_p);
|
||||
|
||||
/* qosFlowIdentifier */
|
||||
ass_qos_item_p->qosFlowIdentifier = pdusession_setup_resp_p->pdusessions[i].associated_qos_flows[j].qfi;
|
||||
|
||||
/* qosFlowMappingIndication */
|
||||
// if(pdusession_setup_resp_p->pdusessions[i].associated_qos_flows[j].qos_flow_mapping_ind != QOSFLOW_MAPPING_INDICATION_NON) {
|
||||
// ass_qos_item_p->qosFlowMappingIndication = malloc(sizeof(*ass_qos_item_p->qosFlowMappingIndication));
|
||||
// *ass_qos_item_p->qosFlowMappingIndication = pdusession_setup_resp_p->pdusessions[i].associated_qos_flows[j].qos_flow_mapping_ind;
|
||||
// }
|
||||
}
|
||||
|
||||
asn_encode_to_new_buffer_result_t res = asn_encode_to_new_buffer(NULL, ATS_ALIGNED_CANONICAL_PER, &asn_DEF_NGAP_PDUSessionResourceSetupResponseTransfer, &pdusessionTransfer);
|
||||
AssertFatal (res.buffer, "ASN1 message encoding failed (%s, %lu)!\n", res.result.failed_type->name, res.result.encoded);
|
||||
item->pDUSessionResourceSetupResponseTransfer.buf = res.buffer;
|
||||
item->pDUSessionResourceSetupResponseTransfer.size = res.result.encoded;
|
||||
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_PDUSessionResourceSetupResponseTransfer, &pdusessionTransfer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1208,3 +1225,17 @@ int ngap_gNB_pdusession_release_resp(instance_t instance, ngap_pdusession_releas
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ngap_gNB_path_switch_req(instance_t instance, ngap_path_switch_req_t *path_switch_req_p)
|
||||
//------------------------------------------------------------------------------
|
||||
{
|
||||
//TODO
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ngap_gNB_generate_PDUSESSION_Modification_Indication(instance_t instance, ngap_pdusession_modification_ind_t *pdusession_modification_ind)
|
||||
//-----------------------------------------------------------------------------
|
||||
{
|
||||
//TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -63,4 +63,10 @@ int ngap_gNB_pdusession_modify_resp(instance_t instance,
|
||||
int ngap_gNB_pdusession_release_resp(instance_t instance,
|
||||
ngap_pdusession_release_resp_t *pdusession_release_resp_p);
|
||||
|
||||
int ngap_gNB_path_switch_req(instance_t instance,
|
||||
ngap_path_switch_req_t *path_switch_req_p);
|
||||
|
||||
int ngap_gNB_generate_PDUSESSION_Modification_Indication(
|
||||
instance_t instance, ngap_pdusession_modification_ind_t *pdusession_modification_ind);
|
||||
|
||||
#endif /* NGAP_GNB_NAS_PROCEDURES_H_ */
|
||||
|
||||
@@ -71,12 +71,5 @@
|
||||
#include "NGAP_UnsuccessfulOutcome.h"
|
||||
#include "NGAP_UserLocationInformationNR.h"
|
||||
#include "NGAP_asn_constant.h"
|
||||
#include "NGAP_PDUSessionResourceSetupRequestTransfer.h"
|
||||
#include "NGAP_QosFlowSetupRequestItem.h"
|
||||
#include "NGAP_QosCharacteristics.h"
|
||||
#include "NGAP_NonDynamic5QIDescriptor.h"
|
||||
#include "NGAP_Dynamic5QIDescriptor.h"
|
||||
#include "NGAP_PDUSessionResourceModifyRequestTransfer.h"
|
||||
#include "NGAP_QosFlowAddOrModifyRequestItem.h"
|
||||
|
||||
#endif // NGAP_MSG_INCLUDES_H
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
#define NR_FC_ALG_KEY_DER (0x69)
|
||||
#define NR_FC_ALG_KEY_NG_RAN_STAR_DER (0x70)
|
||||
|
||||
void log_hex_buffer(const char *label, const uint8_t *buf, const int len)
|
||||
static void log_hex_buffer(const char *label, const uint8_t *buf, const int len)
|
||||
{
|
||||
char hex_str[len * 2 + 1];
|
||||
for (int i = 0; i < len; i++) {
|
||||
|
||||
@@ -36,6 +36,4 @@ void nr_derive_key_ng_ran_star(uint16_t pci, uint64_t nr_arfcn_dl, const uint8_t
|
||||
|
||||
void nr_derive_nh(const uint8_t k_amf[SECURITY_KEY_LEN], const uint8_t *sync_input, uint8_t *nh);
|
||||
|
||||
void log_hex_buffer(const char *label, const uint8_t *buf, const int len);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -897,8 +897,7 @@ int gtpv1u_delete_all_s1u_tunnel(const instance_t instance, const rnti_t rnti)
|
||||
return newGtpuDeleteAllTunnels(instance, rnti);
|
||||
}
|
||||
|
||||
int newGtpuDeleteTunnels(instance_t instance, ue_id_t ue_id, int nbTunnels, int *pdusession_id)
|
||||
{
|
||||
int newGtpuDeleteTunnels(instance_t instance, ue_id_t ue_id, int nbTunnels, pdusessionid_t *pdusession_id) {
|
||||
LOG_D(GTPU, "[%ld] Start delete tunnels for ue id %lu\n",
|
||||
instance, ue_id);
|
||||
pthread_mutex_lock(&globGtp.gtp_lock);
|
||||
|
||||
@@ -103,7 +103,7 @@ extern "C" {
|
||||
|
||||
int newGtpuDeleteOneTunnel(instance_t instance, ue_id_t ue_id, int rb_id);
|
||||
int newGtpuDeleteAllTunnels(instance_t instance, ue_id_t ue_id);
|
||||
int newGtpuDeleteTunnels(instance_t instance, ue_id_t ue_id, int nbTunnels, int *pdusession_id);
|
||||
int newGtpuDeleteTunnels(instance_t instance, ue_id_t ue_id, int nbTunnels, pdusessionid_t *pdusession_id);
|
||||
|
||||
void gtpv1uSendDirect(instance_t instance, ue_id_t ue_id, int bearer_id, uint8_t *buf, size_t len, bool seqNumFlag, bool npduNumFlag);
|
||||
|
||||
|
||||
@@ -1,4 +1,17 @@
|
||||
add_library(vrtsim MODULE vrtsim.c noise_device.c)
|
||||
set_target_properties(vrtsim PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
target_link_libraries(vrtsim PRIVATE SIMU shm_td_iq_channel actor)
|
||||
target_link_libraries(vrtsim PRIVATE SIMU shm_td_iq_channel actor taps_client)
|
||||
add_dependencies(vrtsim generate_T)
|
||||
set(TAPS_API_HEADER taps_generated.h)
|
||||
|
||||
add_custom_command(OUTPUT ${TAPS_API_HEADER}
|
||||
COMMAND flatc -c ${CMAKE_CURRENT_SOURCE_DIR}/taps.fbs
|
||||
DEPENDS taps.fbs
|
||||
COMMENT "Generating flatbuffers API from ${TAPS_IF_PATH}"
|
||||
)
|
||||
add_library(taps_api INTERFACE)
|
||||
target_include_directories(taps_api INTERFACE ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
add_library(taps_client taps_client.cpp ${TAPS_API_HEADER})
|
||||
target_include_directories(taps_client PUBLIC .)
|
||||
target_link_libraries(taps_client PUBLIC flatbuffers taps_api SIMU nanomsg)
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
#include "assertions.h"
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include "noise_device.h"
|
||||
@@ -74,7 +75,8 @@ void init_noise_device(float noise_power)
|
||||
void free_noise_device(void)
|
||||
{
|
||||
state.running = false;
|
||||
pthread_join(state.noise_device_thread, NULL);
|
||||
int ret = pthread_join(state.noise_device_thread, NULL);
|
||||
AssertFatal(ret == 0, "pthread_join failed: %d, errno %d (%s)\n", ret, errno, strerror(errno));
|
||||
}
|
||||
|
||||
void get_noise_vector(float *noise_vector, int length)
|
||||
|
||||
14
radio/vrtsim/taps.fbs
Normal file
14
radio/vrtsim/taps.fbs
Normal file
@@ -0,0 +1,14 @@
|
||||
// This file defines the structure of the Taps table used in the PHY layer.
|
||||
namespace Phy;
|
||||
|
||||
// Taps form the discrete complex baseband-equivalent channel impulse response and can be used
|
||||
// to model the channel characteristics in link layer simulations.
|
||||
table Taps {
|
||||
id:uint;
|
||||
num_tx_antennas:uint;
|
||||
num_rx_antennas:uint;
|
||||
taps_len:uint;
|
||||
taps:[float];
|
||||
}
|
||||
|
||||
root_type Taps;
|
||||
194
radio/vrtsim/taps_client.cpp
Normal file
194
radio/vrtsim/taps_client.cpp
Normal file
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (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.openairinterface.org/?page_id=698
|
||||
*
|
||||
* 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.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
#include <nanomsg/nn.h>
|
||||
#include <nanomsg/pubsub.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "pthread.h"
|
||||
#include "taps_generated.h"
|
||||
#include "SIMULATION/TOOLS/sim.h"
|
||||
extern "C" {
|
||||
#include "assertions.h"
|
||||
#include "common/utils/LOG/log.h"
|
||||
#include "sim.h"
|
||||
#include "utils.h"
|
||||
}
|
||||
#include <cfloat>
|
||||
|
||||
#define NUM_TAPS_BUFFERS 4
|
||||
#define MAX_TAPS_LEN 100
|
||||
#define MAX_TAPS_MSG_SIZE (sizeof(struct complexf) * MAX_TAPS_LEN * 4 * 4 + 20)
|
||||
|
||||
static pthread_t client_thread;
|
||||
static bool should_run = true;
|
||||
typedef struct {
|
||||
int id;
|
||||
int sock;
|
||||
uint32_t num_tx_antennas;
|
||||
uint32_t num_rx_antennas;
|
||||
channel_desc_t **channel_desc;
|
||||
} client_thread_args_t;
|
||||
|
||||
typedef struct {
|
||||
void *taps_msg;
|
||||
channel_desc_t *channel_desc;
|
||||
} taps_buffer_t;
|
||||
|
||||
typedef struct {
|
||||
taps_buffer_t taps_buffers[NUM_TAPS_BUFFERS];
|
||||
int current_buffer;
|
||||
} taps_storage_t;
|
||||
|
||||
void ascii_line_plot(const float *data, size_t size, char* buffer) {
|
||||
const char *levels = "_.-=#"; // ASCII characters for different levels
|
||||
size_t num_levels = strlen(levels) - 1; // Number of levels (excluding the null terminator)
|
||||
|
||||
// Calculate min and max values from the data
|
||||
float min_val = FLT_MAX;
|
||||
float max_val = FLT_MIN;
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
if (data[i] < min_val) min_val = data[i];
|
||||
if (data[i] > max_val) max_val = data[i];
|
||||
}
|
||||
|
||||
// Handle edge case where all values are the same
|
||||
if (min_val == max_val) {
|
||||
min_val -= 1.0f;
|
||||
max_val += 1.0f;
|
||||
}
|
||||
|
||||
// Normalize and map data to levels
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
float normalized = (data[i] - min_val) / (max_val - min_val); // Normalize to [0, 1]
|
||||
size_t level_index = (size_t)(normalized * num_levels); // Map to level index
|
||||
if (level_index > num_levels) level_index = num_levels; // Clamp to valid range
|
||||
snprintf(buffer + i, 2, "%c", levels[level_index]);
|
||||
}
|
||||
}
|
||||
|
||||
static void init_taps_storage(taps_storage_t *storage, int num_tx_antennas, int num_rx_antennas)
|
||||
{
|
||||
for (int i = 0; i < NUM_TAPS_BUFFERS; i++) {
|
||||
storage->taps_buffers[i].taps_msg = calloc_or_fail(1, MAX_TAPS_MSG_SIZE);
|
||||
storage->taps_buffers[i].channel_desc = (channel_desc_t *)calloc_or_fail(1, sizeof(channel_desc_t));
|
||||
storage->taps_buffers[i].channel_desc->ch_ps =
|
||||
(struct complexf **)calloc_or_fail(num_rx_antennas * num_tx_antennas, sizeof(struct complexf *));
|
||||
}
|
||||
storage->current_buffer = 0;
|
||||
}
|
||||
|
||||
static taps_storage_t taps_storage;
|
||||
|
||||
void *client_thread_func(void *args)
|
||||
{
|
||||
client_thread_args_t *client_thread_args = (client_thread_args_t *)args;
|
||||
while (should_run) {
|
||||
int next_buffer = (taps_storage.current_buffer + 1) % NUM_TAPS_BUFFERS;
|
||||
taps_buffer_t *taps_buffer = &taps_storage.taps_buffers[next_buffer];
|
||||
int ret = nn_recv(client_thread_args->sock, taps_buffer->taps_msg, MAX_TAPS_MSG_SIZE, 0);
|
||||
if (ret < 0) {
|
||||
LOG_E(HW, "nn_recv() failed: errno: %d, %s\n", errno, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
auto taps_message = Phy::GetTaps(taps_buffer->taps_msg);
|
||||
if (taps_message->num_rx_antennas() != client_thread_args->num_rx_antennas
|
||||
|| taps_message->num_tx_antennas() != client_thread_args->num_tx_antennas) {
|
||||
LOG_E(HW,
|
||||
"Number of antennas mismatch: expected %d x %d, got %d x %d\n",
|
||||
client_thread_args->num_rx_antennas,
|
||||
client_thread_args->num_tx_antennas,
|
||||
taps_message->num_rx_antennas(),
|
||||
taps_message->num_tx_antennas());
|
||||
continue;
|
||||
}
|
||||
channel_desc_t *channel_desc = taps_buffer->channel_desc;
|
||||
const flatbuffers::Vector<float> *taps = taps_message->taps();
|
||||
struct complexf *base_pointer = (struct complexf *)taps->data();
|
||||
int taps_len = taps_message->taps_len();
|
||||
AssertFatal(taps_len < MAX_TAPS_LEN, "Too many samples in the taps array, taps_len = %d\n", taps_len);
|
||||
for (unsigned int aarx = 0U; aarx < client_thread_args->num_rx_antennas; aarx++) {
|
||||
for (unsigned int aatx = 0U; aatx < client_thread_args->num_tx_antennas; aatx++) {
|
||||
channel_desc->ch_ps[aarx + (client_thread_args->num_rx_antennas * aatx)] =
|
||||
&base_pointer[(aarx + (client_thread_args->num_rx_antennas * aatx)) * taps_len];
|
||||
}
|
||||
}
|
||||
channel_desc->path_loss_dB = 0;
|
||||
channel_desc->channel_length = taps_len;
|
||||
*client_thread_args->channel_desc = channel_desc;
|
||||
taps_storage.current_buffer = next_buffer;
|
||||
LOG_A(HW, "Receved new taps message, channel_length %d, buffer %d\n", channel_desc->channel_length, next_buffer);
|
||||
for (unsigned int aarx = 0; aarx < client_thread_args->num_rx_antennas; aarx++) {
|
||||
for (unsigned int aatx = 0; aatx < client_thread_args->num_tx_antennas; aatx++) {
|
||||
char buffer[MAX_TAPS_LEN + 1];
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
float magnitudes[MAX_TAPS_LEN];
|
||||
cf_t *channel = channel_desc->ch_ps[aarx + (client_thread_args->num_rx_antennas * aatx)];
|
||||
for (int i = 0; i < channel_desc->channel_length; i++) {
|
||||
magnitudes[i] = sqrtf(powf(channel[i].r, 2) + powf(channel[i].i, 2));
|
||||
}
|
||||
ascii_line_plot(magnitudes, channel_desc->channel_length, buffer);
|
||||
LOG_A(HW, "Taps message %d, channel %d x %d: %s\n", client_thread_args->id, aarx, aatx, buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
extern "C" void taps_client_connect(int id,
|
||||
const char *socket_path,
|
||||
int num_tx_antennas,
|
||||
int num_rx_antennas,
|
||||
channel_desc_t **channel_desc)
|
||||
{
|
||||
// Create a socket
|
||||
int sock = nn_socket(AF_SP, NN_SUB);
|
||||
AssertFatal(sock >= 0, "nn_socket() failed: errno: %d, %s\n", errno, strerror(errno));
|
||||
|
||||
int ret = nn_connect(sock, socket_path);
|
||||
AssertFatal(ret >= 0, "nn_connect() failed: errno: %d, %s\n", errno, strerror(errno));
|
||||
|
||||
// Subscribe to all messages
|
||||
ret = nn_setsockopt(sock, NN_SUB, NN_SUB_SUBSCRIBE, "", 0);
|
||||
AssertFatal(ret == 0, "nn_setsockopt() failed, errno %d, %s\n", errno, strerror(errno));
|
||||
|
||||
init_taps_storage(&taps_storage, num_tx_antennas, num_rx_antennas);
|
||||
|
||||
client_thread_args_t *client_thread_args = static_cast<client_thread_args_t *>(malloc(sizeof(client_thread_args_t)));
|
||||
client_thread_args->id = id;
|
||||
client_thread_args->sock = sock;
|
||||
client_thread_args->num_rx_antennas = num_rx_antennas;
|
||||
client_thread_args->num_tx_antennas = num_tx_antennas;
|
||||
client_thread_args->channel_desc = channel_desc;
|
||||
ret = pthread_create(&client_thread, NULL, client_thread_func, client_thread_args);
|
||||
AssertFatal(ret == 0, "pthread_create() failed: errno: %d, %s\n", errno, strerror(errno));
|
||||
}
|
||||
|
||||
extern "C" void taps_client_stop()
|
||||
{
|
||||
should_run = false;
|
||||
pthread_join(client_thread, NULL);
|
||||
for (int i = 0; i < NUM_TAPS_BUFFERS; i++) {
|
||||
free(taps_storage.taps_buffers[i].taps_msg);
|
||||
free(taps_storage.taps_buffers[i].channel_desc->ch_ps);
|
||||
free(taps_storage.taps_buffers[i].channel_desc);
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
@@ -19,20 +19,20 @@
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#ifndef FGMM_AUTH_REJECT_H
|
||||
#define FGMM_AUTH_REJECT_H
|
||||
#ifndef TAPS_CLIENT_H
|
||||
#define TAPS_CLIENT_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "fgmm_lib.h"
|
||||
#include "common/utils/ds/byte_array.h"
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
// EAP Message (Optional)
|
||||
byte_array_t eap_msg;
|
||||
} fgmm_auth_reject_msg_t;
|
||||
#include "sim.h"
|
||||
|
||||
int decode_fgmm_auth_reject(fgmm_auth_reject_msg_t *msg, const byte_array_t *buffer);
|
||||
int encode_fgmm_auth_reject(byte_array_t *buffer, const fgmm_auth_reject_msg_t *msg);
|
||||
bool eq_auth_reject(fgmm_auth_reject_msg_t *a, fgmm_auth_reject_msg_t *b);
|
||||
void taps_client_connect(int id, const char *socket_path, int num_tx_antennas, int num_rx_antennas, channel_desc_t **channel_desc);
|
||||
void taps_client_stop();
|
||||
|
||||
#endif /* FGMM_AUTH_REJECT_H */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -19,6 +19,7 @@
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#include "PHY/TOOLS/tools_defs.h"
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
@@ -46,11 +47,13 @@
|
||||
#include "actor.h"
|
||||
#include "noise_device.h"
|
||||
#include "simde/x86/avx512.h"
|
||||
#include "taps_client.h"
|
||||
|
||||
// Simulator role
|
||||
typedef enum { ROLE_SERVER = 1, ROLE_CLIENT } role;
|
||||
|
||||
#define NUM_CHANMOD_THREADS 1
|
||||
#define MAX_NUM_ANTENNAS_TX 4
|
||||
#define MAX_CHANNEL_LENGTH (1 << 20)
|
||||
|
||||
#define ROLE_CLIENT_STRING "client"
|
||||
#define ROLE_SERVER_STRING "server"
|
||||
@@ -58,6 +61,8 @@ typedef enum { ROLE_SERVER = 1, ROLE_CLIENT } role;
|
||||
#define VRTSIM_SECTION "vrtsim"
|
||||
#define TIME_SCALE_HLP \
|
||||
"sample time scale. 1.0 means realtime. Values > 1 mean faster than realtime. Values < 1 mean slower than realtime\n"
|
||||
#define TAPS_SOCKET_HLP \
|
||||
"Socket to connect to the channel emulation server. If not set channel emulation would be done inline\n"
|
||||
|
||||
// clang-format off
|
||||
#define VRTSIM_PARAMS_DESC \
|
||||
@@ -66,6 +71,7 @@ typedef enum { ROLE_SERVER = 1, ROLE_CLIENT } role;
|
||||
{"role", "either client or server\n", 0, .strptr = &role, .defstrval = ROLE_CLIENT_STRING, TYPE_STRING, 0}, \
|
||||
{"timescale", TIME_SCALE_HLP, 0, .dblptr = &vrtsim_state->timescale, .defdblval = 1.0, TYPE_DOUBLE, 0}, \
|
||||
{"chanmod", "Enable channel modelling", 0, .iptr = &vrtsim_state->chanmod, .defintval = 0, TYPE_INT, 0}, \
|
||||
{"taps-socket", TAPS_SOCKET_HLP, 0, .strptr = &vrtsim_state->taps_socket, .defstrval = NULL, TYPE_STRING, 0}, \
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -110,8 +116,12 @@ typedef struct {
|
||||
int rx_num_channels;
|
||||
channel_desc_t *channel_desc;
|
||||
Actor_t *channel_modelling_actors;
|
||||
char *taps_socket;
|
||||
} vrtsim_state_t;
|
||||
|
||||
// Sample history for channel impulse response
|
||||
static c16_t saved_samples[MAX_NUM_ANTENNAS_TX][MAX_CHANNEL_LENGTH] __attribute__((aligned(32))) = {0};
|
||||
|
||||
static void histogram_add(histogram_t *histogram, double diff)
|
||||
{
|
||||
histogram->num_samples++;
|
||||
@@ -149,6 +159,16 @@ static void load_channel_model(vrtsim_state_t *vrtsim_state)
|
||||
vrtsim_state->tx_bw);
|
||||
char *model_name = vrtsim_state->role == ROLE_CLIENT ? "client_tx_channel_model" : "server_tx_channel_model";
|
||||
vrtsim_state->channel_desc = find_channel_desc_fromname(model_name);
|
||||
AssertFatal(vrtsim_state->channel_desc != NULL,
|
||||
"Could not find model name %s. Make sure it is present in the config file",
|
||||
model_name);
|
||||
LOG_I(HW,
|
||||
"Channel model %s parameters: path_loss_dB=%.2f, nb_tx=%d, nb_rx=%d, channel_length=%d\n",
|
||||
model_name,
|
||||
vrtsim_state->channel_desc->path_loss_dB,
|
||||
vrtsim_state->channel_desc->nb_tx,
|
||||
vrtsim_state->channel_desc->nb_rx,
|
||||
vrtsim_state->channel_desc->channel_length);
|
||||
random_channel(vrtsim_state->channel_desc, 0);
|
||||
AssertFatal(vrtsim_state->channel_desc != NULL, "Could not find channel model %s\n", model_name);
|
||||
}
|
||||
@@ -168,6 +188,9 @@ static void vrtsim_readconfig(vrtsim_state_t *vrtsim_state)
|
||||
} else {
|
||||
AssertFatal(false, "Invalid role configuration\n");
|
||||
}
|
||||
if (vrtsim_state->taps_socket) {
|
||||
LOG_A(HW, "VRTSIM: will use taps socket %s\n", vrtsim_state->taps_socket);
|
||||
}
|
||||
}
|
||||
|
||||
static void *vrtsim_timing_job(void *arg)
|
||||
@@ -311,12 +334,20 @@ static int vrtsim_connect(openair0_device *device)
|
||||
|
||||
// Handle channel modelling after number of RX antennas are known
|
||||
int num_tx_stats = 1;
|
||||
if (vrtsim_state->chanmod) {
|
||||
if (vrtsim_state->chanmod || vrtsim_state->taps_socket) {
|
||||
vrtsim_state->channel_modelling_actors = calloc_or_fail(vrtsim_state->peer_info.num_rx_antennas, sizeof(Actor_t));
|
||||
for (int i = 0; i < vrtsim_state->peer_info.num_rx_antennas; i++) {
|
||||
init_actor(&vrtsim_state->channel_modelling_actors[i], "chanmod", -1);
|
||||
}
|
||||
load_channel_model(vrtsim_state);
|
||||
if (vrtsim_state->taps_socket) {
|
||||
taps_client_connect(0,
|
||||
vrtsim_state->taps_socket,
|
||||
device->openair0_cfg[0].tx_num_channels,
|
||||
vrtsim_state->peer_info.num_rx_antennas,
|
||||
&vrtsim_state->channel_desc);
|
||||
} else {
|
||||
load_channel_model(vrtsim_state);
|
||||
}
|
||||
num_tx_stats = vrtsim_state->peer_info.num_rx_antennas;
|
||||
}
|
||||
vrtsim_state->tx_timing = calloc_or_fail(num_tx_stats, sizeof(tx_timing_t));
|
||||
@@ -376,7 +407,7 @@ static int vrtsim_write_internal(vrtsim_state_t *vrtsim_state,
|
||||
typedef struct {
|
||||
vrtsim_state_t *vrtsim_state;
|
||||
openair0_timestamp timestamp;
|
||||
c16_t *samples[4];
|
||||
c16_t *samples[MAX_NUM_ANTENNAS_TX];
|
||||
int nsamps;
|
||||
int nbAnt;
|
||||
int flags;
|
||||
@@ -386,6 +417,7 @@ typedef struct {
|
||||
static void perform_channel_modelling(void *arg)
|
||||
{
|
||||
channel_modelling_args_t *channel_modelling_args = arg;
|
||||
vrtsim_state_t *vrtsim_state = channel_modelling_args->vrtsim_state;
|
||||
int nsamps = channel_modelling_args->nsamps;
|
||||
int aarx = channel_modelling_args->aarx;
|
||||
int nb_tx_ant = channel_modelling_args->nbAnt;
|
||||
@@ -396,31 +428,43 @@ static void perform_channel_modelling(void *arg)
|
||||
// Apply noise from global settings
|
||||
get_noise_vector((float *)samples, nsamps * 2);
|
||||
|
||||
channel_desc_t *channel_desc = channel_modelling_args->vrtsim_state->channel_desc;
|
||||
const float pathloss_linear = powf(10, channel_desc->path_loss_dB / 20.0);
|
||||
channel_desc_t *channel_desc = vrtsim_state->channel_desc;
|
||||
|
||||
if (channel_desc == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert channel impulse response to float + apply pathloss
|
||||
cf_t channel_impulse_response[nb_tx_ant][channel_desc->channel_length];
|
||||
for (int aatx = 0; aatx < nb_tx_ant; aatx++) {
|
||||
const struct complexd *channelModel = channel_desc->ch[aarx + (aatx * channel_desc->nb_rx)];
|
||||
for (int i = 0; i < channel_desc->channel_length; i++) {
|
||||
channel_impulse_response[aatx][i].r = channelModel[i].r * pathloss_linear;
|
||||
channel_impulse_response[aatx][i].i = channelModel[i].i * pathloss_linear;
|
||||
cf_t *channel_impulse_response_p[nb_tx_ant];
|
||||
if (!vrtsim_state->taps_socket) {
|
||||
const float pathloss_linear = powf(10, channel_desc->path_loss_dB / 20.0);
|
||||
// Convert channel impulse response to float + apply pathloss
|
||||
for (int aatx = 0; aatx < nb_tx_ant; aatx++) {
|
||||
const struct complexd *channelModel = channel_desc->ch[aarx + (aatx * channel_desc->nb_rx)];
|
||||
for (int i = 0; i < channel_desc->channel_length; i++) {
|
||||
channel_impulse_response[aatx][i].r = channelModel[i].r * pathloss_linear;
|
||||
channel_impulse_response[aatx][i].i = channelModel[i].i * pathloss_linear;
|
||||
}
|
||||
channel_impulse_response_p[aatx] = channel_impulse_response[aatx];
|
||||
}
|
||||
} else {
|
||||
for (int aatx = 0; aatx < nb_tx_ant; aatx++) {
|
||||
struct complexf *channelModel = channel_desc->ch_ps[aarx + (aatx * channel_desc->nb_rx)];
|
||||
channel_impulse_response_p[aatx] = channelModel;
|
||||
}
|
||||
}
|
||||
|
||||
for (int aatx = 0; aatx < nb_tx_ant; aatx++) {
|
||||
c16_t *previous_samples = saved_samples[aatx];
|
||||
for (int i = 0; i < nsamps; i++) {
|
||||
cf_t *impulse_response = channel_impulse_response[aatx];
|
||||
cf_t *impulse_response = channel_impulse_response_p[aatx];
|
||||
for (int l = 0; l < channel_desc->channel_length; l++) {
|
||||
int idx = i - l;
|
||||
// TODO: Use AVX512 for this
|
||||
// TODO: What are the previously sent samples (for impulse response)
|
||||
if (idx >= 0) {
|
||||
c16_t tx_input = input_samples[aatx][idx];
|
||||
samples[i].r += tx_input.r * impulse_response[l].r - tx_input.i * impulse_response[l].i;
|
||||
samples[i].i += tx_input.i * impulse_response[l].r + tx_input.r * impulse_response[l].i;
|
||||
}
|
||||
// TODO: Use AVX2 for this
|
||||
c16_t tx_input = idx >= 0 ? input_samples[aatx][idx]
|
||||
: previous_samples[(channel_modelling_args->timestamp + i + idx) % MAX_CHANNEL_LENGTH];
|
||||
samples[i].r += tx_input.r * impulse_response[l].r - tx_input.i * impulse_response[l].i;
|
||||
samples[i].i += tx_input.i * impulse_response[l].r + tx_input.r * impulse_response[l].i;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -462,6 +506,7 @@ static int vrtsim_write_with_chanmod(vrtsim_state_t *vrtsim_state,
|
||||
int nbAnt,
|
||||
int flags)
|
||||
{
|
||||
AssertFatal(nbAnt < MAX_NUM_ANTENNAS_TX, "Number of antennas %d exceeds maximum %d\n", nbAnt, MAX_NUM_ANTENNAS_TX);
|
||||
for (int aarx = 0; aarx < vrtsim_state->peer_info.num_rx_antennas; aarx++) {
|
||||
notifiedFIFO_elt_t *task = newNotifiedFIFO_elt(sizeof(channel_modelling_args_t), 0, NULL, perform_channel_modelling);
|
||||
channel_modelling_args_t *args = (channel_modelling_args_t *)NotifiedFifoData(task);
|
||||
@@ -476,6 +521,23 @@ static int vrtsim_write_with_chanmod(vrtsim_state_t *vrtsim_state,
|
||||
}
|
||||
pushNotifiedFIFO(&vrtsim_state->channel_modelling_actors[aarx].fifo, task);
|
||||
}
|
||||
int start_index = timestamp % MAX_CHANNEL_LENGTH;
|
||||
if (start_index + nsamps > MAX_CHANNEL_LENGTH) {
|
||||
// Requires two copies
|
||||
for (int aatx = 0; aatx < nbAnt; aatx++) {
|
||||
int first_copy_size = MAX_CHANNEL_LENGTH - start_index;
|
||||
c16_t *samples = (c16_t *)samplesVoid[aatx];
|
||||
memcpy(&saved_samples[aatx][start_index], &samples[0], sizeof(c16_t) * first_copy_size);
|
||||
int second_copy_size = nsamps - first_copy_size;
|
||||
memcpy(&saved_samples[aatx][0], &samples[first_copy_size], sizeof(c16_t) * second_copy_size);
|
||||
}
|
||||
} else {
|
||||
// Single copy
|
||||
for (int aatx = 0; aatx < nbAnt; aatx++) {
|
||||
c16_t *samples = (c16_t *)samplesVoid[aatx];
|
||||
memcpy(&saved_samples[aatx][start_index], &samples[0], sizeof(c16_t) * nsamps);
|
||||
}
|
||||
}
|
||||
return nsamps;
|
||||
}
|
||||
|
||||
@@ -483,14 +545,23 @@ static int vrtsim_write(openair0_device *device, openair0_timestamp timestamp, v
|
||||
{
|
||||
timestamp -= device->openair0_cfg->command_line_sample_advance;
|
||||
vrtsim_state_t *vrtsim_state = (vrtsim_state_t *)device->priv;
|
||||
return vrtsim_state->chanmod ? vrtsim_write_with_chanmod(vrtsim_state, timestamp, samplesVoid, nsamps, nbAnt, flags)
|
||||
: vrtsim_write_internal(vrtsim_state, timestamp, (c16_t *)samplesVoid[0], nsamps, 0, flags, 0);
|
||||
bool channel_modelling = vrtsim_state->chanmod || vrtsim_state->taps_socket;
|
||||
return channel_modelling ? vrtsim_write_with_chanmod(vrtsim_state, timestamp, samplesVoid, nsamps, nbAnt, flags)
|
||||
: vrtsim_write_internal(vrtsim_state, timestamp, (c16_t *)samplesVoid[0], nsamps, 0, flags, 0);
|
||||
}
|
||||
|
||||
static int vrtsim_read(openair0_device *device, openair0_timestamp *ptimestamp, void **samplesVoid, int nsamps, int nbAnt)
|
||||
{
|
||||
vrtsim_state_t *vrtsim_state = (vrtsim_state_t *)device->priv;
|
||||
shm_td_iq_channel_wait(vrtsim_state->channel, vrtsim_state->last_received_sample + nsamps);
|
||||
if (shm_td_iq_channel_is_aborted(vrtsim_state->channel)) {
|
||||
LOG_E(HW, "Channel is aborted, returning void samples\n");
|
||||
for (int i = 0; i < nbAnt; i++) {
|
||||
memset(samplesVoid[i], 0, sizeof(c16_t) * nsamps);
|
||||
}
|
||||
return nsamps;
|
||||
}
|
||||
uint64_t timeout_uS = 2 * 1000 * 1000 / vrtsim_state->timescale; // 2 seconds in uS
|
||||
shm_td_iq_channel_wait(vrtsim_state->channel, vrtsim_state->last_received_sample + nsamps, timeout_uS);
|
||||
int ret = shm_td_iq_channel_rx(vrtsim_state->channel, vrtsim_state->last_received_sample, nsamps, 0, samplesVoid[0]);
|
||||
if (ret == CHANNEL_ERROR_TOO_LATE) {
|
||||
vrtsim_state->rx_samples_late += nsamps;
|
||||
@@ -506,14 +577,14 @@ static int vrtsim_read(openair0_device *device, openair0_timestamp *ptimestamp,
|
||||
static void vrtsim_end(openair0_device *device)
|
||||
{
|
||||
vrtsim_state_t *vrtsim_state = (vrtsim_state_t *)device->priv;
|
||||
if (vrtsim_state->role == ROLE_SERVER) {
|
||||
if (vrtsim_state->role == ROLE_SERVER && vrtsim_state->run_timing_thread) {
|
||||
vrtsim_state->run_timing_thread = false;
|
||||
int ret = pthread_join(vrtsim_state->timing_thread, NULL);
|
||||
AssertFatal(ret == 0, "pthread_join() failed: errno: %d, %s\n", errno, strerror(errno));
|
||||
}
|
||||
|
||||
tx_timing_t *tx_timing = vrtsim_state->tx_timing;
|
||||
if (vrtsim_state->chanmod) {
|
||||
if (vrtsim_state->chanmod || vrtsim_state->taps_socket) {
|
||||
for (int i = 0; i < vrtsim_state->peer_info.num_rx_antennas; i++) {
|
||||
shutdown_actor(&vrtsim_state->channel_modelling_actors[i]);
|
||||
}
|
||||
@@ -526,9 +597,12 @@ static void vrtsim_end(openair0_device *device)
|
||||
tx_timing->tx_samples_total += tx_timing[i].tx_samples_total;
|
||||
}
|
||||
tx_timing->average_tx_budget /= vrtsim_state->peer_info.num_rx_antennas;
|
||||
free_noise_device();
|
||||
if (vrtsim_state->taps_socket) {
|
||||
taps_client_stop();
|
||||
}
|
||||
}
|
||||
// produce 1 second of extra samples so threads can finish
|
||||
shm_td_iq_channel_produce_samples(vrtsim_state->channel, vrtsim_state->sample_rate);
|
||||
shm_td_iq_channel_abort(vrtsim_state->channel);
|
||||
sleep(1);
|
||||
shm_td_iq_channel_destroy(vrtsim_state->channel);
|
||||
|
||||
@@ -588,10 +662,11 @@ __attribute__((__visibility__("default"))) int device_init(openair0_device *devi
|
||||
vrtsim_state->tx_num_channels = openair0_cfg->tx_num_channels;
|
||||
vrtsim_state->rx_num_channels = openair0_cfg->rx_num_channels;
|
||||
|
||||
if (vrtsim_state->chanmod) {
|
||||
if (vrtsim_state->chanmod || vrtsim_state->taps_socket) {
|
||||
init_channelmod();
|
||||
int noise_power_dBFS = get_noise_power_dBFS();
|
||||
int16_t noise_power = noise_power_dBFS == INVALID_DBFS_VALUE ? 0 : (int16_t)(32767.0 / powf(10.0, .05 * -noise_power_dBFS));
|
||||
LOG_A(HW, "VRTSIM: Noise power %d sample value\n", noise_power);
|
||||
init_noise_device(noise_power);
|
||||
}
|
||||
return 0;
|
||||
|
||||
@@ -11,7 +11,7 @@ gNBs =
|
||||
|
||||
// Tracking area code, 0x0000 and 0xfffe are reserved values
|
||||
tracking_area_code = 1;
|
||||
plmn_list = ({ mcc = 001; mnc = 01; mnc_length = 2; snssaiList = ({ sst = 1; }) }, { mcc = 001; mnc = 02; mnc_length = 2; snssaiList = ({ sst = 1; }) });
|
||||
plmn_list = ({ mcc = 001; mnc = 01; mnc_length = 2; snssaiList = ({ sst = 1; }) });
|
||||
|
||||
nr_cellid = 12345678L;
|
||||
|
||||
@@ -19,7 +19,7 @@ gNBs =
|
||||
|
||||
do_CSIRS = 1;
|
||||
do_SRS = 1;
|
||||
min_rxtxtime = 6;
|
||||
|
||||
#uess_agg_levels = [0,1,2,2,1]
|
||||
servingCellConfigCommon = (
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user