Commit 32c81b7b authored by Robert Schmidt's avatar Robert Schmidt

Merge branch 'integration_2025_w38' into 'develop'

Integration: `2025.w38`

Closes #954

See merge request oai/openairinterface5g!3646

* !3639 Fix error ind unpack
* !3643 Fix memory allocation issue in KPM RAN function sd parameter handling
* !3568 Fix UE DCI monitoring after RRC setup
* !3642 Check command line for unknown options also at gNB
* !3647 Add nr-cuup to run_locally.sh
* !3596 L3 measurements and measReport A2
* !3648 fix MSG3 with C-RNTI failure
* !3649 CI: build images on Jetson (armv8)
* !3334 N2 Handover
parents 206c7667 84c51802
......@@ -363,6 +363,7 @@ add_library(ngap
${NGAP_DIR}/ngap_gNB.c
${NGAP_DIR}/ngap_common.c
${NGAP_DIR}/ngap_gNB_context_management_procedures.c
${NGAP_DIR}/ngap_gNB_mobility_management.c
${NGAP_DIR}/ngap_gNB_decoder.c
${NGAP_DIR}/ngap_gNB_encoder.c
${NGAP_DIR}/ngap_gNB_handlers.c
......
......@@ -175,6 +175,28 @@ pipeline {
}
}
}
stage ("Ubuntu-Jetson-Image-Builder") {
steps {
script {
triggerSlaveJob ('RAN-Ubuntu-Jetson-Image-Builder', 'Ubuntu-Jetson-Image-Builder')
}
}
post {
always {
script {
// Using a unique variable name for each test stage to avoid overwriting on a global variable
// due to parallel-time concurrency
ubuntuJetsonBuildStatus = finalizeSlaveJob('RAN-Ubuntu-Jetson-Image-Builder')
}
}
failure {
script {
currentBuild.result = 'FAILURE'
failingStages += ubuntuJetsonBuildStatus
}
}
}
}
stage ("RHEL-Cluster-Image-Builder") {
steps {
script {
......
......@@ -304,13 +304,18 @@ class Containerize():
result = re.search('build_cross_arm64', self.imageKind)
if result is not None:
self.dockerfileprefix = '.ubuntu.cross-arm64'
result = re.search('native_arm', self.imageKind)
result = re.search('native_armv9', self.imageKind)
if result is not None:
imageNames.append(('oai-gnb', 'gNB', 'oai-gnb', ''))
imageNames.append(('ran-build-fhi72', 'build.fhi72.native_arm', 'ran-build-fhi72', ''))
imageNames.append(('oai-nr-cuup', 'nr-cuup', 'oai-nr-cuup', ''))
imageNames.append(('oai-nr-ue', 'nrUE', 'oai-nr-ue', ''))
imageNames.append(('oai-gnb-aerial', 'gNB.aerial', 'oai-gnb-aerial', ''))
result = re.search('native_armv8', self.imageKind)
if result is not None:
imageNames.append(('oai-gnb', 'gNB', 'oai-gnb', ''))
imageNames.append(('oai-nr-cuup', 'nr-cuup', 'oai-nr-cuup', ''))
imageNames.append(('oai-nr-ue', 'nrUE', 'oai-nr-ue', ''))
cmd.cd(lSourcePath)
# if asterix, copy the entitlement and subscription manager configurations
......
......@@ -15,7 +15,7 @@ gNBs =
// Tracking area code, 0x0000 and 0xfffe are reserved values
tracking_area_code = 1;
plmn_list = ({ mcc = 208; mnc = 99; mnc_length = 2; snssaiList = ({ sst = 1, sd = 0xffffff }) });
@include "neighbour-config.conf"
nr_cellid = 12345678L;
......
Active_gNBs = ( "cu-cp-0");
# Asn1_verbosity, choice in: none, info, annoying
Asn1_verbosity = "none";
gNBs =
(
{
////////// Identification parameters:
gNB_ID = 0xe00;
# cell_type = "CELL_MACRO_GNB";
gNB_name = "cu-cp-0";
// Tracking area code, 0x0000 and 0xfffe are reserved values
tracking_area_code = 1;
plmn_list = ({ mcc = 208; mnc = 99; mnc_length = 2; snssaiList = ({ sst = 1, sd = 0xffffff }) });
@include "neighbour-config.conf"
nr_cellid = 12345678L;
tr_s_preference = "f1";
local_s_address = "192.168.71.150";
remote_s_address = "192.168.71.171";
local_s_portd = 2153;
remote_s_portd = 2153;
# ------- SCTP definitions
SCTP :
{
# Number of streams to use in input/output
SCTP_INSTREAMS = 2;
SCTP_OUTSTREAMS = 2;
};
////////// AMF parameters:
amf_ip_address = ({ ipv4 = "192.168.71.132"; });
E1_INTERFACE =
(
{
type = "cp";
ipv4_cucp = "192.168.71.150";
port_cucp = 38462;
ipv4_cuup = "0.0.0.0"; # multiple CU-UPs
port_cuup = 38462;
}
)
NETWORK_INTERFACES :
{
GNB_IPV4_ADDRESS_FOR_NG_AMF = "192.168.71.150";
};
}
);
security = {
# preferred ciphering algorithms
# the first one of the list that an UE supports in chosen
# valid values: nea0, nea1, nea2, nea3
ciphering_algorithms = ( "nea0" );
# preferred integrity algorithms
# the first one of the list that an UE supports in chosen
# valid values: nia0, nia1, nia2, nia3
integrity_algorithms = ( "nia2", "nia0" );
# setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter
# what 'ciphering_algorithms' configures; same thing for 'drb_integrity'
drb_ciphering = "yes";
drb_integrity = "no";
};
log_config : {
global_log_level = "info";
pdcp_log_level = "info";
rrc_log_level = "info";
f1ap_log_level = "info";
ngap_log_level = "info";
};
############################################################
# gNB-to-gNB neighbour list + measurement configuration #
# for the 2-cell rfsim setup (gNB_ID 0xe00 & 0xb00) #
############################################################
neighbour_list = (
##########################################################
# Entry USED BY gNB_ID = 0xe00 (nr_cellid = 1) #
##########################################################
{
nr_cellid = 1;
nr_cellid = 0; # Serving cell of gNB 0xe00
neighbour_cell_configuration = (
{
gNB_ID = 0xb00;
nr_cellid = 2;
physical_cellId = 0x002;
absoluteFrequencySSB = 641280 ;
subcarrierSpacing = 1; #30 KHz
plmn = { mcc = 216; mnc = 03; mnc_length = 2};
tracking_area_code = 2;
},
{
gNB_ID = 0xa00;
nr_cellid = 3;
physical_cellId = 0x003;
absoluteFrequencySSB = 641280 ;
subcarrierSpacing = 1; #30 KHz
plmn = { mcc = 999; mnc = 99; mnc_length = 2};
tracking_area_code = 3;
},
{
gNB_ID = 0xc00;
nr_cellid = 4;
physical_cellId = 0x004;
absoluteFrequencySSB = 641280 ;
subcarrierSpacing = 1; #30 KHz
plmn = { mcc = 999; mnc = 99; mnc_length = 2};
tracking_area_code = 4;
gNB_ID = 0xb00;
nr_cellid = 1; # Cell served by gNB 0xb00
physical_cellId = 1;
absoluteFrequencySSB= 621312;
subcarrierSpacing = 1; # 30 kHz
band = 78;
plmn = { mcc = 208; mnc = 99; mnc_length = 2 };
tracking_area_code = 1;
}
)
);
},
##########################################################
# Entry USED BY gNB_ID = 0xb00 (nr_cellid = 2) #
##########################################################
{
nr_cellid = 2;
nr_cellid = 1; # Serving cell of gNB 0xb00
neighbour_cell_configuration = (
{
gNB_ID = 0xe00;
nr_cellid = 1;
physical_cellId = 0x000;
absoluteFrequencySSB = 641280 ;
subcarrierSpacing = 1; #30 KHz
plmn = { mcc = 001; mnc = 01; mnc_length = 2};
tracking_area_code = 1;
gNB_ID = 0xe00;
nr_cellid = 0; # Cell served by gNB 0xe00
physical_cellId = 0;
absoluteFrequencySSB= 641280;
subcarrierSpacing = 1; # 30 kHz
band = 78;
plmn = { mcc = 208; mnc = 99; mnc_length = 2 };
tracking_area_code = 1;
}
)
);
}
);
);
############################################################
# Common NR measurement-event configuration #
############################################################
nr_measurement_configuration = {
Periodical = {
......
......@@ -15,16 +15,18 @@ fi
# The script assumes you've build the following images:
#
# docker build . -f docker/Dockerfile.gNB.ubuntu22 -t oai-gnb
# docker build . -f docker/Dockerfile.nrUE.ubuntu22 -t oai-nr-ue
# docker build . -f docker/Dockerfile.gNB.ubuntu -t oai-gnb
# docker build . -f docker/Dockerfile.nr-cuup.ubuntu -t oai-nr-cuup
# docker build . -f docker/Dockerfile.nrUE.ubuntu -t oai-nr-ue
#
# The images above depend on the following images:
#
# docker build . -f docker/Dockerfile.build.ubuntu22 -t ran-build
# dokcer build . -f docker/Dockerfile.base.ubuntu22 -t ran-base
# docker build . -f docker/Dockerfile.build.ubuntu -t ran-build
# docker build . -f docker/Dockerfile.base.ubuntu -t ran-base
docker tag oai-nr-ue oai-ci/oai-nr-ue:develop-${SHORT_COMMIT_SHA}
docker tag oai-gnb oai-ci/oai-gnb:develop-${SHORT_COMMIT_SHA}
docker tag oai-nr-cuup oai-ci/oai-nr-cuup:develop-${SHORT_COMMIT_SHA}
python3 main.py --mode=InitiateHtml --ranRepository=NONE --ranBranch=${CURRENT_BRANCH} \
--ranCommitID=${COMMIT_SHA} --ranAllowMerge=false \
......
<!--
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
-->
<testCaseList>
<htmlTabRef>rfsim-5gnr-f1-n2-ho</htmlTabRef>
<htmlTabName>F1 SA TDD N2 Handover</htmlTabName>
<htmlTabIcon>wrench</htmlTabIcon>
<TestCaseRequestedList>
111111
800813
000001
000002
000003
020001
020002
030001
030002
000004
040001
050001
020001
020002
050002
030001
030002
050003
020001
020002
050004
050001
020001
020002
050002
100001
222222
</TestCaseRequestedList>
<TestCaseExclusionList></TestCaseExclusionList>
<testCase id="111111">
<class>Pull_Local_Registry</class>
<desc>Pull Images from Local Registry</desc>
<svr_id>0</svr_id>
<images>oai-gnb-asan oai-nr-cuup-asan oai-nr-ue-asan</images>
</testCase>
<testCase id="800813">
<class>Create_Workspace</class>
<desc>Create new Workspace</desc>
<eNB_instance>0</eNB_instance>
<eNB_serverId>0</eNB_serverId>
</testCase>
<testCase id="000001">
<class>Deploy_Object</class>
<desc>Deploy OAI 5G CoreNetwork</desc>
<yaml_path>ci-scripts/yaml_files/5g_rfsimulator_n2_ho</yaml_path>
<services>mysql oai-amf oai-smf oai-upf oai-ext-dn</services>
<eNB_instance>0</eNB_instance>
<eNB_serverId>0</eNB_serverId>
</testCase>
<testCase id="000002">
<class>Deploy_Object</class>
<desc>Deploy OAI 5G CU-CP/CU-UP/DU 0 + UE RFsim SA</desc>
<yaml_path>ci-scripts/yaml_files/5g_rfsimulator_n2_ho</yaml_path>
<services>oai-cucp-0 oai-cuup-0 oai-du-0 oai-nr-ue</services>
<eNB_instance>0</eNB_instance>
<eNB_serverId>0</eNB_serverId>
</testCase>
<testCase id="000003">
<class>Attach_UE</class>
<desc>Attach OAI UE (Wait for IP)</desc>
<id>rfsim5g_ue</id>
<nodes>acamas</nodes>
</testCase>
<testCase id="000004">
<class>Deploy_Object</class>
<desc>Deploy OAI 5G CU-CP/CU-UP/DU 1 RFsim SA</desc>
<yaml_path>ci-scripts/yaml_files/5g_rfsimulator_n2_ho</yaml_path>
<services>oai-cucp-1 oai-cuup-1 oai-du-1</services>
<eNB_instance>0</eNB_instance>
<eNB_serverId>0</eNB_serverId>
</testCase>
<testCase id="020001">
<class>Ping</class>
<desc>Ping NR-UE from ext-dn</desc>
<id>rfsim5g_ext_dn</id>
<nodes>acamas</nodes>
<svr_id>rfsim5g_ue</svr_id>
<svr_node>acamas</svr_node>
<ping_args>-c 100 -i 0.25</ping_args>
<ping_packetloss_threshold>5</ping_packetloss_threshold>
</testCase>
<testCase id="020002">
<class>Ping</class>
<desc>Ping ext-dn from NR-UE</desc>
<id>rfsim5g_ue</id>
<nodes>acamas</nodes>
<svr_id>rfsim5g_ext_dn</svr_id>
<svr_node>acamas</svr_node>
<ping_args>-c 100 -i 0.25</ping_args>
<ping_packetloss_threshold>10</ping_packetloss_threshold>
</testCase>
<testCase id="030001">
<class>Iperf</class>
<desc>Iperf (DL/10Mbps/UDP)(30 sec)</desc>
<iperf_args>-u -b 3M -t 20 -R</iperf_args>
<id>rfsim5g_ue</id>
<nodes>acamas</nodes>
<svr_id>rfsim5g_ext_dn</svr_id>
<svr_node>acamas</svr_node>
<iperf_packetloss_threshold>5</iperf_packetloss_threshold>
<iperf_bitrate_threshold>90</iperf_bitrate_threshold>
</testCase>
<testCase id="030002">
<class>Iperf</class>
<desc>Iperf (UL/4Mbps/UDP)(30 sec)</desc>
<iperf_args>-u -b 1M -t 20</iperf_args>
<id>rfsim5g_ue</id>
<nodes>acamas</nodes>
<svr_id>rfsim5g_ext_dn</svr_id>
<svr_node>acamas</svr_node>
<iperf_packetloss_threshold>5</iperf_packetloss_threshold>
<iperf_bitrate_threshold>90</iperf_bitrate_threshold>
</testCase>
<testCase id="040001">
<class>IdleSleep</class>
<desc>Sleep</desc>
<idle_sleep_time_in_sec>5</idle_sleep_time_in_sec>
</testCase>
<testCase id="050001">
<class>Custom_Command</class>
<desc>Trigger N2 Handover</desc>
<node>acamas</node>
<command>echo ci trigger_n2_ho 1,1 | ncat 192.168.71.150 9090</command>
<command_fail>yes</command_fail>
</testCase>
<testCase id="050002">
<class>Custom_Command</class>
<desc>UE (1) connected to DU-PCI 1?</desc>
<node>acamas</node>
<command>echo ci fetch_du_by_ue_id 1 | ncat 192.168.71.180 9090 | grep "1234"</command>
</testCase>
<testCase id="050003">
<class>Custom_Command</class>
<desc>Trigger N2 Handover</desc>
<node>acamas</node>
<command>echo ci trigger_n2_ho 0,1 | ncat 192.168.71.180 9090</command>
<command_fail>yes</command_fail>
</testCase>
<testCase id="050004">
<class>Custom_Command</class>
<desc>UE (1) connected to DU-PCI 0?</desc>
<node>acamas</node>
<command>echo ci fetch_du_by_ue_id 1 | ncat 192.168.71.150 9090 | grep "3584"</command>
</testCase>
<testCase id="100001">
<class>Undeploy_Object</class>
<always_exec>true</always_exec>
<desc>Undeploy all OAI 5G stack</desc>
<yaml_path>ci-scripts/yaml_files/5g_rfsimulator_n2_ho</yaml_path>
<eNB_instance>0</eNB_instance>
<eNB_serverId>0</eNB_serverId>
<d_retx_th>10,100,100,100</d_retx_th>
<u_retx_th>10,100,100,100</u_retx_th>
</testCase>
<testCase id="222222">
<class>Clean_Test_Server_Images</class>
<always_exec>true</always_exec>
<desc>Clean Test Images on Test Server</desc>
<svr_id>0</svr_id>
<images>oai-gnb-asan oai-nr-cuup-asan oai-nr-ue-asan</images>
</testCase>
</testCaseList>
......@@ -40,7 +40,7 @@
<class>Build_Image</class>
<desc>Build all Images</desc>
<node>gracehopper3-oai</node>
<kind>native_arm</kind>
<kind>native_armv9</kind>
</testCase>
<testCase id="000010">
......
<!--
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
-->
<testCaseList>
<htmlTabRef>build-tab</htmlTabRef>
<htmlTabName>Build Container Images for ARM</htmlTabName>
<htmlTabIcon>wrench</htmlTabIcon>
<TestCaseRequestedList>
800813
000001
000010
</TestCaseRequestedList>
<TestCaseExclusionList></TestCaseExclusionList>
<testCase id="800813">
<class>Create_Workspace</class>
<desc>Create new Workspace for server 0</desc>
<node>jetson3-oai</node>
</testCase>
<testCase id="000001">
<class>Build_Image</class>
<desc>Build all Images</desc>
<node>jetson3-oai</node>
<kind>native_armv8</kind>
</testCase>
<testCase id="000010">
<class>Push_Local_Registry</class>
<desc>Push Images to Local Registry</desc>
<node>jetson3-oai</node>
<tag_prefix>armv8_</tag_prefix>
</testCase>
</testCaseList>
......@@ -100,7 +100,6 @@ services:
- SYS_NICE
environment:
USE_ADDITIONAL_OPTIONS: --log_config.global_log_options level,nocolor,time
--rfsimulator.options chanmod
--gNBs.[0].remote_s_address 0.0.0.0
--telnetsrv --telnetsrv.listenaddr 192.168.71.150
--telnetsrv.shrmod ci
......@@ -111,6 +110,7 @@ services:
public_net:
ipv4_address: 192.168.71.150
volumes:
- ../../conf_files/neighbour-config.conf:/opt/oai-gnb/etc/neighbour-config.conf
- ../../conf_files/gnb-cu.sa.band78.106prb.conf:/opt/oai-gnb/etc/gnb.conf
healthcheck:
test: /bin/bash -c "pgrep nr-softmodem"
......
This diff is collapsed.
......@@ -7,7 +7,7 @@ services:
ulimits:
core: -1 # for core dumps
environment:
USE_ADDITIONAL_OPTIONS: --telnetsrv --telnetsrv.listenport 9090 --telnetsrv.shrmod ci --sa
USE_ADDITIONAL_OPTIONS: --telnetsrv --telnetsrv.listenport 9090 --telnetsrv.shrmod ci
--log_config.global_log_options level,nocolor,utc_time,line_num,function
volumes:
- ../../conf_files/gnb-cu.sa.f1.ho.conf:/opt/oai-gnb/etc/gnb.conf
......@@ -37,7 +37,7 @@ services:
core: -1 # for core dumps
environment:
USE_B2XX: 'yes'
USE_ADDITIONAL_OPTIONS: --RUs.[0].sdr_addrs serial=30AD30F --sa
USE_ADDITIONAL_OPTIONS: --RUs.[0].sdr_addrs serial=30AD30F
--telnetsrv --telnetsrv.listenport 9091 --telnetsrv.shrmod ci
--log_config.global_log_options level,nocolor,utc_time,line_num,function
devices:
......@@ -69,7 +69,7 @@ services:
core: -1 # for core dumps
environment:
USE_B2XX: 'yes'
USE_ADDITIONAL_OPTIONS: --RUs.[0].sdr_addrs serial=31F8010 --sa
USE_ADDITIONAL_OPTIONS: --RUs.[0].sdr_addrs serial=31F8010
--telnetsrv --telnetsrv.listenport 9091 --telnetsrv.shrmod ci
--log_config.global_log_options level,nocolor,utc_time,line_num,function
devices:
......
......@@ -9,7 +9,7 @@ services:
container_name: oai-gnb
environment:
TZ: Europe/Paris
USE_ADDITIONAL_OPTIONS: --sa --thread-pool 7,8,9,10,11,12
USE_ADDITIONAL_OPTIONS: --thread-pool 7,8,9,10,11,12
devices:
- /dev/vfio:/dev/vfio/
volumes:
......
......@@ -88,6 +88,8 @@ static inline const char *rnti_types(nr_rnti_type_t rr)
#define NR_NUMBER_OF_SYMBOLS_PER_SLOT_EXTENDED_CP 12
#define NR_MAX_NB_LAYERS 4 // 8
#define BOUNDED_EVAL(a, b, c) (min(c, max(a, b)))
// Since the IQ samples are represented by SQ15 R+I (see https://en.wikipedia.org/wiki/Q_(number_format)) we need to compensate when
// calcualting signal energy. Instead of shifting each sample right by 15, we can normalize the result in dB scale once its
// calcualted. Signal energy is calculated using RMS^2, where each sample is squared before taking the average of the sum, therefore
......@@ -175,6 +177,17 @@ typedef struct {
uint32_t step;
} NR_timer_t;
typedef struct val_init {
int val;
bool init;
} val_init_t;
typedef struct meas_s {
uint16_t Nid_cell;
val_init_t ss_rsrp_dBm;
val_init_t csi_rsrp_dBm;
} meas_t;
/**
* @brief To start a timer
* @param timer Timer to be started
......
......@@ -38,6 +38,7 @@
#include "openair2/LAYER2/nr_rlc/nr_rlc_ue_manager.h"
#include "openair2/LAYER2/nr_rlc/nr_rlc_entity_am.h"
#include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h"
#include "openair2/RRC/NR/rrc_gNB_mobility.h"
#define TELNETSERVERCODE
#include "telnetsrv.h"
......@@ -196,6 +197,53 @@ int rrc_gNB_trigger_f1_ho(char *buf, int debug, telnet_printfunc_t prnt)
return 0;
}
extern void nr_HO_N2_trigger_telnet(gNB_RRC_INST *rrc, uint32_t neighbour_pci, uint32_t rrc_ue_id);
/** @brief Trigger N2 handover for UE
* @param buf: Neighbour PCI, SCell PCI, RRC UE ID
* @param debug: Debug flag
* @param prnt: Print function
* @return 0 on success, -1 on failure */
int rrc_gNB_trigger_n2_ho(char *buf, int debug, telnet_printfunc_t prnt)
{
if (!RC.nrrrc)
ERROR_MSG_RET("no RRC present, cannot list counts\n");
if (!buf) {
ERROR_MSG_RET("Please provide neighbour cell id and ue id\n");
} else {
// Parse neighbour cell PCI
char *token = strtok(buf, ",");
if (!token) {
ERROR_MSG_RET("Invalid input. Expected format: Neighbour PCI, ueId\n");
}
uint32_t neighbour_pci = strtol(token, NULL, 10);
// Parse ueId
token = strtok(NULL, ",");
if (!token) {
ERROR_MSG_RET("Missing UE ID\n");
}
uint32_t ueId = strtol(token, NULL, 10);
// Retrieve UE context
rrc_gNB_ue_context_t *ue_p = rrc_gNB_get_ue_context(RC.nrrrc[0], ueId);
if (!ue_p) {
ERROR_MSG_RET("UE with id %u not found\n", ueId);
}
gNB_RRC_UE_t *UE = &ue_p->ue_context;
// Trigger N2 handover
nr_HO_N2_trigger_telnet(RC.nrrrc[0], neighbour_pci, UE->rrc_ue_id);
// Print success message
prnt("RRC N2 handover triggered for UE %u with neighbour cell id %u\n",
ueId,
neighbour_pci);
}
return 0;
}
int force_ul_failure(char *buf, int debug, telnet_printfunc_t prnt)
{
if (!RC.nrmac)
......@@ -245,6 +293,7 @@ static telnetshell_cmddef_t cicmds[] = {
{"trigger_f1_ho", "[rrc_ue_id(int,opt)]", rrc_gNB_trigger_f1_ho},
{"fetch_du_by_ue_id", "[rrc_ue_id(int,opt)]", fetch_du_by_ue_id},
{"get_current_bwp", "[rnti(hex,opt)]", get_current_bwp},
{"trigger_n2_ho", "[neighbour_pci(uint32_t),ueId(uint32_t)]", rrc_gNB_trigger_n2_ho},
{"", "", NULL},
};
......
......@@ -210,7 +210,7 @@ sequenceDiagram
end
```
## Handover
## Inter-DU Handover (F1)
The basic handover (HO) structure is as follows. In order to support various
handover "message passing implementation" (F1AP, NGAP, XnAP), RRC employs
......@@ -264,6 +264,94 @@ sequenceDiagram
sdu->>cucp: F1AP UE Context Release Complete
Note over ue,tdu: UE active on target DU
```
## Inter-gNB Handover (N2)
This is an inter-NG-RAN procedure. The N2 handover specification is defined in the following documents:
* 3GPP TS 23.502, 4.9.1.3 Inter NG-RAN node N2 based handover:
- Outlines detailed handover signaling flows for N2-based handovers.
- Covers both intra-system (between 5G gNBs) and inter-system (between 5G and LTE eNBs) handovers.
* 3GPP TS 38.300, section 9 Mobility and State Transitions:
- describes mobility procedures at the NG-RAN level, depending on the RRC state.
* 3GPP TS 38.413 (NGAP), section 8.4 UE Mobility Management Procedures:
- Specifies the signaling procedures over the N2 interface.
- Includes messages like Handover Request, Handover Command, and Handover Preparation.
* 3GPP TS 38.331 (RRC): details the UE-level RRC procedures involved during handovers
### End-to-end flow
```mermaid
sequenceDiagram
participant ue as UE
participant sdu as source DU
participant scucp as source CU-CP
participant scuup as source CU-UP
participant tdu as target DU
participant tcucp as target CU-CP
participant tcuup as target CU-UP
participant amf as AMF
Note over ue,sdu: UE active on source DU
alt HO triggered through A3 event
ue->>sdu: RRC Measurement Report
sdu->>scucp: F1AP UL RRC Msg Transfer (RRC Measurement Report)
Note over scucp: Handover decision (A3 event trigger)
else Manual Trigger
Note over scucp: Handover decision (e.g., telnet)
end
Note over scucp: nr_rrc_trigger_n2_ho() ("on source CU")
scucp->>amf: HANDOVER REQUIRED
amf->>tcucp: HANDOVER REQUEST
Note over tcucp: rrc_gNB_process_Handover_Request
Note over tcucp: trigger_bearer_setup
tcucp->>tcuup: Bearer Context Setup Request
tcuup->>tcucp: Bearer Context Setup Response
Note over tcucp: rrc_gNB_process_e1_bearer_context_setup_resp
Note over tcucp: nr_rrc_trigger_n2_ho_target() ("on target CU")
Note over tcucp: nr_initiate_handover()
tcucp->>tdu: F1AP UE Context Setup Req
Note over tdu: Create UE context
tdu->>tcucp: F1AP UE Context Setup Resp (incl. CellGroupConfig)
Note over tcucp: rrc_CU_process_ue_context_setup_response() ("on target CU")
Note over tcucp: e1_send_bearer_updates()
tcucp->>tcuup: E1AP Bearer Context Modification Req
tcuup->>tcucp: E1AP Bearer Context Modification Resp
tcucp-->>tcucp: callback: ho_req_ack()
Note over tcucp: nr_rrc_n2_ho_acknowledge() ("on target CU")
tcucp->>amf: HANDOVER REQUEST ACKNOWLEDGE (data forwarding info)
amf->>scucp: HANDOVER COMMAND
scucp->>sdu: F1AP UE Context Modification Req (RRC Reconfiguration)
sdu->>ue: RRC Reconfiguration
sdu->>scucp: F1AP UE Context Modification Resp
Note over sdu: Stop scheduling UE
Note over scucp: rrc_CU_process_ue_context_modification_response()
Note over scucp: e1_send_bearer_updates()
scucp->>scuup: E1 Bearer Context Modification Req (PDCP Status Request)
scuup->>scucp: E1 Bearer Context Modification Resp (PDCP Status Info)
scucp->>amf: NG Uplink RAN Status Transfer
amf->>tcucp: NG Downlink RAN Status Transfer
tcucp->>tcuup: E1 Bearer Context Modification Req (PDCP Status Info)
tcuup->>tcucp: E1 Bearer Context Modification Resp
Note over ue: UE attachment to target DU
Note over ue,tdu: RA (Msg1 + Msg2)
ue->>tdu: RRC Reconfiguration Complete
tdu->>tcucp: F1AP UL RRC Msg Transfer (RRC Reconfiguration Complete)
tcucp-->>tcucp: callback: ho_success()
Note over tcucp: nr_rrc_n2_ho_complete() ("on target CU")
Note over tcucp: handle_rrcReconfigurationComplete() ("on target CU")
tcucp->>amf: HANDOVER NOTIFY
amf->>scucp: UE Context Release Command
note over scucp: ngap_gNB_handle_ue_context_release_command
note over scucp: rrc_gNB_process_NGAP_UE_CONTEXT_RELEASE_COMMAND
scucp->>scuup: E1 Bearer Context Release Command
scuup->>scucp: E1 Bearer Context Release Complete
Note over scucp: rrc_gNB_generate_RRCRelease
scucp->>sdu: F1 UE Context Release Command
sdu->>scucp: F1 UE Context Release Complete
note over scucp: rrc_CU_process_ue_context_release_complete
note over scucp: rrc_remove_ue
Note over ue,tdu: UE active on target DU
```
# Structures
......@@ -308,7 +396,8 @@ corresponding CU.
`nr_ho_source_cu_t` contains notably a function pointer `ho_cancel` for
handover cancel. `nr_ho_target_cu_t` contains function pointers `ho_req_ack`
for handover request acknowledge and `ho_success` for handover success. As can
for handover request acknowledge, `ho_success` for handover success,
`ho_failure` for handover failure (N2 only).
be seen in the sequence diagram above, either the "target CU" or "source CU"
needs to do an operation, and a "switch" from target to source CU is done using
these function pointers. For instance, in F1, the handover request acknowledge
......
......@@ -99,6 +99,26 @@ the [MAC configuration](../MAC/mac-usage.md) as well for SIB configuration.
### Neighbor-gNB configuration
TBD
#### What is a gNB neighbor?
Network continuity is a key aspect of 5G. In the 5G architecture, gNB neighbors play a central role in maintaining service continuity through mechanisms such as handover and load balancing. By definition, a gNB neighbor is another gNB that can be measured and linked by the UE. If the current serving gNB is no longer optimal, the UE may connect to a neighbor gNB.
To support this behavior, the network configuration specifies additional frequencies and cells that the UE should measure. The UE reports these measurements to the network, which then decides whether or not to initiate a handover.
Neighbor types include:
- **Intra-gNB neighbors** - cells belonging to the same gNB
- **Inter-gNB neighbors** - cells belonging to different gNBs
- **Inter-RAT neighbors** - cells belonging to another RAT (e.g., LTE)
#### Required configuration parameters
To define a neighbor cell in the configuration file, the following parameters are typically needed:
- **gNB ID** - unique identifier of the gNB
- **Cell ID** - identifier of the cell within the gNB
- **Physical Cell ID** - identifier of the cell’s synchronization signal (PCI)
- **Absolute Frequency** - frequency used by the SSB (absoluteFrequencySSB)
- **Subcarrier Spacing** - numerology (e.g., 15 kHz, 30 kHz)
- **PLMN configuration** - MCC, MNC, and MNC length
- **Tracking Area Code (TAC)** - identifier of the tracking area
Refer to the [handover tutorial](../handover-tutorial.md) for more information.
......@@ -85,10 +85,8 @@ The standalone mode is the default mode.
Before tag `2024.w45`, the default mode was NSA. Thus, in the past, to run
either the gNB or the UE in standalone mode, it was necessary to provide the
`--sa` flag in the command line. This is not necessary anymore; if in doubt,
you can provide `--sa` on the command line. The gNB will ignore this option if
not relevant; the UE might complain that it does not know this option, which
means that standalone is already active.
`--sa` flag in the command line. This is not the case anymore. If provided
the softmodem exits reporting that it does not know this option.
The default (SA) mode does the following:
- At the gNB:
......
......@@ -113,7 +113,7 @@ information on how the images are built.
- [RAN-Ubuntu18-Image-Builder](https://jenkins-oai.eurecom.fr/job/RAN-Ubuntu18-Image-Builder/)
~BUILD-ONLY ~4G-LTE ~5G-NR ~nrUE
- run formatting check from `ci-scripts/docker/Dockerfile.formatting.ubuntu`
- obelix: Ubuntu 22 image build using docker (Note: builds U22 images while pipeline is named U18!)
- obelix: Ubuntu image build using docker (Note: builds Ubuntu images of newer version while pipeline is named U18!)
- base image from `Dockerfile.base.ubuntu`
- build image from `Dockerfile.build.ubuntu`, followed by
- target image from `Dockerfile.eNB.ubuntu`
......@@ -128,13 +128,21 @@ information on how the images are built.
- build unit tests from `ci-scripts/docker/Dockerfile.unittest.ubuntu`, and run them
- [RAN-Ubuntu-ARM-Image-Builder](https://jenkins-oai.eurecom.fr/job/RAN-Ubuntu-ARM-Image-Builder/)
~BUILD-ONLY ~4G-LTE ~5G-NR
- gracehopper3-oai: ARM Ubuntu 22 image build using docker
- gracehopper3-oai: ARM Ubuntu image build using docker
- base image from `Dockerfile.base.ubuntu`
- build image from `Dockerfile.build.ubuntu`, followed by
- target image from `Dockerfile.gNB.ubuntu`
- target image from `Dockerfile.nr-cuup.ubuntu`
- target image from `Dockerfile.nrUE.ubuntu`
- target image from `Dockerfile.gNB.aerial.ubuntu`
- [RAN-Ubuntu-Jetson-Image-Builder](https://jenkins-oai.eurecom.fr/job/RAN-Ubuntu-Jetson-Image-Builder/)
~BUILD-ONLY ~4G-LTE ~5G-NR
- jetson3-oai: ARMv8 Ubuntu image build using docker
- base image from `Dockerfile.base.ubuntu`
- build image from `Dockerfile.build.ubuntu`, followed by
- target image from `Dockerfile.gNB.ubuntu`
- target image from `Dockerfile.nr-cuup.ubuntu`
- target image from `Dockerfile.nrUE.ubuntu`
#### Image Test pipelines
......
......@@ -207,6 +207,7 @@ neighbour_list = (
physical_cellId = 1;
absoluteFrequencySSB = 643296;
subcarrierSpacing = 1; #30 KHz
band = 78;
plmn = { mcc = 001; mnc = 01; mnc_length = 2};
tracking_area_code = 1;
}
......@@ -221,6 +222,7 @@ neighbour_list = (
physical_cellId = 0;
absoluteFrequencySSB = 643296;
subcarrierSpacing = 1; #30 KHz
band = 78;
plmn = { mcc = 001; mnc = 01; mnc_length = 2};
tracking_area_code = 1;
}
......@@ -340,3 +342,147 @@ while true; do
sleep 15
done
```
# N2 Handover
## Run the setup
An N2 handover involves the transfer of a UE from one gNB to another via the 5G core network. Unlike F1 handover, where the CU handles the process internally between its DUs, N2 handover requires signaling through the AMF, making it a core-network-based handover.
We assume:
* Two independent gNBs connected to the same 5GC via N2 interface.
* A UE initially connected to gNB-PCI0, which will be handed over to gNB-PCI1.
* Handover is triggered by either by decision based measurement event (e.g. A3) or telnet command.
## Steps to run N2 handover with OAI UE
1. Similarly to F1 handover, UE does not support any measurement reporting and handover is triggered by
telnet command. Therefore, ensure that both gNBs and UE are built with telnet support:
```sh
./build_oai --ninja --nrUE --gNB --build-lib telnetsrv
```
Run the 5G Core Network if not already running. See [OAI CN5G tutorial](./NR_SA_Tutorial_OAI_CN5G.md).
2. Start the source gNB (gNB-PCI0) e.g.
```sh
sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.pci0.rfsim.conf --telnetsrv --telnetsrv.shrmod ci --gNBs.[0].min_rxtxtime 6 --rfsim --rfsimulator.serveraddr 127.0.0.1
```
3. Start the UE e.g.
```sh
sudo ./nr-uesoftmodem -r 106 --numerology 1 --band 78 -C 3619200000 --rfsim --uicc0.imsi 001010000000001 -O ../../../ci-scripts/conf_files/nrue.uicc.conf --rfsimulator.serveraddr server
```
Ensure the UE successfully registers with the network.
4. Start the target gNB (gNB PCI1) e.g.
```sh
sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.pci1.rfsim.conf --sa --rfsim --telnetsrv --telnetsrv.shrmod ci --gNBs.[0].min_rxtxtime 6 --rfsimulator.serveraddr 127.0.0.1
```
5. Trigger the N2 handover, e.g.
From gNB-PCI0, trigger handover on target gNB with PCI 1 for UE ID 1:
```sh
echo ci trigger_n2_ho 1,1 | nc 127.0.0.1 9090 && echo
```
where the input parameters correspond to the PCI of the neighbor call and the RRC ID of the UE.
This will initiate the N2 handover on the source gNB.
## Neighbour list and measurement configuration
Make sure the configuration file contains a neighbour list and measurement configuration, e.g. [neighbour-config-rfsim.conf](../../ci-scripts/conf_files/neighbour-config.conf). This configuration can also be present in a different file and included in the gNB configuration file with `@include "neighbour-config-rfsim.conf"`.
For each gNB there is a `neighbour_cell_configuration` linked to its serving cell ID.
The measurement configuration is based on A2 and A3 measurement events in 5G NR. These events are used by the UE to report radio conditions to the gNB. The A2 Measurement Event indicates that the serving cell’s signal quality has degraded below a defined threshold and the UE shall initiate measurement of neighboring cells. The A3 Measurement Event indicates that a neighboring cell’s signal quality is better than that of the serving cell by a certain offset and the UE shall trigger handover to a stronger neighboring cell
This is an example with comments on how to use the configuration file:
```
############################################################
# gNB-to-gNB neighbour list + measurement configuration #
# for the 2-cell rfsim setup (gNB_ID 0xe00 & 0xb00) #
############################################################
neighbour_list = (
##########################################################
# Entry USED BY gNB_ID = 0xe00 (nr_cellid = 12345678L) #
##########################################################
{
nr_cellid = 12345678L; # Serving cell of gNB 0xe00
neighbour_cell_configuration = (
{
gNB_ID = 0xb00;
nr_cellid = 720898; # Cell served by gNB 0xb00
physical_cellId = 1;
absoluteFrequencySSB= 621312;
subcarrierSpacing = 1; # 30 kHz
band = 78;
plmn = { mcc = 208; mnc = 99; mnc_length = 2 };
tracking_area_code = 1;
}
);
},
##########################################################
# Entry USED BY gNB_ID = 0xb00 (nr_cellid = 720898) #
##########################################################
{
nr_cellid = 720898; # Serving cell of gNB 0xb00
neighbour_cell_configuration = (
{
gNB_ID = 0xe00;
nr_cellid = 12345678L; # Cell served by gNB 0xe00
physical_cellId = 0;
absoluteFrequencySSB= 641280;
subcarrierSpacing = 1; # 30 kHz
band = 78;
plmn = { mcc = 208; mnc = 99; mnc_length = 2 };
tracking_area_code = 1;
}
);
}
);
############################################################
# Common NR measurement-event configuration #
############################################################
nr_measurement_configuration = {
Periodical = {
enable = 1;
includeBeamMeasurements = 1;
maxNrofRS_IndexesToReport = 4;
};
A2 = {
enable = 1;
threshold = 60;
timeToTrigger = 1;
};
A3 = (
{
cell_id = 720898; # neighbour of gNB 0xe00
offset = 10;
hysteresis = 0;
timeToTrigger = 1;
},
{
cell_id = 12345678; # neighbour of gNB 0xb00
offset = 5;
hysteresis = 1;
timeToTrigger = 2;
}
);
};
```
......@@ -713,6 +713,11 @@ int main( int argc, char **argv ) {
// wait for end of program
printf("TYPE <CTRL-C> TO TERMINATE\n");
// Sleep a while before checking all parameters have been used
// Some are used directly in external threads, asynchronously
sleep(2);
config_check_unknown_cmdlineopt(uniqCfg, CONFIG_CHECKALLSECTIONS);
itti_wait_tasks_end(NULL);
printf("Returned from ITTI signal handler\n");
......
......@@ -1866,22 +1866,23 @@ uint8_t unpack_nr_stop_indication(uint8_t **ppReadPackedMsg, uint8_t *end, void
uint8_t pack_nr_error_indication(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t *config)
{
nfapi_nr_error_indication_scf_t *pNfapiMsg = (nfapi_nr_error_indication_scf_t *)msg;
uint8_t retval = push16(pNfapiMsg->sfn, ppWritePackedMsg, end) != 0;
retval &= push16(pNfapiMsg->slot, ppWritePackedMsg, end) != 0;
retval &= push8(pNfapiMsg->message_id, ppWritePackedMsg, end);
retval &= push8(pNfapiMsg->error_code, ppWritePackedMsg, end);
retval &= pack_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config);
return retval;
if (push16(pNfapiMsg->sfn, ppWritePackedMsg, end) && push16(pNfapiMsg->slot, ppWritePackedMsg, end)
&& push8(pNfapiMsg->message_id, ppWritePackedMsg, end) && push8(pNfapiMsg->error_code, ppWritePackedMsg, end)
&& pack_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)) {
return 1;
} else {
return 0;
}
}
uint8_t unpack_nr_error_indication(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t *config)
{
nfapi_nr_error_indication_scf_t *pNfapiMsg = (nfapi_nr_error_indication_scf_t *)msg;
uint8_t retval = pull16(ppReadPackedMsg, &pNfapiMsg->sfn, end);
retval &= pull16(ppReadPackedMsg, &pNfapiMsg->slot, end);
retval &= pull8(ppReadPackedMsg, &pNfapiMsg->message_id, end);
retval &= pull8(ppReadPackedMsg, &pNfapiMsg->error_code, end);
retval &= unpack_nr_tlv_list(NULL, 0, ppReadPackedMsg, end, config, &(pNfapiMsg->vendor_extension));
return retval;
if (pull16(ppReadPackedMsg, &pNfapiMsg->sfn, end) && pull16(ppReadPackedMsg, &pNfapiMsg->slot, end)
&& pull8(ppReadPackedMsg, &pNfapiMsg->message_id, end) && pull8(ppReadPackedMsg, &pNfapiMsg->error_code, end)
&& unpack_nr_tlv_list(NULL, 0, ppReadPackedMsg, end, config, &(pNfapiMsg->vendor_extension))) {
return 1;
} else {
return 0;
}
}
......@@ -20,7 +20,7 @@
#define FAPI_NR_RX_PDU_TYPE_DLSCH 0x03
#define FAPI_NR_DCI_IND 0x04
#define FAPI_NR_RX_PDU_TYPE_RAR 0x05
#define FAPI_NR_CSIRS_IND 0x06
#define FAPI_NR_MEAS_IND 0x06
#define FAPI_NR_SIBS_MASK_SIB1 0x1
......
......@@ -49,16 +49,23 @@ typedef enum {
NFAPI_NR_FORMAT_0_1_AND_1_1,
} nfapi_nr_dci_formats_e;
typedef enum {
NFAPI_NR_CSI_MEAS,
NFAPI_NR_SS_MEAS
} nfapi_nr_meas_type_e;
typedef struct {
uint32_t rsrp;
int rsrp_dBm;
uint32_t gNB_index;
uint16_t Nid_cell;
nfapi_nr_meas_type_e meas_type;
bool is_neighboring_cell;
uint8_t rsrp_dBm;
uint8_t rank_indicator;
uint16_t i1;
uint8_t i2;
uint8_t cqi;
rlm_t radiolink_monitoring;
} fapi_nr_csirs_measurements_t;
} fapi_nr_l1_measurements_t;
typedef struct {
/// frequency_domain_resource;
......@@ -145,7 +152,7 @@ typedef struct {
fapi_nr_pdsch_pdu_t pdsch_pdu;
fapi_nr_ssb_pdu_t ssb_pdu;
fapi_nr_sib_pdu_t sib_pdu;
fapi_nr_csirs_measurements_t csirs_measurements;
fapi_nr_l1_measurements_t l1_measurements;
};
} fapi_nr_rx_indication_body_t;
......
......@@ -707,18 +707,41 @@ typedef enum {
NFAPI_NR_STOP_MSG_INVALID_STATE
} nfapi_nr_stop_errors_e;
//3.3.5 PHY Notifications
// 3.3.5 PHY Notifications
#define SCF_ERROR_LIST \
X(NFAPI_NR_PHY_API_MSG_OK, 0x0) \
X(NFAPI_NR_PHY_API_MSG_INVALID_STATE, 0x1) \
X(NFAPI_NR_PHY_API_MSG_INVALID_CONFIG, 0x2) \
X(NFAPI_NR_PHY_API_SFN_OUT_OF_SYNC, 0X3) \
X(NFAPI_NR_PHY_API_MSG_SLOR_ERR, 0X4) \
X(NFAPI_NR_PHY_API_MSG_BCH_MISSING, 0X5) \
X(NFAPI_NR_PHY_API_MSG_INVALID_SFN, 0X6) \
X(NFAPI_NR_PHY_API_MSG_UL_DCI_ERR, 0X7) \
X(NFAPI_NR_PHY_API_MSG_TX_ERR, 0X8)
#ifdef ENABLE_AERIAL
#define AERIAL_ERROR_LIST \
X(AERIAL_ERROR_CODE_FAPI_END, 0x32) \
X(AERIAL_ERROR_CODE_L1_PROC_OBJ_UNAVAILABLE_ERR, 0x33) \
X(AERIAL_ERROR_CODE_MSG_LATE_SLOT_ERR, 0x34) \
X(AERIAL_ERROR_CODE_PARTIAL_SRS_IND_ERR, 0x35) \
X(AERIAL_ERROR_CODE_L1_DL_CPLANE_TX_ERROR, 0x36) \
X(AERIAL_ERROR_CODE_L1_UL_CPLANE_TX_ERROR, 0x37) \
X(AERIAL_ERROR_CODE_L1_DL_GPU_ERROR, 0x38) \
X(AERIAL_ERROR_CODE_L1_DL_CPU_TASK_ERROR, 0x39) \
X(AERIAL_ERROR_CODE_L1_UL_CPU_TASK_ERROR, 0x3A) \
X(AERIAL_ERROR_CODE_L1_P1_EXIT_ERROR, 0x3B) \
X(AERIAL_ERROR_CODE_L1_P2_EXIT_ERROR, 0x3C) \
X(AERIAL_ERROR_CODE_L1_DL_CH_ERROR, 0x3D) \
X(AERIAL_ERROR_CODE_L1_UL_CH_ERROR, 0x3E)
#else
#define AERIAL_ERROR_LIST
#endif
#define NFAPI_PHY_ERROR_LIST \
X(NFAPI_NR_PHY_API_MSG_OK ,0x0)\
X(NFAPI_NR_PHY_API_MSG_INVALID_STATE ,0x1)\
X(NFAPI_NR_PHY_API_MSG_INVALID_CONFIG ,0x2)\
X(NFAPI_NR_PHY_API_SFN_OUT_OF_SYNC ,0X3)\
X(NFAPI_NR_PHY_API_MSG_SLOR_ERR ,0X4)\
X(NFAPI_NR_PHY_API_MSG_BCH_MISSING ,0X5)\
X(NFAPI_NR_PHY_API_MSG_INVALID_SFN ,0X6)\
X(NFAPI_NR_PHY_API_MSG_UL_DCI_ERR ,0X7)\
X(NFAPI_NR_PHY_API_MSG_TX_ERR ,0X8)
SCF_ERROR_LIST \
AERIAL_ERROR_LIST
typedef enum {
#define X(name, value) name = value,
......
......@@ -37,6 +37,7 @@
#include "PHY/phy_extern_nr_ue.h"
#include "common/utils/LOG/log.h"
#include "PHY/sse_intrin.h"
#include "SCHED_NR_UE/defs.h"
#define K1 ((long long int) 512)
#define K2 ((long long int) (1024-K1))
......@@ -254,6 +255,24 @@ void nr_ue_ssb_rsrp_measurements(PHY_VARS_NR_UE *ue,
ue->measurements.ssb_rsrp_dBm[ssb_index],
rsrp_db_per_re,
ue->measurements.ssb_sinr_dB[ssb_index]);
// Send SS measurements to MAC
if (!ue->if_inst || !ue->if_inst->dl_indication)
return;
fapi_nr_l1_measurements_t l1_measurements = {
.gNB_index = proc->gNB_id,
.meas_type = NFAPI_NR_SS_MEAS,
.Nid_cell = ue->frame_parms.Nid_cell,
.is_neighboring_cell = false,
};
int ssb_rsrp_dBm = ue->measurements.ssb_rsrp_dBm[ssb_index];
l1_measurements.rsrp_dBm = BOUNDED_EVAL(16, ssb_rsrp_dBm + 157, 113); // TS 38.133 - Table 10.1.6.1-1
nr_downlink_indication_t dl_indication = {0};
fapi_nr_rx_indication_t rx_ind = {0};
nr_fill_dl_indication(&dl_indication, NULL, &rx_ind, proc, ue, NULL);
nr_fill_rx_indication(&rx_ind, FAPI_NR_MEAS_IND, ue, NULL, NULL, 1, proc, &l1_measurements, NULL);
ue->if_inst->dl_indication(&dl_indication);
}
// This function computes the received noise power
......
......@@ -979,18 +979,24 @@ void nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue,
}
// Send CSI measurements to MAC
fapi_nr_csirs_measurements_t csirs_measurements;
csirs_measurements.rsrp = rsrp;
csirs_measurements.rsrp_dBm = rsrp_dBm;
csirs_measurements.rank_indicator = rank_indicator;
csirs_measurements.i1 = *i1;
csirs_measurements.i2 = *i2;
csirs_measurements.cqi = cqi;
csirs_measurements.radiolink_monitoring = RLM_no_monitoring; // TODO do be activated in case of RLM based on CSI-RS
if (!ue->if_inst || !ue->if_inst->dl_indication)
return;
fapi_nr_l1_measurements_t l1_measurements = {
.gNB_index = proc->gNB_id,
.meas_type = NFAPI_NR_CSI_MEAS,
.Nid_cell = frame_parms->Nid_cell,
.is_neighboring_cell = false,
.rsrp_dBm = BOUNDED_EVAL(16, rsrp_dBm + 157, 113), // TS 38.133 - Table 10.1.6.1-1
.rank_indicator = rank_indicator,
.i1 = *i1,
.i2 = *i2,
.cqi = cqi,
.radiolink_monitoring = RLM_no_monitoring, // TODO do be activated in case of RLM based on CSI-RS
};
nr_downlink_indication_t dl_indication;
fapi_nr_rx_indication_t rx_ind = {0};
nr_fill_dl_indication(&dl_indication, NULL, &rx_ind, proc, ue, NULL);
nr_fill_rx_indication(&rx_ind, FAPI_NR_CSIRS_IND, ue, NULL, NULL, 1, proc, (void *)&csirs_measurements, NULL);
if (ue->if_inst && ue->if_inst->dl_indication)
ue->if_inst->dl_indication(&dl_indication);
nr_fill_rx_indication(&rx_ind, FAPI_NR_MEAS_IND, ue, NULL, NULL, 1, proc, (void *)&l1_measurements, NULL);
ue->if_inst->dl_indication(&dl_indication);
}
......@@ -186,8 +186,8 @@ void nr_fill_rx_indication(fapi_nr_rx_indication_t *rx_ind,
rx->ssb_pdu.decoded_pdu = false;
}
} break;
case FAPI_NR_CSIRS_IND:
memcpy(&rx->csirs_measurements, typeSpecific, sizeof(fapi_nr_csirs_measurements_t));
case FAPI_NR_MEAS_IND:
memcpy(&rx->l1_measurements, typeSpecific, sizeof(fapi_nr_l1_measurements_t));
break;
default:
break;
......
......@@ -178,3 +178,12 @@ void *rrc_nrue(void *notUsed)
{
return NULL;
}
void nr_mac_rrc_meas_ind_ue(module_id_t module_id,
uint32_t gNB_index,
uint16_t Nid_cell,
bool csi_meas,
bool is_neighboring_cell,
uint8_t rsrp_dBm)
{
}
define_property(TEST PROPERTY TEST_DESCRIPTION BRIEF_DOCS "A human-readable description of this test")
define_property(TEST PROPERTY TEST_DESCRIPTION
BRIEF_DOCS "A human-readable description of this test"
FULL_DOCS "A human-readable description of this test")
# Define a macro to add tests for different physical simulators
macro(add_physim_test test_name test_description test_exec)
......@@ -23,7 +25,9 @@ macro(add_physim_test test_name test_description test_exec)
add_dependencies(tests ${test_exec})
endmacro()
define_property(TEST PROPERTY CHECK_COUNT BRIEF_DOCS "helper property to enumerate checks in environment")
define_property(TEST PROPERTY CHECK_COUNT
BRIEF_DOCS "helper property to enumerate checks in environment"
FULL_DOCS "the property counts the number of threshold checks, used to enumerate environment variables given to analyze-timing.sh")
function(add_timed_physim_test test_name test_description test_exec)
# catch all the arguments past the last expected arqument and store them in the options_list
if (NOT TARGET ${test_exec})
......
......@@ -283,6 +283,22 @@ typedef struct bearer_context_pdcp_config_s {
bool pDCP_Reestablishment;
} bearer_context_pdcp_config_t;
/* 9.3.1.35 3GPP TS 38.463 */
typedef struct {
// PDCP SN
uint32_t sn;
// HFN
uint32_t hfn;
} e1_pdcp_count_t;
/* 9.3.1.58 3GPP TS 38.463 */
typedef struct {
// UL Count Value
e1_pdcp_count_t ul_count;
// DL Count Value
e1_pdcp_count_t dl_count;
} e1_pdcp_status_info_t;
typedef struct drb_to_setup_s {
long drbId;
bearer_context_pdcp_config_t pdcp_config;
......@@ -384,6 +400,8 @@ typedef struct DRB_nGRAN_to_modify_s {
bearer_context_pdcp_config_t *pdcp_config;
// PDCP SN Status Request (O)
bool pdcp_sn_status_requested;
// PDCP SN Status Information
e1_pdcp_status_info_t *pdcp_status;
// DL UP Transport Layer Information (O) (clause 9.3.1.13, 9.3.2.1)
int numDlUpParam;
up_params_t DlUpParamList[E1AP_MAX_NUM_UP_PARAM];
......@@ -561,9 +579,8 @@ typedef struct DRB_nGRAN_modified_s {
// Flow Failed List (O)
int numQosFlowFailed;
qos_flow_failed_t qosFlowsFailed[E1AP_MAX_NUM_QOS_FLOWS];
// Old QoS Flow List (O)
int numOldQosFlow;
qos_flow_list_t oldQosFlows[E1AP_MAX_NUM_QOS_FLOWS];
// PDCP SN Status Information (0)
e1_pdcp_status_info_t *pdcp_status;
} DRB_nGRAN_modified_t;
typedef struct DRB_nGRAN_failed_s {
......
......@@ -62,3 +62,7 @@ MESSAGE_DEF(NR_RRC_MAC_SBCCH_DATA_IND, MESSAGE_PRIORITY_MED_PLUS, NRRrcMacSBc
// Message to GNB_APP to update SIB19 satellite position information
MESSAGE_DEF(GNB_SAT_POSITION_UPDATE, MESSAGE_PRIORITY_MED, gnb_sat_position_update_t, gnb_sat_position_update)
// nrUE
MESSAGE_DEF(NR_RRC_MAC_MEAS_DATA_IND, MESSAGE_PRIORITY_MED_PLUS, NRRrcMacMeasDataInd, nr_rrc_mac_meas_data_ind)
......@@ -44,6 +44,8 @@
#define NR_RRC_MAC_BCCH_DATA_IND(mSGpTR) (mSGpTR)->ittiMsg.nr_rrc_mac_bcch_data_ind
#define NR_RRC_MAC_SBCCH_DATA_IND(mSGpTR) (mSGpTR)->ittiMsg.nr_rrc_mac_sbcch_data_ind
#define NR_RRC_MAC_MEAS_DATA_IND(mSGpTR) (mSGpTR)->ittiMsg.nr_rrc_mac_meas_data_ind
#define RRC_MAC_BCCH_MBMS_DATA_REQ(mSGpTR) (mSGpTR)->ittiMsg.rrc_mac_bcch_mbms_data_req
#define RRC_MAC_BCCH_MBMS_DATA_IND(mSGpTR) (mSGpTR)->ittiMsg.rrc_mac_bcch_mbms_data_ind
......@@ -142,6 +144,14 @@ typedef struct NRRrcMacSBcchDataInd_s {
uint8_t rsrp;
} NRRrcMacSBcchDataInd;
typedef struct NRRrcMacMeasDataInd_s {
uint8_t gnb_index;
uint8_t rsrp_dBm;
uint16_t Nid_cell;
bool is_csi_meas;
bool is_neighboring_cell;
} NRRrcMacMeasDataInd;
typedef struct RrcMacBcchMbmsDataReq_s {
uint32_t frame;
uint32_t sdu_size;
......
......@@ -71,6 +71,13 @@ 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_HANDOVER_REQUIRED, MESSAGE_PRIORITY_MED, ngap_handover_required_t, ngap_handover_required)
MESSAGE_DEF(NGAP_HANDOVER_FAILURE, MESSAGE_PRIORITY_MED, ngap_handover_failure_t, ngap_handover_failure)
MESSAGE_DEF(NGAP_HANDOVER_REQUEST_ACKNOWLEDGE, MESSAGE_PRIORITY_MED, ngap_handover_request_ack_t, ngap_handover_request_ack)
MESSAGE_DEF(NGAP_HANDOVER_NOTIFY, MESSAGE_PRIORITY_MED, ngap_handover_notify_t, ngap_handover_notify)
MESSAGE_DEF(NGAP_HANDOVER_CANCEL, MESSAGE_PRIORITY_MED, ngap_handover_cancel_t, ngap_handover_cancel)
MESSAGE_DEF(NGAP_UL_RAN_STATUS_TRANSFER, MESSAGE_PRIORITY_MED, ngap_ran_status_transfer_t, ngap_ul_ran_status_transfer)
MESSAGE_DEF(NGAP_DL_RAN_STATUS_TRANSFER, MESSAGE_PRIORITY_MED, ngap_ran_status_transfer_t, ngap_dl_ran_status_transfer)
/* NGAP -> RRC messages */
MESSAGE_DEF(NGAP_DOWNLINK_NAS , MESSAGE_PRIORITY_MED, ngap_downlink_nas_t , ngap_downlink_nas )
......@@ -81,6 +88,9 @@ MESSAGE_DEF(NGAP_PDUSESSION_SETUP_REQ , MESSAGE_PRIORITY_MED, ngap_pd
MESSAGE_DEF(NGAP_PDUSESSION_MODIFY_REQ , MESSAGE_PRIORITY_MED, ngap_pdusession_modify_req_t , ngap_pdusession_modify_req )
MESSAGE_DEF(NGAP_PDUSESSION_RELEASE_COMMAND , MESSAGE_PRIORITY_MED, ngap_pdusession_release_command_t , ngap_pdusession_release_command)
MESSAGE_DEF(NGAP_UE_CONTEXT_RELEASE_COMMAND, MESSAGE_PRIORITY_MED, ngap_ue_release_command_t , ngap_ue_release_command)
MESSAGE_DEF(NGAP_HANDOVER_REQUEST, MESSAGE_PRIORITY_MED, ngap_handover_request_t, ngap_handover_request)
MESSAGE_DEF(NGAP_HANDOVER_COMMAND, MESSAGE_PRIORITY_MED, ngap_handover_command_t, ngap_handover_command)
MESSAGE_DEF(NGAP_HANDOVER_CANCEL_ACK, MESSAGE_PRIORITY_MED, ngap_handover_cancel_ack_t, ngap_handover_cancel_ack)
/* NGAP <-> RRC messages (can be initiated either by MME or gNB) */
MESSAGE_DEF(NGAP_UE_CONTEXT_RELEASE_REQ , MESSAGE_PRIORITY_MED, ngap_ue_release_req_t , ngap_ue_release_req)
This diff is collapsed.
......@@ -360,6 +360,39 @@ static E1AP_UP_Parameters_t encode_dl_up_parameters(const int numUpParam, const
return out;
}
/** @brief PDCP SN Status Information (9.3.1.58 3GPP TS 38.463) */
static E1AP_PDCP_SN_Status_Information_t encode_pdcp_status_info(const e1_pdcp_status_info_t *in)
{
E1AP_PDCP_SN_Status_Information_t pdcp = {0};
pdcp.pdcpStatusTransfer_DL.hFN = in->dl_count.hfn;
pdcp.pdcpStatusTransfer_DL.pDCP_SN = in->dl_count.sn;
pdcp.pdcpStatusTransfer_UL.countValue.hFN = in->ul_count.hfn;
pdcp.pdcpStatusTransfer_UL.countValue.pDCP_SN = in->ul_count.sn;
return pdcp;
}
/** @brief PDCP SN Status Information (9.3.1.58 3GPP TS 38.463) */
static e1_pdcp_status_info_t decode_pdcp_status_info(const E1AP_PDCP_SN_Status_Information_t* in)
{
e1_pdcp_status_info_t out = {0};
const E1AP_PDCP_Count_t *dl = &in->pdcpStatusTransfer_DL;
const E1AP_PDCP_Count_t *ul = &in->pdcpStatusTransfer_UL.countValue;
out.dl_count.hfn = dl->hFN;
out.dl_count.sn = dl->pDCP_SN;
out.ul_count.hfn = ul->hFN;
out.ul_count.sn = ul->pDCP_SN;
return out;
}
static bool eq_pdcp_info(const e1_pdcp_status_info_t *a, const e1_pdcp_status_info_t *b)
{
_E1_EQ_CHECK_INT(a->dl_count.hfn, b->dl_count.hfn);
_E1_EQ_CHECK_INT(a->dl_count.sn, b->dl_count.sn);
_E1_EQ_CHECK_INT(a->ul_count.hfn, b->ul_count.hfn);
_E1_EQ_CHECK_INT(a->ul_count.sn, b->ul_count.sn);
return true;
}
/**
* @brief Equality check for DRB_nGRAN_to_setup_t
*/
......@@ -1409,6 +1442,11 @@ static E1AP_PDU_Session_Resource_To_Modify_Item_t e1_encode_pdu_session_to_mod_i
asn1cCalloc(drb2Mod->pDCP_SN_Status_Request, pDCP_SN_Status_Request);
*pDCP_SN_Status_Request = E1AP_PDCP_SN_Status_Request_requested;
}
// PDCP Status Information (O)
if (j->pdcp_status) {
asn1cCalloc(drb2Mod->pdcp_SN_Status_Information, pdcp);
*pdcp = encode_pdcp_status_info(j->pdcp_status);
}
// DL UP TNL parameters (O)
if (j->numDlUpParam > 0) {
asn1cCalloc(drb2Mod->dL_UP_Parameters, DL_UP_Param_List);
......@@ -1658,7 +1696,7 @@ static bool e1_decode_pdu_session_to_mod_item(pdu_session_to_mod_t *out, const E
drb->id = drb2Mod->dRB_ID;
// PDCP Config (O)
if (drb2Mod->pDCP_Configuration) {
drb->pdcp_config = malloc_or_fail(sizeof(*drb->pdcp_config));
drb->pdcp_config = calloc_or_fail(1, sizeof(*drb->pdcp_config));
CHECK_E1AP_DEC(e1_decode_pdcp_config(drb->pdcp_config, drb2Mod->pDCP_Configuration));
}
// SDAP Config (O)
......@@ -1667,9 +1705,14 @@ static bool e1_decode_pdu_session_to_mod_item(pdu_session_to_mod_t *out, const E
CHECK_E1AP_DEC(e1_decode_sdap_config(drb->sdap_config, drb2Mod->sDAP_Configuration));
}
// PDCP SN Status Request (O)
if (drb2Mod->pDCP_SN_Status_Request) {
if (drb2Mod->pDCP_SN_Status_Request && *drb2Mod->pDCP_SN_Status_Request == E1AP_PDCP_SN_Status_Request_requested) {
drb->pdcp_sn_status_requested = true;
}
// PDCP SN Status Information (O)
if (drb2Mod->pdcp_SN_Status_Information) {
drb->pdcp_status = malloc_or_fail(sizeof(*drb->pdcp_status));
*drb->pdcp_status = decode_pdcp_status_info(drb2Mod->pdcp_SN_Status_Information);
}
// DL UP TNL parameters (O)
if (drb2Mod->dL_UP_Parameters) {
E1AP_UP_Parameters_t *dl_up_paramList = drb2Mod->dL_UP_Parameters;
......@@ -1843,6 +1886,7 @@ static DRB_nGRAN_to_mod_t cp_drb_to_mod_item(const DRB_nGRAN_to_mod_t *msg)
cp = *msg;
_E1_CP_OPTIONAL_IE(&cp, msg, sdap_config);
_E1_CP_OPTIONAL_IE(&cp, msg, pdcp_config);
_E1_CP_OPTIONAL_IE(&cp, msg, pdcp_status);
return cp;
}
......@@ -1904,12 +1948,15 @@ static bool eq_drb_to_mod(const DRB_nGRAN_to_mod_t *a, const DRB_nGRAN_to_mod_t
_E1_EQ_CHECK_INT(a->numDlUpParam, b->numDlUpParam);
for (int i = 0; i < a->numDlUpParam; i++) {
_E1_EQ_CHECK_INT(a->DlUpParamList[i].cell_group_id, b->DlUpParamList[i].cell_group_id);
eq_up_tl_info(&a->DlUpParamList[i].tl_info, &b->DlUpParamList[i].tl_info);
result &= eq_up_tl_info(&a->DlUpParamList[i].tl_info, &b->DlUpParamList[i].tl_info);
}
if (a->pdcp_config && b->pdcp_config)
result &= eq_pdcp_config(a->pdcp_config, b->pdcp_config);
if (a->sdap_config && b->sdap_config)
result &= eq_sdap_config(a->sdap_config, b->sdap_config);
_E1_EQ_CHECK_OPTIONAL_PTR(a, b, pdcp_status);
if (a->pdcp_status && b->pdcp_status)
result &= eq_pdcp_info(a->pdcp_status, b->pdcp_status);
return result;
}
......@@ -1984,6 +2031,7 @@ static void free_drb_to_mod_item(const DRB_nGRAN_to_mod_t *msg)
{
free(msg->pdcp_config);
free(msg->sdap_config);
free(msg->pdcp_status);
}
/* Free PDU Session to modify item */
......@@ -2111,6 +2159,13 @@ struct E1AP_E1AP_PDU *encode_E1_bearer_context_mod_response(const e1ap_bearer_mo
asn1cSequenceAdd(drb_mod->flow_Failed_List->list, E1AP_QoS_Flow_Failed_Item_t, fail);
encode_qos_flow_failed_item(fail, &drb->qosFlowsFailed[q]);
}
// PDCP Status Information (O)
if (drb->pdcp_status) {
asn1cCalloc(drb_mod->pDCP_SN_Status_Information, pdcp);
*pdcp = encode_pdcp_status_info(drb->pdcp_status);
}
// UL UP Parameters (O)
if (drb->numUpParam)
drb_mod->uL_UP_Transport_Parameters = calloc_or_fail(1, sizeof(*drb_mod->uL_UP_Transport_Parameters));
......@@ -2310,6 +2365,11 @@ bool decode_E1_bearer_context_mod_response(e1ap_bearer_modif_resp_t *out, const
drbMod->qosFlowsFailed[i] = decode_qos_flow_failed_item(drbIE->flow_Failed_List->list.array[i]);
}
}
// PDCP Status Info (O)
if (drbIE->pDCP_SN_Status_Information) {
drbMod->pdcp_status = malloc_or_fail(sizeof(*drbMod->pdcp_status));
*drbMod->pdcp_status = decode_pdcp_status_info(drbIE->pDCP_SN_Status_Information);
}
}
}
// DRB Failed to Mod list
......@@ -2347,8 +2407,12 @@ e1ap_bearer_modif_resp_t cp_bearer_context_mod_response(const e1ap_bearer_modif_
// Shallow copy
cp = *msg;
// Deep copy PDU sessions modified items
for (int i = 0; i < msg->numPDUSessionsMod; i++)
for (int i = 0; i < msg->numPDUSessionsMod; i++) {
cp.pduSessionMod[i] = cp_pdu_session_mod_item(&msg->pduSessionMod[i]);
for (int j = 0; j < msg->pduSessionMod[i].numDRBModified; j++) {
_E1_CP_OPTIONAL_IE(&cp.pduSessionMod[i].DRBnGRanModList[j], &msg->pduSessionMod[i].DRBnGRanModList[j], pdcp_status);
}
}
return cp;
}
......@@ -2359,6 +2423,8 @@ bool eq_bearer_context_mod_response(const e1ap_bearer_modif_resp_t *a, const e1a
{
if (!a || !b) return false; // Null-check both inputs
bool result = true;
// Basic members
_E1_EQ_CHECK_INT(a->gNB_cu_cp_ue_id, b->gNB_cu_cp_ue_id);
_E1_EQ_CHECK_INT(a->gNB_cu_up_ue_id, b->gNB_cu_up_ue_id);
......@@ -2375,7 +2441,7 @@ bool eq_bearer_context_mod_response(const e1ap_bearer_modif_resp_t *a, const e1a
_E1_EQ_CHECK_OPTIONAL_PTR(pduA, pduB, ng_DL_UP_TL_info);
if (pduA->ng_DL_UP_TL_info && pduB->ng_DL_UP_TL_info)
eq_up_tl_info(pduA->ng_DL_UP_TL_info, pduB->ng_DL_UP_TL_info);
result &= eq_up_tl_info(pduA->ng_DL_UP_TL_info, pduB->ng_DL_UP_TL_info);
// DRB Modified List
_E1_EQ_CHECK_INT(pduA->numDRBModified, pduB->numDRBModified);
......@@ -2387,6 +2453,10 @@ bool eq_bearer_context_mod_response(const e1ap_bearer_modif_resp_t *a, const e1a
for (int j = 0; j < drbModA->numQosFlowSetup; j++) {
_E1_EQ_CHECK_LONG(drbModA->qosFlows[j].qfi, drbModB->qosFlows[j].qfi);
}
_E1_EQ_CHECK_OPTIONAL_PTR(drbModA, drbModB, pdcp_status);
if (drbModA->pdcp_status && drbModB->pdcp_status) {
result &= eq_pdcp_info(drbModA->pdcp_status, drbModA->pdcp_status);
}
}
// DRB Failed to Modify List
......@@ -2420,7 +2490,7 @@ bool eq_bearer_context_mod_response(const e1ap_bearer_modif_resp_t *a, const e1a
}
return true;
return result;
}
/**
......@@ -2432,6 +2502,9 @@ void free_e1ap_context_mod_response(const e1ap_bearer_modif_resp_t *msg)
free(msg->pduSessionMod[i].confidentialityProtectionIndication);
free(msg->pduSessionMod[i].integrityProtectionIndication);
free(msg->pduSessionMod[i].ng_DL_UP_TL_info);
for (int j = 0; j < msg->pduSessionMod[i].numDRBModified; j++) {
free(msg->pduSessionMod[i].DRBnGRanModList[j].pdcp_status);
}
}
}
......
......@@ -490,6 +490,13 @@ static void test_bearer_context_modification_request(void)
.qos_params.qos_characteristics.non_dynamic.fiveqi = 9,
};
const e1_pdcp_status_info_t dummy_pdcp_status = {
.dl_count.hfn = 12,
.dl_count.sn = 34,
.ul_count.hfn = 56,
.ul_count.sn = 78,
};
DRB_nGRAN_to_mod_t drb_to_mod = {
.numDlUpParam = 1,
.DlUpParamList[0].cell_group_id = MCG,
......@@ -497,10 +504,12 @@ static void test_bearer_context_modification_request(void)
.id = 1,
.pdcp_config = malloc_or_fail(sizeof(*drb_to_mod.pdcp_config)),
.pdcp_sn_status_requested = true,
.pdcp_status = malloc_or_fail(sizeof(*drb_to_mod.pdcp_status)),
.numQosFlow2Setup = 1,
.qosFlows[0] = dummy_qos_flows,
};
*drb_to_mod.pdcp_config = dummy_pdcp_config;
*drb_to_mod.pdcp_status = dummy_pdcp_status;
pdu_session_to_mod_t pdusession_mod_item = {
.sessionId = 1,
......@@ -592,12 +601,21 @@ const DRB_nGRAN_failed_t dummy_drb_failed = {
*/
static void test_bearer_context_modification_response(void)
{
const e1_pdcp_status_info_t dummy_pdcp_status = {
.dl_count.hfn = 12,
.dl_count.sn = 2,
.ul_count.hfn = 12,
.ul_count.sn = 3,
};
// DRB Modified List
DRB_nGRAN_modified_t drb_mod = {
.id = 1,
.numQosFlowSetup = 1,
.qosFlows[0].qfi = 1,
.pdcp_status = malloc_or_fail(sizeof(*drb_mod.pdcp_status)),
};
*drb_mod.pdcp_status = dummy_pdcp_status;
// DRB Setup List
DRB_nGRAN_setup_t setup = {
......
......@@ -170,7 +170,7 @@ static void capture_sst_sd(test_cond_value_t* test_cond_value, uint8_t *sst, uin
DevAssert(test_cond_value->octet_string_value->len == 4);
uint8_t *buf = test_cond_value->octet_string_value->buf;
*sst = buf[0];
*sd = malloc(**sd);
*sd = malloc(sizeof(uint32_t));
**sd = buf[1] << 16 | buf[2] << 8 | buf[3];
}
printf("[E2 AGENT][E2SM-KPM] Condition NSSAI (%d, %x).\n", *sst, (*sd) ? **sd : 0xffffff);
......
......@@ -722,6 +722,8 @@ void RCconfig_verify(configmodule_interface_t *cfg, ngran_node_t node_type)
verify_section_notset(cfg, GNB_CONFIG_STRING_GNB_LIST ".[0]", GNB_CONFIG_STRING_AMF_IP_ADDRESS);
verify_section_notset(cfg, NULL, CONFIG_STRING_SECURITY);
verify_section_notset(cfg, NULL, CONFIG_STRING_NR_PDCP_LIST);
verify_section_notset(cfg, NULL, GNB_CONFIG_STRING_NEIGHBOUR_LIST);
verify_section_notset(cfg, NULL, GNB_CONFIG_STRING_MEASUREMENT_CONFIGURATION);
} // else nothing to be checked
/* other possible verifications: PNF, VNF, CU-CP, CU-UP, ...? */
......@@ -1858,21 +1860,21 @@ static void fill_neighbour_cell_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc
GNBNEIGHBOURCELLPARAMS_DESC,
GNB_CONFIG_STRING_NEIGHBOUR_CELL_LIST,
neighbourpath);
LOG_D(GNB_APP, "HO LOG: For the Cell: %ld Neighbour Cell ELM NUM: %d\n", cell.nr_cell_id, NeighbourCellParamList.numelt);
LOG_I(GNB_APP, "Cell %ld has %d neighbours\n", cell.nr_cell_id, NeighbourCellParamList.numelt);
if (NeighbourCellParamList.numelt < 1)
continue;
cell.neighbour_cells = malloc_or_fail(sizeof(seq_arr_t));
seq_arr_init(cell.neighbour_cells, sizeof(nr_neighbour_cell_t));
for (int l = 0; l < NeighbourCellParamList.numelt; ++l) {
nr_neighbour_cell_t neighbourCell = {0};
neighbourCell.gNB_ID = *(NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_GNB_ID_IDX].uptr);
neighbourCell.nrcell_id = (uint64_t) * (NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_NR_CELLID_IDX].u64ptr);
neighbourCell.physicalCellId = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_PHYSICAL_ID_IDX].uptr;
neighbourCell.subcarrierSpacing = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_SCS_IDX].uptr;
neighbourCell.band = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_BAND_IDX].uptr;
neighbourCell.absoluteFrequencySSB = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_ABS_FREQ_SSB_IDX].i64ptr;
neighbourCell.tac = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_TAC_IDX].uptr;
nr_neighbour_cell_t n = {0};
n.gNB_ID = *(NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_GNB_ID_IDX].uptr);
n.nrcell_id = (uint64_t) * (NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_NR_CELLID_IDX].u64ptr);
n.physicalCellId = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_PHYSICAL_ID_IDX].uptr;
n.subcarrierSpacing = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_SCS_IDX].uptr;
n.band = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_BAND_IDX].uptr;
n.absoluteFrequencySSB = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_ABS_FREQ_SSB_IDX].i64ptr;
n.tac = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_TAC_IDX].uptr;
char neighbour_plmn_path[CONFIG_MAXOPTLENGTH];
snprintf(neighbour_plmn_path,
......@@ -1884,10 +1886,22 @@ static void fill_neighbour_cell_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc
GNB_CONFIG_STRING_NEIGHBOUR_PLMN);
GET_PARAMS(NeighbourPlmn, GNBPLMNPARAMS_DESC, neighbour_plmn_path);
neighbourCell.plmn.mcc = *NeighbourPlmn[GNB_MOBILE_COUNTRY_CODE_IDX].uptr;
neighbourCell.plmn.mnc = *NeighbourPlmn[GNB_MOBILE_NETWORK_CODE_IDX].uptr;
neighbourCell.plmn.mnc_digit_length = *NeighbourPlmn[GNB_MNC_DIGIT_LENGTH].uptr;
seq_arr_push_back(cell.neighbour_cells, &neighbourCell, sizeof(neighbourCell));
n.plmn.mcc = *NeighbourPlmn[GNB_MOBILE_COUNTRY_CODE_IDX].uptr;
n.plmn.mnc = *NeighbourPlmn[GNB_MOBILE_NETWORK_CODE_IDX].uptr;
n.plmn.mnc_digit_length = *NeighbourPlmn[GNB_MNC_DIGIT_LENGTH].uptr;
seq_arr_push_back(cell.neighbour_cells, &n, sizeof(n));
LOG_I(GNB_APP,
" [%d] neighbor ID %d cellId %ld PCI %d SCS %d SSB ARFCN %u TAC %u PLMN %03u.%0*u\n",
l,
n.gNB_ID,
n.nrcell_id,
n.physicalCellId,
n.subcarrierSpacing,
n.absoluteFrequencySSB,
n.tac,
n.plmn.mcc,
n.plmn.mnc_digit_length,
n.plmn.mnc);
}
seq_arr_push_back(rrc->neighbour_cell_configuration, &cell, sizeof(cell));
}
......
......@@ -594,8 +594,8 @@ typedef struct NR_UE_MAC_INST_s {
nr_csi_report_t csi_report_template[MAX_CSI_REPORTCONFIG];
/// measurements from CSI-RS
fapi_nr_csirs_measurements_t csirs_measurements;
/// measurements from SS or CSI-RS
fapi_nr_l1_measurements_t l1_measurements;
//// FAPI-like interface message
fapi_nr_ul_config_request_t *ul_config_request;
......
......@@ -117,10 +117,8 @@ csi_payload_t nr_ue_aperiodic_csi_reporting(NR_UE_MAC_INST_t *mac, dci_field_t c
nr_dci_format_t nr_ue_process_dci_indication_pdu(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, fapi_nr_dci_indication_pdu_t *dci);
int8_t nr_ue_process_csirs_measurements(NR_UE_MAC_INST_t *mac,
frame_t frame,
int slot,
fapi_nr_csirs_measurements_t *csirs_measurements);
void nr_ue_process_l1_measurements(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, fapi_nr_l1_measurements_t *l1_measurements);
void nr_ue_aperiodic_srs_scheduling(NR_UE_MAC_INST_t *mac, long resource_trigger, int frame, int slot);
bool trigger_periodic_scheduling_request(NR_UE_MAC_INST_t *mac,
......
......@@ -302,7 +302,7 @@ void release_mac_configuration(NR_UE_MAC_INST_t *mac, NR_UE_MAC_reset_cause_t ca
release_ul_BWP(mac, i);
memset(&mac->ssb_measurements, 0, sizeof(mac->ssb_measurements));
memset(&mac->csirs_measurements, 0, sizeof(mac->csirs_measurements));
memset(&mac->l1_measurements, 0, sizeof(mac->l1_measurements));
memset(&mac->ul_time_alignment, 0, sizeof(mac->ul_time_alignment));
for (int i = mac->TAG_list.count; i > 0 ; i--)
asn_sequence_del(&mac->TAG_list, i - 1, 1);
......
......@@ -1193,7 +1193,9 @@ void nr_ra_contention_resolution_failed(NR_UE_MAC_INST_t *mac)
ra->t_crnti = 0;
// flush MSG3 buffer
free_and_zero(ra->Msg3_buffer);
nr_mac_rrc_msg3_ind(mac->ue_id, 0, true);
// MSG3 with C-RNTI is a L2 procedure, we shouldn't send any indication to RRC
if (!mac->msg3_C_RNTI)
nr_mac_rrc_msg3_ind(mac->ue_id, 0, true);
NR_PRACH_RESOURCES_t *prach_resources = &ra->prach_resources;
prach_resources->preamble_tx_counter++;
if (prach_resources->preamble_tx_counter == ra->preambleTransMax + 1) {
......
......@@ -489,19 +489,42 @@ void ue_dci_configuration(NR_UE_MAC_INST_t *mac, fapi_nr_dl_config_request_t *dl
config_dci_pdu(mac, dl_config, rnti_type, slot, ra_SS);
}
} else if (mac->state == UE_CONNECTED) {
/*
In RRC Connected state, the UE monitors for fallback DCI with C-RNTI in common and UE-specific SS.
First the UE check all UE specific SS. If no fallback DCI is configured, it configures one of following
common SS with the shown priority
1. RA SS
2. Other SI SS
3. Paging SS
4. SIB1 SS
There is a possibility that gNB could configure multiple UE-specific SS for fallback DCI or/and common SS,
and in a given slot more than one SS become active. For the moment, we assume such configuration wouldn't happen
and hence don't handle it for the sake of implementation simplicity.
*/
bool configured_fallback_dci = false;
for (int i = 0; i < pdcch_config->list_SS.count; i++) {
NR_SearchSpace_t *ss = pdcch_config->list_SS.array[i];
if (is_ss_monitor_occasion(frame, slot, slots_per_frame, ss))
if (is_ss_monitor_occasion(frame, slot, slots_per_frame, ss)) {
config_dci_pdu(mac, dl_config, TYPE_C_RNTI_, slot, ss);
configured_fallback_dci |= (ss->searchSpaceType->present == NR_SearchSpace__searchSpaceType_PR_common);
}
}
const NR_SearchSpace_t *ra_SS = get_common_search_space(mac, pdcch_config->ra_SS_id);
if (pdcch_config->list_SS.count == 0 && ra_SS) {
// If the UE has not been provided a Type3-PDCCH CSS set or a USS set and
// the UE has received a C-RNTI and has been provided a Type1-PDCCH CSS set,
// the UE monitors PDCCH candidates for DCI format 0_0 and DCI format 1_0
// with CRC scrambled by the C-RNTI in the Type1-PDCCH CSS set
if (is_ss_monitor_occasion(frame, slot, slots_per_frame, ra_SS))
config_dci_pdu(mac, dl_config, TYPE_C_RNTI_, slot, ra_SS);
const NR_SearchSpace_t *css = NULL;
if (!configured_fallback_dci) {
#define CSS_VALID_CUR_SLOT(CSS) \
((CSS > -1) && is_ss_monitor_occasion(frame, slot, slots_per_frame, get_common_search_space(mac, CSS)))
if (CSS_VALID_CUR_SLOT(pdcch_config->ra_SS_id))
css = get_common_search_space(mac, pdcch_config->ra_SS_id);
else if (CSS_VALID_CUR_SLOT(pdcch_config->otherSI_SS_id))
css = get_common_search_space(mac, pdcch_config->otherSI_SS_id);
else if (CSS_VALID_CUR_SLOT(pdcch_config->paging_SS_id))
css = get_common_search_space(mac, pdcch_config->paging_SS_id);
#undef CSS_VALID_CUR_SLOT
else
css = mac->search_space_zero;
AssertFatal(css, "Atleast one CSS should be present in connected state\n");
config_dci_pdu(mac, dl_config, TYPE_C_RNTI_, slot, css);
}
}
}
......@@ -1504,13 +1504,17 @@ nr_dci_format_t nr_ue_process_dci_indication_pdu(NR_UE_MAC_INST_t *mac, frame_t
return format;
}
int8_t nr_ue_process_csirs_measurements(NR_UE_MAC_INST_t *mac,
frame_t frame,
int slot,
fapi_nr_csirs_measurements_t *csirs_measurements) {
LOG_D(NR_MAC,"(%d.%d) Received CSI-RS measurements\n", frame, slot);
memcpy(&mac->csirs_measurements, csirs_measurements, sizeof(*csirs_measurements));
return 0;
void nr_ue_process_l1_measurements(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, fapi_nr_l1_measurements_t *l1_measurements)
{
LOG_D(NR_MAC, "(%d.%d) Received CSI-RS measurements\n", frame, slot);
memcpy(&mac->l1_measurements, l1_measurements, sizeof(*l1_measurements));
bool csi_meas = l1_measurements->meas_type == NFAPI_NR_CSI_MEAS;
nr_mac_rrc_meas_ind_ue(mac->ue_id,
l1_measurements->gNB_index,
l1_measurements->Nid_cell,
csi_meas,
l1_measurements->is_neighboring_cell,
l1_measurements->rsrp_dBm);
}
static void set_harq_status(NR_UE_MAC_INST_t *mac,
......@@ -2993,9 +2997,9 @@ static csi_payload_t get_csirs_RI_PMI_CQI_payload(NR_UE_MAC_INST_t *mac,
AssertFatal(csi_report, "Couldn't find CSI report with ID %ld\n", csi_reportconfig->reportConfigId);
int cri_bitlen = csi_report->csi_meas_bitlen.cri_bitlen;
int ri_bitlen = csi_report->csi_meas_bitlen.ri_bitlen;
int pmi_x1_bitlen = csi_report->csi_meas_bitlen.pmi_x1_bitlen[mac->csirs_measurements.rank_indicator];
int pmi_x2_bitlen = csi_report->csi_meas_bitlen.pmi_x2_bitlen[mac->csirs_measurements.rank_indicator];
int cqi_bitlen = csi_report->csi_meas_bitlen.cqi_bitlen[mac->csirs_measurements.rank_indicator];
int pmi_x1_bitlen = csi_report->csi_meas_bitlen.pmi_x1_bitlen[mac->l1_measurements.rank_indicator];
int pmi_x2_bitlen = csi_report->csi_meas_bitlen.pmi_x2_bitlen[mac->l1_measurements.rank_indicator];
int cqi_bitlen = csi_report->csi_meas_bitlen.cqi_bitlen[mac->l1_measurements.rank_indicator];
if (get_softmodem_params()->emulate_l1) {
static const uint8_t mcs_to_cqi[] = {0, 1, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,
......@@ -3003,9 +3007,9 @@ static csi_payload_t get_csirs_RI_PMI_CQI_payload(NR_UE_MAC_INST_t *mac,
CHECK_INDEX(nr_bler_data, NR_NUM_MCS - 1);
int mcs = get_mcs_from_sinr(nr_bler_data, (mac->nr_ue_emul_l1.cqi - 640) * 0.1);
CHECK_INDEX(mcs_to_cqi, mcs);
mac->csirs_measurements.rank_indicator = mac->nr_ue_emul_l1.ri;
mac->csirs_measurements.i1 = mac->nr_ue_emul_l1.pmi;
mac->csirs_measurements.cqi = mcs_to_cqi[mcs];
mac->l1_measurements.rank_indicator = mac->nr_ue_emul_l1.ri;
mac->l1_measurements.i1 = mac->nr_ue_emul_l1.pmi;
mac->l1_measurements.cqi = mcs_to_cqi[mcs];
}
int padding_bitlen = 0;
......@@ -3014,19 +3018,19 @@ static csi_payload_t get_csirs_RI_PMI_CQI_payload(NR_UE_MAC_INST_t *mac,
p1_bits = cri_bitlen + ri_bitlen + cqi_bitlen;
p2_bits = pmi_x1_bitlen + pmi_x2_bitlen;
temp_payload_1 = (0/*mac->csi_measurements.cri*/ << (cqi_bitlen + ri_bitlen)) |
(mac->csirs_measurements.rank_indicator << cqi_bitlen) |
(mac->csirs_measurements.cqi);
temp_payload_2 = (mac->csirs_measurements.i1 << pmi_x2_bitlen) |
mac->csirs_measurements.i2;
(mac->l1_measurements.rank_indicator << cqi_bitlen) |
(mac->l1_measurements.cqi);
temp_payload_2 = (mac->l1_measurements.i1 << pmi_x2_bitlen) |
mac->l1_measurements.i2;
}
else {
p1_bits = nr_get_csi_bitlen(csi_report);
padding_bitlen = p1_bits - (cri_bitlen + ri_bitlen + pmi_x1_bitlen + pmi_x2_bitlen + cqi_bitlen);
temp_payload_1 = (0/*mac->csi_measurements.cri*/ << (cqi_bitlen + pmi_x2_bitlen + pmi_x1_bitlen + padding_bitlen + ri_bitlen)) |
(mac->csirs_measurements.rank_indicator << (cqi_bitlen + pmi_x2_bitlen + pmi_x1_bitlen + padding_bitlen)) |
(mac->csirs_measurements.i1 << (cqi_bitlen + pmi_x2_bitlen)) |
(mac->csirs_measurements.i2 << (cqi_bitlen)) |
(mac->csirs_measurements.cqi);
(mac->l1_measurements.rank_indicator << (cqi_bitlen + pmi_x2_bitlen + pmi_x1_bitlen + padding_bitlen)) |
(mac->l1_measurements.i1 << (cqi_bitlen + pmi_x2_bitlen)) |
(mac->l1_measurements.i2 << (cqi_bitlen)) |
(mac->l1_measurements.cqi);
}
temp_payload_1 = reverse_bits(temp_payload_1, p1_bits);
......@@ -3085,17 +3089,7 @@ static csi_payload_t get_csirs_RSRP_payload(NR_UE_MAC_INST_t *mac,
}
// TODO: Improvements will be needed to cri_ssbri_bitlen>0
// TS 38.133 - Table 10.1.6.1-1
int rsrp_dBm = mac->csirs_measurements.rsrp_dBm;
if (rsrp_dBm < -140) {
temp_payload = 16;
} else if (rsrp_dBm > -44) {
temp_payload = 113;
} else {
temp_payload = mac->csirs_measurements.rsrp_dBm + 157;
}
temp_payload = reverse_bits(temp_payload, n_bits);
temp_payload = reverse_bits(mac->l1_measurements.rsrp_dBm, n_bits); // rsrp_dBm as in TS 38.133 - Table 10.1.6.1-1
LOG_D(NR_MAC, "cri_ssbri_bitlen = %d\n", cri_ssbri_bitlen);
LOG_D(NR_MAC, "rsrp_bitlen = %d\n", rsrp_bitlen);
......
......@@ -3461,11 +3461,10 @@ void nr_measgap_scheduling(gNB_MAC_INST *nr_mac, frame_t frame, sub_frame_t slot
continue;
NR_timer_t *t = &UE->UE_sched_ctrl.transm_interrupt;
interrupt_followup_action_t a = nr_timer_is_active(t) ? UE->interrupt_action : FOLLOW_INSYNC;
// start a timer to stop scheduling UE during MeasGap, or extend timer for
// duration of measGap with existing follow-up action
if (!nr_timer_is_active(t) || nr_timer_remaining_time(t) < mgc->mgl_slots) {
nr_mac_interrupt_ue_transmission(nr_mac, UE, a, mgc->mgl_slots);
nr_mac_interrupt_ue_transmission(nr_mac, UE, mgc->mgl_slots);
}
}
}
......@@ -3549,7 +3548,7 @@ int nr_mac_get_reconfig_delay_slots(NR_SubcarrierSpacing_t scs)
return (delay_ms << scs) + sl_ahead;
}
int nr_mac_interrupt_ue_transmission(gNB_MAC_INST *mac, NR_UE_info_t *UE, interrupt_followup_action_t action, int slots)
int nr_mac_interrupt_ue_transmission(gNB_MAC_INST *mac, NR_UE_info_t *UE, int slots)
{
DevAssert(mac != NULL);
DevAssert(UE != NULL);
......@@ -3557,7 +3556,6 @@ int nr_mac_interrupt_ue_transmission(gNB_MAC_INST *mac, NR_UE_info_t *UE, interr
nr_timer_setup(&UE->UE_sched_ctrl.transm_interrupt, slots, 1);
nr_timer_start(&UE->UE_sched_ctrl.transm_interrupt);
UE->interrupt_action = action;
// it might happen that timing advance command should be sent during the UE
// inactivity time. To prevent this, set a variable as if we would have just
......@@ -3565,14 +3563,27 @@ int nr_mac_interrupt_ue_transmission(gNB_MAC_INST *mac, NR_UE_info_t *UE, interr
// frames, after the inactivity of the UE.
UE->UE_sched_ctrl.ta_frame = (mac->frame - 1 + 1024) % 1024;
LOG_D(NR_MAC, "UE %04x: Interrupt UE transmission (%d slots) action %d\n", UE->rnti, slots, UE->interrupt_action);
LOG_D(NR_MAC, "UE %04x: Interrupt UE transmission (%d slots)\n", UE->rnti, slots);
return 0;
}
static void nr_mac_ue_transmission_timeout(gNB_MAC_INST *mac, NR_UE_info_t *UE, int slots)
{
DevAssert(mac != NULL);
DevAssert(UE != NULL);
NR_SCHED_ENSURE_LOCKED(&mac->sched_lock);
nr_timer_setup(&UE->UE_sched_ctrl.transm_timeout, slots, 1);
nr_timer_start(&UE->UE_sched_ctrl.transm_timeout);
LOG_I(NR_MAC, "UE %04x: Timeout for UE transmission (%d slots)\n", UE->rnti, slots);
return;
}
int nr_transmission_action_indicator_stop(gNB_MAC_INST *mac, NR_UE_info_t *UE_info)
{
int delay = nr_mac_get_reconfig_delay_slots(UE_info->current_DL_BWP.scs);
nr_mac_interrupt_ue_transmission(mac, UE_info, FOLLOW_OUTOFSYNC, delay);
nr_mac_ue_transmission_timeout(mac, UE_info, delay);
LOG_I(NR_MAC, "gNB-DU received the TransmissionActionIndicator with Stop value for UE %04x\n", UE_info->rnti);
return 0;
}
......@@ -3641,9 +3652,11 @@ void nr_mac_update_timers(module_id_t module_id, frame_t frame, slot_t slot)
if (nr_timer_tick(&sched_ctrl->transm_interrupt)) {
/* expired */
nr_timer_stop(&sched_ctrl->transm_interrupt);
if (UE->interrupt_action == FOLLOW_OUTOFSYNC)
nr_mac_trigger_ul_failure(sched_ctrl, UE->current_DL_BWP.scs);
/* else: default FOLLOW_INSYNC: nothing to do (UE is now active again) */
}
if (nr_timer_tick(&sched_ctrl->transm_timeout)) {
nr_timer_stop(&sched_ctrl->transm_timeout);
LOG_W(NR_MAC, "UE %04x UL failure after transmission timeout\n", UE->rnti);
nr_mac_trigger_ul_failure(sched_ctrl, UE->current_DL_BWP.scs);
}
}
}
......
......@@ -65,7 +65,7 @@ void nr_mac_prepare_ra_ue(gNB_MAC_INST *nrmac, NR_UE_info_t *UE);
bool add_new_UE_RA(gNB_MAC_INST *nr_mac, NR_UE_info_t *UE);
int nr_mac_get_reconfig_delay_slots(NR_SubcarrierSpacing_t scs);
int nr_mac_interrupt_ue_transmission(gNB_MAC_INST *mac, NR_UE_info_t *UE, interrupt_followup_action_t action, int slots);
int nr_mac_interrupt_ue_transmission(gNB_MAC_INST *mac, NR_UE_info_t *UE, int slots);
int nr_transmission_action_indicator_stop(gNB_MAC_INST *mac, NR_UE_info_t *UE_info);
void clear_nr_nfapi_information(gNB_MAC_INST *gNB,
......
......@@ -688,6 +688,10 @@ typedef struct {
/// Timer for RRC processing procedures and transmission activity
NR_timer_t transm_interrupt;
/// Timer for timeout before UE is set to UL failure (e.g.,
/// "TransmissionActionIndicator" handling
NR_timer_t transm_timeout;
/// sri, ul_ri and tpmi based on SRS
nr_srs_feedback_t srs_feedback;
......@@ -762,8 +766,6 @@ typedef struct measgap_config {
int mgl_slots;
} measgap_config_t;
typedef enum interrupt_followup_action { FOLLOW_INSYNC, FOLLOW_OUTOFSYNC } interrupt_followup_action_t;
/*! \brief UE list used by gNB to order UEs/CC for scheduling*/
typedef struct {
rnti_t rnti;
......@@ -780,7 +782,6 @@ typedef struct {
/// in case of reestablishment, old spCellConfig to apply after
/// reconfiguration
NR_SpCellConfig_t *reconfigSpCellConfig;
interrupt_followup_action_t interrupt_action;
NR_UE_NR_Capability_t *capability;
measgap_config_t measgap_config;
// UE selected beam index
......
......@@ -291,6 +291,32 @@ void e1_bearer_context_modif(const e1ap_bearer_mod_req_t *req)
&security_parameters);
}
// PDCP Status Information requested
if (to_modif->pdcp_sn_status_requested) {
modified->pdcp_status = malloc_or_fail(sizeof(*modified->pdcp_status));
nr_pdcp_count_t dl_count = {0};
nr_pdcp_count_t ul_count = {0};
nr_pdcp_get_drb_count_values(req->gNB_cu_cp_ue_id, to_modif->id, &ul_count, &dl_count);
modified->pdcp_status->dl_count.hfn = dl_count.hfn;
modified->pdcp_status->dl_count.sn = dl_count.sn;
modified->pdcp_status->ul_count.hfn = ul_count.hfn;
modified->pdcp_status->ul_count.sn = ul_count.sn;
}
// PDCP Status received (from source CU-UP)
if (to_modif->pdcp_status) {
DevAssert(to_modif->pdcp_config);
DevAssert(to_modif->pdcp_config->pDCP_SN_Size_DL == to_modif->pdcp_config->pDCP_SN_Size_UL);
bool is_sn_len_18 = to_modif->pdcp_config->pDCP_SN_Size_DL == NR_PDCP_Config__drb__pdcp_SN_SizeDL_len18bits;
nr_pdcp_count_t dl_count = { .hfn = to_modif->pdcp_status->dl_count.hfn, .sn = to_modif->pdcp_status->dl_count.sn};
nr_pdcp_count_t ul_count = { .hfn = to_modif->pdcp_status->ul_count.hfn, .sn = to_modif->pdcp_status->ul_count.sn};
nr_pdcp_count_update(req->gNB_cu_cp_ue_id,
to_modif->id,
dl_count,
ul_count,
is_sn_len_18 ? LONG_SN_SIZE : SHORT_SN_SIZE);
}
if (f1inst < 0) // no F1-U?
continue; // nothing to do
......@@ -300,6 +326,7 @@ void e1_bearer_context_modif(const e1ap_bearer_mod_req_t *req)
in_addr_t addr = to_modif->DlUpParamList[k].tl_info.tlAddress;
GtpuUpdateTunnelOutgoingAddressAndTeid(f1inst, req->gNB_cu_cp_ue_id, to_modif->id, addr, to_modif->DlUpParamList[k].tl_info.teId);
}
}
}
......
......@@ -601,6 +601,94 @@ static void nr_pdcp_entity_get_stats(nr_pdcp_entity_t *entity,
*out = entity->stats;
}
/** @note: this function applies to the gNB only */
static nr_pdcp_count_t nr_pdcp_entity_get_count_dl(nr_pdcp_entity_t *entity)
{
nr_pdcp_count_t count = {0};
const int sn_bits = entity->sn_size;
const uint32_t sn_mask = entity->sn_max;
count.hfn = entity->rx_deliv >> sn_bits;
count.sn = entity->rx_deliv & sn_mask;
return count;
}
/** @note: this function applies to the gNB only */
static nr_pdcp_count_t nr_pdcp_entity_get_count_ul(nr_pdcp_entity_t *entity)
{
nr_pdcp_count_t count = {0};
const int sn_bits = entity->sn_size;
const uint32_t sn_mask = entity->sn_max;
count.hfn = entity->tx_next >> sn_bits;
count.sn = entity->tx_next & sn_mask;
return count;
}
/** @note: this function applies to the gNB only */
static void nr_pdcp_entity_set_count_dl(nr_pdcp_entity_t *entity, nr_pdcp_count_t pdcp_count, int sn_size)
{
// SN length in bits
const uint32_t sn_mask = (1 << sn_size) - 1;
// Compose COUNT values for tx_next (DL) and rx_next (UL)
uint32_t count = (pdcp_count.hfn << sn_size) | (pdcp_count.sn & sn_mask);
// Apply the COUNT values
entity->rx_next = count + 1;
entity->rx_deliv = count;
LOG_I(PDCP,
"DRB %d: Applied PDCP Count\n"
" DL COUNT - SN: %d HFN: %d (COUNT=%u)\n"
" SN length: %s\n"
" PDCP entity state after update:\n"
" rx_next = %u\n"
" rx_deliv = %u\n"
" sn_size = %d\n"
" sn_max = %d\n"
" window = %d\n",
entity->rb_id,
pdcp_count.sn,
pdcp_count.hfn,
count,
sn_size == LONG_SN_SIZE ? "18-bit" : "12-bit",
entity->rx_next,
entity->rx_deliv,
entity->sn_size,
entity->sn_max,
entity->window_size);
}
/** @note: this function applies to the gNB only */
static void nr_pdcp_entity_set_count_ul(nr_pdcp_entity_t *entity, nr_pdcp_count_t pdcp_count, int sn_size)
{
// SN length in bits
const uint32_t sn_mask = (1 << sn_size) - 1;
// Compose COUNT values for tx_next (DL) and rx_next (UL)
uint32_t count = (pdcp_count.hfn << sn_size) | (pdcp_count.sn & sn_mask);
// Apply the COUNT values
entity->tx_next = count;
LOG_I(PDCP,
"DRB %d: Applied PDCP Count\n"
" UL COUNT - SN: %d HFN: %d (COUNT=%u)\n"
" SN length: %s\n"
" PDCP entity state after update:\n"
" tx_next = %u\n"
" sn_size = %d\n"
" sn_max = %d\n"
" window = %d\n",
entity->rb_id,
pdcp_count.sn,
pdcp_count.hfn,
count,
sn_size == LONG_SN_SIZE ? "18-bit" : "12-bit",
entity->tx_next,
entity->sn_size,
entity->sn_max,
entity->window_size);
}
nr_pdcp_entity_t *new_nr_pdcp_entity(
nr_pdcp_entity_type_t type,
......@@ -675,5 +763,11 @@ nr_pdcp_entity_t *new_nr_pdcp_entity(
nr_pdcp_entity_set_security(ret, security_parameters);
/* PDCP Count API */
ret->get_pdcp_count_dl = nr_pdcp_entity_get_count_dl;
ret->get_pdcp_count_ul = nr_pdcp_entity_get_count_ul;
ret->set_pdcp_count_dl = nr_pdcp_entity_set_count_dl;
ret->set_pdcp_count_ul = nr_pdcp_entity_set_count_ul;
return ret;
}
......@@ -55,6 +55,11 @@ typedef struct {
uint8_t ciphering_key[NR_K_KEY_SIZE];
} nr_pdcp_entity_security_keys_and_algos_t;
typedef struct {
uint32_t sn;
uint32_t hfn;
} nr_pdcp_count_t;
typedef struct {
//nr_pdcp_entity_type_t mode;
/* PDU stats */
......@@ -87,7 +92,6 @@ typedef struct {
uint8_t mode; /* 0: PDCP AM, 1: PDCP UM, 2: PDCP TM */
} nr_pdcp_statistics_t;
typedef struct nr_pdcp_entity_t {
nr_pdcp_entity_type_t type;
......@@ -180,6 +184,13 @@ typedef struct nr_pdcp_entity_t {
/* Keep tracks of whether the PDCP entity was suspended or not */
bool entity_suspended;
/* PDCP Count API */
nr_pdcp_count_t (*get_pdcp_count_dl)(struct nr_pdcp_entity_t *entity);
nr_pdcp_count_t (*get_pdcp_count_ul)(struct nr_pdcp_entity_t *entity);
void (*set_pdcp_count_dl)(struct nr_pdcp_entity_t *entity, nr_pdcp_count_t count, int sn_size);
void (*set_pdcp_count_ul)(struct nr_pdcp_entity_t *entity, nr_pdcp_count_t count, int sn_size);
} nr_pdcp_entity_t;
nr_pdcp_entity_t *new_nr_pdcp_entity(
......
......@@ -1072,3 +1072,57 @@ int nr_pdcp_get_num_ues(ue_id_t *ue_list, int len)
return num_ues;
}
void nr_pdcp_count_update(ue_id_t ue_id,
rb_id_t drb_id,
nr_pdcp_count_t dl_count,
nr_pdcp_count_t ul_count,
int sn_size)
{
nr_pdcp_manager_lock(nr_pdcp_ue_manager);
nr_pdcp_ue_t *ue = nr_pdcp_manager_get_ue(nr_pdcp_ue_manager, ue_id);
if (ue == NULL) {
LOG_E(PDCP, "UE %ld not found in PDCP manager\n", ue_id);
nr_pdcp_manager_unlock(nr_pdcp_ue_manager);
return;
}
nr_pdcp_entity_t *entity = nr_pdcp_get_rb(ue, drb_id, false);
if (entity == NULL) {
LOG_E(PDCP, "No PDCP entity found for UE %ld DRB %ld\n", ue_id, drb_id);
nr_pdcp_manager_unlock(nr_pdcp_ue_manager);
return;
}
entity->set_pdcp_count_dl(entity, dl_count, sn_size);
entity->set_pdcp_count_ul(entity, ul_count, sn_size);
nr_pdcp_manager_unlock(nr_pdcp_ue_manager);
}
/** * @brief Get PDCP COUNT values (PDCP-SN and HFN) for UL and DL from the PDCP entity
* @param[in] ue_id Unique UE ID
* @param[in] rb_id Radio Bearer ID
* @param[out] ul_count UL PDCP count (SN, HFN)
* @param[out] dl_count DL PDCP count (SN, HFN)
*/
void nr_pdcp_get_drb_count_values(ue_id_t ue_id, rb_id_t rb_id, nr_pdcp_count_t *ul_count, nr_pdcp_count_t *dl_count)
{
nr_pdcp_manager_lock(nr_pdcp_ue_manager);
nr_pdcp_ue_t *ue = nr_pdcp_manager_get_ue(nr_pdcp_ue_manager, ue_id);
nr_pdcp_entity_t *entity = nr_pdcp_get_rb(ue, rb_id, false);
if (!entity) {
LOG_E(PDCP, "No entity found (DRB %ld)\n", rb_id);
nr_pdcp_manager_unlock(nr_pdcp_ue_manager);
return;
}
*dl_count = entity->get_pdcp_count_dl(entity);
*ul_count = entity->get_pdcp_count_ul(entity);
nr_pdcp_manager_unlock(nr_pdcp_ue_manager);
}
......@@ -125,4 +125,12 @@ int nr_pdcp_get_num_ues(ue_id_t *ue_list, int len);
bool nr_pdcp_get_statistics(ue_id_t ue_id, int srb_flag, int rb_id, nr_pdcp_statistics_t *out);
void nr_pdcp_count_update(ue_id_t ue_id,
rb_id_t drb_id,
nr_pdcp_count_t dl_count,
nr_pdcp_count_t ul_count,
int sn_size);
void nr_pdcp_get_drb_count_values(ue_id_t ue_id, rb_id_t rb_id, nr_pdcp_count_t *ul_count, nr_pdcp_count_t *dl_count);
#endif /* NR_PDCP_OAI_API_H */
......@@ -1174,13 +1174,11 @@ static void handle_rlm(rlm_t rlm_result, int frame, NR_UE_MAC_INST_t *mac)
nr_mac_rrc_sync_ind(mac->ue_id, frame, is_sync);
}
static int8_t handle_csirs_measurements(NR_UE_MAC_INST_t *mac,
frame_t frame,
int slot,
fapi_nr_csirs_measurements_t *csirs_measurements)
static int8_t handle_l1_measurements(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, fapi_nr_l1_measurements_t *l1_measurements)
{
handle_rlm(csirs_measurements->radiolink_monitoring, frame, mac);
return nr_ue_process_csirs_measurements(mac, frame, slot, csirs_measurements);
handle_rlm(l1_measurements->radiolink_monitoring, frame, mac);
nr_ue_process_l1_measurements(mac, frame, slot, l1_measurements);
return 0;
}
void update_harq_status(NR_UE_MAC_INST_t *mac, uint8_t harq_pid, uint8_t ack_nack)
......@@ -1316,11 +1314,11 @@ static uint32_t nr_ue_dl_processing(NR_UE_MAC_INST_t *mac, nr_downlink_indicatio
}
ret_mask |= (handle_dlsch(mac, dl_info, i)) << FAPI_NR_RX_PDU_TYPE_RAR;
break;
case FAPI_NR_CSIRS_IND:
ret_mask |= (handle_csirs_measurements(mac,
dl_info->frame,
dl_info->slot,
&rx_indication_body.csirs_measurements)) << FAPI_NR_CSIRS_IND;
case FAPI_NR_MEAS_IND:
ret_mask |= (handle_l1_measurements(mac,
dl_info->frame,
dl_info->slot,
&rx_indication_body.l1_measurements)) << FAPI_NR_MEAS_IND;
break;
default:
break;
......
This diff is collapsed.
......@@ -50,11 +50,14 @@
#include "NR_ReestablishmentCause.h"
#include "NR_SRB-ToAddModList.h"
#include "NR_SecurityConfig.h"
#include "NR_MeasurementReport.h"
#include "NR_MeasurementTimingConfiguration.h"
#include "NR_UE-CapabilityRAT-ContainerList.h"
#include "ds/seq_arr.h"
#include "ds/byte_array.h"
#include "rrc_messages_types.h"
#include "openair2/LAYER2/nr_pdcp/nr_pdcp_configuration.h"
#include "common/utils/nr/nr_common.h"
struct asn_TYPE_descriptor_s;
typedef struct {
......@@ -69,6 +72,7 @@ typedef struct {
NR_CellGroupConfig_t *cell_group_config;
bool masterKeyUpdate;
int nextHopChainingCount;
byte_array_t ue_cap;
} nr_rrc_reconfig_param_t;
/*
......@@ -127,6 +131,15 @@ int do_NR_MeasurementTimingConfiguration(const NR_MeasurementTimingConfiguration
int do_RRCSetupRequest(uint8_t *buffer, size_t buffer_size, uint8_t *rv, uint64_t fiveG_S_TMSI_part1);
int do_nrMeasurementReport_SA(NR_MeasurementReport_t *measurementReport,
long trigger_to_measid,
long trigger_quantity,
long rs_type,
uint16_t Nid_cell,
int rsrp_dBm,
uint8_t *buffer,
size_t buffer_size);
int do_NR_RRCReconfigurationComplete_for_nsa(uint8_t *buffer, size_t buffer_size, NR_RRC_TransactionIdentifier_t Transaction_id);
int do_NR_RRCReconfigurationComplete(uint8_t *buffer, size_t buffer_size, const uint8_t Transaction_id);
......@@ -161,4 +174,12 @@ NR_MeasConfig_t *get_MeasConfig(const NR_MeasTiming_t *mt,
void free_MeasConfig(NR_MeasConfig_t *mc);
int do_NR_Paging(uint8_t Mod_id, uint8_t *buffer, uint32_t tmsi);
byte_array_t get_HandoverPreparationInformation(nr_rrc_reconfig_param_t *params, int scell_pci);
byte_array_t get_HandoverCommandMessage(nr_rrc_reconfig_param_t *params);
void fill_removal_lists_from_source_measConfig(NR_MeasConfig_t *measConfig, byte_array_t prep_info);
int doRRCReconfiguration_from_HandoverCommand(byte_array_t *ba, byte_array_t handoverCommand);
struct NR_UE_NR_Capability *get_ue_nr_capability(int rnti, uint8_t *buf, uint32_t len);
NR_UE_NR_Capability_t *decode_nr_ue_capability(int rnti, const NR_UE_CapabilityRAT_ContainerList_t *clist);
#endif /* __RRC_NR_MESSAGES_ASN1_MSG__H__ */
......@@ -315,7 +315,7 @@ typedef struct {
int absoluteFrequencySSB;
int subcarrierSpacing;
int band;
plmn_identity_t plmn;
plmn_id_t plmn;
uint32_t tac;
bool isIntraFrequencyNeighbour;
} nr_neighbour_cell_t;
......
......@@ -125,4 +125,9 @@ nr_rrc_reconfig_param_t get_RRCReconfiguration_params(gNB_RRC_INST *rrc, gNB_RRC
pdusession_level_qos_parameter_t *get_qos_characteristics(const int qfi, rrc_pdu_session_param_t *pduSession);
f1ap_qos_flow_param_t get_qos_char_from_qos_flow_param(const pdusession_level_qos_parameter_t *qos_param);
void openair_rrc_gNB_configuration(gNB_RRC_INST *rrc, gNB_RrcConfigurationReq *configuration);
NR_SRB_ToAddModList_t *createSRBlist(gNB_RRC_UE_t *ue, uint8_t reestablish);
NR_DRB_ToAddModList_t *createDRBlist(gNB_RRC_UE_t *ue, bool reestablish);
void activate_srb(gNB_RRC_UE_t *UE, int srb_id);
void e1_send_bearer_updates(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, f1ap_drb_setup_t *drbs, const ngap_drb_status_t *drb_status);
#endif
This diff is collapsed.
This diff is collapsed.
......@@ -89,4 +89,26 @@ void nr_rrc_pdcp_config_security(gNB_RRC_UE_t *UE, bool enable_ciphering);
int rrc_gNB_process_PAGING_IND(MessageDef *msg_p, instance_t instance);
void rrc_gNB_send_NGAP_HANDOVER_REQUIRED(gNB_RRC_INST *rrc,
gNB_RRC_UE_t *UE,
const nr_neighbour_cell_t *neighbourCellConfiguration,
const byte_array_t hoPrepInfo);
void rrc_gNB_send_NGAP_HANDOVER_FAILURE(gNB_RRC_INST *rrc, ngap_handover_failure_t *msg);
int rrc_gNB_process_Handover_Request(gNB_RRC_INST *rrc, instance_t instance, ngap_handover_request_t *msg);
void rrc_gNB_free_Handover_Request(ngap_handover_request_t *msg);
void rrc_gNB_send_NGAP_HANDOVER_REQUEST_ACKNOWLEDGE(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, byte_array_t ho_command);
void rrc_gNB_process_HandoverCommand(gNB_RRC_INST *rrc, const ngap_handover_command_t *msg);
void rrc_gNB_free_Handover_Command(ngap_handover_command_t *msg);
void rrc_gNB_send_NGAP_HANDOVER_NOTIFY(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE);
void rrc_gNB_send_NGAP_HANDOVER_CANCEL(int module_id, gNB_RRC_UE_t *UE, ngap_cause_t cause);
int rrc_gNB_send_NGAP_ul_ran_status_transfer(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const int n_to_mod, const e1_pdcp_status_info_t *pdcp_status);
int rrc_gNB_process_NGAP_DL_RAN_STATUS_TRANSFER(MessageDef *msg_p, instance_t instance);
#endif
This diff is collapsed.
......@@ -23,6 +23,7 @@
#include <stdint.h>
#include "common/utils/ds/byte_array.h"
#include "nr_rrc_defs.h"
/* forward declarations */
typedef struct gNB_RRC_INST_s gNB_RRC_INST;
......@@ -32,6 +33,8 @@ typedef struct nr_rrc_du_container_t nr_rrc_du_container_t;
typedef struct NR_CellGroupConfig NR_CellGroupConfig_t;
typedef void (*ho_cancel_t)(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue);
typedef int (*ho_status_transfer_t)(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const int n_to_mod, const e1_pdcp_status_info_t *pdcp_status);
typedef struct nr_ho_source_cu {
/// pointer to the (source) DU structure
const nr_rrc_du_container_t *du;
......@@ -47,11 +50,16 @@ typedef struct nr_ho_source_cu {
/// function pointer to announce the handover cancellation, e.g.,
/// reestablishment
ho_cancel_t ho_cancel;
/// status transfer
ho_status_transfer_t ho_status_transfer;
} nr_ho_source_cu_t;
/* acknowledgement of handover request. buf+len is the RRC Reconfiguration */
typedef void (*ho_req_ack_t)(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue);
typedef void (*ho_success_t)(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue);
typedef void (*ho_failure_t)(gNB_RRC_INST *rrc, uint32_t gnb_ue_id, ngap_handover_failure_t *msg);
typedef void (*ho_trigger_t)(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue);
typedef struct nr_ho_target_cu {
/// pointer to the (target) DU structure
const nr_rrc_du_container_t *du;
......@@ -61,10 +69,16 @@ typedef struct nr_ho_target_cu {
uint32_t du_ue_id;
/// new (target) RNTI (as for du_ue_id)
rnti_t new_rnti;
/// Handover Preparation Buffer
byte_array_t ue_ho_prep_info;
/// function pointer to trigger handover on target gNB
ho_trigger_t ho_trigger;
/// function pointer to announce handover request acknowledgment
ho_req_ack_t ho_req_ack;
/// function pointer to announce handover success
ho_success_t ho_success;
/// function pointer to announce the handover failure
ho_failure_t ho_failure;
} nr_ho_target_cu_t;
typedef struct nr_handover_context_s {
......@@ -72,7 +86,20 @@ typedef struct nr_handover_context_s {
nr_ho_target_cu_t *target;
} nr_handover_context_t;
typedef enum { HO_CTX_BOTH, HO_CTX_SOURCE, HO_CTX_TARGET } ho_ctx_type_t;
nr_handover_context_t *alloc_ho_ctx(ho_ctx_type_t type);
void nr_rrc_trigger_f1_ho(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue, nr_rrc_du_container_t *source_du, nr_rrc_du_container_t *target_du);
void nr_rrc_finalize_ho(gNB_RRC_UE_t *ue);
void nr_rrc_n2_ho_failure(gNB_RRC_INST *rrc, uint32_t gnb_ue_id, ngap_handover_failure_t *msg);
void nr_rrc_trigger_n2_ho(gNB_RRC_INST *rrc,
gNB_RRC_UE_t *ue,
int serving_pci,
const nr_neighbour_cell_t *neighbour_config);
void rrc_gNB_trigger_reconfiguration_for_handover(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue, uint8_t *rrc_reconf, int rrc_reconf_len);
void nr_rrc_trigger_n2_ho_target(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue);
#endif /* RRC_GNB_MOBILITY_H_ */
......@@ -37,6 +37,17 @@
typedef uint32_t channel_t;
void nr_mac_rrc_meas_ind_ue(module_id_t module_id, uint32_t gNB_index, uint16_t Nid_cell, bool csi_meas, bool is_neighboring_cell, uint8_t rsrp_dBm)
{
MessageDef *message_p = itti_alloc_new_message(TASK_MAC_UE, 0, NR_RRC_MAC_MEAS_DATA_IND);
NR_RRC_MAC_MEAS_DATA_IND(message_p).gnb_index = gNB_index;
NR_RRC_MAC_MEAS_DATA_IND(message_p).Nid_cell = Nid_cell;
NR_RRC_MAC_MEAS_DATA_IND(message_p).is_csi_meas = csi_meas;
NR_RRC_MAC_MEAS_DATA_IND(message_p).is_neighboring_cell = is_neighboring_cell;
NR_RRC_MAC_MEAS_DATA_IND(message_p).rsrp_dBm = rsrp_dBm;
itti_send_msg_to_task(TASK_RRC_NRUE, GNB_MODULE_ID_TO_INSTANCE(module_id), message_p);
}
void nr_mac_rrc_sync_ind(const module_id_t module_id, const frame_t frame, const bool in_sync)
{
MessageDef *message_p = itti_alloc_new_message(TASK_MAC_UE, 0, NR_RRC_MAC_SYNC_IND);
......
......@@ -37,6 +37,12 @@ void nr_mac_rrc_data_ind_ue(const module_id_t module_id,
const channel_t channel,
const uint8_t* pduP,
const sdu_size_t pdu_len);
void nr_mac_rrc_meas_ind_ue(module_id_t module_id,
uint32_t gNB_index,
uint16_t Nid_cell,
bool csi_meas,
bool is_neighboring_cell,
uint8_t rsrp_dBm);
void nr_mac_rrc_inactivity_timer_ind(const module_id_t mod_id);
void nr_mac_rrc_msg3_ind(const module_id_t mod_id, const int rnti, bool prepare_payload);
void nr_ue_rrc_timer_trigger(int instance, int frame, int gnb_id);
......
This diff is collapsed.
......@@ -192,6 +192,20 @@ typedef enum {
typedef enum { RB_NOT_PRESENT, RB_ESTABLISHED, RB_SUSPENDED } NR_RB_status_t;
typedef struct l3_measurements_s {
float ssb_filter_coeff_rsrp;
float csi_RS_filter_coeff_rsrp;
meas_t serving_cell;
long trigger_to_measid;
long trigger_quantity;
long rs_type;
int reports_sent;
int max_reports;
long report_interval_ms;
NR_timer_t TA2;
NR_timer_t periodic_report_timer;
} l3_measurements_t;
typedef struct rrcPerNB {
NR_MeasObjectToAddMod_t *MeasObj[MAX_MEAS_OBJ];
NR_ReportConfigToAddMod_t *ReportConfig[MAX_MEAS_CONFIG];
......@@ -201,6 +215,7 @@ typedef struct rrcPerNB {
NR_MeasGapConfig_t *measGapConfig;
NR_UE_RRC_SI_INFO SInfo;
NR_RSRP_Range_t s_measure;
l3_measurements_t l3_measurements;
} rrcPerNB_t;
typedef struct NR_UE_RRC_INST_s {
......@@ -233,6 +248,10 @@ typedef struct NR_UE_RRC_INST_s {
e_NR_IntegrityProtAlgorithm integrityProtAlgorithm;
long keyToUse;
bool as_security_activated;
/// Next Hop Chaining Count
uint8_t nh[32];
uint64_t nhcc;
bool detach_after_release;
NR_timer_t release_timer;
NR_RRCRelease_t *RRCRelease;
......
......@@ -55,6 +55,8 @@ void nr_rrc_going_to_IDLE(NR_UE_RRC_INST_t *rrc,
void handle_RRCRelease(NR_UE_RRC_INST_t *rrc);
void rrc_ue_generate_measurementReport(rrcPerNB_t *rrc, instance_t ue_id);
void set_rlf_sib1_timers_and_constants(NR_UE_Timers_Constants_t *tac, NR_UE_TimersAndConstants_t *ue_TimersAndConstants);
/**\brief RRC UE task.
......@@ -83,6 +85,7 @@ void nr_ue_rrc_timer_trigger(int module_id, int frame, int gnb_id);
void handle_t300_expiry(NR_UE_RRC_INST_t *rrc);
void handle_t430_expiry(NR_UE_RRC_INST_t *rrc);
int get_A2_event_time_to_trigger(long time_to_trigger);
void reset_rlf_timers_and_constants(NR_UE_Timers_Constants_t *tac);
void set_default_timers_and_constants(NR_UE_Timers_Constants_t *tac);
void nr_rrc_set_sib1_timers_and_constants(NR_UE_Timers_Constants_t *tac, NR_SIB1_t *sib1);
......
......@@ -122,6 +122,36 @@ void nr_rrc_SI_timers(NR_UE_RRC_SI_INFO *SInfo)
}
}
void handle_meas_timers(NR_UE_RRC_INST_t *rrc)
{
for (int i = 0; i < NB_CNX_UE; i++) {
rrcPerNB_t *nb = &rrc->perNB[i];
l3_measurements_t *l3_measurements = &nb->l3_measurements;
bool ta2_expired = nr_timer_tick(&l3_measurements->TA2);
if (ta2_expired && l3_measurements->trigger_quantity > 0) {
rrc_ue_generate_measurementReport(nb, rrc->ue_id);
l3_measurements->reports_sent = 1;
if (l3_measurements->reports_sent < l3_measurements->max_reports) {
nr_timer_setup(&l3_measurements->periodic_report_timer, l3_measurements->report_interval_ms, 10);
nr_timer_start(&l3_measurements->periodic_report_timer);
}
}
bool periodic_expired = nr_timer_tick(&l3_measurements->periodic_report_timer);
if (periodic_expired && l3_measurements->reports_sent < l3_measurements->max_reports) {
rrc_ue_generate_measurementReport(nb, rrc->ue_id);
l3_measurements->reports_sent++;
if (l3_measurements->reports_sent < l3_measurements->max_reports) {
nr_timer_setup(&l3_measurements->periodic_report_timer, l3_measurements->report_interval_ms, 10);
nr_timer_start(&l3_measurements->periodic_report_timer);
}
}
}
}
void nr_rrc_handle_timers(NR_UE_RRC_INST_t *rrc)
{
NR_UE_Timers_Constants_t *timers = &rrc->timers_and_constants;
......@@ -185,6 +215,8 @@ void nr_rrc_handle_timers(NR_UE_RRC_INST_t *rrc)
// Spec 38.331 Section 5.2.2.6
handle_t430_expiry(rrc);
}
handle_meas_timers(rrc);
}
int nr_rrc_get_T304(long t304)
......@@ -630,3 +662,43 @@ void reset_rlf_timers_and_constants(NR_UE_Timers_Constants_t *tac)
tac->N310_cnt = 0;
tac->N311_cnt = 0;
}
int get_A2_event_time_to_trigger(long time_to_trigger)
{
switch (time_to_trigger) {
case NR_TimeToTrigger_ms0:
return 0;
case NR_TimeToTrigger_ms40:
return 40;
case NR_TimeToTrigger_ms64:
return 64;
case NR_TimeToTrigger_ms80:
return 80;
case NR_TimeToTrigger_ms100:
return 100;
case NR_TimeToTrigger_ms128:
return 128;
case NR_TimeToTrigger_ms160:
return 160;
case NR_TimeToTrigger_ms256:
return 256;
case NR_TimeToTrigger_ms320:
return 320;
case NR_TimeToTrigger_ms480:
return 480;
case NR_TimeToTrigger_ms512:
return 512;
case NR_TimeToTrigger_ms640:
return 640;
case NR_TimeToTrigger_ms1024:
return 1024;
case NR_TimeToTrigger_ms1280:
return 1280;
case NR_TimeToTrigger_ms2560:
return 2560;
case NR_TimeToTrigger_ms5120:
return 5120;
default:
AssertFatal(false, "Invalid TimeToTrigger %ld\n", time_to_trigger);
}
}
This diff is collapsed.
......@@ -83,10 +83,16 @@ typedef int (*ngap_message_decoded_callback)(sctp_assoc_t assoc_id, uint32_t str
void encode_ngap_cause(NGAP_Cause_t *out, const ngap_cause_t *in);
nr_guami_t decode_ngap_guami(const NGAP_GUAMI_t *in);
ngap_cause_t decode_ngap_cause(const NGAP_Cause_t *in);
ngap_ambr_t decode_ngap_UEAggregateMaximumBitRate(const NGAP_UEAggregateMaximumBitRate_t *in);
nssai_t decode_ngap_nssai(const NGAP_S_NSSAI_t *in);
ngap_security_capabilities_t decode_ngap_security_capabilities(const NGAP_UESecurityCapabilities_t *in);
ngap_mobility_restriction_t decode_ngap_mobility_restriction(const NGAP_MobilityRestrictionList_t *in);
void encode_ngap_target_id(NGAP_HandoverRequiredIEs_t *out, const target_ran_node_id_t *in);
void encode_ngap_nr_cgi(NGAP_NR_CGI_t *out, const plmn_id_t *plmn, const uint32_t cell_id);
pdusession_level_qos_parameter_t fill_qos(uint8_t qfi, const NGAP_QosFlowLevelQosParameters_t *params);
void *decode_pdusession_transfer(const asn_TYPE_descriptor_t *td, const OCTET_STRING_t buf);
bool decodePDUSessionResourceSetup(pdusession_transfer_t *out, const OCTET_STRING_t in);
/** @}*/
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -200,3 +200,11 @@ void tnl_to_bitstring(BIT_STRING_t *out, const transport_layer_addr_t in)
out->bits_unused = 0;
}
}
void bitstring_to_tnl(transport_layer_addr_t *out, const BIT_STRING_t in)
{
if (in.size) {
memcpy(out->buffer, in.buf, in.size);
out->length = in.size;
}
}
......@@ -50,4 +50,6 @@ void ngap_gNB_prepare_internal_data(void);
void tnl_to_bitstring(BIT_STRING_t *out, const transport_layer_addr_t in);
void bitstring_to_tnl(transport_layer_addr_t *out, const BIT_STRING_t in);
#endif /* NGAP_GNB_MANAGEMENT_PROCEDURES_H_ */
This diff is collapsed.
This diff is collapsed.
......@@ -76,6 +76,12 @@ struct ngap_gNB_ue_context_s *ngap_get_ue_context(uint32_t gNB_ue_ngap_id)
return RB_FIND(ngap_ue_map, &ngap_ue_head, &temp);
}
ngap_gNB_ue_context_t *ngap_get_ue_context_from_amf_ue_ngap_id(uint32_t amf_ue_ngap_id)
{
ngap_gNB_ue_context_t temp = {.amf_ue_ngap_id = amf_ue_ngap_id};
return RB_FIND(ngap_ue_map, &ngap_ue_head, &temp);
}
struct ngap_gNB_ue_context_s *ngap_detach_ue_context(uint32_t gNB_ue_ngap_id)
{
struct ngap_gNB_ue_context_s *tmp = ngap_get_ue_context(gNB_ue_ngap_id);
......
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment