From 56d05276bd602248f7d164ac058e8d8df7bc232e Mon Sep 17 00:00:00 2001 From: Sakthivel Velumani Date: Mon, 30 Sep 2024 16:50:55 -0400 Subject: [PATCH 01/75] Fix bug in websrv opening page allocating enough memory to hold url to index page. --- common/utils/websrv/websrv.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/common/utils/websrv/websrv.c b/common/utils/websrv/websrv.c index 33ae8313bf..6debf1283e 100644 --- a/common/utils/websrv/websrv.c +++ b/common/utils/websrv/websrv.c @@ -267,7 +267,7 @@ int websrv_callback_get_softmodemhelp(const struct _u_request *request, struct _ int httpstatus = 204; // no content char *hlpfile = strstr(request->http_url, "helpfiles"); if (hlpfile != NULL) { - char *hlppath = malloc(strlen(hlpfile) + strlen(websrvparams.fpath) + 1); + char *hlppath = malloc(strlen(hlpfile) + strlen(websrvparams.fpath) + 2); sprintf(hlppath, "%s/%s", websrvparams.fpath, hlpfile); help_string = websrv_read_file(hlppath); if (help_string == NULL) { @@ -291,9 +291,10 @@ int websrv_callback_default(const struct _u_request *request, struct _u_response LOG_I(UTIL, "[websrv] Requested file is: %s %s\n", request->http_verb, request->http_url); websrv_dump_request("default ", request, websrvparams.dbglvl); - char *fpath = malloc(strlen(request->http_url) + strlen(websrvparams.fpath) + 2); + const char *index_file_name = "index.html"; + char *fpath = malloc(strlen(request->http_url) + strlen(websrvparams.fpath) + strlen(index_file_name) + 2); if ((strcmp(request->http_url + 1, websrvparams.fpath) == 0) || (strcmp(request->http_url, "/") == 0)) { - sprintf(fpath, "%s/index.html", websrvparams.fpath); + sprintf(fpath, "%s/%s", websrvparams.fpath, index_file_name); } else { sprintf(fpath, "%s/%s", websrvparams.fpath, request->http_url); } From f8a51921a8c77bcce4f8d78c0f1d4a1fb11ecf99 Mon Sep 17 00:00:00 2001 From: Sakthivel Velumani Date: Mon, 30 Sep 2024 21:02:29 -0400 Subject: [PATCH 02/75] Update default path for websrv resources --- common/utils/websrv/DOC/websrvuse.md | 2 +- common/utils/websrv/websrv.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/common/utils/websrv/DOC/websrvuse.md b/common/utils/websrv/DOC/websrvuse.md index 684f64b104..27c0795634 100644 --- a/common/utils/websrv/DOC/websrvuse.md +++ b/common/utils/websrv/DOC/websrvuse.md @@ -244,7 +244,7 @@ The web server back-end is using the [oai configuration module](Config/Rtusage). | `listenaddr` | `ipV4 address, ascii format` | "0.0.0.0" | local address the back-end is listening on | | `listenport` | `integer` | 8090 | port number the server is listening on | | debug | `integer` | 0 | When not 0, http requests headers and json objects dump are added to back-end traces | -| fpath | character string | websrv | The path to on-disk http server resources . The default value matches the front-end installation when running the softmodem from the executables repository. | +| fpath | character string | common/utils/websrv | The path to on-disk http server resources . The default value matches the front-end installation when running the softmodem from the executables repository. | | cert, key, rootca | `character string` | null | certificates and key used to trigger https protocol (not tested) | | | | | | diff --git a/common/utils/websrv/websrv.c b/common/utils/websrv/websrv.c index 6debf1283e..f6fb898104 100644 --- a/common/utils/websrv/websrv.c +++ b/common/utils/websrv/websrv.c @@ -56,7 +56,7 @@ paramdef_t websrvoptions[] = { {"listenport", "\n", 0, uptr : &(websrvparams.listenport), defuintval : 8090, TYPE_UINT, 0}, {"priority", "\n", 0, uptr : &websrvparams.dbglvl, defuintval : 0, TYPE_UINT, 0}, - {"fpath", "\n", 0, strptr : &websrvparams.fpath, defstrval : "websrv", TYPE_STRING, 0}, + {"fpath", "\n", 0, strptr : &websrvparams.fpath, defstrval : "common/utils/websrv", TYPE_STRING, 0}, {"cert", "\n", 0, strptr : &websrvparams.certfile, defstrval : NULL, TYPE_STRING, 0}, {"key", "\n", 0, strptr : &websrvparams.keyfile, defstrval : NULL, TYPE_STRING, 0}, {"rootca", "\n", 0, strptr : &websrvparams.rootcafile, defstrval : NULL, TYPE_STRING, 0}, From f97c6ceb6cf8f6ecb45c5fce0506eecc9b78abac Mon Sep 17 00:00:00 2001 From: Jaroslava Fiedlerova Date: Thu, 10 Oct 2024 19:02:06 +0200 Subject: [PATCH 03/75] CI: Update enc/decoder tests in RAN-gNB-N300-Timing-Phytest-LDPC Set a maximum SNR value using the "-S" option to ensure that nr_dlsim or nr_ulsim is executed only for a given SNR. This approach allows us to verify the success of the encoding/decoding process at the specified SNR. Check if the test succeeds is not yet implemented (currently we only retrieve an information about encoding/decoding processing time). To be implemented in the separate MR. Always execute all the nr_dlsim/nr_ulsim tests even if one of them fails. Each test takes around 5s, so we can execute them all to get results for all the test scenarios. --- .../xml_files/t2_offload_dec_nr_ulsim.xml | 54 ++++++++++++------- .../xml_files/t2_offload_enc_nr_dlsim.xml | 54 ++++++++++++------- 2 files changed, 72 insertions(+), 36 deletions(-) diff --git a/ci-scripts/xml_files/t2_offload_dec_nr_ulsim.xml b/ci-scripts/xml_files/t2_offload_dec_nr_ulsim.xml index b7125f100b..4e44f7f853 100644 --- a/ci-scripts/xml_files/t2_offload_dec_nr_ulsim.xml +++ b/ci-scripts/xml_files/t2_offload_dec_nr_ulsim.xml @@ -33,145 +33,163 @@ Run_T2Test Run nr_ulsim with CPU: SNR = 30, MCS = 5, 106 PRBs, 1 layer + true nr_ulsim 300 - -n100 -s30 -m5 -r106 -R106 -C10 -P + -n100 -s30 -S30.2 -m5 -r106 -R106 -C10 -P Run_T2Test Run nr_ulsim with T2 LDPC offload: SNR = 30, MCS = 5, 106 PRBs, 1 layer + true nr_ulsim 100 - -n100 -s30 -m5 -r106 -R106 -o -P --ldpc_offload.dpdk_dev d8:00.0 + -n100 -s30 -S30.2 -m5 -r106 -R106 -o -P --ldpc_offload.dpdk_dev d8:00.0 Run_T2Test Run nr_ulsim with CPU: SNR = 30, MCS = 15, 106 PRBs, 1 layer + true nr_ulsim 300 - -n100 -s30 -m15 -r106 -R106 -C10 -P + -n100 -s30 -S30.2 -m15 -r106 -R106 -C10 -P Run_T2Test Run nr_ulsim with T2 LDPC offload: SNR = 30, MCS = 15, 106 PRBs, 1 layer + true nr_ulsim 150 - -n100 -s30 -m15 -r106 -R106 -o -P --ldpc_offload.dpdk_dev d8:00.0 + -n100 -s30 -S30.2 -m15 -r106 -R106 -o -P --ldpc_offload.dpdk_dev d8:00.0 Run_T2Test Run nr_ulsim with CPU: SNR = 30, MCS = 25, 106 PRBs, 1 layer + true nr_ulsim 250 - -n100 -s30 -m25 -r106 -R106 -C10 -P + -n100 -s30 -S30.2 -m25 -r106 -R106 -C10 -P Run_T2Test Run nr_ulsim with T2 LDPC offload: SNR = 30, MCS = 25, 106 PRBs, 1 layer + true nr_ulsim 250 - -n100 -s30 -m25 -r106 -R106 -o -P --ldpc_offload.dpdk_dev d8:00.0 + -n100 -s30 -S30.2 -m25 -r106 -R106 -o -P --ldpc_offload.dpdk_dev d8:00.0 Run_T2Test Run nr_ulsim with CPU: SNR = 30, MCS = 5, 273 PRBs, 1 layer + true nr_ulsim 300 - -n100 -s30 -m5 -r273 -R273 -C10 -P + -n100 -s30 -S30.2 -m5 -r273 -R273 -C10 -P Run_T2Test Run nr_ulsim with T2 LDPC offload: SNR = 30, MCS = 5, 273 PRBs, 1 layer + true nr_ulsim 150 - -n100 -s30 -m5 -r273 -R273 -o -P --ldpc_offload.dpdk_dev d8:00.0 + -n100 -s30 -S30.2 -m5 -r273 -R273 -o -P --ldpc_offload.dpdk_dev d8:00.0 Run_T2Test Run nr_ulsim with CPU: SNR = 30, MCS = 15, 273 PRBs, 1 layer + true nr_ulsim 400 - -n100 -s30 -m15 -r273 -R273 -C10 -P + -n100 -s30 -S30.2 -m15 -r273 -R273 -C10 -P Run_T2Test Run nr_ulsim with T2 LDPC offload: SNR = 30, MCS = 15, 273 PRBs, 1 layer + true nr_ulsim 350 - -n100 -s30 -m15 -r273 -R273 -o -P --ldpc_offload.dpdk_dev d8:00.0 + -n100 -s30 -S30.2 -m15 -r273 -R273 -o -P --ldpc_offload.dpdk_dev d8:00.0 Run_T2Test Run nr_ulsim with CPU: SNR = 30, MCS = 25, 273 PRBs, 1 layer + true nr_ulsim 400 - -n100 -s30 -m25 -r273 -R273 -C10 -P + -n100 -s30 -S30.2 -m25 -r273 -R273 -C10 -P Run_T2Test Run nr_ulsim with T2 LDPC offload: SNR = 30, MCS = 25, 273 PRBs, 1 layer + true nr_ulsim 550 - -n100 -s30 -m25 -r273 -R273 -o -P --ldpc_offload.dpdk_dev d8:00.0 + -n100 -s30 -S30.2 -m25 -r273 -R273 -o -P --ldpc_offload.dpdk_dev d8:00.0 Run_T2Test Run nr_ulsim with CPU: SNR = 30, MCS = 5, 273 PRBs, 2 layers + true nr_ulsim 300 - -n100 -s30 -m5 -r273 -R273 -C10 -W2 -z2 -y2 -P + -n100 -s30 -S30.2 -m5 -r273 -R273 -C10 -W2 -z2 -y2 -P Run_T2Test Run nr_ulsim with T2 LDPC offload: SNR = 30, MCS = 5, 273 PRBs, 2 layers + true nr_ulsim 250 - -n100 -s30 -m5 -r273 -R273 -o -W2 -z2 -y2 -P --ldpc_offload.dpdk_dev d8:00.0 + -n100 -s30 -S30.2 -m5 -r273 -R273 -o -W2 -z2 -y2 -P --ldpc_offload.dpdk_dev d8:00.0 Run_T2Test Run nr_ulsim with CPU: SNR = 30, MCS = 15, 273 PRBs, 2 layers + true nr_ulsim 600 - -n100 -s30 -m15 -r273 -R273 -C10 -W2 -z2 -y2 -P + -n100 -s30 -S30.2 -m15 -r273 -R273 -C10 -W2 -z2 -y2 -P Run_T2Test Run nr_ulsim with T2 LDPC offload: SNR = 30, MCS = 15, 273 PRBs, 2 layers + true nr_ulsim 650 - -n100 -s30 -m15 -r273 -R273 -o -W2 -z2 -y2 -P --ldpc_offload.dpdk_dev d8:00.0 + -n100 -s30 -S30.2 -m15 -r273 -R273 -o -W2 -z2 -y2 -P --ldpc_offload.dpdk_dev d8:00.0 Run_T2Test Run nr_ulsim with CPU: SNR = 30, MCS = 25, 273 PRBs, 2 layers + true nr_ulsim 650 - -n100 -s30 -m25 -r273 -R273 -C10 -W2 -z2 -y2 -P + -n100 -s30 -S30.2 -m25 -r273 -R273 -C10 -W2 -z2 -y2 -P Run_T2Test Run nr_ulsim with T2 LDPC offload: SNR = 30, MCS = 25, 273 PRBs, 2 layers + true nr_ulsim 1100 - -n100 -s30 -m25 -r273 -R273 -o -W2 -z2 -y2 -P --ldpc_offload.dpdk_dev d8:00.0 + -n100 -s30 -S30.2 -m25 -r273 -R273 -o -W2 -z2 -y2 -P --ldpc_offload.dpdk_dev d8:00.0 diff --git a/ci-scripts/xml_files/t2_offload_enc_nr_dlsim.xml b/ci-scripts/xml_files/t2_offload_enc_nr_dlsim.xml index 9a9b7b2437..0c09f2722c 100644 --- a/ci-scripts/xml_files/t2_offload_enc_nr_dlsim.xml +++ b/ci-scripts/xml_files/t2_offload_enc_nr_dlsim.xml @@ -33,145 +33,163 @@ Run_T2Test Run nr_dlsim with CPU: SNR = 30, MCS = 5, 106 PRBs, 1 layer + true nr_dlsim 200 - -n100 -s30 -e5 -b106 -R106 -X8 -P + -n100 -s30 -S30.2 -e5 -b106 -R106 -X8 -P Run_T2Test Run nr_dlsim with T2 LDPC offload: SNR = 30, MCS = 5, 106 PRBs, 1 layer + true nr_dlsim 100 - -n100 -s30 -e5 -b106 -R106 -c -P --ldpc_offload.dpdk_dev d8:00.0 + -n100 -s30 -S30.2 -e5 -b106 -R106 -c -P --ldpc_offload.dpdk_dev d8:00.0 Run_T2Test Run nr_dlsim with CPU: SNR = 30, MCS = 15, 106 PRBs, 1 layer + true nr_dlsim 3000 - -n100 -s30 -e15 -b106 -R106 -X8 -P + -n100 -s30 -S30.2 -e15 -b106 -R106 -X8 -P Run_T2Test Run nr_dlsim with T2 LDPC offload: SNR = 30, MCS = 15, 106 PRBs, 1 layer + true nr_dlsim 100 - -n100 -s30 -e15 -b106 -R106 -c -P --ldpc_offload.dpdk_dev d8:00.0 + -n100 -s30 -S30.2 -e15 -b106 -R106 -c -P --ldpc_offload.dpdk_dev d8:00.0 Run_T2Test Run nr_dlsim with CPU: SNR = 30, MCS = 25, 106 PRBs, 1 layer + true nr_dlsim 400 - -n100 -s30 -e25 -b106 -R106 -X8 -P + -n100 -s30 -S30.2 -e25 -b106 -R106 -X8 -P Run_T2Test Run nr_dlsim with T2 LDPC offload: SNR = 30, MCS = 25, 106 PRBs, 1 layer + true nr_dlsim 200 - -n100 -s30 -e25 -b106 -R106 -c -P --ldpc_offload.dpdk_dev d8:00.0 + -n100 -s30 -S30.2 -e25 -b106 -R106 -c -P --ldpc_offload.dpdk_dev d8:00.0 Run_T2Test Run nr_dlsim with CPU: SNR = 30, MCS = 5, 273 PRBs, 1 layer + true nr_dlsim 300 - -n100 -s30 -e5 -b273 -R273 -X8 -P + -n100 -s30 -S30.2 -e5 -b273 -R273 -X8 -P Run_T2Test Run nr_dlsim with T2 LDPC offload: SNR = 30, MCS = 5, 273 PRBs, 1 layer + true nr_dlsim 150 - -n100 -s30 -e5 -b273 -R273 -c -P --ldpc_offload.dpdk_dev d8:00.0 + -n100 -s30 -S30.2 -e5 -b273 -R273 -c -P --ldpc_offload.dpdk_dev d8:00.0 Run_T2Test Run nr_dlsim with CPU: SNR = 30, MCS = 15, 273 PRBs, 1 layer + true nr_dlsim 450 - -n100 -s30 -e15 -b273 -R273 -X8 -P + -n100 -s30 -S30.2 -e15 -b273 -R273 -X8 -P Run_T2Test Run nr_dlsim with T2 LDPC offload: SNR = 30, MCS = 15, 273 PRBs, 1 layer + true nr_dlsim 250 - -n100 -s30 -e15 -b273 -R273 -c -P --ldpc_offload.dpdk_dev d8:00.0 + -n100 -s30 -S30.2 -e15 -b273 -R273 -c -P --ldpc_offload.dpdk_dev d8:00.0 Run_T2Test Run nr_dlsim with CPU: SNR = 30, MCS = 25, 273 PRBs, 1 layer + true nr_dlsim 500 - -n100 -s30 -e25 -b273 -R273 -X8 -P + -n100 -s30 -S30.2 -e25 -b273 -R273 -X8 -P Run_T2Test Run nr_dlsim with T2 LDPC offload: SNR = 30, MCS = 25, 273 PRBs, 1 layer + true nr_dlsim 400 - -n100 -s30 -e25 -b273 -R273 -c -P --ldpc_offload.dpdk_dev d8:00.0 + -n100 -s30 -S30.2 -e25 -b273 -R273 -c -P --ldpc_offload.dpdk_dev d8:00.0 Run_T2Test Run nr_dlsim with CPU: SNR = 30, MCS = 5, 273 PRBs, 2 layers + true nr_dlsim 350 - -n100 -s30 -e5 -b273 -R273 -X8 -x2 -z2 -y2 -P + -n100 -s30 -S30.2 -e5 -b273 -R273 -X8 -x2 -z2 -y2 -P Run_T2Test Run nr_dlsim with T2 LDPC offload: SNR = 30, MCS = 5, 273 PRBs, 2 layers + true nr_dlsim 200 - -n100 -s30 -e5 -b273 -R273 -c -x2 -z2 -y2 -P --ldpc_offload.dpdk_dev d8:00.0 + -n100 -s30 -S30.2 -e5 -b273 -R273 -c -x2 -z2 -y2 -P --ldpc_offload.dpdk_dev d8:00.0 Run_T2Test Run nr_dlsim with CPU: SNR = 30, MCS = 15, 273 PRBs, 2 layers + true nr_dlsim 600 - -n100 -s30 -e15 -b273 -R273 -X8 -x2 -z2 -y2 -P + -n100 -s30 -S30.2 -e15 -b273 -R273 -X8 -x2 -z2 -y2 -P Run_T2Test Run nr_dlsim with T2 LDPC offload: SNR = 30, MCS = 15, 273 PRBs, 2 layers + true nr_dlsim 500 - -n100 -s30 -e15 -b273 -R273 -c -x2 -z2 -y2 -P --ldpc_offload.dpdk_dev d8:00.0 + -n100 -s30 -S30.2 -e15 -b273 -R273 -c -x2 -z2 -y2 -P --ldpc_offload.dpdk_dev d8:00.0 Run_T2Test Run nr_dlsim with CPU: SNR = 30, MCS = 25, 273 PRBs, 2 layers + true nr_dlsim 800 - -n100 -s30 -e25 -b273 -R273 -X8 -x2 -z2 -y2 -P + -n100 -s30 -S30.2 -e25 -b273 -R273 -X8 -x2 -z2 -y2 -P Run_T2Test Run nr_dlsim with T2 LDPC offload: SNR = 30, MCS = 25, 273 PRBs, 2 layers + true nr_dlsim 800 - -n100 -s30 -e25 -b273 -R273 -c -x2 -z2 -y2 -P --ldpc_offload.dpdk_dev d8:00.0 + -n100 -s30 -S30.2 -e25 -b273 -R273 -c -x2 -z2 -y2 -P --ldpc_offload.dpdk_dev d8:00.0 From 61e7c0ae39e7f5d69603ab8151945b9c3e93b00c Mon Sep 17 00:00:00 2001 From: Jaroslava Fiedlerova Date: Wed, 16 Oct 2024 08:43:29 +0200 Subject: [PATCH 04/75] CI: Enable thread-pool in RAN-gNB-N300-Timing-Phytest-LDPC Enable multi-threading in the nr_dlsim test with CPU, set 5 cores for thread-pool using "-X 8,9,10,11,12" option. --- .../xml_files/t2_offload_enc_nr_dlsim.xml | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/ci-scripts/xml_files/t2_offload_enc_nr_dlsim.xml b/ci-scripts/xml_files/t2_offload_enc_nr_dlsim.xml index 0c09f2722c..1e4b7b2e19 100644 --- a/ci-scripts/xml_files/t2_offload_enc_nr_dlsim.xml +++ b/ci-scripts/xml_files/t2_offload_enc_nr_dlsim.xml @@ -35,8 +35,8 @@ Run nr_dlsim with CPU: SNR = 30, MCS = 5, 106 PRBs, 1 layer true nr_dlsim - 200 - -n100 -s30 -S30.2 -e5 -b106 -R106 -X8 -P + 230 + -n100 -s30 -S30.2 -e5 -b106 -R106 -X 8,9,10,11,12 -P @@ -53,8 +53,8 @@ Run nr_dlsim with CPU: SNR = 30, MCS = 15, 106 PRBs, 1 layer true nr_dlsim - 3000 - -n100 -s30 -S30.2 -e15 -b106 -R106 -X8 -P + 300 + -n100 -s30 -S30.2 -e15 -b106 -R106 -X 8,9,10,11,12 -P @@ -71,8 +71,8 @@ Run nr_dlsim with CPU: SNR = 30, MCS = 25, 106 PRBs, 1 layer true nr_dlsim - 400 - -n100 -s30 -S30.2 -e25 -b106 -R106 -X8 -P + 350 + -n100 -s30 -S30.2 -e25 -b106 -R106 -X 8,9,10,11,12 -P @@ -90,7 +90,7 @@ true nr_dlsim 300 - -n100 -s30 -S30.2 -e5 -b273 -R273 -X8 -P + -n100 -s30 -S30.2 -e5 -b273 -R273 -X 8,9,10,11,12 -P @@ -107,8 +107,8 @@ Run nr_dlsim with CPU: SNR = 30, MCS = 15, 273 PRBs, 1 layer true nr_dlsim - 450 - -n100 -s30 -S30.2 -e15 -b273 -R273 -X8 -P + 350 + -n100 -s30 -S30.2 -e15 -b273 -R273 -X 8,9,10,11,12 -P @@ -125,8 +125,8 @@ Run nr_dlsim with CPU: SNR = 30, MCS = 25, 273 PRBs, 1 layer true nr_dlsim - 500 - -n100 -s30 -S30.2 -e25 -b273 -R273 -X8 -P + 400 + -n100 -s30 -S30.2 -e25 -b273 -R273 -X 8,9,10,11,12 -P @@ -143,8 +143,8 @@ Run nr_dlsim with CPU: SNR = 30, MCS = 5, 273 PRBs, 2 layers true nr_dlsim - 350 - -n100 -s30 -S30.2 -e5 -b273 -R273 -X8 -x2 -z2 -y2 -P + 400 + -n100 -s30 -S30.2 -e5 -b273 -R273 -X 8,9,10,11,12 -x2 -z2 -y2 -P @@ -161,8 +161,8 @@ Run nr_dlsim with CPU: SNR = 30, MCS = 15, 273 PRBs, 2 layers true nr_dlsim - 600 - -n100 -s30 -S30.2 -e15 -b273 -R273 -X8 -x2 -z2 -y2 -P + 450 + -n100 -s30 -S30.2 -e15 -b273 -R273 -X 8,9,10,11,12 -x2 -z2 -y2 -P @@ -179,8 +179,8 @@ Run nr_dlsim with CPU: SNR = 30, MCS = 25, 273 PRBs, 2 layers true nr_dlsim - 800 - -n100 -s30 -S30.2 -e25 -b273 -R273 -X8 -x2 -z2 -y2 -P + 500 + -n100 -s30 -S30.2 -e25 -b273 -R273 -X 8,9,10,11,12 -x2 -z2 -y2 -P @@ -188,7 +188,7 @@ Run nr_dlsim with T2 LDPC offload: SNR = 30, MCS = 25, 273 PRBs, 2 layers true nr_dlsim - 800 + 500 -n100 -s30 -S30.2 -e25 -b273 -R273 -c -x2 -z2 -y2 -P --ldpc_offload.dpdk_dev d8:00.0 From 0d4c6b8c4f1b420fa74dd073675e3d89ab421157 Mon Sep 17 00:00:00 2001 From: Jaroslava Fiedlerova Date: Wed, 16 Oct 2024 11:21:15 +0200 Subject: [PATCH 05/75] CI: add new testcases for nr_dlsim testing in timing pipeline Add new nr_dlsim test cases for testing with 4 antennas, 2 layers in both scenarios - with and without T2 card. --- .../xml_files/t2_offload_enc_nr_dlsim.xml | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/ci-scripts/xml_files/t2_offload_enc_nr_dlsim.xml b/ci-scripts/xml_files/t2_offload_enc_nr_dlsim.xml index 1e4b7b2e19..cff66b56a4 100644 --- a/ci-scripts/xml_files/t2_offload_enc_nr_dlsim.xml +++ b/ci-scripts/xml_files/t2_offload_enc_nr_dlsim.xml @@ -27,6 +27,7 @@ 000111 000112 000121 000122 000131 000132 000211 000212 000221 000222 000231 000232 000311 000312 000321 000322 000331 000332 + 000411 000412 000421 000422 000431 000432 @@ -192,4 +193,57 @@ -n100 -s30 -S30.2 -e25 -b273 -R273 -c -x2 -z2 -y2 -P --ldpc_offload.dpdk_dev d8:00.0 + + Run_T2Test + Run nr_dlsim with CPU: SNR = 30, MCS = 5, 273 PRBs, 2 layers, 4 antennas + true + nr_dlsim + 400 + -n100 -s30 -S30.2 -e5 -b273 -R273 -X8,9,10,11,12 -x2 -z4 -y4 -P + + + + Run_T2Test + Run nr_dlsim with T2 LDPC offload: SNR = 30, MCS = 5, 273 PRBs, 2 layers, 4 antennas + true + nr_dlsim + 150 + -n100 -s30 -S30.2 -e5 -b273 -R273 -c -x2 -z4 -y4 -P --ldpc_offload.dpdk_dev d8:00.0 + + + + Run_T2Test + Run nr_dlsim with CPU: SNR = 30, MCS = 20, 273 PRBs, 2 layers, 4 antennas + true + nr_dlsim + 400 + -n100 -s30 -S30.2 -e15 -b273 -R273 -X8,9,10,11,12 -x2 -z4 -y4 -P + + + + Run_T2Test + Run nr_dlsim with T2 LDPC offload: SNR = 30, MCS = 20, 273 PRBs, 2 layers, 4 antennas + true + nr_dlsim + 300 + -n100 -s30 -S30.2 -e15 -b273 -R273 -c -x2 -z4 -y4 -P --ldpc_offload.dpdk_dev d8:00.0 + + + + Run_T2Test + Run nr_dlsim with CPU: SNR = 30, MCS = 27, 273 PRBs, 2 layers, 4 antennas + true + nr_dlsim + 450 + -n100 -s30 -S30.2 -e25 -b273 -R273 -X8,9,10,11,12 -x2 -z4 -y4 -P + + + + Run_T2Test + Run nr_dlsim with T2 LDPC offload: SNR = 30, MCS = 27, 273 PRBs, 2 layers, 4 antennas + true + nr_dlsim + 450 + -n100 -s30 -S30.2 -e25 -b273 -R273 -c -x2 -z4 -y4 -P --ldpc_offload.dpdk_dev d8:00.0 + From 21a7f994c3da5fc0d56454fad97b1067c8c7f624 Mon Sep 17 00:00:00 2001 From: Laurent THOMAS Date: Mon, 12 Aug 2024 15:14:50 +0200 Subject: [PATCH 06/75] process registration reject in UE --- openair3/NAS/NR_UE/nr_nas_msg_sim.c | 10 +++++++--- openair3/NAS/NR_UE/nr_nas_msg_sim.h | 1 + 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/openair3/NAS/NR_UE/nr_nas_msg_sim.c b/openair3/NAS/NR_UE/nr_nas_msg_sim.c index c942e079cd..87953f8b4c 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg_sim.c +++ b/openair3/NAS/NR_UE/nr_nas_msg_sim.c @@ -1449,9 +1449,13 @@ void *nas_nrue(void *args_p) offset++; } } break; - case FGS_PDU_SESSION_ESTABLISHMENT_REJ: - LOG_E(NAS, "Received PDU Session Establishment reject\n"); - break; + case FGS_PDU_SESSION_ESTABLISHMENT_REJ: + LOG_E(NAS, "Received PDU Session Establishment reject\n"); + break; + case REGISTRATION_REJECT: + LOG_E(NAS, "Received Registration reject\n"); + exit(1); + break; default: LOG_W(NR_RRC, "unknown message type %d\n", msg_type); break; diff --git a/openair3/NAS/NR_UE/nr_nas_msg_sim.h b/openair3/NAS/NR_UE/nr_nas_msg_sim.h index c52096107d..bb54660bbd 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg_sim.h +++ b/openair3/NAS/NR_UE/nr_nas_msg_sim.h @@ -52,6 +52,7 @@ #define REGISTRATION_REQUEST 0b01000001 /* 65 = 0x41 */ #define REGISTRATION_ACCEPT 0b01000010 /* 66 = 0x42 */ #define REGISTRATION_COMPLETE 0b01000011 /* 67 = 0x43 */ +#define REGISTRATION_REJECT 68 #define FGS_DEREGISTRATION_REQUEST_UE_ORIGINATING 0b01000101 #define FGS_DEREGISTRATION_ACCEPT 0b01000110 #define FGS_AUTHENTICATION_REQUEST 0b01010110 /* 86 = 0x56 */ From b2b418fc2c0b3565f7a8371b449844c4b5957ad7 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Tue, 22 Oct 2024 17:37:14 +0200 Subject: [PATCH 07/75] fix nr rlc tests in openair2/LAYER2/nr_rlc/tests: ./run_tests.sh was failing. --- openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c b/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c index 480338fd84..8c85075598 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c @@ -28,6 +28,7 @@ #include "LOG/log.h" #include "common/utils/time_stat.h" +#include "common/utils/assertions.h" /* for a given SDU/SDU segment, computes the corresponding PDU header size */ static int compute_pdu_header_size(nr_rlc_entity_am_t *entity, From 5c6d90aaff415f9e928adefce6d418314d070753 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 31 May 2024 12:30:47 +0200 Subject: [PATCH 08/75] Use NR_timer_t for UE transmission interrupt, e.g., RRC processing Refactor the RRC processing timer to be a generic "transmission interrupt" timer, and use NR_timer_t for it. Also, depending on the kind of RRC processing (see 38.331 table 12.1-1), timing requirements might be different. However, the DU does not always know which RRC processing is ongoing, and does not get this information via F1. Hence, introduce a "worst case" delay time, which aligns with the spec (it says these times are "minima") and is accepted by COTS UE. The gNB MAC might need to stop transmission either for some time (RRC processing), or continuously (transmission stop requested by CU). Those can be handled in one common timer implementation. The continuous case will be used in a follow-up commit. Co-authored-by: Luis Pereira --- openair2/LAYER2/NR_MAC_gNB/config.c | 6 +-- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 18 +++---- .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 5 +- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 54 ++++++++++--------- .../LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c | 2 +- .../LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 4 +- .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 2 +- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 4 +- .../LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c | 3 +- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 9 ++-- 10 files changed, 56 insertions(+), 51 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index bfbb5dcfb5..ea4fbed192 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -844,9 +844,9 @@ bool nr_mac_prepare_ra_ue(gNB_MAC_INST *nrmac, uint32_t rnti, NR_CellGroupConfig /* Prepare a new CellGroupConfig to be applied for this UE. We cannot * immediatly apply it, as we have to wait for the reconfiguration through RRC. * This function sets up everything to apply the reconfiguration. Later, we - * will trigger the timer with nr_mac_enable_ue_rrc_processing_timer(); upon - * expiry nr_mac_apply_cellgroup() will apply the CellGroupConfig (radio config - * etc). */ + * will trigger the UE inactivity with nr_mac_interrupt_ue_transmission(); upon + * expiry, nr_mac_apply_cellgroup() will apply the CellGroupConfig (radio + * config etc). */ bool nr_mac_prepare_cellgroup_update(gNB_MAC_INST *nrmac, NR_UE_info_t *UE, NR_CellGroupConfig_t *CellGroup) { DevAssert(nrmac != NULL); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index d6dfa19dd4..1e437aa63e 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -1698,12 +1698,8 @@ static void nr_generate_Msg2(module_id_t module_idP, if (ra->cfra) { NR_UE_info_t *UE = find_nr_UE(&RC.nrmac[module_idP]->UE_info, ra->rnti); if (UE) { - const NR_ServingCellConfig_t *servingCellConfig = UE->CellGroup ? UE->CellGroup->spCellConfig->spCellConfigDedicated : NULL; - uint32_t delay_ms = servingCellConfig && servingCellConfig->downlinkBWP_ToAddModList - ? NR_RRC_SETUP_DELAY_MS + NR_RRC_BWP_SWITCHING_DELAY_MS - : NR_RRC_SETUP_DELAY_MS; - NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - sched_ctrl->rrc_processing_timer = (delay_ms << ra->DL_BWP.scs); + int delay = nr_mac_get_reconfig_delay_slots(ra->DL_BWP.scs); + nr_mac_interrupt_ue_transmission(RC.nrmac[module_idP], UE, FOLLOW_INSYNC, delay); } } @@ -2248,8 +2244,9 @@ static void nr_generate_Msg4_MsgB(module_id_t module_idP, // 3GPP TS 38.331 Section 12 Table 12.1-1: UE performance requirements for RRC procedures for UEs // Msg4 may transmit a RRCReconfiguration, for example when UE sends RRCReestablishmentComplete and MAC CE for C-RNTI in Msg3. // In that case, gNB will generate a RRCReconfiguration that will be transmitted in Msg4, so we need to apply CellGroup after the Ack, - // UE->apply_cellgroup was already set when processing RRCReestablishment message - nr_mac_enable_ue_rrc_processing_timer(nr_mac, UE, UE->apply_cellgroup); + // UE->reconfigCellGroup was already set when processing RRCReestablishment message + int delay = nr_mac_get_reconfig_delay_slots(UE->current_UL_BWP.scs); + nr_mac_interrupt_ue_transmission(nr_mac, UE, UE->interrupt_action, delay); nr_clear_ra_proc(ra); } else { @@ -2291,8 +2288,9 @@ static void nr_check_Msg4_MsgB_Ack(module_id_t module_id, int CC_id, frame_t fra // 3GPP TS 38.331 Section 12 Table 12.1-1: UE performance requirements for RRC procedures for UEs // Msg4 may transmit a RRCReconfiguration, for example when UE sends RRCReestablishmentComplete and MAC CE for C-RNTI in Msg3. // In that case, gNB will generate a RRCReconfiguration that will be transmitted in Msg4, so we need to apply CellGroup after the Ack, - // UE->apply_cellgroup was already set when processing RRCReestablishment message - nr_mac_enable_ue_rrc_processing_timer(RC.nrmac[module_id], UE, UE->apply_cellgroup); + // UE->reconfigCellGroup already set when processing RRCReestablishment message + int delay = nr_mac_get_reconfig_delay_slots(UE->current_UL_BWP.scs); + nr_mac_interrupt_ue_transmission(RC.nrmac[module_id], UE, UE->interrupt_action, delay); nr_clear_ra_proc(ra); if (sched_ctrl->retrans_dl_harq.head >= 0) { diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index af2a2b24e7..ab9be4a271 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -334,9 +334,8 @@ static void nr_store_dlsch_buffer(module_id_t module_id, frame_t frame, sub_fram const int lcid = c->lcid; const uint16_t rnti = UE->rnti; LOG_D(NR_MAC, "In %s: UE %x: LCID %d\n", __FUNCTION__, rnti, lcid); - if (lcid == DL_SCH_LCID_DTCH && sched_ctrl->rrc_processing_timer > 0) { + if (lcid == DL_SCH_LCID_DTCH && nr_timer_is_active(&sched_ctrl->transm_interrupt)) continue; - } start_meas(&RC.nrmac[module_id]->rlc_status_ind); sched_ctrl->rlc_status[lcid] = mac_rlc_status_ind(module_id, rnti, @@ -985,7 +984,7 @@ void nr_schedule_ue_spec(module_id_t module_id, * Possible improvement: take the periodicity from input file. * If such UE is not scheduled now, it will be by the preprocessor later. * If we add the CE, ta_apply will be reset */ - if (frame == (sched_ctrl->ta_frame + 100) % 1024) { + if (frame == ((sched_ctrl->ta_frame + 100) % 1024) && !nr_timer_is_active(&sched_ctrl->transm_interrupt)) { sched_ctrl->ta_apply = true; /* the timer is reset once TA CE is scheduled */ LOG_D(NR_MAC, "[UE %04x][%d.%d] UL timing alignment procedures: setting flag for Timing Advance command\n", UE->rnti, frame, slot); } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 834e42d7a3..d860ec49bd 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -2733,9 +2733,8 @@ void nr_csirs_scheduling(int Mod_idP, frame_t frame, sub_frame_t slot, int n_slo if (UE_info->sched_csirs & (1 << dl_bwp->bwp_id)) continue; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - if (sched_ctrl->rrc_processing_timer > 0) { + if (nr_timer_is_active(&sched_ctrl->transm_interrupt)) continue; - } if (!UE->sc_info.csi_MeasConfig) continue; @@ -2951,15 +2950,15 @@ void nr_csirs_scheduling(int Mod_idP, frame_t frame, sub_frame_t slot, int n_slo static void nr_mac_apply_cellgroup(gNB_MAC_INST *mac, NR_UE_info_t *UE, frame_t frame, sub_frame_t slot) { - LOG_D(NR_MAC, "%4d.%2d RNTI %04x: RRC processing timer expired\n", frame, slot, UE->rnti); + LOG_D(NR_MAC, "%4d.%2d RNTI %04x: UE inactivity timer expired\n", frame, slot, UE->rnti); /* check if there is a new CellGroupConfig to be applied */ - if (UE->apply_cellgroup && UE->reconfigCellGroup != NULL) { - LOG_D(NR_MAC, "%4d.%2d RNTI %04x: Apply CellGroupConfig after RRC processing timer expiry\n", frame, slot, UE->rnti); + if (UE->interrupt_action == FOLLOW_INSYNC_RECONFIG && UE->reconfigCellGroup != NULL) { + LOG_D(NR_MAC, "%4d.%2d RNTI %04x: Apply CellGroupConfig after UE inactivity\n", frame, slot, UE->rnti); ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->CellGroup); UE->CellGroup = UE->reconfigCellGroup; UE->reconfigCellGroup = NULL; - UE->apply_cellgroup = false; + UE->interrupt_action = FOLLOW_INSYNC; if (LOG_DEBUGFLAG(DEBUG_ASN1)) xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void *)UE->CellGroup); @@ -2987,31 +2986,34 @@ static void nr_mac_apply_cellgroup(gNB_MAC_INST *mac, NR_UE_info_t *UE, frame_t } } -int nr_mac_enable_ue_rrc_processing_timer(gNB_MAC_INST *mac, NR_UE_info_t *UE, bool apply_cellgroup) +int nr_mac_get_reconfig_delay_slots(NR_SubcarrierSpacing_t scs) +{ + /* we previously assumed a specific "slot ahead" value for the PHY processing + * time. However, we cannot always know it (e.g., third-party PHY), so simply + * assume a tentative worst-case slot processing time */ + const uint16_t sl_ahead = 10; + /* 16ms seems to be the most common: See 38.331 Tab 12.1-1 */ + int delay_ms = NR_RRC_RECONFIGURATION_DELAY_MS + NR_RRC_BWP_SWITCHING_DELAY_MS; + 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) { DevAssert(mac != NULL); DevAssert(UE != NULL); NR_SCHED_ENSURE_LOCKED(&mac->sched_lock); - const uint16_t sl_ahead = mac->if_inst->sl_ahead; - // TODO: account for BWP switch with NR_RRC_BWP_SWITCHING_DELAY_MS - int delay = NR_RRC_RECONFIGURATION_DELAY_MS; - NR_SubcarrierSpacing_t scs = UE->current_UL_BWP.scs; + nr_timer_setup(&UE->UE_sched_ctrl.transm_interrupt, slots, 1); + nr_timer_start(&UE->UE_sched_ctrl.transm_interrupt); + UE->interrupt_action = action; - UE->UE_sched_ctrl.rrc_processing_timer = (delay << scs) + sl_ahead; - UE->apply_cellgroup = apply_cellgroup; - AssertFatal(!UE->apply_cellgroup || (UE->apply_cellgroup && UE->reconfigCellGroup), - "logic bug: apply_cellgroup %d and UE->reconfigCellGroup %p: did you try to apply a cellGroup, while none is deposited?\n", - UE->apply_cellgroup, - UE->reconfigCellGroup); - - // it might happen that timing advance command should be sent during the RRC - // processing timer. To prevent this, set a variable as if we would have just + // 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 // sent it. This way, another TA command will for sure be sent in some - // frames, after RRC processing timer. + // frames, after the inactivity of the UE. UE->UE_sched_ctrl.ta_frame = (mac->frame - 1 + 1024) % 1024; - LOG_D(NR_MAC, "UE %04x: Activate RRC processing timer (%d ms)\n", UE->rnti, delay); + LOG_D(NR_MAC, "UE %04x: Interrupt UE transmission (%d slots) action %d reconfigCellGroup %p\n", UE->rnti, slots, UE->interrupt_action, UE->reconfigCellGroup); return 0; } @@ -3073,10 +3075,10 @@ void nr_mac_update_timers(module_id_t module_id, /* check if UL failure and trigger release request if necessary */ nr_mac_check_ul_failure(mac, UE->rnti, sched_ctrl); - if (sched_ctrl->rrc_processing_timer > 0) { - sched_ctrl->rrc_processing_timer--; - if (sched_ctrl->rrc_processing_timer == 0) - nr_mac_apply_cellgroup(mac, UE, frame, slot); + if (nr_timer_tick(&sched_ctrl->transm_interrupt)) { + /* expired */ + nr_timer_stop(&sched_ctrl->transm_interrupt); + nr_mac_apply_cellgroup(mac, UE, frame, slot); } } } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c index 5045d6cbe8..945e078e37 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c @@ -533,7 +533,7 @@ void nr_schedule_srs(int module_id, frame_t frame, int slot) sched_ctrl->sched_srs.srs_scheduled = false; } - if ((sched_ctrl->ul_failure && !get_softmodem_params()->phy_test) || sched_ctrl->rrc_processing_timer > 0) { + if ((sched_ctrl->ul_failure && !get_softmodem_params()->phy_test) || nr_timer_is_active(&sched_ctrl->transm_interrupt)) { continue; } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index facef09b52..ee573e89a1 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -223,7 +223,7 @@ void nr_csi_meas_reporting(int Mod_idP, NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP; const int n_slots_frame = nr_slots_per_frame[ul_bwp->scs]; - if ((sched_ctrl->rrc_processing_timer > 0) || (sched_ctrl->ul_failure && !get_softmodem_params()->phy_test)) { + if (nr_timer_is_active(&sched_ctrl->transm_interrupt) || (sched_ctrl->ul_failure && !get_softmodem_params()->phy_test)) { continue; } const NR_CSI_MeasConfig_t *csi_measconfig = UE->sc_info.csi_MeasConfig; @@ -1389,7 +1389,7 @@ void nr_sr_reporting(gNB_MAC_INST *nrmac, frame_t SFN, sub_frame_t slot) NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP; const int n_slots_frame = nr_slots_per_frame[ul_bwp->scs]; - if (sched_ctrl->ul_failure || sched_ctrl->rrc_processing_timer > 0) + if (sched_ctrl->ul_failure || nr_timer_is_active(&sched_ctrl->transm_interrupt)) continue; NR_PUCCH_Config_t *pucch_Config = ul_bwp->pucch_Config; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 4599349a04..de0ca18ad5 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -1856,7 +1856,7 @@ static void pf_ul(module_id_t module_id, const bool do_sched = nr_UE_is_to_be_scheduled(scc, 0, UE, sched_pusch->frame, sched_pusch->slot, nrmac->ulsch_max_frame_inactivity); LOG_D(NR_MAC,"pf_ul: do_sched UE %04x => %s\n",UE->rnti,do_sched ? "yes" : "no"); - if ((B == 0 && !do_sched) || (sched_ctrl->rrc_processing_timer > 0)) { + if ((B == 0 && !do_sched) || nr_timer_is_active(&sched_ctrl->transm_interrupt)) { continue; } diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index da3b612561..e63bbd8f99 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -53,8 +53,10 @@ void nr_mac_configure_sib19(gNB_MAC_INST *nrmac); bool nr_mac_add_test_ue(gNB_MAC_INST *nrmac, uint32_t rnti, NR_CellGroupConfig_t *CellGroup); bool nr_mac_prepare_ra_ue(gNB_MAC_INST *nrmac, uint32_t rnti, NR_CellGroupConfig_t *CellGroup); +int nr_mac_get_reconfig_delay_slots(NR_SubcarrierSpacing_t scs); + bool nr_mac_prepare_cellgroup_update(gNB_MAC_INST *nrmac, NR_UE_info_t *UE, NR_CellGroupConfig_t *CellGroup); -int nr_mac_enable_ue_rrc_processing_timer(gNB_MAC_INST *mac, NR_UE_info_t *UE, bool apply_cellGroup); +int nr_mac_interrupt_ue_transmission(gNB_MAC_INST *mac, NR_UE_info_t *UE, interrupt_followup_action_t action, int slots); void clear_nr_nfapi_information(gNB_MAC_INST *gNB, int CC_idP, diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c index 407e5869ce..33c0d5e33e 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -728,7 +728,8 @@ void dl_rrc_message_transfer(const f1ap_dl_rrc_message_t *dl_rrc) * the CellGroupConfig. Below, we trigger a timer, and the CellGroupConfig * will be applied after its expiry in nr_mac_apply_cellgroup().*/ NR_SCHED_LOCK(&mac->sched_lock); - nr_mac_enable_ue_rrc_processing_timer(mac, UE, /* apply_cellGroup = */ true); + int delay = nr_mac_get_reconfig_delay_slots(UE->current_UL_BWP.scs); + nr_mac_interrupt_ue_transmission(mac, UE, FOLLOW_INSYNC_RECONFIG, delay); NR_SCHED_UNLOCK(&mac->sched_lock); UE->expect_reconfiguration = false; /* Re-establish RLC for all remaining bearers */ diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index aa07e8f474..8d97ddc607 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -43,6 +43,7 @@ #include #include #include "common/utils/ds/seq_arr.h" +#include "common/utils/nr/nr_common.h" #define NR_SCHED_LOCK(lock) \ do { \ @@ -664,8 +665,8 @@ typedef struct { NR_list_t retrans_ul_harq; NR_UE_mac_ce_ctrl_t UE_mac_ce_ctrl; // MAC CE related information - /// Timer for RRC processing procedures - uint32_t rrc_processing_timer; + /// Timer for RRC processing procedures and transmission activity + NR_timer_t transm_interrupt; /// sri, ul_ri and tpmi based on SRS nr_srs_feedback_t srs_feedback; @@ -738,6 +739,8 @@ typedef struct nr_mac_rrc_ul_if_s { initial_ul_rrc_message_transfer_func_t initial_ul_rrc_message_transfer; } nr_mac_rrc_ul_if_t; +typedef enum interrupt_followup_action { FOLLOW_INSYNC, FOLLOW_INSYNC_RECONFIG } interrupt_followup_action_t; + /*! \brief UE list used by gNB to order UEs/CC for scheduling*/ typedef struct { rnti_t rnti; @@ -756,7 +759,7 @@ typedef struct { /// reestablishRLC has to be signaled in RRCreconfiguration bool reestablish_rlc; NR_CellGroupConfig_t *reconfigCellGroup; - bool apply_cellgroup; + interrupt_followup_action_t interrupt_action; NR_UE_NR_Capability_t *capability; // UE selected beam index uint8_t UE_beam_index; From d70561d509dd7c838222ab1c13225ac50f5b7930 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 17 May 2024 17:57:47 +0200 Subject: [PATCH 09/75] Implement F1 UE Ctxt HandoverPrepInfo in F1 Implement the HandoverPreparationInformation F1AP forwarding logic, and add it to the F1 internal representation structure. No logic is implemented in this commit. Co-authored-by: batuhanduyuler Co-authored-by: rmagueta --- openair2/COMMON/f1ap_messages_types.h | 2 ++ openair2/F1AP/f1ap_cu_ue_context_management.c | 15 ++++++++++ openair2/F1AP/f1ap_du_ue_context_management.c | 30 ++++++++++++++++--- openair2/RRC/NR/mac_rrc_dl_f1ap.c | 9 +++++- 4 files changed, 51 insertions(+), 5 deletions(-) diff --git a/openair2/COMMON/f1ap_messages_types.h b/openair2/COMMON/f1ap_messages_types.h index f159e63ca3..f357fae2d8 100644 --- a/openair2/COMMON/f1ap_messages_types.h +++ b/openair2/COMMON/f1ap_messages_types.h @@ -442,6 +442,8 @@ typedef struct cu_to_du_rrc_information_s { uint32_t uE_CapabilityRAT_ContainerList_length; uint8_t * measConfig; uint32_t measConfig_length; + uint8_t *handoverPreparationInfo; + uint32_t handoverPreparationInfo_length; }cu_to_du_rrc_information_t; typedef struct du_to_cu_rrc_information_s { diff --git a/openair2/F1AP/f1ap_cu_ue_context_management.c b/openair2/F1AP/f1ap_cu_ue_context_management.c index 65c34a10c1..ca6c939a3a 100644 --- a/openair2/F1AP/f1ap_cu_ue_context_management.c +++ b/openair2/F1AP/f1ap_cu_ue_context_management.c @@ -276,6 +276,21 @@ int CU_send_UE_CONTEXT_SETUP_REQUEST(sctp_assoc_t assoc_id, f1ap_ue_context_setu OCTET_STRING_fromBuf(measConfig, (const char*)f1ap_ue_context_setup_req->cu_to_du_rrc_information->measConfig, f1ap_ue_context_setup_req->cu_to_du_rrc_information->measConfig_length); } + + /* optional */ + /* HandoverPreparationInformation */ + if (f1ap_ue_context_setup_req->cu_to_du_rrc_information->handoverPreparationInfo_length > 0) { + DevAssert(f1ap_ue_context_setup_req->cu_to_du_rrc_information->handoverPreparationInfo != NULL); + F1AP_ProtocolExtensionContainer_10696P60_t *p = calloc(1, sizeof(*p)); + ie6->value.choice.CUtoDURRCInformation.iE_Extensions = (struct F1AP_ProtocolExtensionContainer *)p; + asn1cSequenceAdd(p->list, F1AP_CUtoDURRCInformation_ExtIEs_t, ie_ext); + ie_ext->id = F1AP_ProtocolIE_ID_id_HandoverPreparationInformation; + ie_ext->criticality = F1AP_Criticality_ignore; + ie_ext->extensionValue.present = F1AP_CUtoDURRCInformation_ExtIEs__extensionValue_PR_HandoverPreparationInformation; + OCTET_STRING_fromBuf(&ie_ext->extensionValue.choice.HandoverPreparationInformation, + (const char *)f1ap_ue_context_setup_req->cu_to_du_rrc_information->handoverPreparationInfo, + f1ap_ue_context_setup_req->cu_to_du_rrc_information->handoverPreparationInfo_length); + } } /* optional */ diff --git a/openair2/F1AP/f1ap_du_ue_context_management.c b/openair2/F1AP/f1ap_du_ue_context_management.c index ad728d5c89..8844e79baf 100644 --- a/openair2/F1AP/f1ap_du_ue_context_management.c +++ b/openair2/F1AP/f1ap_du_ue_context_management.c @@ -171,12 +171,34 @@ int DU_handle_UE_CONTEXT_SETUP_REQUEST(instance_t instance, sctp_assoc_t assoc_i F1AP_ProtocolIE_ID_id_CUtoDURRCInformation, false); if(ieCuRrcInfo!=NULL){ f1ap_ue_context_setup_req->cu_to_du_rrc_information = (cu_to_du_rrc_information_t *)calloc(1,sizeof(cu_to_du_rrc_information_t)); - if(ieCuRrcInfo->value.choice.CUtoDURRCInformation.uE_CapabilityRAT_ContainerList!=NULL){ - f1ap_ue_context_setup_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList = (uint8_t *)calloc(1,ieCuRrcInfo->value.choice.CUtoDURRCInformation.uE_CapabilityRAT_ContainerList->size); - memcpy(f1ap_ue_context_setup_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList, ieCuRrcInfo->value.choice.CUtoDURRCInformation.uE_CapabilityRAT_ContainerList->buf, ieCuRrcInfo->value.choice.CUtoDURRCInformation.uE_CapabilityRAT_ContainerList->size); - f1ap_ue_context_setup_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList_length = ieCuRrcInfo->value.choice.CUtoDURRCInformation.uE_CapabilityRAT_ContainerList->size; + cu_to_du_rrc_information_t *cu2du = f1ap_ue_context_setup_req->cu_to_du_rrc_information; + const F1AP_CUtoDURRCInformation_t *cu2duie = &ieCuRrcInfo->value.choice.CUtoDURRCInformation; + if(cu2duie->uE_CapabilityRAT_ContainerList!=NULL){ + cu2du->uE_CapabilityRAT_ContainerList = calloc(1, cu2duie->uE_CapabilityRAT_ContainerList->size); + memcpy(cu2du->uE_CapabilityRAT_ContainerList, + cu2duie->uE_CapabilityRAT_ContainerList->buf, + cu2duie->uE_CapabilityRAT_ContainerList->size); + cu2du->uE_CapabilityRAT_ContainerList_length = cu2duie->uE_CapabilityRAT_ContainerList->size; LOG_D(F1AP, "Size f1ap_ue_context_setup_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList_length: %d \n", f1ap_ue_context_setup_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList_length); } + if (cu2duie->iE_Extensions != NULL) { + const F1AP_ProtocolExtensionContainer_10696P60_t *ext = (const F1AP_ProtocolExtensionContainer_10696P60_t *)cu2duie->iE_Extensions; + for (int i = 0; i < ext->list.count; ++i) { + const F1AP_CUtoDURRCInformation_ExtIEs_t *cu2du_info = ext->list.array[i]; + switch (cu2du_info->id) { + case F1AP_ProtocolIE_ID_id_HandoverPreparationInformation: + DevAssert(cu2du_info->extensionValue.present == F1AP_CUtoDURRCInformation_ExtIEs__extensionValue_PR_HandoverPreparationInformation); + const F1AP_HandoverPreparationInformation_t *hopi = &cu2du_info->extensionValue.choice.MeasurementTimingConfiguration; + cu2du->handoverPreparationInfo = calloc_or_fail(1, hopi->size); + memcpy(cu2du->handoverPreparationInfo, hopi->buf, hopi->size); + cu2du->handoverPreparationInfo_length = hopi->size; + break; + default: + LOG_W(F1AP, "unsupported CUtoDURRCInformation_ExtIE %ld encountered, ignoring\n", cu2du_info->id); + break; + } + } + } } /* DRB */ diff --git a/openair2/RRC/NR/mac_rrc_dl_f1ap.c b/openair2/RRC/NR/mac_rrc_dl_f1ap.c index e2e094d866..a802e7ab4d 100644 --- a/openair2/RRC/NR/mac_rrc_dl_f1ap.c +++ b/openair2/RRC/NR/mac_rrc_dl_f1ap.c @@ -79,8 +79,8 @@ static void ue_context_setup_request_f1ap(sctp_assoc_t assoc_id, const f1ap_ue_c AssertFatal(f1ap_msg->cu_to_du_rrc_information != NULL, "out of memory\n"); AssertFatal(req->cu_to_du_rrc_information->cG_ConfigInfo == NULL && req->cu_to_du_rrc_information->cG_ConfigInfo_length == 0, "cg_ConfigInfo not implemented\n"); AssertFatal(req->cu_to_du_rrc_information->measConfig == NULL && req->cu_to_du_rrc_information->measConfig_length == 0, "cg_ConfigInfo not implemented\n"); + const cu_to_du_rrc_information_t *du2cu_req = req->cu_to_du_rrc_information; if (req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList != NULL) { - const cu_to_du_rrc_information_t *du2cu_req = req->cu_to_du_rrc_information; cu_to_du_rrc_information_t* du2cu_new = f1ap_msg->cu_to_du_rrc_information; DevAssert(du2cu_req->uE_CapabilityRAT_ContainerList_length > 0); du2cu_new->uE_CapabilityRAT_ContainerList_length = du2cu_req->uE_CapabilityRAT_ContainerList_length; @@ -88,6 +88,13 @@ static void ue_context_setup_request_f1ap(sctp_assoc_t assoc_id, const f1ap_ue_c AssertFatal(du2cu_new->uE_CapabilityRAT_ContainerList != NULL, "out of memory\n"); memcpy(du2cu_new->uE_CapabilityRAT_ContainerList, du2cu_req->uE_CapabilityRAT_ContainerList, du2cu_new->uE_CapabilityRAT_ContainerList_length); } + if (req->cu_to_du_rrc_information->handoverPreparationInfo != NULL) { + cu_to_du_rrc_information_t *du2cu_new = f1ap_msg->cu_to_du_rrc_information; + DevAssert(du2cu_req->handoverPreparationInfo_length > 0); + du2cu_new->handoverPreparationInfo_length = du2cu_req->handoverPreparationInfo_length; + du2cu_new->handoverPreparationInfo = malloc_or_fail(du2cu_new->handoverPreparationInfo_length); + memcpy(du2cu_new->handoverPreparationInfo, du2cu_req->handoverPreparationInfo, du2cu_new->handoverPreparationInfo_length); + } } if (req->drbs_to_be_setup_length > 0) { int n = req->drbs_to_be_setup_length; From 004403c84d57e8c0efb253e267b63a39b2cead63 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 23 May 2024 18:00:15 +0200 Subject: [PATCH 10/75] Implement F1 UE Ctxt Modif Transmission Action Indicator Implement the Transmission Action Indicator F1AP forwarding logic, and add it to the F1 internal representation structure. After the transmission interrupt timer (during which SRB1 can send messages), the UE will be out-of-sync (we assume it's not there anymore). Co-authored-by: batuhanduyuler Co-authored-by: rmagueta --- openair2/COMMON/f1ap_messages_types.h | 6 ++++++ openair2/F1AP/f1ap_cu_ue_context_management.c | 7 +++++-- openair2/F1AP/f1ap_du_ue_context_management.c | 15 +++++++++++++++ .../LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c | 13 ++++++++++++- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 1 + openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c | 5 +++++ openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 2 +- openair2/RRC/NR/mac_rrc_dl_f1ap.c | 5 +++++ 8 files changed, 50 insertions(+), 4 deletions(-) diff --git a/openair2/COMMON/f1ap_messages_types.h b/openair2/COMMON/f1ap_messages_types.h index f357fae2d8..569f3857c0 100644 --- a/openair2/COMMON/f1ap_messages_types.h +++ b/openair2/COMMON/f1ap_messages_types.h @@ -466,6 +466,11 @@ typedef enum ReconfigurationCompl_e { RRCreconf_success = 2, } ReconfigurationCompl_t; +typedef enum TransmActionInd_e { + TransmActionInd_STOP, + TransmActionInd_RESTART, +} TransmActionInd_t; + typedef struct f1ap_ue_context_setup_s { uint32_t gNB_CU_ue_id; uint32_t gNB_DU_ue_id; @@ -496,6 +501,7 @@ typedef struct f1ap_ue_context_setup_s { ReconfigurationCompl_t ReconfigComplOutcome; uint8_t *rrc_container; int rrc_container_length; + TransmActionInd_t *transm_action_ind; } f1ap_ue_context_setup_t, f1ap_ue_context_modif_req_t, f1ap_ue_context_modif_resp_t; typedef enum F1ap_Cause_e { diff --git a/openair2/F1AP/f1ap_cu_ue_context_management.c b/openair2/F1AP/f1ap_cu_ue_context_management.c index ca6c939a3a..924c9ecfca 100644 --- a/openair2/F1AP/f1ap_cu_ue_context_management.c +++ b/openair2/F1AP/f1ap_cu_ue_context_management.c @@ -1023,12 +1023,15 @@ int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(sctp_assoc_t assoc_id, f1ap_ue_conte /* optional */ /* c7. TransmissionActionIndicator */ - if (0) { + if (f1ap_ue_context_modification_req->transm_action_ind != NULL) { asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie7); ie7->id = F1AP_ProtocolIE_ID_id_TransmissionActionIndicator; ie7->criticality = F1AP_Criticality_ignore; ie7->value.present = F1AP_UEContextModificationRequestIEs__value_PR_TransmissionActionIndicator; - ie7->value.choice.TransmissionActionIndicator = F1AP_TransmissionActionIndicator_stop; + ie7->value.choice.TransmissionActionIndicator = *f1ap_ue_context_modification_req->transm_action_ind; + // Stop is guaranteed to be 0, by restart might be different from 1 + static_assert((int)F1AP_TransmissionActionIndicator_restart == (int)TransmActionInd_RESTART, + "mismatch of ASN.1 and internal representation\n"); } /* optional */ diff --git a/openair2/F1AP/f1ap_du_ue_context_management.c b/openair2/F1AP/f1ap_du_ue_context_management.c index 8844e79baf..18a04962ad 100644 --- a/openair2/F1AP/f1ap_du_ue_context_management.c +++ b/openair2/F1AP/f1ap_du_ue_context_management.c @@ -911,6 +911,21 @@ int DU_handle_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance, sctp_assoc_t F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextModificationRequestIEs_t, ieSrb, container, F1AP_ProtocolIE_ID_id_SRBs_ToBeSetupMod_List, false); + F1AP_UEContextModificationRequestIEs_t *ieTxInd; + F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextModificationRequestIEs_t, + ieTxInd, + container, + F1AP_ProtocolIE_ID_id_TransmissionActionIndicator, + false); + + if (ieTxInd != NULL) { + f1ap_ue_context_modification_req->transm_action_ind = calloc_or_fail(1, sizeof(*f1ap_ue_context_modification_req->transm_action_ind)); + *f1ap_ue_context_modification_req->transm_action_ind = ieTxInd->value.choice.TransmissionActionIndicator; + // Stop is guaranteed to be 0, by restart might be different from 1 + static_assert((int)F1AP_TransmissionActionIndicator_restart == (int)TransmActionInd_RESTART, + "mismatch of ASN.1 and internal representation\n"); + } + if(ieSrb != NULL) { f1ap_ue_context_modification_req->srbs_to_be_setup_length = ieSrb->value.choice.SRBs_ToBeSetupMod_List.list.count; f1ap_ue_context_modification_req->srbs_to_be_setup = calloc(f1ap_ue_context_modification_req->srbs_to_be_setup_length, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index d860ec49bd..5ae2eb8607 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -3017,6 +3017,14 @@ int nr_mac_interrupt_ue_transmission(gNB_MAC_INST *mac, NR_UE_info_t *UE, interr return 0; } +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); + LOG_I(NR_MAC, "gNB-DU received the TransmissionActionIndicator with Stop value for UE %04x\n", UE_info->rnti); + return 0; +} + void nr_mac_trigger_release_complete(gNB_MAC_INST *mac, int rnti) { // the CU might not know such UE, e.g., because we never sent a message to @@ -3078,7 +3086,10 @@ void nr_mac_update_timers(module_id_t module_id, if (nr_timer_tick(&sched_ctrl->transm_interrupt)) { /* expired */ nr_timer_stop(&sched_ctrl->transm_interrupt); - nr_mac_apply_cellgroup(mac, UE, frame, slot); + if (UE->interrupt_action == FOLLOW_OUTOFSYNC) + nr_mac_trigger_ul_failure(sched_ctrl, UE->current_DL_BWP.scs); + else + nr_mac_apply_cellgroup(mac, UE, frame, slot); } } } diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index e63bbd8f99..4ee100f812 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -57,6 +57,7 @@ int nr_mac_get_reconfig_delay_slots(NR_SubcarrierSpacing_t scs); bool nr_mac_prepare_cellgroup_update(gNB_MAC_INST *nrmac, NR_UE_info_t *UE, NR_CellGroupConfig_t *CellGroup); int nr_mac_interrupt_ue_transmission(gNB_MAC_INST *mac, NR_UE_info_t *UE, interrupt_followup_action_t action, 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, int CC_idP, diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c index 33c0d5e33e..a69ab2732e 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -588,6 +588,11 @@ void ue_context_modification_request(const f1ap_ue_context_modif_req_t *req) } else { ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, new_CellGroup); // we actually don't need it } + + if (req->transm_action_ind != NULL) { + AssertFatal(*req->transm_action_ind == TransmActionInd_STOP, "Transmission Action Indicator restart not handled yet\n"); + nr_transmission_action_indicator_stop(mac, UE); + } NR_SCHED_UNLOCK(&mac->sched_lock); /* some sanity checks, since we use the same type for request and response */ diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 8d97ddc607..e0cf53c5a0 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -739,7 +739,7 @@ typedef struct nr_mac_rrc_ul_if_s { initial_ul_rrc_message_transfer_func_t initial_ul_rrc_message_transfer; } nr_mac_rrc_ul_if_t; -typedef enum interrupt_followup_action { FOLLOW_INSYNC, FOLLOW_INSYNC_RECONFIG } interrupt_followup_action_t; +typedef enum interrupt_followup_action { FOLLOW_INSYNC, FOLLOW_INSYNC_RECONFIG, FOLLOW_OUTOFSYNC } interrupt_followup_action_t; /*! \brief UE list used by gNB to order UEs/CC for scheduling*/ typedef struct { diff --git a/openair2/RRC/NR/mac_rrc_dl_f1ap.c b/openair2/RRC/NR/mac_rrc_dl_f1ap.c index a802e7ab4d..70d36a144f 100644 --- a/openair2/RRC/NR/mac_rrc_dl_f1ap.c +++ b/openair2/RRC/NR/mac_rrc_dl_f1ap.c @@ -168,6 +168,11 @@ static void ue_context_modification_request_f1ap(sctp_assoc_t assoc_id, const f1 f1ap_msg->rrc_container_length = req->rrc_container_length; memcpy(f1ap_msg->rrc_container, req->rrc_container, req->rrc_container_length); } + if (req->transm_action_ind != NULL) { + f1ap_msg->transm_action_ind = malloc(sizeof *f1ap_msg->transm_action_ind); + AssertFatal(f1ap_msg->transm_action_ind != NULL, "out of memory\n"); + *f1ap_msg->transm_action_ind = *req->transm_action_ind; + } itti_send_msg_to_task(TASK_CU_F1, 0, msg); } From c854b9cebb4f380f4b0b4c139eeaa264ab51d18b Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 23 May 2024 18:53:57 +0200 Subject: [PATCH 11/75] get_UE_waiting_CFRA_msg3(): check that RA process is for given RNTI Co-authored-by: batuhanduyuler --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index de0ca18ad5..5dc88739a5 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -561,12 +561,16 @@ static void abort_nr_ul_harq(NR_UE_info_t *UE, int8_t harq_pid) sched_ctrl->sched_ul_bytes = 0; } -static bool get_UE_waiting_CFRA_msg3(const gNB_MAC_INST *gNB_mac, const int CC_id, const frame_t frame, const sub_frame_t slot) +static bool get_UE_waiting_CFRA_msg3(const gNB_MAC_INST *gNB_mac, + const int CC_id, + const frame_t frame, + const sub_frame_t slot, + rnti_t rnti) { bool UE_waiting_CFRA_msg3 = false; for (int i = 0; i < NR_NB_RA_PROC_MAX; i++) { const NR_RA_t *ra = &gNB_mac->common_channels[CC_id].ra[i]; - if (ra->cfra == true && ra->ra_state == nrRA_WAIT_Msg3 && frame == ra->Msg3_frame && slot == ra->Msg3_slot) { + if (ra->cfra && ra->ra_state == nrRA_WAIT_Msg3 && frame == ra->Msg3_frame && slot == ra->Msg3_slot && rnti == ra->rnti) { UE_waiting_CFRA_msg3 = true; break; } @@ -584,7 +588,7 @@ void handle_nr_ul_harq(const int CC_idP, NR_SCHED_LOCK(&nrmac->sched_lock); NR_UE_info_t *UE = find_nr_UE(&nrmac->UE_info, crc_pdu->rnti); - bool UE_waiting_CFRA_msg3 = get_UE_waiting_CFRA_msg3(nrmac, CC_idP, frame, slot); + bool UE_waiting_CFRA_msg3 = get_UE_waiting_CFRA_msg3(nrmac, CC_idP, frame, slot, crc_pdu->rnti); if (!UE || UE_waiting_CFRA_msg3 == true) { LOG_D(NR_MAC, "handle harq for rnti %04x, in RA process\n", crc_pdu->rnti); @@ -700,7 +704,7 @@ static void _nr_rx_sdu(const module_id_t gnb_mod_idP, const int pusch_failure_thres = gNB_mac->pusch_failure_thres; NR_UE_info_t *UE = find_nr_UE(&gNB_mac->UE_info, current_rnti); - bool UE_waiting_CFRA_msg3 = get_UE_waiting_CFRA_msg3(gNB_mac, CC_idP, frameP, slotP); + bool UE_waiting_CFRA_msg3 = get_UE_waiting_CFRA_msg3(gNB_mac, CC_idP, frameP, slotP, current_rnti); if (UE && UE_waiting_CFRA_msg3 == false) { From fef589cf88848dadd72fbb88ce896ec7d4143bc9 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 23 May 2024 19:23:08 +0200 Subject: [PATCH 12/75] Refactor reconfigurationWithSync ASN.1 to separate function Will be reused later for handover. Co-authored-by: batuhanduyuler --- openair2/RRC/NR/nr_rrc_config.c | 82 +++++++++++++++++---------------- openair2/RRC/NR/nr_rrc_config.h | 2 + 2 files changed, 44 insertions(+), 40 deletions(-) diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index 201a0e84d4..dab37f6f1a 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -3293,46 +3293,8 @@ NR_CellGroupConfig_t *get_default_secondaryCellGroup(const NR_ServingCellConfigC secondaryCellGroup->spCellConfig->reconfigurationWithSync = calloc(1, sizeof(*secondaryCellGroup->spCellConfig->reconfigurationWithSync)); - NR_ReconfigurationWithSync_t *reconfigurationWithSync = secondaryCellGroup->spCellConfig->reconfigurationWithSync; - reconfigurationWithSync->spCellConfigCommon = clone_ServingCellConfigCommon(servingcellconfigcommon); - reconfigurationWithSync->newUE_Identity = - (get_softmodem_params()->phy_test == 1) ? 0x1234 : (taus() & 0xffff); - reconfigurationWithSync->t304 = NR_ReconfigurationWithSync__t304_ms2000; - reconfigurationWithSync->rach_ConfigDedicated = NULL; - reconfigurationWithSync->ext1 = NULL; - - // For 2-step contention-free random access procedure - reconfigurationWithSync->rach_ConfigDedicated = calloc(1, sizeof(*reconfigurationWithSync->rach_ConfigDedicated)); - reconfigurationWithSync->rach_ConfigDedicated->present = NR_ReconfigurationWithSync__rach_ConfigDedicated_PR_uplink; - reconfigurationWithSync->rach_ConfigDedicated->choice.uplink = calloc(1, sizeof(struct NR_RACH_ConfigDedicated)); - reconfigurationWithSync->rach_ConfigDedicated->choice.uplink->cfra = calloc(1, sizeof(struct NR_CFRA)); - reconfigurationWithSync->rach_ConfigDedicated->choice.uplink->ra_Prioritization = NULL; - reconfigurationWithSync->rach_ConfigDedicated->choice.uplink->cfra->occasions = calloc(1, sizeof(struct NR_CFRA__occasions)); - memcpy(&reconfigurationWithSync->rach_ConfigDedicated->choice.uplink->cfra->occasions->rach_ConfigGeneric, - &servingcellconfigcommon->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric, - sizeof(NR_RACH_ConfigGeneric_t)); - asn1cCallocOne(reconfigurationWithSync->rach_ConfigDedicated->choice.uplink->cfra->occasions->ssb_perRACH_Occasion, - NR_CFRA__occasions__ssb_perRACH_Occasion_one); - reconfigurationWithSync->rach_ConfigDedicated->choice.uplink->cfra->resources.present = NR_CFRA__resources_PR_ssb; - reconfigurationWithSync->rach_ConfigDedicated->choice.uplink->cfra->resources.choice.ssb = - calloc(1, sizeof(struct NR_CFRA__resources__ssb)); - reconfigurationWithSync->rach_ConfigDedicated->choice.uplink->cfra->resources.choice.ssb->ra_ssb_OccasionMaskIndex = 0; - - int n_ssb = 0; - struct NR_CFRA_SSB_Resource *ssbElem[64]; - for (int i = 0; i < 64; i++) { - if ((bitmap >> (63 - i)) & 0x01) { - ssbElem[n_ssb] = calloc(1, sizeof(struct NR_CFRA_SSB_Resource)); - ssbElem[n_ssb]->ssb = i; - ssbElem[n_ssb]->ra_PreambleIndex = 63 - (uid % 64); - asn1cSeqAdd(&secondaryCellGroup->spCellConfig->reconfigurationWithSync->rach_ConfigDedicated->choice.uplink->cfra->resources - .choice.ssb->ssb_ResourceList.list, - ssbElem[n_ssb]); - n_ssb++; - } - } - - secondaryCellGroup->spCellConfig->reconfigurationWithSync->rach_ConfigDedicated->choice.uplink->cfra->ext1 = NULL; + rnti_t rnti = get_softmodem_params()->phy_test == 1 ? 0x1234 : (taus() & 0xffff); + secondaryCellGroup->spCellConfig->reconfigurationWithSync = get_reconfiguration_with_sync(rnti, uid, servingcellconfigcommon); secondaryCellGroup->spCellConfig->rlf_TimersAndConstants = calloc(1, sizeof(*secondaryCellGroup->spCellConfig->rlf_TimersAndConstants)); @@ -3602,3 +3564,43 @@ NR_CellGroupConfig_t *get_default_secondaryCellGroup(const NR_ServingCellConfigC } return secondaryCellGroup; } + +NR_ReconfigurationWithSync_t *get_reconfiguration_with_sync(rnti_t rnti, uid_t uid, const NR_ServingCellConfigCommon_t *scc) +{ + NR_ReconfigurationWithSync_t *reconfigurationWithSync = calloc(1, sizeof(*reconfigurationWithSync)); + reconfigurationWithSync->newUE_Identity = rnti; + reconfigurationWithSync->t304 = NR_ReconfigurationWithSync__t304_ms2000; + reconfigurationWithSync->rach_ConfigDedicated = NULL; + reconfigurationWithSync->ext1 = NULL; + + reconfigurationWithSync->spCellConfigCommon = clone_ServingCellConfigCommon(scc); + + reconfigurationWithSync->rach_ConfigDedicated = calloc(1, sizeof(*reconfigurationWithSync->rach_ConfigDedicated)); + reconfigurationWithSync->rach_ConfigDedicated->present = NR_ReconfigurationWithSync__rach_ConfigDedicated_PR_uplink; + NR_RACH_ConfigDedicated_t *uplink = calloc(1, sizeof(*uplink)); + reconfigurationWithSync->rach_ConfigDedicated->choice.uplink = uplink; + uplink->ra_Prioritization = NULL; + uplink->cfra = calloc(1, sizeof(struct NR_CFRA)); + uplink->cfra->ext1 = NULL; + uplink->cfra->occasions = calloc(1, sizeof(struct NR_CFRA__occasions)); + memcpy(&uplink->cfra->occasions->rach_ConfigGeneric, + &scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric, + sizeof(NR_RACH_ConfigGeneric_t)); + asn1cCallocOne(uplink->cfra->occasions->ssb_perRACH_Occasion, NR_CFRA__occasions__ssb_perRACH_Occasion_one); + uplink->cfra->resources.present = NR_CFRA__resources_PR_ssb; + uplink->cfra->resources.choice.ssb = calloc(1, sizeof(struct NR_CFRA__resources__ssb)); + uplink->cfra->resources.choice.ssb->ra_ssb_OccasionMaskIndex = 0; + + uint64_t bitmap = get_ssb_bitmap(scc); + for (int i = 0; i < 64; i++) { + if (((bitmap >> (63 - i)) & 0x01) == 0) + continue; + + NR_CFRA_SSB_Resource_t *ssbElem = calloc(1, sizeof(*ssbElem)); + ssbElem->ssb = i; + ssbElem->ra_PreambleIndex = 63 - (uid % 64); + asn1cSeqAdd(&uplink->cfra->resources.choice.ssb->ssb_ResourceList.list, ssbElem); + } + + return reconfigurationWithSync; +} diff --git a/openair2/RRC/NR/nr_rrc_config.h b/openair2/RRC/NR/nr_rrc_config.h index 87640834e5..ff94f2ab7e 100644 --- a/openair2/RRC/NR/nr_rrc_config.h +++ b/openair2/RRC/NR/nr_rrc_config.h @@ -102,4 +102,6 @@ NR_CellGroupConfig_t *get_default_secondaryCellGroup(const NR_ServingCellConfigC const nr_mac_config_t *configuration, int uid); +NR_ReconfigurationWithSync_t *get_reconfiguration_with_sync(rnti_t rnti, uid_t uid, const NR_ServingCellConfigCommon_t *scc); + #endif From 5c2b72565416c70d2d52b7fcaf58abb117d04e27 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 24 May 2024 14:43:57 +0200 Subject: [PATCH 13/75] Refactor new-RNTI functionality in separate function This function will be used in the case of a handover for getting a new RNTI (checking that we do not reuse an already used RNTI). --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 27 +++---------------- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 25 +++++++++++++++++ openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 2 ++ 3 files changed, 30 insertions(+), 24 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index 1e437aa63e..061ad1ba27 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -40,7 +40,6 @@ #include "common/utils/LOG/vcd_signal_dumper.h" #include "common/utils/nr/nr_common.h" #include "UTIL/OPT/opt.h" -#include "SIMULATION/TOOLS/sim.h" // for taus /* rlc */ #include "openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h" @@ -677,16 +676,6 @@ static NR_RA_t *find_free_nr_RA(NR_RA_t *ra_base, int ra_count, uint16_t preambl return NULL; } -static const NR_RA_t *find_nr_RA_rnti(const NR_RA_t *ra_base, int ra_count, rnti_t rnti) -{ - for (int i = 0; i < ra_count; ++i) { - const NR_RA_t *ra = &ra_base[i]; - if (ra->ra_state != nrRA_gNB_IDLE && ra->rnti == rnti) - return ra; - } - return NULL; -} - void nr_initiate_ra_proc(module_id_t module_idP, int CC_id, frame_t frameP, @@ -712,23 +701,13 @@ void nr_initiate_ra_proc(module_id_t module_idP, } if (ra->rnti == 0) { // This condition allows for the usage of a preconfigured rnti for the CFRA - int loop = 0; - bool exist_connected_ue, exist_in_pending_ra_ue; - rnti_t trial = 0; - do { - // 3GPP TS 38.321 version 15.13.0 Section 7.1 Table 7.1-1: RNTI values - while (trial < 1 || trial > 0xffef) - trial = (taus() % 0xffef) + 1; - exist_connected_ue = find_nr_UE(&nr_mac->UE_info, trial) != NULL; - exist_in_pending_ra_ue = find_nr_RA_rnti(cc->ra, sizeofArray(cc->ra), ra->rnti) != NULL; - loop++; - } while (loop < 100 && (exist_connected_ue || exist_in_pending_ra_ue) ); - if (loop == 100) { + bool rnti_found = nr_mac_get_new_rnti(&nr_mac->UE_info, cc->ra, sizeofArray(cc->ra), &ra->rnti); + if (!rnti_found) { LOG_E(NR_MAC, "initialisation random access: no more available RNTIs for new UE\n"); + nr_clear_ra_proc(ra); NR_SCHED_UNLOCK(&nr_mac->sched_lock); return; } - ra->rnti = trial; } ra->preamble_frame = frameP; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 5ae2eb8607..b091cf69ee 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -53,6 +53,8 @@ #include "uper_encoder.h" #include "uper_decoder.h" +#include "SIMULATION/TOOLS/sim.h" // for taus + #define ENABLE_MAC_PAYLOAD_DEBUG #define DEBUG_gNB_SCHEDULER 1 @@ -3395,3 +3397,26 @@ bool nr_mac_remove_lcid(NR_UE_sched_ctrl_t *sched_ctrl, long lcid) seq_arr_erase(&sched_ctrl->lc_config, elm.it); return true; } + +static const NR_RA_t *find_nr_RA_rnti(const NR_RA_t *ra_base, int ra_count, rnti_t rnti) +{ + for (int i = 0; i < ra_count; ++i) { + const NR_RA_t *ra = &ra_base[i]; + if (ra->ra_state != nrRA_gNB_IDLE && ra->rnti == rnti) + return ra; + } + return NULL; +} + +bool nr_mac_get_new_rnti(NR_UEs_t *UEs, const NR_RA_t *ra_base, int ra_count, rnti_t *rnti) +{ + int loop = 0; + bool exist_connected_ue, exist_in_pending_ra_ue; + do { + *rnti = (taus() % 0xffef) + 1; + exist_connected_ue = find_nr_UE(UEs, *rnti) != NULL; + exist_in_pending_ra_ue = find_nr_RA_rnti(ra_base, ra_count, *rnti) != NULL; + loop++; + } while (loop < 100 && (exist_connected_ue || exist_in_pending_ra_ue)); + return loop < 100; // nothing found: loop count 100 +} diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 4ee100f812..a75b9c0f60 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -477,4 +477,6 @@ void process_addmod_bearers_cellGroupConfig(NR_UE_sched_ctrl_t *sched_ctrl, bool nr_mac_add_lcid(NR_UE_sched_ctrl_t *sched_ctrl, const nr_lc_config_t *c); bool nr_mac_remove_lcid(NR_UE_sched_ctrl_t *sched_ctrl, long lcid); +bool nr_mac_get_new_rnti(NR_UEs_t *UEs, const NR_RA_t *ra_base, int ra_count, rnti_t *rnti); + #endif /*__LAYER2_NR_MAC_PROTO_H__*/ From a927db9ef68802fe1a6a316f876ff5501b7fd966 Mon Sep 17 00:00:00 2001 From: rmagueta Date: Mon, 13 May 2024 17:25:14 +0100 Subject: [PATCH 14/75] Add c-rnti to UE context setup response No logic changes in this commit; to be used for the handover case later. Co-authored-by: rmagueta --- openair2/COMMON/f1ap_messages_types.h | 1 + openair2/F1AP/f1ap_cu_ue_context_management.c | 6 ++++++ openair2/F1AP/f1ap_du_ue_context_management.c | 7 ++----- openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c | 4 ++++ 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/openair2/COMMON/f1ap_messages_types.h b/openair2/COMMON/f1ap_messages_types.h index 569f3857c0..36c3ad4f76 100644 --- a/openair2/COMMON/f1ap_messages_types.h +++ b/openair2/COMMON/f1ap_messages_types.h @@ -485,6 +485,7 @@ typedef struct f1ap_ue_context_setup_s { //uint8_t *du_to_cu_rrc_information; du_to_cu_rrc_information_t *du_to_cu_rrc_information; uint32_t du_to_cu_rrc_information_length; + uint16_t *crnti; f1ap_drb_to_be_setup_t *drbs_to_be_setup; uint8_t drbs_to_be_setup_length; f1ap_drb_to_be_setup_t *drbs_to_be_modified; diff --git a/openair2/F1AP/f1ap_cu_ue_context_management.c b/openair2/F1AP/f1ap_cu_ue_context_management.c index 924c9ecfca..f72ac3c588 100644 --- a/openair2/F1AP/f1ap_cu_ue_context_management.c +++ b/openair2/F1AP/f1ap_cu_ue_context_management.c @@ -622,6 +622,12 @@ int CU_handle_UE_CONTEXT_SETUP_RESPONSE(instance_t instance, sctp_assoc_t assoc_ F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, true); f1ap_ue_context_setup_resp->gNB_DU_ue_id = ie->value.choice.GNB_DU_UE_F1AP_ID; LOG_D(F1AP, "f1ap_ue_context_setup_resp->gNB_DU_ue_id is: %d \n", f1ap_ue_context_setup_resp->gNB_DU_ue_id); + F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextSetupResponseIEs_t, ie, container, F1AP_ProtocolIE_ID_id_C_RNTI, false); + if (ie) { + f1ap_ue_context_setup_resp->crnti = calloc(1, sizeof(uint16_t)); + *f1ap_ue_context_setup_resp->crnti = ie->value.choice.C_RNTI; + } + // DUtoCURRCInformation F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextSetupResponseIEs_t, ie, container, F1AP_ProtocolIE_ID_id_DUtoCURRCInformation, true); diff --git a/openair2/F1AP/f1ap_du_ue_context_management.c b/openair2/F1AP/f1ap_du_ue_context_management.c index 18a04962ad..d92da99d06 100644 --- a/openair2/F1AP/f1ap_du_ue_context_management.c +++ b/openair2/F1AP/f1ap_du_ue_context_management.c @@ -375,15 +375,12 @@ int DU_send_UE_CONTEXT_SETUP_RESPONSE(sctp_assoc_t assoc_id, f1ap_ue_context_set /* optional */ /* c4. C_RNTI */ - if (0) { + if (resp->crnti!=NULL) { asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupResponseIEs_t, ie4); ie4->id = F1AP_ProtocolIE_ID_id_C_RNTI; ie4->criticality = F1AP_Criticality_ignore; ie4->value.present = F1AP_UEContextSetupResponseIEs__value_PR_C_RNTI; - //C_RNTI_TO_BIT_STRING(rntiP, &ie->value.choice.C_RNTI); - ie4->value.choice.C_RNTI=0; - AssertFatal(false, "not implemented\n"); - LOG_E(F1AP,"RNTI to code!\n"); + ie4->value.choice.C_RNTI = *resp->crnti; } /* optional */ diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c index 2af81d0cfd..6d8f7a7115 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c @@ -112,6 +112,10 @@ static void ue_context_setup_response_f1ap(const f1ap_ue_context_setup_t *req, c for (int i = 0; i < f1ap_msg->drbs_to_be_setup_length; ++i) f1ap_msg->drbs_to_be_setup[i] = resp->drbs_to_be_setup[i]; } + if (resp->crnti) { + f1ap_msg->crnti = calloc(1, sizeof(uint16_t)); + *f1ap_msg->crnti = *resp->crnti; + } f1ap_msg->du_to_cu_rrc_information = malloc(sizeof(*resp->du_to_cu_rrc_information)); AssertFatal(f1ap_msg->du_to_cu_rrc_information != NULL, "out of memory\n"); From c4a9bd1718c376172b10941b95c259eca00e247e Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 11 Jun 2024 06:41:01 +0200 Subject: [PATCH 15/75] Refactor reading of NR cap from capability list The next commit will modify the UE context setup request procedure to (possibly) receive UE capabilities through Handover Preparation Information, which extracts the UE capabilities for the UE to be setup. To avoid code duplication, extract the code that will be needed in UE capability extraction from Handover Preparation Information. --- .../LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c | 50 +++++++++++-------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c index a69ab2732e..a6193580de 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -375,6 +375,33 @@ static int handle_ue_context_drbs_release(NR_UE_info_t *UE, return drbs_len; } +static NR_UE_NR_Capability_t *get_nr_cap(const NR_UE_CapabilityRAT_ContainerList_t *clist) +{ + for (int i = 0; i < clist->list.count; i++) { + const NR_UE_CapabilityRAT_Container_t *c = clist->list.array[i]; + if (c->rat_Type != NR_RAT_Type_nr) { + LOG_W(NR_MAC, "ignoring capability of type %ld\n", c->rat_Type); + continue; + } + + NR_UE_NR_Capability_t *cap = NULL; + asn_dec_rval_t dec_rval = uper_decode(NULL, + &asn_DEF_NR_UE_NR_Capability, + (void **)&cap, + c->ue_CapabilityRAT_Container.buf, + c->ue_CapabilityRAT_Container.size, + 0, + 0); + if (dec_rval.code != RC_OK) { + LOG_W(NR_MAC, "cannot decode NR UE capability, ignoring\n"); + ASN_STRUCT_FREE(asn_DEF_NR_UE_NR_Capability, cap); + continue; + } + return cap; + } + return NULL; +} + static NR_UE_NR_Capability_t *get_ue_nr_cap(int rnti, uint8_t *buf, uint32_t len) { if (buf == NULL || len == 0) @@ -387,27 +414,8 @@ static NR_UE_NR_Capability_t *get_ue_nr_cap(int rnti, uint8_t *buf, uint32_t len return NULL; } - NR_UE_NR_Capability_t *cap = NULL; - for (int i = 0; i < clist->list.count; i++) { - const NR_UE_CapabilityRAT_Container_t *c = clist->list.array[i]; - if (cap != NULL || c->rat_Type != NR_RAT_Type_nr) { - LOG_W(NR_MAC, "UE RNTI %04x: ignoring capability of type %ld\n", rnti, c->rat_Type); - continue; - } - - asn_dec_rval_t dec_rval = uper_decode(NULL, - &asn_DEF_NR_UE_NR_Capability, - (void **)&cap, - c->ue_CapabilityRAT_Container.buf, - c->ue_CapabilityRAT_Container.size, - 0, - 0); - if (dec_rval.code != RC_OK) { - LOG_W(NR_MAC, "cannot decode NR UE capabilities of UE RNTI %04x, ignoring NR capability\n", rnti); - cap = NULL; - continue; - } - } + NR_UE_NR_Capability_t *cap = get_nr_cap(clist); + ASN_STRUCT_FREE(asn_DEF_NR_UE_CapabilityRAT_ContainerList, clist); return cap; } From e7b56b3d088e867d46f9b8e14f2282220167fe3a Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 4 Jun 2024 14:27:44 +0200 Subject: [PATCH 16/75] UE context setup req: gNB_DU_ue_id optional, use 0xffffffff to signal --- openair2/F1AP/f1ap_du_ue_context_management.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/openair2/F1AP/f1ap_du_ue_context_management.c b/openair2/F1AP/f1ap_du_ue_context_management.c index d92da99d06..98de177af1 100644 --- a/openair2/F1AP/f1ap_du_ue_context_management.c +++ b/openair2/F1AP/f1ap_du_ue_context_management.c @@ -133,8 +133,13 @@ int DU_handle_UE_CONTEXT_SETUP_REQUEST(instance_t instance, sctp_assoc_t assoc_i /* GNB_DU_UE_F1AP_ID */ F1AP_UEContextSetupRequestIEs_t *ieDU_UE; F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextSetupRequestIEs_t, ieDU_UE, container, - F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, true); - f1ap_ue_context_setup_req->gNB_DU_ue_id = ieDU_UE->value.choice.GNB_DU_UE_F1AP_ID; + F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, false); + // this should be optional. At present, the DU uses the RNTI, and hence, this + // value cannot exceed 0xffff (or something below, whatever is a valid + // C-RNTI). So we use a value > 0xffff to mark optionality + f1ap_ue_context_setup_req->gNB_DU_ue_id = -1; // 0xffffffff + if (ieDU_UE != NULL) + f1ap_ue_context_setup_req->gNB_DU_ue_id = ieDU_UE->value.choice.GNB_DU_UE_F1AP_ID; /* SpCell_ID */ F1AP_UEContextSetupRequestIEs_t *ieNet; From 0b2757b36acdb68d120c81eaa20213ed94279dc8 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 24 May 2024 20:01:53 +0200 Subject: [PATCH 17/75] Implement handler for F1 UE context Setup in HO case This commit implements adding a new UE on the target DU in case of handover. We identify this case by the fact that the gNB-CU did not send a gNB-DU UE ID (which is optional in F1AP, but not in our implementation), such that we know there is no corresponding UE, which therefore has to be created. If it happens that there is a handover preparation information, we read the UE capabilities from this information, and subsequently trigger the creation of a new UE. Another change is that for all bearers that we are asked to setup, we add reestablishRLC so that the UE does a reestablishment during the reconfiguration. As we have to remove the reconfigurationWithSync and reestablishRLC IE after application of the CellGroupConfig (because we might reuse the CellGroupConfig later), free these IEs. As there are now multiple fields to free, introduce a separate nr_mac_clean_cellgroup() function that handles cleaning of the CellGroupConfig. Co-authored-by: batuhanduyuler Co-authored-by: rmagueta --- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 27 +++-- .../LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c | 101 ++++++++++++++++-- 2 files changed, 114 insertions(+), 14 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index b091cf69ee..0b09bb78a9 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -2950,6 +2950,25 @@ void nr_csirs_scheduling(int Mod_idP, frame_t frame, sub_frame_t slot, int n_slo } } +static void nr_mac_clean_cellgroup(NR_CellGroupConfig_t *cell_group) +{ + /* remove a reconfigurationWithSync, we don't need it anymore */ + if (cell_group->spCellConfig->reconfigurationWithSync != NULL) { + ASN_STRUCT_FREE(asn_DEF_NR_ReconfigurationWithSync, cell_group->spCellConfig->reconfigurationWithSync); + cell_group->spCellConfig->reconfigurationWithSync = NULL; + } + /* remove the rlc_BearerToReleaseList, we don't need it anymore */ + if (cell_group->rlc_BearerToReleaseList != NULL) { + struct NR_CellGroupConfig__rlc_BearerToReleaseList *l = cell_group->rlc_BearerToReleaseList; + asn_sequence_del(&l->list, l->list.count, /* free */ 1); + free(cell_group->rlc_BearerToReleaseList); + cell_group->rlc_BearerToReleaseList = NULL; + } + /* remove reestablishRLC, we don't need it anymore */ + for (int i = 0; i < cell_group->rlc_BearerToAddModList->list.count; ++i) + free_and_zero(cell_group->rlc_BearerToAddModList->list.array[i]->reestablishRLC); +} + static void nr_mac_apply_cellgroup(gNB_MAC_INST *mac, NR_UE_info_t *UE, frame_t frame, sub_frame_t slot) { LOG_D(NR_MAC, "%4d.%2d RNTI %04x: UE inactivity timer expired\n", frame, slot, UE->rnti); @@ -2965,13 +2984,7 @@ static void nr_mac_apply_cellgroup(gNB_MAC_INST *mac, NR_UE_info_t *UE, frame_t if (LOG_DEBUGFLAG(DEBUG_ASN1)) xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void *)UE->CellGroup); - /* remove the rlc_BearerToReleaseList, we don't need it anymore */ - if (UE->CellGroup->rlc_BearerToReleaseList != NULL) { - struct NR_CellGroupConfig__rlc_BearerToReleaseList *l = UE->CellGroup->rlc_BearerToReleaseList; - asn_sequence_del(&l->list, l->list.count, /* free */1); - free(UE->CellGroup->rlc_BearerToReleaseList); - UE->CellGroup->rlc_BearerToReleaseList = NULL; - } + nr_mac_clean_cellgroup(UE->CellGroup); } NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon; diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c index a6193580de..4089b224d1 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -26,6 +26,7 @@ #include "openair2/F1AP/f1ap_common.h" #include "openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h" #include "F1AP_CauseRadioNetwork.h" +#include "NR_HandoverPreparationInformation.h" #include "openair3/ocp-gtpu/gtp_itf.h" #include "openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h" #include "lib/f1ap_interface_management.h" @@ -419,6 +420,35 @@ static NR_UE_NR_Capability_t *get_ue_nr_cap(int rnti, uint8_t *buf, uint32_t len return cap; } +/* \brief return UE capabilties from HandoverPreparationInformation. + * + * The HandoverPreparationInformation contains more, but for the moment, let's + * keep it simple and only handle that. The function asserts if other IEs are + * present. */ +static NR_UE_NR_Capability_t *get_ue_nr_cap_from_ho_prep_info(uint8_t *buf, uint32_t len) +{ + if (buf == NULL || len == 0) + return NULL; + NR_HandoverPreparationInformation_t *hpi = NULL; + asn_dec_rval_t dec_rval = uper_decode_complete(NULL, &asn_DEF_NR_HandoverPreparationInformation, (void **)&hpi, buf, len); + if (dec_rval.code != RC_OK) { + LOG_W(NR_MAC, "cannot decode HandoverPreparationInformation, ignoring capabilities\n"); + return NULL; + } + NR_UE_NR_Capability_t *cap = NULL; + if (hpi->criticalExtensions.present != NR_HandoverPreparationInformation__criticalExtensions_PR_c1 + || hpi->criticalExtensions.choice.c1 == NULL + || hpi->criticalExtensions.choice.c1->present + != NR_HandoverPreparationInformation__criticalExtensions__c1_PR_handoverPreparationInformation + || hpi->criticalExtensions.choice.c1->choice.handoverPreparationInformation == NULL) { + } else { + const NR_HandoverPreparationInformation_IEs_t *hpi_ie = hpi->criticalExtensions.choice.c1->choice.handoverPreparationInformation; + cap = get_nr_cap(&hpi_ie->ue_CapabilityRAT_List); + } + ASN_STRUCT_FREE(asn_DEF_NR_HandoverPreparationInformation, hpi); + return cap; +} + NR_CellGroupConfig_t *clone_CellGroupConfig(const NR_CellGroupConfig_t *orig) { uint8_t buf[16636]; @@ -431,6 +461,40 @@ NR_CellGroupConfig_t *clone_CellGroupConfig(const NR_CellGroupConfig_t *orig) return cloned; } +static NR_UE_info_t *create_new_UE(gNB_MAC_INST *mac, uint32_t cu_id) +{ + int CC_id = 0; + const NR_COMMON_channels_t *cc = &mac->common_channels[CC_id]; + rnti_t rnti; + bool found = nr_mac_get_new_rnti(&mac->UE_info, cc->ra, sizeofArray(cc->ra), &rnti); + if (!found) + return NULL; + + NR_UE_info_t* UE = add_new_nr_ue(mac, rnti, NULL); + if (!UE) + return NULL; + + f1_ue_data_t new_ue_data = {.secondary_ue = cu_id}; + du_add_f1_ue_data(rnti, &new_ue_data); + + const NR_ServingCellConfigCommon_t *scc = mac->common_channels[CC_id].ServingCellConfigCommon; + const NR_ServingCellConfig_t *sccd = mac->common_channels[CC_id].pre_ServingCellConfig; + NR_CellGroupConfig_t *cellGroupConfig = get_initial_cellGroupConfig(UE->uid, scc, sccd, &mac->radio_config); + cellGroupConfig->spCellConfig->reconfigurationWithSync = get_reconfiguration_with_sync(UE->rnti, UE->uid, scc); + // note: we don't pass the cellGroupConfig to add_new_nr_ue() because we need + // the uid to create the CellGroupConfig (which is in the UE context created + // by add_new_nr_ue(); it's a kind of chicken-and-egg problem), so below we + // complete the UE context with the information that add_new_nr_ue() would + // have added + UE->Msg4_MsgB_ACKed = true; + UE->CellGroup = cellGroupConfig; + + nr_rlc_activate_srb0(UE->rnti, UE, NULL); + nr_mac_prepare_ra_ue(mac, rnti, UE->CellGroup); + /* SRB1 is added to RLC and MAC in the handler later */ + return UE; +} + void ue_context_setup_request(const f1ap_ue_context_setup_t *req) { gNB_MAC_INST *mac = RC.nrmac[0]; @@ -440,19 +504,34 @@ void ue_context_setup_request(const f1ap_ue_context_setup_t *req) .gNB_DU_ue_id = req->gNB_DU_ue_id, }; + /* gNB-DU UE ID is optional. As of now, the F1AP module fills -1 (on uint, so + * 0xffffffff), but the DU uses the RNTI, so check if it's a legal RNTI in + * which case we consider; if not, assume no DU UE ID given */ + bool ue_id_provided = resp.gNB_DU_ue_id > 0 && resp.gNB_DU_ue_id < 0xffff; + NR_UE_NR_Capability_t *ue_cap = NULL; if (req->cu_to_du_rrc_information != NULL) { - AssertFatal(req->cu_to_du_rrc_information->cG_ConfigInfo == NULL, "CG-ConfigInfo not handled\n"); - ue_cap = get_ue_nr_cap(req->gNB_DU_ue_id, - req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList, - req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList_length); - AssertFatal(req->cu_to_du_rrc_information->measConfig == NULL, "MeasConfig not handled\n"); + const cu_to_du_rrc_information_t *cu2du = req->cu_to_du_rrc_information; + AssertFatal(cu2du->cG_ConfigInfo == NULL, "CG-ConfigInfo not handled\n"); + if (cu2du->handoverPreparationInfo != NULL) { + ue_cap = get_ue_nr_cap_from_ho_prep_info(cu2du->handoverPreparationInfo, cu2du->handoverPreparationInfo_length); + } else if (cu2du->uE_CapabilityRAT_ContainerList != NULL) { + ue_cap = get_ue_nr_cap(req->gNB_DU_ue_id, cu2du->uE_CapabilityRAT_ContainerList, cu2du->uE_CapabilityRAT_ContainerList_length); + } + AssertFatal(cu2du->measConfig == NULL, "MeasConfig not handled\n"); } NR_SCHED_LOCK(&mac->sched_lock); - NR_UE_info_t *UE = find_nr_UE(&RC.nrmac[0]->UE_info, req->gNB_DU_ue_id); - AssertFatal(UE, "did not find UE with RNTI %04x, but UE Context Setup Failed not implemented\n", req->gNB_DU_ue_id); + NR_UE_info_t *UE = NULL; + if (!ue_id_provided) { + UE = create_new_UE(mac, req->gNB_CU_ue_id); + resp.gNB_DU_ue_id = UE->rnti; + resp.crnti = &UE->rnti; + } else { + UE = find_nr_UE(&mac->UE_info, req->gNB_DU_ue_id); + } + AssertFatal(UE, "no UE found or could not be created, but UE Context Setup Failed not implemented\n"); NR_CellGroupConfig_t *new_CellGroup = clone_CellGroupConfig(UE->CellGroup); @@ -484,6 +563,14 @@ void ue_context_setup_request(const f1ap_ue_context_setup_t *req) update_cellGroupConfig(new_CellGroup, UE->uid, UE->capability, &mac->radio_config, scc); } + if (!ue_id_provided) { + /* new UE: tell the UE to reestablish RLC */ + struct NR_CellGroupConfig__rlc_BearerToAddModList *addmod = new_CellGroup->rlc_BearerToAddModList; + for (int i = 0; i < addmod->list.count; ++i) { + asn1cCallocOne(addmod->list.array[i]->reestablishRLC, NR_RLC_BearerConfig__reestablishRLC_true); + } + } + resp.du_to_cu_rrc_information = calloc(1, sizeof(du_to_cu_rrc_information_t)); AssertFatal(resp.du_to_cu_rrc_information != NULL, "out of memory\n"); resp.du_to_cu_rrc_information->cellGroupConfig = calloc(1,1024); From dadd05e0eb023e68a6ed74ec7dd4de5a10d0b6cf Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 2 Aug 2024 16:48:22 +0200 Subject: [PATCH 18/75] Skip adding of second LCID1 Our initial CellGroupConfig always contains LCID1, because in normal connection setup, the DU has to automatically set it up anyway. In handover/UE Context Setup, the CU requests to set up SRB1 (which we assume to be LCID1), but we reuse the initial CellGroupConfig. To not have SRB1 added twice, skip in this case. --- openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c index 4089b224d1..e7ff5c4574 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -238,8 +238,16 @@ static int handle_ue_context_srbs_setup(NR_UE_info_t *UE, (*resp_srbs)[i].srb_id = srb->srb_id; (*resp_srbs)[i].lcid = c.lcid; - int ret = ASN_SEQUENCE_ADD(&cellGroupConfig->rlc_BearerToAddModList->list, rlc_BearerConfig); - DevAssert(ret == 0); + if (rlc_BearerConfig->logicalChannelIdentity == 1) { + // CU asks to add SRB1: when creating a cellGroupConfig, we always add it + // (see get_initial_cellGroupConfig()) + const struct NR_CellGroupConfig__rlc_BearerToAddModList *addmod = cellGroupConfig->rlc_BearerToAddModList; + DevAssert(addmod->list.count >= 1 && addmod->list.array[0]->logicalChannelIdentity == 1); + ASN_STRUCT_FREE(asn_DEF_NR_RLC_BearerConfig, rlc_BearerConfig); + } else { + int ret = ASN_SEQUENCE_ADD(&cellGroupConfig->rlc_BearerToAddModList->list, rlc_BearerConfig); + DevAssert(ret == 0); + } } return srbs_len; } From 1783932e37fd7961210c7e513a762bba21ecc002 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 7 Aug 2024 09:44:42 +0200 Subject: [PATCH 19/75] Msg2: Apply CellGroupConfig if necessary After RA, in the case of HO, we need to make sure to use the right radio configuration (MCS table, etc). This commit is important to make HO actually work. --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index 061ad1ba27..e43123b55c 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -1678,7 +1678,8 @@ static void nr_generate_Msg2(module_id_t module_idP, NR_UE_info_t *UE = find_nr_UE(&RC.nrmac[module_idP]->UE_info, ra->rnti); if (UE) { int delay = nr_mac_get_reconfig_delay_slots(ra->DL_BWP.scs); - nr_mac_interrupt_ue_transmission(RC.nrmac[module_idP], UE, FOLLOW_INSYNC, delay); + interrupt_followup_action_t action = UE->reconfigCellGroup ? FOLLOW_INSYNC_RECONFIG : FOLLOW_INSYNC; + nr_mac_interrupt_ue_transmission(RC.nrmac[module_idP], UE, action, delay); } } From 5378c4d8d960ab39cf42211a672e285b8ad1ab32 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 4 Jun 2024 10:40:10 +0200 Subject: [PATCH 20/75] Refactor RRC Reconfiguration function Refactor the RRC reconfiguration function to reuse it also later for sending the reconfiguration including the handover trigger. --- openair2/RRC/NR/rrc_gNB.c | 101 +++++++++++++++++++++----------------- 1 file changed, 57 insertions(+), 44 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 5ab7c0ba12..9803991db5 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -481,6 +481,60 @@ static void rrc_gNB_process_RRCSetupComplete(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE rrc_gNB_send_NGAP_NAS_FIRST_REQ(rrc, UE, rrcSetupComplete); } +static int rrc_gNB_encode_RRCReconfiguration(gNB_RRC_INST *rrc, + gNB_RRC_UE_t *UE, + uint8_t xid, + struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList *nas_messages, + uint8_t *buf, + int max_len, + bool reestablish) +{ + NR_CellGroupConfig_t *cellGroupConfig = UE->masterCellGroup; + nr_rrc_du_container_t *du = get_du_for_ue(rrc, UE->rrc_ue_id); + DevAssert(du != NULL); + f1ap_served_cell_info_t *cell_info = &du->setup_req->cell[0].info; + NR_MeasConfig_t *measconfig = NULL; + if (du->mtc != NULL) { + int scs = get_ssb_scs(cell_info); + int band = get_dl_band(cell_info); + const NR_MeasTimingList_t *mtlist = du->mtc->criticalExtensions.choice.c1->choice.measTimingConf->measTiming; + const NR_MeasTiming_t *mt = mtlist->list.array[0]; + const neighbour_cell_configuration_t *neighbour_config = get_neighbour_config(cell_info->nr_cellid); + seq_arr_t *neighbour_cells = NULL; + if (neighbour_config) + neighbour_cells = neighbour_config->neighbour_cells; + + measconfig = get_MeasConfig(mt, band, scs, &rrc->measurementConfiguration, neighbour_cells); + } + + if (UE->measConfig) + free_MeasConfig(UE->measConfig); + + UE->measConfig = measconfig; + + NR_SRB_ToAddModList_t *SRBs = createSRBlist(UE, reestablish); + NR_DRB_ToAddModList_t *DRBs = createDRBlist(UE, reestablish); + + int size = do_RRCReconfiguration(UE, + buf, + max_len, + xid, + SRBs, + DRBs, + UE->DRB_ReleaseList, + NULL, + measconfig, + nas_messages, + cellGroupConfig); + LOG_DUMPMSG(NR_RRC, DEBUG_RRC, (char *)buf, size, "[MSG] RRC Reconfiguration\n"); + freeSRBlist(SRBs); + freeDRBlist(DRBs); + ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToReleaseList, UE->DRB_ReleaseList); + UE->DRB_ReleaseList = NULL; + + return size; +} + static void rrc_gNB_generate_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p) { uint8_t xid = rrc_gNB_get_next_transaction_identifier(rrc->module_id); @@ -517,51 +571,10 @@ static void rrc_gNB_generate_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_ for (int i = 0; i < ue_p->nb_of_pdusessions; i++) clear_nas_pdu(&ue_p->pduSession[i].param.nas_pdu); - NR_CellGroupConfig_t *cellGroupConfig = ue_p->masterCellGroup; - - const nr_rrc_du_container_t *du = get_du_for_ue(rrc, ue_p->rrc_ue_id); - DevAssert(du != NULL); - f1ap_served_cell_info_t *cell_info = &du->setup_req->cell[0].info; - NR_MeasConfig_t *measconfig = NULL; - - if (du->mtc != NULL) { - int scs = get_ssb_scs(cell_info); - int band = get_dl_band(cell_info); - const NR_MeasTimingList_t *mtlist = du->mtc->criticalExtensions.choice.c1->choice.measTimingConf->measTiming; - const NR_MeasTiming_t *mt = mtlist->list.array[0]; - const neighbour_cell_configuration_t *neighbour_config = get_neighbour_config(cell_info->nr_cellid); - seq_arr_t *neighbour_cells = NULL; - if (neighbour_config) - neighbour_cells = neighbour_config->neighbour_cells; - - measconfig = get_MeasConfig(mt, band, scs, &rrc->measurementConfiguration, neighbour_cells); - } - - if (ue_p->measConfig) - free_MeasConfig(ue_p->measConfig); - - ue_p->measConfig = measconfig; - uint8_t buffer[NR_RRC_BUF_SIZE] = {0}; - NR_SRB_ToAddModList_t *SRBs = createSRBlist(ue_p, false); - NR_DRB_ToAddModList_t *DRBs = createDRBlist(ue_p, false); - - int size = do_RRCReconfiguration(ue_p, - buffer, - NR_RRC_BUF_SIZE, - xid, - SRBs, - DRBs, - ue_p->DRB_ReleaseList, - NULL, - measconfig, - dedicatedNAS_MessageList, - cellGroupConfig); - LOG_DUMPMSG(NR_RRC, DEBUG_RRC, (char *)buffer, size, "[MSG] RRC Reconfiguration\n"); - freeSRBlist(SRBs); - freeDRBlist(DRBs); - ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToReleaseList, ue_p->DRB_ReleaseList); - ue_p->DRB_ReleaseList = NULL; + // TODO refactor dedicatedNAS_MessageList + int size = rrc_gNB_encode_RRCReconfiguration(rrc, ue_p, xid, dedicatedNAS_MessageList, buffer, sizeof(buffer), false); + DevAssert(size > 0 && size <= sizeof(buffer)); LOG_I(NR_RRC, "UE %d: Generate RRCReconfiguration (bytes %d, xid %d)\n", ue_p->rrc_ue_id, size, xid); nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DCCH, buffer, size); From 345bd9cc825f581b614e6a07411ad3bb1e195666 Mon Sep 17 00:00:00 2001 From: Laurent THOMAS Date: Tue, 22 Oct 2024 18:40:10 +0200 Subject: [PATCH 21/75] remove duplicated code, add registration reject cause --- CMakeLists.txt | 4 +- common/utils/ocp_itti/intertask_interface.h | 2 - doc/Doxyfile | 6 +- executables/nr-uesoftmodem.c | 4 +- openair2/RRC/NR_UE/rrc_UE.c | 2 +- .../ESM/MSG/PduSessionEstablishmentAccept.c | 2 +- openair3/NAS/COMMON/NR_NAS_defs.h | 108 ++++----- .../NR_UE/{nr_nas_msg_sim.c => nr_nas_msg.c} | 22 +- .../NR_UE/{nr_nas_msg_sim.h => nr_nas_msg.h} | 93 +++----- openair3/NAS/NR_UE/ue_process_nas.c | 178 --------------- openair3/NAS/gNB/network_process_nas.c | 214 ------------------ 11 files changed, 101 insertions(+), 534 deletions(-) rename openair3/NAS/NR_UE/{nr_nas_msg_sim.c => nr_nas_msg.c} (99%) rename openair3/NAS/NR_UE/{nr_nas_msg_sim.h => nr_nas_msg.h} (53%) delete mode 100644 openair3/NAS/NR_UE/ue_process_nas.c delete mode 100644 openair3/NAS/gNB/network_process_nas.c diff --git a/CMakeLists.txt b/CMakeLists.txt index af48eca7b3..836e546a62 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1781,7 +1781,7 @@ add_library(LIB_NAS_SIMUE ${NAS_SRC}UE/nas_parser.c ${NAS_SRC}UE/nas_proc.c ${NAS_SRC}UE/nas_user.c - ${NAS_SRC}NR_UE/nr_nas_msg_sim.c + ${NAS_SRC}NR_UE/nr_nas_msg.c ${libnas_api_OBJS} ${libnas_ue_api_OBJS} ${libnas_emm_msg_OBJS} @@ -1844,8 +1844,6 @@ add_library(NB_IoT MODULE ${NBIOT_SOURCES} ) add_library(LIB_5GNAS_GNB ${NAS_SRC}/COMMON/nr_common.c - ${NAS_SRC}/gNB/network_process_nas.c - ${NAS_SRC}/NR_UE/ue_process_nas.c ${OPENAIR3_DIR}//UICC/usim_interface.c ) diff --git a/common/utils/ocp_itti/intertask_interface.h b/common/utils/ocp_itti/intertask_interface.h index f8f33a9c82..2f2ad54174 100644 --- a/common/utils/ocp_itti/intertask_interface.h +++ b/common/utils/ocp_itti/intertask_interface.h @@ -321,8 +321,6 @@ typedef struct { TASK_DEF(TASK_DU_F1, 200) \ TASK_DEF(TASK_CUCP_E1, 200) \ TASK_DEF(TASK_CUUP_E1, 200) \ - TASK_DEF(TASK_RRC_UE_SIM, 200) \ - TASK_DEF(TASK_RRC_GNB_SIM, 200) \ TASK_DEF(TASK_RRC_NSA_UE, 200) \ TASK_DEF(TASK_RRC_NSA_NRUE, 200) \ TASK_DEF(TASK_NAS_NRUE, 200) \ diff --git a/doc/Doxyfile b/doc/Doxyfile index 360bdd0535..bd1661fe60 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -1133,9 +1133,8 @@ INPUT = \ @CMAKE_CURRENT_SOURCE_DIR@/../openair3/UICC/usim_interface.h \ @CMAKE_CURRENT_SOURCE_DIR@/../openair3/UICC/usim_interface.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair3/ocp-gtpu/gtp_itf.h \ -@CMAKE_CURRENT_SOURCE_DIR@/../openair3/NAS/NR_UE/nr_nas_msg_sim.h \ -@CMAKE_CURRENT_SOURCE_DIR@/../openair3/NAS/NR_UE/ue_process_nas.c \ -@CMAKE_CURRENT_SOURCE_DIR@/../openair3/NAS/NR_UE/nr_nas_msg_sim.c \ +@CMAKE_CURRENT_SOURCE_DIR@/../openair3/NAS/NR_UE/nr_nas_msg.h \ +@CMAKE_CURRENT_SOURCE_DIR@/../openair3/NAS/NR_UE/nr_nas_msgc \ @CMAKE_CURRENT_SOURCE_DIR@/../openair3/NAS/UE/nas_itti_messaging.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair3/NAS/UE/user_defs.h \ @CMAKE_CURRENT_SOURCE_DIR@/../openair3/NAS/UE/EMM/emm_proc.h \ @@ -1584,7 +1583,6 @@ INPUT = \ @CMAKE_CURRENT_SOURCE_DIR@/../openair3/NAS/COMMON/ESM/MSG/ActivateDefaultEpsBearerContextAccept.h \ @CMAKE_CURRENT_SOURCE_DIR@/../openair3/NAS/COMMON/userDef.h \ @CMAKE_CURRENT_SOURCE_DIR@/../openair3/NAS/COMMON/nr_common.c \ -@CMAKE_CURRENT_SOURCE_DIR@/../openair3/NAS/gNB/network_process_nas.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair3/UTILS/conversions.h \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/X2AP/x2ap_eNB_encoder.h \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/X2AP/x2ap_eNB_management_procedures.c \ diff --git a/executables/nr-uesoftmodem.c b/executables/nr-uesoftmodem.c index f665dd2673..4e5e1a19f9 100644 --- a/executables/nr-uesoftmodem.c +++ b/executables/nr-uesoftmodem.c @@ -84,7 +84,7 @@ unsigned short config_frames[4] = {2,9,11,13}; #include "executables/softmodem-common.h" #include "executables/thread-common.h" -#include "nr_nas_msg_sim.h" +#include "nr_nas_msg.h" #include #include "openair2/GNB_APP/gnb_paramdef.h" @@ -335,7 +335,7 @@ static void trigger_stop(int sig) static void trigger_deregistration(int sig) { if (!stop_immediately) { - MessageDef *msg = itti_alloc_new_message(TASK_RRC_UE_SIM, 0, NAS_DEREGISTRATION_REQ); + MessageDef *msg = itti_alloc_new_message(TASK_NAS_NRUE, 0, NAS_DEREGISTRATION_REQ); NAS_DEREGISTRATION_REQ(msg).cause = AS_DETACH; itti_send_msg_to_task(TASK_NAS_NRUE, 0, msg); stop_immediately = true; diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index 7ea7dad968..89d73f1abc 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -68,7 +68,7 @@ #include "SIMULATION/TOOLS/sim.h" // for taus -#include "nr_nas_msg_sim.h" +#include "nr_nas_msg.h" #include "openair2/SDAP/nr_sdap/nr_sdap_entity.h" static NR_UE_RRC_INST_t *NR_UE_rrc_inst; diff --git a/openair3/NAS/COMMON/ESM/MSG/PduSessionEstablishmentAccept.c b/openair3/NAS/COMMON/ESM/MSG/PduSessionEstablishmentAccept.c index f5d053ae58..a062fec68e 100644 --- a/openair3/NAS/COMMON/ESM/MSG/PduSessionEstablishmentAccept.c +++ b/openair3/NAS/COMMON/ESM/MSG/PduSessionEstablishmentAccept.c @@ -21,7 +21,7 @@ #include "PduSessionEstablishmentAccept.h" #include "common/utils/LOG/log.h" -#include "nr_nas_msg_sim.h" +#include "nr_nas_msg.h" #include "common/utils/tun_if.h" #include "openair2/SDAP/nr_sdap/nr_sdap.h" diff --git a/openair3/NAS/COMMON/NR_NAS_defs.h b/openair3/NAS/COMMON/NR_NAS_defs.h index b6c0b715fc..f49852f62c 100644 --- a/openair3/NAS/COMMON/NR_NAS_defs.h +++ b/openair3/NAS/COMMON/NR_NAS_defs.h @@ -63,55 +63,55 @@ typedef enum { SGSmobilitymanagementmessages=0x7e, } Extendedprotocoldiscriminator_t; -#define FOREACH_TYPE(TYPE_DEF) \ - TYPE_DEF( Registrationrequest,0x41 )\ -TYPE_DEF( Registrationaccept,0x42 )\ -TYPE_DEF( Registrationcomplete,0x43 )\ -TYPE_DEF( Registrationreject,0x44 )\ -TYPE_DEF( DeregistrationrequestUEoriginating,0x45 )\ -TYPE_DEF( DeregistrationacceptUEoriginating,0x46 )\ -TYPE_DEF( DeregistrationrequestUEterminated,0x47 )\ -TYPE_DEF( DeregistrationacceptUEterminated,0x48 )\ -TYPE_DEF( Servicerequest,0x4c )\ -TYPE_DEF( Servicereject,0x4d )\ -TYPE_DEF( Serviceaccept,0x4e )\ -TYPE_DEF( Controlplaneservicerequest,0x4f )\ -TYPE_DEF( Networkslicespecificauthenticationcommand,0x50 )\ -TYPE_DEF( Networkslicespecificauthenticationcomplete,0x51 )\ -TYPE_DEF( Networkslicespecificauthenticationresult,0x52 )\ -TYPE_DEF( Configurationupdatecommand,0x54 )\ -TYPE_DEF( Configurationupdatecomplete,0x55 )\ -TYPE_DEF( Authenticationrequest,0x56 )\ -TYPE_DEF( Authenticationresponse,0x57 )\ -TYPE_DEF( Authenticationreject,0x58 )\ -TYPE_DEF( Authenticationfailure,0x59 )\ -TYPE_DEF( Authenticationresult,0x5a )\ -TYPE_DEF( Identityrequest,0x5b )\ -TYPE_DEF( Identityresponse,0x5c )\ -TYPE_DEF( Securitymodecommand,0x5d )\ -TYPE_DEF( Securitymodecomplete,0x5e )\ -TYPE_DEF( Securitymodereject,0x5f )\ -TYPE_DEF( SGMMstatus,0x64 )\ -TYPE_DEF( Notification,0x65 )\ -TYPE_DEF( Notificationresponse,0x66 )\ -TYPE_DEF( ULNAStransport,0x67 )\ -TYPE_DEF( DLNAStransport,0x68 )\ -TYPE_DEF( PDUsessionestablishmentrequest,0xc1 )\ -TYPE_DEF( PDUsessionestablishmentaccept,0xc2 )\ -TYPE_DEF( PDUsessionestablishmentreject,0xc3 )\ -TYPE_DEF( PDUsessionauthenticationcommand,0xc5 )\ -TYPE_DEF( PDUsessionauthenticationcomplete,0xc6 )\ -TYPE_DEF( PDUsessionauthenticationresult,0xc7 )\ -TYPE_DEF( PDUsessionmodificationrequest,0xc9 )\ -TYPE_DEF( PDUsessionmodificationreject,0xca )\ -TYPE_DEF( PDUsessionmodificationcommand,0xcb )\ -TYPE_DEF( PDUsessionmodificationcomplete,0xcc )\ -TYPE_DEF( PDUsessionmodificationcommandreject,0xcd )\ -TYPE_DEF( PDUsessionreleaserequest,0xd1 )\ -TYPE_DEF( PDUsessionreleasereject,0xd2 )\ -TYPE_DEF( PDUsessionreleasecommand,0xd3 )\ -TYPE_DEF( PDUsessionreleasecomplete,0xd4 )\ -TYPE_DEF( SGSMstatus,0xd6 )\ +#define FOREACH_TYPE(TYPE_DEF) \ + TYPE_DEF(REGISTRATION_REQUEST, 0x41) \ + TYPE_DEF(REGISTRATION_ACCEPT, 0x42) \ + TYPE_DEF(REGISTRATION_COMPLETE, 0x43) \ + TYPE_DEF(REGISTRATION_REJECT, 0x44) \ + TYPE_DEF(FGS_DEREGISTRATION_REQUEST_UE_ORIGINATING, 0x45) \ + TYPE_DEF(FGS_DEREGISTRATION_ACCEPT_UE_ORIGINATING, 0x46) \ + TYPE_DEF(DeregistrationrequestUEterminated, 0x47) \ + TYPE_DEF(DeregistrationacceptUEterminated, 0x48) \ + TYPE_DEF(Servicerequest, 0x4c) \ + TYPE_DEF(Servicereject, 0x4d) \ + TYPE_DEF(Serviceaccept, 0x4e) \ + TYPE_DEF(Controlplaneservicerequest, 0x4f) \ + TYPE_DEF(Networkslicespecificauthenticationcommand, 0x50) \ + TYPE_DEF(Networkslicespecificauthenticationcomplete, 0x51) \ + TYPE_DEF(Networkslicespecificauthenticationresult, 0x52) \ + TYPE_DEF(Configurationupdatecommand, 0x54) \ + TYPE_DEF(Configurationupdatecomplete, 0x55) \ + TYPE_DEF(FGS_AUTHENTICATION_REQUEST, 0x56) \ + TYPE_DEF(FGS_AUTHENTICATION_RESPONSE, 0x57) \ + TYPE_DEF(Authenticationreject, 0x58) \ + TYPE_DEF(Authenticationfailure, 0x59) \ + TYPE_DEF(Authenticationresult, 0x5a) \ + TYPE_DEF(FGS_IDENTITY_REQUEST, 0x5b) \ + TYPE_DEF(FGS_IDENTITY_RESPONSE, 0x5c) \ + TYPE_DEF(FGS_SECURITY_MODE_COMMAND, 0x5d) \ + TYPE_DEF(FGS_SECURITY_MODE_COMPLETE, 0x5e) \ + TYPE_DEF(Securitymodereject, 0x5f) \ + TYPE_DEF(SGMMstatus, 0x64) \ + TYPE_DEF(Notification, 0x65) \ + TYPE_DEF(Notificationresponse, 0x66) \ + TYPE_DEF(FGS_UPLINK_NAS_TRANSPORT, 0x67) \ + TYPE_DEF(FGS_DOWNLINK_NAS_TRANSPORT, 0x68) \ + TYPE_DEF(FGS_PDU_SESSION_ESTABLISHMENT_REQ, 0xc1) \ + TYPE_DEF(FGS_PDU_SESSION_ESTABLISHMENT_ACC, 0xc2) \ + TYPE_DEF(FGS_PDU_SESSION_ESTABLISHMENT_REJ, 0xc3) \ + TYPE_DEF(PDUsessionauthenticationcommand, 0xc5) \ + TYPE_DEF(PDUsessionauthenticationcomplete, 0xc6) \ + TYPE_DEF(PDUsessionauthenticationresult, 0xc7) \ + TYPE_DEF(PDUsessionmodificationrequest, 0xc9) \ + TYPE_DEF(PDUsessionmodificationreject, 0xca) \ + TYPE_DEF(PDUsessionmodificationcommand, 0xcb) \ + TYPE_DEF(PDUsessionmodificationcomplete, 0xcc) \ + TYPE_DEF(PDUsessionmodificationcommandreject, 0xcd) \ + TYPE_DEF(PDUsessionreleaserequest, 0xd1) \ + TYPE_DEF(PDUsessionreleasereject, 0xd2) \ + TYPE_DEF(PDUsessionreleasecommand, 0xd3) \ + TYPE_DEF(PDUsessionreleasecomplete, 0xd4) \ + TYPE_DEF(SGSMstatus, 0xd6) static const text_info_t message_text_info[] = { FOREACH_TYPE(TO_TEXT) @@ -124,11 +124,11 @@ typedef enum { // TS 24.501 typedef enum { - notsecurityprotected=0, - Integrityprotected=1, - Integrityprotectedandciphered=2, - Integrityprotectedwithnew5GNASsecuritycontext=3, - Integrityprotectedandcipheredwithnew5GNASsecuritycontext=4, + PLAIN_5GS_MSG = 0, + INTEGRITY_PROTECTED = 1, + INTEGRITY_PROTECTED_AND_CIPHERED = 2, + INTEGRITY_PROTECTED_WITH_NEW_SECU_CTX = 3, + INTEGRITY_PROTECTED_AND_CIPHERED_WITH_NEW_SECU_CTX = 4, } Security_header_t; typedef enum { diff --git a/openair3/NAS/NR_UE/nr_nas_msg_sim.c b/openair3/NAS/NR_UE/nr_nas_msg.c similarity index 99% rename from openair3/NAS/NR_UE/nr_nas_msg_sim.c rename to openair3/NAS/NR_UE/nr_nas_msg.c index 87953f8b4c..98a87c7bfd 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg_sim.c +++ b/openair3/NAS/NR_UE/nr_nas_msg.c @@ -19,7 +19,7 @@ * contact@openairinterface.org */ -/*! \file nr_nas_msg_sim.c +/*! \file nr_nas_msg.c * \brief simulator for nr nas message * \author Yoshio INOUE, Masayuki HARADA * \email yoshio.inoue@fujitsu.com,masayuki.harada@fujitsu.com @@ -35,7 +35,7 @@ #include "nas_log.h" #include "TLVDecoder.h" #include "TLVEncoder.h" -#include "nr_nas_msg_sim.h" +#include "nr_nas_msg.h" #include "aka_functions.h" #include "secu_defs.h" #include "kdf.h" @@ -1393,7 +1393,7 @@ void *nas_nrue(void *args_p) if (security_state == NAS_SECURITY_UNPROTECTED) { int msg_type = get_msg_type(pdu_buffer, pdu_length); /* for the moment, only FGS_DEREGISTRATION_ACCEPT is accepted */ - if (msg_type == FGS_DEREGISTRATION_ACCEPT) + if (msg_type == FGS_DEREGISTRATION_ACCEPT_UE_ORIGINATING) security_state = NAS_SECURITY_INTEGRITY_PASSED; } @@ -1420,7 +1420,7 @@ void *nas_nrue(void *args_p) case REGISTRATION_ACCEPT: handle_registration_accept(nas, pdu_buffer, pdu_length); break; - case FGS_DEREGISTRATION_ACCEPT: + case FGS_DEREGISTRATION_ACCEPT_UE_ORIGINATING: LOG_I(NAS, "received deregistration accept\n"); break; case FGS_PDU_SESSION_ESTABLISHMENT_ACC: { @@ -1449,13 +1449,13 @@ void *nas_nrue(void *args_p) offset++; } } break; - case FGS_PDU_SESSION_ESTABLISHMENT_REJ: - LOG_E(NAS, "Received PDU Session Establishment reject\n"); - break; - case REGISTRATION_REJECT: - LOG_E(NAS, "Received Registration reject\n"); - exit(1); - break; + case FGS_PDU_SESSION_ESTABLISHMENT_REJ: + LOG_E(NAS, "Received PDU Session Establishment reject\n"); + break; + case REGISTRATION_REJECT: + LOG_E(NAS, "Received Registration reject cause: %s\n", cause_text_info[pdu_buffer[17]].text); + exit(1); + break; default: LOG_W(NR_RRC, "unknown message type %d\n", msg_type); break; diff --git a/openair3/NAS/NR_UE/nr_nas_msg_sim.h b/openair3/NAS/NR_UE/nr_nas_msg.h similarity index 53% rename from openair3/NAS/NR_UE/nr_nas_msg_sim.h rename to openair3/NAS/NR_UE/nr_nas_msg.h index bb54660bbd..2e687baf8f 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg_sim.h +++ b/openair3/NAS/NR_UE/nr_nas_msg.h @@ -19,7 +19,7 @@ * contact@openairinterface.org */ -/*! \file nr_nas_msg_sim.h +/*! \file nr_nas_msg.h * \brief simulator for nr nas message * \author Yoshio INOUE, Masayuki HARADA * \email yoshio.inoue@fujitsu.com,masayuki.harada@fujitsu.com @@ -27,8 +27,6 @@ * \version 0.1 */ - - #ifndef __NR_NAS_MSG_SIM_H__ #define __NR_NAS_MSG_SIM_H__ @@ -43,38 +41,12 @@ #include #include "secu_defs.h" -#define PLAIN_5GS_MSG 0b0000 -#define INTEGRITY_PROTECTED 0b0001 -#define INTEGRITY_PROTECTED_AND_CIPHERED 0b0010 -#define INTEGRITY_PROTECTED_WITH_NEW_SECU_CTX 0b0011 // only for SECURITY MODE COMMAND -#define INTEGRITY_PROTECTED_AND_CIPHERED_WITH_NEW_SECU_CTX 0b0100 // only for SECURITY MODE COMPLETE +#define INITIAL_REGISTRATION 0b001 -#define REGISTRATION_REQUEST 0b01000001 /* 65 = 0x41 */ -#define REGISTRATION_ACCEPT 0b01000010 /* 66 = 0x42 */ -#define REGISTRATION_COMPLETE 0b01000011 /* 67 = 0x43 */ -#define REGISTRATION_REJECT 68 -#define FGS_DEREGISTRATION_REQUEST_UE_ORIGINATING 0b01000101 -#define FGS_DEREGISTRATION_ACCEPT 0b01000110 -#define FGS_AUTHENTICATION_REQUEST 0b01010110 /* 86 = 0x56 */ -#define FGS_AUTHENTICATION_RESPONSE 0b01010111 /* 87 = 0x57 */ -#define FGS_IDENTITY_REQUEST 0b01011011 /* 91 = 0x5b */ -#define FGS_IDENTITY_RESPONSE 0b01011100 /* 92 = 0x5c */ -#define FGS_SECURITY_MODE_COMMAND 0b01011101 /* 93 = 0x5d */ -#define FGS_SECURITY_MODE_COMPLETE 0b01011110 /* 94 = 0x5e */ -#define FGS_UPLINK_NAS_TRANSPORT 0b01100111 /* 103= 0x67 */ -#define FGS_DOWNLINK_NAS_TRANSPORT 0b01101000 /* 104= 0x68 */ - -// message type for 5GS session management -#define FGS_PDU_SESSION_ESTABLISHMENT_REQ 0b11000001 /* 193= 0xc1 */ -#define FGS_PDU_SESSION_ESTABLISHMENT_ACC 0b11000010 /* 194= 0xc2 */ -#define FGS_PDU_SESSION_ESTABLISHMENT_REJ 0b11000011 /* 195= 0xc3 */ - -#define INITIAL_REGISTRATION 0b001 - -#define PLAIN_5GS_NAS_MESSAGE_HEADER_LENGTH 3 -#define SECURITY_PROTECTED_5GS_NAS_MESSAGE_HEADER_LENGTH 7 -#define PAYLOAD_CONTAINER_LENGTH_MIN 3 -#define PAYLOAD_CONTAINER_LENGTH_MAX 65537 +#define PLAIN_5GS_NAS_MESSAGE_HEADER_LENGTH 3 +#define SECURITY_PROTECTED_5GS_NAS_MESSAGE_HEADER_LENGTH 7 +#define PAYLOAD_CONTAINER_LENGTH_MIN 3 +#define PAYLOAD_CONTAINER_LENGTH_MAX 65537 /* List of allowed NSSAI from NAS messaging. */ typedef struct { @@ -104,20 +76,19 @@ typedef struct { stream_security_container_t *security_container; Guti5GSMobileIdentity_t *guti; bool termination_procedure; - uint8_t *registration_request_buf; - uint32_t registration_request_len; + uint8_t *registration_request_buf; + uint32_t registration_request_len; instance_t UE_id; } nr_ue_nas_t; typedef enum fgs_protocol_discriminator_e { /* Protocol discriminator identifier for 5GS Mobility Management */ - FGS_MOBILITY_MANAGEMENT_MESSAGE = 0x7E, + FGS_MOBILITY_MANAGEMENT_MESSAGE = 0x7E, /* Protocol discriminator identifier for 5GS Session Management */ - FGS_SESSION_MANAGEMENT_MESSAGE = 0x2E, + FGS_SESSION_MANAGEMENT_MESSAGE = 0x2E, } fgs_protocol_discriminator_t; - typedef struct { uint8_t ex_protocol_discriminator; uint8_t security_header_type; @@ -126,27 +97,25 @@ typedef struct { /* Structure of security protected header */ typedef struct { - fgs_protocol_discriminator_t protocol_discriminator; - uint8_t security_header_type; - uint32_t message_authentication_code; - uint8_t sequence_number; + fgs_protocol_discriminator_t protocol_discriminator; + uint8_t security_header_type; + uint32_t message_authentication_code; + uint8_t sequence_number; } fgs_nas_message_security_header_t; typedef union { - mm_msg_header_t header; - registration_request_msg registration_request; - fgs_identiy_response_msg fgs_identity_response; - fgs_authentication_response_msg fgs_auth_response; + mm_msg_header_t header; + registration_request_msg registration_request; + fgs_identiy_response_msg fgs_identity_response; + fgs_authentication_response_msg fgs_auth_response; fgs_deregistration_request_ue_originating_msg fgs_deregistration_request_ue_originating; - fgs_security_mode_complete_msg fgs_security_mode_complete; - registration_complete_msg registration_complete; - fgs_uplink_nas_transport_msg uplink_nas_transport; + fgs_security_mode_complete_msg fgs_security_mode_complete; + registration_complete_msg registration_complete; + fgs_uplink_nas_transport_msg uplink_nas_transport; } MM_msg; - - typedef struct { - MM_msg mm_msg; /* 5GS Mobility Management messages */ + MM_msg mm_msg; /* 5GS Mobility Management messages */ } fgs_nas_message_plain_t; typedef struct { @@ -154,7 +123,6 @@ typedef struct { fgs_nas_message_plain_t plain; } fgs_nas_message_security_protected_t; - typedef union { fgs_nas_message_security_header_t header; fgs_nas_message_security_protected_t security_protected; @@ -165,11 +133,11 @@ typedef struct { union { mm_msg_header_t plain_nas_msg_header; struct security_protected_nas_msg_header_s { - uint8_t ex_protocol_discriminator; - uint8_t security_header_type; + uint8_t ex_protocol_discriminator; + uint8_t security_header_type; uint16_t message_authentication_code1; uint16_t message_authentication_code2; - uint8_t sequence_number; + uint8_t sequence_number; } security_protected_nas_msg_header_t; } choice; } nas_msg_header_t; @@ -182,10 +150,10 @@ typedef struct { } fgs_sm_nas_msg_header_t; typedef struct { - mm_msg_header_t plain_nas_msg_header; - uint8_t payload_container_type; - uint16_t payload_container_length; - fgs_sm_nas_msg_header_t sm_nas_msg_header; + mm_msg_header_t plain_nas_msg_header; + uint8_t payload_container_type; + uint16_t payload_container_length; + fgs_sm_nas_msg_header_t sm_nas_msg_header; } dl_nas_transport_t; nr_ue_nas_t *get_ue_nas_info(module_id_t module_id); @@ -194,6 +162,3 @@ void *nas_nrue_task(void *args_p); void *nas_nrue(void *args_p); #endif /* __NR_NAS_MSG_SIM_H__*/ - - - diff --git a/openair3/NAS/NR_UE/ue_process_nas.c b/openair3/NAS/NR_UE/ue_process_nas.c deleted file mode 100644 index a89a07218e..0000000000 --- a/openair3/NAS/NR_UE/ue_process_nas.c +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Author and copyright: Laurent Thomas, open-cells.com - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ -#include -#include - - -void SGSabortNet(void *msg, nr_user_nas_t *UE) { -} - -void ue_nas_schedule(void) { -} - -/* - *Message reception - */ - -void SGSauthenticationReq(void *msg, nr_user_nas_t *UE) { - authenticationrequestHeader_t *amsg=(authenticationrequestHeader_t *) msg; - arrayCpy(UE->uicc->rand,amsg->RAND); - arrayCpy(UE->uicc->autn,amsg->AUTN); - // AUTHENTICATION REQUEST message that contains a valid ngKSI, SQN and MAC is received - // TBD verify ngKSI (we set it as '2', see gNB code) - // SQN and MAC are tested in auth resp processing - ue_nas_schedule(); -} - -void SGSidentityReq(void *msg, nr_user_nas_t *UE) { - Identityrequest_t *idmsg=(Identityrequest_t *) msg; - - if (idmsg->it == SUCI ) { - LOG_I(NAS,"Received Identity request, scheduling answer\n"); - ue_nas_schedule(); - } else - LOG_E(NAS,"Not developped: identity request for %d\n", idmsg->it); -} - -void SGSsecurityModeCommand(void *msg, nr_user_nas_t *UE) { -} - - -void UEprocessNAS(void *msg,nr_user_nas_t *UE) { - SGScommonHeader_t *header=(SGScommonHeader_t *) msg; - - if ( header->sh > 4 ) - SGSabortNet(msg, UE); - else { - switch (header->epd) { - case SGSmobilitymanagementmessages: - LOG_I(NAS,"Received message: %s\n", idStr(message_text_info, header->mt)); - - switch (header->mt) { - case Authenticationrequest: - SGSauthenticationReq(msg, UE); - break; - - case Identityrequest: - SGSidentityReq(msg, UE); - break; - - case Securitymodecommand: - SGSsecurityModeCommand(msg, UE); - break; - - default: - SGSabortNet(msg, UE); - } - - break; - - case SGSsessionmanagementmessages: - SGSabortNet(msg, UE); - break; - - default: - SGSabortNet(msg, UE); - } - } -} - -/* - * Messages emission - */ - -int identityResponse(void **msg, nr_user_nas_t *UE) { - if (UE->uicc == NULL) - // config file section hardcoded as "uicc", nevertheless it opens to manage several UEs or a multi SIM UE - UE->uicc=init_uicc("uicc"); - - // TS 24.501 9.11.3.4 - int imsiL=strlen(UE->uicc->imsiStr); - int msinL=imsiL-3-UE->uicc->nmc_size; - int respSize=sizeof(IdentityresponseIMSI_t) + (msinL+1)/2; - IdentityresponseIMSI_t *resp=(IdentityresponseIMSI_t *) calloc(respSize,1); - resp->common.epd=SGSmobilitymanagementmessages; - resp->common.sh=0; - resp->common.mt=Identityresponse; - resp->common.len=htons(respSize-sizeof(Identityresponse_t)); - resp->mi=SUCI; - resp->mcc1=UE->uicc->imsiStr[0]-'0'; - resp->mcc2=UE->uicc->imsiStr[1]-'0'; - resp->mcc3=UE->uicc->imsiStr[2]-'0'; - resp->mnc1=UE->uicc->imsiStr[3]-'0'; - resp->mnc2=UE->uicc->imsiStr[4]-'0'; - resp->mnc3=UE->uicc->nmc_size==2? 0xF : UE->uicc->imsiStr[3]-'0'; - // TBD: routing to fill (FF ?) - char *out=(char *)(resp+1); - char *ptr=UE->uicc->imsiStr + 3 + UE->uicc->nmc_size; - - while ( ptr < UE->uicc->imsiStr+strlen(UE->uicc->imsiStr) ) { - *out=((*(ptr+1)-'0')<<4) | (*(ptr) -'0'); - out++; - ptr+=2; - } - - if (msinL%2 == 1) - *out=((*(ptr-1)-'0')) | 0xF0; - - *msg=resp; - return respSize; -} - -int authenticationResponse(void **msg,nr_user_nas_t *UE) { - if (UE->uicc == NULL) - // config file section hardcoded as "uicc", nevertheless it opens to manage several UEs or a multi SIM UE - UE->uicc=init_uicc("uicc"); - - myCalloc(resp, authenticationresponse_t); - resp->epd=SGSmobilitymanagementmessages; - resp->sh=0; - resp->mt=Authenticationresponse; - resp->iei=IEI_AuthenticationResponse; - resp->RESlen=sizeof(resp->RES); // always 16 see TS 24.501 Table 8.2.2.1.1 - // Verify the AUTN - // a full implementation need to test several SQN - // as the last 5bits can be any value - // and the value can also be greater and accepted (if it is in the accepted window) - uint8_t AUTN[16]; - uicc_milenage_generate(AUTN, UE->uicc); - - if ( memcmp(UE->uicc->autn, AUTN, sizeof(AUTN)) == 0 ) { - // prepare and send good answer - resToresStar(resp->RES,UE->uicc); - } else { - // prepare and send autn is not compatible with our data - abort(); - } - - *msg=resp; - return sizeof(authenticationresponse_t); -} - -int securityModeComplete(void **msg, nr_user_nas_t *UE) { - return -1; -} - -int registrationComplete(void **msg, nr_user_nas_t *UE) { - return -1; -} diff --git a/openair3/NAS/gNB/network_process_nas.c b/openair3/NAS/gNB/network_process_nas.c deleted file mode 100644 index ce8897730b..0000000000 --- a/openair3/NAS/gNB/network_process_nas.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Author and copyright: Laurent Thomas, open-cells.com - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ -#include - -void SGSabortUE(void *msg, NRUEcontext_t *UE) { -} -void nas_schedule(void) { -} -/* - *Message reception - */ - -void SGSregistrationReq(void *msg, NRUEcontext_t *UE) { -} - -void SGSderegistrationUEReq(void *msg, NRUEcontext_t *UE) { -} - -void SGSidentityResp(void *msg, NRUEcontext_t *UE) { - // use the UE SUPI to load the USIM - IdentityresponseIMSI_t *resp=(IdentityresponseIMSI_t *)msg; - char configName[100]={0}; - char * ptr= stpcpy(configName,"uicc"); - *ptr++=resp->mcc1+'0'; - *ptr++=resp->mcc2+'0'; - *ptr++=resp->mcc3+'0'; - *ptr++=resp->mnc1+'0'; - *ptr++=resp->mnc2+'0'; - if ( resp->mnc3 != 0xF ) - *ptr++=resp->mnc3 +'0'; - int respSize=ntohs(resp->common.len); - int msinByteSize=respSize-sizeof(IdentityresponseIMSI_t); - uint8_t * msin=(uint8_t *) (resp+1); - for(int i=3 ; i> 4) ; - *ptr++=(msin[i] & 0xf) +'0'; - if (digit1 != 0xf) - *ptr++=digit1 +'0'; - } - *ptr=0; - if (UE->uicc == NULL) - // config file section hardcoded as "uicc", nevertheless it opens to manage several UEs or a multi SIM UE - UE->uicc=init_uicc(configName); - //We schedule Authentication request - nas_schedule(); -} - -void SGSauthenticationResp(void *msg, NRUEcontext_t *UE) { - // Let's check the answer - authenticationresponse_t* resp=(authenticationresponse_t*) msg; - uint8_t resStarLocal[16]; - resToresStar(resStarLocal,UE->uicc); - if ( memcmp(resStarLocal, resp->RES, sizeof(resStarLocal)) == 0 ) { - LOG_I(NAS,"UE answer to authentication resquest is correct\n"); - // we will send securityModeCommand - nas_schedule(); - } else { - LOG_E(NAS,"UE authentication response not good\n"); - // To be implemented ? - } -} - -void SGSsecurityModeComplete(void *msg, NRUEcontext_t *UE) { - -} - -void SGSregistrationComplete(void *msg, NRUEcontext_t *UE) { -} - -void processNAS(void *msg, NRUEcontext_t *UE) { - SGScommonHeader_t *header=(SGScommonHeader_t *) msg; - - if ( header->sh > 4 ) - SGSabortUE(msg, UE); - else { - switch (header->epd) { - case SGSmobilitymanagementmessages: - LOG_I(NAS,"Received message: %s\n", idStr(message_text_info, header->mt)); - - switch (header->mt) { - case Registrationrequest: - SGSregistrationReq(msg, UE); - break; - - case DeregistrationrequestUEoriginating: - SGSderegistrationUEReq(msg, UE); - break; - - case Authenticationresponse: - SGSauthenticationResp(msg, UE); - break; - - case Identityresponse: - SGSidentityResp(msg, UE); - break; - - case Securitymodecomplete: - SGSsecurityModeComplete(msg, UE); - break; - - case Registrationcomplete: - SGSregistrationComplete(msg, UE); - break; - - default: - SGSabortUE(msg, UE); - } - - break; - - case SGSsessionmanagementmessages: - SGSabortUE(msg, UE); - break; - - default: - SGSabortUE(msg, UE); - } - } -} - -/* - * Messages emission - */ - -int identityRequest(void **msg, NRUEcontext_t *UE) { - myCalloc(req, Identityrequest_t); - req->epd=SGSmobilitymanagementmessages; - req->sh=0; - req->mt=Identityrequest; - req->it=SUCI; - *msg=req; - return sizeof(Identityrequest_t); -} - -int authenticationRequest(void **msg, NRUEcontext_t *UE) { - - myCalloc(req, authenticationrequestHeader_t); - req->epd=SGSmobilitymanagementmessages; - req->sh=0; - req->mt=Authenticationrequest; - // native security context => bit 4 to 0 - // probably from TS 33.501, table A-8.1 - // N-NAS-int-alg (Native NAS integrity) - /* - N-NAS-enc-alg 0x01 - N-NAS-int-alg 0x02 - N-RRC-enc-alg 0x03 - N-RRC-int-alg 0x04 - N-UP-enc-alg 0x05 - N-UP-int-alg 0x06 - */ - req->ngKSI=2; - // TS 33.501, Annex A.7.1: Initial set of security features defined for 5GS. - req->ABBALen=2; - req->ABBA=0; - //rand (TV) - req->ieiRAND=IEI_RAND; - FILE *h=fopen("/dev/random","r"); - - if ( sizeof(req->RAND) != fread(req->RAND,1,sizeof(req->RAND),h) ) - LOG_E(NAS, "can't read /dev/random\n"); - - fclose(h); - memcpy(UE->uicc->rand, req->RAND, sizeof(UE->uicc->rand)); - // challenge/AUTN (TLV) - req->ieiAUTN=IEI_AUTN; - req->AUTNlen=sizeof(req->AUTN); - uicc_milenage_generate( req->AUTN, UE->uicc); - // EAP message (TLV-E) - // not developped - *msg=req; - return sizeof(authenticationrequestHeader_t); -} - -int securityModeCommand(void **msg, NRUEcontext_t *UE) { - *msg=NULL; - myCalloc(req, securityModeCommand_t); - req->epd=SGSmobilitymanagementmessages; - req->sh=0; - req->mt=Securitymodecommand; - - // integrity algo from 5G-IA0 (null algo) to 5G-IA7 in first 4 bits - unsigned int ia=0; - // cyphering algo from 5G-EA0 (null algo) to 5G-IA7 in MSB 4 bits - unsigned int ea=0; - // trace from commercial: 5G-IA0 (0) 128-5G-IA2 (2) - req->selectedNASsecurityalgorithms= ea<<4 | ia; - - // KSI: N-NAS-int-alg 0x02 - req->ngKSI=2; - - *msg=req; - return 0; -} From 78a4d0754d9628ab6eae3982f3939a4829c6dbe3 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Wed, 23 Oct 2024 14:27:32 +0200 Subject: [PATCH 22/75] T: don't check argument in optimized version of T IDs --- common/utils/T/T.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/common/utils/T/T.h b/common/utils/T/T.h index 07919e843a..746607cc6e 100644 --- a/common/utils/T/T.h +++ b/common/utils/T/T.h @@ -177,6 +177,7 @@ extern int *T_active; #else /* #ifdef __cplusplus */ /* C version of T_HEADER with time */ +#ifdef CHECK_T_TYPE #define T_HEADER(x) \ do { \ if (!__builtin_types_compatible_p(typeof(x), struct T_header *)) { \ @@ -191,6 +192,16 @@ extern int *T_active; T_LOCAL_size += sizeof(struct timespec); \ T_PUT_int(1, (int)(uintptr_t)(x)); \ } while (0) +#else /* CHECK_T_TYPE */ +#define T_HEADER(x) \ + do { \ + struct timespec T_HEADER_time; \ + if (clock_gettime(CLOCK_REALTIME, &T_HEADER_time)) abort(); \ + memcpy(T_LOCAL_buf, &T_HEADER_time, sizeof(struct timespec)); \ + T_LOCAL_size += sizeof(struct timespec); \ + T_PUT_int(1, (int)(uintptr_t)(x)); \ + } while (0) +#endif /* CHECK_T_TYPE */ #endif /* #ifdef __cplusplus */ @@ -207,6 +218,7 @@ extern int *T_active; #else /* #ifdef __cplusplus */ /* C version of T_HEADER without time */ +#ifdef CHECK_T_TYPE #define T_HEADER(x) \ do { \ if (!__builtin_types_compatible_p(typeof(x), struct T_header *)) { \ @@ -217,6 +229,12 @@ extern int *T_active; } \ T_PUT_int(1, (int)(uintptr_t)(x)); \ } while (0) +#else /* CHECK_T_TYPE */ +#define T_HEADER(x) \ + do { \ + T_PUT_int(1, (int)(uintptr_t)(x)); \ + } while (0) +#endif /* CHECK_T_TYPE */ #endif /* #ifdef __cplusplus */ From 5855f766f8b445c0046732f2093b107128b59c2d Mon Sep 17 00:00:00 2001 From: Sakthivel Velumani Date: Mon, 21 Oct 2024 22:20:33 -0400 Subject: [PATCH 23/75] Bugfix in ue pusch mac pdu creation When more than one sdu with equal priority is present, there could be buffer left after serving the lcids and also not enough for equaly serving all lcids. This commit checks for this condition. Before this fix the ue would send malformed mac pdus when serving multiple lcids. --- openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 9003cc42d2..42b6571669 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -3608,7 +3608,11 @@ uint8_t nr_ue_get_sdu(NR_UE_MAC_INST_t *mac, buflen_remain); if (num_lcids_same_priority == count_same_priority_lcids) { - buflen_ep = (buflen_remain - (count_same_priority_lcids * sh_size)) / count_same_priority_lcids; + const int32_t buflen_ep_tmp = (buflen_remain - (count_same_priority_lcids * sh_size)) / count_same_priority_lcids; + /* after serving equal priority LCIDs in the first round, buflen_remain could be > 0 and < (count_same_priority_lcids * sh_size) + if above division yeilds a remainder. hence the following sets buflen_ep to 0 if there is not enough buffer left for subsequent rounds + */ + buflen_ep = buflen_ep_tmp < 0 ? 0 : buflen_ep_tmp; } while (buflen_remain > 0) { From 9333662cd8f6574472b9628a16b413f262216276 Mon Sep 17 00:00:00 2001 From: Sakthivel Velumani Date: Mon, 21 Oct 2024 22:28:33 -0400 Subject: [PATCH 24/75] Update logging in mac --- openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 2 +- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 42b6571669..b15d80aa01 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -3450,7 +3450,7 @@ static bool fill_mac_sdu(NR_UE_MAC_INST_t *mac, *pdu -= sh_size; lcids_data_status[lc_idx] = false; (*num_lcids_same_priority)--; - LOG_D(NR_MAC, "No data to transmit for RB with LCID 0x%02x\n and hence set to false", lcid); + LOG_D(NR_MAC, "No data to transmit for RB with LCID 0x%02x and hence set to false\n", lcid); return 0; } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 319d8fec67..03aec3bc6a 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -501,7 +501,7 @@ static int nr_process_mac_pdu(instance_t module_idP, break; default: - LOG_E(NR_MAC, "RNTI %0x, received unknown MAC header (LCID = 0x%02x)\n", UE->rnti, rx_lcid); + LOG_E(NR_MAC, "RNTI %0x [%d.%d], received unknown MAC header (LCID = 0x%02x)\n", UE->rnti, frameP, slot, rx_lcid); return -1; break; } From e7f858f6b2c02579f7e9229131e8057acfee600d Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Mon, 30 Sep 2024 20:50:57 +0200 Subject: [PATCH 25/75] Add iterator to hashtable and hashtable unit tests --- common/utils/CMakeLists.txt | 3 + common/utils/hashtable/hashtable.c | 21 ++++ common/utils/hashtable/hashtable.h | 11 +- common/utils/hashtable/tests/CMakeLists.txt | 5 + .../utils/hashtable/tests/test_hashtable.cpp | 106 ++++++++++++++++++ 5 files changed, 144 insertions(+), 2 deletions(-) create mode 100644 common/utils/hashtable/tests/CMakeLists.txt create mode 100644 common/utils/hashtable/tests/test_hashtable.cpp diff --git a/common/utils/CMakeLists.txt b/common/utils/CMakeLists.txt index 025091249b..7cf067dd14 100644 --- a/common/utils/CMakeLists.txt +++ b/common/utils/CMakeLists.txt @@ -16,3 +16,6 @@ add_subdirectory(threadPool) add_library(utils utils.c system.c time_meas.c time_stat.c tun_if.c) target_include_directories(utils PUBLIC .) target_link_libraries(utils PRIVATE ${T_LIB}) +if (ENABLE_TESTS) + add_subdirectory(hashtable/tests) +endif() diff --git a/common/utils/hashtable/hashtable.c b/common/utils/hashtable/hashtable.c index e9641f8e0c..bbd03692e4 100644 --- a/common/utils/hashtable/hashtable.c +++ b/common/utils/hashtable/hashtable.c @@ -305,3 +305,24 @@ hashtable_rc_t hashtable_get(const hash_table_t *const hashtblP, const hash_key_ *dataP = NULL; return HASH_TABLE_KEY_NOT_EXISTS; } + +hash_table_iterator_s hashtable_get_iterator(const hash_table_t *const hashtbl) +{ + return (hash_table_iterator_s){.index = 0, .node = hashtbl->nodes[0], .hashtbl = hashtbl}; +} + +bool hashtable_iterator_getnext(hash_table_iterator_s *iterator, void **dataP) +{ + // Iterate over table indexes + while (iterator->node == NULL) { + iterator->index++; + if (iterator->index >= iterator->hashtbl->size) { + *dataP = NULL; + return false; + } + iterator->node = iterator->hashtbl->nodes[iterator->index]; + } + *dataP = iterator->node->data; + iterator->node = iterator->node->next; + return true; +} diff --git a/common/utils/hashtable/hashtable.h b/common/utils/hashtable/hashtable.h index 09f8623ce2..c50c23ae7b 100644 --- a/common/utils/hashtable/hashtable.h +++ b/common/utils/hashtable/hashtable.h @@ -24,6 +24,7 @@ #include #include #include +#include typedef size_t hash_size_t; typedef uint64_t hash_key_t; @@ -54,6 +55,12 @@ typedef struct hash_table_s { void (*freefunc)(void *); } hash_table_t; +typedef struct hash_table_iterator_s { + int index; + hash_node_t* node; + const hash_table_t* const hashtbl; +} hash_table_iterator_s; + char *hashtable_rc_code2string(hashtable_rc_t rcP); void hash_free_int_func(void *memoryP); hash_table_t *hashtable_create (const hash_size_t size, hash_size_t (*hashfunc)(const hash_key_t ), void (*freefunc)(void *)); @@ -63,8 +70,8 @@ hashtable_rc_t hashtable_dump_content (const hash_table_t *const hashtblP, char hashtable_rc_t hashtable_insert (hash_table_t *const hashtbl, const hash_key_t key, void *data); hashtable_rc_t hashtable_remove (hash_table_t *const hashtbl, const hash_key_t key); hashtable_rc_t hashtable_get (const hash_table_t *const hashtbl, const hash_key_t key, void **dataP); - - +hash_table_iterator_s hashtable_get_iterator(const hash_table_t *const hashtbl); +bool hashtable_iterator_getnext(hash_table_iterator_s* iterator, void **dataP); #endif diff --git a/common/utils/hashtable/tests/CMakeLists.txt b/common/utils/hashtable/tests/CMakeLists.txt new file mode 100644 index 0000000000..baf2461262 --- /dev/null +++ b/common/utils/hashtable/tests/CMakeLists.txt @@ -0,0 +1,5 @@ +add_executable(test_hashtable test_hashtable.cpp) +add_dependencies(tests test_hashtable) +target_link_libraries(test_hashtable PRIVATE HASHTABLE GTest::gtest) +add_test(NAME test_hashtable + COMMAND ./test_hashtable) diff --git a/common/utils/hashtable/tests/test_hashtable.cpp b/common/utils/hashtable/tests/test_hashtable.cpp new file mode 100644 index 0000000000..aa63caa331 --- /dev/null +++ b/common/utils/hashtable/tests/test_hashtable.cpp @@ -0,0 +1,106 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include +extern "C" { +#include "hashtable.h" +} + +TEST(hashtable, test_insert_remove) { + hash_table_t* table = hashtable_create(250, NULL, NULL); + int* a = (int*)calloc(1, sizeof(*a)); + EXPECT_EQ(hashtable_insert(table, 1, a), HASH_TABLE_OK); + EXPECT_EQ(hashtable_remove(table, 1), HASH_TABLE_OK); + EXPECT_EQ(hashtable_destroy(&table), HASH_TABLE_OK); +} + +TEST(hashtable, test_insert_iterate_remove) { + hash_table_t* table = hashtable_create(250, NULL, NULL); + int* a = (int*)calloc(1, sizeof(*a)); + EXPECT_EQ(hashtable_insert(table, 1, a), HASH_TABLE_OK); + auto iterator = hashtable_get_iterator(table); + void* ptr; + int num_items = 0; + while(hashtable_iterator_getnext(&iterator, &ptr)) { + num_items++; + } + EXPECT_EQ(num_items, 1); + EXPECT_EQ(hashtable_remove(table, 1), HASH_TABLE_OK); + num_items = 0; + + auto iterator2 = hashtable_get_iterator(table); + while(hashtable_iterator_getnext(&iterator2, &ptr)) { + num_items++; + } + EXPECT_EQ(num_items, 0); + EXPECT_EQ(hashtable_destroy(&table), HASH_TABLE_OK); +} + +TEST(hashtable, test_insert_three_iterate_remove) { + hash_table_t* table = hashtable_create(250, NULL, NULL); + int* a1 = (int*)calloc(1, sizeof(*a1)); + int* a2 = (int*)calloc(1, sizeof(*a2)); + int* a3 = (int*)calloc(1, sizeof(*a3)); + EXPECT_EQ(hashtable_insert(table, 1, a1), HASH_TABLE_OK); + EXPECT_EQ(hashtable_insert(table, 2, a2), HASH_TABLE_OK); + EXPECT_EQ(hashtable_insert(table, 3, a3), HASH_TABLE_OK); + auto iterator = hashtable_get_iterator(table); + void* ptr; + int num_items = 0; + while(hashtable_iterator_getnext(&iterator, &ptr)) { + num_items++; + } + EXPECT_EQ(num_items, 3); + EXPECT_EQ(hashtable_remove(table, 1), HASH_TABLE_OK); + num_items = 0; + + auto iterator2 = hashtable_get_iterator(table); + while(hashtable_iterator_getnext(&iterator2, &ptr)) { + num_items++; + } + EXPECT_EQ(num_items, 2); + EXPECT_EQ(hashtable_destroy(&table), HASH_TABLE_OK); +} + +TEST(hashtable, test_insert_empty_insert_interate) { + hash_table_t* table = hashtable_create(250, NULL, NULL); + int* a = (int*)calloc(1, sizeof(*a)); + EXPECT_EQ(hashtable_insert(table, 1, a), HASH_TABLE_OK); + EXPECT_EQ(hashtable_remove(table, 1), HASH_TABLE_OK); + + int* a2 = (int*)calloc(1, sizeof(*a2)); + EXPECT_EQ(hashtable_insert(table, 1, a2), HASH_TABLE_OK); + auto iterator3 = hashtable_get_iterator(table); + int num_items = 0; + void* ptr; + while(hashtable_iterator_getnext(&iterator3, &ptr)) { + num_items++; + } + EXPECT_EQ(num_items, 1); + + EXPECT_EQ(hashtable_destroy(&table), HASH_TABLE_OK); +} + +int main(int argc, char** argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} From 883333bfe634bde5f32052a32921334a84e56bf4 Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Fri, 11 Oct 2024 10:57:10 +0200 Subject: [PATCH 26/75] Use hashtable for mapping FDs to buffer_ts in rfsimulator. Use hashtable for determining which buffer_t does a sock map to. This lifts the restriction for number of FDs used by applications using rfsimulator. --- radio/rfsimulator/CMakeLists.txt | 2 +- radio/rfsimulator/simulator.c | 73 ++++++++++++++++++++++++++------ 2 files changed, 62 insertions(+), 13 deletions(-) diff --git a/radio/rfsimulator/CMakeLists.txt b/radio/rfsimulator/CMakeLists.txt index efba710bad..61b053a1ce 100644 --- a/radio/rfsimulator/CMakeLists.txt +++ b/radio/rfsimulator/CMakeLists.txt @@ -3,7 +3,7 @@ add_library(rfsimulator MODULE apply_channelmod.c ../../openair1/PHY/TOOLS/signal_energy.c ) -target_link_libraries(rfsimulator PRIVATE SIMU) +target_link_libraries(rfsimulator PRIVATE SIMU HASHTABLE) set_target_properties(rfsimulator PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) add_executable(replay_node stored_node.c) diff --git a/radio/rfsimulator/simulator.c b/radio/rfsimulator/simulator.c index 3c19b492c8..d362d5ef7b 100644 --- a/radio/rfsimulator/simulator.c +++ b/radio/rfsimulator/simulator.c @@ -50,6 +50,7 @@ #define CHANNELMOD_DYNAMICLOAD #include #include "rfsimulator.h" +#include "hashtable.h" #define PORT 4043 //default TCP port for this simulator // @@ -82,6 +83,8 @@ // Until a convenient management is implemented, the MAX_FD_RFSIMU is used everywhere (instead of // FD_SETSIE) and reduced to 125. This should allow for around 20 simultaeous UEs. // +// An indirection level via hashtable was added to allow the software to use FDs above MAX_FD_RFSIMU. +// // #define MAX_FD_RFSIMU FD_SETSIZE #define MAX_FD_RFSIMU 250 #define SEND_BUFF_SIZE 100000000 // Socket buffer size @@ -162,6 +165,9 @@ typedef struct { uint16_t port; int saveIQfile; buffer_t buf[MAX_FD_RFSIMU]; + int next_buf; + // Hashtable used as an indirection level between file descriptor and the buf array + hash_table_t *fd_to_buf_map; int rx_num_channels; int tx_num_channels; double sample_rate; @@ -178,11 +184,38 @@ typedef struct { double prop_delay_ms; } rfsimulator_state_t; + +static buffer_t *get_buff_from_socket(rfsimulator_state_t *simulator_state, int socket) +{ + uint64_t buffer_index; + if (hashtable_get(simulator_state->fd_to_buf_map, socket, (void **)&buffer_index) == HASH_TABLE_OK) { + return &simulator_state->buf[buffer_index]; + } else { + return NULL; + } +} + +static void add_buff_to_socket_mapping(rfsimulator_state_t *simulator_state, int socket, uint64_t buff_index) +{ + hashtable_rc_t rc = hashtable_insert(simulator_state->fd_to_buf_map, socket, (void *)buff_index); + AssertFatal(rc == HASH_TABLE_OK, + "%s sock = %d\n", + rc == HASH_TABLE_INSERT_OVERWRITTEN_DATA ? "Duplicate entry in hashtable" : "Hashtable is not allocated", + socket); +} + +static void remove_buff_to_socket_mapping(rfsimulator_state_t *simulator_state, int socket) +{ + // Failure is fine here + hashtable_remove(simulator_state->fd_to_buf_map, socket); +} + static int allocCirBuf(rfsimulator_state_t *bridge, int sock) { /* TODO: cleanup code so that this AssertFatal becomes useless */ AssertFatal(sock >= 0 && sock < sizeofArray(bridge->buf), "socket %d is not in range\n", sock); - buffer_t *ptr=&bridge->buf[sock]; + uint64_t buff_index = bridge->next_buf++ % MAX_FD_RFSIMU; + buffer_t *ptr=&bridge->buf[buff_index]; ptr->circularBuf = calloc(1, sampleToByte(CirSize, 1)); if (ptr->circularBuf == NULL) { LOG_E(HW, "malloc(%lu) failed\n", sampleToByte(CirSize, 1)); @@ -235,6 +268,7 @@ static int allocCirBuf(rfsimulator_state_t *bridge, int sock) random_channel(ptr->channel_model,false); LOG_I(HW, "Random channel %s in rfsimulator activated\n", modelname); } + add_buff_to_socket_mapping(bridge, sock, buff_index); return 0; } @@ -243,17 +277,23 @@ static void removeCirBuf(rfsimulator_state_t *bridge, int sock) { LOG_E(HW, "epoll_ctl(EPOLL_CTL_DEL) failed\n"); } close(sock); - free(bridge->buf[sock].circularBuf); - // Fixme: no free_channel_desc_scm(bridge->buf[sock].channel_model) implemented - // a lot of mem leaks - //free(bridge->buf[sock].channel_model); - memset(&bridge->buf[sock], 0, sizeof(buffer_t)); - bridge->buf[sock].conn_sock=-1; - nb_ue--; + buffer_t* buf = get_buff_from_socket(bridge, sock); + if (buf) { + free(buf->circularBuf); + // Fixme: no free_channel_desc_scm(bridge->buf[sock].channel_model) implemented + // a lot of mem leaks + //free(bridge->buf[sock].channel_model); + memset(buf, 0, sizeof(buffer_t)); + buf->conn_sock=-1; + remove_buff_to_socket_mapping(bridge, sock); + nb_ue--; + } } static void socketError(rfsimulator_state_t *bridge, int sock) { - if (bridge->buf[sock].conn_sock!=-1) { + buffer_t* buf = get_buff_from_socket(bridge, sock); + if (!buf) return; + if (buf->conn_sock != -1) { LOG_W(HW, "Lost socket\n"); removeCirBuf(bridge, sock); @@ -789,7 +829,7 @@ static bool flushInput(rfsimulator_state_t *t, int timeout, int nsamps_for_initi rfsimulator_write_internal(t, t->lastWroteTS > 1 ? t->lastWroteTS - 1 : 0, samplesVoid, 1, t->tx_num_channels, 1, false); - buffer_t *b = &t->buf[conn_sock]; + buffer_t *b = get_buff_from_socket(t, conn_sock); if (b->channel_model) b->channel_model->start_TS = t->lastWroteTS; } else { @@ -798,8 +838,8 @@ static bool flushInput(rfsimulator_state_t *t, int timeout, int nsamps_for_initi continue; } - buffer_t *b=&t->buf[fd]; - + buffer_t *b = get_buff_from_socket(t, fd); + if (!b) continue; if ( b->circularBuf == NULL ) { LOG_E(HW, "Received data on not connected socket %d\n", events[nbEv].data.fd); continue; @@ -1044,6 +1084,7 @@ static void rfsimulator_end(openair0_device *device) { removeCirBuf(s, b->conn_sock); } close(s->epollfd); + hashtable_destroy(&s->fd_to_buf_map); } static int rfsimulator_stop(openair0_device *device) { return 0; @@ -1059,6 +1100,12 @@ static int rfsimulator_set_gains(openair0_device *device, openair0_config_t *ope static int rfsimulator_write_init(openair0_device *device) { return 0; } + +void do_not_free_integer(void *integer) +{ + (void)integer; +} + __attribute__((__visibility__("default"))) int device_init(openair0_device *device, openair0_config_t *openair0_cfg) { // to change the log level, use this on command line @@ -1104,6 +1151,8 @@ int device_init(openair0_device *device, openair0_config_t *openair0_cfg) { for (int i = 0; i < MAX_FD_RFSIMU; i++) rfsimulator->buf[i].conn_sock=-1; + rfsimulator->next_buf = 0; + rfsimulator->fd_to_buf_map = hashtable_create(MAX_FD_RFSIMU, NULL, do_not_free_integer); AssertFatal((rfsimulator->epollfd = epoll_create1(0)) != -1, "epoll_create1() failed, errno(%d)", errno); // we need to call randominit() for telnet server (use gaussdouble=>uniformrand) From 7c13c790d71136aef12f99caf040c3aa8037b4d1 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 24 Oct 2024 09:12:54 +0200 Subject: [PATCH 27/75] Bugfix: Fill QFI for N3 GTP messages Instead of hardcoding to 0, instruct the GTP module to send N3 GTP packets with the right GTP. We currently only support one QoS Flow, so check that it is really only one. --- openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c index 0cccdbcb6c..e0ac130279 100644 --- a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c +++ b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c @@ -157,6 +157,7 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req) AssertFatal(req_pdu->numDRB2Setup == 1, "can only handle one DRB per PDU session\n"); resp_pdu->numDRBSetup = req_pdu->numDRB2Setup; const DRB_nGRAN_to_setup_t *req_drb = &req_pdu->DRBnGRanList[0]; + AssertFatal(req_drb->numQosFlow2Setup == 1, "can only handle one QoS Flow per DRB\n"); DRB_nGRAN_setup_t *resp_drb = &resp_pdu->DRBnGRanList[0]; resp_drb->id = req_drb->id; resp_drb->numQosFlowSetup = req_drb->numQosFlow2Setup; @@ -168,7 +169,7 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req) // GTP tunnel for N3/to core gtpv1u_gnb_create_tunnel_resp_t resp_n3 = {0}; - int qfi = 0; // put PDU session marker + int qfi = req_drb->qosFlows[0].qfi; int ret = drb_gtpu_create(n3inst, cu_up_ue_id, req_drb->id, From 3add5761955747e7c87a3d67c92df0082f512a27 Mon Sep 17 00:00:00 2001 From: francescomani Date: Thu, 17 Oct 2024 14:56:37 +0200 Subject: [PATCH 28/75] remove use of VRB map bitwise not in dlsch and ulsch preprocessor --- .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 26 +++++++------------ .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 22 ++++++++-------- 2 files changed, 21 insertions(+), 27 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index af2a2b24e7..7314ff32d7 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -477,7 +477,7 @@ static bool allocate_dl_retransmission(module_id_t module_id, rbSize = 0; const uint16_t slbitmap = SL_to_bitmap(retInfo->tda_info.startSymbolIndex, retInfo->tda_info.nrOfSymbols); - while (rbStart < rbStop && (rballoc_mask[rbStart] & slbitmap) != slbitmap) + while (rbStart < rbStop && (rballoc_mask[rbStart] & slbitmap)) rbStart++; if (rbStart >= rbStop) { @@ -488,9 +488,7 @@ static bool allocate_dl_retransmission(module_id_t module_id, return false; } - while (rbStart + rbSize <= rbStop && - (rballoc_mask[rbStart + rbSize] & slbitmap) == slbitmap && - rbSize < retInfo->rbSize) + while (rbStart + rbSize <= rbStop && !(rballoc_mask[rbStart + rbSize] & slbitmap) && rbSize < retInfo->rbSize) rbSize++; } } else { @@ -502,10 +500,10 @@ static bool allocate_dl_retransmission(module_id_t module_id, layers); const uint16_t slbitmap = SL_to_bitmap(temp_tda.startSymbolIndex, temp_tda.nrOfSymbols); - while (rbStart < rbStop && (rballoc_mask[rbStart] & slbitmap) != slbitmap) + while (rbStart < rbStop && (rballoc_mask[rbStart] & slbitmap)) rbStart++; - while (rbStart + rbSize <= rbStop && (rballoc_mask[rbStart + rbSize] & slbitmap) == slbitmap) + while (rbStart + rbSize <= rbStop && !(rballoc_mask[rbStart + rbSize] & slbitmap)) rbSize++; uint32_t new_tbs; @@ -594,7 +592,7 @@ static bool allocate_dl_retransmission(module_id_t module_id, *n_rb_sched -= sched_ctrl->sched_pdsch.rbSize; for (int rb = 0; rb < sched_ctrl->sched_pdsch.rbSize; rb++) - rballoc_mask[rb + sched_ctrl->sched_pdsch.rbStart] ^= SL_to_bitmap(retInfo->tda_info.startSymbolIndex, retInfo->tda_info.nrOfSymbols); + rballoc_mask[rb + sched_ctrl->sched_pdsch.rbStart] |= SL_to_bitmap(retInfo->tda_info.startSymbolIndex, retInfo->tda_info.nrOfSymbols); return true; } @@ -810,12 +808,12 @@ static void pf_dl(module_id_t module_id, int rbStart = 0; get_start_stop_allocation(mac, iterator->UE, &rbStart, &rbStop); // Freq-demain allocation - while (rbStart < rbStop && (rballoc_mask[rbStart] & slbitmap) != slbitmap) + while (rbStart < rbStop && (rballoc_mask[rbStart] & slbitmap)) rbStart++; uint16_t max_rbSize = 1; - while (rbStart + max_rbSize <= rbStop && (rballoc_mask[rbStart + max_rbSize] & slbitmap) == slbitmap) + while (rbStart + max_rbSize <= rbStop && !(rballoc_mask[rbStart + max_rbSize] & slbitmap)) max_rbSize++; sched_pdsch->dmrs_parms = get_dl_dmrs_params(scc, @@ -851,7 +849,7 @@ static void pf_dl(module_id_t module_id, n_rb_sched -= sched_pdsch->rbSize; for (int rb = 0; rb < sched_pdsch->rbSize; rb++) - rballoc_mask[rb + sched_pdsch->rbStart] ^= slbitmap; + rballoc_mask[rb + sched_pdsch->rbStart] |= slbitmap; remainUEs--; iterator++; @@ -891,14 +889,10 @@ static void nr_fr1_dlsch_preprocessor(module_id_t module_id, frame_t frame, sub_ int n_rb_sched = 0; for (int i = 0; i < bwpSize; i++) { - // calculate mask: init with "NOT" vrb_map: - // if any RB in vrb_map is blocked (1), the current RBG will be 0 - rballoc_mask[i] = (~vrb_map[i+BWPStart])&0x3fff; //bitwise not and 14 symbols - + rballoc_mask[i] = vrb_map[i + BWPStart]; // if all the pdsch symbols are free - if ((rballoc_mask[i]&slbitmap) == slbitmap) { + if (!(rballoc_mask[i] & slbitmap)) n_rb_sched++; - } } /* Retrieve amount of data to send for this UE */ diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 4599349a04..84d80bc930 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -1655,7 +1655,7 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac, if (reuse_old_tda && nrOfLayers == retInfo->nrOfLayers) { /* Check the resource is enough for retransmission */ const uint16_t slbitmap = SL_to_bitmap(retInfo->tda_info.startSymbolIndex, retInfo->tda_info.nrOfSymbols); - while (rbStart < bwpSize && (rballoc_mask[rbStart] & slbitmap) != slbitmap) + while (rbStart < bwpSize && (rballoc_mask[rbStart] & slbitmap)) rbStart++; if (rbStart + retInfo->rbSize > bwpSize) { LOG_D(NR_MAC, "[UE %04x][%4d.%2d] could not allocate UL retransmission: no resources (rbStart %d, retInfo->rbSize %d, bwpSize %d) \n", @@ -1676,10 +1676,10 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac, /* the retransmission will use a different time domain allocation, check * that we have enough resources */ const uint16_t slbitmap = SL_to_bitmap(tda_info.startSymbolIndex, tda_info.nrOfSymbols); - while (rbStart < bwpSize && (rballoc_mask[rbStart] & slbitmap) != slbitmap) + while (rbStart < bwpSize && (rballoc_mask[rbStart] & slbitmap)) rbStart++; int rbSize = 0; - while (rbStart + rbSize < bwpSize && (rballoc_mask[rbStart + rbSize] & slbitmap) == slbitmap) + while (rbStart + rbSize < bwpSize && !(rballoc_mask[rbStart + rbSize] & slbitmap)) rbSize++; uint32_t new_tbs; uint16_t new_rbSize; @@ -1762,7 +1762,7 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac, /* Mark the corresponding RBs as used */ n_rb_sched -= sched_pusch->rbSize; for (int rb = 0; rb < sched_ctrl->sched_pusch.rbSize; rb++) - rballoc_mask[rb + sched_ctrl->sched_pusch.rbStart] ^= SL_to_bitmap(sched_pusch->tda_info.startSymbolIndex, sched_pusch->tda_info.nrOfSymbols); + rballoc_mask[rb + sched_ctrl->sched_pusch.rbStart] |= SL_to_bitmap(sched_pusch->tda_info.startSymbolIndex, sched_pusch->tda_info.nrOfSymbols); return true; } @@ -1907,7 +1907,7 @@ static void pf_ul(module_id_t module_id, LOG_D(NR_MAC,"Looking for min_rb %d RBs, starting at %d num_dmrs_cdm_grps_no_data %d\n", min_rb, rbStart, sched_pusch->dmrs_info.num_dmrs_cdm_grps_no_data); const uint16_t slbitmap = SL_to_bitmap(sched_pusch->tda_info.startSymbolIndex, sched_pusch->tda_info.nrOfSymbols); - while (rbStart < bwpSize && (rballoc_mask[rbStart] & slbitmap) != slbitmap) + while (rbStart < bwpSize && (rballoc_mask[rbStart] & slbitmap)) rbStart++; if (rbStart + min_rb >= bwpSize) { LOG_D(NR_MAC, "[UE %04x][%4d.%2d] could not allocate continuous UL data: no resources (rbStart %d, min_rb %d, bwpSize %d)\n", @@ -1964,7 +1964,7 @@ static void pf_ul(module_id_t module_id, /* Mark the corresponding RBs as used */ n_rb_sched -= sched_pusch->rbSize; for (int rb = 0; rb < sched_ctrl->sched_pusch.rbSize; rb++) - rballoc_mask[rb + sched_ctrl->sched_pusch.rbStart] ^= slbitmap; + rballoc_mask[rb + sched_ctrl->sched_pusch.rbStart] |= slbitmap; remainUEs--; continue; @@ -2033,11 +2033,11 @@ static void pf_ul(module_id_t module_id, int rbStart = 0; const uint16_t slbitmap = SL_to_bitmap(sched_pusch->tda_info.startSymbolIndex, sched_pusch->tda_info.nrOfSymbols); const uint16_t bwpSize = current_BWP->BWPSize; - while (rbStart < bwpSize && (rballoc_mask[rbStart] & slbitmap) != slbitmap) + while (rbStart < bwpSize && (rballoc_mask[rbStart] & slbitmap)) rbStart++; sched_pusch->rbStart = rbStart; uint16_t max_rbSize = 1; - while (rbStart + max_rbSize < bwpSize && (rballoc_mask[rbStart + max_rbSize] & slbitmap) == slbitmap) + while (rbStart + max_rbSize < bwpSize && !(rballoc_mask[rbStart + max_rbSize] & slbitmap)) max_rbSize++; if (rbStart + min_rb >= bwpSize || max_rbSize < min_rb) { @@ -2109,7 +2109,7 @@ static void pf_ul(module_id_t module_id, n_rb_sched -= sched_pusch->rbSize; for (int rb = 0; rb < sched_ctrl->sched_pusch.rbSize; rb++) - rballoc_mask[rb + sched_ctrl->sched_pusch.rbStart] ^= slbitmap; + rballoc_mask[rb + sched_ctrl->sched_pusch.rbStart] |= slbitmap; /* reduce max_num_ue once we are sure UE can be allocated, i.e., has CCE */ remainUEs--; @@ -2202,8 +2202,8 @@ static bool nr_fr1_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_ uint16_t rballoc_mask[bwpSize]; /* Calculate mask: if any RB in vrb_map_UL is blocked (1), the current RB will be 0 */ - for (int i = 0; i < bwpSize; i++) - rballoc_mask[i] = (i >= st && i <= e)*SL_to_bitmap(startSymbolIndex, nrOfSymbols); + for (int i = st; i < e; i++) + rballoc_mask[i] = vrb_map_UL[bwpStart + i]; int bw = scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth; int average_agg_level = 4; // TODO find a better estimation From 38a05d8aada1847e499e87ce5430b7df985fe5bd Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 25 Sep 2024 15:40:35 +0200 Subject: [PATCH 29/75] making DLSCH preprocessor agnostic to UEs BWP and TDA --- openair1/PHY/NR_TRANSPORT/nr_dlsch.c | 4 +- .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 167 +++++++----------- 2 files changed, 63 insertions(+), 108 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c index a1b9b5b283..321ff3028b 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c @@ -250,8 +250,8 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx, int frame, int slot) NR_DL_FRAME_PARMS *fp = &gNB->frame_parms; const uint32_t *gold = nr_gold_pdsch(fp->N_RB_DL, fp->symbols_per_slot, rel15->dlDmrsScramblingId, rel15->SCID, slot, l_symbol); - nr_modulation(gold, n_dmrs * DMRS_MOD_ORDER, DMRS_MOD_ORDER, - (int16_t *)mod_dmrs); // Qm = 2 as DMRS is QPSK modulated + // Qm = 2 as DMRS is QPSK modulated + nr_modulation(gold, n_dmrs * DMRS_MOD_ORDER, DMRS_MOD_ORDER, (int16_t *)mod_dmrs); #ifdef DEBUG_DLSCH printf("DMRS modulation (symbol %d, %d symbols, type %d):\n", l_symbol, n_dmrs, dmrs_Type); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 7314ff32d7..5faa5d3c13 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -52,8 +52,8 @@ #define WORD 32 //#define SIZE_OF_POINTER sizeof (void *) -int get_dl_tda(const gNB_MAC_INST *nrmac, const NR_ServingCellConfigCommon_t *scc, int slot) { - +int get_dl_tda(const gNB_MAC_INST *nrmac, const NR_ServingCellConfigCommon_t *scc, int slot) +{ /* we assume that this function is mutex-protected from outside */ const NR_TDD_UL_DL_Pattern_t *tdd = scc->tdd_UL_DL_ConfigurationCommon ? &scc->tdd_UL_DL_ConfigurationCommon->pattern1 : NULL; AssertFatal(tdd || nrmac->common_channels->frame_type == FDD, "Dynamic TDD not handled yet\n"); @@ -390,10 +390,12 @@ void abort_nr_dl_harq(NR_UE_info_t* UE, int8_t harq_pid) UE->mac_stats.dl.errors++; } -static void get_start_stop_allocation(gNB_MAC_INST *mac, - NR_UE_info_t *UE, - int *rbStart, - int *rbStop) +typedef struct { + int bwpStart; + int bwpSize; +} dl_bwp_info_t; + +static dl_bwp_info_t get_bwp_start_size(gNB_MAC_INST *mac, NR_UE_info_t *UE) { NR_UE_DL_BWP_t *dl_bwp = &UE->current_DL_BWP; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; @@ -402,25 +404,28 @@ static void get_start_stop_allocation(gNB_MAC_INST *mac, // in which case the size of CORESET 0 shall be used if CORESET 0 is configured for the cell // and the size of initial DL bandwidth part shall be used if CORESET 0 is not configured for the cell. // TS 38.214 Section 5.1.2.2.2 - *rbStop = dl_bwp->BWPSize - 1; - *rbStart = 0; // start wrt BWPstart + dl_bwp_info_t bwp_info; + bwp_info.bwpSize = dl_bwp->BWPSize; + bwp_info.bwpStart = dl_bwp->BWPStart; if (sched_ctrl->search_space->searchSpaceType->present == NR_SearchSpace__searchSpaceType_PR_common && dl_bwp->dci_format == NR_DL_DCI_FORMAT_1_0) { if (mac->cset0_bwp_size != 0) { - *rbStart = mac->cset0_bwp_start; - *rbStop = *rbStart + mac->cset0_bwp_size - 1; + bwp_info.bwpStart = mac->cset0_bwp_start; + bwp_info.bwpSize = mac->cset0_bwp_size; } else { - *rbStart = UE->sc_info.initial_dl_BWPStart; - *rbStop = *rbStart + UE->sc_info.initial_dl_BWPSize - 1; + // TODO this is not entirely correct + // start would be the start of CORESET not of the initial BWP + bwp_info.bwpStart = UE->sc_info.initial_dl_BWPStart; + bwp_info.bwpSize = UE->sc_info.initial_dl_BWPSize; } } + return bwp_info; } static bool allocate_dl_retransmission(module_id_t module_id, frame_t frame, sub_frame_t slot, - uint16_t *rballoc_mask, int *n_rb_sched, NR_UE_info_t *UE, int current_harq_pid) @@ -442,12 +447,6 @@ static bool allocate_dl_retransmission(module_id_t module_id, int pm_index = (curInfo->nrOfLayers < retInfo->nrOfLayers) ? curInfo->pm_index : retInfo->pm_index; const int coresetid = sched_ctrl->coreset->controlResourceSetId; - - int rbStop = 0; - int rbStart = 0; - get_start_stop_allocation(nr_mac, UE, &rbStart, &rbStop); - - int rbSize = 0; const int tda = get_dl_tda(nr_mac, scc, slot); AssertFatal(tda>=0,"Unable to find PDSCH time domain allocation in list\n"); @@ -470,6 +469,14 @@ static bool allocate_dl_retransmission(module_id_t module_id, reuse_old_tda ? "reuse" : "do not reuse", layers == retInfo->nrOfLayers ? "same" : "different"); + // TODO assuming beam 0 for now + uint16_t *rballoc_mask = nr_mac->common_channels[CC_id].vrb_map[0]; + + dl_bwp_info_t bwp_info = get_bwp_start_size(nr_mac, UE); + int rbStart = bwp_info.bwpStart; + int rbStop = bwp_info.bwpStart + bwp_info.bwpSize - 1; + int rbSize = 0; + if (reuse_old_tda && layers == retInfo->nrOfLayers) { /* Check that there are enough resources for retransmission */ while (rbSize < retInfo->rbSize) { @@ -481,23 +488,17 @@ static bool allocate_dl_retransmission(module_id_t module_id, rbStart++; if (rbStart >= rbStop) { - LOG_D(NR_MAC, "[UE %04x][%4d.%2d] could not allocate DL retransmission: no resources\n", - UE->rnti, - frame, - slot); + LOG_D(NR_MAC, "[UE %04x][%4d.%2d] could not allocate DL retransmission: no resources\n", UE->rnti, frame, slot); return false; } - while (rbStart + rbSize <= rbStop && !(rballoc_mask[rbStart + rbSize] & slbitmap) && rbSize < retInfo->rbSize) + while (rbStart + rbSize <= rbStop && !(rballoc_mask[rbStart + rbSize] & slbitmap) && rbSize < retInfo->rbSize) rbSize++; } } else { /* the retransmission will use a different time domain allocation, check * that we have enough resources */ - NR_pdsch_dmrs_t temp_dmrs = get_dl_dmrs_params(scc, - dl_bwp, - &temp_tda, - layers); + NR_pdsch_dmrs_t temp_dmrs = get_dl_dmrs_params(scc, dl_bwp, &temp_tda, layers); const uint16_t slbitmap = SL_to_bitmap(temp_tda.startSymbolIndex, temp_tda.nrOfSymbols); while (rbStart < rbStop && (rballoc_mask[rbStart] & slbitmap)) @@ -546,7 +547,9 @@ static bool allocate_dl_retransmission(module_id_t module_id, /* Find a free CCE */ int CCEIndex = get_cce_index(nr_mac, - CC_id, slot, UE->rnti, + CC_id, + slot, + UE->rnti, &sched_ctrl->aggregation_level, beam, sched_ctrl->search_space, @@ -554,10 +557,7 @@ static bool allocate_dl_retransmission(module_id_t module_id, &sched_ctrl->sched_pdcch, false); if (CCEIndex<0) { - LOG_D(NR_MAC, "[UE %04x][%4d.%2d] could not find free CCE for DL DCI retransmission\n", - UE->rnti, - frame, - slot); + LOG_D(NR_MAC, "[UE %04x][%4d.%2d] could not find free CCE for DL DCI retransmission\n", UE->rnti, frame, slot); return false; } @@ -569,30 +569,27 @@ static bool allocate_dl_retransmission(module_id_t module_id, int r_pucch = nr_get_pucch_resource(sched_ctrl->coreset, ul_bwp->pucch_Config, CCEIndex); alloc = nr_acknack_scheduling(nr_mac, UE, frame, slot, beam, r_pucch, 0); if (alloc < 0) { - LOG_D(NR_MAC, "[UE %04x][%4d.%2d] could not find PUCCH for DL DCI retransmission\n", - UE->rnti, - frame, - slot); + LOG_D(NR_MAC, "[UE %04x][%4d.%2d] could not find PUCCH for DL DCI retransmission\n", UE->rnti, frame, slot); return false; } } sched_ctrl->cce_index = CCEIndex; fill_pdcch_vrb_map(nr_mac, - /* CC_id = */ 0, + CC_id, &sched_ctrl->sched_pdcch, CCEIndex, sched_ctrl->aggregation_level, beam); /* just reuse from previous scheduling opportunity, set new start RB */ sched_ctrl->sched_pdsch = *retInfo; - sched_ctrl->sched_pdsch.rbStart = rbStart; + sched_ctrl->sched_pdsch.rbStart = rbStart - bwp_info.bwpStart; sched_ctrl->sched_pdsch.pucch_allocation = alloc; /* retransmissions: directly allocate */ *n_rb_sched -= sched_ctrl->sched_pdsch.rbSize; - for (int rb = 0; rb < sched_ctrl->sched_pdsch.rbSize; rb++) - rballoc_mask[rb + sched_ctrl->sched_pdsch.rbStart] |= SL_to_bitmap(retInfo->tda_info.startSymbolIndex, retInfo->tda_info.nrOfSymbols); + for (int rb = rbStart; rb < sched_ctrl->sched_pdsch.rbSize; rb++) + rballoc_mask[rb] |= SL_to_bitmap(retInfo->tda_info.startSymbolIndex, retInfo->tda_info.nrOfSymbols); return true; } @@ -612,8 +609,7 @@ static void pf_dl(module_id_t module_id, sub_frame_t slot, NR_UE_info_t **UE_list, int max_num_ue, - int n_rb_sched, - uint16_t *rballoc_mask) + int n_rb_sched) { gNB_MAC_INST *mac = RC.nrmac[module_id]; NR_ServingCellConfigCommon_t *scc=mac->common_channels[0].ServingCellConfigCommon; @@ -649,7 +645,7 @@ static void pf_dl(module_id_t module_id, /* retransmission */ if (sched_pdsch->dl_harq_pid >= 0) { /* Allocate retransmission */ - bool r = allocate_dl_retransmission(module_id, frame, slot, rballoc_mask, &n_rb_sched, UE, sched_pdsch->dl_harq_pid); + bool r = allocate_dl_retransmission(module_id, frame, slot, &n_rb_sched, UE, sched_pdsch->dl_harq_pid); if (!r) { LOG_D(NR_MAC, "[UE %04x][%4d.%2d] DL retransmission could not be allocated\n", @@ -744,7 +740,9 @@ static void pf_dl(module_id_t module_id, int beam = 0; int CCEIndex = get_cce_index(mac, - CC_id, slot, iterator->UE->rnti, + CC_id, + slot, + iterator->UE->rnti, &sched_ctrl->aggregation_level, beam, sched_ctrl->search_space, @@ -778,12 +776,7 @@ static void pf_dl(module_id_t module_id, } sched_ctrl->cce_index = CCEIndex; - fill_pdcch_vrb_map(mac, - /* CC_id = */ 0, - &sched_ctrl->sched_pdcch, - CCEIndex, - sched_ctrl->aggregation_level, - beam); + fill_pdcch_vrb_map(mac, CC_id, &sched_ctrl->sched_pdcch, CCEIndex, sched_ctrl->aggregation_level, beam); /* MCS has been set above */ sched_pdsch->time_domain_allocation = get_dl_tda(mac, scc, slot); @@ -804,22 +797,22 @@ static void pf_dl(module_id_t module_id, const uint16_t slbitmap = SL_to_bitmap(tda_info->startSymbolIndex, tda_info->nrOfSymbols); - int rbStop = 0; - int rbStart = 0; - get_start_stop_allocation(mac, iterator->UE, &rbStart, &rbStop); + // TODO assuming beam 0 for now + uint16_t *rballoc_mask = mac->common_channels[CC_id].vrb_map[0]; + dl_bwp_info_t bwp_info = get_bwp_start_size(mac, iterator->UE); + int rbStart = 0; // WRT BWP start + int rbStop = bwp_info.bwpSize - 1; + int bwp_start = bwp_info.bwpStart; // Freq-demain allocation - while (rbStart < rbStop && (rballoc_mask[rbStart] & slbitmap)) + while (rbStart < rbStop && (rballoc_mask[rbStart + bwp_start] & slbitmap)) rbStart++; uint16_t max_rbSize = 1; - while (rbStart + max_rbSize <= rbStop && !(rballoc_mask[rbStart + max_rbSize] & slbitmap)) + while (rbStart + max_rbSize <= rbStop && !(rballoc_mask[rbStart + max_rbSize + bwp_start] & slbitmap)) max_rbSize++; - sched_pdsch->dmrs_parms = get_dl_dmrs_params(scc, - dl_bwp, - tda_info, - sched_pdsch->nrOfLayers); + sched_pdsch->dmrs_parms = get_dl_dmrs_params(scc, dl_bwp, tda_info, sched_pdsch->nrOfLayers); sched_pdsch->Qm = nr_get_Qm_dl(sched_pdsch->mcs, dl_bwp->mcsTableIdx); sched_pdsch->R = nr_get_code_rate_dl(sched_pdsch->mcs, dl_bwp->mcsTableIdx); sched_pdsch->pucch_allocation = alloc; @@ -848,7 +841,7 @@ static void pf_dl(module_id_t module_id, /* transmissions: directly allocate */ n_rb_sched -= sched_pdsch->rbSize; - for (int rb = 0; rb < sched_pdsch->rbSize; rb++) + for (int rb = bwp_start; rb < sched_pdsch->rbSize; rb++) rballoc_mask[rb + sched_pdsch->rbStart] |= slbitmap; remainUEs--; @@ -864,41 +857,11 @@ static void nr_fr1_dlsch_preprocessor(module_id_t module_id, frame_t frame, sub_ return; NR_ServingCellConfigCommon_t *scc = RC.nrmac[module_id]->common_channels[0].ServingCellConfigCommon; - const int CC_id = 0; - /* Get bwpSize and TDAfrom the first UE */ - /* This is temporary and it assumes all UEs have the same BWP and TDA*/ - NR_UE_info_t *UE=UE_info->list[0]; - NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - NR_UE_DL_BWP_t *current_BWP = &UE->current_DL_BWP; - const int tda = get_dl_tda(RC.nrmac[module_id], scc, slot); - int startSymbolIndex, nrOfSymbols; - const int coresetid = sched_ctrl->coreset->controlResourceSetId; - const struct NR_PDSCH_TimeDomainResourceAllocationList *tdaList = - get_dl_tdalist(current_BWP, coresetid, sched_ctrl->search_space->searchSpaceType->present, TYPE_C_RNTI_); - AssertFatal(tda < tdaList->list.count, "time_domain_allocation %d>=%d\n", tda, tdaList->list.count); - const int startSymbolAndLength = tdaList->list.array[tda]->startSymbolAndLength; - SLIV2SL(startSymbolAndLength, &startSymbolIndex, &nrOfSymbols); - - const uint16_t bwpSize = current_BWP->BWPSize; - const uint16_t BWPStart = current_BWP->BWPStart; - - const uint16_t slbitmap = SL_to_bitmap(startSymbolIndex, nrOfSymbols); - // TODO improve handling of beam in vrb_map (for now just using 0) - uint16_t *vrb_map = RC.nrmac[module_id]->common_channels[CC_id].vrb_map[0]; - uint16_t rballoc_mask[bwpSize]; - int n_rb_sched = 0; - - for (int i = 0; i < bwpSize; i++) { - rballoc_mask[i] = vrb_map[i + BWPStart]; - // if all the pdsch symbols are free - if (!(rballoc_mask[i] & slbitmap)) - n_rb_sched++; - } + int bw = scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth; /* Retrieve amount of data to send for this UE */ nr_store_dlsch_buffer(module_id, frame, slot); - int bw = scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth; int average_agg_level = 4; // TODO find a better estimation int max_sched_ues = bw / (average_agg_level * NR_NB_REG_PER_CCE); @@ -911,8 +874,7 @@ static void nr_fr1_dlsch_preprocessor(module_id_t module_id, frame_t frame, sub_ slot, UE_info->list, max_sched_ues, - n_rb_sched, - rballoc_mask); + bw); // we set the whole BW as max number } nr_pp_impl_dl nr_init_fr1_dlsch_preprocessor(int CC_id) { @@ -1087,8 +1049,9 @@ void nr_schedule_ue_spec(module_id_t module_id, const int pduindex = gNB_mac->pdu_index[CC_id]++; pdsch_pdu->pduIndex = pduindex; - pdsch_pdu->BWPSize = current_BWP->BWPSize; - pdsch_pdu->BWPStart = current_BWP->BWPStart; + dl_bwp_info_t bwp_info = get_bwp_start_size(gNB_mac, UE); + pdsch_pdu->BWPSize = bwp_info.bwpSize; + pdsch_pdu->BWPStart = bwp_info.bwpStart; pdsch_pdu->SubcarrierSpacing = current_BWP->scs; pdsch_pdu->CyclicPrefix = current_BWP->cyclicprefix ? *current_BWP->cyclicprefix : 0; @@ -1202,17 +1165,9 @@ void nr_schedule_ue_spec(module_id_t module_id, AssertFatal(pdsch_Config == NULL || pdsch_Config->resourceAllocation == NR_PDSCH_Config__resourceAllocation_resourceAllocationType1, "Only frequency resource allocation type 1 is currently supported\n"); - - // For a PDSCH scheduled with a DCI format 1_0 in any type of PDCCH common search space, regardless of which - // bandwidth part is the active bandwidth part, RB numbering starts from the lowest RB of the CORESET in which the - // DCI was received; otherwise RB numbering starts from the lowest RB in the determined downlink bandwidth part. - // TS 38.214 Section 5.1.2.2.2 - int rbStop = 0; - int rbStart = 0; - get_start_stop_allocation(gNB_mac, UE, &rbStart, &rbStop); dci_payload.frequency_domain_assignment.val = PRBalloc_to_locationandbandwidth0(pdsch_pdu->rbSize, - pdsch_pdu->rbStart - rbStart, - rbStop - rbStart + 1); + pdsch_pdu->rbStart, + pdsch_pdu->BWPSize); dci_payload.format_indicator = 1; dci_payload.time_domain_assignment.val = sched_pdsch->time_domain_allocation; dci_payload.mcs = sched_pdsch->mcs; From 52f96fd91ba678436c713be6daa3d76b0a6c156a Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Fri, 11 Oct 2024 17:57:36 +0200 Subject: [PATCH 30/75] Complete adoption of Equality Check macros in f1ap_lib_common.c --- openair2/F1AP/lib/f1ap_interface_management.c | 3 +- openair2/F1AP/lib/f1ap_lib_common.c | 48 +++++++------------ 2 files changed, 17 insertions(+), 34 deletions(-) diff --git a/openair2/F1AP/lib/f1ap_interface_management.c b/openair2/F1AP/lib/f1ap_interface_management.c index cb0b6ab8aa..fe079faa4c 100644 --- a/openair2/F1AP/lib/f1ap_interface_management.c +++ b/openair2/F1AP/lib/f1ap_interface_management.c @@ -955,8 +955,7 @@ bool decode_f1ap_setup_failure(const F1AP_F1AP_PDU_t *pdu, f1ap_setup_failure_t */ bool eq_f1ap_setup_failure(const f1ap_setup_failure_t *a, const f1ap_setup_failure_t *b) { - if (a->transaction_id != b->transaction_id) - return false; + _F1_EQ_CHECK_INT(a->transaction_id, b->transaction_id); return true; } diff --git a/openair2/F1AP/lib/f1ap_lib_common.c b/openair2/F1AP/lib/f1ap_lib_common.c index edf48f426c..2938898aff 100644 --- a/openair2/F1AP/lib/f1ap_lib_common.c +++ b/openair2/F1AP/lib/f1ap_lib_common.c @@ -37,32 +37,24 @@ bool eq_f1ap_plmn(const f1ap_plmn_t *a, const f1ap_plmn_t *b) bool eq_f1ap_freq_info(const f1ap_nr_frequency_info_t *a, const f1ap_nr_frequency_info_t *b) { - if (a->arfcn != b->arfcn) - return false; - if (a->band != b->band) - return false; + _F1_EQ_CHECK_INT(a->arfcn, b->arfcn); + _F1_EQ_CHECK_INT(a->band, b->band); return true; } bool eq_f1ap_tx_bandwidth(const f1ap_transmission_bandwidth_t *a, const f1ap_transmission_bandwidth_t *b) { - if (a->nrb != b->nrb) - return false; - if (a->scs != b->scs) - return false; + _F1_EQ_CHECK_INT(a->nrb, b->nrb); + _F1_EQ_CHECK_INT(a->scs, b->scs); return true; } bool eq_f1ap_cell_info(const f1ap_served_cell_info_t *a, const f1ap_served_cell_info_t *b) { - if (a->nr_cellid != b->nr_cellid) - return false; - if (a->nr_pci != b->nr_pci) - return false; - if (*a->tac != *b->tac) - return false; - if (a->mode != b->mode) - return false; + _F1_EQ_CHECK_LONG(a->nr_cellid, b->nr_cellid); + _F1_EQ_CHECK_INT(a->nr_pci, b->nr_pci); + _F1_EQ_CHECK_INT(*a->tac, *b->tac); + _F1_EQ_CHECK_INT(a->mode, b->mode); if (a->mode == F1AP_MODE_TDD) { /* TDD */ if (!eq_f1ap_tx_bandwidth(&a->tdd.tbw, &b->tdd.tbw)) @@ -80,10 +72,8 @@ bool eq_f1ap_cell_info(const f1ap_served_cell_info_t *a, const f1ap_served_cell_ if (!eq_f1ap_freq_info(&a->fdd.ul_freqinfo, &b->fdd.ul_freqinfo)) return false; } - if (a->measurement_timing_config_len != b->measurement_timing_config_len) - return false; - if (*a->measurement_timing_config != *b->measurement_timing_config) - return false; + _F1_EQ_CHECK_INT(a->measurement_timing_config_len, b->measurement_timing_config_len); + _F1_EQ_CHECK_INT(*a->measurement_timing_config, *b->measurement_timing_config); if (!eq_f1ap_plmn(&a->plmn, &b->plmn)) return false; return true; @@ -92,19 +82,13 @@ bool eq_f1ap_cell_info(const f1ap_served_cell_info_t *a, const f1ap_served_cell_ bool eq_f1ap_sys_info(const f1ap_gnb_du_system_info_t *a, const f1ap_gnb_du_system_info_t *b) { /* MIB */ - if (a->mib_length != b->mib_length) - return false; - for (int i = 0; i < a->mib_length; i++) { - if (a->mib[i] != b->mib[i]) - return false; - } + _F1_EQ_CHECK_INT(a->mib_length, b->mib_length); + for (int i = 0; i < a->mib_length; i++) + _F1_EQ_CHECK_INT(a->mib[i], b->mib[i]); /* SIB1 */ - if (a->sib1_length != b->sib1_length) - return false; - for (int i = 0; i < a->sib1_length; i++) { - if (a->sib1[i] != b->sib1[i]) - return false; - } + _F1_EQ_CHECK_INT(a->sib1_length, b->sib1_length); + for (int i = 0; i < a->sib1_length; i++) + _F1_EQ_CHECK_INT(a->sib1[i], b->sib1[i]); return true; } From 46fadda22f8f0eed7ac93db98d2ece0847cda468 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Fri, 11 Oct 2024 17:58:03 +0200 Subject: [PATCH 31/75] Add license header to f1ap_lib_test.c --- openair2/F1AP/tests/f1ap_lib_test.c | 30 +++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/openair2/F1AP/tests/f1ap_lib_test.c b/openair2/F1AP/tests/f1ap_lib_test.c index 969efc5afa..046c2a463d 100644 --- a/openair2/F1AP/tests/f1ap_lib_test.c +++ b/openair2/F1AP/tests/f1ap_lib_test.c @@ -1,3 +1,33 @@ +/* + * 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 + */ + +/*! \file f1ap_lib_test.c + * \brief Test functions for F1AP encoding/decoding library + * \author Guido Casati, Robert Schmidt + * \date 2024 + * \version 0.1 + * \note + * \warning + */ + #include #include #include From a29cbf05436eaa51028147566c48aa6c94036a58 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Fri, 11 Oct 2024 18:01:27 +0200 Subject: [PATCH 32/75] Cleanup of cast in gNB_DU_name memcpy --- openair2/F1AP/tests/f1ap_lib_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/F1AP/tests/f1ap_lib_test.c b/openair2/F1AP/tests/f1ap_lib_test.c index 046c2a463d..71d2bea953 100644 --- a/openair2/F1AP/tests/f1ap_lib_test.c +++ b/openair2/F1AP/tests/f1ap_lib_test.c @@ -196,7 +196,7 @@ static void test_f1ap_setup_request(void) /* gNB_DU_name */ uint8_t *gNB_DU_name = calloc(strlen("OAI DU") + 1, sizeof(uint8_t)); AssertFatal(gNB_DU_name != NULL, "out of memory\n"); - memcpy((void *)gNB_DU_name, "OAI DU", strlen("OAI DU") + 1); + memcpy(gNB_DU_name, "OAI DU", strlen("OAI DU") + 1); /* sys_info */ uint8_t *mib = calloc(3, sizeof(uint8_t)); uint8_t *sib1 = calloc(3, sizeof(uint8_t)); From 5e5d17b05bdab441410d0556ab832d14d6cb4fab Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Wed, 16 Oct 2024 19:53:24 +0200 Subject: [PATCH 33/75] Free F1 Setup Response in the context where it was allocated --- openair2/F1AP/f1ap_du_interface_management.c | 2 ++ openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openair2/F1AP/f1ap_du_interface_management.c b/openair2/F1AP/f1ap_du_interface_management.c index 85e963ea6a..8f6114a9e5 100644 --- a/openair2/F1AP/f1ap_du_interface_management.c +++ b/openair2/F1AP/f1ap_du_interface_management.c @@ -186,6 +186,8 @@ int DU_handle_F1_SETUP_RESPONSE(instance_t instance, sctp_assoc_t assoc_id, uint } LOG_D(F1AP, "Sending F1AP_SETUP_RESP ITTI message\n"); f1_setup_response(&resp); + // free F1AP message after use + free_f1ap_setup_response(&resp); return 0; } diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c index 407e5869ce..51c655c791 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -172,8 +172,6 @@ void f1_setup_response(const f1ap_setup_resp_t *resp) AssertFatal(mac->f1_config.setup_resp != NULL, "out of memory\n"); // Copy F1AP message *mac->f1_config.setup_resp = cp_f1ap_setup_response(resp); - // free F1AP message after copy - free_f1ap_setup_response(resp); NR_SCHED_UNLOCK(&mac->sched_lock); // NOTE: Before accepting any UEs, we should initialize the UE states. From 74804f2ba35b597a9fb06277d10b4046d6d4952a Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Wed, 16 Oct 2024 19:54:45 +0200 Subject: [PATCH 34/75] Free F1 DL RRC Message Transfer after use in F1AP_CU_task --- openair2/F1AP/f1ap_cu_task.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openair2/F1AP/f1ap_cu_task.c b/openair2/F1AP/f1ap_cu_task.c index 72e3d86ea2..59e4bb29af 100644 --- a/openair2/F1AP/f1ap_cu_task.c +++ b/openair2/F1AP/f1ap_cu_task.c @@ -34,6 +34,7 @@ #include "f1ap_cu_interface_management.h" #include "f1ap_cu_rrc_message_transfer.h" #include "f1ap_cu_ue_context_management.h" +#include "lib/f1ap_rrc_message_transfer.h" #include "f1ap_cu_paging.h" #include "f1ap_cu_task.h" #include @@ -174,7 +175,7 @@ void *F1AP_CU_task(void *arg) { case F1AP_DL_RRC_MESSAGE: // from rrc CU_send_DL_RRC_MESSAGE_TRANSFER(assoc_id, &F1AP_DL_RRC_MESSAGE(received_msg)); - free(F1AP_DL_RRC_MESSAGE(received_msg).rrc_container); + free_dl_rrc_message_transfer(&F1AP_DL_RRC_MESSAGE(received_msg)); break; case F1AP_UE_CONTEXT_SETUP_REQ: // from rrc From b17f1d1b5757f5878f44ed404e4ad5cba686f250 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Wed, 16 Oct 2024 19:55:01 +0200 Subject: [PATCH 35/75] Free F1 UL RRC Message Transfer after use in F1AP_DU_task --- openair2/F1AP/f1ap_du_task.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openair2/F1AP/f1ap_du_task.c b/openair2/F1AP/f1ap_du_task.c index d221d3b35c..0d675a76e1 100644 --- a/openair2/F1AP/f1ap_du_task.c +++ b/openair2/F1AP/f1ap_du_task.c @@ -34,6 +34,7 @@ #include "f1ap_du_interface_management.h" #include "f1ap_du_ue_context_management.h" #include "f1ap_du_rrc_message_transfer.h" +#include "lib/f1ap_rrc_message_transfer.h" #include "f1ap_du_task.h" #include @@ -180,6 +181,7 @@ void *F1AP_DU_task(void *arg) { case F1AP_UL_RRC_MESSAGE: // to rrc DU_send_UL_NR_RRC_MESSAGE_TRANSFER(assoc_id, &F1AP_UL_RRC_MESSAGE(msg)); + free_ul_rrc_message_transfer(&F1AP_UL_RRC_MESSAGE(msg)); break; case F1AP_UE_CONTEXT_SETUP_RESP: From f85271a349024b1930c6588ebaead1f3e16a9c49 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Thu, 24 Oct 2024 15:55:30 +0200 Subject: [PATCH 36/75] Free F1AP messages in RRC task after processing --- openair2/RRC/NR/rrc_gNB.c | 5 ++++- openair2/RRC/NR/rrc_gNB_du.c | 2 -- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 5ab7c0ba12..e960119d81 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -98,6 +98,7 @@ #include "openair2/SDAP/nr_sdap/nr_sdap_entity.h" #include "openair2/E1AP/e1ap.h" #include "cucp_cuup_if.h" +#include "lib/f1ap_interface_management.h" #include "BIT_STRING.h" #include "assertions.h" @@ -2309,7 +2310,7 @@ void *rrc_gnb_task(void *args_p) { /* From DU -> CU */ case F1AP_UL_RRC_MESSAGE: rrc_gNB_decode_dcch(RC.nrrrc[instance], &F1AP_UL_RRC_MESSAGE(msg_p)); - free(F1AP_UL_RRC_MESSAGE(msg_p).rrc_container); + free_ul_rrc_message_transfer(&F1AP_UL_RRC_MESSAGE(msg_p)); break; case NGAP_DOWNLINK_NAS: @@ -2332,6 +2333,7 @@ void *rrc_gnb_task(void *args_p) { case F1AP_SETUP_REQ: AssertFatal(!NODE_IS_DU(RC.nrrrc[instance]->node_type), "should not receive F1AP_SETUP_REQUEST in DU!\n"); rrc_gNB_process_f1_setup_req(&F1AP_SETUP_REQ(msg_p), msg_p->ittiMsgHeader.originInstance); + free_f1ap_setup_request(&F1AP_SETUP_REQ(msg_p)); break; case F1AP_UE_CONTEXT_SETUP_RESP: @@ -2361,6 +2363,7 @@ void *rrc_gnb_task(void *args_p) { case F1AP_GNB_DU_CONFIGURATION_UPDATE: AssertFatal(!NODE_IS_DU(RC.nrrrc[instance]->node_type), "should not receive F1AP_SETUP_REQUEST in DU!\n"); rrc_gNB_process_f1_du_configuration_update(&F1AP_GNB_DU_CONFIGURATION_UPDATE(msg_p), msg_p->ittiMsgHeader.originInstance); + free_f1ap_du_configuration_update(&F1AP_GNB_DU_CONFIGURATION_UPDATE(msg_p)); break; case F1AP_GNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE: diff --git a/openair2/RRC/NR/rrc_gNB_du.c b/openair2/RRC/NR/rrc_gNB_du.c index e2806edf60..df0bf15a74 100644 --- a/openair2/RRC/NR/rrc_gNB_du.c +++ b/openair2/RRC/NR/rrc_gNB_du.c @@ -383,8 +383,6 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id) f1ap_setup_resp_t resp = {.transaction_id = req->transaction_id, .num_cells_to_activate = 1, .cells_to_activate[0] = cell}; - // free F1AP message after use - free_f1ap_setup_request(req); int num = read_version(TO_STRING(NR_RRC_VERSION), &resp.rrc_ver[0], &resp.rrc_ver[1], &resp.rrc_ver[2]); AssertFatal(num == 3, "could not read RRC version string %s\n", TO_STRING(NR_RRC_VERSION)); if (rrc->node_name != NULL) From cf9854601cce4a8a6970f6d8c1e1790b48d7f690 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 24 Oct 2024 13:18:22 +0200 Subject: [PATCH 37/75] getopt() returns int See getopt(3): returns int, so store it in an int variable. I went through all occurrences, project-wide. All return values of getopt() should be stored in ints now. --- openair1/PHY/CODING/viterbi_lte.c | 2 +- openair1/PHY/TOOLS/smbv.c | 3 ++- openair1/SIMULATION/LTE_PHY/framegen.c | 4 +--- openair1/SIMULATION/LTE_PHY/pbchsim.c | 2 +- openair1/SIMULATION/LTE_PHY/pdcchsim.c | 2 +- openair1/SIMULATION/LTE_PHY/prachsim.c | 2 +- openair1/SIMULATION/LTE_PHY/pucchsim.c | 2 +- openair1/SIMULATION/LTE_PHY/scansim.c | 2 +- openair1/SIMULATION/LTE_PHY/syncsim.c | 2 +- openair1/SIMULATION/NR_PHY/dlschsim.c | 2 +- openair1/SIMULATION/NR_PHY/pbchsim.c | 2 +- openair1/SIMULATION/NR_PHY/prachsim.c | 2 +- openair1/SIMULATION/NR_PHY/psbchsim.c | 2 +- openair1/SIMULATION/NR_PHY/pucchsim.c | 2 +- openair1/SIMULATION/NR_PHY/ulschsim.c | 3 +-- openair1/SIMULATION/NR_PHY/ulsim.c | 2 +- openair2/UTIL/OMG/omg.c | 2 +- 17 files changed, 18 insertions(+), 20 deletions(-) diff --git a/openair1/PHY/CODING/viterbi_lte.c b/openair1/PHY/CODING/viterbi_lte.c index d3fd71bc13..4efab84f49 100644 --- a/openair1/PHY/CODING/viterbi_lte.c +++ b/openair1/PHY/CODING/viterbi_lte.c @@ -340,7 +340,7 @@ int test_viterbi(uint8_t dabflag) int main(int argc, char **argv) { - char c; + int c; uint8_t dabflag=0; while ((c = getopt (argc, argv, "d")) != -1) { diff --git a/openair1/PHY/TOOLS/smbv.c b/openair1/PHY/TOOLS/smbv.c index d361872547..a1088cc705 100644 --- a/openair1/PHY/TOOLS/smbv.c +++ b/openair1/PHY/TOOLS/smbv.c @@ -567,7 +567,7 @@ void help (void) int main(int argc,char **argv) { - char c,smbv_ip[16],smbv_fname[256]; + char smbv_ip[16], smbv_fname[256]; extern char *optarg; int i; @@ -575,6 +575,7 @@ int main(int argc,char **argv) strcpy(smbv_ip,DEFAULT_SMBV_IP); strcpy(smbv_fname,DEFAULT_SMBV_FNAME); + int c; while ((c = getopt (argc, argv, "hW:")) != -1) { switch (c) { case 'W': diff --git a/openair1/SIMULATION/LTE_PHY/framegen.c b/openair1/SIMULATION/LTE_PHY/framegen.c index 521df12ca1..fe1c4b49b7 100644 --- a/openair1/SIMULATION/LTE_PHY/framegen.c +++ b/openair1/SIMULATION/LTE_PHY/framegen.c @@ -461,9 +461,6 @@ void lte_param_init( unsigned char transmission_mode, int main(int argc, char **argv) { - - char c; - int i,l,aa,aarx,sector; unsigned char pbch_pdu[6]; @@ -504,6 +501,7 @@ int main(int argc, char **argv) logInit(); g_log->log_component[PHY].level = LOG_DEBUG; + int c; while ((c = getopt (argc, argv, "hpFb:n:m:x:N:R:")) != -1) { switch (c) { case 'n': diff --git a/openair1/SIMULATION/LTE_PHY/pbchsim.c b/openair1/SIMULATION/LTE_PHY/pbchsim.c index 799008c121..393d5778d6 100644 --- a/openair1/SIMULATION/LTE_PHY/pbchsim.c +++ b/openair1/SIMULATION/LTE_PHY/pbchsim.c @@ -57,7 +57,6 @@ int32_t dummy3[2048*14]; int main(int argc, char **argv) { - char c; int i,l,aa; double sigma2, sigma2_dB=0,SNR,snr0=-2.0,snr1; uint8_t snr1set=0; @@ -104,6 +103,7 @@ int main(int argc, char **argv) { logInit(); number_of_cards = 1; + int c; while ((c = getopt (argc, argv, "f:hA:pf:g:i:j:n:s:S:t:x:y:z:N:F:GR:O:dP:")) != -1) { switch (c) { case 'f': diff --git a/openair1/SIMULATION/LTE_PHY/pdcchsim.c b/openair1/SIMULATION/LTE_PHY/pdcchsim.c index 540911134d..14587d2a5d 100644 --- a/openair1/SIMULATION/LTE_PHY/pdcchsim.c +++ b/openair1/SIMULATION/LTE_PHY/pdcchsim.c @@ -374,7 +374,6 @@ DCI_PDU *get_dci(LTE_DL_FRAME_PARMS *lte_frame_parms,uint8_t log2L, uint8_t log2 extern int QPSK[4],QPSK2[4]; int main(int argc, char **argv) { - char c; int i,l,aa; double sigma2, sigma2_dB=0,SNR,snr0=-2.0,snr1; int **txdata; @@ -425,6 +424,7 @@ int main(int argc, char **argv) { cpuf = get_cpu_freq_GHz(); logInit(); + int c; while ((c = getopt (argc, argv, "hapFg:R:c:n:s:x:y:z:L:M:N:I:f:i:S:P:Y")) != -1) { switch (c) { case 'a': diff --git a/openair1/SIMULATION/LTE_PHY/prachsim.c b/openair1/SIMULATION/LTE_PHY/prachsim.c index 5b7c6ddeff..1b7f9e80e4 100644 --- a/openair1/SIMULATION/LTE_PHY/prachsim.c +++ b/openair1/SIMULATION/LTE_PHY/prachsim.c @@ -45,7 +45,6 @@ double cpuf; void dump_prach_config(LTE_DL_FRAME_PARMS *frame_parms,uint8_t subframe); int main(int argc, char **argv) { - char c; int i,aa,aarx; double sigma2, sigma2_dB=0,SNR,snr0=-2.0,snr1=0.0,ue_speed0=0.0,ue_speed1=0.0; uint8_t snr1set=0; @@ -85,6 +84,7 @@ int main(int argc, char **argv) { logInit(); number_of_cards = 1; + int c; while ((c = getopt (argc, argv, "hHaA:Cr:p:g:n:s:S:t:x:y:v:V:z:N:F:d:Z:L:R:E")) != -1) { switch (c) { case 'a': diff --git a/openair1/SIMULATION/LTE_PHY/pucchsim.c b/openair1/SIMULATION/LTE_PHY/pucchsim.c index 2ca891f023..a65c681c07 100644 --- a/openair1/SIMULATION/LTE_PHY/pucchsim.c +++ b/openair1/SIMULATION/LTE_PHY/pucchsim.c @@ -45,7 +45,6 @@ PHY_VARS_UE *UE; double cpuf; int main(int argc, char **argv) { - char c; int i,l,aa; double sigma2, sigma2_dB=0,SNR,snr0=-2.0,snr1=0.0; uint8_t snr1set=0; @@ -88,6 +87,7 @@ int main(int argc, char **argv) { number_of_cards = 1; cpuf = get_cpu_freq_GHz(); + int c; while ((c = getopt (argc, argv, "har:pf:g:n:s:S:x:y:z:N:F:T:R:")) != -1) { switch (c) { case 'a': diff --git a/openair1/SIMULATION/LTE_PHY/scansim.c b/openair1/SIMULATION/LTE_PHY/scansim.c index a473370f02..8921eaa680 100644 --- a/openair1/SIMULATION/LTE_PHY/scansim.c +++ b/openair1/SIMULATION/LTE_PHY/scansim.c @@ -57,7 +57,6 @@ mod_sym_t dummy3[2048*14]; int main(int argc, char **argv) { - char c; int i,l,aa; double sigma2, sigma2_dB=0,SNR,snr0=-2.0,snr1; uint8_t snr1set=0; @@ -103,6 +102,7 @@ int main(int argc, char **argv) { number_of_cards = 1; openair_daq_vars.rx_rf_mode = 1; + int c; while ((c = getopt (argc, argv, "f:hpf:g:n:s:S:t:x:y:z:N:F:GdP:")) != -1) { switch (c) { case 'f': diff --git a/openair1/SIMULATION/LTE_PHY/syncsim.c b/openair1/SIMULATION/LTE_PHY/syncsim.c index e8976ea898..ccdac230f8 100644 --- a/openair1/SIMULATION/LTE_PHY/syncsim.c +++ b/openair1/SIMULATION/LTE_PHY/syncsim.c @@ -304,7 +304,6 @@ void lte_param_init(unsigned char N_tx, unsigned char N_rx,unsigned char transmi int main(int argc, char **argv) { - char c; int i,iout,l,aa,aarx; double sigma2, sigma2_dB=0,SNR,snr0=10.0,snr1=11.0; uint8_t snr1set=0; @@ -377,6 +376,7 @@ int main(int argc, char **argv) { rxdata[0] = (int *)malloc16(FRAME_LENGTH_BYTES); rxdata[1] = (int *)malloc16(FRAME_LENGTH_BYTES); */ + int c; while ((c = getopt (argc, argv, "aehc:f:g:i:j:n:r:s:t:x:y:z:A:F:N:O:R:S:ZYDT:C:G:dB:U:u")) != -1) { switch (c) { case 'a': diff --git a/openair1/SIMULATION/NR_PHY/dlschsim.c b/openair1/SIMULATION/NR_PHY/dlschsim.c index b49eed1bd6..6aebb80dac 100644 --- a/openair1/SIMULATION/NR_PHY/dlschsim.c +++ b/openair1/SIMULATION/NR_PHY/dlschsim.c @@ -101,7 +101,6 @@ configmodule_interface_t *uniqCfg = NULL; int main(int argc, char **argv) { - char c; int i; double SNR, SNR_lin, snr0 = -2.0, snr1 = 2.0; double snr_step = 0.1; @@ -146,6 +145,7 @@ int main(int argc, char **argv) // logInit(); randominit(0); + int c; while ((c = getopt(argc, argv, "--:O:df:hpVg:i:j:n:l:m:r:s:S:y:z:M:N:F:R:P:L:X:")) != -1) { /* ignore long options starting with '--' and their arguments that are handled by configmodule */ diff --git a/openair1/SIMULATION/NR_PHY/pbchsim.c b/openair1/SIMULATION/NR_PHY/pbchsim.c index f9b39de894..9f3f1760bd 100644 --- a/openair1/SIMULATION/NR_PHY/pbchsim.c +++ b/openair1/SIMULATION/NR_PHY/pbchsim.c @@ -177,7 +177,6 @@ void nr_phy_config_request_sim_pbchsim(PHY_VARS_gNB *gNB, configmodule_interface_t *uniqCfg = NULL; int main(int argc, char **argv) { - char c; int i,aa,start_symbol; double sigma2, sigma2_dB=10,SNR,snr0=-2.0,snr1=2.0; double cfo=0; @@ -246,6 +245,7 @@ int main(int argc, char **argv) exit_fun("[NR_PBCHSIM] Error, configuration module init failed\n"); } + int c; while ((c = getopt (argc, argv, "--:O:c:F:g:hIL:m:M:n:N:o:P:r:R:s:S:x:y:z:")) != -1) { /* ignore long options starting with '--', option '-O' and their arguments that are handled by configmodule */ diff --git a/openair1/SIMULATION/NR_PHY/prachsim.c b/openair1/SIMULATION/NR_PHY/prachsim.c index d4b109a529..4ccf0317e9 100644 --- a/openair1/SIMULATION/NR_PHY/prachsim.c +++ b/openair1/SIMULATION/NR_PHY/prachsim.c @@ -117,7 +117,6 @@ int NB_UE_INST = 1; configmodule_interface_t *uniqCfg = NULL; int main(int argc, char **argv){ - char c; get_softmodem_params()->sl_mode = 0; double sigma2, sigma2_dB = 0, SNR, snr0 = -2.0, snr1 = 0.0, ue_speed0 = 0.0, ue_speed1 = 0.0; double **s_re, **s_im, **r_re, **r_im, iqim = 0.0, delay_avg = 0, ue_speed = 0, fs=-1, bw; @@ -155,6 +154,7 @@ int main(int argc, char **argv){ randominit(0); + int c; while ((c = getopt (argc, argv, "--:O:hHaA:Cc:l:r:p:g:m:n:s:S:t:x:y:v:V:z:N:F:d:Z:L:R:E")) != -1) { /* ignore long options starting with '--', option '-O' and their arguments that are handled by configmodule */ diff --git a/openair1/SIMULATION/NR_PHY/psbchsim.c b/openair1/SIMULATION/NR_PHY/psbchsim.c index 3f461e8666..972605fc96 100644 --- a/openair1/SIMULATION/NR_PHY/psbchsim.c +++ b/openair1/SIMULATION/NR_PHY/psbchsim.c @@ -315,7 +315,6 @@ double cpuf; configmodule_interface_t *uniqCfg = NULL; int main(int argc, char **argv) { - char c; int test_freqdomain_loopback = 0, test_slss_search = 0; int frame = 5, slot = 10, frame_tx = 0, slot_tx = 0; int loglvl = OAILOG_INFO; @@ -343,6 +342,7 @@ int main(int argc, char **argv) randominit(0); + int c; while ((c = getopt(argc, argv, "--:O:c:hn:o:s:FIL:N:R:S:T:")) != -1) { /* ignore long options starting with '--', option '-O' and their arguments that are handled by configmodule */ diff --git a/openair1/SIMULATION/NR_PHY/pucchsim.c b/openair1/SIMULATION/NR_PHY/pucchsim.c index 359310050c..45bc2aaa42 100644 --- a/openair1/SIMULATION/NR_PHY/pucchsim.c +++ b/openair1/SIMULATION/NR_PHY/pucchsim.c @@ -97,7 +97,6 @@ nrUE_params_t *get_nrUE_params(void) { configmodule_interface_t *uniqCfg = NULL; int main(int argc, char **argv) { - char c; int i;//,l; double sigma2, sigma2_dB=10,SNR,snr0=-2.0,snr1=2.0; double cfo=0; @@ -155,6 +154,7 @@ int main(int argc, char **argv) randominit(0); logInit(); + int c; while ((c = getopt (argc, argv, "--:O:f:hA:f:g:i:I:P:B:b:t:T:m:n:r:o:s:S:x:y:z:N:F:GR:IL:q:cd:")) != -1) { /* ignore long options starting with '--', option '-O' and their arguments that are handled by configmodule */ diff --git a/openair1/SIMULATION/NR_PHY/ulschsim.c b/openair1/SIMULATION/NR_PHY/ulschsim.c index ebe0ff8915..306e882ebf 100644 --- a/openair1/SIMULATION/NR_PHY/ulschsim.c +++ b/openair1/SIMULATION/NR_PHY/ulschsim.c @@ -121,7 +121,6 @@ nrUE_params_t *get_nrUE_params(void) { configmodule_interface_t *uniqCfg = NULL; int main(int argc, char **argv) { - char c; int i; double SNR, snr0 = -2.0, snr1 = 2.0, SNR_lin; double snr_step = 0.1; @@ -165,7 +164,7 @@ int main(int argc, char **argv) //logInit(); randominit(0); - //while ((c = getopt(argc, argv, "--:df:hpg:i:j:n:l:m:r:s:S:y:z:M:N:F:R:P:")) != -1) { + int c; while ((c = getopt(argc, argv, "--:O:hg:n:s:S:py:z:M:N:R:F:m:l:q:r:W:")) != -1) { /* ignore long options starting with '--', option '-O' and their arguments that are handled by configmodule */ diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index 910d076e0f..431e4875fc 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -145,7 +145,6 @@ int main(int argc, char *argv[]) { FILE *csv_file = NULL; char *filename_csv = NULL; - char c; int i; double SNR, snr0 = -2.0, snr1 = 2.0; double sigma, sigma_dB; @@ -224,6 +223,7 @@ int main(int argc, char *argv[]) /* initialize the sin-cos table */ InitSinLUT(); + int c; while ((c = getopt(argc, argv, "--:O:a:b:c:d:ef:g:h:i:k:m:n:op:q:r:s:t:u:v:w:y:z:C:F:G:H:I:M:N:PR:S:T:U:L:ZW:E:X:")) != -1) { /* ignore long options starting with '--', option '-O' and their arguments that are handled by configmodule */ diff --git a/openair2/UTIL/OMG/omg.c b/openair2/UTIL/OMG/omg.c index 23b8bb114c..67a78d245a 100644 --- a/openair2/UTIL/OMG/omg.c +++ b/openair2/UTIL/OMG/omg.c @@ -423,7 +423,7 @@ usage (void) { int get_options (int argc, char *argv[]) { int node_t; - char tag; + int tag; while ((tag = getopt (argc, argv, From a85be06c72dcb8647e490dfa074e056a3a6820f6 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 30 Sep 2024 16:32:55 +0200 Subject: [PATCH 38/75] Add defines for IPv4 and IPv6 PDU address header fields --- .../NAS/COMMON/ESM/MSG/PduSessionEstablishmentAccept.c | 8 ++++---- .../NAS/COMMON/ESM/MSG/PduSessionEstablishmentAccept.h | 5 ++++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/openair3/NAS/COMMON/ESM/MSG/PduSessionEstablishmentAccept.c b/openair3/NAS/COMMON/ESM/MSG/PduSessionEstablishmentAccept.c index f5d053ae58..86aa3eaf7f 100644 --- a/openair3/NAS/COMMON/ESM/MSG/PduSessionEstablishmentAccept.c +++ b/openair3/NAS/COMMON/ESM/MSG/PduSessionEstablishmentAccept.c @@ -128,14 +128,14 @@ void capture_pdu_session_establishment_accept_msg(uint8_t *buffer, uint32_t msg_ uint8_t *addr = psea_msg.pdu_addr_ie.pdu_addr_oct; if (psea_msg.pdu_addr_ie.pdu_type == PDU_SESSION_TYPE_IPV4) { - for (int i = 0; i < 4; ++i) + for (int i = 0; i < IPv4_ADDRESS_LENGTH; ++i) addr[i] = *curPtr++; char ip[20]; capture_ipv4_addr(&addr[0], ip, sizeof(ip)); tun_config(1, ip, NULL, "oaitun_ue"); setup_ue_ipv4_route(1, ip, "oaitun_ue"); } else if (psea_msg.pdu_addr_ie.pdu_type == PDU_SESSION_TYPE_IPV6) { - for (int i = 0; i < 8; ++i) + for (int i = 0; i < IPv6_INTERFACE_ID_LENGTH; ++i) addr[i] = *curPtr++; char ipv6[40]; capture_ipv6_addr(addr, ipv6, sizeof(ipv6)); @@ -145,12 +145,12 @@ void capture_pdu_session_establishment_accept_msg(uint8_t *buffer, uint32_t msg_ // IPv4v6, the PDU address information in octet 4 to octet 11 // contains an interface identifier for the IPv6 link local address // and in octet 12 to octet 15 contains an IPv4 address." - for (int i = 0; i < 12; ++i) + for (int i = 0; i < IPv4_ADDRESS_LENGTH + IPv6_INTERFACE_ID_LENGTH; ++i) addr[i] = *curPtr++; char ipv6[40]; capture_ipv6_addr(addr, ipv6, sizeof(ipv6)); char ipv4[20]; - capture_ipv4_addr(&addr[8], ipv4, sizeof(ipv4)); + capture_ipv4_addr(&addr[IPv6_INTERFACE_ID_LENGTH], ipv4, sizeof(ipv4)); tun_config(1, ipv4, ipv6, "oaitun_ue"); setup_ue_ipv4_route(1, ipv4, "oaitun_ue"); } else { diff --git a/openair3/NAS/COMMON/ESM/MSG/PduSessionEstablishmentAccept.h b/openair3/NAS/COMMON/ESM/MSG/PduSessionEstablishmentAccept.h index a254debfbe..e655607d9c 100644 --- a/openair3/NAS/COMMON/ESM/MSG/PduSessionEstablishmentAccept.h +++ b/openair3/NAS/COMMON/ESM/MSG/PduSessionEstablishmentAccept.h @@ -42,6 +42,8 @@ #define PDU_SESSION_TYPE_IPV4 0b001 #define PDU_SESSION_TYPE_IPV6 0b010 #define PDU_SESSION_TYPE_IPV4V6 0b011 +#define IPv4_ADDRESS_LENGTH 4 // length of the IPv4 address associated with a PDU session +#define IPv6_INTERFACE_ID_LENGTH 8 // interface identifier for the IPv6 link local address /* Rule operation codes - TS 24.501 Table 9.11.4.13.1 */ @@ -114,7 +116,8 @@ typedef struct pdu_address_s { uint8_t pdu_iei; /* PDU Address IEI (0x29) */ uint8_t pdu_length; /* Length of PDU address contents */ uint8_t pdu_type; /* PDU session type value */ - uint8_t pdu_addr_oct[12]; /* PDU address information (depending on type, up to 12 bytes)*/ + /// PDU address information (depending on type, up to 12 bytes) + uint8_t pdu_addr_oct[IPv4_ADDRESS_LENGTH + IPv6_INTERFACE_ID_LENGTH]; } pdu_address_t; /* TS 24.501 9.11.4.10 */ typedef struct dnn_s { From 66231badaf52abc31e258a8f49c19baf01a0de99 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Thu, 3 Oct 2024 12:35:08 +0200 Subject: [PATCH 39/75] Refactor PDU address IE in PDU Session Establishment Accept * take 3 bits for PDU session type value * add define for SMF's IPv6 link local address --- .../COMMON/ESM/MSG/PduSessionEstablishmentAccept.c | 12 +++++++++++- .../COMMON/ESM/MSG/PduSessionEstablishmentAccept.h | 1 + 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/openair3/NAS/COMMON/ESM/MSG/PduSessionEstablishmentAccept.c b/openair3/NAS/COMMON/ESM/MSG/PduSessionEstablishmentAccept.c index 86aa3eaf7f..aee6d0e63d 100644 --- a/openair3/NAS/COMMON/ESM/MSG/PduSessionEstablishmentAccept.c +++ b/openair3/NAS/COMMON/ESM/MSG/PduSessionEstablishmentAccept.c @@ -124,8 +124,18 @@ void capture_pdu_session_establishment_accept_msg(uint8_t *buffer, uint32_t msg_ case IEI_PDU_ADDRESS: LOG_T(NAS, "PDU SESSION ESTABLISHMENT ACCEPT - Received PDU Address IE\n"); psea_msg.pdu_addr_ie.pdu_length = *curPtr++; - psea_msg.pdu_addr_ie.pdu_type = *curPtr++; + /* Octet 3 */ + // PDU type (3 bits) + psea_msg.pdu_addr_ie.pdu_type = *curPtr & 0x07; + // SMF's IPv6 link local address (1 bit) + uint8_t si6lla = (*curPtr >> 3) & 0x01; + if (si6lla) + LOG_E(NAS, "SMF's IPv6 link local address is not handled\n"); + curPtr++; + + /* Octet 4 to n */ + // PDU address information uint8_t *addr = psea_msg.pdu_addr_ie.pdu_addr_oct; if (psea_msg.pdu_addr_ie.pdu_type == PDU_SESSION_TYPE_IPV4) { for (int i = 0; i < IPv4_ADDRESS_LENGTH; ++i) diff --git a/openair3/NAS/COMMON/ESM/MSG/PduSessionEstablishmentAccept.h b/openair3/NAS/COMMON/ESM/MSG/PduSessionEstablishmentAccept.h index e655607d9c..c283079998 100644 --- a/openair3/NAS/COMMON/ESM/MSG/PduSessionEstablishmentAccept.h +++ b/openair3/NAS/COMMON/ESM/MSG/PduSessionEstablishmentAccept.h @@ -44,6 +44,7 @@ #define PDU_SESSION_TYPE_IPV4V6 0b011 #define IPv4_ADDRESS_LENGTH 4 // length of the IPv4 address associated with a PDU session #define IPv6_INTERFACE_ID_LENGTH 8 // interface identifier for the IPv6 link local address +#define SMF_IPv6_LLA_LENGTH 16 /* Rule operation codes - TS 24.501 Table 9.11.4.13.1 */ From b5f4c55d88060cc85b79be7bd1013867ca253fed Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Fri, 25 Oct 2024 11:48:11 +0200 Subject: [PATCH 40/75] Use capture_pdu_session_establishment_accept_msg with NAS_DOWNLINK_DATA_IND:FGS_PDU_SESSION_ESTABLISHMENT_ACC * the capture_pdu_session_establishment_accept_msg function is already handling the code in the case FGS_PDU_SESSION_ESTABLISHMENT_ACC of NAS_DOWNLINK_DATA_IND Closes: #841 --- openair3/NAS/NR_UE/nr_nas_msg_sim.c | 29 +++-------------------------- 1 file changed, 3 insertions(+), 26 deletions(-) diff --git a/openair3/NAS/NR_UE/nr_nas_msg_sim.c b/openair3/NAS/NR_UE/nr_nas_msg_sim.c index c942e079cd..d5652c4f07 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg_sim.c +++ b/openair3/NAS/NR_UE/nr_nas_msg_sim.c @@ -1423,32 +1423,9 @@ void *nas_nrue(void *args_p) case FGS_DEREGISTRATION_ACCEPT: LOG_I(NAS, "received deregistration accept\n"); break; - case FGS_PDU_SESSION_ESTABLISHMENT_ACC: { - uint8_t offset = 0; - uint8_t *payload_container = pdu_buffer; - offset += SECURITY_PROTECTED_5GS_NAS_MESSAGE_HEADER_LENGTH; - uint32_t payload_container_length = htons(((dl_nas_transport_t *)(pdu_buffer + offset))->payload_container_length); - if ((payload_container_length >= PAYLOAD_CONTAINER_LENGTH_MIN) - && (payload_container_length <= PAYLOAD_CONTAINER_LENGTH_MAX)) - offset += (PLAIN_5GS_NAS_MESSAGE_HEADER_LENGTH + 3); - if (offset < NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.length) - payload_container = pdu_buffer + offset; - - while (offset < payload_container_length) { - if (*(payload_container + offset) == 0x29) { // PDU address IEI - if ((*(payload_container + offset + 1) == 0x05) && (*(payload_container + offset + 2) == 0x01)) { // IPV4 - uint8_t *ip_p = payload_container + offset + 3; - char ip[20]; - snprintf(ip, sizeof(ip), "%d.%d.%d.%d", *(ip_p), *(ip_p + 1), *(ip_p + 2), *(ip_p + 3)); - LOG_I(NAS, "Received PDU Session Establishment Accept, UE IP: %s\n", ip); - tun_config(1, ip, NULL, "oaitun_ue"); - setup_ue_ipv4_route(1, ip, "oaitun_ue"); - break; - } - } - offset++; - } - } break; + case FGS_PDU_SESSION_ESTABLISHMENT_ACC: + capture_pdu_session_establishment_accept_msg(pdu_buffer, pdu_length); + break; case FGS_PDU_SESSION_ESTABLISHMENT_REJ: LOG_E(NAS, "Received PDU Session Establishment reject\n"); break; From 9a67c5e5b50451f19acf3cc493d3f53f0b0e145d Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 23 Sep 2024 10:40:52 +0200 Subject: [PATCH 41/75] Fix scoping issues for variable declarations in switch-case blocks (capture_pdu_session_establishment_accept_msg) --- .../ESM/MSG/PduSessionEstablishmentAccept.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/openair3/NAS/COMMON/ESM/MSG/PduSessionEstablishmentAccept.c b/openair3/NAS/COMMON/ESM/MSG/PduSessionEstablishmentAccept.c index aee6d0e63d..a3c6039752 100644 --- a/openair3/NAS/COMMON/ESM/MSG/PduSessionEstablishmentAccept.c +++ b/openair3/NAS/COMMON/ESM/MSG/PduSessionEstablishmentAccept.c @@ -174,42 +174,47 @@ void capture_pdu_session_establishment_accept_msg(uint8_t *buffer, uint32_t msg_ curPtr++; /* TS 24.008 10.5.7.3 */ break; - case IEI_SNSSAI: /* Ommited */ + case IEI_SNSSAI: { LOG_T(NAS, "PDU SESSION ESTABLISHMENT ACCEPT - Received S-NSSAI IE\n"); uint8_t snssai_length = *curPtr; curPtr += (snssai_length + sizeof(snssai_length)); break; + } case IEI_ALWAYSON_PDU: /* Ommited */ LOG_T(NAS, "PDU SESSION ESTABLISHMENT ACCEPT - Received Always-on PDU Session indication IE\n"); curPtr++; break; - case IEI_MAPPED_EPS: /* Ommited */ + case IEI_MAPPED_EPS: { LOG_T(NAS, "PDU SESSION ESTABLISHMENT ACCEPT - Received Mapped EPS bearer context IE\n"); uint16_t mapped_eps_length = getShort(curPtr); curPtr += mapped_eps_length; break; + } - case IEI_EAP_MSG: /* Ommited */ + case IEI_EAP_MSG: { LOG_T(NAS, "PDU SESSION ESTABLISHMENT ACCEPT - Received EAP message IE\n"); uint16_t eap_length = getShort(curPtr); curPtr += (eap_length + sizeof(eap_length)); break; + } - case IEI_AUTH_QOS_DESC: /* Ommited */ + case IEI_AUTH_QOS_DESC: { LOG_T(NAS, "PDU SESSION ESTABLISHMENT ACCEPT - Received Authorized QoS flow descriptions IE\n"); psea_msg.qos_fd_ie.length = getShort(curPtr); curPtr += (psea_msg.qos_fd_ie.length + sizeof(psea_msg.qos_fd_ie.length)); break; + } - case IEI_EXT_CONF_OPT: /* Ommited */ + case IEI_EXT_CONF_OPT: { LOG_T(NAS, "PDU SESSION ESTABLISHMENT ACCEPT - Received Extended protocol configuration options IE\n"); psea_msg.ext_pp_ie.length = getShort(curPtr); curPtr += (psea_msg.ext_pp_ie.length + sizeof(psea_msg.ext_pp_ie.length)); break; + } - case IEI_DNN: + case IEI_DNN: { LOG_T(NAS, "PDU SESSION ESTABLISHMENT ACCEPT - Received DNN IE\n"); psea_msg.dnn_ie.dnn_length = *curPtr++; char apn[APN_MAX_LEN]; @@ -223,6 +228,7 @@ void capture_pdu_session_establishment_accept_msg(uint8_t *buffer, uint32_t msg_ curPtr = buffer + msg_length; // we force stop processing break; + } default: LOG_T(NAS, "PDU SESSION ESTABLISHMENT ACCEPT - Not known IE\n"); From c3f1824f0b818605f8019ed02418e6da81dda33b Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Fri, 25 Oct 2024 12:35:49 +0200 Subject: [PATCH 42/75] Use capture_pdu_session_establishment_accept_msg in handleDownlinkNASTransport * DL NAS Transport messages can piggy-back 5GSM messages * the relevant decoding functions can be called in the handler (e.g. capture_pdu_session_establishment_accept_msg) --- openair3/NAS/NR_UE/nr_nas_msg_sim.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/openair3/NAS/NR_UE/nr_nas_msg_sim.c b/openair3/NAS/NR_UE/nr_nas_msg_sim.c index d5652c4f07..64f3d2b9a9 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg_sim.c +++ b/openair3/NAS/NR_UE/nr_nas_msg_sim.c @@ -848,16 +848,15 @@ static void generateRegistrationComplete(nr_ue_nas_t *nas, } } -void decodeDownlinkNASTransport(as_nas_info_t *initialNasMsg, uint8_t *pdu_buffer) +/** + * @brief Handle DL NAS Transport and process piggybacked 5GSM messages + */ +static void handleDownlinkNASTransport(uint8_t *pdu_buffer, uint32_t msg_length) { uint8_t msg_type = *(pdu_buffer + 16); if (msg_type == FGS_PDU_SESSION_ESTABLISHMENT_ACC) { - uint8_t *ip_p = pdu_buffer + 39; - char ip[20]; - sprintf(ip, "%d.%d.%d.%d", *(ip_p), *(ip_p + 1), *(ip_p + 2), *(ip_p + 3)); - LOG_A(NAS, "Received PDU Session Establishment Accept\n"); - tun_config(1, ip, NULL, "oaitun_ue"); - setup_ue_ipv4_route(1, ip, "oaitun_ue"); + LOG_A(NAS, "Received PDU Session Establishment Accept in DL NAS Transport\n"); + capture_pdu_session_establishment_accept_msg(pdu_buffer, msg_length); } else { LOG_E(NAS, "Received unexpected message in DLinformationTransfer %d\n", msg_type); } @@ -1415,7 +1414,7 @@ void *nas_nrue(void *args_p) handle_security_mode_command(nas, &initialNasMsg, pdu_buffer, pdu_length); break; case FGS_DOWNLINK_NAS_TRANSPORT: - decodeDownlinkNASTransport(&initialNasMsg, pdu_buffer); + handleDownlinkNASTransport(pdu_buffer, pdu_length); break; case REGISTRATION_ACCEPT: handle_registration_accept(nas, pdu_buffer, pdu_length); From 4a5bf53caad55fd0255e02c396061f8533ce7675 Mon Sep 17 00:00:00 2001 From: rmagueta Date: Thu, 25 Jul 2024 13:38:51 +0200 Subject: [PATCH 43/75] UE: Improve synchronization for reconfigurationWithSync Improve synchronization to also handle handover between gNB-DUs with differing carrier freqs. --- executables/nr-ue.c | 19 +++++++++++++++++-- openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 2 +- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/executables/nr-ue.c b/executables/nr-ue.c index 01f18dc38d..a06c13a59a 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -38,6 +38,7 @@ #include "LAYER2/nr_rlc/nr_rlc_oai_api.h" #include "RRC/NR/MESSAGES/asn1_msg.h" #include "openair1/PHY/TOOLS/phy_scope_interface.h" +#include "PHY/MODULATION/nr_modulation.h" /* * NR SLOT PROCESSING SEQUENCE @@ -604,9 +605,23 @@ static int UE_dl_preprocessing(PHY_VARS_NR_UE *UE, const UE_nr_rxtx_proc_t *proc // Start synchronization with a target gNB if (UE->synch_request.received_synch_request == 1) { + fapi_nr_synch_request_t *synch_req = &UE->synch_request.synch_req; UE->is_synchronized = 0; - UE->UE_scan_carrier = UE->synch_request.synch_req.ssb_bw_scan; - UE->target_Nid_cell = UE->synch_request.synch_req.target_Nid_cell; + UE->UE_scan_carrier = synch_req->ssb_bw_scan; + UE->target_Nid_cell = synch_req->target_Nid_cell; + + uint64_t dl_bw = (12 * fp->N_RB_DL) * (15000 << fp->numerology_index); + uint64_t dl_CarrierFreq = (dl_bw >> 1) + (uint64_t)UE->nrUE_config.carrier_config.dl_frequency * 1000; + uint64_t ul_bw = (12 * fp->N_RB_UL) * (15000 << fp->numerology_index); + uint64_t ul_CarrierFreq = (ul_bw >> 1) + (uint64_t)UE->nrUE_config.carrier_config.uplink_frequency * 1000; + if (dl_CarrierFreq != fp->dl_CarrierFreq || ul_CarrierFreq != fp->ul_CarrierFreq) { + fp->dl_CarrierFreq = dl_CarrierFreq; + fp->ul_CarrierFreq = ul_CarrierFreq; + nr_rf_card_config_freq(&openair0_cfg[UE->rf_map.card], ul_CarrierFreq, dl_CarrierFreq, 0); + UE->rfdevice.trx_set_freq_func(&UE->rfdevice, &openair0_cfg[0]); + init_symbol_rotation(fp); + } + clean_UE_harq(UE); UE->synch_request.received_synch_request = 0; } diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 9003cc42d2..1eb79ebda5 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -2240,7 +2240,7 @@ static int get_nr_prach_info_from_ssb_index(prach_association_pattern_t *prach_a ssb_info_p->mapped_ro[n_mapped_ro]->frame, ssb_info_p->mapped_ro[n_mapped_ro]->slot, prach_assoc_pattern->nb_of_frame); - if ((slot == ssb_info_p->mapped_ro[n_mapped_ro]->slot) && + if ((slot == ssb_info_p->mapped_ro[n_mapped_ro]->slot) && prach_assoc_pattern->prach_conf_period_list[0].nb_of_frame != 0 && (ssb_info_p->mapped_ro[n_mapped_ro]->frame == (frame % prach_assoc_pattern->nb_of_frame))) { uint8_t prach_config_period_nb = ssb_info_p->mapped_ro[n_mapped_ro]->frame / prach_assoc_pattern->prach_conf_period_list[0].nb_of_frame; uint8_t frame_nb_in_prach_config_period = ssb_info_p->mapped_ro[n_mapped_ro]->frame % prach_assoc_pattern->prach_conf_period_list[0].nb_of_frame; From cddffe6f3055a80d8e0d619cafcd7095d4847e2d Mon Sep 17 00:00:00 2001 From: Roberto Magueta Date: Tue, 30 Apr 2024 15:13:36 +0100 Subject: [PATCH 44/75] Add config files (TDD/FDD) for multiple DUs scenario Co-authored-by: rmagueta --- .../GENERIC-NR-5GC/CONF/gnb-cu.sa.f1.conf | 74 ++++++ .../gnb-du.sa.band66.25prb.rfsim.pci0.conf | 215 ++++++++++++++++++ .../gnb-du.sa.band66.25prb.rfsim.pci1.conf | 215 ++++++++++++++++++ .../gnb-du.sa.band78.106prb.rfsim.pci0.conf | 212 +++++++++++++++++ .../gnb-du.sa.band78.106prb.rfsim.pci1.conf | 212 +++++++++++++++++ 5 files changed, 928 insertions(+) create mode 100644 targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-cu.sa.f1.conf create mode 100644 targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band66.25prb.rfsim.pci0.conf create mode 100644 targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band66.25prb.rfsim.pci1.conf create mode 100644 targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band78.106prb.rfsim.pci0.conf create mode 100644 targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band78.106prb.rfsim.pci1.conf diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-cu.sa.f1.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-cu.sa.f1.conf new file mode 100644 index 0000000000..08b72bf6c6 --- /dev/null +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-cu.sa.f1.conf @@ -0,0 +1,74 @@ +Active_gNBs = ( "cu-rfsim"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; +Num_Threads_PUSCH = 8; + +gNBs = +( + { + ////////// Identification parameters: + gNB_ID = 0xe00; + gNB_name = "cu-rfsim"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = 1; + plmn_list = ({ mcc = 001; mnc = 01; mnc_length = 2; snssaiList = ({ sst = 1; }) }); + + nr_cellid = 12345678L; + + tr_s_preference = "f1"; + + local_s_if_name = "lo"; + local_s_address = "127.0.0.3"; + remote_s_address = "0.0.0.0"; # multiple DUs + local_s_portc = 501; + local_s_portd = 2152; + remote_s_portc = 500; + remote_s_portd = 2152; + + + # ------- 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.70.132"; }); + + NETWORK_INTERFACES : + { + GNB_IPV4_ADDRESS_FOR_NG_AMF = "192.168.70.129/24"; + GNB_IPV4_ADDRESS_FOR_NGU = "192.168.70.129/24"; + GNB_PORT_FOR_S1U = 2152; # Spec 2152 + }; + } +); + +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"; +}; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band66.25prb.rfsim.pci0.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band66.25prb.rfsim.pci0.conf new file mode 100644 index 0000000000..abd624747d --- /dev/null +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band66.25prb.rfsim.pci0.conf @@ -0,0 +1,215 @@ +Active_gNBs = ( "du-rfsim"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +gNBs = +( + { + ////////// Identification parameters: + gNB_ID = 0xe00; + gNB_DU_ID = 0xe00; + gNB_name = "du-rfsim"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = 1; + plmn_list = ({ mcc = 208; mnc = 95; mnc_length = 2; snssaiList = ({ sst = 1; }) }); + + nr_cellid = 12345678L; + + ////////// Physical parameters: + + min_rxtxtime = 4; + sib1_tda = 15; + + servingCellConfigCommon = ( + { + #spCellConfigCommon + + physCellId = 0; + +# downlinkConfigCommon + #frequencyInfoDL + # this is 3600 MHz + 43 PRBs@30kHz SCS (same as initial BWP) + absoluteFrequencySSB = 430610; + dl_frequencyBand = 66; + # this is 3600 MHz + dl_absoluteFrequencyPointA = 430000; + #scs-SpecificCarrierList + dl_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + dl_subcarrierSpacing = 0; + dl_carrierBandwidth = 25; + #initialDownlinkBWP + #genericParameters + # this is RBstart=27,L=48 (275*(L-1))+RBstart + initialDLBWPlocationAndBandwidth = 6600; # 6366 12925 12956 28875 12952 +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialDLBWPsubcarrierSpacing = 0; + #pdcch-ConfigCommon + initialDLBWPcontrolResourceSetZero = 0; + initialDLBWPsearchSpaceZero = 0; + + #uplinkConfigCommon + #frequencyInfoUL + ul_frequencyBand = 66; + # this is 1750 MHz + ul_absoluteFrequencyPointA = 350000; + #scs-SpecificCarrierList + ul_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + ul_subcarrierSpacing = 0; + ul_carrierBandwidth = 25; + pMax = 20; + #initialUplinkBWP + #genericParameters + initialULBWPlocationAndBandwidth = 6600; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialULBWPsubcarrierSpacing = 0; + #rach-ConfigCommon + #rach-ConfigGeneric + prach_ConfigurationIndex = 98; +#prach_msg1_FDM +#0 = one, 1=two, 2=four, 3=eight + prach_msg1_FDM = 0; + prach_msg1_FrequencyStart = 0; + zeroCorrelationZoneConfig = 13; + preambleReceivedTargetPower = -96; +#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200) + preambleTransMax = 6; +#powerRampingStep +# 0=dB0,1=dB2,2=dB4,3=dB6 + powerRampingStep = 1; +#ra_ReponseWindow +#1,2,4,8,10,20,40,80 + ra_ResponseWindow = 4; +#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR +#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen + ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; +#oneHalf (0..15) 4,8,12,16,...60,64 + ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15; +#ra_ContentionResolutionTimer +#(0..7) 8,16,24,32,40,48,56,64 + ra_ContentionResolutionTimer = 7; + rsrp_ThresholdSSB = 19; +#prach-RootSequenceIndex_PR +#1 = 839, 2 = 139 + prach_RootSequenceIndex_PR = 2; + prach_RootSequenceIndex = 1; + # SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex + # + msg1_SubcarrierSpacing = 0, +# restrictedSetConfig +# 0=unrestricted, 1=restricted type A, 2=restricted type B + restrictedSetConfig = 0, + + msg3_DeltaPreamble = 1; + p0_NominalWithGrant =-90; + +# pucch-ConfigCommon setup : +# pucchGroupHopping +# 0 = neither, 1= group hopping, 2=sequence hopping + pucchGroupHopping = 0; + hoppingId = 40; + p0_nominal = -90; + + ssb_PositionsInBurst_Bitmap = 1; + +# ssb_periodicityServingCell +# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1 + ssb_periodicityServingCell = 2; + +# dmrs_TypeA_position +# 0 = pos2, 1 = pos3 + dmrs_TypeA_Position = 0; + +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + subcarrierSpacing = 0; + + + #tdd-UL-DL-ConfigurationCommon +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + referenceSubcarrierSpacing = 0; + # pattern1 + # dl_UL_TransmissionPeriodicity + # 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10 + dl_UL_TransmissionPeriodicity = 6; + nrofDownlinkSlots = 7; + nrofDownlinkSymbols = 6; + nrofUplinkSlots = 2; + nrofUplinkSymbols = 4; + + ssPBCH_BlockPower = -25; + } + + ); + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + } +); + +MACRLCs = ({ + num_cc = 1; + tr_s_preference = "local_L1"; + tr_n_preference = "f1"; + local_n_if_name = "lo"; + local_n_address = "127.0.0.4"; + remote_n_address = "127.0.0.3"; + local_n_portc = 500; + local_n_portd = 2152; + remote_n_portc = 501; + remote_n_portd = 2152; + pusch_FailureThres = 1000; +}); + +L1s = ({ + num_cc = 1; + tr_n_preference = "local_mac"; + prach_dtx_threshold = 200; + pucch0_dtx_threshold = 150; + ofdm_offset_divisor = 8; #set this to UINT_MAX for offset 0 +}); + +RUs = ({ + local_rf = "yes" + nb_tx = 1 + nb_rx = 1 + att_tx = 0 + att_rx = 0; + bands = [66]; + max_pdschReferenceSignalPower = -27; + max_rxgain = 114; + eNB_instances = [0]; + clock_src = "internal"; +}); + +rfsimulator: { + serveraddr = "server"; + serverport = 4043; + options = (); #("saviq"); or/and "chanmod" + modelname = "AWGN"; + IQfile = "/tmp/rfsimulator.iqs" +} + +log_config: { + global_log_level = "info"; + hw_log_level = "info"; + nr_phy_log_level = "info"; + nr_mac_log_level = "info"; + rlc_log_level = "info"; + pdcp_log_level = "info"; + rrc_log_level = "info"; + f1ap_log_level = "info"; + ngap_log_level = "debug"; +}; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band66.25prb.rfsim.pci1.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band66.25prb.rfsim.pci1.conf new file mode 100644 index 0000000000..8d2e46b44e --- /dev/null +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band66.25prb.rfsim.pci1.conf @@ -0,0 +1,215 @@ +Active_gNBs = ( "du-rfsim"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +gNBs = +( + { + ////////// Identification parameters: + gNB_ID = 0xe00; + gNB_DU_ID = 0xe01; + gNB_name = "du-rfsim"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = 1; + plmn_list = ({ mcc = 208; mnc = 95; mnc_length = 2; snssaiList = ({ sst = 1; }) }); + + nr_cellid = 11111111L; + + ////////// Physical parameters: + + min_rxtxtime = 4; + sib1_tda = 15; + + servingCellConfigCommon = ( + { + #spCellConfigCommon + + physCellId = 1; + +# downlinkConfigCommon + #frequencyInfoDL + # this is 3600 MHz + 43 PRBs@30kHz SCS (same as initial BWP) + absoluteFrequencySSB = 435610; + dl_frequencyBand = 66; + # this is 3600 MHz + dl_absoluteFrequencyPointA = 435000; + #scs-SpecificCarrierList + dl_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + dl_subcarrierSpacing = 0; + dl_carrierBandwidth = 25; + #initialDownlinkBWP + #genericParameters + # this is RBstart=27,L=48 (275*(L-1))+RBstart + initialDLBWPlocationAndBandwidth = 6600; # 6366 12925 12956 28875 12952 +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialDLBWPsubcarrierSpacing = 0; + #pdcch-ConfigCommon + initialDLBWPcontrolResourceSetZero = 0; + initialDLBWPsearchSpaceZero = 0; + + #uplinkConfigCommon + #frequencyInfoUL + ul_frequencyBand = 66; + # this is 1750 MHz + ul_absoluteFrequencyPointA = 355000; + #scs-SpecificCarrierList + ul_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + ul_subcarrierSpacing = 0; + ul_carrierBandwidth = 25; + pMax = 20; + #initialUplinkBWP + #genericParameters + initialULBWPlocationAndBandwidth = 6600; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialULBWPsubcarrierSpacing = 0; + #rach-ConfigCommon + #rach-ConfigGeneric + prach_ConfigurationIndex = 98; +#prach_msg1_FDM +#0 = one, 1=two, 2=four, 3=eight + prach_msg1_FDM = 0; + prach_msg1_FrequencyStart = 0; + zeroCorrelationZoneConfig = 13; + preambleReceivedTargetPower = -96; +#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200) + preambleTransMax = 6; +#powerRampingStep +# 0=dB0,1=dB2,2=dB4,3=dB6 + powerRampingStep = 1; +#ra_ReponseWindow +#1,2,4,8,10,20,40,80 + ra_ResponseWindow = 4; +#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR +#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen + ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; +#oneHalf (0..15) 4,8,12,16,...60,64 + ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15; +#ra_ContentionResolutionTimer +#(0..7) 8,16,24,32,40,48,56,64 + ra_ContentionResolutionTimer = 7; + rsrp_ThresholdSSB = 19; +#prach-RootSequenceIndex_PR +#1 = 839, 2 = 139 + prach_RootSequenceIndex_PR = 2; + prach_RootSequenceIndex = 1; + # SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex + # + msg1_SubcarrierSpacing = 0, +# restrictedSetConfig +# 0=unrestricted, 1=restricted type A, 2=restricted type B + restrictedSetConfig = 0, + + msg3_DeltaPreamble = 1; + p0_NominalWithGrant =-90; + +# pucch-ConfigCommon setup : +# pucchGroupHopping +# 0 = neither, 1= group hopping, 2=sequence hopping + pucchGroupHopping = 0; + hoppingId = 40; + p0_nominal = -90; + + ssb_PositionsInBurst_Bitmap = 1; + +# ssb_periodicityServingCell +# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1 + ssb_periodicityServingCell = 2; + +# dmrs_TypeA_position +# 0 = pos2, 1 = pos3 + dmrs_TypeA_Position = 0; + +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + subcarrierSpacing = 0; + + + #tdd-UL-DL-ConfigurationCommon +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + referenceSubcarrierSpacing = 0; + # pattern1 + # dl_UL_TransmissionPeriodicity + # 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10 + dl_UL_TransmissionPeriodicity = 6; + nrofDownlinkSlots = 7; + nrofDownlinkSymbols = 6; + nrofUplinkSlots = 2; + nrofUplinkSymbols = 4; + + ssPBCH_BlockPower = -25; + } + + ); + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + } +); + +MACRLCs = ({ + num_cc = 1; + tr_s_preference = "local_L1"; + tr_n_preference = "f1"; + local_n_if_name = "lo"; + local_n_address = "127.0.0.5"; + remote_n_address = "127.0.0.3"; + local_n_portc = 500; + local_n_portd = 2152; + remote_n_portc = 501; + remote_n_portd = 2152; + pusch_FailureThres = 1000; +}); + +L1s = ({ + num_cc = 1; + tr_n_preference = "local_mac"; + prach_dtx_threshold = 200; + pucch0_dtx_threshold = 150; + ofdm_offset_divisor = 8; #set this to UINT_MAX for offset 0 +}); + +RUs = ({ + local_rf = "yes" + nb_tx = 1 + nb_rx = 1 + att_tx = 0 + att_rx = 0; + bands = [66]; + max_pdschReferenceSignalPower = -27; + max_rxgain = 114; + eNB_instances = [0]; + clock_src = "internal"; +}); + +rfsimulator: { + serveraddr = "server"; + serverport = 4043; + options = (); #("saviq"); or/and "chanmod" + modelname = "AWGN"; + IQfile = "/tmp/rfsimulator.iqs" +} + +log_config: { + global_log_level = "info"; + hw_log_level = "info"; + nr_phy_log_level = "info"; + nr_mac_log_level = "info"; + rlc_log_level = "info"; + pdcp_log_level = "info"; + rrc_log_level = "info"; + f1ap_log_level = "info"; + ngap_log_level = "debug"; +}; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band78.106prb.rfsim.pci0.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band78.106prb.rfsim.pci0.conf new file mode 100644 index 0000000000..2e0f721504 --- /dev/null +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band78.106prb.rfsim.pci0.conf @@ -0,0 +1,212 @@ +Active_gNBs = ( "du-rfsim"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +gNBs = +( + { + ////////// Identification parameters: + gNB_ID = 0xe00; + gNB_DU_ID = 0xe00; + gNB_name = "du-rfsim"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = 1; + plmn_list = ({ mcc = 001; mnc = 01; mnc_length = 2; snssaiList = ({ sst = 1; }) }); + + nr_cellid = 12345678L; + + ////////// Physical parameters: + + min_rxtxtime = 4; + + servingCellConfigCommon = ( + { + #spCellConfigCommon + + physCellId = 0; + +# downlinkConfigCommon + #frequencyInfoDL + # this is 3600 MHz + 43 PRBs@30kHz SCS (same as initial BWP) + absoluteFrequencySSB = 630048; + dl_frequencyBand = 78; + # this is 3600 MHz + dl_absoluteFrequencyPointA = 628776; + #scs-SpecificCarrierList + dl_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + dl_subcarrierSpacing = 1; + dl_carrierBandwidth = 106; + #initialDownlinkBWP + #genericParameters + # this is RBstart=27,L=48 (275*(L-1))+RBstart + initialDLBWPlocationAndBandwidth = 28875; # 6366 12925 12956 28875 12952 +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialDLBWPsubcarrierSpacing = 1; + #pdcch-ConfigCommon + initialDLBWPcontrolResourceSetZero = 12; + initialDLBWPsearchSpaceZero = 0; + + #uplinkConfigCommon + #frequencyInfoUL + ul_frequencyBand = 78; + #scs-SpecificCarrierList + ul_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + ul_subcarrierSpacing = 1; + ul_carrierBandwidth = 106; + pMax = 20; + #initialUplinkBWP + #genericParameters + initialULBWPlocationAndBandwidth = 28875; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialULBWPsubcarrierSpacing = 1; + #rach-ConfigCommon + #rach-ConfigGeneric + prach_ConfigurationIndex = 98; +#prach_msg1_FDM +#0 = one, 1=two, 2=four, 3=eight + prach_msg1_FDM = 0; + prach_msg1_FrequencyStart = 0; + zeroCorrelationZoneConfig = 13; + preambleReceivedTargetPower = -96; +#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200) + preambleTransMax = 6; +#powerRampingStep +# 0=dB0,1=dB2,2=dB4,3=dB6 + powerRampingStep = 1; +#ra_ReponseWindow +#1,2,4,8,10,20,40,80 + ra_ResponseWindow = 4; +#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR +#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen + ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; +#oneHalf (0..15) 4,8,12,16,...60,64 + ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 14; +#ra_ContentionResolutionTimer +#(0..7) 8,16,24,32,40,48,56,64 + ra_ContentionResolutionTimer = 7; + rsrp_ThresholdSSB = 19; +#prach-RootSequenceIndex_PR +#1 = 839, 2 = 139 + prach_RootSequenceIndex_PR = 2; + prach_RootSequenceIndex = 1; + # SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex + # + msg1_SubcarrierSpacing = 1, +# restrictedSetConfig +# 0=unrestricted, 1=restricted type A, 2=restricted type B + restrictedSetConfig = 0, + + msg3_DeltaPreamble = 1; + p0_NominalWithGrant =-90; + +# pucch-ConfigCommon setup : +# pucchGroupHopping +# 0 = neither, 1= group hopping, 2=sequence hopping + pucchGroupHopping = 0; + hoppingId = 40; + p0_nominal = -90; + + ssb_PositionsInBurst_Bitmap = 1; + +# ssb_periodicityServingCell +# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1 + ssb_periodicityServingCell = 2; + +# dmrs_TypeA_position +# 0 = pos2, 1 = pos3 + dmrs_TypeA_Position = 0; + +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + subcarrierSpacing = 1; + + + #tdd-UL-DL-ConfigurationCommon +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + referenceSubcarrierSpacing = 1; + # pattern1 + # dl_UL_TransmissionPeriodicity + # 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10 + dl_UL_TransmissionPeriodicity = 6; + nrofDownlinkSlots = 7; + nrofDownlinkSymbols = 6; + nrofUplinkSlots = 2; + nrofUplinkSymbols = 4; + + ssPBCH_BlockPower = -25; + } + + ); + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + } +); + +MACRLCs = ({ + num_cc = 1; + tr_s_preference = "local_L1"; + tr_n_preference = "f1"; + local_n_if_name = "lo"; + local_n_address = "127.0.0.4"; + remote_n_address = "127.0.0.3"; + local_n_portc = 500; + local_n_portd = 2152; + remote_n_portc = 501; + remote_n_portd = 2152; + pusch_FailureThres = 1000; +}); + +L1s = ({ + num_cc = 1; + tr_n_preference = "local_mac"; + prach_dtx_threshold = 200; + pucch0_dtx_threshold = 150; + ofdm_offset_divisor = 8; #set this to UINT_MAX for offset 0 +}); + +RUs = ({ + local_rf = "yes" + nb_tx = 1 + nb_rx = 1 + att_tx = 0 + att_rx = 0; + bands = [78]; + max_pdschReferenceSignalPower = -27; + max_rxgain = 114; + eNB_instances = [0]; + clock_src = "internal"; +}); + +rfsimulator: { + serveraddr = "server"; + serverport = 4043; + options = (); #("saviq"); or/and "chanmod" + modelname = "AWGN"; + IQfile = "/tmp/rfsimulator.iqs" +} + +log_config: { + global_log_level = "info"; + hw_log_level = "info"; + nr_phy_log_level = "info"; + nr_mac_log_level = "info"; + rlc_log_level = "info"; + pdcp_log_level = "info"; + rrc_log_level = "info"; + f1ap_log_level = "info"; + ngap_log_level = "debug"; +}; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band78.106prb.rfsim.pci1.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band78.106prb.rfsim.pci1.conf new file mode 100644 index 0000000000..8e939887ce --- /dev/null +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band78.106prb.rfsim.pci1.conf @@ -0,0 +1,212 @@ +Active_gNBs = ( "du-rfsim"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +gNBs = +( + { + ////////// Identification parameters: + gNB_ID = 0xe00; + gNB_DU_ID = 0xe01; + gNB_name = "du-rfsim"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = 1; + plmn_list = ({ mcc = 001; mnc = 01; mnc_length = 2; snssaiList = ({ sst = 1; }) }); + + nr_cellid = 11111111L; + + ////////// Physical parameters: + + min_rxtxtime = 4; + + servingCellConfigCommon = ( + { + #spCellConfigCommon + + physCellId = 1; + +# downlinkConfigCommon + #frequencyInfoDL + # this is 3600 MHz + 43 PRBs@30kHz SCS (same as initial BWP) + absoluteFrequencySSB = 643296; + dl_frequencyBand = 78; + # this is 3600 MHz + dl_absoluteFrequencyPointA = 642024; + #scs-SpecificCarrierList + dl_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + dl_subcarrierSpacing = 1; + dl_carrierBandwidth = 106; + #initialDownlinkBWP + #genericParameters + # this is RBstart=27,L=48 (275*(L-1))+RBstart + initialDLBWPlocationAndBandwidth = 28875; # 6366 12925 12956 28875 12952 +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialDLBWPsubcarrierSpacing = 1; + #pdcch-ConfigCommon + initialDLBWPcontrolResourceSetZero = 12; + initialDLBWPsearchSpaceZero = 0; + + #uplinkConfigCommon + #frequencyInfoUL + ul_frequencyBand = 78; + #scs-SpecificCarrierList + ul_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + ul_subcarrierSpacing = 1; + ul_carrierBandwidth = 106; + pMax = 20; + #initialUplinkBWP + #genericParameters + initialULBWPlocationAndBandwidth = 28875; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialULBWPsubcarrierSpacing = 1; + #rach-ConfigCommon + #rach-ConfigGeneric + prach_ConfigurationIndex = 98; +#prach_msg1_FDM +#0 = one, 1=two, 2=four, 3=eight + prach_msg1_FDM = 0; + prach_msg1_FrequencyStart = 0; + zeroCorrelationZoneConfig = 13; + preambleReceivedTargetPower = -96; +#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200) + preambleTransMax = 6; +#powerRampingStep +# 0=dB0,1=dB2,2=dB4,3=dB6 + powerRampingStep = 1; +#ra_ReponseWindow +#1,2,4,8,10,20,40,80 + ra_ResponseWindow = 4; +#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR +#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen + ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; +#oneHalf (0..15) 4,8,12,16,...60,64 + ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 14; +#ra_ContentionResolutionTimer +#(0..7) 8,16,24,32,40,48,56,64 + ra_ContentionResolutionTimer = 7; + rsrp_ThresholdSSB = 19; +#prach-RootSequenceIndex_PR +#1 = 839, 2 = 139 + prach_RootSequenceIndex_PR = 2; + prach_RootSequenceIndex = 1; + # SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex + # + msg1_SubcarrierSpacing = 1, +# restrictedSetConfig +# 0=unrestricted, 1=restricted type A, 2=restricted type B + restrictedSetConfig = 0, + + msg3_DeltaPreamble = 1; + p0_NominalWithGrant =-90; + +# pucch-ConfigCommon setup : +# pucchGroupHopping +# 0 = neither, 1= group hopping, 2=sequence hopping + pucchGroupHopping = 0; + hoppingId = 40; + p0_nominal = -90; + + ssb_PositionsInBurst_Bitmap = 3; + +# ssb_periodicityServingCell +# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1 + ssb_periodicityServingCell = 2; + +# dmrs_TypeA_position +# 0 = pos2, 1 = pos3 + dmrs_TypeA_Position = 0; + +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + subcarrierSpacing = 1; + + + #tdd-UL-DL-ConfigurationCommon +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + referenceSubcarrierSpacing = 1; + # pattern1 + # dl_UL_TransmissionPeriodicity + # 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10 + dl_UL_TransmissionPeriodicity = 6; + nrofDownlinkSlots = 7; + nrofDownlinkSymbols = 6; + nrofUplinkSlots = 2; + nrofUplinkSymbols = 4; + + ssPBCH_BlockPower = -25; + } + + ); + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + } +); + +MACRLCs = ({ + num_cc = 1; + tr_s_preference = "local_L1"; + tr_n_preference = "f1"; + local_n_if_name = "lo"; + local_n_address = "127.0.0.5"; + remote_n_address = "127.0.0.3"; + local_n_portc = 500; + local_n_portd = 2152; + remote_n_portc = 501; + remote_n_portd = 2152; + pusch_FailureThres = 1000; +}); + +L1s = ({ + num_cc = 1; + tr_n_preference = "local_mac"; + prach_dtx_threshold = 200; + pucch0_dtx_threshold = 150; + ofdm_offset_divisor = 8; #set this to UINT_MAX for offset 0 +}); + +RUs = ({ + local_rf = "yes" + nb_tx = 1 + nb_rx = 1 + att_tx = 0 + att_rx = 0; + bands = [78]; + max_pdschReferenceSignalPower = -27; + max_rxgain = 114; + eNB_instances = [0]; + clock_src = "internal"; +}); + +rfsimulator: { + serveraddr = "server"; + serverport = 4043; + options = (); #("saviq"); or/and "chanmod" + modelname = "AWGN"; + IQfile = "/tmp/rfsimulator.iqs" +} + +log_config: { + global_log_level = "info"; + hw_log_level = "info"; + nr_phy_log_level = "info"; + nr_mac_log_level = "info"; + rlc_log_level = "info"; + pdcp_log_level = "info"; + rrc_log_level = "info"; + f1ap_log_level = "info"; + ngap_log_level = "debug"; +}; From ecd941e9466edac9379dcf3d974c5763437690d9 Mon Sep 17 00:00:00 2001 From: rmagueta Date: Wed, 5 Jun 2024 08:11:56 +0200 Subject: [PATCH 45/75] Remove old RA process(es) when removing UE In handover, we might need to remove a UE that we knew under it's C-RNTI, for which we also have the RA process. Hence, when removing a UE by RNTI, remove it also from RA. --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 0b09bb78a9..7ac6d28fb8 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -2675,6 +2675,16 @@ void mac_remove_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rnti) memcpy(UE_info->list, newUEs, sizeof(UE_info->list)); NR_SCHED_UNLOCK(&UE_info->mutex); + const int CC_id = 0; + NR_COMMON_channels_t *cc = &nr_mac->common_channels[CC_id]; + for (int i = 0; i < NR_NB_RA_PROC_MAX; i++) { + NR_RA_t *ra = &cc->ra[i]; + if (ra->rnti == UE->rnti) { + nr_clear_ra_proc(ra); + ra->cfra = 0; + } + } + delete_nr_ue_data(UE, nr_mac->common_channels, &UE_info->uid_allocator); } From c3ef6df44bf9e3460701b68f0046e73a1851c060 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 8 Oct 2024 10:53:56 +0200 Subject: [PATCH 46/75] Bugfix: request release in case of failed RA Prior to this commit, after RA failure, the DU would send a UE context release complete, without actually requesting one. This could lead to inconsistent state between DU and CU, because the CU might just discard this (unrequested) message, and not actually trigger a release [1]. Thus, refactor the release request into a function, and use it to request release of a UE for which RA has not been completed. If the CU does not know the UE, release the UE immediately. [1] One possibility would be that during reestablishment, the CU would request to look up an old DU UE ID when it has been released, resulting in Assertion (oldUE) failed! In dl_rrc_message_transfer() /home/oaicicd/robert/openairinterface5g/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c:860 CU claims we should know UE bc7f, but we don't --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 5 +-- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 33 ++++++++++++++----- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 3 +- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index e43123b55c..3e738db42a 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -2435,8 +2435,9 @@ void nr_schedule_RA(module_id_t module_idP, ra->contention_resolution_timer--; if (ra->contention_resolution_timer < 0) { LOG_W(NR_MAC, "(%d.%d) RA Contention Resolution timer expired for UE 0x%04x, RA procedure failed...\n", frameP, slotP, ra->rnti); - nr_mac_release_ue(mac, ra->rnti); - nr_mac_trigger_release_complete(mac, ra->rnti); + bool requested = nr_mac_request_release_ue(mac, ra->rnti); + if (!requested) + nr_mac_release_ue(mac, ra->rnti); nr_clear_ra_proc(ra); continue; } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 7ac6d28fb8..5930ef7f44 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -3302,7 +3302,27 @@ void nr_mac_reset_ul_failure(NR_UE_sched_ctrl_t *sched_ctrl) sched_ctrl->pusch_consecutive_dtx_cnt = 0; } -void nr_mac_check_ul_failure(const gNB_MAC_INST *nrmac, int rnti, NR_UE_sched_ctrl_t *sched_ctrl) +/* \brief trigger a release request towards the CU. + * \returns true if release was requested, else false (in which case the CU + * does not know the UE, and we can safely remove it). */ +bool nr_mac_request_release_ue(const gNB_MAC_INST *nrmac, int rnti) +{ + if (!du_exists_f1_ue_data(rnti)) { + LOG_W(NR_MAC, "UE %04x: no CU-UE ID stored, cannot request release\n", rnti); + return false; + } + f1_ue_data_t ue_data = du_get_f1_ue_data(rnti); + f1ap_ue_context_release_req_t request = { + .gNB_CU_ue_id = ue_data.secondary_ue, + .gNB_DU_ue_id = rnti, + .cause = F1AP_CAUSE_RADIO_NETWORK, + .cause_value = F1AP_CauseRadioNetwork_rl_failure_others, + }; + nrmac->mac_rrc.ue_context_release_request(&request); + return true; +} + +void nr_mac_check_ul_failure(gNB_MAC_INST *nrmac, int rnti, NR_UE_sched_ctrl_t *sched_ctrl) { if (!sched_ctrl->ul_failure) return; @@ -3312,14 +3332,9 @@ void nr_mac_check_ul_failure(const gNB_MAC_INST *nrmac, int rnti, NR_UE_sched_ct * stop at 0 and we wait for a UE release command from upper layers */ if (sched_ctrl->ul_failure_timer == 1) { LOG_W(MAC, "UE %04x: request release after UL failure timer expiry\n", rnti); - f1_ue_data_t ue_data = du_get_f1_ue_data(rnti); - f1ap_ue_context_release_req_t request = { - .gNB_CU_ue_id = ue_data.secondary_ue, - .gNB_DU_ue_id = rnti, - .cause = F1AP_CAUSE_RADIO_NETWORK, - .cause_value = F1AP_CauseRadioNetwork_rl_failure_others, - }; - nrmac->mac_rrc.ue_context_release_request(&request); + bool requested = nr_mac_request_release_ue(nrmac, rnti); + if (!requested) + nr_mac_release_ue(nrmac, rnti); } } diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index a75b9c0f60..c5df1782fd 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -464,10 +464,11 @@ void nr_mac_trigger_release_timer(NR_UE_sched_ctrl_t *sched_ctrl, NR_SubcarrierS bool nr_mac_check_release(NR_UE_sched_ctrl_t *sched_ctrl, int rnti); void nr_mac_trigger_release_complete(gNB_MAC_INST *mac, int rnti); void nr_mac_release_ue(gNB_MAC_INST *mac, int rnti); +bool nr_mac_request_release_ue(const gNB_MAC_INST *nrmac, int rnti); void nr_mac_trigger_ul_failure(NR_UE_sched_ctrl_t *sched_ctrl, NR_SubcarrierSpacing_t subcarrier_spacing); void nr_mac_reset_ul_failure(NR_UE_sched_ctrl_t *sched_ctrl); -void nr_mac_check_ul_failure(const gNB_MAC_INST *nrmac, int rnti, NR_UE_sched_ctrl_t *sched_ctrl); +void nr_mac_check_ul_failure(gNB_MAC_INST *nrmac, int rnti, NR_UE_sched_ctrl_t *sched_ctrl); void nr_mac_trigger_reconfiguration(const gNB_MAC_INST *nrmac, const NR_UE_info_t *UE); From 67eb94db3ffaaa5fd1c4f32926bc1a1aefb69ccf Mon Sep 17 00:00:00 2001 From: Roberto Magueta Date: Mon, 2 Sep 2024 16:37:16 +0200 Subject: [PATCH 47/75] Print RRC neighbor cell measurements, if present Co-authored-by: Luis Pereira --- openair2/RRC/NR/rrc_gNB.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 9803991db5..9e3cd6aa1d 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -2194,6 +2194,24 @@ static void print_rrc_meas(FILE *f, const NR_MeasResults_t *measresults) } else { fprintf(f, "NOT PROVIDED\n"); } + + if (measresults->measResultNeighCells + && measresults->measResultNeighCells->present == NR_MeasResults__measResultNeighCells_PR_measResultListNR) { + NR_MeasResultListNR_t *meas_neigh = measresults->measResultNeighCells->choice.measResultListNR; + for (int i = 0; i < meas_neigh->list.count; ++i) { + NR_MeasResultNR_t *measresultneigh = meas_neigh->list.array[i]; + NR_MeasQuantityResults_t *neigh_mqr = measresultneigh->measResult.cellResults.resultsSSB_Cell; + fprintf(f, " neighboring cell for phyCellId %ld:\n resultSSB:", *measresultneigh->physCellId); + if (mqr != NULL) { + const long rrsrp = *neigh_mqr->rsrp - 156; + const float rrsrq = (float)(*neigh_mqr->rsrq - 87) / 2.0f; + const float rsinr = (float)(*neigh_mqr->sinr - 46) / 2.0f; + fprintf(f, "RSRP %ld dBm RSRQ %.1f dB SINR %.1f dB\n", rrsrp, rrsrq, rsinr); + } else { + fprintf(f, "NOT PROVIDED\n"); + } + } + } } static const char *get_pdusession_status_text(pdu_session_status_t status) From 6cd76ff862491fe9742e2673a6b1fbdab82f8bbe Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 1 Oct 2024 19:30:02 +0200 Subject: [PATCH 48/75] Remove unused includes and comment with resolved issue --- openair2/RRC/NR/nr_rrc_defs.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index b5b27a6f4d..aebbed95b0 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -69,14 +69,6 @@ #include "intertask_interface.h" -/* TODO: be sure this include is correct. - * It solves a problem of compilation of the RRH GW, - * issue #186. - */ - #include "as_message.h" - - #include "commonDef.h" - #define PROTOCOL_NR_RRC_CTXT_UE_FMT PROTOCOL_CTXT_FMT #define PROTOCOL_NR_RRC_CTXT_UE_ARGS(CTXT_Pp) PROTOCOL_NR_CTXT_ARGS(CTXT_Pp) From 35995c8a10c4c591e0bbd07ef67e3c3fec8f86e2 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 4 Oct 2024 19:38:12 +0200 Subject: [PATCH 49/75] Move RETURN_IF_INVALID_ASSOC_ID() to header for use elsewhere RETURN_IF_INVALID_ASSOC_ID() checks if an assoc_id (of a DU) is valid. It will be also used in the mobility RRC module later. Move it to the DU header (where it logically belongs) to move it from there. --- openair2/RRC/NR/rrc_gNB.c | 10 ---------- openair2/RRC/NR/rrc_gNB_du.h | 10 ++++++++++ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 9e3cd6aa1d..840844a0ec 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -112,16 +112,6 @@ extern RAN_CONTEXT_t RC; mui_t rrc_gNB_mui = 0; -// the assoc_id might be 0 (if the DU goes offline). Below helper macro to -// print an error and return from the function in that case -#define RETURN_IF_INVALID_ASSOC_ID(assoc_id) \ - { \ - if (assoc_id == 0) { \ - LOG_E(NR_RRC, "cannot send data: invalid assoc_id 0, DU offline\n"); \ - return; \ - } \ - } - ///---------------------------------------------------------------------------------------------------------------/// ///---------------------------------------------------------------------------------------------------------------/// diff --git a/openair2/RRC/NR/rrc_gNB_du.h b/openair2/RRC/NR/rrc_gNB_du.h index 3ee0b611ef..2c0b5574ce 100644 --- a/openair2/RRC/NR/rrc_gNB_du.h +++ b/openair2/RRC/NR/rrc_gNB_du.h @@ -48,4 +48,14 @@ int get_dl_band(const struct f1ap_served_cell_info_t *cell_info); int get_ssb_scs(const struct f1ap_served_cell_info_t *cell_info); int get_ssb_arfcn(const struct nr_rrc_du_container_t *du); +// the assoc_id might be 0 (if the DU goes offline). Below helper macro to +// print an error and return from the function in that case +#define RETURN_IF_INVALID_ASSOC_ID(assoc_id) \ + { \ + if (assoc_id == 0) { \ + LOG_E(NR_RRC, "cannot send data: invalid assoc_id 0, DU offline\n"); \ + return; \ + } \ + } + #endif /* RRC_GNB_DU_H_ */ From b5e35077649f80bc828a55263d26ad77b8629d2e Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 22 Oct 2024 13:43:19 +0200 Subject: [PATCH 50/75] Fix: store CellGroupConfig from initial UL RRC message This F1 message sends us the CellGroupConfig of the UE. Store it in case we need it. For instance, at least in OAI, it is possible to make a handover without a DRB (this might or might not be standard compliant). However, in this case, we did never receive a UE context setup request, which stores the CellGroupConfig. Hence, store the first CellGroupConfig we receive, to be able to do e.g., handover. --- openair2/RRC/NR/rrc_gNB.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 840844a0ec..7b0333db85 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1029,9 +1029,18 @@ static void rrc_handle_RRCSetupRequest(gNB_RRC_INST *rrc, return; } + NR_CellGroupConfig_t *cellGroupConfig = NULL; + asn_dec_rval_t dec_rval = uper_decode_complete(NULL, + &asn_DEF_NR_CellGroupConfig, + (void **)&cellGroupConfig, + msg->du2cu_rrc_container, + msg->du2cu_rrc_container_length); + AssertFatal(dec_rval.code == RC_OK && dec_rval.consumed > 0, "Cell group config decode error\n"); + gNB_RRC_UE_t *UE = &ue_context_p->ue_context; UE = &ue_context_p->ue_context; UE->establishment_cause = rrcSetupRequest->establishmentCause; + UE->masterCellGroup = cellGroupConfig; activate_srb(UE, 1); rrc_gNB_generate_RRCSetup(0, msg->crnti, ue_context_p, msg->du2cu_rrc_container, msg->du2cu_rrc_container_length); } From b4bf59c55bce0c66d5a4055fb5d7b7ca2e2227fb Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 4 Jun 2024 13:51:21 +0200 Subject: [PATCH 51/75] Add telnet module function to trigger F1 HO --- common/utils/telnetsrv/telnetsrv_ci.c | 81 ++++++++++++++++++++------- 1 file changed, 62 insertions(+), 19 deletions(-) diff --git a/common/utils/telnetsrv/telnetsrv_ci.c b/common/utils/telnetsrv/telnetsrv_ci.c index 9f3c03c39a..700ff73135 100644 --- a/common/utils/telnetsrv/telnetsrv_ci.c +++ b/common/utils/telnetsrv/telnetsrv_ci.c @@ -71,30 +71,41 @@ int get_single_rnti(char *buf, int debug, telnet_printfunc_t prnt) return 0; } +rrc_gNB_ue_context_t *get_single_rrc_ue(void) +{ + rrc_gNB_ue_context_t *ue = NULL; + rrc_gNB_ue_context_t *l = NULL; + int n = 0; + RB_FOREACH (l, rrc_nr_ue_tree_s, &RC.nrrrc[0]->rrc_ue_head) { + if (ue == NULL) + ue = l; + n++; + } + if (!ue) { + printf("could not find any UE in RRC\n"); + } + if (n > 1) { + printf("more than one UE in RRC present\n"); + ue = NULL; + } + + return ue; +} + int get_reestab_count(char *buf, int debug, telnet_printfunc_t prnt) { if (!RC.nrrrc) ERROR_MSG_RET("no RRC present, cannot list counts\n"); rrc_gNB_ue_context_t *ue = NULL; - int rnti = -1; if (!buf) { - rrc_gNB_ue_context_t *l = NULL; - int n = 0; - RB_FOREACH(l, rrc_nr_ue_tree_s, &RC.nrrrc[0]->rrc_ue_head) { - if (ue == NULL) ue = l; - n++; - } + ue = get_single_rrc_ue(); if (!ue) - ERROR_MSG_RET("could not find any UE in RRC\n"); - if (n > 1) - ERROR_MSG_RET("more than one UE in RRC present\n"); + ERROR_MSG_RET("no single UE in RRC present\n"); } else { - rnti = strtol(buf, NULL, 16); - if (rnti < 1 || rnti >= 0xfffe) - ERROR_MSG_RET("RNTI needs to be [1,0xfffe]\n"); - ue = rrc_gNB_get_ue_context_by_rnti_any_du(RC.nrrrc[0], rnti); + ue_id_t ue_id = strtol(buf, NULL, 10); + ue = rrc_gNB_get_ue_context(RC.nrrrc[0], ue_id); if (!ue) - ERROR_MSG_RET("could not find UE with RNTI %04x in RRC\n"); + ERROR_MSG_RET("could not find UE with ue_id %d in RRC\n"); } prnt("UE RNTI %04x reestab %d reconfig %d\n", @@ -125,11 +136,43 @@ int trigger_reestab(char *buf, int debug, telnet_printfunc_t prnt) return 0; } +extern void nr_HO_F1_trigger_telnet(gNB_RRC_INST *rrc, uint32_t rrc_ue_id); +/** + * @brief Trigger F1 handover for UE + * @param buf: RRC UE ID or NULL for the first UE in list + * @param debug: Debug flag + * @param prnt: Print function + * @return 0 on success, -1 on failure + */ +int rrc_gNB_trigger_f1_ho(char *buf, int debug, telnet_printfunc_t prnt) +{ + if (!RC.nrrrc) + ERROR_MSG_RET("no RRC present, cannot list counts\n"); + rrc_gNB_ue_context_t *ue = NULL; + if (!buf) { + ue = get_single_rrc_ue(); + if (!ue) + ERROR_MSG_RET("no single UE in RRC present\n"); + } else { + ue_id_t ue_id = strtol(buf, NULL, 10); + ue = rrc_gNB_get_ue_context(RC.nrrrc[0], ue_id); + if (!ue) + ERROR_MSG_RET("could not find UE with ue_id %d in RRC\n", ue_id); + } + + gNB_RRC_UE_t *UE = &ue->ue_context; + nr_HO_F1_trigger_telnet(RC.nrrrc[0], UE->rrc_ue_id); + prnt("RRC F1 handover triggered for UE %u\n", UE->rrc_ue_id); + + return 0; +} + static telnetshell_cmddef_t cicmds[] = { - {"get_single_rnti", "", get_single_rnti}, - {"force_reestab", "[rnti(hex,opt)]", trigger_reestab}, - {"get_reestab_count", "[rnti(hex,opt)]", get_reestab_count}, - {"", "", NULL}, + {"get_single_rnti", "", get_single_rnti}, + {"force_reestab", "[rnti(hex,opt)]", trigger_reestab}, + {"get_reestab_count", "[rnti(hex,opt)]", get_reestab_count}, + {"trigger_f1_ho", "[rrc_ue_id(int,opt)]", rrc_gNB_trigger_f1_ho}, + {"", "", NULL}, }; static telnetshell_vardef_t civars[] = { From 90d8eefa591c0935a6b4ba814ff256bbc211c9af Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 25 Jul 2024 13:43:20 +0200 Subject: [PATCH 52/75] Add new handover context structures for handover operation --- CMakeLists.txt | 1 + openair2/RRC/NR/nr_rrc_defs.h | 22 ++-------- openair2/RRC/NR/rrc_gNB.c | 1 + openair2/RRC/NR/rrc_gNB_mobility.c | 48 +++++++++++++++++++++ openair2/RRC/NR/rrc_gNB_mobility.h | 69 ++++++++++++++++++++++++++++++ 5 files changed, 123 insertions(+), 18 deletions(-) create mode 100644 openair2/RRC/NR/rrc_gNB_mobility.c create mode 100644 openair2/RRC/NR/rrc_gNB_mobility.h diff --git a/CMakeLists.txt b/CMakeLists.txt index af48eca7b3..c34e3cbbd7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1271,6 +1271,7 @@ set(L2_NR_SRC ${NR_RRC_DIR}/rrc_gNB_radio_bearers.c ${NR_RRC_DIR}/rrc_gNB_cuup.c ${NR_RRC_DIR}/rrc_gNB_du.c + ${NR_RRC_DIR}/rrc_gNB_mobility.c ) set(L2_SRC_UE diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index aebbed95b0..14d08e9c45 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -112,23 +112,6 @@ typedef struct nr_e_rab_param_s { uint8_t xid; // transaction_id } __attribute__ ((__packed__)) nr_e_rab_param_t; - -typedef struct HANDOVER_INFO_NR_s { - uint8_t ho_prepare; - uint8_t ho_complete; - uint8_t modid_s; //module_idP of serving cell - uint8_t modid_t; //module_idP of target cell - uint8_t ueid_s; //UE index in serving cell - uint8_t ueid_t; //UE index in target cell - - // NR not define at this moment - //AS_Config_t as_config; /* these two parameters are taken from 36.331 section 10.2.2: HandoverPreparationInformation-r8-IEs */ - //AS_Context_t as_context; /* They are mandatory for HO */ - - uint8_t buf[NR_RRC_BUF_SIZE]; /* ASN.1 encoded handoverCommandMessage */ - int size; /* size of above message in bytes */ -} NR_HANDOVER_INFO; - typedef struct nr_rrc_guami_s { uint16_t mcc; uint16_t mnc; @@ -214,6 +197,9 @@ typedef enum { RRC_UECAPABILITY_ENQUIRY, } rrc_action_t; +/* forward declaration */ +typedef struct nr_handover_context_s nr_handover_context_t; + typedef struct gNB_RRC_UE_s { time_t last_seen; // last time this UE has been accessed @@ -222,7 +208,7 @@ typedef struct gNB_RRC_UE_s { NR_SRB_INFO_TABLE_ENTRY Srb[NR_NUM_SRB]; NR_MeasConfig_t *measConfig; - NR_HANDOVER_INFO *handover_info; + nr_handover_context_t *ho_context; NR_MeasResults_t *measResults; bool as_security_active; diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 7b0333db85..df865c02a8 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -77,6 +77,7 @@ #include "rrc_gNB_NGAP.h" #include "rrc_gNB_du.h" +#include "rrc_gNB_mobility.h" #include "rrc_gNB_GTPV1U.h" diff --git a/openair2/RRC/NR/rrc_gNB_mobility.c b/openair2/RRC/NR/rrc_gNB_mobility.c new file mode 100644 index 0000000000..72ae57b67e --- /dev/null +++ b/openair2/RRC/NR/rrc_gNB_mobility.c @@ -0,0 +1,48 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include + +#include "assertions.h" +#include "rrc_gNB_mobility.h" + +typedef enum { HO_CTX_BOTH, HO_CTX_SOURCE, HO_CTX_TARGET } ho_ctx_type_t; +static nr_handover_context_t *alloc_ho_ctx(ho_ctx_type_t type) +{ + nr_handover_context_t *ho_ctx = calloc(1, sizeof(*ho_ctx)); + AssertFatal(ho_ctx != NULL, "out of memory\n"); + if (type == HO_CTX_SOURCE || type == HO_CTX_BOTH) { + ho_ctx->source = calloc(1, sizeof(*ho_ctx->source)); + AssertFatal(ho_ctx->source != NULL, "out of memory\n"); + } + if (type == HO_CTX_TARGET || type == HO_CTX_BOTH) { + ho_ctx->target = calloc(1, sizeof(*ho_ctx->target)); + AssertFatal(ho_ctx->target != NULL, "out of memory\n"); + } + return ho_ctx; +} + +static void free_ho_ctx(nr_handover_context_t *ho_ctx) +{ + free(ho_ctx->source); + free(ho_ctx->target); + free(ho_ctx); +} diff --git a/openair2/RRC/NR/rrc_gNB_mobility.h b/openair2/RRC/NR/rrc_gNB_mobility.h new file mode 100644 index 0000000000..fefa39982b --- /dev/null +++ b/openair2/RRC/NR/rrc_gNB_mobility.h @@ -0,0 +1,69 @@ +/* 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 + */ + +#ifndef RRC_GNB_MOBILITY_H_ +#define RRC_GNB_MOBILITY_H_ + +#include + +/* forward declarations */ +typedef struct gNB_RRC_INST_s gNB_RRC_INST; +typedef struct gNB_RRC_UE_s gNB_RRC_UE_t; +typedef struct nr_rrc_du_container_t nr_rrc_du_container_t; + +typedef void (*ho_cancel_t)(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue); +typedef struct nr_ho_source_cu { + /// pointer to the (source) DU structure + const nr_rrc_du_container_t *du; + /// (source) DU UE ID; in F1, the DU UE ID will change to the new (target) DU + /// UE ID during handover, and the CU needs to keep track of this in case of + /// reestablishment + uint32_t du_ue_id; + /// old (source) RNTI (to recognize a UE during reestablishment) + rnti_t old_rnti; + /// function pointer to announce the handover cancellation, e.g., + /// reestablishment + ho_cancel_t ho_cancel; +} 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, uint8_t *buf, uint32_t len); +typedef void (*ho_success_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; + /// (target) DU UE ID; the (source) DU UE ID will change to the new (target) + /// DU UE ID after sending a reconfiguration, which is later than when + /// receiving this ID + uint32_t du_ue_id; + /// new (target) RNTI (as for du_ue_id) + rnti_t new_rnti; + /// 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; +} nr_ho_target_cu_t; + +typedef struct nr_handover_context_s { + nr_ho_source_cu_t *source; + nr_ho_target_cu_t *target; +} nr_handover_context_t; + +#endif /* RRC_GNB_MOBILITY_H_ */ From 746dc29a466001a1fc47ae0a75c2c3aea5312342 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 4 Oct 2024 20:01:46 +0200 Subject: [PATCH 53/75] Add HandoverPreparationInformation() ASN.1 encoder function HandoverPreparationInformation will be used in the follow-up commit to trigger a handover. Co-authored-by: batuhanduyuler Co-authored-by: rmagueta --- openair2/RRC/NR/MESSAGES/asn1_msg.c | 41 +++++++++++++++++++++++++++++ openair2/RRC/NR/MESSAGES/asn1_msg.h | 2 ++ 2 files changed, 43 insertions(+) diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 8025fb2243..68a8c49774 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -80,6 +80,8 @@ #include "NR_PCCH-Message.h" #include "NR_PagingRecord.h" #include "NR_UE-CapabilityRequestFilterNR.h" +#include "NR_HandoverPreparationInformation.h" +#include "NR_HandoverPreparationInformation-IEs.h" #include "common/utils/nr/nr_common.h" #if defined(NR_Rel16) #include "NR_SCS-SpecificCarrier.h" @@ -1373,3 +1375,42 @@ int do_NR_Paging(uint8_t Mod_id, uint8_t *buffer, uint32_t tmsi) return((enc_rval.encoded+7)/8); } + +/* \brief generate HandoverPreparationInformation to be sent to the DU for + * handover. Takes uecap_buf in encoded form as (1) this is the form present at + * the CU already (2) we have to clone this information anyway, so can take it + * in encoded form which we decode + add to the handoverPreparationInformation */ +int do_NR_HandoverPreparationInformation(const uint8_t *uecap_buf, int uecap_buf_size, uint8_t *buf, int buf_size) +{ + NR_HandoverPreparationInformation_t *hpi = calloc(1, sizeof(*hpi)); + AssertFatal(hpi != NULL, "out of memory\n"); + hpi->criticalExtensions.present = NR_HandoverPreparationInformation__criticalExtensions_PR_c1; + hpi->criticalExtensions.choice.c1 = calloc(1, sizeof(*hpi->criticalExtensions.choice.c1)); + AssertFatal(hpi->criticalExtensions.choice.c1 != NULL, "out of memory\n"); + hpi->criticalExtensions.choice.c1->present = + NR_HandoverPreparationInformation__criticalExtensions__c1_PR_handoverPreparationInformation; + NR_HandoverPreparationInformation_IEs_t *hpi_ie = calloc(1, sizeof(*hpi_ie)); + AssertFatal(hpi_ie != NULL, "out of memory\n"); + hpi->criticalExtensions.choice.c1->choice.handoverPreparationInformation = hpi_ie; + + NR_UE_CapabilityRAT_ContainerList_t *list = NULL; + asn_dec_rval_t dec_rval = + uper_decode_complete(NULL, &asn_DEF_NR_UE_CapabilityRAT_ContainerList, (void **)&list, uecap_buf, uecap_buf_size); + if (dec_rval.code == RC_OK) { + hpi_ie->ue_CapabilityRAT_List = *list; + free(list); /* list itself is not needed, members below will be freed in ASN_STRUCT_FREE */ + } else { + /* problem with decoding, don't put a capability */ + ASN_STRUCT_FREE(asn_DEF_NR_UE_CapabilityRAT_ContainerList, list); + list = NULL; + } + + if (LOG_DEBUGFLAG(DEBUG_ASN1)) + xer_fprint(stdout, &asn_DEF_NR_HandoverPreparationInformation, hpi); + + asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_HandoverPreparationInformation, NULL, hpi, buf, buf_size); + AssertFatal(enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n", enc_rval.failed_type->name, enc_rval.encoded); + + ASN_STRUCT_FREE(asn_DEF_NR_HandoverPreparationInformation, hpi); + return (enc_rval.encoded + 7) / 8; +} diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.h b/openair2/RRC/NR/MESSAGES/asn1_msg.h index 8609e20328..2f0b4febf8 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.h +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.h @@ -109,6 +109,8 @@ int do_RRCSetupComplete(uint8_t *buffer, const int dedicatedInfoNASLength, const char *dedicatedInfoNAS); +int do_NR_HandoverPreparationInformation(const uint8_t *uecap_buf, int uecap_buf_size, uint8_t *buf, int buf_size); + int do_RRCSetupRequest(uint8_t *buffer, size_t buffer_size, uint8_t *rv); int do_NR_RRCReconfigurationComplete_for_nsa(uint8_t *buffer, size_t buffer_size, NR_RRC_TransactionIdentifier_t Transaction_id); From c0770cc19b52375d615d617033b9d5d565f2e5ad Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 4 Oct 2024 20:02:44 +0200 Subject: [PATCH 54/75] Make QoS characteristics function available Functions get_qos_char_from_qos_flow_param() and get_qos_characteristics() will be used in rrc_gNB_mobility.c to read PDU information for handover. Move the definitions to a header to reuse later. --- openair2/RRC/NR/nr_rrc_proto.h | 3 +++ openair2/RRC/NR/rrc_gNB.c | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/openair2/RRC/NR/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h index 9c3d276394..576a1f636a 100644 --- a/openair2/RRC/NR/nr_rrc_proto.h +++ b/openair2/RRC/NR/nr_rrc_proto.h @@ -130,4 +130,7 @@ void rrc_gNB_generate_UeContextModificationRequest(const gNB_RRC_INST *rrc, int n_rel_drbs, const f1ap_drb_to_be_released_t *rel_drbs); +pdusession_level_qos_parameter_t *get_qos_characteristics(const int qfi, rrc_pdu_session_param_t *pduSession); +f1ap_qos_characteristics_t get_qos_char_from_qos_flow_param(const pdusession_level_qos_parameter_t *qos_param); + #endif diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index df865c02a8..268dfb7772 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -2023,7 +2023,7 @@ unsigned int mask_flip(unsigned int x) { return((((x>>8) + (x<<8))&0xffff)>>6); } -static pdusession_level_qos_parameter_t *get_qos_characteristics(const int qfi, rrc_pdu_session_param_t *pduSession) +pdusession_level_qos_parameter_t *get_qos_characteristics(const int qfi, rrc_pdu_session_param_t *pduSession) { pdusession_t *pdu = &pduSession->param; for (int i = 0; i < pdu->nb_qos; i++) { @@ -2035,7 +2035,7 @@ static pdusession_level_qos_parameter_t *get_qos_characteristics(const int qfi, } /* \bref return F1AP QoS characteristics based on Qos flow parameters */ -static f1ap_qos_characteristics_t get_qos_char_from_qos_flow_param(const pdusession_level_qos_parameter_t *qos_param) +f1ap_qos_characteristics_t get_qos_char_from_qos_flow_param(const pdusession_level_qos_parameter_t *qos_param) { f1ap_qos_characteristics_t qos_char = {0}; if (qos_param->fiveQI_type == DYNAMIC) { From 66b548060e8d3740553b68a1662e2d9964d6c0ff Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 4 Oct 2024 20:03:44 +0200 Subject: [PATCH 55/75] Implement F1 Handover Trigger Add a function to trigger an F1 handover, including the corresponding telnet function implementation. The function looks up source&target DU, creates a HO context, and reads PDU information to send a UE context setup request to the target DU towards which to handover. Co-authored-by: batuhanduyuler Co-authored-by: rmagueta --- openair2/RRC/NR/rrc_gNB_du.c | 28 +++++ openair2/RRC/NR/rrc_gNB_du.h | 2 + openair2/RRC/NR/rrc_gNB_mobility.c | 195 +++++++++++++++++++++++++++++ openair2/RRC/NR/rrc_gNB_mobility.h | 2 + 4 files changed, 227 insertions(+) diff --git a/openair2/RRC/NR/rrc_gNB_du.c b/openair2/RRC/NR/rrc_gNB_du.c index e2806edf60..51abc95dd0 100644 --- a/openair2/RRC/NR/rrc_gNB_du.c +++ b/openair2/RRC/NR/rrc_gNB_du.c @@ -592,3 +592,31 @@ void dump_du_info(const gNB_RRC_INST *rrc, FILE *f) } } } + +nr_rrc_du_container_t *find_target_du(gNB_RRC_INST *rrc, sctp_assoc_t source_assoc_id) +{ + nr_rrc_du_container_t *target_du = NULL; + nr_rrc_du_container_t *it = NULL; + bool next_du = false; + RB_FOREACH (it, rrc_du_tree, &rrc->dus) { + if (next_du == false && source_assoc_id != it->assoc_id) { + continue; + } else if (source_assoc_id == it->assoc_id) { + next_du = true; + } else { + target_du = it; + break; + } + } + if (target_du == NULL) { + RB_FOREACH (it, rrc_du_tree, &rrc->dus) { + if (source_assoc_id == it->assoc_id) { + continue; + } else { + target_du = it; + break; + } + } + } + return target_du; +} diff --git a/openair2/RRC/NR/rrc_gNB_du.h b/openair2/RRC/NR/rrc_gNB_du.h index 2c0b5574ce..55a0d7c2c8 100644 --- a/openair2/RRC/NR/rrc_gNB_du.h +++ b/openair2/RRC/NR/rrc_gNB_du.h @@ -48,6 +48,8 @@ int get_dl_band(const struct f1ap_served_cell_info_t *cell_info); int get_ssb_scs(const struct f1ap_served_cell_info_t *cell_info); int get_ssb_arfcn(const struct nr_rrc_du_container_t *du); +struct nr_rrc_du_container_t *find_target_du(struct gNB_RRC_INST_s *rrc, sctp_assoc_t source_assoc_id); + // the assoc_id might be 0 (if the DU goes offline). Below helper macro to // print an error and return from the function in that case #define RETURN_IF_INVALID_ASSOC_ID(assoc_id) \ diff --git a/openair2/RRC/NR/rrc_gNB_mobility.c b/openair2/RRC/NR/rrc_gNB_mobility.c index 72ae57b67e..cb6e851ebb 100644 --- a/openair2/RRC/NR/rrc_gNB_mobility.c +++ b/openair2/RRC/NR/rrc_gNB_mobility.c @@ -22,8 +22,16 @@ #include #include "assertions.h" + #include "rrc_gNB_mobility.h" +#include "nr_rrc_proto.h" +#include "rrc_gNB_du.h" +#include "rrc_gNB_radio_bearers.h" +#include "rrc_gNB_UE_context.h" +#include "openair2/F1AP/f1ap_ids.h" +#include "MESSAGES/asn1_msg.h" + typedef enum { HO_CTX_BOTH, HO_CTX_SOURCE, HO_CTX_TARGET } ho_ctx_type_t; static nr_handover_context_t *alloc_ho_ctx(ho_ctx_type_t type) { @@ -46,3 +54,190 @@ static void free_ho_ctx(nr_handover_context_t *ho_ctx) free(ho_ctx->target); free(ho_ctx); } + +/* \brief Initiate a handover of UE to a specific target cell handled by this + * CU. + * \param ue a UE context for which the handover should be triggered. The UE + * context must be non-null (if the HO request comes from "outside" (N2, Xn), + * the UE contex must be created first. + * \param target_du the DU towards which to handover. Note: currently, the CU + * is limited to one cell per DU, so DU and cell are equivalent here. + * \param ho_ctxt contextual data for the type of handover (F1, N2, Xn) */ +static void nr_initiate_handover(const gNB_RRC_INST *rrc, + gNB_RRC_UE_t *ue, + const nr_rrc_du_container_t *source_du, + const nr_rrc_du_container_t *target_du, + uint8_t *ho_prep_buf, + uint32_t ho_prep_len, + ho_req_ack_t ack, + ho_success_t success, + ho_cancel_t cancel) +{ + DevAssert(rrc != NULL); + DevAssert(ue != NULL); + DevAssert(target_du != NULL); + // source_du might be NULL -> inter-CU handover + DevAssert(ho_prep_buf != NULL && ho_prep_len > 0); + + if (ue->ho_context != NULL) { + LOG_E(NR_RRC, "handover for UE %u ongoing, cannot trigger new\n", ue->rrc_ue_id); + return; + } + // if any reconfiguration is ongoing, abort handover request + for (int i = 0; i < NR_RRC_TRANSACTION_IDENTIFIER_NUMBER; ++i) { + if (ue->xids[i] != RRC_ACTION_NONE) { + LOG_E(NR_RRC, "UE %d: ongoig transaction %d (action %d), cannot trigger handover\n", ue->rrc_ue_id, i, ue->xids[i]); + return; + } + } + + // if we know the source DU (F1 handover), allocate the context for it, + // otherwise only for the target DU (N2, Xn) + ho_ctx_type_t ctx_type = source_du != NULL ? HO_CTX_BOTH : HO_CTX_TARGET; + nr_handover_context_t *ho_ctx = alloc_ho_ctx(ctx_type); + ho_ctx->target->du = target_du; + // we will know target->{du_ue_id,new_rnti} once we have UE ctxt setup + // response + ho_ctx->target->ho_req_ack = ack; + ho_ctx->target->ho_success = success; + + const f1_ue_data_t ue_data = cu_get_f1_ue_data(ue->rrc_ue_id); + if (source_du != NULL) { + DevAssert(source_du->assoc_id == ue_data.du_assoc_id); + // we also have the source DU (F1 handover), store meta info + ho_ctx->source->ho_cancel = cancel; + + ho_ctx->source->du = source_du; + ho_ctx->source->du_ue_id = ue_data.secondary_ue; + ho_ctx->source->old_rnti = ue->rnti; + } + ue->ho_context = ho_ctx; + LOG_A(NR_RRC, + "Handover triggered for UE %u/RNTI %04x towards DU %ld/assoc_id %d/PCI %d\n", + ue->rrc_ue_id, + ue->rnti, + target_du->setup_req->gNB_DU_id, + target_du->assoc_id, + target_du->setup_req->cell[0].info.nr_pci); + + cu_to_du_rrc_information_t cu2du = { + .handoverPreparationInfo = ho_prep_buf, + .handoverPreparationInfo_length = ho_prep_len, + }; + + f1ap_drb_to_be_setup_t drbs[32] = {0}; // maximum DRB can be 32 + int nb_drb = 0; + for (int i = 0; i < 32; ++i) { /* for each DRB */ + drb_t *rrc_drb = &ue->established_drbs[i]; + if (rrc_drb->status == DRB_INACTIVE) + continue; + + f1ap_drb_to_be_setup_t *drb = &drbs[nb_drb]; + nb_drb++; + drb->drb_id = rrc_drb->drb_id; + drb->rlc_mode = rrc->configuration.um_on_default_drb ? F1AP_RLC_MODE_UM_BIDIR : F1AP_RLC_MODE_AM; + memcpy(&drb->up_ul_tnl[0].tl_address, &rrc_drb->cuup_tunnel_config.addr.buffer, sizeof(uint8_t) * 4); + drb->up_ul_tnl[0].port = rrc->eth_params_s.my_portd; + drb->up_ul_tnl[0].teid = rrc_drb->cuup_tunnel_config.teid; + drb->up_ul_tnl_length = 1; + + /* fetch an existing PDU session for this DRB */ + rrc_pdu_session_param_t *pdu = find_pduSession_from_drbId(ue, drb->drb_id); + AssertFatal(pdu != NULL, "no PDU session for DRB ID %ld\n", drb->drb_id); + drb->nssai = pdu->param.nssai; + + // for the moment, we only support one QoS flow. Put a reminder in case + // this changes + AssertFatal(pdu->param.nb_qos == 1, "only 1 Qos flow supported\n"); + drb->drb_info.flows_to_be_setup_length = 1; + drb->drb_info.flows_mapped_to_drb = calloc(1, sizeof(f1ap_flows_mapped_to_drb_t)); + AssertFatal(drb->drb_info.flows_mapped_to_drb, "could not allocate memory\n"); + int qfi = rrc_drb->cnAssociation.sdap_config.mappedQoS_FlowsToAdd[0]; + DevAssert(qfi > 0); + drb->drb_info.flows_mapped_to_drb[0].qfi = qfi; + pdusession_level_qos_parameter_t *in_qos_char = get_qos_characteristics(qfi, pdu); + drb->drb_info.flows_mapped_to_drb[0].qos_params.qos_characteristics = get_qos_char_from_qos_flow_param(in_qos_char); + + /* the DRB QoS parameters: we just reuse the ones from the first flow */ + drb->drb_info.drb_qos = drb->drb_info.flows_mapped_to_drb[0].qos_params; + } + + f1ap_srb_to_be_setup_t srbs[2] = {{.srb_id = 1, .lcid = 1}, {.srb_id = 2, .lcid = 2}}; + f1ap_served_cell_info_t *cell_info = &target_du->setup_req->cell[0].info; + RETURN_IF_INVALID_ASSOC_ID(target_du->assoc_id); + f1ap_ue_context_setup_t ue_context_setup_req = { + .gNB_CU_ue_id = ue->rrc_ue_id, + .gNB_DU_ue_id = 0, /* TODO: this should be optional! */ + .plmn.mcc = cell_info->plmn.mcc, + .plmn.mnc = cell_info->plmn.mnc, + .plmn.mnc_digit_length = cell_info->plmn.mnc_digit_length, + .nr_cellid = cell_info->nr_cellid, + .servCellId = 0, // TODO: correct value? + .srbs_to_be_setup_length = 2, + .srbs_to_be_setup = srbs, + .drbs_to_be_setup_length = nb_drb, + .drbs_to_be_setup = drbs, + .cu_to_du_rrc_information = &cu2du, + }; + rrc->mac_rrc.ue_context_setup_request(target_du->assoc_id, &ue_context_setup_req); +} + +/* +void nr_rrc_trigger_n2_ho(gNB_RRC_INST *rrc, int nr_cgi, uint8_t *ho_prep_info, uint32_t *ho_prep_len, void *pdu_session) +{ + // call from outside (via NGAP message), with the request for handover for a + // (any) UE. This handler should, in order: + // + // 1. look up the target DU =du= via get_du_by_cell_id(nr_cgi) + // (and reject the request if it can't find the DU) + // 2. create a context for a new UE =UE=, based on pdu_session information + // 3. call nr_initiate_handover(rrc, UE, NULL, du, ho_prep_info, ho_prep_len); + // + // after success of the DU, send the result via =success_ptr= to the source + // CU. +} +*/ + +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) +{ + DevAssert(rrc != NULL); + DevAssert(ue != NULL); + + uint8_t buf[NR_RRC_BUF_SIZE]; + int size = do_NR_HandoverPreparationInformation(ue->ue_cap_buffer.buf, ue->ue_cap_buffer.len, buf, sizeof buf); + + // corresponds to a "handover request", 38.300 Sec 9.3.2.3 + // see also 38.413 Sec 9.3.1.29 for information on source-CU to target-CU + // information (Source NG-RAN Node to Target NG-RAN Node Transparent Container) + // here: target Cell is preselected, target CU has access to UE information + // and therefore also the PDU sessions. Orig RRC reconfiguration should be in + // handover preparation information + ho_req_ack_t ack = NULL; + ho_success_t success = NULL; + ho_cancel_t cancel = NULL; + nr_initiate_handover(rrc, ue, source_du, target_du, buf, size, ack, success, cancel); +} + +void nr_HO_F1_trigger_telnet(gNB_RRC_INST *rrc, uint32_t rrc_ue_id) +{ + rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(rrc, rrc_ue_id); + if (ue_context_p == NULL) { + LOG_E(NR_RRC, "cannot find UE context for UE ID %d\n", rrc_ue_id); + return; + } + gNB_RRC_UE_t *ue = &ue_context_p->ue_context; + nr_rrc_du_container_t *source_du = get_du_for_ue(rrc, ue->rrc_ue_id); + if (source_du == NULL) { + f1_ue_data_t ue_data = cu_get_f1_ue_data(rrc_ue_id); + LOG_E(NR_RRC, "cannot get source gNB-DU with assoc_id %d for UE %u\n", ue_data.du_assoc_id, ue->rrc_ue_id); + return; + } + + nr_rrc_du_container_t *target_du = find_target_du(rrc, source_du->assoc_id); + if (target_du == NULL) { + LOG_E(NR_RRC, "No target gNB-DU found. Handover for UE %u aborted.\n", ue->rrc_ue_id); + return; + } + + nr_rrc_trigger_f1_ho(rrc, ue, source_du, target_du); +} diff --git a/openair2/RRC/NR/rrc_gNB_mobility.h b/openair2/RRC/NR/rrc_gNB_mobility.h index fefa39982b..5811804009 100644 --- a/openair2/RRC/NR/rrc_gNB_mobility.h +++ b/openair2/RRC/NR/rrc_gNB_mobility.h @@ -66,4 +66,6 @@ typedef struct nr_handover_context_s { nr_ho_target_cu_t *target; } nr_handover_context_t; +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); + #endif /* RRC_GNB_MOBILITY_H_ */ From 7b163f16889398385f9af1233e20eef7a1bf2f64 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 4 Oct 2024 21:54:39 +0200 Subject: [PATCH 56/75] Harmonize UE context setup resp bearer handling This is preparatory work to handle the UE context setup response from the target DU. There are two cases: - "Initial" UE context setup response (during connection setup): we need to inform the CU-UP via an E1 message of the new bearers (GTP tunnel update) - F1 handover: we need to inform the CU-UP via an E1 message that there are DRBs to reestablish There are two different functions, e1_send_bearer_updates() and cuup_notify_reestablishment(), to do this. Harmonize the code, before implementing the actual handover logic in the next commit. --- openair2/RRC/NR/rrc_gNB.c | 8 +++++++- openair2/RRC/NR/rrc_gNB_radio_bearers.c | 9 +++++++++ openair2/RRC/NR/rrc_gNB_radio_bearers.h | 3 +++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 268dfb7772..08547d7542 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1851,11 +1851,17 @@ static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, instance xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, UE->masterCellGroup); if (resp->drbs_to_be_setup_length > 0) { + int num_drb = get_number_active_drbs(UE); + DevAssert(num_drb == 0 || num_drb == resp->drbs_to_be_setup_length); + /* Note: we would ideally check that SRB2 is acked, but at least LiteOn DU * seems buggy and does not ack, so simply check that locally we activated */ AssertFatal(UE->Srb[1].Active && UE->Srb[2].Active, "SRBs 1 and 2 must be active during DRB Establishment"); store_du_f1u_tunnel(resp->drbs_to_be_setup, resp->drbs_to_be_setup_length, UE); - e1_send_bearer_updates(rrc, UE, resp->drbs_to_be_setup_length, resp->drbs_to_be_setup); + if (num_drb == 0) + e1_send_bearer_updates(rrc, UE, resp->drbs_to_be_setup_length, resp->drbs_to_be_setup); + else + cuup_notify_reestablishment(rrc, UE); } rrc_gNB_generate_dedicatedRRCReconfiguration(rrc, UE); diff --git a/openair2/RRC/NR/rrc_gNB_radio_bearers.c b/openair2/RRC/NR/rrc_gNB_radio_bearers.c index ab2bf13071..aec7865a1c 100644 --- a/openair2/RRC/NR/rrc_gNB_radio_bearers.c +++ b/openair2/RRC/NR/rrc_gNB_radio_bearers.c @@ -181,6 +181,15 @@ uint8_t get_next_available_drb_id(gNB_RRC_UE_t *ue) return DRB_INACTIVE; } +int get_number_active_drbs(gNB_RRC_UE_t *ue) +{ + int n = 0; + for (int i = 0; i < MAX_DRBS_PER_UE; ++i) + if (ue->established_drbs[i].status != DRB_INACTIVE) + n++; + return n; +} + bool drb_is_active(gNB_RRC_UE_t *ue, uint8_t drb_id) { drb_t *drb = get_drb(ue, drb_id); diff --git a/openair2/RRC/NR/rrc_gNB_radio_bearers.h b/openair2/RRC/NR/rrc_gNB_radio_bearers.h index 82502d8669..29fead6bea 100644 --- a/openair2/RRC/NR/rrc_gNB_radio_bearers.h +++ b/openair2/RRC/NR/rrc_gNB_radio_bearers.h @@ -61,6 +61,9 @@ drb_t *generateDRB(gNB_RRC_UE_t *ue, /// @brief return the next available (inactive) DRB ID of UE ue uint8_t get_next_available_drb_id(gNB_RRC_UE_t *ue); +/// @brief returns the number of active DRBs for this UE +int get_number_active_drbs(gNB_RRC_UE_t *ue); + /// @brief check if DRB with ID drb_id of UE ue is active bool drb_is_active(gNB_RRC_UE_t *ue, uint8_t drb_id); From 0e20c4c25735c36f609251233cf4244bdaf9478a Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 4 Oct 2024 22:00:06 +0200 Subject: [PATCH 57/75] Handle UE context setup resp for HO: trigger reconfiguration on source In this commit, handle the reception of a UE context setup response, in the case of handover. In that case, store the gNB-DU UE ID and C-RNTI of the UE at the target DU, and trigger a reconfiguration towards the UE at the source DU via the callback. To ensure that the CU-UP's PDCP is SN-aligned with the UE, use cuup_notify_reestablishment() to reset the bearers with PDCP reestablishment, which has already been implemented in the last commit. Co-authored-by: batuhanduyuler Co-authored-by: rmagueta --- openair2/RRC/NR/rrc_gNB.c | 22 ++++++++- openair2/RRC/NR/rrc_gNB_mobility.c | 76 +++++++++++++++++++++++++++++- 2 files changed, 96 insertions(+), 2 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 08547d7542..e0c94fc293 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1864,7 +1864,27 @@ static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, instance cuup_notify_reestablishment(rrc, UE); } - rrc_gNB_generate_dedicatedRRCReconfiguration(rrc, UE); + if (UE->ho_context == NULL) { + rrc_gNB_generate_dedicatedRRCReconfiguration(rrc, UE); + } else { + // case of handover + // handling of "target CU" information + DevAssert(UE->ho_context->target != NULL); + DevAssert(resp->crnti != NULL); + UE->ho_context->target->du_ue_id = resp->gNB_DU_ue_id; + UE->ho_context->target->new_rnti = *resp->crnti; + + uint8_t xid = rrc_gNB_get_next_transaction_identifier(0); + UE->xids[xid] = RRC_DEDICATED_RECONF; + uint8_t buffer[NR_RRC_BUF_SIZE] = {0}; + int size = rrc_gNB_encode_RRCReconfiguration(rrc, UE, xid, NULL, buffer, sizeof(buffer), true); + DevAssert(size > 0 && size <= sizeof(buffer)); + + // TODO N2 38.413 sec 9.3.1.21: admitted PDU sessions (in UE), Target to + // Source Transparent Container (9.3.1.21) which encodes the RRC + // reconfiguration above + UE->ho_context->target->ho_req_ack(rrc, UE, buffer, size); + } } static void rrc_CU_process_ue_context_release_request(MessageDef *msg_p) diff --git a/openair2/RRC/NR/rrc_gNB_mobility.c b/openair2/RRC/NR/rrc_gNB_mobility.c index cb6e851ebb..c423e400f4 100644 --- a/openair2/RRC/NR/rrc_gNB_mobility.c +++ b/openair2/RRC/NR/rrc_gNB_mobility.c @@ -31,6 +31,11 @@ #include "rrc_gNB_UE_context.h" #include "openair2/F1AP/f1ap_ids.h" #include "MESSAGES/asn1_msg.h" +#include "nr_pdcp/nr_pdcp_oai_api.h" +#include "openair3/SECU/key_nas_deriver.h" + +/* declared in rrc_gNB.c: should be cleaned up through helper function? useful? */ +extern mui_t rrc_gNB_mui; typedef enum { HO_CTX_BOTH, HO_CTX_SOURCE, HO_CTX_TARGET } ho_ctx_type_t; static nr_handover_context_t *alloc_ho_ctx(ho_ctx_type_t type) @@ -198,6 +203,75 @@ void nr_rrc_trigger_n2_ho(gNB_RRC_INST *rrc, int nr_cgi, uint8_t *ho_prep_info, } */ +typedef struct deliver_ue_ctxt_modification_data_t { + gNB_RRC_INST *rrc; + f1ap_ue_context_modif_req_t *modification_req; + sctp_assoc_t assoc_id; +} deliver_ue_ctxt_modification_data_t; +static void rrc_deliver_ue_ctxt_modif_req(void *deliver_pdu_data, ue_id_t ue_id, int srb_id, char *buf, int size, int sdu_id) +{ + DevAssert(deliver_pdu_data != NULL); + deliver_ue_ctxt_modification_data_t *data = deliver_pdu_data; + data->modification_req->rrc_container = (uint8_t*)buf; + data->modification_req->rrc_container_length = size; + data->rrc->mac_rrc.ue_context_modification_request(data->assoc_id, data->modification_req); +} +static void rrc_gNB_trigger_reconfiguration_for_handover(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue, uint8_t *rrc_reconf, int rrc_reconf_len) +{ + f1_ue_data_t ue_data = cu_get_f1_ue_data(ue->rrc_ue_id); + + TransmActionInd_t transmission_action_indicator = TransmActionInd_STOP; + RETURN_IF_INVALID_ASSOC_ID(ue_data.du_assoc_id); + f1ap_ue_context_modif_req_t ue_context_modif_req = { + .gNB_CU_ue_id = ue->rrc_ue_id, + .gNB_DU_ue_id = ue_data.secondary_ue, + .plmn.mcc = rrc->configuration.mcc[0], + .plmn.mnc = rrc->configuration.mnc[0], + .plmn.mnc_digit_length = rrc->configuration.mnc_digit_length[0], + .nr_cellid = rrc->nr_cellid, // TODO target cell ID + .servCellId = 0, // TODO: correct value? + .ReconfigComplOutcome = RRCreconf_success, + .transm_action_ind = &transmission_action_indicator, + }; + deliver_ue_ctxt_modification_data_t data = {.rrc = rrc, + .modification_req = &ue_context_modif_req, + .assoc_id = ue_data.du_assoc_id}; + int srb_id = 1; + nr_pdcp_data_req_srb(ue->rrc_ue_id, + srb_id, + rrc_gNB_mui++, + rrc_reconf_len, + (unsigned char *const)rrc_reconf, + rrc_deliver_ue_ctxt_modif_req, + &data); +} + +static void nr_rrc_f1_ho_acknowledge(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, uint8_t *rrc_reconf_buf, uint32_t rrc_reconf_len) +{ + // N2/Xn HO: fill with UE caps, as-context, rrc reconf, send to source CU + // also, fill the UE->rnti from the new one (in F1 case, happens after + // confirmation of ue ctxt modif + + // F1 HO: handling of "source CU" information + DevAssert(UE->ho_context->source != NULL); + rrc_gNB_trigger_reconfiguration_for_handover(rrc, UE, rrc_reconf_buf, rrc_reconf_len); + LOG_A(NR_RRC, "HO acknowledged: Send reconfiguration for UE %u/RNTI %04x...\n", UE->rrc_ue_id, UE->rnti); + + /* Re-establish SRB2 according to clause 5.3.5.6.3 of 3GPP TS 38.331 + * (SRB1 is re-established with RRCReestablishment message) + */ + int srb_id = 2; + if (UE->Srb[srb_id].Active) { + nr_pdcp_entity_security_keys_and_algos_t security_parameters; + /* Derive the keys from kgnb */ + nr_derive_key(RRC_ENC_ALG, UE->ciphering_algorithm, UE->kgnb, security_parameters.ciphering_key); + nr_derive_key(RRC_INT_ALG, UE->integrity_algorithm, UE->kgnb, security_parameters.integrity_key); + security_parameters.integrity_algorithm = UE->integrity_algorithm; + security_parameters.ciphering_algorithm = UE->ciphering_algorithm; + nr_pdcp_reestablishment(UE->rrc_ue_id, srb_id, true, &security_parameters); + } +} + 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) { DevAssert(rrc != NULL); @@ -212,7 +286,7 @@ void nr_rrc_trigger_f1_ho(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue, nr_rrc_du_contain // here: target Cell is preselected, target CU has access to UE information // and therefore also the PDU sessions. Orig RRC reconfiguration should be in // handover preparation information - ho_req_ack_t ack = NULL; + ho_req_ack_t ack = nr_rrc_f1_ho_acknowledge; ho_success_t success = NULL; ho_cancel_t cancel = NULL; nr_initiate_handover(rrc, ue, source_du, target_du, buf, size, ack, success, cancel); From e42c303bd72006262a60a50c887ada401aaed810 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 31 May 2024 19:49:43 +0200 Subject: [PATCH 58/75] Handle UE Context Modification Response in HO case We expect the UE's RRC Reconfiguration Complete to come through the target DU, as the "new UE" at the target CU. Also, function CU_handle_UL_RRC_MESSAGE_TRANSFER() checks that the UL RRC Message, through which we will receive RRC Reconfiguration Complete, matches the DU UE ID stored in RRC. Since the DU UE ID will be the one at the target DU, while up to now, we stored the DU UE ID at the source DU. Correspondingly, update the DU UE ID to the one at the target DU; also update the corresponding assoc_id. Co-authored-by: batuhanduyuler Co-authored-by: rmagueta --- openair2/RRC/NR/rrc_gNB.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index e0c94fc293..3335116a21 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1983,6 +1983,24 @@ static void rrc_CU_process_ue_context_modification_response(MessageDef *msg_p, i rrc_gNB_generate_dedicatedRRCReconfiguration(rrc, UE); } + + // Reconfiguration should have been sent to the UE, so it will attempt the + // handover. In the F1 case, update with new RNTI, and update secondary UE + // association, so we can receive the new UE from the target DU (in N2/Xn, + // nothing is to be done, we wait for confirmation to release the UE in the + // CU/DU) + if (UE->ho_context && UE->ho_context->target && UE->ho_context->source) { + nr_ho_target_cu_t *target_ctx = UE->ho_context->target; + f1_ue_data_t ue_data = cu_get_f1_ue_data(UE->rrc_ue_id); + ue_data.secondary_ue = target_ctx->du_ue_id; + ue_data.du_assoc_id = target_ctx->du->assoc_id; + cu_remove_f1_ue_data(UE->rrc_ue_id); + cu_add_f1_ue_data(UE->rrc_ue_id, &ue_data); + LOG_I(NR_RRC, "UE %d handover: update RNTI from %04x to %04x\n", UE->rrc_ue_id, UE->rnti, target_ctx->new_rnti); + nr_ho_source_cu_t *source_ctx = UE->ho_context->source; + DevAssert(source_ctx->old_rnti == UE->rnti); + UE->rnti = target_ctx->new_rnti; + } } static void rrc_CU_process_ue_modification_required(MessageDef *msg_p, instance_t instance) From a2da391e70034ea22aac0eb3e8ceb2d459ca7629 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 4 Oct 2024 19:46:00 +0200 Subject: [PATCH 59/75] Handle successful HO after reconfigurationComplete The HO is completed (from a pure RAN perspective) when receiving reconfiguration complete. In that case, remove the HO context, and signal successful handover through the callback. For the F1 handover, this means releasing the UE at the source DU. Co-authored-by: batuhanduyuler Co-authored-by: rmagueta --- openair2/RRC/NR/rrc_gNB.c | 8 ++++++++ openair2/RRC/NR/rrc_gNB_mobility.c | 26 +++++++++++++++++++++++++- openair2/RRC/NR/rrc_gNB_mobility.h | 1 + 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 3335116a21..0ab53e0bf7 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1558,6 +1558,14 @@ static void handle_rrcReconfigurationComplete(gNB_RRC_INST *rrc, gNB_RRC_UE_t *U LOG_I(RRC, "UE %d: transaction %d still ongoing for action %d\n", UE->rrc_ue_id, i, UE->xids[i]); } } + + if (UE->ho_context != NULL) { + LOG_A(NR_RRC, "handover for UE %d/RNTI %04x complete!\n", UE->rrc_ue_id, UE->rnti); + DevAssert(UE->ho_context->target != NULL); + + UE->ho_context->target->ho_success(rrc, UE); + nr_rrc_finalize_ho(UE); + } } static void rrc_gNB_generate_UECapabilityEnquiry(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue) diff --git a/openair2/RRC/NR/rrc_gNB_mobility.c b/openair2/RRC/NR/rrc_gNB_mobility.c index c423e400f4..6f6a034aa3 100644 --- a/openair2/RRC/NR/rrc_gNB_mobility.c +++ b/openair2/RRC/NR/rrc_gNB_mobility.c @@ -272,6 +272,24 @@ static void nr_rrc_f1_ho_acknowledge(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, uint8_ } } +static void nr_rrc_f1_ho_complete(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE) +{ + DevAssert(UE->ho_context != NULL); + nr_ho_source_cu_t *source_ctx = UE->ho_context->source; + DevAssert(source_ctx != NULL); + RETURN_IF_INVALID_ASSOC_ID(source_ctx->du->assoc_id); + f1ap_ue_context_release_cmd_t cmd = { + .gNB_CU_ue_id = UE->rrc_ue_id, + .gNB_DU_ue_id = source_ctx->du_ue_id, + .cause = F1AP_CAUSE_RADIO_NETWORK, // better + .cause_value = 5, // 5 = F1AP_CauseRadioNetwork_interaction_with_other_procedure + .srb_id = DCCH, + }; + rrc->mac_rrc.ue_context_release_command(source_ctx->du->assoc_id, &cmd); + LOG_I(NR_RRC, "UE %d Handover: trigger release on DU assoc_id %d\n", UE->rrc_ue_id, source_ctx->du->assoc_id); +} + + 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) { DevAssert(rrc != NULL); @@ -287,11 +305,17 @@ void nr_rrc_trigger_f1_ho(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue, nr_rrc_du_contain // and therefore also the PDU sessions. Orig RRC reconfiguration should be in // handover preparation information ho_req_ack_t ack = nr_rrc_f1_ho_acknowledge; - ho_success_t success = NULL; + ho_success_t success = nr_rrc_f1_ho_complete; ho_cancel_t cancel = NULL; nr_initiate_handover(rrc, ue, source_du, target_du, buf, size, ack, success, cancel); } +void nr_rrc_finalize_ho(gNB_RRC_UE_t *ue) +{ + free_ho_ctx(ue->ho_context); + ue->ho_context = NULL; +} + void nr_HO_F1_trigger_telnet(gNB_RRC_INST *rrc, uint32_t rrc_ue_id) { rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(rrc, rrc_ue_id); diff --git a/openair2/RRC/NR/rrc_gNB_mobility.h b/openair2/RRC/NR/rrc_gNB_mobility.h index 5811804009..1078cffe4e 100644 --- a/openair2/RRC/NR/rrc_gNB_mobility.h +++ b/openair2/RRC/NR/rrc_gNB_mobility.h @@ -67,5 +67,6 @@ typedef struct nr_handover_context_s { } nr_handover_context_t; 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); #endif /* RRC_GNB_MOBILITY_H_ */ From 145fd2b41552ac411a5bb062b3d940ba47e07fbc Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 14 Aug 2024 15:36:52 +0200 Subject: [PATCH 60/75] Handle Release request during handover If we release a request from a DU during, handle as follows: - from the source: Handover is still ongoing, so ignore it by acknowledging the release, and marking handover as done. In this case, we did not receive an acknowledgement from the target, but since the source DU does not keep the UE context, we could not cancel the handover anymore either. The UE might come back on any DU through reestablishment (or simply be connected on the target) - from the target: consider this to be a genuine release, and forward to AMF. Co-authored-by: batuhanduyuler Co-authored-by: rmagueta --- openair2/RRC/NR/rrc_gNB.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 0ab53e0bf7..ea962d7461 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1895,7 +1895,7 @@ static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, instance } } -static void rrc_CU_process_ue_context_release_request(MessageDef *msg_p) +static void rrc_CU_process_ue_context_release_request(MessageDef *msg_p, sctp_assoc_t assoc_id) { const int instance = 0; f1ap_ue_context_release_req_t *req = &F1AP_UE_CONTEXT_RELEASE_REQ(msg_p); @@ -1906,6 +1906,31 @@ static void rrc_CU_process_ue_context_release_request(MessageDef *msg_p) return; } + gNB_RRC_UE_t *UE = &ue_context_p->ue_context; + if (UE->ho_context != NULL) { + nr_ho_source_cu_t *source_ctx = UE->ho_context->source; + bool from_source_du = source_ctx && source_ctx->du->assoc_id == assoc_id; + if (from_source_du) { + // we received release request from the source DU, but HO is still + // ongoing; free the UE, and remove the HO context. + LOG_W(NR_RRC, "UE %d: release request from source DU ID %ld during HO, marking HO as complete\n", UE->rrc_ue_id, source_ctx->du->setup_req->gNB_DU_id); + RETURN_IF_INVALID_ASSOC_ID(source_ctx->du->assoc_id); + f1ap_ue_context_release_cmd_t cmd = { + .gNB_CU_ue_id = UE->rrc_ue_id, + .gNB_DU_ue_id = source_ctx->du_ue_id, + .cause = F1AP_CAUSE_RADIO_NETWORK, + .cause_value = 5, // 5 = F1AP_CauseRadioNetwork_interaction_with_other_procedure + .srb_id = DCCH, + }; + rrc->mac_rrc.ue_context_release_command(assoc_id, &cmd); + nr_rrc_finalize_ho(UE); + return; + } + // if we receive the release request from the target DU (regardless if + // successful), we assume it is "genuine" and ask the AMF to release + nr_rrc_finalize_ho(UE); + } + /* TODO: marshall types correctly */ LOG_I(NR_RRC, "received UE Context Release Request for UE %u, forwarding to AMF\n", req->gNB_CU_ue_id); rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_REQ(instance, @@ -2430,7 +2455,7 @@ void *rrc_gnb_task(void *args_p) { break; case F1AP_UE_CONTEXT_RELEASE_REQ: - rrc_CU_process_ue_context_release_request(msg_p); + rrc_CU_process_ue_context_release_request(msg_p, msg_p->ittiMsgHeader.originInstance); break; case F1AP_UE_CONTEXT_RELEASE_COMPLETE: From c6434c80fd12239866e784f1cfe0a05c3a7e557c Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 25 Oct 2024 14:42:56 +0200 Subject: [PATCH 61/75] Reestablishment hack: free reconfigurationWithSync After handover, the last CellGroupConfig received is the one for handover, containing a reconfigurationWithSync. Resending this CellGroupConfig to the UE after reestablishment would trigger a handover. Free the reconfigurationWithSync to have the UE complete reestablishment at the current cell. The CU implementation of reestablishment modifies the CellGroupConfig. It should not do this, but does as of now. The specification (38.473 Sec 8.7) foresees an optional F1 UE context modification procedure (which can be used to receive the CellGroupConfig). This should be done instead to retrieve the correct CellGroupConfig. Note that the F1 UE context setup procedure, similar to the UE context modification procedure, would also allow to perform reestablishment on a DU that is not the original one. --- openair2/RRC/NR/rrc_gNB.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index ea962d7461..04e2a3d02f 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -909,6 +909,17 @@ static void rrc_gNB_process_RRCReestablishmentComplete(gNB_RRC_INST *rrc, gNB_RR NR_RLC_BearerConfig__reestablishRLC_true); } + /* TODO: remove a reconfigurationWithSync, we don't need it for + * reestablishment. The whole reason why this might be here is that we store + * the CellGroupConfig (after handover), and simply reuse it for + * reestablishment, instead of re-requesting the CellGroupConfig from the DU. + * Hence, add below hack; the solution would be to request the + * CellGroupConfig from the DU when doing reestablishment. */ + if (cellGroupConfig->spCellConfig->reconfigurationWithSync != NULL) { + ASN_STRUCT_FREE(asn_DEF_NR_ReconfigurationWithSync, cellGroupConfig->spCellConfig->reconfigurationWithSync); + cellGroupConfig->spCellConfig->reconfigurationWithSync = NULL; + } + /* Re-establish SRB2 according to clause 5.3.5.6.3 of 3GPP TS 38.331 * (SRB1 is re-established with RRCReestablishment message) */ From b6ccf8aa7773359b5182abf042b354ceaf500f55 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 7 Aug 2024 17:00:38 +0200 Subject: [PATCH 62/75] Handle reestablishment during handover This commit implements reestablishment during handover when occurring at the source DU, either as a handover Failure or "normal" reestablishment (something else went wrong). In this case, the CU will trigger HO cancel, which in F1, means to cancel on the target DU. Also, undo any previous ID changes. Retain the old CellGroupConfig (before handover) for the case of reestablishment at source. If not needed, it is freed after the reconfiguration complete. Reestablishment on target cell during handover cannot be handled by the gNB (yet). It is the same as with a normal reestablishment (not during handover) on a different cell: that cell has no notion of the old UE, so we cannot simply indicate the old UE to reestablish; at least, we would need to cleanup the CellGroupConfig, and I am not sure this works out of the box, either. --- openair2/RRC/NR/rrc_gNB.c | 61 ++++++++++++++++++++++++++++-- openair2/RRC/NR/rrc_gNB_mobility.c | 21 +++++++++- openair2/RRC/NR/rrc_gNB_mobility.h | 5 +++ 3 files changed, 82 insertions(+), 5 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 04e2a3d02f..6c642cb582 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1072,6 +1072,20 @@ static const char *get_reestab_cause(NR_ReestablishmentCause_t c) return "UNKNOWN Failure (ASN.1 decoder error?)"; } +static rrc_gNB_ue_context_t *rrc_gNB_get_ue_context_source_cell(gNB_RRC_INST *rrc_instance_pP, long pci, rnti_t rntiP) +{ + rrc_gNB_ue_context_t *ue_context_p; + RB_FOREACH(ue_context_p, rrc_nr_ue_tree_s, &rrc_instance_pP->rrc_ue_head) { + gNB_RRC_UE_t *ue = &ue_context_p->ue_context; + if (!ue->ho_context || !ue->ho_context->source) + continue; + nr_ho_source_cu_t *source_ctx = ue->ho_context->source; + if (source_ctx->old_rnti == rntiP && source_ctx->du->setup_req->cell[0].info.nr_pci == pci) + return ue_context_p; + } + return NULL; +} + static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, sctp_assoc_t assoc_id, const NR_RRCReestablishmentRequest_IEs_t *req, @@ -1082,7 +1096,12 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, const long physCellId = req->ue_Identity.physCellId; long ngap_cause = NGAP_CAUSE_RADIO_NETWORK_UNSPECIFIED; /* cause in case of NGAP release req */ rrc_gNB_ue_context_t *ue_context_p = NULL; - LOG_I(NR_RRC, "UE %04x physCellId %ld NR_RRCReestablishmentRequest cause %s\n", msg->crnti, physCellId, scause); + LOG_I(NR_RRC, + "Reestablishment RNTI %04x req C-RNTI %04lx physCellId %ld cause %s\n", + msg->crnti, + req->ue_Identity.c_RNTI, + physCellId, + scause); const nr_rrc_du_container_t *du = get_du_by_assoc_id(rrc, assoc_id); if (du == NULL) { @@ -1117,13 +1136,47 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, rnti_t old_rnti = req->ue_Identity.c_RNTI; ue_context_p = rrc_gNB_get_ue_context_by_rnti(rrc, assoc_id, old_rnti); if (ue_context_p == NULL) { - LOG_E(NR_RRC, "NR_RRCReestablishmentRequest without UE context, fallback to RRC setup\n"); - goto fallback_rrc_setup; + ue_context_p = rrc_gNB_get_ue_context_source_cell(rrc, physCellId, old_rnti); + if (ue_context_p == NULL) { + LOG_E(NR_RRC, "NR_RRCReestablishmentRequest without UE context, fallback to RRC setup\n"); + goto fallback_rrc_setup; + } } gNB_RRC_UE_t *UE = &ue_context_p->ue_context; + /* should check phys cell ID to identify the correct cell */ const f1ap_served_cell_info_t *cell_info = &du->setup_req->cell[0].info; - if (physCellId != cell_info->nr_pci) { + const f1ap_served_cell_info_t *previous_cell_info = get_cell_information_by_phycellId(physCellId); + + nr_ho_source_cu_t *source_ctx = UE->ho_context ? UE->ho_context->source : NULL; + DevAssert(!source_ctx || source_ctx->du->setup_req->num_cells_available == 1); + bool ho_reestab_on_source = source_ctx && previous_cell_info->nr_cellid == source_ctx->du->setup_req->cell[0].info.nr_cellid; + + if (ho_reestab_on_source) { + /* the UE came back on the source DU while doing handover, release at + * target DU and and update the association to the initial DU one */ + LOG_W(NR_RRC, "handover for UE %d/RNTI %04x failed, rollback to original cell\n", UE->rrc_ue_id, UE->rnti); + + // find the transaction of handover (the corresponding reconfig) and abort it + for (int i = 0; i < NR_RRC_TRANSACTION_IDENTIFIER_NUMBER; ++i) { + if (UE->xids[i] == RRC_DEDICATED_RECONF) + UE->xids[i] = RRC_ACTION_NONE; + } + + source_ctx->ho_cancel(rrc, UE); + + /* we need the original CellGroupConfig */ + ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->masterCellGroup); + UE->masterCellGroup = source_ctx->old_cellGroupConfig; + source_ctx->old_cellGroupConfig = NULL; + + /* update to old DU assoc id -- RNTI + secondary DU UE ID further below */ + f1_ue_data_t ue_data = cu_get_f1_ue_data(UE->rrc_ue_id); + ue_data.du_assoc_id = source_ctx->du->assoc_id; + cu_remove_f1_ue_data(UE->rrc_ue_id); + cu_add_f1_ue_data(UE->rrc_ue_id, &ue_data); + nr_rrc_finalize_ho(UE); + } else if (physCellId != cell_info->nr_pci) { /* UE was moving from previous cell so quickly that RRCReestablishment for previous cell was received in this cell */ LOG_I(NR_RRC, "RRC Reestablishment Request from different physCellId (%ld) than current physCellId (%d), fallback to RRC setup\n", diff --git a/openair2/RRC/NR/rrc_gNB_mobility.c b/openair2/RRC/NR/rrc_gNB_mobility.c index 6f6a034aa3..137e7010c2 100644 --- a/openair2/RRC/NR/rrc_gNB_mobility.c +++ b/openair2/RRC/NR/rrc_gNB_mobility.c @@ -115,6 +115,9 @@ static void nr_initiate_handover(const gNB_RRC_INST *rrc, ho_ctx->source->du = source_du; ho_ctx->source->du_ue_id = ue_data.secondary_ue; ho_ctx->source->old_rnti = ue->rnti; + + int result = asn_copy(&asn_DEF_NR_CellGroupConfig, (void **)&ho_ctx->source->old_cellGroupConfig, ue->masterCellGroup); + AssertFatal(result == 0, "error during asn_copy() of CellGroupConfig\n"); } ue->ho_context = ho_ctx; LOG_A(NR_RRC, @@ -289,6 +292,20 @@ static void nr_rrc_f1_ho_complete(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE) LOG_I(NR_RRC, "UE %d Handover: trigger release on DU assoc_id %d\n", UE->rrc_ue_id, source_ctx->du->assoc_id); } +static void nr_rrc_cancel_f1_ho(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE) +{ + DevAssert(UE->ho_context != NULL); + nr_ho_target_cu_t *target_ctx = UE->ho_context->target; + DevAssert(target_ctx != NULL); + f1ap_ue_context_release_cmd_t cmd = { + .gNB_CU_ue_id = UE->rrc_ue_id, + .gNB_DU_ue_id = target_ctx->du_ue_id, + .cause = F1AP_CAUSE_RADIO_NETWORK, // better + .cause_value = 5, // 5 = F1AP_CauseRadioNetwork_interaction_with_other_procedure + .srb_id = DCCH, + }; + rrc->mac_rrc.ue_context_release_command(target_ctx->du->assoc_id, &cmd); +} 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) { @@ -306,12 +323,14 @@ void nr_rrc_trigger_f1_ho(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue, nr_rrc_du_contain // handover preparation information ho_req_ack_t ack = nr_rrc_f1_ho_acknowledge; ho_success_t success = nr_rrc_f1_ho_complete; - ho_cancel_t cancel = NULL; + ho_cancel_t cancel = nr_rrc_cancel_f1_ho; nr_initiate_handover(rrc, ue, source_du, target_du, buf, size, ack, success, cancel); } void nr_rrc_finalize_ho(gNB_RRC_UE_t *ue) { + if (ue->ho_context->source) + ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, ue->ho_context->source->old_cellGroupConfig); free_ho_ctx(ue->ho_context); ue->ho_context = NULL; } diff --git a/openair2/RRC/NR/rrc_gNB_mobility.h b/openair2/RRC/NR/rrc_gNB_mobility.h index 1078cffe4e..5046176c1d 100644 --- a/openair2/RRC/NR/rrc_gNB_mobility.h +++ b/openair2/RRC/NR/rrc_gNB_mobility.h @@ -28,6 +28,8 @@ typedef struct gNB_RRC_INST_s gNB_RRC_INST; typedef struct gNB_RRC_UE_s gNB_RRC_UE_t; 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 struct nr_ho_source_cu { /// pointer to the (source) DU structure @@ -38,6 +40,9 @@ typedef struct nr_ho_source_cu { uint32_t du_ue_id; /// old (source) RNTI (to recognize a UE during reestablishment) rnti_t old_rnti; + /// old (source) CellGroupConfig (to send the cellGroupConfig in case of + /// reestablishment) + NR_CellGroupConfig_t *old_cellGroupConfig; /// function pointer to announce the handover cancellation, e.g., /// reestablishment ho_cancel_t ho_cancel; From 546ffee56bab5b0fc0c87dc4f1bd11aa8739d20e Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 9 Aug 2024 14:57:21 +0200 Subject: [PATCH 63/75] DU dies during HO: free HO context of UE to avoid dangling data --- openair2/RRC/NR/rrc_gNB_du.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/openair2/RRC/NR/rrc_gNB_du.c b/openair2/RRC/NR/rrc_gNB_du.c index 51abc95dd0..bc2ade3253 100644 --- a/openair2/RRC/NR/rrc_gNB_du.c +++ b/openair2/RRC/NR/rrc_gNB_du.c @@ -24,6 +24,7 @@ #include "common/ran_context.h" #include "nr_rrc_defs.h" #include "rrc_gNB_UE_context.h" +#include "rrc_gNB_mobility.h" #include "openair2/F1AP/f1ap_common.h" #include "openair2/F1AP/f1ap_ids.h" #include "executables/softmodem-common.h" @@ -397,7 +398,12 @@ static int invalidate_du_connections(gNB_RRC_INST *rrc, sctp_assoc_t assoc_id) int count = 0; rrc_gNB_ue_context_t *ue_context_p = NULL; RB_FOREACH(ue_context_p, rrc_nr_ue_tree_s, &rrc->rrc_ue_head) { - uint32_t ue_id = ue_context_p->ue_context.rrc_ue_id; + gNB_RRC_UE_t *UE = &ue_context_p->ue_context; + uint32_t ue_id = UE->rrc_ue_id; + if (UE->ho_context != NULL) { + LOG_W(NR_RRC, "DU disconnected while handover for UE %d active\n", ue_id); + nr_rrc_finalize_ho(UE); + } f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_id); if (ue_data.du_assoc_id == assoc_id) { /* this UE belongs to the DU that disconnected, set du_assoc_id to 0, From 8b4259c047b715769ffbee1bf0f2151379c11c97 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 22 Oct 2024 13:49:31 +0200 Subject: [PATCH 64/75] Ignore UE Context Modification Required during handover During handover, we might receive a UE context Modification required message. Currently, we cannot handle this; ignore the message. --- openair2/RRC/NR/rrc_gNB.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 6c642cb582..6e0906b63c 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -2100,7 +2100,7 @@ static void rrc_CU_process_ue_context_modification_response(MessageDef *msg_p, i } } -static void rrc_CU_process_ue_modification_required(MessageDef *msg_p, instance_t instance) +static void rrc_CU_process_ue_modification_required(MessageDef *msg_p, instance_t instance, sctp_assoc_t assoc_id) { gNB_RRC_INST *rrc = RC.nrrrc[instance]; f1ap_ue_context_modif_required_t *required = &F1AP_UE_CONTEXT_MODIFICATION_REQUIRED(msg_p); @@ -2117,6 +2117,12 @@ static void rrc_CU_process_ue_modification_required(MessageDef *msg_p, instance_ return; } + gNB_RRC_UE_t *UE = &ue_context_p->ue_context; + if (UE->ho_context && UE->ho_context->source && UE->ho_context->source->du && UE->ho_context->source->du->assoc_id == assoc_id) { + LOG_W(NR_RRC, "UE %d: UE Context Modification Required during handover, ignoring message\n", UE->rrc_ue_id); + return; + } + if (required->du_to_cu_rrc_information && required->du_to_cu_rrc_information->cellGroupConfig) { gNB_RRC_UE_t *UE = &ue_context_p->ue_context; LOG_I(RRC, @@ -2515,7 +2521,7 @@ void *rrc_gnb_task(void *args_p) { break; case F1AP_UE_CONTEXT_MODIFICATION_REQUIRED: - rrc_CU_process_ue_modification_required(msg_p, instance); + rrc_CU_process_ue_modification_required(msg_p, instance, msg_p->ittiMsgHeader.originInstance); break; case F1AP_UE_CONTEXT_RELEASE_REQ: From c956de6f27368aba45ececd8ab1c9581051740e2 Mon Sep 17 00:00:00 2001 From: Roberto Magueta Date: Tue, 3 Sep 2024 10:53:16 +0200 Subject: [PATCH 65/75] Trigger F1 Handover on A3 event When receiving a measurement report including an A3 event, trigger handover towards the indicated cell. Note that currently, we are still limited to one Cell by DU, hence looking up a cell comes down to looking up a DU, as is done here. Co-authored-by: batuhanduyuler Co-authored-by: Luis Pereira Co-authored-by: Robert Schmidt --- openair2/RRC/NR/rrc_gNB.c | 29 ++++++++++++++++++----------- openair2/RRC/NR/rrc_gNB_du.c | 12 ++++++++++++ openair2/RRC/NR/rrc_gNB_du.h | 1 + 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 6e0906b63c..0f9fce815b 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1236,7 +1236,7 @@ static void process_Periodical_Measurement_Report(gNB_RRC_UE_t *ue_ctxt, NR_Meas measurementReport->criticalExtensions.choice.measurementReport = NULL; } -static void process_Event_Based_Measurement_Report(NR_ReportConfigNR_t *report, NR_MeasurementReport_t *measurementReport) +static void process_Event_Based_Measurement_Report(gNB_RRC_UE_t *ue, NR_ReportConfigNR_t *report, NR_MeasurementReport_t *measurementReport) { NR_EventTriggerConfig_t *event_triggered = report->reportType.choice.eventTriggered; @@ -1250,7 +1250,7 @@ static void process_Event_Based_Measurement_Report(NR_ReportConfigNR_t *report, break; case NR_EventTriggerConfig__eventId_PR_eventA3: { - LOG_I(NR_RRC, "HO LOG: Event A3 Report - Neighbour Becomes Better than Serving!\n"); + LOG_W(NR_RRC, "HO LOG: Event A3 Report - Neighbour Becomes Better than Serving!\n"); const NR_MeasResults_t *measResults = &measurementReport->criticalExtensions.choice.measurementReport->measResults; for (int serving_cell_idx = 0; serving_cell_idx < measResults->measResultServingMOList.list.count; serving_cell_idx++) { @@ -1289,13 +1289,13 @@ static void process_Event_Based_Measurement_Report(NR_ReportConfigNR_t *report, neighbourCellId, neighbourCellRSRP); - const f1ap_served_cell_info_t *neighbour_cell_du_context = get_cell_information_by_phycellId(neighbourCellId); - const f1ap_served_cell_info_t *serving_cell_du_context = get_cell_information_by_phycellId(servingCellId); + const f1ap_served_cell_info_t *neigh_cell = get_cell_information_by_phycellId(neighbourCellId); + const f1ap_served_cell_info_t *serving_cell = get_cell_information_by_phycellId(servingCellId); const nr_neighbour_gnb_configuration_t *neighbour = - get_neighbour_cell_information(serving_cell_du_context->nr_cellid, neighbourCellId); + get_neighbour_cell_information(serving_cell->nr_cellid, neighbourCellId); // CU does not have f1 connection with neighbour cell context. So check does serving cell has this phyCellId as a // neighbour. - if (!neighbour_cell_du_context && neighbour) { + if (!neigh_cell && neighbour) { // No F1 connection but static neighbour configuration is available const nr_a3_event_t *a3_event_configuration = get_a3_configuration(neighbour->physicalCellId); // Additional check - This part can be modified according to additional cell specific Handover Margin @@ -1304,6 +1304,15 @@ static void process_Event_Based_Measurement_Report(NR_ReportConfigNR_t *report, < (neighbourCellRSRP - servingCellRSRP))) { LOG_D(NR_RRC, "HO LOG: Trigger N2 HO for the neighbour gnb: %u cell: %lu\n", neighbour->gNB_ID, neighbour->nrcell_id); } + } else if (neigh_cell && neighbour) { + /* we know the cell and are connected to the DU! */ + gNB_RRC_INST *rrc = RC.nrrrc[0]; + nr_rrc_du_container_t *source_du = get_du_by_cell_id(rrc, serving_cell->nr_cellid); + DevAssert(source_du); + nr_rrc_du_container_t *target_du = get_du_by_cell_id(rrc, neigh_cell->nr_cellid); + nr_rrc_trigger_f1_ho(rrc, ue, source_du, target_du); + } else { + LOG_W(NR_RRC, "UE %d: received A3 event for stronger neighbor PCI %d, but no such neighbour in configuration\n", ue->rrc_ue_id, neighbourCellId); } } @@ -1365,12 +1374,10 @@ static void rrc_gNB_process_MeasurementReport(gNB_RRC_UE_t *UE, NR_MeasurementRe if (report_config->choice.reportConfigNR->reportType.present == NR_ReportConfigNR__reportType_PR_periodical) return process_Periodical_Measurement_Report(UE, measurementReport); - if (report_config->choice.reportConfigNR->reportType.present != NR_ReportConfigNR__reportType_PR_eventTriggered) { - LOG_D(NR_RRC, "Incoming Report Type: %d is not supported! \n", report_config->choice.reportConfigNR->reportType.present); - return; - } + if (report_config->choice.reportConfigNR->reportType.present == NR_ReportConfigNR__reportType_PR_eventTriggered) + return process_Event_Based_Measurement_Report(UE, report_config->choice.reportConfigNR, measurementReport); - process_Event_Based_Measurement_Report(report_config->choice.reportConfigNR, measurementReport); + LOG_E(NR_RRC, "Incoming Report Type: %d is not supported! \n", report_config->choice.reportConfigNR->reportType.present); } static int handle_rrcReestablishmentComplete(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const NR_RRCReestablishmentComplete_t *cplt) diff --git a/openair2/RRC/NR/rrc_gNB_du.c b/openair2/RRC/NR/rrc_gNB_du.c index bc2ade3253..4e065e530c 100644 --- a/openair2/RRC/NR/rrc_gNB_du.c +++ b/openair2/RRC/NR/rrc_gNB_du.c @@ -567,6 +567,18 @@ nr_rrc_du_container_t *get_du_by_assoc_id(gNB_RRC_INST *rrc, sctp_assoc_t assoc_ return RB_FIND(rrc_du_tree, &rrc->dus, &e); } +/* \brief find DU by cell ID. Note: currently the CU is limited to one cell per + * DU, hence here, DU == cell. Modify this to look up a specific cell. */ +nr_rrc_du_container_t *get_du_by_cell_id(gNB_RRC_INST *rrc, uint64_t cell_id) +{ + nr_rrc_du_container_t *du = NULL; + RB_FOREACH(du, rrc_du_tree, &rrc->dus) { + if (cell_id == du->setup_req->cell[0].info.nr_cellid) + return du; + } + return NULL; +} + void dump_du_info(const gNB_RRC_INST *rrc, FILE *f) { fprintf(f, "%ld connected DUs \n", rrc->num_dus); diff --git a/openair2/RRC/NR/rrc_gNB_du.h b/openair2/RRC/NR/rrc_gNB_du.h index 55a0d7c2c8..bd3c4f6443 100644 --- a/openair2/RRC/NR/rrc_gNB_du.h +++ b/openair2/RRC/NR/rrc_gNB_du.h @@ -41,6 +41,7 @@ void rrc_gNB_process_f1_du_configuration_update(struct f1ap_gnb_du_configuration struct nr_rrc_du_container_t *get_du_for_ue(struct gNB_RRC_INST_s *rrc, uint32_t ue_id); struct nr_rrc_du_container_t *get_du_by_assoc_id(struct gNB_RRC_INST_s *rrc, sctp_assoc_t assoc_id); const struct f1ap_served_cell_info_t *get_cell_information_by_phycellId(int phyCellId); +struct nr_rrc_du_container_t *get_du_by_cell_id(struct gNB_RRC_INST_s *rrc, uint64_t cell_id); void dump_du_info(const struct gNB_RRC_INST_s *rrc, FILE *f); From e02aae46249f88da0acce23d7e87b2d06bd9fe45 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 8 Oct 2024 11:06:55 +0200 Subject: [PATCH 66/75] Open TODOs at RRC --- openair2/RRC/NR/rrc_gNB.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 0f9fce815b..3739b2d5fa 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1972,8 +1972,10 @@ static void rrc_CU_process_ue_context_release_request(MessageDef *msg_p, sctp_as f1ap_ue_context_release_req_t *req = &F1AP_UE_CONTEXT_RELEASE_REQ(msg_p); gNB_RRC_INST *rrc = RC.nrrrc[instance]; rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(rrc, req->gNB_CU_ue_id); + // TODO what happens if no AMF connected? should also handle, set an_release true if (!ue_context_p) { LOG_E(RRC, "could not find UE context for CU UE ID %u, aborting transaction\n", req->gNB_CU_ue_id); + // TODO just request the DU to release to make it happy return; } From 5c8ee816836db8c9332e5f7d971ab2f77d93e9ae Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 24 Jul 2024 16:47:37 +0200 Subject: [PATCH 67/75] Update FEATURE_SET.md with F1 handover procedures --- doc/F1AP/F1-design.md | 2 +- doc/FEATURE_SET.md | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/F1AP/F1-design.md b/doc/F1AP/F1-design.md index 4690639d5b..06f8a3115b 100644 --- a/doc/F1AP/F1-design.md +++ b/doc/F1AP/F1-design.md @@ -59,8 +59,8 @@ This is the current status: * SA * Single cell per DU * Multiple DUs connected to one CU (both CP and UP) + * Mobility between DUs connected to a single CU - Not supported: - * Mobility * NSA ## F1-C diff --git a/doc/FEATURE_SET.md b/doc/FEATURE_SET.md index eb1027bb3e..21e2f5ca8d 100644 --- a/doc/FEATURE_SET.md +++ b/doc/FEATURE_SET.md @@ -137,6 +137,7 @@ These modes of operation are supported: - evaluation of CQI report - MAC scheduling of SR reception - Support of up to 16 UEs (can be increased to 32) +- Intra-frequency handover ## gNB RLC @@ -221,6 +222,7 @@ These modes of operation are supported: - Interface with RRC - Interface with GTP-u (tunnel creation/handling for F1-U interface) - One CU(-CP) can handle multiple DUs +- Support for intra-CU mobility (across DUs) ## gNB E1AP From ad81d48285ff5164799e6352e0007d0c7854bc61 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 8 Oct 2024 11:16:46 +0200 Subject: [PATCH 68/75] MAC doc: minor clarifications --- doc/MAC/mac-usage.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/doc/MAC/mac-usage.md b/doc/MAC/mac-usage.md index e6241202c4..4c7bf4df8e 100644 --- a/doc/MAC/mac-usage.md +++ b/doc/MAC/mac-usage.md @@ -143,10 +143,13 @@ In the last lines: # Configuration of the MAC -## Split-related options +## Split-related options (running in a DU) See [nFAPI documentation](../L2NFAPI.md) or [Aerial -tutorial](../Aerial_FAPI_Split_Tutorial.md). +tutorial](../Aerial_FAPI_Split_Tutorial.md) for information about the FAPI +split. + +See [F1 documentation](../F1-design.md) for information about the F1 split. ## MAC scheduler-related configuration options From 05f10decee118b181006e5a1670ece0729b830b4 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 14 Aug 2024 17:02:33 +0200 Subject: [PATCH 69/75] Add handover tutorial Co-authored-by: rmagueta --- doc/README.md | 1 + doc/RRC/ho.mmd | 9 ++ doc/RRC/ho.png | Bin 0 -> 7905 bytes doc/handover-tutorial.md | 329 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 339 insertions(+) create mode 100644 doc/RRC/ho.mmd create mode 100644 doc/RRC/ho.png create mode 100644 doc/handover-tutorial.md diff --git a/doc/README.md b/doc/README.md index ba7e5fbd12..7fc28f061a 100644 --- a/doc/README.md +++ b/doc/README.md @@ -53,6 +53,7 @@ There is some general information in the [OpenAirInterface Gitlab Wiki](https:// - [How to run with E2 agent](../openair2/E2AP/README.md) - [How to run the physical simulators](./physical-simulators.md) - [How to setup OAI with Nvidia Aerial and Foxconn](./Aerial_FAPI_Split_Tutorial.md) +- [How to do a handover](./handover-tutorial.md) Legacy unmaintained files: - [`L2NFAPI_NOS1.md`](./L2NFAPI_NOS1.md), [`L2NFAPI_S1.md`](./L2NFAPI_S1.md): diff --git a/doc/RRC/ho.mmd b/doc/RRC/ho.mmd new file mode 100644 index 0000000000..f86e36a087 --- /dev/null +++ b/doc/RRC/ho.mmd @@ -0,0 +1,9 @@ +block-beta + columns 5 + space space DU0 space UE + CU space space space space + space space DU1 space pos["new pos"] + CU<-- "F1" -->DU0 + CU<-- "F1" -->DU1 + DU0-- "Uu" -->UE + UE-- "move" -->pos diff --git a/doc/RRC/ho.png b/doc/RRC/ho.png new file mode 100644 index 0000000000000000000000000000000000000000..dd93d6fd1aba4e2e854252a7de7e52168826f969 GIT binary patch literal 7905 zcmaKxWmuHYAMPJQK$-;sX%LZ;QbJlJC<4z5SEmZk}f5srRxXM-2zK@ zobmtWoL6UFz+QV@JI_2b-}v13AT-nziSTLgAqXORp(LjXK^WfPvo#(j`0GmvrjhQdzn|D-4dV^!Yb*=4@I)wdz&fa-Y2>2i%tPnmnH)DeHVK{P7^lS?0`o;w zGPluPQUjA#Xs2;_FVblI4Q?2mTAGOz&n4hb6$T!*sdIoFZh&JZyrla;l9ff-68!4a#>I6_-ZmI>i^nKMLcKT=?I=RRW-=O zP>`F)fG1ir2@WR{V+Lq&S?2^%%d>AMgtjfl+x2eTK@gi#4A0G#=*vn-NWc&|@0}Dl ztUW`dnf}A4*^F|nsEA>ZY#?EXQ(`qU(^4ONak%!ls;Vk9#9PvDAk}}h_x73XIOch1 zy{jDur)P5P2L?5RfpiJi<1HjTy`5Q?D7SILNU!Z@wz;)g)`t&KDJg#Y9aIM)wf3_w zRaN`@`f^4$lb_g?u|DibN-^-=moM~QEH?O~sU>V_xi+-fnVXv`XuD+Mpp>b>W7MOQ zlBVQL3PGQeJxL)Z%1B#V+Y*yz_rK%S(X^utjXt;&;$oM51zPjGMs-tjbLS^Je^Z2f zD*SE>_|3Mp-yfH?bamk(yKu3wy|4DW1_lO_1ueTjC%C$*9X!Owe4d8GH2fTb{OjvU z#FO}1q@Ft8to7U0+9^N#$ZB9RzmR6fPblVfvT=3(0S+gFAe^@BhK94&kUl}%8^z;L z5)wYbzdJkq{r!z@=(%BL&q4EEw7kZn5Ha0Z)3CR(1qN1V>cA_s^79FWWU$B0Tq~f)-vZ}Ag3GUZl!k&|e)4|X1Ysyl8 zp`y~-8iLsJ5QWjV({65(ac!e8efB7v@-I*JdeXXXVAuJjrSr41L{M2xjqm=_9qy-s zf(feXO01vtuQ=UX2L^U0E3NjD)beVptGjoXS5_#<$e3Y>ABOfiI`=|k$nZn6wPfTb_AVWbg9I4C7 zrd1xggZhCCGdqyHC&v=|^V-XDCgwe2i-L7$I!)}8VH7N>d-|;5tdjb zwm7Nt74iq0=ATPo_V(6FevK(KG+Q8=rCpiFaNZ~>9EA+7@66VNoHjjJk=9>YUItm9 zDtUWrB>}RyqJl-LnFE4oQ_8=6TO(nd3rYlU9E9uU<9#J)ej~QGzh6*Lz`@I#n6T&G zkRt4Ganbbg<;d7rg5PLzGR;Ft`hh%WXJ@csUwBP?cc!XAkZ}E7la%xY(X+bRQ2}E> zdL6FaJCE+jglIMiY1J|$C48^WJ}h@0pK}#c;1e7!njF{FttawYxwyK%pR5Rz$^2FH z;X|)pafDGdr|UqflB}$!i%ZA(;UgoX`=fcy7a@o!!-HA3cb%Qzh>3ZgJ)2Zjjdog- zSIqNrSmou~C#R-rtDYJ)Byq$lQSusdm=rfO z=+|JgnO(WN(bE@x-0>h+at_5Mf2775*WK9I2t%}wjg5_t#?!>!;Itx`dZ5$Dp8qz?+))lTr7dXs=+Xu*Hpz5T}WsUsu~wO-;QyI(}zt z9A|2lh(f*ot=Ib-1kX-Okk$4!oeq5LZ^MT%BL1Ac(^IO*4#&q(8=sxsPI@{6OYFw_ z`ug&6+grZmh-l~N{1{_d>#Y(tjjejcuLlb7prQzD8V(>F_{7Q9m?3wQIE zQzZL}+jS|!3QI^Lc8v%Y%s3!H-$7QJ-u;H;11r-=Cp!2}{&d1`4w zcFEp%qZNX1CnqNrW9ayWgnZ|{TwPr&CbzS)Sct<$CnsO9#i3NbB_`^bo0}^s;l)$y zlM_3FHto7SK}JgIc-m06j6;Uk@oz?5U0rfEm5tL8)Dx>3``P4_6a$UDUFn_V? z8RD?EMMv((k6*CDf?AZ6l->%U4tSoOpP$do%~fbUe*Bmwy2fE%Qn5=AmF;-DdW(kSe_I6g`+FOcGhCH=ZRY#knd33~K{g#&(7bDhB z9URc|k(AN*pM0BVBNgdu;Zspo?j0L*0sBx@dX)D6^lf3lGP$Xu!bC#Q67nu-Ur0U%X#{V{v!?@ec^G`5w`R!k^Ogx3&gKGnMIo zZ+VZxf*7QH#jT6TvdIKc;?AZd|9+~Wq2cJrM?nRG6^7{R@Be97Qd3hC5P(6r^8kjZ ztE)?{q2Qki@Vk9#*TMB^qd{0zRn=RPv5gNfTxluEgG{C%y5CHsoS4zhp^P0J9gfNd ztS}uN9iQVdJqY4VxH#!&!!`|Pid72D->4D_ub&RBt%TZt=||f0v!Bky#1IRm^e;Nv z*xEWdIdw(TcA1ucQ%mbH7XVcN6a`0-nUsSmXBQU0Kv|9}%KWF+XG;QF8 zfYi`>^X83)#;-+3eeN%@v1E}QG*NL3nEVaYq7kFQMw@Aj2317AAH4M(J6lqZ=pYbr z@dR`e)UtPQ@X^J^qFn#we)6mD1PMtk1pGFe0IR;Yjm^+-W(@sb zY6gafmp5vfno&Q0u2Pxg^a%fS`TNFZtFy0KSdZI ziqFEYfWpE;0JN>i^={}U@D=E9erJneU%!3@w7j;m;_l`3cWY~Hb+y|*DKW9@EuV_2 zDlH9-CfM<)C}KL1GK=0XV2Wac+QOB4@xEOrC%TY73Y9y8j*@0#3J3@=>x>#68%q=S zIB34TMo&!WV_{)|SS2Ar0=9vqy}T~d#N4v7vb=qK9&>YpR|R6M)bJ;0NY~fb7Fi(U z|CI=f9t!AJ0+-%z^N#=-qoboi@dj&v!{IJ2)g#e*O&h-kKR0qv!vdrU84RZNY^jFO zeVv^+>6!)F3`pF{YcuM#wKbgHefNf-AgolKJJ{ITy1F%0RS>kW4wpJxz=EXZ@gv0>wG6yS1&C9-Au7Z*L1o1+zK`!(uCOOBt^^n z?&or9j&5{pBMCoSU*>9ZCUC|o0bT}WGd+DS2$!U_wRLyC84a2%VDJ=><6*(UzwIB! zDv64TCD=C{$cJ?wv5?|5U%M6|H-H@I>tk$fr5v&j4Glf|N47+?|9G>aNwVkGUz(7T zGXcL@3{!pIT^!jpIx-Sy9C&kcL&6}Q^vr3kEsO+27mF=`(72=|c0WcRpVh8M?0%lP zMMYH9A`iqao#o{Vygd{;=PIp`0N^2iB+^7x)xyK0e47*5)#z~;(dR`9_7Mjc7gwCY zL{k$}Jy-J`*d4HQ;zW3OZ!0JLuJ*&Enf#r&ApgorCt2B`goFfeDACbGQ78?07<~(T!JKv zqEW@t z*?6I^qonj(UFteMJzdgvoSTl=?fhVMy4HbF(i_Mru0KKv;V}UiJJSwN1~Q~v&~yDo zdV{anr+9dxs;XoOLvg=L|9`kGzm);ol%m3BtPsRJh}Mrk4YjmJgM+buDBppYU;l7;fj3bbui9?|PJd1uOvx8qHz{e-e*eOE@>o_R`t%;v7 zg%2Kx&+X};u#NUl`!|gA^{J0^{V|;Z9xxyuQATE7@S#*tT*|=8flS#joJ#?`_62`?G1*`;F42RHt*r}yNayD*qlJZ>LMhj0`^#K< zCE{KugoPvk4EU(gf-sb*%U0F9(G_Lur!?Zf2L>cRu7sEGzpadACXHA`qj_P73zc^4Jrrf%mg@g2KYJU%yHV@&-sZL<5nWA?8LLO4&$^kb6^Q9Xl26DQ_~oIAh1< zm9Mn6o*AUi?y}Eded0nBO-TyIUJrR)RaJbyrIg2kIUq71Hn=H!r>CboIxMcv_R$uy zo}P6G#0z`--OCiDG<(3=*_qS&0GxUpJ$EM*PC&^$6m0ahbmMFw$4gzSiTBe5bL>4r zG_|n(%#RPtK$iX~v9q^da}-%!UDYc!2B8wtE1jO6UQ&V{z&AGyYzQVz4pztp$U-mS zd32nh2tzz|+cng|)*<@T98N5ct3G^R=BKt`WI@3u*wBT-Xl>4r`E{?ey+zO)z*EBE z6TOMNVxpoeQp0(dHDxt=YQC|C`1_|gNTUG>`}DG z#e&g4lm%Lx71k${m6wMbS6fqC8`-h6GhLg4LJ@Uxd;ortySVT1)>v$8EN2-#KPDnF zvbU!vFhC53U}a&E8Kq<%euZIVWW;yh&cGl=pSz^AG|U4__q+Z+cp7MspjJ!(PfCeZ zfST|JhtRK8E6ji)pfl6cjkUB6C#^D`%LggtLUF{IUnN6Y7C*>twmEJ=ahL@?7cqs| zROF3&8|4qc66PAtpJHVjBMQ?6e>Jrc73_^J$`}|JfC3eGhk%mD@a$r&p`n4d`Km%4 zZfa`k?cLC~{Ijw$u5FRx-o5h4_Xs(VfLM3JJ4_opIEI0YQyb_uuP83wS?f;$sk@k4 zzitr0=)8Q_!A4a4(@EgI?}gS{3{O~)7uB1HgStIzojX_r?MA4dx6xQX@|&+CvvLc6 zCR9;HosMM)pl5x6Xdt8LeRuH1e-P*}pnEJU&%J#;Jf6jMoAZHeWAI6ZS!7}9VPilk zK!H7TVxypsknA3|b+<|?@f>-$O^K8lX5Rdq+7RY7??O;7hebyJw2=n(1E6_bUF%bO z5ZI2S&LCp|Q-Hnn^YarEs|P&WyS4221NcJFug+-NqM{{@O40ldwV z&`_!hd~Zo9k%{$@-0zY^ZaY&I=G}&q@6^=?n|#CqgM4;pFXb_wkY?jP9l6h-!A=n% z4OJ^BD-#S90xT~rEv>H?3u-xA4)xC}Jxf-z*?PXAW@KRCbbZlbP+MX*leD(8Blc^p zzyEfw?pUi_Kc@^Md>9Lswiuwn-oCs~9s1h90Az~*brgx@*+MCUL}1Iz{Ot9Zl1(f2 z?a^2%UQX9%E%yzlPF?#3{_z( zeO(D3&U!6%>uoXDkQDF~CFxUxK-^Ef)Eujc#wje~`ofF6IGK)$dqk2DPoY`hxw!c1 zaINv9>|+kNmHBpYK09;l@1`aU1j6?Cn5gO85-VfydaG!bkEpl7BLFgSU*gNNWL8((sq}UE`f5?QKd<`sBvr#8KOKb%X>4?QH7xB^oSc+Y zFp>2N8z3L#eL8!qp!g_N%I^`UP50?M+T-Lq{>@Zg4!5v?fTSanQ|}iE9UTjUT3>u< zZ!bwhvo$oPX>9BsMTD!1%QM1*_jY#nHa16lNfYZF*qHoJ4sn5tXEk_J@ow}Mco_qz zCyEfn63hP3!UHh!$<8GS-S4VOr4Nqs_{@*fKgg_o0QJgi3P(VC+;z_v;G_ z>uQeVg@l}g#igf{n>1~Qj%XNO#djPC304CYjsZD}+_|{GAtoO1*+sT3rl!u^+?)a~ zSy|+VZ~eFFhQ1+$+>bVDJ3BAbCC^*O65wV}TstBL^R;LH{;AANJ-@*D@gs`yNvHi{ zE3)}~P0Ywh;*K#9f;h|1)3cowb|Ca0wEzlCND(2FTBoZW|KkUrIRmY|JvU3NzHTS~ zlS)3}T5cX5Y_JgZnHl|(lBlJnJdL24S)aY@JEo#y$T<4xsi{AIZh^<3ql2ociAhV# z-rfYx;$XTCCUkZ6jZVsUZ(|ti;luX@+C8QouL>dv8)G+^F7h%nW7LEbqE8;eUS#02 z#Nw@5>d>>oUf)otr2(Q`?mCr~xmswRth{CWA51S07FER)>2&t@&w{&%{0$E1Ykodd z^1C4hJoIWgN3%emdu{)Rr>EbGjPFH7UF(Ms)ZLw8Y6|ncl{k%4r&LrN{PA%$)wDE} z@-x}BhLO=L6B8=>G|26*i*tT|zmF9CeAGb*; z)GNJHLw1U($!EZ&YzrF&+Hx>Mues?fmdAO8fh#xZ-d$`=gj|-U%W5xNP$UbO``}h7 zRoDR-sfVk*R;N4D@OST?I5y+o2e(xl1Q~xV%(; zW?>;8VQ0)l(K+ei4XpZvF=}8i3kjJO7u#X{x=$@VjMC6M73W3Aq|io6Gl9;goI8@5 zs?5e_sjGW!6$LcdXL>0w-FIeBD8t&GiPhi5_Wof{Pacg7eKIyO z`fzjgLQk&~gf%=QA_5lRPclmd?yZ0yeHWW0XfboxjV2&CxbJc^k8yOg86{|oK^#`^ zeZIXj{fC6H$=cdlE{}G4A_|xoiW3|nboMhMYpcDl9g+<&pqs11Nu*Tz-f6}gV`Jyj z-9Z8>HcW_3?dn%gkLBrZF_*5l0!!>bnivmdq-9@H5PTwCVp=3M5EMvrfmP7%i;MdK z#^E>Ifze|_(07w&!W;G6QB`o0_JD=*wE;5LsJe!s(ha>&{)iX|&`({>Aec zJm=g2cKzjA3YweyI|P~drTK181i1W#d3rt6)ioP0y^ZKT(q4G10V^fLe7Pj(J*)&P z-P>#KYWJpNV95PWODv9{dNcZ*iPQ$%b^h-LR24UXI@;Q?gDBdW6fgMA^Q@qMx1C@M zFf(`B*)#Df4riXCD6FV~aNd;Z+Czzc;|(YU%$j=oa_* X{DNt{t`iCFtf3e3YH}qqZv+1iT(??j literal 0 HcmV?d00001 diff --git a/doc/handover-tutorial.md b/doc/handover-tutorial.md new file mode 100644 index 0000000000..8595fe05d4 --- /dev/null +++ b/doc/handover-tutorial.md @@ -0,0 +1,329 @@ +This tutorial explains how to perform handovers. For the moment, only F1 +handovers are supported. + +[[_TOC_]] + +# Considered setup for F1 handover + +We consider one CU and two DUs, connected over F1. The UE is initially +connected over the radio interface ("Uu") to DU0. Via movement to a new +position ("new pos"), it will trigger an event such that the CU triggers a +handover of the UE from DU0 to DU1. Alternatively, a manual trigger can do the +same. + +![F1 Handover setup](./RRC/ho.png) + +# Steps to run F1 handover with OAI UE + +Measurement reporting and processing of RRC Reconfiguration for Mobility are +not completed at the UE. Nevertheless, it is possible to make simple handover +tests without any radio setup, on a single PC, with the OAI UE, in RFsimulator. + +## Build with telnet support + +Since the UE does not support any measurement reporting, it cannot trigger a +handover on its own; it has to be triggered manually through telnet. Thus, +build both gNB and UE as well as activate the build of telnet to that purpose: + + ./build_oai --ninja --nrUE --gNB --build-lib telnetsrv + +## Run the setup + +This tutorial assumes you have a core network running; [refer to the +corresponding tutorial](./NR_SA_Tutorial_OAI_CN5G.md) if this is not the case +yet. + +We will use the TDD configuration files in the repository for the +[CU](../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-cu.sa.f1.conf) as well for +[DU0](../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band78.106prb.rfsim.pci0.conf) +and +[DU1](../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band78.106prb.rfsim.pci1.conf). +Note how the DUs differ in their DU ID (for identification at the CU), nr +cellid (global identification), physical cell ID (identification through UE), +frequency (limitation at OAI UE), and IP address. + +Make sure that using RFsimulator and the CU and each DU, you can achieve a full +connection of the UE (independently, i.e., running one DU a time). Once this is +done, follow below steps to trigger a handover: + +Start the CU including telnet support: + + sudo ./nr-softmodem --sa -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-cu.sa.f1.conf --telnetsrv --telnetsrv.shrmod ci + +Start DU0: + + sudo ./nr-softmodem --sa --rfsim -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band78.106prb.rfsim.pci0.conf --rfsimulator.serveraddr 127.0.0.1 + +Start the UE, and let it connect completely: + + sudo ./nr-uesoftmodem --sa -C 3450720000 -r 106 --numerology 1 --ssb 516 -O --rfsim --rfsimulator.serveraddr server + +Note how the RFsimulator roles have been switched, and RFsim server is at the +UE side; _this is important_. Replace `` with the UE configuration +matching your core. If you followed the CN and oaiUE tutorials, you can remove +`-O ` and replace it with `--uicc0.imsi 001010000000001`. + +Once the UE is connected, start DU1: + + sudo ./nr-softmodem --sa --rfsim -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band78.106prb.rfsim.pci1.conf --rfsimulator.serveraddr 127.0.0.1 + +Once DU1 is online, you can trigger a handover by issuing this command + + echo ci trigger_f1_ho | nc 127.0.0.1 9090 && echo + +You should see how the UE switches from one DU to another. See additional +information further below. + +A number of remarks: + +1. It is important that you start DU0, UE, DU1 in order, and having UE connect + to DU0 before starting DU1. This is because we don't employ any channel + emulation, and the UE could not decode the SIB1 of DU0 to connect. +1. The RFsimulator roles are switched. Typically, the gNB RFsim acts as the + server and the UE as a client. However, RFsim is limited to one server with + multiple clients. Since the UE should be able to connect to both DUs, it has + to act as the server, and both DUs are a client. +1. If you see errors `could not open a socket` and/or `Could not start the RF + device`, this means that RFsim could not be started. Handover will not work; + please refer to the preceding point to fix this (i.e., run the UE as the + RFsim server). +1. In some cases, if the RFsim server is at the UE, the whole system can block; + in this case, stop UE and all DUs and restart (the CU can keep running). + +## Additional information to the manual HO trigger + +You can trigger the handover manually by logging in through telnet: + + telnet 127.0.0.1 9090 + +and then manually typing `ci trigger_f1_ho`. + +The command using `nc` (`netcat`) above triggers handovers directly from bash. +It does the same as logging in through telnet otherwise, and is a shorthand. + +The full command is + + ci trigger_f1_ho [cu-ue-id] + +`cu-ue-id` is optional. If only one UE context is present in the RRC, it will +trigger the handover for this UE in a round-robin fashion across all DUs. If +there is only one DU, the handover request will be rejected. Similarly, if +there are multiple UE contexts present at RRC, the handover will be rejected, +and you have to manually type the CU UE ID. You can see a list of all UEs in +the file `nrRRC_stats.log` that is printed periodically in the working +directory of the CU. + +# Steps to run F1 handover with COTS UE + +You can do handover across DUs with a COTS UE. Note that these DUs should be +separated by at least multiple meters to ensure that the UE will receive +different signal strengths when moving between cells. + +We only support intra-frequency handovers yet. We have verified with USRPs +only, although other radios should work as well. + +For UEs, we verified Quectel modules and iPhones. Note, though, that not all +phones might work; for instance, we did not achieve handovers with a OnePlus +Nord, yet. + +## Steps + +First, make sure that you can run both DUs with the CU independently. Use the +same radio hardware for both radios to ensure that both cells can be received +equally good by the UE. + +In order to enable handovers (triggered by the UE), you have to configure the +neighbour relation of the DUs at the CU. To do so, proceed as follows: + +1. To simplify filling the right values in the neighbour configuration, you can + rely on the information the CU has about both DUs. Start the CU and both + DUs. Navigate to the directory from which you started the CU, and print RRC + statistics: + ``` + cat nrRRC_stats.log + ``` +1. Fill in the `neighbour-config.conf` configuration file as shown below, and + `@include` it in the CU file. +1. Start the CU and both DUs. +1. Bring the phone close to one cell, and leave flight mode. It should connect + to the DU to which it is closer. +1. Move the UE towards the other DU; it should trigger an "A3 event" (Neighbour + Becomes Better than Serving), and the CU will trigger the handover to the + other DU. + +The output on the terminal should be the same as with RFsim. If no handover is +triggered: + +- Make sure that both DUs use the same hardware. +- Make sure that the UE sees both cells. For instance, you can switch to flight + mode, go closer to the other DU, and switch off flight mode -- the UE should + connect to that second UE. +- We did not manage handover with every phone yet -- make sure you use one of + the list provided above. + +You can also force a handover through telnet as described above. (In fact, the +decision about a handover is always at the network-side, the UE only "assists" +through measurements telling the CU that one DU is stronger than others. +Hence, "forcing" a handover just means that you manually trigger the handover, +instead of waiting for UE measurement report.) + +## Example neighbour configuration + +Below is an example neighbour configuration. It is based on this DU information +gathered from `nrRRC_stats.log` at the CU: + +``` +[1] DU ID 3585 (gNB-in-docker) assoc_id 4161: nrCellID 11111111, PCI 1, SSB ARFCN 643296 + TDD: band 78 ARFCN 642024 SCS 30 (kHz) PRB 106 +[2] DU ID 3584 (gNB-in-docker) assoc_id 4163: nrCellID 12345678, PCI 0, SSB ARFCN 643296 + TDD: band 78 ARFCN 642024 SCS 30 (kHz) PRB 106 +``` + +Note how both DUs have one cell on the same frequency and the same radio +configuration. From this, fill the neighbour list as shown below. + +Concretely, the first cell is `12345678` (on DU `[2]`), and it has `11111111` +(on DU `[1]`) as its neighbour; hence in the first block, you fill +`physical_cellId` and other values for DU `[1]`, and vice versa. + +The below configuration further enables periodic measurements, A2 event +("Serving becomes worse than threshold"), and A3 events ("Neighbour Becomes +Better than Serving"). The A2 event can be disabled by setting `enable = 0`. A3 +events cannot be disabled as of now. Further, the A3 events can be made +specific to cells; `cell_id = -1` means "any cell". + +``` +neighbour_list = ( + { + nr_cellid = 12345678; + neighbour_cell_configuration = ( + { + gNB_ID = 0xe01; + nr_cellid = 11111111; + physical_cellId = 1; + absoluteFrequencySSB = 643296; + subcarrierSpacing = 1; #30 KHz + plmn = { mcc = 001; mnc = 01; mnc_length = 2}; + tracking_area_code = 1; + } + ) + }, + { + nr_cellid = 11111111; + neighbour_cell_configuration = ( + { + gNB_ID = 0xe00; + nr_cellid = 12345678; + physical_cellId = 0; + absoluteFrequencySSB = 643296; + subcarrierSpacing = 1; #30 KHz + plmn = { mcc = 001; mnc = 01; mnc_length = 2}; + tracking_area_code = 1; + } + ) + } + ); + + +nr_measurement_configuration = { + Periodical = { + enable = 1; + includeBeamMeasurements = 1; + maxNrofRS_IndexesToReport = 4; + }; + + A2 = { + enable = 1; + threshold = 60; + timeToTrigger = 1; + }; + + A3 = ({ + cell_id = -1; #Default + offset = 10; + hysteresis = 0; + timeToTrigger = 1 + }) +}; +``` + +# Handovers triggers and NTN + +Typically, in terrestrial networks, channel measurements as well as criteria +such as load in base stations, is used to determine when and where to handover +a UE. + +## NTN + +Doppler spreading and time selectivity of the channel are already a challenge +for conventional terrestrial networks. However, in the context of +non-terrestrial networks (NTN), and low-earth orbit (LEO) systems, the +satellites can have speeds up 7.56 km/s, which is much faster than 0.14 km/s of +a high-speed train in terrestrial networks. Also, the delays in LEO are more varied +and longer, and the path loss is larger, because the communication distances is up +to 10 times longer than in terrestrial networks. Moreover, downlink in LEO +presents a high interference from adjacent satellite beams, and all these +features contribute to reduced received signal strength variation in these +networks compared to terrestrial networks. Typically, the criteria used in +algorithms presented in conventional terrestrial networks to trigger a handover +from a gNB to another one is based on signal strength measurements (cf., A3 +event above). However, the reduced received signal strength variation in NTNs +make these algorithms inefficient for LEO systems. Therefore, algorithms with +criteria for handover triggering that address the specifics of LEO systems are +crucial for an efficient handover processing that ensures a robust +communication with low dropping probability. Some criteria for handovers in NTN +are as follows: + +- **Measurement-based triggering**: This method is based on signal strength + measurement, and as stated above, it may not be efficient. The triggering + thresholds and which measurement events to use as triggers, as reference + signal received power (RSRP), reference signal received quality (RSRQ), or + received signal strength indicator (RSSI), should be configured. This method + relies on UE estimates and established channel estimation techniques, however + it would require neighbouring cell lists which can be hard because the + fast-moving of satellites leads to a fast cell coverage deviation. + +- **Location-based triggering**: This method is based on UE and satellite + location, which can be applied jointly (or not) with another trigger as the + measurement-based trigger. For instance, for a deterministic satellite + movement, it is possible to predict the configure triggering condition, and + the initial association of the UE can be performed based on the distance with + the nearest satellite, because we can know the location of the UE and NTN + satellite to compute the distance. + +- **Elevation angles of source and target cells based triggering**: This method + is similar to the previous one, but it is based on the largest elevation + angle. + +- **Time/timer-based triggering**: This method uses triggering conditions based + on UTC time or a timer-based solution, which can also be applied jointly (or + not) with another trigger as the measurement-based trigger. The timer-based + handover trigger considers the deterministic satellite movement to predict + the time duration for which the satellite’s footprint covers a certain zone. + +- **Timing advance value-based triggering**: This method uses the timing + advance value (independently or jointly with another trigger) to trigger a + handover to the target cell. It is appropriate to overcome the Random-Access + preamble reception issue, where the UE needs to pre-compensate the instant + which sends the preamble. However, UEs with GNSS support are required to + perform this method. + +## Simple location/time-based trigger + +A location-based handover trigger, somewhat aligned with 3GPP Rel.17, taking +advantage of deterministic satellite movement, can be implemented whereby it is +assumed that the locations of the UE and the NTN satellite are known. From a +practical point of view, this means that we know how long it takes to perform +the handover, and therefore we only need to implement a timer. + +It is possible to modify the source code to trigger a time-based handover, or +combine with other methods. If all what is required is a trigger every 15 +seconds, you can also resort to the telnet-based handover trigger above, and +run in a terminal: + +```bash +while true; do + echo ci trigger_f1_ho | nc -N 127.0.0.1 9090 && echo + sleep 15 +done +``` From f2c6fce30ffde7685a4d0f1e2209edaf755454f5 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 7 Oct 2024 19:22:34 +0200 Subject: [PATCH 70/75] Add 5G RRC documentation --- doc/RRC/rrc-dev.md | 318 +++++++++++++++++++++++++++++++++++++++++++ doc/RRC/rrc-usage.md | 99 ++++++++++++++ 2 files changed, 417 insertions(+) create mode 100644 doc/RRC/rrc-dev.md create mode 100644 doc/RRC/rrc-usage.md diff --git a/doc/RRC/rrc-dev.md b/doc/RRC/rrc-dev.md new file mode 100644 index 0000000000..d511421b01 --- /dev/null +++ b/doc/RRC/rrc-dev.md @@ -0,0 +1,318 @@ +This document contains documentation for the 5G RRC layer, destined towards +developers. It explains the basic working of the RRC, and various UE procedure +schemes (connection, reestablishment, handover) including their interworking +with other layers. + +User documentation, such as general configuration options, are described in [a +separate page](./rrc-usage.md). + +[[_TOC_]] + +# General + +5G RRC is basically an ITTI message queue with associated handlers. It +sequentially reads received ITTI messages and handles them through the function +`rrc_gnb_task()` (constituing the thread entry point function). In this +function, one can see three main groups of messages in a big switch statement: + +- NGAP (messages starting with `NGAP_`) +- F1AP (messages starting with `F1AP_`) +- E1AP (messages starting with `E1AP_`) + +For each message, a corresponding handler is called. The messages are roughly +named according to the 3GPP specification messages, so it should already be +possible to find the message in the switch based on a message name in the spec. + +Note that RRC is inherently single-threaded, and processes messages in a FIFO +order. + +# Sequence Diagrams of UE procedures + +The following section presents a number of common UE procedures for connection +establishment&control, bearer establishment, etc. The intention is to help +developers find specific functions within RRC in the context of these +procedures. For more information on message handlers at F1 and E1 layers, +please refer to the respective [F1 documentation](../F1AP/F1-design.md) and [E1 +documentation](../E1AP/E1-design.md). + +For more information on these procedures, please also refer to 3GPP TS 38.401 +(NG-RAN Architecture Description) and O-RAN.WG5.C.1-v11 (NR C-plane profile). + +A lot of the following diagrams would show an exchange between CU-CP, DU, and +UE, in which the CU-CP forwards an "RRC Message" to the UE via an F1AP DL RRC +Message Transfer through the DU, and correspondingly receives the "RRC Message +Answer", as follows: + +```mermaid +sequenceDiagram + participant ue as UE + participant du as DU + participant cucp as CU-CP + cucp->>du: F1AP DL RRC Msg Transfer (RRC Message) + du->>ue: RRC Message + ue->>du: RRC Message Answer + du->>cucp: F1AP UL RRC Msg Transfer (RRC Message Answer) +``` + +To better utilize horizontal space, these exchanges have been collapsed as +follows, but should be read as the above exchange: + +```mermaid +sequenceDiagram + participant ue as UE + participant du as DU + participant cucp as CU-CP + cucp->>ue: F1AP DL RRC Msg Transfer (RRC Message) + ue->>cucp: F1AP UL RRC Msg Transfer (RRC Message Answer) +``` + +## Initial connection setup/Registration + +This sequence diagram shows the principal steps for an initial UE connection. +This can either happen through a _Registration Request_ (e.g., UE connects +"from flight mode"), or a _Service Request_ (i.e., UE connects after leaving +coverage). Both requests are handled similarly by the gNB, and basically +distinguish themselves, from the point of view of the gNB, by having PDU +sessions in the NGAP Initial Context Setup Request present (Service Request) or +not (Registration Request, with following PDU Session Resource Setup Request +procedure). + +```mermaid +sequenceDiagram + participant ue as UE + participant du as DU + participant cucp as CU-CP + participant cuup as CU-UP + participant amf as AMF + + ue->>du: Msg1/Preamble + du->>ue: Msg2/RAR + ue->>cucp: F1AP Initial UL RRC Msg Tr (RRC Setup Req, in Msg3) + Note over cucp: rrc_handle_RRCSetupRequest() + cucp->>ue: F1AP DL RRC Msg Transfer (RRC Setup, in Msg4) + ue->>cucp: F1AP UL RRC Msg Transfer (RRC Setup Complete) + Note over cucp: rrc_handle_RRCSetupComplete() +%% TODO: when is RRC connected? + cucp->>amf: NGAP Initial UE Message (NAS Registration/Service Req) + Note over amf,ue: NAS Authentication Procedure (see 24.501) + Note over amf,ue: NAS Security Procedure (see 24.501) + amf->>cucp: NGAP Initial Context Setup Req + Note over cucp: rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ() + Note over cucp: rrc_gNB_generate_SecurityModeCommand() + cucp->>ue: F1AP DL RRC Msg Transfer (RRC Security Mode Command) + ue->>cucp: F1AP UL RRC Msg Transfer (RRC Security Mode Complete) + Note over cucp: rrc_gNB_decode_dcch() (inline) + opt No UE Capabilities present + Note over cucp: rrc_gNB_generate_UECapabilityEnquiry() + cucp->>ue: F1AP DL RRC Msg Transfer (RRC UE Capability Enquiry) + ue->>cucp: F1AP UL RRC Msg Transfer (RRC UE Capability Information) + Note over cucp: handle_ueCapabilityInformation() + end + opt PDU Sessions in NGAP Initial Context Setup Req present + Note over cucp: trigger_bearer_setup() + cucp->>cuup: E1AP Bearer Context Setup Req + cuup->>cucp: E1AP Bearer Context Setup Resp + Note over cucp: rrc_gNB_process_e1_bearer_context_setup_resp() + cucp->>du: F1AP UE Context Setup Req + du->>cucp: F1AP UE Context Setup Resp + Note over cucp: rrc_CU_process_ue_context_setup_response() + Note over cucp: e1_send_bearer_updates() + cucp->>cuup: E1AP Bearer Context Modification Req + cucp->>ue: F1AP DL RRC Msg Transfer (RRC Reconfiguration) + cuup->>cucp: E1AP Bearer Context Modification Resp + ue->>cucp: F1AP UL RRC Msg Transfer (RRC Reconfiguration Complete) + Note over cucp: handle_rrcReconfigurationComplete() + end + Note over cucp: rrc_gNB_send_NGAP_INITIAL_CONTEXT_SETUP_RESP() + cucp->>amf: NGAP Initial Context Setup Resp (NAS Registration/Service Complete) +``` + +Note that if no PDU session is present in the NGAP Initial UE Context Setup +Req, no F1AP UE Context Setup will be observed during this initial phase. + +If there is no PDU session set up during NGAP Initial Context Setup Req, the UE +typically requests a PDU session(s) through a NAS procedure, which is basically +the same code paths as the above optional PDU Session setup during an NGAP +Initial Context Setup procedure: + +```mermaid +sequenceDiagram + participant ue as UE + participant du as DU + participant cucp as CU-CP + participant cuup as CU-UP + participant amf as AMF + + ue->>cucp: F1AP UL RRC Msg Transfer (RRC UL Information Transfer) + cucp->>amf: NGAP UL NAS Transport (NAS PDU Session Establishment Req) + amf->>cucp: NGAP PDU Session Resource Setup Req (NAS PDU Session Establishment Accept) + Note over cucp: rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ() + Note over cucp: trigger_bearer_setup() + cucp->>cuup: E1AP Bearer Context Setup Req + cuup->>cucp: E1AP Bearer Context Setup Resp + Note over cucp: rrc_gNB_process_e1_bearer_context_setup_resp() + cucp->>du: F1AP UE Context Setup Req + du->>cucp: F1AP UE Context Setup Resp + Note over cucp: rrc_CU_process_ue_context_setup_response() + Note over cucp: e1_send_bearer_updates() + cucp->>cuup: E1AP Bearer Context Modification Req + cucp->>ue: F1AP DL RRC Msg Transfer (RRC Reconfiguration + NAS PDU Session Establishment Accept) + cuup->>cucp: E1AP Bearer Context Modification Resp + ue->>cucp: F1AP UL RRC Msg Transfer (RRC Reconfiguration Complete) + Note over cucp: handle_rrcReconfigurationComplete() + Note over cucp: rrc_gNB_send_NGAP_PDUSESSION_SETUP_RESP() + cucp->>amf: NGAP PDU Session Resource Setup Resp +``` + +## Reestablishment + +The following sequence diagram shows the principal steps during a +reestablishment request. When handling the RRC Reestablishment Request at the +CU-CP, it notably checks if this UE is already known, if the UE is still at the +same DU as it used to be previously (might change because of, or despite +handover), and other validation checks. If all checks pass, the CU-CP continues +with the reestablishment procedure; if any check fails, the CU-CP tries to +release the old UE at the AMF, and continues with the "normal" connection setup +(registration/service request) described above. + +```mermaid +sequenceDiagram + participant ue as UE + participant du as DU + participant cucp as CU-CP + participant cuup as CU-UP + participant amf as AMF + + ue->>du: Msg1/Preamble + du->>ue: Msg2/RAR + ue->>du: Msg3 w/ RRC Reestabishment Request (old C-RNTI/PCI) + Note over du: DU creates UE context for new RNTI + du->>cucp: F1AP Initial UL RRC Msg Tr (RRC Reestab Req, in Msg3) + Note over cucp: rrc_handle_RRCReestablishmentRequest() + alt UE known and at the original DU + Note over cucp: rrc_gNB_generate_RRCReestablishment()
SRB1 PDCP reestablishment + cucp->>du: F1AP DL RRC Msg Tr (old gNB-DU-UE ID) + Note over du: Reuse configuration of and delete old UE
(in dl_rrc_message_transfer()) + du->>ue: RRC Reestablishment + ue->>du: RRC Reestablishment Complete + du->>cucp: F1AP UL RRC Msg Tr (RRC Reestab Complete) + Note over cucp: handle_rrcReestablishmentComplete() + Note over cucp: cuup_notify_reestablishment() + cucp->>cuup: E1AP Bearer Context Modification Req + cucp->>ue: F1AP DL RRC Msg Transfer (RRC Reconfiguration) + cuup->>cucp: E1AP Bearer Context Modification Resp + ue->>cucp: F1AP UL RRC Msg Transfer (RRC Reconfiguration Complete) + Note over cucp: handle_rrcReestablishmentComplete() + else Fallback* + cucp->>amf: NGAP UE Context Release Request + Note over cucp: rrc_gNB_generate_RRCSetup() + Note over ue,amf: Continue with connection setup (registration/service request) + end +``` + +## Handover + +The basic handover (HO) structure is as follows. In order to support various +handover "message passing implementation" (F1AP, NGAP, XnAP), RRC employs +callbacks to signal HO Accept (`ho_req_ack()`), HO Success (`ho_success()`), +and HO Cancel (`ho_cancel()`). These can be used to trigger the corresponding +functionality based on mentioned "message passing implementation". + +The following sequence diagram shows the basic functional execution of a +successful handover in the case of an F1 handover. Note the callbacks as +mentioned above: + +```mermaid +sequenceDiagram + participant ue as UE + participant sdu as source DU + participant tdu as target DU + participant cucp as CU-CP + participant cuup as CU-UP + + Note over ue,sdu: UE active on source DU + alt HO triggered through A3 event + ue->>sdu: RRC Measurement Report + sdu->>cucp: F1AP UL RRC Msg Transfer (RRC Measurement Report) + Note over cucp: Handover decision (A3 event trigger) + else Manual Trigger + Note over cucp: Handover decision (e.g., telnet) + end + Note over cucp: nr_rrc_trigger_f1_ho() ("on source CU") + Note over cucp: nr_initiate_handover() ("on target CU") + cucp->>tdu: F1AP UE Context Setup Req + Note over tdu: Create UE context + tdu->>cucp: F1AP UE Context Setup Resp (incl. CellGroupConfig) + Note over cucp: rrc_CU_process_ue_context_setup_response() ("on target CU") + Note over cucp: cuup_notify_reestablishment() + cucp->>cuup: E1AP Bearer Context Modification Req + cucp-->>cucp: callback: ho_req_ack() + Note over cucp: nr_rrc_f1_ho_acknowledge() ("on source CU") + cucp->>sdu: F1AP Context Modification Req (RRC Reconfiguration) + cuup->>cucp: E1AP Bearer Context Modification Resp + sdu->>ue: RRC Reconfiguration + sdu->>cucp: F1AP Context Modification Resp + Note over sdu: Stop scheduling UE + Note over ue: Resync + Note over ue,tdu: RA (Msg1 + Msg2) + ue->>tdu: RRC Reconfiguration Complete + tdu->>cucp: F1AP UL RRC Msg Transfer (RRC Reconfiguration Complete) + Note over cucp: handle_rrcReconfigurationComplete() ("on target CU") + cucp-->>cucp: callback: ho_success() + Note over cucp: nr_rrc_f1_ho_complete() ("on source CU") + cucp->>sdu: F1AP UE Context Release Command + sdu->>cucp: F1AP UE Context Release Complete + Note over ue,tdu: UE active on target DU +``` + +# Structures + +## Cells + +OAI 5G RRC does not actually handle multiple cells as of now, but multiple DUs, +each being limited to one cell. + +Cell-related data is stored in `nr_rrc_du_container_t`, and kept in a tree +indexed by the SCTP association ID. + +## CU-UPs + +CU-UP information is stored in `nr_rrc_cuup_container_t`, and kept in a tree +indexed by the SCTP association ID. + +## Transactions + +The RRC keeps track of ongoing transaction (RRC procedures) through a per-UE +array `xids`, which is indexed with a transaction ID `xid` in `[0,3]` to keep +track of ongoing transactions. Upon RRC Reconfiguration Complete, these IDs are +deleted. + +Note that while 38.331 requires only one RRC transaction to happen at a time, +the 5G RRC does not actually ensure this; it only tries to prevent it by +chaining of transactions and some checks. For instance, the Security Mode +procedure is followed by a UE capability procedure, and some procedures are not +executed if others are ongoing (ex.: handover if there is reconfiguratio). +However, it might be possible to trigger a procedure while another is ongoing. + +As of now, no queueing mechanims exists to ensure only one operation is +ongoing, which would likely also simplify the code. + +## Handover + +Handover-related data is stored in a per-UE structure of type +`nr_handover_context_t`. It is a pointer and only set during handover +operation. This data structure has in turn two pointers, one to the source CU +(`nr_ho_source_cu_t`), and one to the target CU (`nr_ho_target_cu_t`). In F1, +both are present. In N2 and Xn, only one pointer is supposed to be set a the +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 +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 +function pointers merely calls another (RRC) function which triggers a +reconfiguration. In the case of N2, the handover request acknowledge function +pointer should trigger the NGAP Handover Request Acknowledge, and the handover +success function pointer should trigger the NGAP Handover Success message. diff --git a/doc/RRC/rrc-usage.md b/doc/RRC/rrc-usage.md new file mode 100644 index 0000000000..668c106a0d --- /dev/null +++ b/doc/RRC/rrc-usage.md @@ -0,0 +1,99 @@ +This document describes the basic functioning of the 5G RRC layer, describes +the periodic output, and explains the various configuration options that +influence its behavior. + +Developer documentation, such as UE connection control flow, reestablishment, or handover, are described in [a separate page](./rrc-dev.md). + +[[_TOC_]] + +# General + +The RRC layer controls the basic connection setup of UEs as well as additional +procedures. It is the fundamental building block of OAI's CU-CP, and interacts +with lower layers (DU, basically MAC and RLC) through F1AP messages, and with +the CU-UP through E1AP messages. More information can be found in the +respective [F1AP page](../F1-design.md) and [E1AP page](../E1AP/E1-design.md). + +# Periodic output and interpretation + +Similarly to the scheduler, the RRC periodically prints information about +connected UEs and DUs into file `nrRRC_stats.log` in the current working +directory of the executable running the RRC (typically, `nr-softmodem`). The +output lists first all UEs that are currently connected, and then all DUs, in +order. + +For each UE, it prints: + +``` +UE 0 CU UE ID 1 DU UE ID 40352 RNTI 9da0 random identity c0f1ac9824000000: + last RRC activity: 5 seconds ago + PDU session 0 ID 10 status established + associated DU: DU assoc ID 8 +``` + +where `UE 0` is the UE index, CU UE ID and DU UE IDs are the IDs used to +exchange over F1 (cf. scheduler logs). Further, it shows RNTI, when the last +RRC activity happened, the status of PDU sessions and which DU is associated +(through the SCTP association ID). + + +For each DU, it prints: + +``` +1 connected DUs +[1] DU ID 3584 (gNB-OAI-DU) assoc_id 8: nrCellID 12345678, PCI 0, SSB ARFCN 641280 + TDD: band 78 ARFCN 640008 SCS 30 (kHz) PRB 106 +``` + +i.e., an index (`[1]`), the DU ID and it's name, the SCTP association ID +(`assoc_id 8`, cf. UE information), and DU specific information for the cell +(cell ID, physical cell identity/PCI, the SSB frequency in ARFCN notation, the +band and Point A ARFCN, subcarrier spacing/SCS, and the number of resource +blocks/PRB). Only one cell per DU is supported. + +As of now, it does not print information about connected CU-UPs or AMFs. + +# Configuration of the RRC + +## Split-related options (when running in a CU or CU-CP) + +See [F1 documentation](../F1-design.md) for information about the F1 split. +See [E1 documentation](../E1AP/E1-design.md) for information about the E1 split. + +## RRC-specific configuration options + +In the `gNBs` section of the gNB/CU/CU-CP configuration file is the +RRC-specific configuration + +### cell-specific options + +- `gNB_ID` and `gNB_name`: ID and name of the gNB +- `tracking_area_code`: the current tracking area code in the range `[0x0001, + 0xfffd]` +- `plmn`: the PLMN, which is a list of entries consisting of: + - `mcc`: mobile country code + - `mnc`: mobile network code + - `mnc_length`: length of mobile network code, allowed values: 2, 3 + - `snssaiList`: list of NSSAI (network selection slice assistence + information, "slice ID"), which itself consists in + - `sst`: slice service type, in `[1,255]` + - `sd` (default `0xffffff`): slice differentiator, in `[0,0xffffff]`, + `0xffffff` is a reserved value and means "no SD" + Note that: SST=1, no SD is "eMBB"; SST=2, no SD is "URLLC"; SST=3, no SD + is "mMTC" +- `enable_sdap` (default: false): enable the use of the SDAP layer. If + deactivated, a transparent SDAP header is prepended to packets, but no + further processing is being done. + +### UE-specific configuration + +- `um_on_default_drb` (default: false): use RLC UM instead of RLC AM on default + bearers +- `drbs` (default: 0): the number of DRBs to allocate for a UE, only useful for + do-ra or phy-test testing + +### Neighbor-gNB configuration + + TBD + +Refer to the [handover tutorial](../handover-tutorial.md) for more information. From c8387d706cbd7b0f4905b718bb4c84996e412966 Mon Sep 17 00:00:00 2001 From: francescomani Date: Thu, 26 Sep 2024 10:05:25 +0200 Subject: [PATCH 71/75] making ULSCH preprocessor agnostic to UEs BWP and TDA --- .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 238 +++++++----------- 1 file changed, 90 insertions(+), 148 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 84d80bc930..2149386399 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -1640,7 +1640,8 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac, NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP; int rbStart = 0; // wrt BWP start - const uint16_t bwpSize = ul_bwp->BWPSize; + const uint32_t bwpSize = ul_bwp->BWPSize; + const uint32_t bwpStart = ul_bwp->BWPStart; const uint8_t nrOfLayers = retInfo->nrOfLayers; LOG_D(NR_MAC,"retInfo->time_domain_allocation = %d, tda = %d\n", retInfo->time_domain_allocation, tda); LOG_D(NR_MAC,"tbs %d\n",retInfo->tb_size); @@ -1651,11 +1652,12 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac, tda); if (!tda_info.valid_tda) return false; + bool reuse_old_tda = (retInfo->tda_info.startSymbolIndex == tda_info.startSymbolIndex) && (retInfo->tda_info.nrOfSymbols <= tda_info.nrOfSymbols); if (reuse_old_tda && nrOfLayers == retInfo->nrOfLayers) { /* Check the resource is enough for retransmission */ const uint16_t slbitmap = SL_to_bitmap(retInfo->tda_info.startSymbolIndex, retInfo->tda_info.nrOfSymbols); - while (rbStart < bwpSize && (rballoc_mask[rbStart] & slbitmap)) + while (rbStart < bwpSize && (rballoc_mask[rbStart + bwpStart] & slbitmap)) rbStart++; if (rbStart + retInfo->rbSize > bwpSize) { LOG_D(NR_MAC, "[UE %04x][%4d.%2d] could not allocate UL retransmission: no resources (rbStart %d, retInfo->rbSize %d, bwpSize %d) \n", @@ -1667,19 +1669,16 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac, bwpSize); return false; } - LOG_D(NR_MAC, "%s(): retransmission keeping TDA %d and TBS %d\n", __func__, tda, retInfo->tb_size); + LOG_D(NR_MAC, "Retransmission keeping TDA %d and TBS %d\n", tda, retInfo->tb_size); } else { - NR_pusch_dmrs_t dmrs_info = get_ul_dmrs_params(scc, - ul_bwp, - &tda_info, - nrOfLayers); + NR_pusch_dmrs_t dmrs_info = get_ul_dmrs_params(scc, ul_bwp, &tda_info, nrOfLayers); /* the retransmission will use a different time domain allocation, check * that we have enough resources */ const uint16_t slbitmap = SL_to_bitmap(tda_info.startSymbolIndex, tda_info.nrOfSymbols); - while (rbStart < bwpSize && (rballoc_mask[rbStart] & slbitmap)) + while (rbStart < bwpSize && (rballoc_mask[rbStart + bwpStart] & slbitmap)) rbStart++; int rbSize = 0; - while (rbStart + rbSize < bwpSize && !(rballoc_mask[rbStart + rbSize] & slbitmap)) + while (rbStart + rbSize < bwpSize && !(rballoc_mask[rbStart + bwpStart + rbSize] & slbitmap)) rbSize++; uint32_t new_tbs; uint16_t new_rbSize; @@ -1703,7 +1702,7 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac, retInfo->tb_size); return false; /* the maximum TBsize we might have is smaller than what we need */ } - LOG_D(NR_MAC, "%s(): retransmission with TDA %d->%d and TBS %d -> %d\n", __func__, retInfo->time_domain_allocation, tda, retInfo->tb_size, new_tbs); + LOG_D(NR_MAC, "Retransmission with TDA %d->%d and TBS %d -> %d\n", retInfo->time_domain_allocation, tda, retInfo->tb_size, new_tbs); /* we can allocate it. Overwrite the time_domain_allocation, the number * of RBs, and the new TB size. The rest is done below */ retInfo->tb_size = new_tbs; @@ -1715,7 +1714,9 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac, /* Find a free CCE */ int CCEIndex = get_cce_index(nrmac, - CC_id, slot, UE->rnti, + CC_id, + slot, + UE->rnti, &sched_ctrl->aggregation_level, 0, // TODO use beam index sched_ctrl->search_space, @@ -1723,10 +1724,7 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac, &sched_ctrl->sched_pdcch, false); if (CCEIndex<0) { - LOG_D(NR_MAC, "[UE %04x][%4d.%2d] no free CCE for retransmission UL DCI UE\n", - UE->rnti, - frame, - slot); + LOG_D(NR_MAC, "[UE %04x][%4d.%2d] no free CCE for retransmission UL DCI UE\n", UE->rnti, frame, slot); return false; } @@ -1738,11 +1736,8 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac, sched_ctrl->aggregation_level, 0); // TODO use beam index when implemented - /* frame/slot in sched_pusch has been set previously. In the following, we - * overwrite the information in the retransmission information before storing - * as the new scheduling instruction */ - retInfo->frame = sched_ctrl->sched_pusch.frame; - retInfo->slot = sched_ctrl->sched_pusch.slot; + retInfo->frame = (frame + (slot + tda_info.k2) / nr_slots_per_frame[ul_bwp->scs]) % MAX_FRAME_NUMBER; + retInfo->slot = (slot + tda_info.k2) % nr_slots_per_frame[ul_bwp->scs]; /* Get previous PSUCH field info */ sched_ctrl->sched_pusch = *retInfo; NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch; @@ -1761,7 +1756,7 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac, /* Mark the corresponding RBs as used */ n_rb_sched -= sched_pusch->rbSize; - for (int rb = 0; rb < sched_ctrl->sched_pusch.rbSize; rb++) + for (int rb = bwpStart; rb < sched_ctrl->sched_pusch.rbSize; rb++) rballoc_mask[rb + sched_ctrl->sched_pusch.rbStart] |= SL_to_bitmap(sched_pusch->tda_info.startSymbolIndex, sched_pusch->tda_info.nrOfSymbols); return true; } @@ -1778,22 +1773,22 @@ static int comparator(const void *p, const void *q) { static void pf_ul(module_id_t module_id, frame_t frame, - sub_frame_t slot, + int slot, + frame_t sched_frame, + int sched_slot, NR_UE_info_t *UE_list[], int max_num_ue, - int n_rb_sched, - uint16_t *rballoc_mask) + int n_rb_sched) { - const int CC_id = 0; gNB_MAC_INST *nrmac = RC.nrmac[module_id]; NR_ServingCellConfigCommon_t *scc = nrmac->common_channels[CC_id].ServingCellConfigCommon; - + const int min_rb = nrmac->min_grant_prb; // UEs that could be scheduled UEsched_t UE_sched[MAX_MOBILES_PER_GNB] = {0}; int remainUEs = max_num_ue; - int curUE=0; + int curUE = 0; /* Loop UE_list to calculate throughput and coeff */ UE_iterator(UE_list, UE) { @@ -1805,9 +1800,6 @@ static void pf_ul(module_id_t module_id, LOG_D(NR_MAC,"pf_ul: preparing UL scheduling for UE %04x\n",UE->rnti); NR_UE_UL_BWP_t *current_BWP = &UE->current_UL_BWP; - int rbStart = 0; // wrt BWP start - - const uint16_t bwpSize = current_BWP->BWPSize; NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch; const NR_mac_dir_stats_t *stats = &UE->mac_stats.ul; @@ -1819,12 +1811,16 @@ static void pf_ul(module_id_t module_id, if(remainUEs == 0) continue; + const int index = ul_buffer_index(sched_frame, sched_slot, current_BWP->scs, nrmac->vrb_map_UL_size); + // TODO improve handling of beam in vrb_map (for now just using 0) + uint16_t *rballoc_mask = &nrmac->common_channels[CC_id].vrb_map_UL[0][index * MAX_BWP_SIZE]; + /* Check if retransmission is necessary */ sched_pusch->ul_harq_pid = sched_ctrl->retrans_ul_harq.head; LOG_D(NR_MAC,"pf_ul: UE %04x harq_pid %d\n",UE->rnti,sched_pusch->ul_harq_pid); if (sched_pusch->ul_harq_pid >= 0) { /* Allocate retransmission*/ - const int tda = get_ul_tda(nrmac, scc, sched_pusch->frame, sched_pusch->slot); + const int tda = get_ul_tda(nrmac, scc, sched_frame, sched_slot); bool r = allocate_ul_retransmission(nrmac, frame, slot, rballoc_mask, &n_rb_sched, UE, sched_pusch->ul_harq_pid, scc, tda); if (!r) { LOG_D(NR_MAC, "[UE %04x][%4d.%2d] UL retransmission could not be allocated\n", @@ -1853,7 +1849,7 @@ static void pf_ul(module_id_t module_id, const int B = max(0, sched_ctrl->estimated_ul_buffer - sched_ctrl->sched_ul_bytes); /* preprocessor computed sched_frame/sched_slot */ - const bool do_sched = nr_UE_is_to_be_scheduled(scc, 0, UE, sched_pusch->frame, sched_pusch->slot, nrmac->ulsch_max_frame_inactivity); + const bool do_sched = nr_UE_is_to_be_scheduled(scc, 0, UE, sched_frame, sched_slot, nrmac->ulsch_max_frame_inactivity); LOG_D(NR_MAC,"pf_ul: do_sched UE %04x => %s\n",UE->rnti,do_sched ? "yes" : "no"); if ((B == 0 && !do_sched) || (sched_ctrl->rrc_processing_timer > 0)) { @@ -1892,7 +1888,7 @@ static void pf_ul(module_id_t module_id, } sched_pusch->nrOfLayers = sched_ctrl->srs_feedback.ul_ri + 1; - sched_pusch->time_domain_allocation = get_ul_tda(nrmac, scc, sched_pusch->frame, sched_pusch->slot); + sched_pusch->time_domain_allocation = get_ul_tda(nrmac, scc, sched_frame, sched_slot); sched_pusch->tda_info = get_ul_tda_info(current_BWP, sched_ctrl->coreset->controlResourceSetId, sched_ctrl->search_space->searchSpaceType->present, @@ -1904,13 +1900,20 @@ static void pf_ul(module_id_t module_id, &sched_pusch->tda_info, sched_pusch->nrOfLayers); - LOG_D(NR_MAC,"Looking for min_rb %d RBs, starting at %d num_dmrs_cdm_grps_no_data %d\n", - min_rb, rbStart, sched_pusch->dmrs_info.num_dmrs_cdm_grps_no_data); + int rbStart = 0; // wrt BWP start + LOG_D(NR_MAC, + "Looking for min_rb %d RBs, starting at %d num_dmrs_cdm_grps_no_data %d\n", + min_rb, + rbStart, + sched_pusch->dmrs_info.num_dmrs_cdm_grps_no_data); + const uint32_t bwpSize = current_BWP->BWPSize; + const uint32_t bwpStart = current_BWP->BWPStart; const uint16_t slbitmap = SL_to_bitmap(sched_pusch->tda_info.startSymbolIndex, sched_pusch->tda_info.nrOfSymbols); - while (rbStart < bwpSize && (rballoc_mask[rbStart] & slbitmap)) + while (rbStart < bwpSize && (rballoc_mask[rbStart + bwpStart] & slbitmap)) rbStart++; if (rbStart + min_rb >= bwpSize) { - LOG_D(NR_MAC, "[UE %04x][%4d.%2d] could not allocate continuous UL data: no resources (rbStart %d, min_rb %d, bwpSize %d)\n", + LOG_D(NR_MAC, + "[UE %04x][%4d.%2d] could not allocate continuous UL data: no resources (rbStart %d, min_rb %d, bwpSize %d)\n", UE->rnti, frame, slot, @@ -1921,18 +1924,15 @@ static void pf_ul(module_id_t module_id, } sched_ctrl->cce_index = CCEIndex; - fill_pdcch_vrb_map(nrmac, - CC_id, - &sched_ctrl->sched_pdcch, - CCEIndex, - sched_ctrl->aggregation_level, - 0); // TODO use beam index); + fill_pdcch_vrb_map(nrmac, CC_id, &sched_ctrl->sched_pdcch, CCEIndex, sched_ctrl->aggregation_level, 0); // TODO use beam index NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch; sched_pusch->mcs = min(nrmac->min_grant_mcs, sched_pusch->mcs); update_ul_ue_R_Qm(sched_pusch->mcs, current_BWP->mcs_table, current_BWP->pusch_Config, &sched_pusch->R, &sched_pusch->Qm); sched_pusch->rbStart = rbStart; sched_pusch->rbSize = min_rb; + sched_pusch->frame = sched_frame; + sched_pusch->slot = sched_slot; sched_pusch->tb_size = nr_compute_tbs(sched_pusch->Qm, sched_pusch->R, sched_pusch->rbSize, @@ -1963,7 +1963,7 @@ static void pf_ul(module_id_t module_id, /* Mark the corresponding RBs as used */ n_rb_sched -= sched_pusch->rbSize; - for (int rb = 0; rb < sched_ctrl->sched_pusch.rbSize; rb++) + for (int rb = bwpStart; rb < sched_ctrl->sched_pusch.rbSize; rb++) rballoc_mask[rb + sched_ctrl->sched_pusch.rbStart] |= slbitmap; remainUEs--; @@ -1982,8 +1982,8 @@ static void pf_ul(module_id_t module_id, UE->ul_thr_ue, tbs, coeff_ue); - UE_sched[curUE].coef=coeff_ue; - UE_sched[curUE].UE=UE; + UE_sched[curUE].coef = coeff_ue; + UE_sched[curUE].UE = UE; curUE++; } @@ -2018,7 +2018,7 @@ static void pf_ul(module_id_t module_id, NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch; sched_pusch->nrOfLayers = sched_ctrl->srs_feedback.ul_ri + 1; - sched_pusch->time_domain_allocation = get_ul_tda(nrmac, scc, sched_pusch->frame, sched_pusch->slot); + sched_pusch->time_domain_allocation = get_ul_tda(nrmac, scc, sched_frame, sched_slot); sched_pusch->tda_info = get_ul_tda_info(current_BWP, sched_ctrl->coreset->controlResourceSetId, sched_ctrl->search_space->searchSpaceType->present, @@ -2030,14 +2030,19 @@ static void pf_ul(module_id_t module_id, &sched_pusch->tda_info, sched_pusch->nrOfLayers); + const int index = ul_buffer_index(sched_frame, sched_slot, current_BWP->scs, nrmac->vrb_map_UL_size); + // TODO improve handling of beam in vrb_map (for now just using 0) + uint16_t *rballoc_mask = &nrmac->common_channels[CC_id].vrb_map_UL[0][index * MAX_BWP_SIZE]; + int rbStart = 0; const uint16_t slbitmap = SL_to_bitmap(sched_pusch->tda_info.startSymbolIndex, sched_pusch->tda_info.nrOfSymbols); - const uint16_t bwpSize = current_BWP->BWPSize; - while (rbStart < bwpSize && (rballoc_mask[rbStart] & slbitmap)) + const uint32_t bwpSize = current_BWP->BWPSize; + const uint32_t bwpStart = current_BWP->BWPStart; + while (rbStart < bwpSize && (rballoc_mask[rbStart + bwpStart] & slbitmap)) rbStart++; sched_pusch->rbStart = rbStart; uint16_t max_rbSize = 1; - while (rbStart + max_rbSize < bwpSize && !(rballoc_mask[rbStart + max_rbSize] & slbitmap)) + while (rbStart + max_rbSize < bwpSize && !(rballoc_mask[rbStart + bwpStart + max_rbSize] & slbitmap)) max_rbSize++; if (rbStart + min_rb >= bwpSize || max_rbSize < min_rb) { @@ -2051,13 +2056,18 @@ static void pf_ul(module_id_t module_id, iterator++; continue; } else - LOG_D(NR_MAC, "allocating UL data for RNTI %04x (rbStart %d, min_rb %d, max_rbSize %d, bwpSize %d)\n", iterator->UE->rnti, rbStart, min_rb, max_rbSize, bwpSize); + LOG_D(NR_MAC, + "allocating UL data for RNTI %04x (rbStart %d, min_rb %d, max_rbSize %d, bwpSize %d)\n", + iterator->UE->rnti, + rbStart, + min_rb, + max_rbSize, + bwpSize); /* Calculate the current scheduling bytes */ const int B = cmax(sched_ctrl->estimated_ul_buffer - sched_ctrl->sched_ul_bytes, 0); /* adjust rbSize and MCS according to PHR and BPRE */ - if(sched_ctrl->pcmax!=0 || - sched_ctrl->ph!=0) // verify if the PHR related parameter have been initialized + if(sched_ctrl->pcmax != 0 || sched_ctrl->ph != 0) // verify if the PHR related parameter have been initialized nr_ue_max_mcs_min_rb(current_BWP->scs, sched_ctrl->ph, sched_pusch, current_BWP, min_rb, B, &max_rbSize, &sched_pusch->mcs); if (sched_pusch->mcs < sched_ctrl->ul_bler_stats.mcs) @@ -2093,22 +2103,27 @@ static void pf_ul(module_id_t module_id, sched_pusch->rbSize = rbSize; sched_pusch->tb_size = TBS; - LOG_D(NR_MAC,"rbSize %d (max_rbSize %d), TBS %d, est buf %d, sched_ul %d, B %d, CCE %d, num_dmrs_symb %d, N_PRB_DMRS %d\n", - rbSize, max_rbSize,sched_pusch->tb_size, sched_ctrl->estimated_ul_buffer, sched_ctrl->sched_ul_bytes, B, - sched_ctrl->cce_index,sched_pusch->dmrs_info.num_dmrs_symb,sched_pusch->dmrs_info.N_PRB_DMRS); + sched_pusch->frame = sched_frame; + sched_pusch->slot = sched_slot; + LOG_D(NR_MAC, + "rbSize %d (max_rbSize %d), TBS %d, est buf %d, sched_ul %d, B %d, CCE %d, num_dmrs_symb %d, N_PRB_DMRS %d\n", + rbSize, + max_rbSize, + sched_pusch->tb_size, + sched_ctrl->estimated_ul_buffer, + sched_ctrl->sched_ul_bytes, + B, + sched_ctrl->cce_index, + sched_pusch->dmrs_info.num_dmrs_symb, + sched_pusch->dmrs_info.N_PRB_DMRS); /* Mark the corresponding RBs as used */ sched_ctrl->cce_index = CCEIndex; - fill_pdcch_vrb_map(nrmac, - CC_id, - &sched_ctrl->sched_pdcch, - CCEIndex, - sched_ctrl->aggregation_level, - 0); // TODO use beam index); + fill_pdcch_vrb_map(nrmac, CC_id, &sched_ctrl->sched_pdcch, CCEIndex, sched_ctrl->aggregation_level, 0); // TODO use beam index n_rb_sched -= sched_pusch->rbSize; - for (int rb = 0; rb < sched_ctrl->sched_pusch.rbSize; rb++) + for (int rb = bwpStart; rb < sched_ctrl->sched_pusch.rbSize; rb++) rballoc_mask[rb + sched_ctrl->sched_pusch.rbStart] |= slbitmap; /* reduce max_num_ue once we are sure UE can be allocated, i.e., has CCE */ @@ -2120,92 +2135,25 @@ static void pf_ul(module_id_t module_id, static bool nr_fr1_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t slot) { gNB_MAC_INST *nr_mac = RC.nrmac[module_id]; - NR_COMMON_channels_t *cc = nr_mac->common_channels; - NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; - const NR_SIB1_t *sib1 = nr_mac->common_channels[0].sib1 ? nr_mac->common_channels[0].sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL; - NR_ServingCellConfigCommonSIB_t *scc_sib1 = sib1 ? sib1->servingCellConfigCommon : NULL; - - AssertFatal(scc || scc_sib1, "We need one serving cell config common\n"); - // no UEs if (nr_mac->UE_info.list[0] == NULL) return false; - const int CC_id = 0; - - /* Get the K2 for first UE to compute offset. The other UEs are guaranteed to - * have the same K2 (we don't support multiple/different K2s via different - * TDAs yet). If the TDA is negative, it means that there is no UL slot to - * schedule now (slot + k2 is not UL slot) */ - NR_UE_sched_ctrl_t *sched_ctrl = &nr_mac->UE_info.list[0]->UE_sched_ctrl; - NR_UE_UL_BWP_t *current_BWP = &nr_mac->UE_info.list[0]->current_UL_BWP; - int mu = current_BWP->scs; - const int temp_tda = get_ul_tda(nr_mac, scc, frame, slot); - NR_PUSCH_TimeDomainResourceAllocationList_t *tdaList = get_ul_tdalist(current_BWP, - sched_ctrl->coreset->controlResourceSetId, - sched_ctrl->search_space->searchSpaceType->present, - TYPE_C_RNTI_); - int K2 = get_K2(tdaList, temp_tda, mu, scc); - const int sched_frame = (frame + (slot + K2) / nr_slots_per_frame[mu]) % MAX_FRAME_NUMBER; - const int sched_slot = (slot + K2) % nr_slots_per_frame[mu]; - const int tda = get_ul_tda(nr_mac, scc, sched_frame, sched_slot); - if (tda < 0) - return false; - DevAssert(K2 == get_K2(tdaList, tda, mu, scc)); - + NR_COMMON_channels_t *cc = nr_mac->common_channels; + NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; + const NR_SIB1_t *sib1 = nr_mac->common_channels[0].sib1 ? nr_mac->common_channels[0].sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL; + NR_ServingCellConfigCommonSIB_t *scc_sib1 = sib1 ? sib1->servingCellConfigCommon : NULL; + AssertFatal(scc || scc_sib1, "We need one serving cell config common\n"); + const int slots_frame = nr_slots_per_frame[*scc->ssbSubcarrierSpacing]; + // TODO we assume the same K2 for all UEs + const int K2 = nr_mac->radio_config.minRXTXTIME + get_NTN_Koffset(scc); + const int sched_frame = (frame + (slot + K2) / slots_frame) % MAX_FRAME_NUMBER; + const int sched_slot = (slot + K2) % slots_frame; if (!is_xlsch_in_slot(nr_mac->ulsch_slot_bitmap[sched_slot / 64], sched_slot)) return false; - sched_ctrl->sched_pusch.slot = sched_slot; - sched_ctrl->sched_pusch.frame = sched_frame; - UE_iterator(nr_mac->UE_info.list, UE2) { - NR_UE_sched_ctrl_t *sched_ctrl = &UE2->UE_sched_ctrl; - AssertFatal(K2 == get_K2(tdaList, tda, mu, scc), - "Different K2, %d(UE%d) != %ld(UE%04x)\n", - K2, 0, get_K2(tdaList, tda, mu, scc), UE2->rnti); - sched_ctrl->sched_pusch.slot = sched_slot; - sched_ctrl->sched_pusch.frame = sched_frame; - } - - /* Change vrb_map_UL to rballoc_mask: check which symbols per RB (in - * vrb_map_UL) overlap with the "default" tda and exclude those RBs. - * Calculate largest contiguous RBs */ - const int index = ul_buffer_index(sched_frame, sched_slot, mu, nr_mac->vrb_map_UL_size); - // TODO improve handling of beam in vrb_map (for now just using 0) - uint16_t *vrb_map_UL = &nr_mac->common_channels[CC_id].vrb_map_UL[0][index * MAX_BWP_SIZE]; - - const uint16_t bwpSize = current_BWP->BWPSize; - const uint16_t bwpStart = current_BWP->BWPStart; - - const int startSymbolAndLength = tdaList->list.array[tda]->startSymbolAndLength; - int startSymbolIndex, nrOfSymbols; - SLIV2SL(startSymbolAndLength, &startSymbolIndex, &nrOfSymbols); - const uint16_t symb = SL_to_bitmap(startSymbolIndex, nrOfSymbols); - - int st = 0, e = 0, len = 0; - - for (int i = 0; i < bwpSize; i++) { - while ((vrb_map_UL[bwpStart + i] & symb) != 0 && i < bwpSize) - i++; - st = i; - while ((vrb_map_UL[bwpStart + i] & symb) == 0 && i < bwpSize) - i++; - if (i - st > len) { - len = i - st; - e = i - 1; - } - } - st = e - len + 1; - - LOG_D(NR_MAC,"UL %d.%d : start_prb %d, end PRB %d\n",frame,slot,st,e); - - uint16_t rballoc_mask[bwpSize]; - - /* Calculate mask: if any RB in vrb_map_UL is blocked (1), the current RB will be 0 */ - for (int i = st; i < e; i++) - rballoc_mask[i] = vrb_map_UL[bwpStart + i]; - int bw = scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth; + int average_agg_level = 4; // TODO find a better estimation int max_sched_ues = bw / (average_agg_level * NR_NB_REG_PER_CCE); @@ -2213,13 +2161,7 @@ static bool nr_fr1_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_ max_sched_ues = min(max_sched_ues, MAX_DCI_CORESET); /* proportional fair scheduling algorithm */ - pf_ul(module_id, - frame, - slot, - nr_mac->UE_info.list, - max_sched_ues, - len, - rballoc_mask); + pf_ul(module_id, frame, slot, sched_frame, sched_slot, nr_mac->UE_info.list, max_sched_ues, bw); return true; } From 62301e9eef0b439598b667d3bab6305bace83427 Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 15 Oct 2024 14:51:27 +0200 Subject: [PATCH 72/75] remove bf_weights from 2step RA config file --- .../CONF/gnb.sa.band78.106PRB.usrpb210.RA_2-Step.conf | 2 -- 1 file changed, 2 deletions(-) diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.106PRB.usrpb210.RA_2-Step.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.106PRB.usrpb210.RA_2-Step.conf index 45dbf2197f..d59dca9384 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.106PRB.usrpb210.RA_2-Step.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.106PRB.usrpb210.RA_2-Step.conf @@ -226,8 +226,6 @@ RUs = ( max_pdschReferenceSignalPower = -27; max_rxgain = 114; eNB_instances = [0]; - #beamforming 1x4 matrix: - bf_weights = [0x00007fff, 0x0000, 0x0000, 0x0000]; clock_src = "internal"; } ); From ad9b91627c5894a145b41a8f62de88bf9194862b Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Tue, 1 Oct 2024 12:46:52 +0100 Subject: [PATCH 73/75] Prevent DLSCH scheduler to allocate PRBs outside of current BWP --- .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 81 +++++++++++-------- 1 file changed, 47 insertions(+), 34 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 5faa5d3c13..57b2356f52 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -736,6 +736,53 @@ static void pf_dl(module_id_t module_id, NR_sched_pdsch_t *sched_pdsch = &sched_ctrl->sched_pdsch; sched_pdsch->dl_harq_pid = sched_ctrl->available_dl_harq.head; + /* MCS has been set above */ + sched_pdsch->time_domain_allocation = get_dl_tda(mac, scc, slot); + AssertFatal(sched_pdsch->time_domain_allocation>=0,"Unable to find PDSCH time domain allocation in list\n"); + + const int coresetid = sched_ctrl->coreset->controlResourceSetId; + sched_pdsch->tda_info = get_dl_tda_info(dl_bwp, + sched_ctrl->search_space->searchSpaceType->present, + sched_pdsch->time_domain_allocation, + scc->dmrs_TypeA_Position, + 1, + TYPE_C_RNTI_, + coresetid, + false); + AssertFatal(sched_pdsch->tda_info.valid_tda, "Invalid TDA from get_dl_tda_info\n"); + + NR_tda_info_t *tda_info = &sched_pdsch->tda_info; + + const uint16_t slbitmap = SL_to_bitmap(tda_info->startSymbolIndex, tda_info->nrOfSymbols); + + // TODO assuming beam 0 for now + uint16_t *rballoc_mask = mac->common_channels[CC_id].vrb_map[0]; + dl_bwp_info_t bwp_info = get_bwp_start_size(mac, iterator->UE); + int rbStart = 0; // WRT BWP start + int rbStop = bwp_info.bwpSize - 1; + int bwp_start = bwp_info.bwpStart; + // Freq-demain allocation + while (rbStart < rbStop && (rballoc_mask[rbStart + bwp_start] & slbitmap)) + rbStart++; + + uint16_t max_rbSize = 1; + + while (rbStart + max_rbSize <= rbStop && !(rballoc_mask[rbStart + max_rbSize + bwp_start] & slbitmap)) + max_rbSize++; + + if (max_rbSize < min_rbSize) { + LOG_D(NR_MAC, + "(%d.%d) Cannot schedule RNTI %04x, rbStart %d, rbSize %d, rbStop %d\n", + frame, + slot, + rnti, + rbStart, + max_rbSize, + rbStop); + iterator++; + continue; + } + // TODO properly set the beam index (currently only done for RA) int beam = 0; @@ -778,40 +825,6 @@ static void pf_dl(module_id_t module_id, sched_ctrl->cce_index = CCEIndex; fill_pdcch_vrb_map(mac, CC_id, &sched_ctrl->sched_pdcch, CCEIndex, sched_ctrl->aggregation_level, beam); - /* MCS has been set above */ - sched_pdsch->time_domain_allocation = get_dl_tda(mac, scc, slot); - AssertFatal(sched_pdsch->time_domain_allocation>=0,"Unable to find PDSCH time domain allocation in list\n"); - - const int coresetid = sched_ctrl->coreset->controlResourceSetId; - sched_pdsch->tda_info = get_dl_tda_info(dl_bwp, - sched_ctrl->search_space->searchSpaceType->present, - sched_pdsch->time_domain_allocation, - scc->dmrs_TypeA_Position, - 1, - TYPE_C_RNTI_, - coresetid, - false); - AssertFatal(sched_pdsch->tda_info.valid_tda, "Invalid TDA from get_dl_tda_info\n"); - - NR_tda_info_t *tda_info = &sched_pdsch->tda_info; - - const uint16_t slbitmap = SL_to_bitmap(tda_info->startSymbolIndex, tda_info->nrOfSymbols); - - // TODO assuming beam 0 for now - uint16_t *rballoc_mask = mac->common_channels[CC_id].vrb_map[0]; - dl_bwp_info_t bwp_info = get_bwp_start_size(mac, iterator->UE); - int rbStart = 0; // WRT BWP start - int rbStop = bwp_info.bwpSize - 1; - int bwp_start = bwp_info.bwpStart; - // Freq-demain allocation - while (rbStart < rbStop && (rballoc_mask[rbStart + bwp_start] & slbitmap)) - rbStart++; - - uint16_t max_rbSize = 1; - - while (rbStart + max_rbSize <= rbStop && !(rballoc_mask[rbStart + max_rbSize + bwp_start] & slbitmap)) - max_rbSize++; - sched_pdsch->dmrs_parms = get_dl_dmrs_params(scc, dl_bwp, tda_info, sched_pdsch->nrOfLayers); sched_pdsch->Qm = nr_get_Qm_dl(sched_pdsch->mcs, dl_bwp->mcsTableIdx); sched_pdsch->R = nr_get_code_rate_dl(sched_pdsch->mcs, dl_bwp->mcsTableIdx); From e086334a0850a77a29909d5f3f21fdd941c53caf Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Wed, 23 Oct 2024 12:31:09 +0200 Subject: [PATCH 74/75] Update yaml-cpp dependency handling - Added CPM fallback in case package is not found automatically. - Using yaml-cpp::yaml-cpp target instead of yaml-cpp to silence deprecation warnings on newer cmake versions. --- common/config/yaml/CMakeLists.txt | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/common/config/yaml/CMakeLists.txt b/common/config/yaml/CMakeLists.txt index 5ff8c23eb1..635887e37e 100644 --- a/common/config/yaml/CMakeLists.txt +++ b/common/config/yaml/CMakeLists.txt @@ -1,25 +1,18 @@ -find_package(yaml-cpp REQUIRED PATHS /usr/lib/aarch64-linux-gnu/pkgconfig/) -# include(FetchContent) - -# FetchContent_Declare( -# yaml-cpp -# GIT_REPOSITORY https://github.com/jbeder/yaml-cpp.git -# GIT_TAG 0.8.0 -# ) -# FetchContent_GetProperties(yaml-cpp) - -# if(NOT yaml-cpp_POPULATED) -# message(STATUS "Fetching yaml-cpp...") -# FetchContent_Populate(yaml-cpp) -# add_subdirectory(${yaml-cpp_SOURCE_DIR} ${yaml-cpp_BINARY_DIR}) -# endif() +find_package(yaml-cpp) +if (NOT yaml-cpp_FOUND) + CPMAddPackage("gh:jbeder/yaml-cpp#yaml-cpp-0.7.0@0.7.0") +else() + if (NOT TARGET yaml-cpp::yaml-cpp) + add_library(yaml-cpp::yaml-cpp ALIAS yaml-cpp) + endif() +endif() add_library(params_yaml_static config_yaml.cpp) -target_link_libraries(params_yaml_static PUBLIC UTIL yaml-cpp) +target_link_libraries(params_yaml_static PUBLIC UTIL yaml-cpp::yaml-cpp) if (ENABLE_TESTS) add_subdirectory(tests) endif() add_library(params_yaml MODULE config_yaml.cpp) -target_link_libraries(params_yaml PUBLIC UTIL yaml-cpp) +target_link_libraries(params_yaml PUBLIC UTIL yaml-cpp::yaml-cpp) set_target_properties(params_yaml PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) From d8d11d36c0e337f1f67a811250c948012a9bee88 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 28 Oct 2024 10:48:56 +0100 Subject: [PATCH 75/75] Mark CPM_SOURCE_CACHE as a CACHE variable By omitting the variable CPM_SOURCE_CACHE as CACHE'd, it is actually given to CPM, but does not appear when viewing it's content, e.g., through ccmake. Mark is as CACHE so that it will also appear. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index af48eca7b3..48fe9562c9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,7 +32,7 @@ set (OPENAIR_DIR ${CMAKE_SOURCE_DIR}) include("cmake_targets/macros.cmake") if(NOT DEFINED ENV{CPM_SOURCE_CACHE}) - set(CPM_SOURCE_CACHE ~/.cache/cpm/) + set(CPM_SOURCE_CACHE ~/.cache/cpm/ CACHE FILEPATH "Directory to download CPM dependencies") endif() include("cmake_targets/CPM.cmake")