diff --git a/CMakeLists.txt b/CMakeLists.txt index b607056aa4..16dac5f2fe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1147,7 +1147,6 @@ set(L2_NR_SRC ${NR_RRC_DIR}/rrc_gNB.c ${NR_RRC_DIR}/mac_rrc_dl_direct.c ${NR_RRC_DIR}/mac_rrc_dl_f1ap.c - ${NR_RRC_DIR}/nr_rrc_config.c ${NR_RRC_DIR}/rrc_gNB_nsa.c ${NR_RRC_DIR}/rrc_gNB_UE_context.c ${NR_RRC_DIR}/rrc_gNB_NGAP.c @@ -1230,6 +1229,7 @@ set (MAC_NR_SRC ${NR_GNB_MAC_DIR}/mac_rrc_dl_handler.c ${NR_GNB_MAC_DIR}/mac_rrc_ul_direct.c ${NR_GNB_MAC_DIR}/mac_rrc_ul_f1ap.c + ${NR_GNB_MAC_DIR}/nr_radio_config.c ) diff --git a/ci-scripts/conf_files/gnb.nsa.band78.106prb.usrpb200.conf b/ci-scripts/conf_files/gnb.nsa.band78.106prb.usrpb200.conf index 37eaa80b8c..bbe3168aa2 100644 --- a/ci-scripts/conf_files/gnb.nsa.band78.106prb.usrpb200.conf +++ b/ci-scripts/conf_files/gnb.nsa.band78.106prb.usrpb200.conf @@ -169,10 +169,10 @@ gNBs = NETWORK_INTERFACES : { - GNB_IPV4_ADDRESS_FOR_S1_MME = "192.168.68.194"; - GNB_IPV4_ADDRESS_FOR_S1U = "192.168.68.194"; + GNB_IPV4_ADDRESS_FOR_S1_MME = "172.21.16.109"; + GNB_IPV4_ADDRESS_FOR_S1U = "172.21.16.109"; GNB_PORT_FOR_S1U = 2152; # Spec 2152 - GNB_IPV4_ADDRESS_FOR_X2C = "192.168.68.194"; + GNB_IPV4_ADDRESS_FOR_X2C = "172.21.16.109"; GNB_PORT_FOR_X2C = 36422; # Spec 36422 }; diff --git a/ci-scripts/yaml_files/nsa_b200_gnb/docker-compose.yml b/ci-scripts/yaml_files/nsa_b200_gnb/docker-compose.yml index 3bd90a3fff..bb6576054e 100644 --- a/ci-scripts/yaml_files/nsa_b200_gnb/docker-compose.yml +++ b/ci-scripts/yaml_files/nsa_b200_gnb/docker-compose.yml @@ -9,6 +9,7 @@ services: - IPC_LOCK ulimits: core: -1 # for core dumps + network_mode: "host" environment: USE_B2XX: 'yes' USE_ADDITIONAL_OPTIONS: --nsa -E -q --RUs.[0].sdr_addrs serial=30C51D4 --continuous-tx --log_config.global_log_options level,nocolor,time,line_num,function @@ -16,9 +17,6 @@ services: - /dev/bus/usb/:/dev/bus/usb/ volumes: - ../../conf_files/gnb.nsa.band78.106prb.usrpb200.conf:/opt/oai-gnb/etc/gnb.conf - networks: - public_net: - ipv4_address: 192.168.68.194 #entrypoint: /bin/bash -c "sleep infinity" healthcheck: # pgrep does NOT work @@ -26,12 +24,3 @@ services: interval: 10s timeout: 5s retries: 5 - -networks: - public_net: - name: nsa-b200-gnb-net - ipam: - config: - - subnet: 192.168.68.192/26 - driver_opts: - com.docker.network.bridge.name: "nsa-gnb-net" diff --git a/common/5g_platform_types.h b/common/5g_platform_types.h index 6f055e9305..a5b7b7a1fc 100644 --- a/common/5g_platform_types.h +++ b/common/5g_platform_types.h @@ -35,6 +35,16 @@ typedef struct nssai_s { uint32_t sd; } nssai_t; +// Globally Unique AMF Identifier +typedef struct nr_guami_s { + uint16_t mcc; + uint16_t mnc; + uint8_t mnc_len; + uint8_t amf_region_id; + uint16_t amf_set_id; + uint8_t amf_pointer; +} nr_guami_t; + typedef enum { NON_DYNAMIC, DYNAMIC } fiveQI_t; #endif diff --git a/common/utils/T/tracer/event.c b/common/utils/T/tracer/event.c index 61fb12dd2a..b7459ddcb8 100644 --- a/common/utils/T/tracer/event.c +++ b/common/utils/T/tracer/event.c @@ -24,9 +24,11 @@ event get_event(int socket, OBUF *event_buffer, void *database) again: if (fullread(socket, &length, 4) == -1) goto read_error; #ifdef T_SEND_TIME + if (length < sizeof(struct timespec)) goto error; if (fullread(socket, &t, sizeof(struct timespec)) == -1) goto read_error; length -= sizeof(struct timespec); #endif + if (length < sizeof(int)) goto error; if (fullread(socket, &type, sizeof(int)) == -1) goto read_error; length -= sizeof(int); if (event_buffer->omaxsize < length) { @@ -48,6 +50,9 @@ again: return new_event(type, length, event_buffer->obuf, database); #endif +error: + printf("error: bad data in get_event()\n"); + read_error: return (event){.type = -1}; } @@ -64,6 +69,9 @@ event new_event(int type, int length, char *buffer, void *database) int i; int offset; + /* arbitrary limit to 1GiB (to simplify size checks) */ + if (length < 0 || length > 1024 * 1024 * 1024) goto fatal; + #ifdef T_SEND_TIME e.sending_time = sending_time; #endif @@ -87,26 +95,33 @@ event new_event(int type, int length, char *buffer, void *database) for (i = 0; i < f.count; i++) { //e.e[i].offset = offset; if (!strcmp(f.type[i], "int")) { + if (offset + 4 > length) goto fatal; e.e[i].type = EVENT_INT; e.e[i].i = *(int *)(&buffer[offset]); offset += 4; } else if (!strcmp(f.type[i], "ulong")) { + if (offset + sizeof(unsigned long) > length) goto fatal; e.e[i].type = EVENT_ULONG; e.e[i].ul = *(unsigned long *)(&buffer[offset]); offset += sizeof(unsigned long); } else if (!strcmp(f.type[i], "float")) { + if (offset + sizeof(float) > length) goto fatal; e.e[i].type = EVENT_FLOAT; e.e[i].f = *(float *)(&buffer[offset]); offset += sizeof(float); } else if (!strcmp(f.type[i], "string")) { + if (offset + 1 > length) goto fatal; e.e[i].type = EVENT_STRING; e.e[i].s = &buffer[offset]; - while (buffer[offset]) offset++; + while (offset < length && buffer[offset]) offset++; + if (offset == length) goto fatal; offset++; } else if (!strcmp(f.type[i], "buffer")) { + if (offset + sizeof(int) > length) goto fatal; int len; e.e[i].type = EVENT_BUFFER; len = *(int *)(&buffer[offset]); + if (len <= 0 || offset + len + sizeof(int) > length) goto fatal; e.e[i].bsize = len; e.e[i].b = &buffer[offset+sizeof(int)]; offset += len+sizeof(int); @@ -119,4 +134,8 @@ event new_event(int type, int length, char *buffer, void *database) if (e.ecount==0) { printf("FORMAT not set in event %d\n", type); abort(); } return e; + +fatal: + printf("fatal: bad buffer in new_event\n"); + abort(); } diff --git a/common/utils/T/tracer/extract_config.c b/common/utils/T/tracer/extract_config.c index b908e60a83..73640cd3c1 100644 --- a/common/utils/T/tracer/extract_config.c +++ b/common/utils/T/tracer/extract_config.c @@ -46,8 +46,8 @@ int main(int n, char **v) /* read event from file */ if (fread(&length, 4, 1, in) != 1) break; - if (ebuf.omaxsize < length) { - ebuf.omaxsize = (length + 65535) & ~65535; + if (ebuf.omaxsize < length + 4) { + ebuf.omaxsize = (length + 4 + 65535) & ~65535; ebuf.obuf = realloc(ebuf.obuf, ebuf.omaxsize); if (ebuf.obuf == NULL) { printf("out of memory\n"); exit(1); } } diff --git a/common/utils/T/tracer/hacks/multi-rru-clean.c b/common/utils/T/tracer/hacks/multi-rru-clean.c index ec7c8f9d1b..1887c9bb2b 100644 --- a/common/utils/T/tracer/hacks/multi-rru-clean.c +++ b/common/utils/T/tracer/hacks/multi-rru-clean.c @@ -157,8 +157,8 @@ int main(int n, char **v) /* read event from file */ if (fread(&length, 4, 1, in) != 1) break; - if (ebuf.omaxsize < length) { - ebuf.omaxsize = (length + 65535) & ~65535; + if (ebuf.omaxsize < length + 4) { + ebuf.omaxsize = (length + 4 + 65535) & ~65535; ebuf.obuf = realloc(ebuf.obuf, ebuf.omaxsize); if (ebuf.obuf == NULL) { printf("out of memory\n"); exit(1); } } diff --git a/common/utils/T/tracer/multi.c b/common/utils/T/tracer/multi.c index 0b2e48ec7a..8e49ff43a1 100644 --- a/common/utils/T/tracer/multi.c +++ b/common/utils/T/tracer/multi.c @@ -114,8 +114,8 @@ int read_tracee(int s, OBUF *ebuf, int *_type, int32_t *_length) int vpos = 0; if (fullread(s, &length, 4) == -1) return -1; - if (ebuf->omaxsize < length) { - ebuf->omaxsize = (length + 65535) & ~65535; + if (ebuf->omaxsize < length + 4) { + ebuf->omaxsize = (length + 4 + 65535) & ~65535; ebuf->obuf = realloc(ebuf->obuf, ebuf->omaxsize); if (ebuf->obuf == NULL) { printf("out of memory\n"); exit(1); } } @@ -123,10 +123,12 @@ int read_tracee(int s, OBUF *ebuf, int *_type, int32_t *_length) memcpy(v+vpos, &length, 4); vpos += 4; #ifdef T_SEND_TIME + if (length < sizeof(struct timespec)) return -1; if (fullread(s,v+vpos,sizeof(struct timespec))==-1) return -1; vpos += sizeof(struct timespec); length -= sizeof(struct timespec); #endif + if (length < sizeof(int)) return -1; if (fullread(s, &type, sizeof(int)) == -1) return -1; memcpy(v+vpos, &type, sizeof(int)); vpos += sizeof(int); diff --git a/common/utils/T/tracer/record.c b/common/utils/T/tracer/record.c index 9e3c4c41a3..f9d9dece64 100644 --- a/common/utils/T/tracer/record.c +++ b/common/utils/T/tracer/record.c @@ -133,8 +133,8 @@ int main(int n, char **v) int vpos = 0; if (fullread(socket, &length, 4) == -1) goto read_error; - if (ebuf.omaxsize < length) { - ebuf.omaxsize = (length + 65535) & ~65535; + if (ebuf.omaxsize < length + 4) { + ebuf.omaxsize = (length + 4 + 65535) & ~65535; ebuf.obuf = realloc(ebuf.obuf, ebuf.omaxsize); if (ebuf.obuf == NULL) { printf("out of memory\n"); exit(1); } } @@ -142,10 +142,12 @@ int main(int n, char **v) memcpy(v+vpos, &length, 4); vpos += 4; #ifdef T_SEND_TIME + if (length < sizeof(struct timespec)) goto read_error; if (fullread(socket,v+vpos,sizeof(struct timespec))==-1) goto read_error; vpos += sizeof(struct timespec); length -= sizeof(struct timespec); #endif + if (length < sizeof(int)) goto read_error; if (fullread(socket, &type, sizeof(int)) == -1) goto read_error; memcpy(v+vpos, &type, sizeof(int)); vpos += sizeof(int); diff --git a/common/utils/T/tracer/replay.c b/common/utils/T/tracer/replay.c index d9a505520a..10aec1588e 100644 --- a/common/utils/T/tracer/replay.c +++ b/common/utils/T/tracer/replay.c @@ -146,8 +146,8 @@ int main(int n, char **v) /* read event from file */ if (fread(&length, 4, 1, in) != 1) break; - if (ebuf.omaxsize < length) { - ebuf.omaxsize = (length + 65535) & ~65535; + if (ebuf.omaxsize < length + 4) { + ebuf.omaxsize = (length + 4 + 65535) & ~65535; ebuf.obuf = realloc(ebuf.obuf, ebuf.omaxsize); if (ebuf.obuf == NULL) { printf("out of memory\n"); exit(1); } } diff --git a/common/utils/ds/byte_array.c b/common/utils/ds/byte_array.c index d6ad97e324..99375bf2aa 100644 --- a/common/utils/ds/byte_array.c +++ b/common/utils/ds/byte_array.c @@ -23,15 +23,21 @@ #include #include +#include "common/utils/utils.h" // for malloc_or_fail + +byte_array_t create_byte_array(const size_t len, const uint8_t* buffer) +{ + byte_array_t result = {.len = len}; + if (len) { + result.buf = malloc_or_fail(len); + memcpy(result.buf, buffer, len); + } + return result; +} byte_array_t copy_byte_array(byte_array_t src) { - byte_array_t dst = {0}; - dst.buf = malloc(src.len); - assert(dst.buf != NULL && "Memory exhausted"); - memcpy(dst.buf, src.buf, src.len); - dst.len = src.len; - return dst; + return create_byte_array(src.len, src.buf); } void free_byte_array(byte_array_t ba) diff --git a/common/utils/ds/byte_array.h b/common/utils/ds/byte_array.h index 18adb33047..e303d38e75 100644 --- a/common/utils/ds/byte_array.h +++ b/common/utils/ds/byte_array.h @@ -28,6 +28,13 @@ #include #include +#define FREE_AND_ZERO_BYTE_ARRAY(BA) \ + do { \ + free_byte_array(BA); \ + BA.buf = NULL; \ + BA.len = 0; \ + } while (0) + typedef struct { size_t len; uint8_t* buf; @@ -43,5 +50,6 @@ bool eq_byte_array(const byte_array_t* m0, const byte_array_t* m1); byte_array_t cp_str_to_ba(const char* str); char* cp_ba_to_str(const byte_array_t ba); +byte_array_t create_byte_array(const size_t len, const uint8_t* buffer); #endif diff --git a/common/utils/nr/nr_common.c b/common/utils/nr/nr_common.c index 078ef027e8..5d98a99bb4 100644 --- a/common/utils/nr/nr_common.c +++ b/common/utils/nr/nr_common.c @@ -207,7 +207,7 @@ int get_smallest_supported_bandwidth_index(int scs, frequency_range_t frequency_ return -1; // not found } -// Table 5.2-1 NR operating bands in FR1 & FR2 (3GPP TS 38.101) +// Table 5.2-1 NR operating bands in FR1 & FR2 (3GPP TS 38.101) (Rel.17) // Table 5.4.2.3-1 Applicable NR-ARFCN per operating band in FR1 & FR2 (3GPP TS 38.101) // Notes: // - N_OFFs for bands from 80 to 89 and band 95 is referred to UL @@ -236,6 +236,7 @@ const nr_bandentry_t nr_bandtable[] = {{1, 1920000, 1980000, 2110000, 2170000, 2 {40, 2300000, 2400000, 2300000, 2400000, 20, 460000, 100}, {41, 2496000, 2690000, 2496000, 2690000, 3, 499200, 15}, {41, 2496000, 2690000, 2496000, 2690000, 6, 499200, 30}, + {46, 5150000, 5925000, 5150000, 5925000, 1, 743334, 15}, {47, 5855000, 5925000, 5855000, 5925000, 1, 790334, 15}, {48, 3550000, 3700000, 3550000, 3700000, 1, 636667, 15}, {48, 3550000, 3700000, 3550000, 3700000, 2, 636668, 30}, @@ -273,6 +274,11 @@ const nr_bandentry_t nr_bandtable[] = {{1, 1920000, 1980000, 2110000, 2170000, 2 {94, 880000, 915000, 1432000, 1517000, 20, 286400, 100}, {95, 2010000, 2025000, 000, 000, 20, 402000, 100}, {96, 5925000, 7125000, 5925000, 7125000, 1, 795000, 15}, + {100, 874400, 880000, 919400, 925000, 20, 174880, 100}, + {101, 1900000, 1910000, 1900000, 1910000, 20, 380000, 100}, + {102, 5925000, 6425000, 5925000, 6425000, 1, 795000, 15}, + {104, 6425000, 7125000, 6425000, 7125000, 1, 828334, 15}, + {104, 6425000, 7125000, 6425000, 7125000, 2, 828334, 30}, {254, 1610000, 1626500, 2483500, 2500000, 20, 496700, 100}, {254, 1610000, 1626500, 2483500, 2500000, 2, 496700, 10}, {255, 1626500, 1660500, 1525000, 1559000, 20, 305000, 100}, @@ -288,7 +294,7 @@ const nr_bandentry_t nr_bandtable[] = {{1, 1920000, 1980000, 2110000, 2170000, 2 {261, 27500040, 28350000, 27500040, 28350000, 1, 2070833, 60}, {261, 27500040, 28350000, 27500040, 28350000, 2, 2070833, 120}}; -// synchronization raster per band tables (Rel.15) +// synchronization raster per band tables (Rel.17) // (38.101-1 Table 5.4.3.3-1 and 38.101-2 Table 5.4.3.3-1) // band nb, sub-carrier spacing index, Range of gscn (First, Step size, Last) // clang-format off @@ -321,8 +327,9 @@ const sync_raster_t sync_raster[] = { {40, 1, 5762, 1, 5989}, {41, 0, 6246, 3, 6717}, {41, 1, 6252, 3, 6714}, + {46, 1, 8993, 1, 9530}, {48, 1, 7884, 1, 7982}, - {50, 0, 3584, 1, 3787}, + {50, 1, 3590, 1, 3781}, {51, 0, 3572, 1, 3574}, {53, 0, 6215, 1, 6232}, {53, 1, 6221, 1, 6226}, @@ -343,7 +350,13 @@ const sync_raster_t sync_raster[] = { {91, 0, 3572, 1, 3574}, {92, 0, 3584, 1, 3787}, {93, 0, 3572, 1, 3574}, - {94, 0, 3584, 1, 3587}, + {94, 0, 3584, 1, 3787}, + {96, 1, 9531, 1, 10363}, + {100, 0, 2303, 1, 2307}, + {101, 0, 4754, 1, 4768}, + {101, 1, 4760, 1, 4764}, + {102, 1, 9531, 1, 9877}, + {104, 1, 9882, 7, 10358}, {254, 0, 6215, 1, 6244}, {254, 1, 6218, 1, 6241}, {255, 0, 3818, 1, 3892}, diff --git a/common/utils/telnetsrv/telnetsrv_o1.c b/common/utils/telnetsrv/telnetsrv_o1.c index 7136f5a1b7..ac368885f6 100644 --- a/common/utils/telnetsrv/telnetsrv_o1.c +++ b/common/utils/telnetsrv/telnetsrv_o1.c @@ -34,7 +34,7 @@ #include "openair2/RRC/NR/nr_rrc_defs.h" #include "openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h" -#include "openair2/RRC/NR/nr_rrc_config.h" +#include "openair2/LAYER2/NR_MAC_gNB/nr_radio_config.h" #include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h" #include "openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c" #include "common/utils/nr/nr_common.h" diff --git a/doc/Doxyfile b/doc/Doxyfile index 6b0b390f05..f128e3eb88 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -1677,6 +1677,7 @@ INPUT = \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h \ +@CMAKE_CURRENT_SOURCE_DIR@/../openair2/LAYER2/NR_MAC_gNB/nr_radio_config.h \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.h \ @@ -1687,6 +1688,7 @@ INPUT = \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c \ +@CMAKE_CURRENT_SOURCE_DIR@/../openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/LAYER2/openair2_proc.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/LAYER2/RLC/rlc.h \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/LAYER2/NR_MAC_UE/mac_tables.c \ @@ -1847,7 +1849,6 @@ INPUT = \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/nr_rrc_defs.h \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/cucp_cuup_if.h \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/cucp_cuup_direct.c \ -@CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/nr_rrc_config.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/mac_rrc_dl_direct.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/rrc_gNB_radio_bearers.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/rrc_gNB_NGAP.h \ @@ -1858,7 +1859,6 @@ INPUT = \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/rrc_gNB_UE_context.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/cucp_cuup_e1ap.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/rrc_gNB.c \ -@CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/nr_rrc_config.h \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/rrc_gNB_radio_bearers.h \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/rrc_gNB_NGAP.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/mac_rrc_dl_f1ap.c \ diff --git a/executables/nr-ue.c b/executables/nr-ue.c index 1939c4175b..d0a8f27a0f 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -43,6 +43,7 @@ #include "position_interface.h" #include "nr_phy_common.h" #include "common/utils/time_manager/time_manager.h" +#include "log.h" /* * NR SLOT PROCESSING SEQUENCE @@ -545,6 +546,28 @@ static void RU_write(nr_rxtx_thread_data_t *rxtxD, bool sl_tx_action, c16_t **tx } } + if (!IS_SOFTMODEM_RFSIM) { + uint64_t deadline_us = rxtxD->absolute_deadline_us; + struct timespec current_time; + if (clock_gettime(CLOCK_REALTIME, ¤t_time)) { + LOG_E(PHY, "clock_gettime failed\n"); + } + uint64_t current_time_us = current_time.tv_sec * 1e6 + current_time.tv_nsec / 1e3; + if (current_time_us > deadline_us) { + static unsigned int deadline_warning_rate_limit = 0; + if (deadline_warning_rate_limit % 1000 == 0) { + LOG_W(PHY, + "Deadline missed for tx slot %d.%d (current time %lu us, deadline %lu us, missed by %lu)\n", + proc->frame_tx, + proc->nr_slot_tx, + current_time_us, + deadline_us, + current_time_us - deadline_us); + } + deadline_warning_rate_limit++; + } + } + openair0_timestamp writeTimestamp = proc->timestamp_tx; int writeBlockSize = rxtxD->writeBlockSize; // if writeBlockSize gets longer that slot size, fill with dummy @@ -728,7 +751,8 @@ static int UE_dl_preprocessing(PHY_VARS_NR_UE *UE, } sampleShift = pbch_pdcch_processing(UE, proc, phy_data); - if (phy_data->dlsch[0].active && phy_data->dlsch[0].rnti_type == TYPE_C_RNTI_) { + if (phy_data->dlsch[0].active + && (phy_data->dlsch[0].rnti_type == TYPE_C_RNTI_ || phy_data->dlsch[0].rnti_type == TYPE_RA_RNTI_)) { // indicate to tx thread to wait for DLSCH decoding if (phy_data->dlsch[0].dlsch_config.k1_feedback) { // if feedback is 0 there is no HARQ associated with this DLSCH const int ack_nack_slot = (proc->nr_slot_rx + phy_data->dlsch[0].dlsch_config.k1_feedback) % fp->slots_per_frame; @@ -1138,8 +1162,13 @@ void *UE_thread(void *arg) const int readBlockSize = get_readBlockSize(slot_nr, fp) - iq_shift_to_apply; openair0_timestamp rx_timestamp; int tmp = UE->rfdevice.trx_read_func(&UE->rfdevice, &rx_timestamp, rxp, readBlockSize, fp->nb_antennas_rx); - UEscopeCopy(UE, ueTimeDomainSamples, rxp[0], sizeof(c16_t), 1, readBlockSize, 0); + metadata meta = {.slot = curMsg.proc.nr_slot_rx, .frame = curMsg.proc.frame_rx}; + UEscopeCopyWithMetadata(UE, ueTimeDomainSamples, rxp[0] - firstSymSamp * sizeof(c16_t), sizeof(c16_t), 1, readBlockSize, 0, &meta); AssertFatal(readBlockSize == tmp, ""); + struct timespec current_time; + if (clock_gettime(CLOCK_REALTIME, ¤t_time)) { + LOG_E(PHY, "clock_gettime failed\n"); + } if(slot_nr == (nb_slot_frame - 1)) { // read in first symbol of next frame and adjust for timing drift @@ -1162,6 +1191,11 @@ void *UE_thread(void *arg) const openair0_timestamp writeTimestamp = rx_timestamp + fp->get_samples_slot_timestamp(slot_nr, fp, duration_rx_to_tx) - firstSymSamp - UE->N_TA_offset - timing_advance; + // Calculate TX deadline, approximately 1 symbol before the first sample should be written + const uint64_t samples_diff = writeTimestamp - rx_timestamp - fp->ofdm_symbol_size; + const float deadline_us = samples_diff / UE->rfdevice.openair0_cfg->sample_rate * 1e6; + const uint64_t absolute_deadline_us = current_time.tv_sec * 1e6 + current_time.tv_nsec / 1e3 + deadline_us; + // but use current UE->timing_advance value to compute writeBlockSize int writeBlockSize = fp->get_samples_per_slot((slot_nr + duration_rx_to_tx) % nb_slot_frame, fp) - iq_shift_to_apply; int new_timing_advance = UE->timing_advance; @@ -1204,6 +1238,7 @@ void *UE_thread(void *arg) curMsgTx->writeBlockSize = writeBlockSize; curMsgTx->proc.timestamp_tx = writeTimestamp; curMsgTx->UE = UE; + curMsgTx->absolute_deadline_us = absolute_deadline_us; int slot = curMsgTx->proc.nr_slot_tx; int slot_and_frame = slot + curMsgTx->proc.frame_tx * UE->frame_parms.slots_per_frame; diff --git a/executables/nr-uesoftmodem.c b/executables/nr-uesoftmodem.c index 3106f823b3..f1e94e9e55 100644 --- a/executables/nr-uesoftmodem.c +++ b/executables/nr-uesoftmodem.c @@ -368,9 +368,6 @@ void start_oai_nrue_threads() int NB_UE_INST = 1; configmodule_interface_t *uniqCfg = NULL; - -// A global var to reduce the changes size -ldpc_interface_t ldpc_interface = {0}, ldpc_interface_offload = {0}; nrLDPC_coding_interface_t nrLDPC_coding_interface = {0}; int main(int argc, char **argv) diff --git a/openair1/PHY/CODING/nrLDPC_extern.h b/openair1/PHY/CODING/nrLDPC_extern.h index a0e10db155..7c4287d3f1 100644 --- a/openair1/PHY/CODING/nrLDPC_extern.h +++ b/openair1/PHY/CODING/nrLDPC_extern.h @@ -31,15 +31,10 @@ typedef struct ldpc_interface_s { LDPC_encoderfunc_t *LDPCencoder; } ldpc_interface_t; -// Global var to limit the rework of the dirty legacy code -extern ldpc_interface_t ldpc_interface, ldpc_interface_offload, ldpc_interface_segment; - /* functions to load the LDPC shared lib, implemented in openair1/PHY/CODING/nrLDPC_load.c */ int load_LDPClib(char *version, ldpc_interface_t *); int free_LDPClib(ldpc_interface_t *ldpc_interface); -LDPC_initfunc_t LDPCinit; -LDPC_shutdownfunc_t LDPCshutdown; LDPC_decoderfunc_t LDPCdecoder; LDPC_encoderfunc_t LDPCencoder; diff --git a/openair1/PHY/INIT/nr_parms.c b/openair1/PHY/INIT/nr_parms.c index aa1eba0822..2ace21eab5 100644 --- a/openair1/PHY/INIT/nr_parms.c +++ b/openair1/PHY/INIT/nr_parms.c @@ -85,6 +85,11 @@ static const int nr_ssb_table[][3] = { {93, 15, nr_ssb_type_A}, {94, 15, nr_ssb_type_A}, {96, 30, nr_ssb_type_C}, + {100, 15, nr_ssb_type_A}, + {101, 15, nr_ssb_type_A}, + {101, 30, nr_ssb_type_C}, + {102, 30, nr_ssb_type_C}, + {104, 30, nr_ssb_type_C}, {254, 15, nr_ssb_type_A}, {254, 30, nr_ssb_type_C}, {255, 15, nr_ssb_type_A}, diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c index a690c85ee3..d266d443e9 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c @@ -323,7 +323,8 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, c16_t ptrs_phase_per_slot[][NR_SYMBOLS_PER_SLOT], int32_t ptrs_re_per_slot[][NR_SYMBOLS_PER_SLOT], int G, - uint32_t nvar) + uint32_t nvar, + pdsch_scope_req_t *scope_req) { const int nl = dlsch[0].Nl; const int matrixSz = ue->frame_parms.nb_antennas_rx * nl; @@ -463,6 +464,12 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, csi_res_bitmap, ue->chest_time); stop_meas_nr_ue_phy(ue, DLSCH_EXTRACT_RBS_STATS); + if (scope_req->copy_chanest_to_scope) { + size_t size = sizeof(c16_t) * dlsch_config->number_rbs * NR_NB_SC_PER_RB; + int copy_index = symbol - dlsch_config->start_symbol; + int offset = copy_index * size; + UEscopeCopyUnsafe(ue, pdschChanEstimates, dl_ch_estimates_ext[0], size, offset, copy_index); + } if (meas_enabled) { LOG_D(PHY, "[AbsSFN %u.%d] Slot%d Symbol %d: Pilot/Data extraction %5.2f \n", @@ -481,6 +488,12 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, nb_re_pdsch = (pilots == 1) ? ((config_type == NFAPI_NR_DMRS_TYPE1) ? nb_rb_pdsch * (12 - 6 * dlsch_config->n_dmrs_cdm_groups) : nb_rb_pdsch * (12 - 4 * dlsch_config->n_dmrs_cdm_groups)) : (nb_rb_pdsch * 12); + if (scope_req->copy_rxdataF_to_scope) { + size_t size = sizeof(c16_t) * nb_re_pdsch; + int copy_index = symbol - dlsch_config->start_symbol; + UEscopeCopyUnsafe(ue, pdschRxdataF, rxdataF_ext[0], size, scope_req->scope_rxdataF_offset, copy_index); + scope_req->scope_rxdataF_offset += size; + } //---------------------------------------------------------- //--------------------- Channel Scaling -------------------- //---------------------------------------------------------- diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h index 9c6e0c1454..8e266a57a3 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h @@ -41,6 +41,13 @@ #define NR_PUSCH_x 2 // UCI placeholder bit TS 38.212 V15.4.0 subclause 5.3.3.1 #define NR_PUSCH_y 3 // UCI placeholder bit +// Specifies the data that should be copied to the scope during PDSCH RX +typedef struct pdsch_scope_req_s { + bool copy_chanest_to_scope; + bool copy_rxdataF_to_scope; + size_t scope_rxdataF_offset; +} pdsch_scope_req_t; + // Functions below implement 36-211 and 36-212 /** @addtogroup _PHY_TRANSPORT_ @@ -314,7 +321,8 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, c16_t ptrs_phase_per_slot[][NR_SYMBOLS_PER_SLOT], int32_t ptrs_re_per_slot[][NR_SYMBOLS_PER_SLOT], int G, - uint32_t nvar); + uint32_t nvar, + pdsch_scope_req_t *scope_req); int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t slot, c16_t **txData); diff --git a/openair1/PHY/TOOLS/imscope/imscope.cpp b/openair1/PHY/TOOLS/imscope/imscope.cpp index 48010e5883..cce7a595f7 100644 --- a/openair1/PHY/TOOLS/imscope/imscope.cpp +++ b/openair1/PHY/TOOLS/imscope/imscope.cpp @@ -248,6 +248,29 @@ class IQHist { if (!ss.str().empty()) { ImGui::Text("Data for %s", ss.str().c_str()); } + if (ImGui::Button("Save IQ")) { + std::stringstream ss; + ss << "iq_"; + if (iq_data->meta.frame != -1) { + ss << iq_data->meta.frame << "_"; + } + if (iq_data->meta.slot != -1) { + ss << iq_data->meta.slot << "_"; + } + ss << scope_id_to_string(static_cast(iq_data->scope_id)); + ss << ".csv"; + std::ofstream file(ss.str()); + if (file.is_open()) { + file << "real;imag\n"; + for (int i = 0; i < iq_data->len; i++) { + file << iq_data->real[i] << ";" << iq_data->imag[i] << "\n"; + } + file.close(); + std::cout << "Saved IQ to file: " << ss.str() << std::endl; + } else { + std::cerr << "Unable to open file"; + } + } ImGui::EndGroup(); } }; @@ -432,6 +455,29 @@ void ShowUeScope(void *data_void_ptr, float t) } ImGui::End(); + if (ImGui::Begin("UE PDSCH Chan est")) { + static auto iq_data = new IQData(); + static auto iq_hist = new IQHist("PDSCH Chan est IQ"); + bool new_data = false; + if (iq_hist->ShouldReadData()) { + new_data = iq_data->TryCollect(&scope_array[pdschChanEstimates], t, iq_hist->GetEpsilon(), iq_procedure_timer); + } + iq_hist->Draw(iq_data, t, new_data); + } + ImGui::End(); + + if (ImGui::Begin("UE PDSCH IQ before compensation")) { + static auto iq_data = new IQData(); + static auto iq_hist = new IQHist("PDSCH IQ before compensation"); + bool new_data = false; + if (iq_hist->ShouldReadData()) { + new_data = iq_data->TryCollect(&scope_array[pdschRxdataF], t, iq_hist->GetEpsilon(), iq_procedure_timer); + } + iq_hist->Draw(iq_data, t, new_data); + } + ImGui::End(); + + if (ImGui::Begin("Time domain samples")) { static auto iq_data = new IQData(); // Issue with imgui deferring draw calls until the end of the frame - cases segfault if scatterplot has too many points diff --git a/openair1/PHY/TOOLS/imscope/imscope_common.cpp b/openair1/PHY/TOOLS/imscope/imscope_common.cpp index b1bdda0905..a480abbf5e 100644 --- a/openair1/PHY/TOOLS/imscope/imscope_common.cpp +++ b/openair1/PHY/TOOLS/imscope/imscope_common.cpp @@ -131,12 +131,9 @@ void unlockScopeData(enum scopeDataType type) total_size += scope_data.data.data_copied_per_offset[i]; } if (total_size != (uint64_t)scope_data.data.scope_graph_data->dataSize) { - LOG_E(PHY, - "Scope is missing data - not all data that was expected was copied - possibly missed copyDataUnsafeWithOffset call. " - "scope = %s, total_size = %lu, dataSize = %d\n", - scope_id_to_string(type), - total_size, - scope_data.data.scope_graph_data->dataSize); + scope_data.data.scope_graph_data->dataSize = total_size; + scope_data.data.scope_graph_data->lineSz = + total_size / scope_data.data.scope_graph_data->elementSz / scope_data.data.scope_graph_data->colSz; } scope_data.data.scope_id = type; scope_data.is_data_ready = true; @@ -179,8 +176,12 @@ const char *scope_id_to_string(scopeDataType type) { return "ueTimeDomainSamplesBeforeSync"; case gNbTimeDomainSamples: return "gNbTimeDomainSamples"; + case pdschChanEstimates: + return "pdschChanEstimates"; + case pdschRxdataF: + return "pdschRxdataF"; default: - return "unknown type"; + return "unknown scope type"; } } diff --git a/openair1/PHY/TOOLS/imscope/imscope_record.cpp b/openair1/PHY/TOOLS/imscope/imscope_record.cpp index 6855e1b69d..a11b609054 100644 --- a/openair1/PHY/TOOLS/imscope/imscope_record.cpp +++ b/openair1/PHY/TOOLS/imscope/imscope_record.cpp @@ -35,7 +35,7 @@ constexpr std::size_t hardware_destructive_interference_size = 64; #endif -#define NUM_CACHED_DATA 4 +#define NUM_CACHED_DATA 8 // Set maximum number of kilobytes written per recording session to 1GB. This is a safeguard against // recoding thread writing too many files and exhausting disk space. #define MAX_KBYTES_WRITTEN_PER_SESSION (1000 * 1000) diff --git a/openair1/PHY/TOOLS/phy_scope_interface.h b/openair1/PHY/TOOLS/phy_scope_interface.h index 181bf5985b..731a6250e5 100644 --- a/openair1/PHY/TOOLS/phy_scope_interface.h +++ b/openair1/PHY/TOOLS/phy_scope_interface.h @@ -77,6 +77,8 @@ enum scopeDataType { ueTimeDomainSamples, ueTimeDomainSamplesBeforeSync, gNbTimeDomainSamples, + pdschChanEstimates, + pdschRxdataF, EXTRA_SCOPE_TYPES }; diff --git a/openair1/PHY/defs_nr_UE.h b/openair1/PHY/defs_nr_UE.h index db8524eddd..9d8683481d 100644 --- a/openair1/PHY/defs_nr_UE.h +++ b/openair1/PHY/defs_nr_UE.h @@ -598,6 +598,7 @@ typedef struct nr_rxtx_thread_data_s { int writeBlockSize; nr_phy_data_t phy_data; dynamic_barrier_t* next_barrier; + uint64_t absolute_deadline_us; } nr_rxtx_thread_data_t; typedef struct LDPCDecode_ue_s { diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index 8484a13101..791f3e4631 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -606,6 +606,24 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue, int32_t log2_maxh = 0; start_meas_nr_ue_phy(ue, RX_PDSCH_STATS); + pdsch_scope_req_t scope_req = { .copy_chanest_to_scope = false, + .copy_rxdataF_to_scope = false, + .scope_rxdataF_offset = 0 }; + if (UEScopeHasTryLock(ue)) { + metadata mt = {.frame = proc->frame_rx, .slot = proc->nr_slot_rx}; + scope_req.copy_chanest_to_scope = UETryLockScopeData(ue, + pdschChanEstimates, + sizeof(c16_t), + 1, + dlschCfg->number_rbs * NR_NB_SC_PER_RB * dlschCfg->number_symbols, + &mt); + scope_req.copy_rxdataF_to_scope = UETryLockScopeData(ue, + pdschRxdataF, + sizeof(c16_t), + 1, + dlschCfg->number_rbs * NR_NB_SC_PER_RB * dlschCfg->number_symbols, + &mt); + } for (int m = dlschCfg->start_symbol; m < (dlschCfg->number_symbols + dlschCfg->start_symbol); m++) { bool first_symbol_flag = false; if (m == first_symbol_with_data) @@ -632,11 +650,25 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue, ptrs_phase_per_slot, ptrs_re_per_slot, G, - nvar) - < 0) + nvar, + &scope_req) + < 0) { + if (scope_req.copy_chanest_to_scope) { + UEunlockScopeData(ue, pdschChanEstimates); + } + if (scope_req.copy_rxdataF_to_scope) { + UEunlockScopeData(ue, pdschRxdataF); + } return -1; + } } // CRNTI active stop_meas_nr_ue_phy(ue, RX_PDSCH_STATS); + if (scope_req.copy_chanest_to_scope) { + UEunlockScopeData(ue, pdschChanEstimates); + } + if (scope_req.copy_rxdataF_to_scope) { + UEunlockScopeData(ue, pdschRxdataF); + } free(toFree); free(toFree2); } @@ -815,7 +847,7 @@ static void nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue, } // DLSCH decoding finished! don't wait anymore in Tx process, we know if we should answer ACK/NACK PUCCH - if (dlsch[0].rnti_type == TYPE_C_RNTI_ && dlsch[0].dlsch_config.k1_feedback) { + if ((dlsch[0].rnti_type == TYPE_C_RNTI_ || dlsch[0].rnti_type == TYPE_RA_RNTI_) && dlsch[0].dlsch_config.k1_feedback) { const int ack_nack_slot_and_frame = (proc->nr_slot_rx + dlsch[0].dlsch_config.k1_feedback) + proc->frame_rx * ue->frame_parms.slots_per_frame; dynamic_barrier_join(&ue->process_slot_tx_barriers[ack_nack_slot_and_frame % NUM_PROCESS_SLOT_TX_BARRIERS]); diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index e36d50c6ad..6238c09a2e 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -37,6 +37,7 @@ #include "LAYER2/NR_MAC_gNB/mac_proto.h" #include "LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.h" #include "LAYER2/NR_MAC_gNB/nr_mac_gNB.h" +#include "LAYER2/NR_MAC_gNB/nr_radio_config.h" #include "NR_BCCH-BCH-Message.h" #include "NR_BWP-Downlink.h" #include "NR_CellGroupConfig.h" @@ -61,7 +62,6 @@ #include "PHY/defs_nr_common.h" #include "PHY/impl_defs_nr.h" #include "PHY/phy_vars_nr_ue.h" -#include "RRC/NR/nr_rrc_config.h" #include "SCHED_NR/fapi_nr_l1.h" #include "SCHED_NR/sched_nr.h" #include "SCHED_NR_UE/defs.h" diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index da85ef0de4..4c12530f30 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -87,7 +87,7 @@ #include "openair1/SIMULATION/TOOLS/sim.h" #include "openair2/LAYER2/NR_MAC_UE/mac_proto.h" #include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h" -#include "openair2/RRC/NR/nr_rrc_config.h" +#include "openair2/LAYER2/NR_MAC_gNB/nr_radio_config.h" #include "time_meas.h" #include "utils.h" diff --git a/openair2/COMMON/ngap_messages_types.h b/openair2/COMMON/ngap_messages_types.h index 588d7c5cba..52cd919338 100644 --- a/openair2/COMMON/ngap_messages_types.h +++ b/openair2/COMMON/ngap_messages_types.h @@ -34,6 +34,7 @@ #include "common/platform_types.h" #include "common/5g_platform_types.h" #include "s1ap_messages_types.h" +#include "ds/byte_array.h" // Defines to access message fields. #define NGAP_REGISTER_GNB_REQ(mSGpTR) (mSGpTR)->ittiMsg.ngap_register_gnb_req @@ -199,15 +200,6 @@ typedef struct pdusession_level_qos_parameter_s { ngap_allocation_retention_priority_t allocation_retention_priority; } pdusession_level_qos_parameter_t; -typedef struct ngap_guami_s { - uint16_t mcc; - uint16_t mnc; - uint8_t mnc_len; - uint8_t amf_region_id; - uint16_t amf_set_id; - uint8_t amf_pointer; -} ngap_guami_t; - typedef struct fiveg_s_tmsi_s { uint16_t amf_set_id; uint8_t amf_pointer; @@ -225,7 +217,6 @@ typedef struct ngap_ue_paging_identity_s { } ngap_ue_paging_identity_t; typedef enum ngap_ue_identities_presenceMask_e { - NGAP_UE_IDENTITIES_NONE = 0, NGAP_UE_IDENTITIES_FiveG_s_tmsi = 1 << 1, NGAP_UE_IDENTITIES_guami = 1 << 2, } ngap_ue_identities_presenceMask_t; @@ -233,16 +224,9 @@ typedef enum ngap_ue_identities_presenceMask_e { typedef struct ngap_ue_identity_s { ngap_ue_identities_presenceMask_t presenceMask; fiveg_s_tmsi_t s_tmsi; - ngap_guami_t guami; + nr_guami_t guami; } ngap_ue_identity_t; -typedef struct ngap_nas_pdu_s { - /* Octet string data */ - uint8_t *buffer; - /* Length of the octet string */ - uint32_t length; -} ngap_pdu_t; - typedef struct ngap_mobility_restriction_s{ ngap_plmn_identity_t serving_plmn; }ngap_mobility_restriction_t; @@ -258,8 +242,8 @@ typedef enum pdu_session_type_e { typedef struct pdusession_s { /* Unique pdusession_id for the UE. */ int pdusession_id; - ngap_pdu_t nas_pdu; - ngap_pdu_t pdusessionTransfer; + byte_array_t nas_pdu; + byte_array_t pdusessionTransfer; uint8_t nb_qos; /* Quality of service for this pdusession */ pdusession_level_qos_parameter_t qos[QOSFLOW_MAX_VALUE]; @@ -506,22 +490,16 @@ typedef struct ngap_deregistered_gnb_ind_s { * will be the unique identifier used between RRC and NGAP. */ typedef struct ngap_nas_first_req_s { - /* UE id for initial connection to NGAP */ + // RAN UE NGAP ID (mandatory) uint32_t gNB_ue_ngap_id; - - /* the chosen PLMN identity as index, see TS 36.331 6.2.2 RRC Connection - * Setup Complete. This index here is zero-based, unlike the standard! */ - int selected_plmn_identity; - - /* Establishment cause as sent by UE */ + /* PLMN: Selected PLMN Identity (optional) + * User Location Information (mandatory) */ + plmn_id_t plmn; + // RRC Establishment Cause (mandatory) ngap_rrc_establishment_cause_t establishment_cause; - - /* NAS PDU */ - ngap_pdu_t nas_pdu; - - /* If this flag is set NGAP layer is expecting the GUAMI. If = 0, - * the temporary s-tmsi is used. - */ + // NAS-PDU (mandatory) + byte_array_t nas_pdu; + // UE identity: 5G-S-TMSI, GUAMI ngap_ue_identity_t ue_identity; } ngap_nas_first_req_t; @@ -529,12 +507,12 @@ typedef struct ngap_uplink_nas_s { /* Unique UE identifier within an gNB */ uint32_t gNB_ue_ngap_id; /* NAS pdu */ - ngap_pdu_t nas_pdu; + byte_array_t nas_pdu; } ngap_uplink_nas_t; typedef struct ngap_ue_cap_info_ind_s { uint32_t gNB_ue_ngap_id; - ngap_pdu_t ue_radio_cap; + byte_array_t ue_radio_cap; } ngap_ue_cap_info_ind_t; typedef struct ngap_initial_context_setup_resp_s { @@ -561,7 +539,7 @@ typedef struct ngap_initial_context_setup_fail_s { typedef struct ngap_nas_non_delivery_ind_s { uint32_t gNB_ue_ngap_id; - ngap_pdu_t nas_pdu; + byte_array_t nas_pdu; /* TODO: add cause */ } ngap_nas_non_delivery_ind_t; @@ -599,7 +577,7 @@ typedef struct ngap_downlink_nas_s { /* UE id for initial connection to NGAP */ uint32_t gNB_ue_ngap_id; /* NAS pdu */ - ngap_pdu_t nas_pdu; + byte_array_t nas_pdu; } ngap_downlink_nas_t; @@ -613,7 +591,7 @@ typedef struct ngap_initial_context_setup_req_s { ngap_ambr_t ue_ambr; /* guami */ - ngap_guami_t guami; + nr_guami_t guami; /* allowed nssai */ uint8_t nb_allowed_nssais; @@ -636,7 +614,7 @@ typedef struct ngap_initial_context_setup_req_s { /* Nas Pdu */ uint8_t nas_pdu_flag; - ngap_pdu_t nas_pdu; + byte_array_t nas_pdu; } ngap_initial_context_setup_req_t; @@ -665,8 +643,8 @@ typedef struct ngap_paging_ind_s { typedef struct { /* Unique pdusession_id for the UE. */ int pdusession_id; - ngap_pdu_t nas_pdu; - ngap_pdu_t pdusessionTransfer; + byte_array_t nas_pdu; + byte_array_t pdusessionTransfer; } pdusession_setup_req_t; typedef struct ngap_pdusession_setup_req_s { @@ -719,7 +697,7 @@ typedef struct ngap_path_switch_req_s { /* AMF UE id */ uint64_t amf_ue_ngap_id; - ngap_guami_t ue_guami; + nr_guami_t ue_guami; uint16_t ue_initial_id; /* Security algorithms */ @@ -792,7 +770,7 @@ typedef struct ngap_ue_release_command_s { typedef struct pdusession_release_s { /* Unique pdusession_id for the UE. */ uint8_t pdusession_id; - ngap_pdu_t data; + byte_array_t data; } pdusession_release_t; typedef struct ngap_ue_release_req_s { @@ -840,7 +818,7 @@ typedef struct ngap_pdusession_release_command_s { uint32_t gNB_ue_ngap_id; /* The NAS PDU should be forwarded by the RRC layer to the NAS layer */ - ngap_pdu_t nas_pdu; + byte_array_t nas_pdu; /* Number of pdusession to be released in the list */ uint8_t nb_pdusessions_torelease; diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 2c82a6eb6e..70e6c026ca 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -42,7 +42,6 @@ #include "PHY/INIT/nr_phy_init.h" #include "PHY/defs_gNB.h" #include "PHY/defs_nr_common.h" -#include "RRC/NR/nr_rrc_config.h" #include "RRC_nr_paramsvalues.h" #include "T.h" #include "asn_SEQUENCE_OF.h" @@ -885,7 +884,7 @@ void RCconfig_verify(configmodule_interface_t *cfg, ngran_node_t node_type) verify_gnb_param_notset(gnbp, GNB_ENABLE_SDAP_IDX, GNB_CONFIG_STRING_ENABLE_SDAP); verify_gnb_param_notset(gnbp, GNB_DRBS, GNB_CONFIG_STRING_DRBS); - verify_section_notset(cfg, GNB_CONFIG_STRING_GNB_LIST ".", GNB_CONFIG_STRING_AMF_IP_ADDRESS); + verify_section_notset(cfg, GNB_CONFIG_STRING_GNB_LIST ".[0]", GNB_CONFIG_STRING_AMF_IP_ADDRESS); verify_section_notset(cfg, NULL, CONFIG_STRING_SECURITY); } // else nothing to be checked diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c index 594992c1cb..b435e9e265 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c @@ -368,8 +368,7 @@ NR_tda_info_t get_ul_tda_info(const NR_UE_UL_BWP_t *ul_bwp, NR_PUSCH_TimeDomainResourceAllocationList_t *tdalist = get_ul_tdalist(ul_bwp, controlResourceSetId, ss_type, rnti_type); // Definition of value j in Table 6.1.2.1.1-4 of 38.214 int scs = ul_bwp->scs; - AssertFatal(scs >= 0 && scs < 5, "Subcarrier spacing indicatior %d invalid value\n", scs); - int j = scs == 0 ? 1 : scs; + int j = get_j_for_k2(scs); if (tdalist) { tda_info.valid_tda = tda_index < tdalist->list.count; if (!tda_info.valid_tda) { @@ -5129,3 +5128,19 @@ int nr_get_prach_or_ul_mu(const NR_MsgA_ConfigCommon_r16_t *msgacc, return mu; } + +int get_delta_for_k2(int mu) +{ + // 38.214 Table 6.1.2.1.1-5: Definition of value Δ + int delta_table[] = {2, 3, 4, 6, 24, 48}; + AssertFatal(mu >= 0 && mu < sizeofArray(delta_table), "Invalid numerology %d\n", mu); + return delta_table[mu]; +} + +int get_j_for_k2(int mu) +{ + // 38.214 Table 6.1.2.1.1-4: Definition of value j + int j_table[] = {1, 1, 2, 3, 11, 21}; + AssertFatal(mu >= 0 && mu < sizeofArray(j_table), "Invalid numerology %d\n", mu); + return j_table[mu]; +} diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h index 2607d8f587..84284f0c48 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h @@ -318,4 +318,8 @@ int get_nrofHARQ_ProcessesForPUSCH(const NR_UE_ServingCell_Info_t *sc_info); int nr_get_prach_or_ul_mu(const NR_MsgA_ConfigCommon_r16_t *msgacc, const NR_RACH_ConfigCommon_t *rach_ConfigCommon, const int ul_mu); +int get_delta_for_k2(int mu); + +int get_j_for_k2(int mu); + #endif diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 16aa7dcb8f..5d3102c07d 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -933,10 +933,19 @@ static int nr_ue_process_dci_dl_10(NR_UE_MAC_INST_t *mac, const int ntn_ue_koffset = GET_NTN_UE_K_OFFSET(&mac->ntn_ta, dlsch_pdu->SubcarrierSpacing); uint16_t feedback_ti = 0; + if (rnti_type == TYPE_RA_RNTI_) { + // RA-RNTI indicates RAR. Ensure we can decode RAR before the earliest UL scheduler call + // that can process the MSG3. Also assume that RAR is sent in the same slot as DCI (k0 == 0) + // This is not perfect as the MSG3 might end up being scheduled later, so we could be + // halting the UL scheduler for a longer time than necessary. + feedback_ti = max(1 + GET_DURATION_RX_TO_TX(&mac->ntn_ta, dlsch_pdu->SubcarrierSpacing), + get_delta_for_k2(mac->current_UL_BWP->scs) + get_j_for_k2(mac->current_UL_BWP->scs)); + } + if (rnti_type != TYPE_RA_RNTI_ && rnti_type != TYPE_SI_RNTI_) { if (!get_FeedbackDisabled(mac->sc_info.downlinkHARQ_FeedbackDisabled_r17, dci->harq_pid.val)) { feedback_ti = 1 + dci->pdsch_to_harq_feedback_timing_indicator.val + ntn_ue_koffset; - AssertFatal(feedback_ti > GET_DURATION_RX_TO_TX(&mac->ntn_ta, dlsch_pdu->SubcarrierSpacing), + AssertFatal(feedback_ti >= GET_DURATION_RX_TO_TX(&mac->ntn_ta, dlsch_pdu->SubcarrierSpacing), "PDSCH to HARQ feedback time (%d) needs to be higher than DURATION_RX_TO_TX (%ld).\n", feedback_ti, GET_DURATION_RX_TO_TX(&mac->ntn_ta, dlsch_pdu->SubcarrierSpacing)); @@ -1232,7 +1241,7 @@ static int nr_ue_process_dci_dl_11(NR_UE_MAC_INST_t *mac, if (!get_FeedbackDisabled(mac->sc_info.downlinkHARQ_FeedbackDisabled_r17, dci->harq_pid.val)) { feedback_ti = pucch_Config->dl_DataToUL_ACK->list.array[dci->pdsch_to_harq_feedback_timing_indicator.val][0] + ntn_ue_koffset; - AssertFatal(feedback_ti > GET_DURATION_RX_TO_TX(&mac->ntn_ta, dlsch_pdu->SubcarrierSpacing), + AssertFatal(feedback_ti >= GET_DURATION_RX_TO_TX(&mac->ntn_ta, dlsch_pdu->SubcarrierSpacing), "PDSCH to HARQ feedback time (%d) needs to be higher than DURATION_RX_TO_TX (%ld). Min feedback time set in config " "file (min_rxtxtime).\n", feedback_ti, diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 2c94de6e70..1922a3420e 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -1547,22 +1547,7 @@ int nr_ue_pusch_scheduler(const NR_UE_MAC_INST_t *mac, if (is_Msg3) { - switch (mu) { - case 0: - delta = 2; - break; - case 1: - delta = 3; - break; - case 2: - delta = 4; - break; - case 3: - delta = 6; - break; - default: - AssertFatal(1 == 0, "Invalid numerology %i\n", mu); - } + delta = get_delta_for_k2(mu); AssertFatal((k2 + delta) > GET_DURATION_RX_TO_TX(&mac->ntn_ta, mu), "Slot offset (%ld) for Msg3 needs to be higher than DURATION_RX_TO_TX (%ld). Please set min_rxtxtime at least to " @@ -1575,7 +1560,7 @@ int nr_ue_pusch_scheduler(const NR_UE_MAC_INST_t *mac, *slot_tx = (current_slot + k2 + delta) % slots_per_frame; *frame_tx = (current_frame + (current_slot + k2 + delta) / slots_per_frame) % MAX_FRAME_NUMBER; } else { - AssertFatal(k2 > GET_DURATION_RX_TO_TX(&mac->ntn_ta, mu), + AssertFatal(k2 >= GET_DURATION_RX_TO_TX(&mac->ntn_ta, mu), "Slot offset K2 (%ld) needs to be higher than DURATION_RX_TO_TX (%ld). Please set min_rxtxtime at least to %ld in " "gNB config file or gNBs.[0].min_rxtxtime=%ld via command line.\n", k2, diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index aacae2bea1..43d48eeeeb 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -44,7 +44,6 @@ #include "NR_BCCH-BCH-Message.h" #include "NR_ServingCellConfigCommon.h" #include "NR_MIB.h" -#include "RRC/NR/nr_rrc_config.h" #include "SCHED_NR/phy_frame_config_nr.h" #include "T.h" #include "asn_internal.h" diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index 63700d2a72..e67a30e67a 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -58,8 +58,6 @@ static void fill_msg3_pusch_pdu(nfapi_nr_pusch_pdu_t *pusch_pdu, int fh); static void nr_fill_rar(uint8_t Mod_idP, NR_UE_info_t *UE, uint8_t *dlsch_buffer, nfapi_nr_pusch_pdu_t *pusch_pdu); -static const uint8_t DELTA[4] = {2, 3, 4, 6}; - static const float ssb_per_rach_occasion[8] = {0.125, 0.25, 0.5, 1, 2, 4, 8}; static int16_t ssb_index_from_prach(module_id_t module_idP, @@ -1566,7 +1564,7 @@ static void nr_generate_Msg2(module_id_t module_idP, const NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP; bool ret = get_feasible_msg3_tda(scc, - DELTA[ul_bwp->scs], + get_delta_for_k2(ul_bwp->scs), ul_bwp->tdaList_Common, frameP, slotP, 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 9928c168c1..28c129cb58 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -22,6 +22,7 @@ #include "mac_rrc_dl_handler.h" #include "mac_proto.h" +#include "nr_radio_config.h" #include "openair2/F1AP/f1ap_ids.h" #include "openair2/F1AP/f1ap_common.h" #include "openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h" diff --git a/openair2/LAYER2/NR_MAC_gNB/main.c b/openair2/LAYER2/NR_MAC_gNB/main.c index 3137ce0902..9c8e414f52 100644 --- a/openair2/LAYER2/NR_MAC_gNB/main.c +++ b/openair2/LAYER2/NR_MAC_gNB/main.c @@ -53,8 +53,6 @@ #include "NR_ServingCellConfig.h" #include "NR_ServingCellConfigCommon.h" #include "NR_TAG.h" -#include "RRC/NR/MESSAGES/asn1_msg.h" -#include "RRC/NR/nr_rrc_config.h" #include "assertions.h" #include "common/ngran_types.h" #include "common/ran_context.h" diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 0b977de276..d97783604f 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -74,7 +74,7 @@ #include "NR_BCCH-BCH-Message.h" #include "NR_CellGroupConfig.h" #include "NR_BCCH-DL-SCH-Message.h" -#include "openair2/RRC/NR/nr_rrc_config.h" +#include "nr_radio_config.h" /* PHY */ #include "time_meas.h" diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c similarity index 96% rename from openair2/RRC/NR/nr_rrc_config.c rename to openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c index dfb5b9e231..22c2207be1 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c @@ -19,26 +19,14 @@ * contact@openairinterface.org */ -/*! \file nr_rrc_config.c - * \brief rrc config for gNB - * \author Raymond Knopp, WEI-TAI CHEN - * \date 2018 - * \version 1.0 - * \company Eurecom, NTUST - * \email: raymond.knopp@eurecom.fr, kroempa@gmail.com - */ +#include "nr_radio_config.h" -#include "nr_rrc_config.h" #include #include #include #include #include "BIT_STRING.h" #include "NULL.h" -#include "RRC/NR/MESSAGES/asn1_msg.h" -#include "RRC/NR/nr_rrc_proto.h" -#include "SIMULATION/TOOLS/sim.h" -#include "T.h" #include "asn_SET_OF.h" #include "asn_codecs.h" #include "asn_internal.h" @@ -49,15 +37,18 @@ #include "constr_TYPE.h" #include "executables/softmodem-common.h" #include "oai_asn1.h" -#include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h" #include "openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h" #include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h" #include "openair3/UTILS/conversions.h" + +#include "NR_MeasurementTimingConfiguration.h" #include "uper_decoder.h" #include "uper_encoder.h" #include "utils.h" #include "xer_encoder.h" +#define NR_MAX_SUPPORTED_DL_LAYERS 4 + #define PUCCH2_SIZE 8 const uint8_t slotsperframe[5] = {10, 20, 40, 80, 160}; @@ -1066,7 +1057,6 @@ void nr_rrc_config_ul_tda(NR_ServingCellConfigCommon_t *scc, int min_fb_delay) AssertFatal(tda->list.count == 0, "already have pusch_TimeDomainAllocationList members\n"); const int k2 = min_fb_delay; - uint8_t DELTA[4]= {2,3,4,6}; // Delta parameter for Msg3 int mu = scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.subcarrierSpacing; struct NR_SetupRelease_PUSCH_ConfigCommon *pusch_ConfigCommon = scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon; @@ -1099,7 +1089,7 @@ void nr_rrc_config_ul_tda(NR_ServingCellConfigCommon_t *scc, int min_fb_delay) int tdd_period_idx = get_tdd_period_idx(scc->tdd_UL_DL_ConfigurationCommon); int nb_periods_per_frame = get_nb_periods_per_frame(tdd_period_idx); int nb_slots_per_period = ((1 << mu) * 10) / nb_periods_per_frame; - int k2_msg3 = nb_slots_per_period - DELTA[mu]; + int k2_msg3 = nb_slots_per_period - get_delta_for_k2(mu); struct NR_PUSCH_TimeDomainResourceAllocation *puschTdrAllocMsg3 = set_TimeDomainResourceAllocation(k2_msg3, 3, ul_symb); if (*puschTdrAllocMsg3->k2 < min_fb_delay) *puschTdrAllocMsg3->k2 += nb_slots_per_period; @@ -3348,6 +3338,116 @@ static NR_SpCellConfig_t *get_initial_SpCellConfig(int uid, return SpCellConfig; } +NR_RLC_BearerConfig_t *get_SRB_RLC_BearerConfig(long channelId, long priority, long bucketSizeDuration) +{ + NR_RLC_BearerConfig_t *rlc_BearerConfig = NULL; + rlc_BearerConfig = calloc(1, sizeof(NR_RLC_BearerConfig_t)); + rlc_BearerConfig->logicalChannelIdentity = channelId; + rlc_BearerConfig->servedRadioBearer = calloc(1, sizeof(*rlc_BearerConfig->servedRadioBearer)); + rlc_BearerConfig->servedRadioBearer->present = NR_RLC_BearerConfig__servedRadioBearer_PR_srb_Identity; + rlc_BearerConfig->servedRadioBearer->choice.srb_Identity = channelId; + rlc_BearerConfig->reestablishRLC = NULL; + + NR_RLC_Config_t *rlc_Config = calloc(1, sizeof(NR_RLC_Config_t)); + rlc_Config->present = NR_RLC_Config_PR_am; + rlc_Config->choice.am = calloc(1, sizeof(*rlc_Config->choice.am)); + rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength = calloc(1, sizeof(NR_SN_FieldLengthAM_t)); + *(rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength) = NR_SN_FieldLengthAM_size12; + rlc_Config->choice.am->dl_AM_RLC.t_Reassembly = NR_T_Reassembly_ms35; + rlc_Config->choice.am->dl_AM_RLC.t_StatusProhibit = NR_T_StatusProhibit_ms0; + rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength = calloc(1, sizeof(NR_SN_FieldLengthAM_t)); + *(rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength) = NR_SN_FieldLengthAM_size12; + rlc_Config->choice.am->ul_AM_RLC.t_PollRetransmit = NR_T_PollRetransmit_ms45; + rlc_Config->choice.am->ul_AM_RLC.pollPDU = NR_PollPDU_infinity; + rlc_Config->choice.am->ul_AM_RLC.pollByte = NR_PollByte_infinity; + rlc_Config->choice.am->ul_AM_RLC.maxRetxThreshold = NR_UL_AM_RLC__maxRetxThreshold_t8; + rlc_BearerConfig->rlc_Config = rlc_Config; + + NR_LogicalChannelConfig_t *logicalChannelConfig = calloc(1, sizeof(NR_LogicalChannelConfig_t)); + logicalChannelConfig->ul_SpecificParameters = calloc(1, sizeof(*logicalChannelConfig->ul_SpecificParameters)); + logicalChannelConfig->ul_SpecificParameters->priority = priority; + logicalChannelConfig->ul_SpecificParameters->prioritisedBitRate = NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity; + logicalChannelConfig->ul_SpecificParameters->bucketSizeDuration = bucketSizeDuration; + + long *logicalChannelGroup = CALLOC(1, sizeof(long)); + *logicalChannelGroup = 0; + logicalChannelConfig->ul_SpecificParameters->logicalChannelGroup = logicalChannelGroup; + logicalChannelConfig->ul_SpecificParameters->schedulingRequestID = CALLOC(1, sizeof(*logicalChannelConfig->ul_SpecificParameters->schedulingRequestID)); + *logicalChannelConfig->ul_SpecificParameters->schedulingRequestID = 0; + logicalChannelConfig->ul_SpecificParameters->logicalChannelSR_Mask = 0; + logicalChannelConfig->ul_SpecificParameters->logicalChannelSR_DelayTimerApplied = 0; + rlc_BearerConfig->mac_LogicalChannelConfig = logicalChannelConfig; + + return rlc_BearerConfig; +} + +static void nr_drb_config(struct NR_RLC_Config *rlc_Config, NR_RLC_Config_PR rlc_config_pr) +{ + switch (rlc_config_pr) { + case NR_RLC_Config_PR_um_Bi_Directional: + // RLC UM Bi-directional Bearer configuration + LOG_I(RLC, "RLC UM Bi-directional Bearer configuration selected \n"); + rlc_Config->choice.um_Bi_Directional = calloc(1, sizeof(*rlc_Config->choice.um_Bi_Directional)); + rlc_Config->choice.um_Bi_Directional->ul_UM_RLC.sn_FieldLength = + calloc(1, sizeof(*rlc_Config->choice.um_Bi_Directional->ul_UM_RLC.sn_FieldLength)); + *rlc_Config->choice.um_Bi_Directional->ul_UM_RLC.sn_FieldLength = NR_SN_FieldLengthUM_size12; + rlc_Config->choice.um_Bi_Directional->dl_UM_RLC.sn_FieldLength = + calloc(1, sizeof(*rlc_Config->choice.um_Bi_Directional->dl_UM_RLC.sn_FieldLength)); + *rlc_Config->choice.um_Bi_Directional->dl_UM_RLC.sn_FieldLength = NR_SN_FieldLengthUM_size12; + rlc_Config->choice.um_Bi_Directional->dl_UM_RLC.t_Reassembly = NR_T_Reassembly_ms15; + break; + case NR_RLC_Config_PR_am: + // RLC AM Bearer configuration + rlc_Config->choice.am = calloc(1, sizeof(*rlc_Config->choice.am)); + rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength = calloc(1, sizeof(*rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength)); + *rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength = NR_SN_FieldLengthAM_size18; + rlc_Config->choice.am->ul_AM_RLC.t_PollRetransmit = NR_T_PollRetransmit_ms45; + rlc_Config->choice.am->ul_AM_RLC.pollPDU = NR_PollPDU_p64; + rlc_Config->choice.am->ul_AM_RLC.pollByte = NR_PollByte_kB500; + rlc_Config->choice.am->ul_AM_RLC.maxRetxThreshold = NR_UL_AM_RLC__maxRetxThreshold_t32; + rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength = calloc(1, sizeof(*rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength)); + *rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength = NR_SN_FieldLengthAM_size18; + rlc_Config->choice.am->dl_AM_RLC.t_Reassembly = NR_T_Reassembly_ms15; + rlc_Config->choice.am->dl_AM_RLC.t_StatusProhibit = NR_T_StatusProhibit_ms15; + break; + default: + AssertFatal(false, "RLC config type %d not handled\n", rlc_config_pr); + break; + } + rlc_Config->present = rlc_config_pr; +} + +NR_RLC_BearerConfig_t *get_DRB_RLC_BearerConfig(long lcChannelId, long drbId, NR_RLC_Config_PR rlc_conf, long priority) +{ + NR_RLC_BearerConfig_t *rlc_BearerConfig = calloc(1, sizeof(NR_RLC_BearerConfig_t)); + rlc_BearerConfig->logicalChannelIdentity = lcChannelId; + rlc_BearerConfig->servedRadioBearer = calloc(1, sizeof(*rlc_BearerConfig->servedRadioBearer)); + rlc_BearerConfig->servedRadioBearer->present = NR_RLC_BearerConfig__servedRadioBearer_PR_drb_Identity; + rlc_BearerConfig->servedRadioBearer->choice.drb_Identity = drbId; + rlc_BearerConfig->reestablishRLC = NULL; + + NR_RLC_Config_t *rlc_Config = calloc(1, sizeof(NR_RLC_Config_t)); + nr_drb_config(rlc_Config, rlc_conf); + rlc_BearerConfig->rlc_Config = rlc_Config; + + NR_LogicalChannelConfig_t *logicalChannelConfig = calloc(1, sizeof(NR_LogicalChannelConfig_t)); + logicalChannelConfig->ul_SpecificParameters = calloc(1, sizeof(*logicalChannelConfig->ul_SpecificParameters)); + logicalChannelConfig->ul_SpecificParameters->priority = priority; + logicalChannelConfig->ul_SpecificParameters->prioritisedBitRate = NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps8; + logicalChannelConfig->ul_SpecificParameters->bucketSizeDuration = NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms100; + + long *logicalChannelGroup = CALLOC(1, sizeof(long)); + *logicalChannelGroup = 1; + logicalChannelConfig->ul_SpecificParameters->logicalChannelGroup = logicalChannelGroup; + logicalChannelConfig->ul_SpecificParameters->schedulingRequestID = CALLOC(1, sizeof(*logicalChannelConfig->ul_SpecificParameters->schedulingRequestID)); + *logicalChannelConfig->ul_SpecificParameters->schedulingRequestID = 0; + logicalChannelConfig->ul_SpecificParameters->logicalChannelSR_Mask = 0; + logicalChannelConfig->ul_SpecificParameters->logicalChannelSR_DelayTimerApplied = 0; + rlc_BearerConfig->mac_LogicalChannelConfig = logicalChannelConfig; + + return rlc_BearerConfig; +} + NR_CellGroupConfig_t *get_initial_cellGroupConfig(int uid, const NR_ServingCellConfigCommon_t *scc, const NR_ServingCellConfig_t *servingcellconfigdedicated, diff --git a/openair2/RRC/NR/nr_rrc_config.h b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.h similarity index 95% rename from openair2/RRC/NR/nr_rrc_config.h rename to openair2/LAYER2/NR_MAC_gNB/nr_radio_config.h index c4189dcb21..d5a7f8d40a 100644 --- a/openair2/RRC/NR/nr_rrc_config.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.h @@ -19,17 +19,8 @@ * contact@openairinterface.org */ -/*! \file nr_rrc_config.c - * \brief rrc config for gNB - * \author Raymond Knopp, WEI-TAI CHEN - * \date 2018 - * \version 1.0 - * \company Eurecom, NTUST - * \email: raymond.knopp@eurecom.fr, kroempa@gmail.com - */ - -#ifndef __NR_RRC_CONFIG_H__ -#define __NR_RRC_CONFIG_H__ +#ifndef __NR_MAC_RRC_CONFIG_H__ +#define __NR_MAC_RRC_CONFIG_H__ #include #include @@ -116,4 +107,7 @@ NR_CellGroupConfig_t *get_default_secondaryCellGroup(const NR_ServingCellConfigC NR_ReconfigurationWithSync_t *get_reconfiguration_with_sync(rnti_t rnti, uid_t uid, const NR_ServingCellConfigCommon_t *scc); +NR_RLC_BearerConfig_t *get_SRB_RLC_BearerConfig(long channelId, long priority, long bucketSizeDuration); +NR_RLC_BearerConfig_t *get_DRB_RLC_BearerConfig(long lcChannelId, long drbId, NR_RLC_Config_PR rlc_conf, long priority); + #endif diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 586e2e7628..6a7ee77b52 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -269,118 +269,6 @@ int do_RRCReject(uint8_t *const buffer) return (enc_rval.encoded + 7) / 8; } -NR_RLC_BearerConfig_t *get_SRB_RLC_BearerConfig(long channelId, - long priority, - e_NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration bucketSizeDuration) -{ - NR_RLC_BearerConfig_t *rlc_BearerConfig = NULL; - rlc_BearerConfig = calloc(1, sizeof(NR_RLC_BearerConfig_t)); - rlc_BearerConfig->logicalChannelIdentity = channelId; - rlc_BearerConfig->servedRadioBearer = calloc(1, sizeof(*rlc_BearerConfig->servedRadioBearer)); - rlc_BearerConfig->servedRadioBearer->present = NR_RLC_BearerConfig__servedRadioBearer_PR_srb_Identity; - rlc_BearerConfig->servedRadioBearer->choice.srb_Identity = channelId; - rlc_BearerConfig->reestablishRLC = NULL; - - NR_RLC_Config_t *rlc_Config = calloc(1, sizeof(NR_RLC_Config_t)); - rlc_Config->present = NR_RLC_Config_PR_am; - rlc_Config->choice.am = calloc(1, sizeof(*rlc_Config->choice.am)); - rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength = calloc(1, sizeof(NR_SN_FieldLengthAM_t)); - *(rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength) = NR_SN_FieldLengthAM_size12; - rlc_Config->choice.am->dl_AM_RLC.t_Reassembly = NR_T_Reassembly_ms35; - rlc_Config->choice.am->dl_AM_RLC.t_StatusProhibit = NR_T_StatusProhibit_ms0; - rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength = calloc(1, sizeof(NR_SN_FieldLengthAM_t)); - *(rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength) = NR_SN_FieldLengthAM_size12; - rlc_Config->choice.am->ul_AM_RLC.t_PollRetransmit = NR_T_PollRetransmit_ms45; - rlc_Config->choice.am->ul_AM_RLC.pollPDU = NR_PollPDU_infinity; - rlc_Config->choice.am->ul_AM_RLC.pollByte = NR_PollByte_infinity; - rlc_Config->choice.am->ul_AM_RLC.maxRetxThreshold = NR_UL_AM_RLC__maxRetxThreshold_t8; - rlc_BearerConfig->rlc_Config = rlc_Config; - - NR_LogicalChannelConfig_t *logicalChannelConfig = calloc(1, sizeof(NR_LogicalChannelConfig_t)); - logicalChannelConfig->ul_SpecificParameters = calloc(1, sizeof(*logicalChannelConfig->ul_SpecificParameters)); - logicalChannelConfig->ul_SpecificParameters->priority = priority; - logicalChannelConfig->ul_SpecificParameters->prioritisedBitRate = NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity; - logicalChannelConfig->ul_SpecificParameters->bucketSizeDuration = bucketSizeDuration; - - long *logicalChannelGroup = CALLOC(1, sizeof(long)); - *logicalChannelGroup = 0; - logicalChannelConfig->ul_SpecificParameters->logicalChannelGroup = logicalChannelGroup; - logicalChannelConfig->ul_SpecificParameters->schedulingRequestID = CALLOC(1, sizeof(*logicalChannelConfig->ul_SpecificParameters->schedulingRequestID)); - *logicalChannelConfig->ul_SpecificParameters->schedulingRequestID = 0; - logicalChannelConfig->ul_SpecificParameters->logicalChannelSR_Mask = 0; - logicalChannelConfig->ul_SpecificParameters->logicalChannelSR_DelayTimerApplied = 0; - rlc_BearerConfig->mac_LogicalChannelConfig = logicalChannelConfig; - - return rlc_BearerConfig; -} - -static void nr_drb_config(struct NR_RLC_Config *rlc_Config, NR_RLC_Config_PR rlc_config_pr) -{ - switch (rlc_config_pr) { - case NR_RLC_Config_PR_um_Bi_Directional: - // RLC UM Bi-directional Bearer configuration - LOG_I(RLC, "RLC UM Bi-directional Bearer configuration selected \n"); - rlc_Config->choice.um_Bi_Directional = calloc(1, sizeof(*rlc_Config->choice.um_Bi_Directional)); - rlc_Config->choice.um_Bi_Directional->ul_UM_RLC.sn_FieldLength = - calloc(1, sizeof(*rlc_Config->choice.um_Bi_Directional->ul_UM_RLC.sn_FieldLength)); - *rlc_Config->choice.um_Bi_Directional->ul_UM_RLC.sn_FieldLength = NR_SN_FieldLengthUM_size12; - rlc_Config->choice.um_Bi_Directional->dl_UM_RLC.sn_FieldLength = - calloc(1, sizeof(*rlc_Config->choice.um_Bi_Directional->dl_UM_RLC.sn_FieldLength)); - *rlc_Config->choice.um_Bi_Directional->dl_UM_RLC.sn_FieldLength = NR_SN_FieldLengthUM_size12; - rlc_Config->choice.um_Bi_Directional->dl_UM_RLC.t_Reassembly = NR_T_Reassembly_ms15; - break; - case NR_RLC_Config_PR_am: - // RLC AM Bearer configuration - rlc_Config->choice.am = calloc(1, sizeof(*rlc_Config->choice.am)); - rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength = calloc(1, sizeof(*rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength)); - *rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength = NR_SN_FieldLengthAM_size18; - rlc_Config->choice.am->ul_AM_RLC.t_PollRetransmit = NR_T_PollRetransmit_ms45; - rlc_Config->choice.am->ul_AM_RLC.pollPDU = NR_PollPDU_p64; - rlc_Config->choice.am->ul_AM_RLC.pollByte = NR_PollByte_kB500; - rlc_Config->choice.am->ul_AM_RLC.maxRetxThreshold = NR_UL_AM_RLC__maxRetxThreshold_t32; - rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength = calloc(1, sizeof(*rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength)); - *rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength = NR_SN_FieldLengthAM_size18; - rlc_Config->choice.am->dl_AM_RLC.t_Reassembly = NR_T_Reassembly_ms15; - rlc_Config->choice.am->dl_AM_RLC.t_StatusProhibit = NR_T_StatusProhibit_ms15; - break; - default: - AssertFatal(false, "RLC config type %d not handled\n", rlc_config_pr); - break; - } - rlc_Config->present = rlc_config_pr; -} - -NR_RLC_BearerConfig_t *get_DRB_RLC_BearerConfig(long lcChannelId, long drbId, NR_RLC_Config_PR rlc_conf, long priority) -{ - NR_RLC_BearerConfig_t *rlc_BearerConfig = calloc(1, sizeof(NR_RLC_BearerConfig_t)); - rlc_BearerConfig->logicalChannelIdentity = lcChannelId; - rlc_BearerConfig->servedRadioBearer = calloc(1, sizeof(*rlc_BearerConfig->servedRadioBearer)); - rlc_BearerConfig->servedRadioBearer->present = NR_RLC_BearerConfig__servedRadioBearer_PR_drb_Identity; - rlc_BearerConfig->servedRadioBearer->choice.drb_Identity = drbId; - rlc_BearerConfig->reestablishRLC = NULL; - - NR_RLC_Config_t *rlc_Config = calloc(1, sizeof(NR_RLC_Config_t)); - nr_drb_config(rlc_Config, rlc_conf); - rlc_BearerConfig->rlc_Config = rlc_Config; - - NR_LogicalChannelConfig_t *logicalChannelConfig = calloc(1, sizeof(NR_LogicalChannelConfig_t)); - logicalChannelConfig->ul_SpecificParameters = calloc(1, sizeof(*logicalChannelConfig->ul_SpecificParameters)); - logicalChannelConfig->ul_SpecificParameters->priority = priority; - logicalChannelConfig->ul_SpecificParameters->prioritisedBitRate = NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps8; - logicalChannelConfig->ul_SpecificParameters->bucketSizeDuration = NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms100; - - long *logicalChannelGroup = CALLOC(1, sizeof(long)); - *logicalChannelGroup = 1; - logicalChannelConfig->ul_SpecificParameters->logicalChannelGroup = logicalChannelGroup; - logicalChannelConfig->ul_SpecificParameters->schedulingRequestID = CALLOC(1, sizeof(*logicalChannelConfig->ul_SpecificParameters->schedulingRequestID)); - *logicalChannelConfig->ul_SpecificParameters->schedulingRequestID = 0; - logicalChannelConfig->ul_SpecificParameters->logicalChannelSR_Mask = 0; - logicalChannelConfig->ul_SpecificParameters->logicalChannelSR_DelayTimerApplied = 0; - rlc_BearerConfig->mac_LogicalChannelConfig = logicalChannelConfig; - - return rlc_BearerConfig; -} - /* returns a default radio bearer config suitable for NSA etc */ NR_RadioBearerConfig_t *get_default_rbconfig(int eps_bearer_id, int rb_id, diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.h b/openair2/RRC/NR/MESSAGES/asn1_msg.h index 344659afbb..afc9226b17 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.h +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.h @@ -69,12 +69,6 @@ int do_SIB2_NR(uint8_t **msg_SIB2, NR_SSB_MTC_t *ssbmtc); int do_RRCReject(uint8_t *const buffer); -NR_RLC_BearerConfig_t *get_SRB_RLC_BearerConfig( - long channelId, - long priority, - e_NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration bucketSizeDuration); -NR_RLC_BearerConfig_t *get_DRB_RLC_BearerConfig(long lcChannelId, long drbId, NR_RLC_Config_PR rlc_conf, long priority); - NR_RadioBearerConfig_t *get_default_rbconfig(int eps_bearer_id, int rb_id, e_NR_CipheringAlgorithm ciphering_algorithm, diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 6cee7e6fa4..7e0789c4ad 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -86,15 +86,6 @@ typedef struct nr_e_rab_param_s { uint8_t xid; // transaction_id } __attribute__ ((__packed__)) nr_e_rab_param_t; -typedef struct nr_rrc_guami_s { - uint16_t mcc; - uint16_t mnc; - uint8_t mnc_len; - uint8_t amf_region_id; - uint16_t amf_set_id; - uint8_t amf_pointer; -} nr_rrc_guami_t; - typedef enum pdu_session_satus_e { PDU_SESSION_STATUS_NEW, PDU_SESSION_STATUS_DONE, @@ -217,7 +208,8 @@ typedef struct gNB_RRC_UE_s { uint64_t nr_cellid; uint32_t rrc_ue_id; uint64_t amf_ue_ngap_id; - nr_rrc_guami_t ue_guami; + // Globally Unique AMF Identifier + nr_guami_t ue_guami; ngap_security_capabilities_t security_capabilities; //NSA block @@ -247,7 +239,7 @@ typedef struct gNB_RRC_UE_s { pdusession_t *initial_pdus; /* Nas Pdu */ - ngap_pdu_t nas_pdu; + byte_array_t nas_pdu; /* hack, see rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ() for more info */ int max_delays_pdu_session; diff --git a/openair2/RRC/NR/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h index c5627b6e55..4546f59723 100644 --- a/openair2/RRC/NR/nr_rrc_proto.h +++ b/openair2/RRC/NR/nr_rrc_proto.h @@ -39,8 +39,6 @@ #include "NR_CG-ConfigInfo.h" #include "NR_RRCReconfiguration.h" -#define NR_MAX_SUPPORTED_DL_LAYERS 4 - void rrc_add_nsa_user(gNB_RRC_INST *rrc, x2ap_ENDC_sgnb_addition_req_t *m, sctp_assoc_t assoc_id); void rrc_add_nsa_user_resp(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const f1ap_ue_context_setup_t *resp); void rrc_release_nsa_user(gNB_RRC_INST *rrc, rrc_gNB_ue_context_t *ue_context); diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 213d4a8f8a..78e472ed60 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -95,6 +95,7 @@ #include "E1AP/lib/e1ap_bearer_context_management.h" #include "E1AP/lib/e1ap_interface_management.h" #include "NR_DL-DCCH-Message.h" +#include "ds/byte_array.h" #ifdef E2_AGENT #include "openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc_extern.h" @@ -123,17 +124,6 @@ static void rrc_deliver_ue_ctxt_release_cmd(void *deliver_pdu_data, ue_id_t ue_i data->rrc->mac_rrc.ue_context_release_command(data->assoc_id, data->release_cmd); } -///---------------------------------------------------------------------------------------------------------------/// -///---------------------------------------------------------------------------------------------------------------/// - -static void clear_nas_pdu(ngap_pdu_t *pdu) -{ - DevAssert(pdu != NULL); - free(pdu->buffer); // does nothing if NULL - pdu->buffer = NULL; - pdu->length = 0; -} - static void freeDRBlist(NR_DRB_ToAddModList_t *list) { ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToAddModList, list); @@ -648,13 +638,11 @@ static void rrc_gNB_generate_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_ struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList *dedicatedNAS_MessageList = CALLOC(1, sizeof(*dedicatedNAS_MessageList)); for (int i = 0; i < ue_p->nb_of_pdusessions; i++) { - if (ue_p->pduSession[i].param.nas_pdu.buffer != NULL) { + if (ue_p->pduSession[i].param.nas_pdu.buf != NULL) { asn1cSequenceAdd(dedicatedNAS_MessageList->list, NR_DedicatedNAS_Message_t, msg); - OCTET_STRING_fromBuf(msg, - (char *)ue_p->pduSession[i].param.nas_pdu.buffer, - ue_p->pduSession[i].param.nas_pdu.length); + OCTET_STRING_fromBuf(msg, (char *)ue_p->pduSession[i].param.nas_pdu.buf, ue_p->pduSession[i].param.nas_pdu.len); - LOG_D(NR_RRC, "add NAS info with size %d (pdusession idx %d)\n", ue_p->pduSession[i].param.nas_pdu.length, i); + LOG_D(NR_RRC, "add NAS info with size %ld (pdusession idx %d)\n", ue_p->pduSession[i].param.nas_pdu.len, i); ue_p->pduSession[i].xid = xid; } if (ue_p->pduSession[i].status < PDU_SESSION_STATUS_ESTABLISHED) { @@ -662,9 +650,9 @@ static void rrc_gNB_generate_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_ } } - if (ue_p->nas_pdu.length) { + if (ue_p->nas_pdu.len) { asn1cSequenceAdd(dedicatedNAS_MessageList->list, NR_DedicatedNAS_Message_t, msg); - OCTET_STRING_fromBuf(msg, (char *)ue_p->nas_pdu.buffer, ue_p->nas_pdu.length); + OCTET_STRING_fromBuf(msg, (char *)ue_p->nas_pdu.buf, ue_p->nas_pdu.len); } /* If list is empty free the list and reset the address */ @@ -675,7 +663,7 @@ static void rrc_gNB_generate_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_ /* Free all NAS PDUs */ for (int i = 0; i < ue_p->nb_of_pdusessions; i++) - clear_nas_pdu(&ue_p->pduSession[i].param.nas_pdu); + FREE_AND_ZERO_BYTE_ARRAY(ue_p->pduSession[i].param.nas_pdu); uint8_t buffer[NR_RRC_BUF_SIZE] = {0}; // TODO refactor dedicatedNAS_MessageList @@ -697,16 +685,17 @@ void rrc_gNB_modify_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t CALLOC(1, sizeof(*dedicatedNAS_MessageList)); for (int i = 0; i < ue_p->nb_of_pdusessions; i++) { + rrc_pdu_session_param_t *session = &ue_p->pduSession[i]; // bypass the new and already configured pdu sessions - if (ue_p->pduSession[i].status >= PDU_SESSION_STATUS_DONE) { - ue_p->pduSession[i].xid = xid; + if (session->status >= PDU_SESSION_STATUS_DONE) { + session->xid = xid; continue; } - if (ue_p->pduSession[i].cause.type != NGAP_CAUSE_NOTHING) { + if (session->cause.type != NGAP_CAUSE_NOTHING) { // set xid of failure pdu session - ue_p->pduSession[i].xid = xid; - ue_p->pduSession[i].status = PDU_SESSION_STATUS_FAILED; + session->xid = xid; + session->status = PDU_SESSION_STATUS_FAILED; continue; } @@ -714,21 +703,21 @@ void rrc_gNB_modify_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t int j; for (j = 0; i < MAX_DRBS_PER_UE; j++) { if (ue_p->established_drbs[j].status != DRB_INACTIVE - && ue_p->established_drbs[j].cnAssociation.sdap_config.pdusession_id == ue_p->pduSession[i].param.pdusession_id) + && ue_p->established_drbs[j].cnAssociation.sdap_config.pdusession_id == session->param.pdusession_id) break; } if (j == MAX_DRBS_PER_UE) { ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CauseRadioNetwork_unspecified}; - ue_p->pduSession[i].xid = xid; - ue_p->pduSession[i].status = PDU_SESSION_STATUS_FAILED; - ue_p->pduSession[i].cause = cause; + session->xid = xid; + session->status = PDU_SESSION_STATUS_FAILED; + session->cause = cause; continue; } // Reference TS23501 Table 5.7.4-1: Standardized 5QI to QoS characteristics mapping - for (qos_flow_index = 0; qos_flow_index < ue_p->pduSession[i].param.nb_qos; qos_flow_index++) { - switch (ue_p->pduSession[i].param.qos[qos_flow_index].fiveQI) { + for (qos_flow_index = 0; qos_flow_index < session->param.nb_qos; qos_flow_index++) { + switch (session->param.qos[qos_flow_index].fiveQI) { case 1: //100ms case 2: //150ms case 3: //50ms @@ -742,27 +731,23 @@ void rrc_gNB_modify_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t break; default: - LOG_E(NR_RRC, "not supported 5qi %lu\n", ue_p->pduSession[i].param.qos[qos_flow_index].fiveQI); + LOG_E(NR_RRC, "not supported 5qi %lu\n", session->param.qos[qos_flow_index].fiveQI); ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CauseRadioNetwork_not_supported_5QI_value}; - ue_p->pduSession[i].status = PDU_SESSION_STATUS_FAILED; - ue_p->pduSession[i].xid = xid; - ue_p->pduSession[i].cause = cause; + session->status = PDU_SESSION_STATUS_FAILED; + session->xid = xid; + session->cause = cause; continue; } - LOG_I(NR_RRC, - "index %d, QOS flow %d, 5QI %ld \n", - i, - qos_flow_index, - ue_p->pduSession[i].param.qos[qos_flow_index].fiveQI); + LOG_I(NR_RRC, "index %d, QOS flow %d, 5QI %ld \n", i, qos_flow_index, session->param.qos[qos_flow_index].fiveQI); } - ue_p->pduSession[i].status = PDU_SESSION_STATUS_DONE; - ue_p->pduSession[i].xid = xid; + session->status = PDU_SESSION_STATUS_DONE; + session->xid = xid; - if (ue_p->pduSession[i].param.nas_pdu.buffer != NULL) { + if (session->param.nas_pdu.buf != NULL) { asn1cSequenceAdd(dedicatedNAS_MessageList->list,NR_DedicatedNAS_Message_t, dedicatedNAS_Message); - OCTET_STRING_fromBuf(dedicatedNAS_Message, (char *)ue_p->pduSession[i].param.nas_pdu.buffer, ue_p->pduSession[i].param.nas_pdu.length); - LOG_I(NR_RRC, "add NAS info with size %d (pdusession id %d)\n", ue_p->pduSession[i].param.nas_pdu.length, ue_p->pduSession[i].param.pdusession_id); + OCTET_STRING_fromBuf(dedicatedNAS_Message, (char *)session->param.nas_pdu.buf, session->param.nas_pdu.len); + LOG_I(NR_RRC, "add NAS info with size %ld (pdusession id %d)\n", session->param.nas_pdu.len, session->param.pdusession_id); } } @@ -790,7 +775,7 @@ void rrc_gNB_modify_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t /* Free all NAS PDUs */ for (int i = 0; i < ue_p->nb_of_pdusessions; i++) - clear_nas_pdu(&ue_p->pduSession[i].param.nas_pdu); + FREE_AND_ZERO_BYTE_ARRAY(ue_p->pduSession[i].param.nas_pdu); LOG_I(NR_RRC, "UE %d: Generate RRCReconfiguration (bytes %d)\n", ue_p->rrc_ue_id, size); const uint32_t msg_id = NR_DL_DCCH_MessageType__c1_PR_rrcReconfiguration; @@ -1571,21 +1556,21 @@ static int handle_rrcReestablishmentComplete(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE */ void rrc_forward_ue_nas_message(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE) { - if (UE->nas_pdu.buffer == NULL || UE->nas_pdu.length == 0) + if (UE->nas_pdu.buf == NULL || UE->nas_pdu.len == 0) return; // no problem: the UE will re-request a NAS PDU - LOG_UE_DL_EVENT(UE, "Send DL Information Transfer [%d bytes]\n", UE->nas_pdu.length); + LOG_UE_DL_EVENT(UE, "Send DL Information Transfer [%ld bytes]\n", UE->nas_pdu.len); uint8_t buffer[4096]; unsigned int xid = rrc_gNB_get_next_transaction_identifier(rrc->module_id); - uint32_t length = do_NR_DLInformationTransfer(buffer, sizeof(buffer), xid, UE->nas_pdu.length, UE->nas_pdu.buffer); + uint32_t length = do_NR_DLInformationTransfer(buffer, sizeof(buffer), xid, UE->nas_pdu.len, UE->nas_pdu.buf); LOG_DUMPMSG(NR_RRC, DEBUG_RRC, buffer, length, "[MSG] RRC DL Information Transfer\n"); rb_id_t srb_id = UE->Srb[2].Active ? DL_SCH_LCID_DCCH1 : DL_SCH_LCID_DCCH; const uint32_t msg_id = NR_DL_DCCH_MessageType__c1_PR_dlInformationTransfer; nr_rrc_transfer_protected_rrc_message(rrc, UE, srb_id, msg_id, buffer, length); - // no need to free UE->nas_pdu.buffer, do_NR_DLInformationTransfer() did that - UE->nas_pdu.buffer = NULL; - UE->nas_pdu.length = 0; + // no need to free UE->nas_pdu.buf, do_NR_DLInformationTransfer() did that + UE->nas_pdu.buf = NULL; + UE->nas_pdu.len = 0; } static void handle_ueCapabilityInformation(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const NR_UECapabilityInformation_t *ue_cap_info) diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 6d0264152a..82aa7b5a86 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -148,67 +148,78 @@ void nr_rrc_pdcp_config_security(gNB_RRC_UE_t *UE, bool enable_ciphering) nr_pdcp_config_set_security(UE->rrc_ue_id, DL_SCH_LCID_DCCH, true, &security_parameters); } -//------------------------------------------------------------------------------ -/* -* Initial UE NAS message on S1AP. -*/ +/** @brief Process AMF Identifier and fill GUAMI struct members */ +static nr_guami_t get_guami(const uint32_t amf_Id, const plmn_id_t plmn) +{ + nr_guami_t guami = {0}; + guami.amf_region_id = (amf_Id >> 16) & 0xff; + guami.amf_set_id = (amf_Id >> 6) & 0x3ff; + guami.amf_pointer = amf_Id & 0x3f; + guami.mcc = plmn.mcc; + guami.mnc = plmn.mnc; + guami.mnc_len = plmn.mnc_digit_length; + return guami; +} + +/** + * @brief Prepare the Initial UE Message (Uplink NAS) to be forwarded to the AMF over N2 + * extracts NAS PDU, Selected PLMN and Registered AMF from the RRCSetupComplete + */ void rrc_gNB_send_NGAP_NAS_FIRST_REQ(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, NR_RRCSetupComplete_IEs_t *rrcSetupComplete) -//------------------------------------------------------------------------------ { MessageDef *message_p = itti_alloc_new_message(TASK_RRC_GNB, rrc->module_id, NGAP_NAS_FIRST_REQ); ngap_nas_first_req_t *req = &NGAP_NAS_FIRST_REQ(message_p); memset(req, 0, sizeof(*req)); + // RAN UE NGAP ID req->gNB_ue_ngap_id = UE->rrc_ue_id; + // RRC Establishment Cause /* Assume that cause is coded in the same way in RRC and NGap, just check that the value is in NGap range */ AssertFatal(UE->establishment_cause < NGAP_RRC_CAUSE_LAST, "Establishment cause invalid (%jd/%d)!", UE->establishment_cause, NGAP_RRC_CAUSE_LAST); req->establishment_cause = UE->establishment_cause; - /* Forward NAS message */ - req->nas_pdu.length = rrcSetupComplete->dedicatedNAS_Message.size; - req->nas_pdu.buffer = malloc(req->nas_pdu.length); - AssertFatal(req->nas_pdu.buffer != NULL, "out of memory\n"); - memcpy(req->nas_pdu.buffer, rrcSetupComplete->dedicatedNAS_Message.buf, req->nas_pdu.length); - // extract_imsi(NGAP_NAS_FIRST_REQ (message_p).nas_pdu.buffer, - // NGAP_NAS_FIRST_REQ (message_p).nas_pdu.length, - // ue_context_pP); + // NAS-PDU + req->nas_pdu = create_byte_array(rrcSetupComplete->dedicatedNAS_Message.size, rrcSetupComplete->dedicatedNAS_Message.buf); - /* selected_plmn_identity: IE is 1-based, convert to 0-based (C array) */ - int selected_plmn_identity = rrcSetupComplete->selectedPLMN_Identity - 1; - if (selected_plmn_identity != 0) - LOG_E(NGAP, "UE %u: sent selected PLMN identity %ld, but only one PLMN supported\n", req->gNB_ue_ngap_id, rrcSetupComplete->selectedPLMN_Identity); + /* Selected PLMN Identity (Optional) + * selectedPLMN-Identity in RRCSetupComplete: Index of the PLMN selected by the UE from the plmn-IdentityInfoList (SIB1) + * Selected PLMN Identity in INITIAL UE MESSAGE: Indicates the selected PLMN id for the non-3GPP access.*/ + if (rrcSetupComplete->selectedPLMN_Identity > rrc->configuration.num_plmn) { + LOG_E(NGAP, + "Failed to send Initial UE Message: selected PLMN (%ld) identity is out of bounds (%d)\n", + rrcSetupComplete->selectedPLMN_Identity, + rrc->configuration.num_plmn); + return; + } + int selected_plmn_identity = rrcSetupComplete->selectedPLMN_Identity - 1; // Convert 1-based PLMN Identity IE to 0-based index + req->plmn = rrc->configuration.plmn[selected_plmn_identity]; // Select from the stored list + LOG_I(NGAP, "Selected PLMN in the NG Initial UE Message: MCC %u, MNC %u\n", req->plmn.mcc, req->plmn.mnc); - req->selected_plmn_identity = 0; /* always zero because we only support one */ - - /* Fill UE identities with available information */ + /* 5G-S-TMSI */ if (UE->Initialue_identity_5g_s_TMSI.presence) { - /* Fill s-TMSI */ - req->ue_identity.presenceMask = NGAP_UE_IDENTITIES_FiveG_s_tmsi; + req->ue_identity.presenceMask |= NGAP_UE_IDENTITIES_FiveG_s_tmsi; req->ue_identity.s_tmsi.amf_set_id = UE->Initialue_identity_5g_s_TMSI.amf_set_id; req->ue_identity.s_tmsi.amf_pointer = UE->Initialue_identity_5g_s_TMSI.amf_pointer; req->ue_identity.s_tmsi.m_tmsi = UE->Initialue_identity_5g_s_TMSI.fiveg_tmsi; - } else if (rrcSetupComplete->registeredAMF != NULL) { + } + + /* Process Registered AMF IE */ + if (rrcSetupComplete->registeredAMF != NULL) { + /* Fetch the AMF-Identifier from the registeredAMF IE + * The IE AMF-Identifier (AMFI) comprises of an AMF Region ID (8b), + * an AMF Set ID (10b) and an AMF Pointer (6b) + * as specified in TS 23.003 [21], clause 2.10.1. */ NR_RegisteredAMF_t *r_amf = rrcSetupComplete->registeredAMF; - req->ue_identity.presenceMask = NGAP_UE_IDENTITIES_guami; - - /* The IE AMF-Identifier (AMFI) comprises of an AMF Region ID (8b), an AMF Set ID (10b) and an AMF Pointer (6b) as specified in TS 23.003 [21], clause 2.10.1. */ + req->ue_identity.presenceMask |= NGAP_UE_IDENTITIES_guami; uint32_t amf_Id = BIT_STRING_to_uint32(&r_amf->amf_Identifier); - req->ue_identity.guami.amf_region_id = (amf_Id >> 16) & 0xff; - req->ue_identity.guami.amf_set_id = (amf_Id >> 6) & 0x3ff; - req->ue_identity.guami.amf_pointer = amf_Id & 0x3f; - - UE->ue_guami.amf_region_id = req->ue_identity.guami.amf_region_id; - UE->ue_guami.amf_set_id = req->ue_identity.guami.amf_set_id; - UE->ue_guami.amf_pointer = req->ue_identity.guami.amf_pointer; - + UE->ue_guami = req->ue_identity.guami = get_guami(amf_Id, req->plmn); LOG_I(NGAP, - "Build NGAP_NAS_FIRST_REQ adding in s_TMSI: GUAMI amf_set_id %u amf_region_id %u ue %x\n", + "GUAMI in NGAP_NAS_FIRST_REQ (UE %04x): AMF Set ID %u, Region ID %u, Pointer %u\n", + UE->rnti, req->ue_identity.guami.amf_set_id, req->ue_identity.guami.amf_region_id, - UE->rnti); - } else { - req->ue_identity.presenceMask = NGAP_UE_IDENTITIES_NONE; + req->ue_identity.guami.amf_pointer); } itti_send_msg_to_task(TASK_NGAP, rrc->module_id, message_p); @@ -247,8 +258,13 @@ static int decodePDUSessionResourceSetup(pdusession_t *session) { NGAP_PDUSessionResourceSetupRequestTransfer_t *pdusessionTransfer = NULL; asn_codec_ctx_t st = {.max_stack_size = 100 * 1000}; - asn_dec_rval_t dec_rval = - aper_decode(&st, &asn_DEF_NGAP_PDUSessionResourceSetupRequestTransfer, (void **)&pdusessionTransfer, session->pdusessionTransfer.buffer, session->pdusessionTransfer.length, 0, 0); + asn_dec_rval_t dec_rval = aper_decode(&st, + &asn_DEF_NGAP_PDUSessionResourceSetupRequestTransfer, + (void **)&pdusessionTransfer, + session->pdusessionTransfer.buf, + session->pdusessionTransfer.len, + 0, + 0); if (dec_rval.code != RC_OK) { LOG_E(NR_RRC, "can not decode PDUSessionResourceSetupRequestTransfer\n"); @@ -491,14 +507,8 @@ int rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, instance_t UE->amf_ue_ngap_id = req->amf_ue_ngap_id; - /* store guami in gNB_RRC_UE_t context; - * we copy individual members because the guami types are different (nr_rrc_guami_t and ngap_guami_t) */ - UE->ue_guami.mcc = req->guami.mcc; - UE->ue_guami.mnc = req->guami.mnc; - UE->ue_guami.mnc_len = req->guami.mnc_len; - UE->ue_guami.amf_region_id = req->guami.amf_region_id; - UE->ue_guami.amf_set_id = req->guami.amf_set_id; - UE->ue_guami.amf_pointer = req->guami.amf_pointer; + // Directly copy the entire guami structure + UE->ue_guami = req->guami; /* NAS PDU */ // this is malloced pointers, we pass it for later free() @@ -713,8 +723,7 @@ int rrc_gNB_process_NGAP_DOWNLINK_NAS(MessageDef *msg_p, instance_t instance, mu msg_fail_p = itti_alloc_new_message(TASK_RRC_GNB, 0, NGAP_NAS_NON_DELIVERY_IND); ngap_nas_non_delivery_ind_t *msg = &NGAP_NAS_NON_DELIVERY_IND(msg_fail_p); msg->gNB_ue_ngap_id = req->gNB_ue_ngap_id; - msg->nas_pdu.length = req->nas_pdu.length; - msg->nas_pdu.buffer = req->nas_pdu.buffer; + msg->nas_pdu = req->nas_pdu; // TODO add failure cause when defined! itti_send_msg_to_task(TASK_NGAP, instance, msg_fail_p); return (-1); @@ -746,8 +755,8 @@ void rrc_gNB_send_NGAP_UPLINK_NAS(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const NR_ memcpy(buf, nas->buf, nas->size); MessageDef *msg_p = itti_alloc_new_message(TASK_RRC_GNB, rrc->module_id, NGAP_UPLINK_NAS); NGAP_UPLINK_NAS(msg_p).gNB_ue_ngap_id = UE->rrc_ue_id; - NGAP_UPLINK_NAS(msg_p).nas_pdu.length = nas->size; - NGAP_UPLINK_NAS(msg_p).nas_pdu.buffer = buf; + NGAP_UPLINK_NAS(msg_p).nas_pdu.len = nas->size; + NGAP_UPLINK_NAS(msg_p).nas_pdu.buf = buf; itti_send_msg_to_task(TASK_NGAP, rrc->module_id, msg_p); } @@ -972,10 +981,16 @@ static void fill_qos2(NGAP_QosFlowAddOrModifyRequestList_t *qos, pdusession_t *s session->nb_qos = qos->list.count; } -static void decodePDUSessionResourceModify(pdusession_t *param, const ngap_pdu_t pdu) +static void decodePDUSessionResourceModify(pdusession_t *param, const byte_array_t pdu) { NGAP_PDUSessionResourceModifyRequestTransfer_t *pdusessionTransfer = NULL; - asn_dec_rval_t dec_rval = aper_decode(NULL, &asn_DEF_NGAP_PDUSessionResourceModifyRequestTransfer, (void **)&pdusessionTransfer, pdu.buffer, pdu.length, 0, 0); + asn_dec_rval_t dec_rval = aper_decode(NULL, + &asn_DEF_NGAP_PDUSessionResourceModifyRequestTransfer, + (void **)&pdusessionTransfer, + pdu.buf, + pdu.len, + 0, + 0); if (dec_rval.code != RC_OK) { LOG_E(NR_RRC, "could not decode PDUSessionResourceModifyRequestTransfer\n"); @@ -1074,7 +1089,7 @@ int rrc_gNB_process_NGAP_PDUSESSION_MODIFY_REQ(MessageDef *msg_p, instance_t ins sess->status = PDU_SESSION_STATUS_NEW; sess->param.pdusession_id = sessMod->pdusession_id; sess->cause.type = NGAP_CAUSE_NOTHING; - if (sessMod->nas_pdu.buffer != NULL) { + if (sessMod->nas_pdu.buf != NULL) { UE->pduSession[i].param.nas_pdu = sessMod->nas_pdu; } // Save new pdu session parameters, qos, upf addr, teid @@ -1347,8 +1362,8 @@ void rrc_gNB_send_NGAP_UE_CAPABILITIES_IND(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, ngap_ue_cap_info_ind_t *ind = &NGAP_UE_CAPABILITIES_IND(msg_p); memset(ind, 0, sizeof(*ind)); ind->gNB_ue_ngap_id = UE->rrc_ue_id; - ind->ue_radio_cap.length = encoded; - ind->ue_radio_cap.buffer = buf2; + ind->ue_radio_cap.len = encoded; + ind->ue_radio_cap.buf = buf2; itti_send_msg_to_task (TASK_NGAP, rrc->module_id, msg_p); LOG_I(NR_RRC,"Send message to ngap: NGAP_UE_CAPABILITIES_IND\n"); } @@ -1427,7 +1442,7 @@ int rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND(MessageDef *msg_p, instance_ if (found) { // TODO RRCReconfiguration To UE LOG_I(NR_RRC, "Send RRCReconfiguration To UE \n"); - rrc_gNB_generate_dedicatedRRCReconfiguration_release(rrc, UE, xid, cmd->nas_pdu.length, cmd->nas_pdu.buffer); + rrc_gNB_generate_dedicatedRRCReconfiguration_release(rrc, UE, xid, cmd->nas_pdu.len, cmd->nas_pdu.buf); } else { // gtp tunnel delete LOG_I(NR_RRC, "gtp tunnel delete all tunnels for UE %04x\n", UE->rnti); diff --git a/openair2/RRC/NR/rrc_gNB_nsa.c b/openair2/RRC/NR/rrc_gNB_nsa.c index 120a400bbf..deabe38327 100644 --- a/openair2/RRC/NR/rrc_gNB_nsa.c +++ b/openair2/RRC/NR/rrc_gNB_nsa.c @@ -40,7 +40,6 @@ #include #include "MESSAGES/asn1_msg.h" #include "OCTET_STRING.h" -#include "RRC/NR/nr_rrc_config.h" #include "T.h" #include "asn_codecs.h" #include "asn_internal.h" diff --git a/openair3/NGAP/ngap_gNB_handlers.c b/openair3/NGAP/ngap_gNB_handlers.c index 97f15ef658..ad8efce5a3 100644 --- a/openair3/NGAP/ngap_gNB_handlers.c +++ b/openair3/NGAP/ngap_gNB_handlers.c @@ -52,15 +52,6 @@ #include "oai_asn1.h" #include "queue.h" -static void allocCopy(ngap_pdu_t *out, OCTET_STRING_t in) -{ - if (in.size) { - out->buffer = malloc(in.size); - memcpy(out->buffer, in.buf, in.size); - } - out->length = in.size; -} - char *ngap_direction2String(int ngap_dir) { static char *ngap_direction_String[] = { "", /* Nothing */ @@ -145,6 +136,36 @@ static int ngap_gNB_handle_ng_setup_failure(sctp_assoc_t assoc_id, uint32_t stre return 0; } +static void ngap_dump_served_guami(const ngap_gNB_amf_data_t *amf_desc_p) +{ + const struct served_guami_s *guami_p; + const struct plmn_identity_s *plmn_p; + const struct served_region_id_s *region_p; + const struct amf_set_id_s *set_id_p; + const struct amf_pointer_s *pointer_p; + + NGAP_DEBUG("Served GUAMIs for AMF %s (assoc_id=%d):\n", + amf_desc_p->amf_name ? amf_desc_p->amf_name : "(no name)", + amf_desc_p->assoc_id); + + STAILQ_FOREACH(guami_p, &amf_desc_p->served_guami, next) + { + NGAP_DEBUG(" GUAMI:\n"); + STAILQ_FOREACH(plmn_p, &guami_p->served_plmns, next) { + NGAP_DEBUG(" PLMN: MCC=%03d, MNC=%0*d\n", plmn_p->mcc, plmn_p->mnc_digit_length, plmn_p->mnc); + } + STAILQ_FOREACH(region_p, &guami_p->served_region_ids, next) { + NGAP_DEBUG(" AMF Region ID: %d\n", region_p->amf_region_id); + } + STAILQ_FOREACH(set_id_p, &guami_p->amf_set_ids, next) { + NGAP_DEBUG(" AMF Set ID: %d\n", set_id_p->amf_set_id); + } + STAILQ_FOREACH(pointer_p, &guami_p->amf_pointers, next) { + NGAP_DEBUG(" AMF Pointer: %d\n", pointer_p->amf_pointer); + } + } +} + static int ngap_gNB_handle_ng_setup_response(sctp_assoc_t assoc_id, uint32_t stream, NGAP_NGAP_PDU_t *pdu) { NGAP_NGSetupResponse_t *container; @@ -173,7 +194,6 @@ static int ngap_gNB_handle_ng_setup_response(sctp_assoc_t assoc_id, uint32_t str /* The list of served guami can contain at most 256 elements. * NR related guami is the first element in the list, i.e with an id of 0. */ - NGAP_DEBUG("servedGUAMIs.list.count %d\n", ie->value.choice.ServedGUAMIList.list.count); DevAssert(ie->value.choice.ServedGUAMIList.list.count > 0); DevAssert(ie->value.choice.ServedGUAMIList.list.count <= NGAP_maxnoofServedGUAMIs); @@ -197,32 +217,27 @@ static int ngap_gNB_handle_ng_setup_response(sctp_assoc_t assoc_id, uint32_t str STAILQ_INSERT_TAIL(&new_guami_p->served_plmns, new_plmn_identity_p, next); new_guami_p->nb_served_plmns++; - NGAP_AMFRegionID_t *amf_region_id_p; struct served_region_id_s *new_region_id_p; - amf_region_id_p = &guami_item_p->gUAMI.aMFRegionID; new_region_id_p = calloc(1, sizeof(struct served_region_id_s)); - OCTET_STRING_TO_INT8(amf_region_id_p, new_region_id_p->amf_region_id); + new_region_id_p->amf_region_id = BIT_STRING_to_uint8(&guami_item_p->gUAMI.aMFRegionID); STAILQ_INSERT_TAIL(&new_guami_p->served_region_ids, new_region_id_p, next); new_guami_p->nb_region_id++; - NGAP_AMFSetID_t *amf_set_id_p; struct amf_set_id_s *new_amf_set_id_p; - amf_set_id_p = &guami_item_p->gUAMI.aMFSetID; new_amf_set_id_p = calloc(1, sizeof(struct amf_set_id_s)); - OCTET_STRING_TO_INT16(amf_set_id_p, new_amf_set_id_p->amf_set_id); + new_amf_set_id_p->amf_set_id = BIT_STRING_to_uint16(&guami_item_p->gUAMI.aMFSetID); STAILQ_INSERT_TAIL(&new_guami_p->amf_set_ids, new_amf_set_id_p, next); new_guami_p->nb_amf_set_id++; - NGAP_AMFPointer_t *amf_pointer_p; struct amf_pointer_s *new_amf_pointer_p; - amf_pointer_p = &guami_item_p->gUAMI.aMFPointer; new_amf_pointer_p = calloc(1, sizeof(struct amf_pointer_s)); - OCTET_STRING_TO_INT8(amf_pointer_p, new_amf_pointer_p->amf_pointer); + new_amf_pointer_p->amf_pointer = BIT_STRING_to_uint8(&guami_item_p->gUAMI.aMFPointer); STAILQ_INSERT_TAIL(&new_guami_p->amf_pointers, new_amf_pointer_p, next); new_guami_p->nb_amf_pointer++; STAILQ_INSERT_TAIL(&amf_desc_p->served_guami, new_guami_p, next); } + ngap_dump_served_guami(amf_desc_p); /* Set the capacity of this AMF */ NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_NGSetupResponseIEs_t, ie, container, @@ -245,13 +260,12 @@ static int ngap_gNB_handle_ng_setup_response(sctp_assoc_t assoc_id, uint32_t str NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_NGSetupResponseIEs_t, ie, container, NGAP_ProtocolIE_ID_id_PLMNSupportList, true); - NGAP_DEBUG("PLMNSupportList.list.count %d\n", ie->value.choice.PLMNSupportList.list.count); DevAssert(ie->value.choice.PLMNSupportList.list.count > 0); DevAssert(ie->value.choice.PLMNSupportList.list.count <= NGAP_maxnoofPLMNs); STAILQ_INIT(&amf_desc_p->plmn_supports); - for (i = 0; i < ie->value.choice.ServedGUAMIList.list.count; i++) { + for (i = 0; i < ie->value.choice.PLMNSupportList.list.count; i++) { NGAP_PLMNSupportItem_t *plmn_support_item_p; struct plmn_support_s *new_plmn_support_p; NGAP_SliceSupportItem_t *slice_support_item_p; @@ -260,11 +274,10 @@ static int ngap_gNB_handle_ng_setup_response(sctp_assoc_t assoc_id, uint32_t str plmn_support_item_p = ie->value.choice.PLMNSupportList.list.array[i]; new_plmn_support_p = calloc(1, sizeof(struct plmn_support_s)); - - TBCD_TO_MCC_MNC(&plmn_support_item_p->pLMNIdentity, new_plmn_support_p->plmn_identity.mcc, - new_plmn_support_p->plmn_identity.mnc, new_plmn_support_p->plmn_identity.mnc_digit_length); - NGAP_DEBUG("PLMNSupportList.list.count %d\n", plmn_support_item_p->sliceSupportList.list.count); + struct plmn_identity_s *plmn = &new_plmn_support_p->plmn_identity; + TBCD_TO_MCC_MNC(&plmn_support_item_p->pLMNIdentity, plmn->mcc, plmn->mnc, plmn->mnc_digit_length); + NGAP_INFO("Supported PLMN %d: MCC=%03d MNC=%0*d\n", i, plmn->mcc, plmn->mnc_digit_length, plmn->mnc); DevAssert(plmn_support_item_p->sliceSupportList.list.count > 0); DevAssert(plmn_support_item_p->sliceSupportList.list.count <= NGAP_maxnoofSliceItems); @@ -282,6 +295,12 @@ static int ngap_gNB_handle_ng_setup_response(sctp_assoc_t assoc_id, uint32_t str new_slice_support_p->sD[1] = slice_support_item_p->s_NSSAI.sD->buf[1]; new_slice_support_p->sD[2] = slice_support_item_p->s_NSSAI.sD->buf[2]; } + NGAP_INFO("Supported slice (PLMN %d): SST=0x%02x SD=%d%d%d\n", + i, + new_slice_support_p->sST, + new_slice_support_p->sD[0], + new_slice_support_p->sD[1], + new_slice_support_p->sD[2]); STAILQ_INSERT_TAIL(&new_plmn_support_p->slice_supports, new_slice_support_p, next); } @@ -772,9 +791,10 @@ static int ngap_gNB_handle_initial_context_request(sctp_assoc_t assoc_id, uint32 } if (item_p->nAS_PDU) { - allocCopy(&msg->pdusession_param[i].nas_pdu, *item_p->nAS_PDU); + msg->pdusession_param[i].nas_pdu = create_byte_array(item_p->nAS_PDU->size, item_p->nAS_PDU->buf); } - allocCopy(&msg->pdusession_param[i].pdusessionTransfer, item_p->pDUSessionResourceSetupRequestTransfer); + OCTET_STRING_t *transfer = &item_p->pDUSessionResourceSetupRequestTransfer; + msg->pdusession_param[i].pdusessionTransfer = create_byte_array(transfer->size, transfer->buf); } } @@ -841,7 +861,7 @@ static int ngap_gNB_handle_initial_context_request(sctp_assoc_t assoc_id, uint32 NGAP_ProtocolIE_ID_id_NAS_PDU, false); if (ie) - allocCopy(&msg->nas_pdu, ie->value.choice.NAS_PDU); + msg->nas_pdu = create_byte_array(ie->value.choice.NAS_PDU.size, ie->value.choice.NAS_PDU.buf); itti_send_msg_to_task(TASK_RRC_GNB, ue_desc_p->gNB_instance->instance, message_p); @@ -985,9 +1005,9 @@ static int ngap_gNB_handle_pdusession_setup_request(sctp_assoc_t assoc_id, uint3 } else { msg->pdusession_setup_params[i].nssai.sd = 0xffffff; } - - allocCopy(&msg->pdusession_setup_params[i].nas_pdu, *item_p->pDUSessionNAS_PDU); - allocCopy(&msg->pdusession_setup_params[i].pdusessionTransfer, item_p->pDUSessionResourceSetupRequestTransfer); + OCTET_STRING_t *transfer = &item_p->pDUSessionResourceSetupRequestTransfer; + msg->pdusession_setup_params[i].nas_pdu = create_byte_array(item_p->pDUSessionNAS_PDU->size, item_p->pDUSessionNAS_PDU->buf); + msg->pdusession_setup_params[i].pdusessionTransfer = create_byte_array(transfer->size, transfer->buf); } itti_send_msg_to_task(TASK_RRC_GNB, ue_desc_p->gNB_instance->instance, message_p); @@ -1164,8 +1184,9 @@ static int ngap_gNB_handle_pdusession_modify_request(sctp_assoc_t assoc_id, uint // check for the NAS PDU if (item_p->nAS_PDU != NULL && item_p->nAS_PDU->size > 0) { - allocCopy(&msg->pdusession_modify_params[i].nas_pdu, *item_p->nAS_PDU); - allocCopy(&msg->pdusession_modify_params[i].pdusessionTransfer, item_p->pDUSessionResourceModifyRequestTransfer); + msg->pdusession_modify_params[i].nas_pdu = create_byte_array(item_p->nAS_PDU->size, item_p->nAS_PDU->buf); + OCTET_STRING_t *transfer = &item_p->pDUSessionResourceModifyRequestTransfer; + msg->pdusession_modify_params[i].pdusessionTransfer = create_byte_array(transfer->size, transfer->buf); } else { LOG_W(NGAP, "received pdu session modify with void content for UE %u, pdu session %lu\n", msg->gNB_ue_ngap_id, item_p->pDUSessionID); continue; @@ -1241,7 +1262,7 @@ static int ngap_gNB_handle_pdusession_release_command(sctp_assoc_t assoc_id, uin NGAP_ProtocolIE_ID_id_NAS_PDU, false); if (ie) - allocCopy(&msg->nas_pdu, ie->value.choice.NAS_PDU); + msg->nas_pdu = create_byte_array(ie->value.choice.NAS_PDU.size, ie->value.choice.NAS_PDU.buf); /* id-PDUSessionResourceToReleaseListRelCmd */ NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_PDUSessionResourceReleaseCommandIEs_t, ie, container, @@ -1252,8 +1273,9 @@ static int ngap_gNB_handle_pdusession_release_command(sctp_assoc_t assoc_id, uin for (i = 0; i < ie->value.choice.PDUSessionResourceToReleaseListRelCmd.list.count; i++) { NGAP_PDUSessionResourceToReleaseItemRelCmd_t *item_p; item_p = ie->value.choice.PDUSessionResourceToReleaseListRelCmd.list.array[i]; - msg->pdusession_release_params[i].pdusession_id = item_p->pDUSessionID; - allocCopy(&msg->pdusession_release_params[i].data, item_p->pDUSessionResourceReleaseCommandTransfer); + pdusession_release_t *r = &msg->pdusession_release_params[i]; + r->pdusession_id = item_p->pDUSessionID; + r->data = create_byte_array(item_p->pDUSessionResourceReleaseCommandTransfer.size, item_p->pDUSessionResourceReleaseCommandTransfer.buf); } itti_send_msg_to_task(TASK_RRC_GNB, ue_desc_p->gNB_instance->instance, message_p); diff --git a/openair3/NGAP/ngap_gNB_itti_messaging.c b/openair3/NGAP/ngap_gNB_itti_messaging.c index 87eb93c8f6..b640f2e556 100644 --- a/openair3/NGAP/ngap_gNB_itti_messaging.c +++ b/openair3/NGAP/ngap_gNB_itti_messaging.c @@ -64,9 +64,7 @@ void ngap_gNB_itti_send_nas_downlink_ind(instance_t instance, uint32_t gNB_ue_ng ngap_downlink_nas = &message_p->ittiMsg.ngap_downlink_nas; ngap_downlink_nas->gNB_ue_ngap_id = gNB_ue_ngap_id; - ngap_downlink_nas->nas_pdu.buffer = malloc(sizeof(uint8_t) * nas_pdu_length); - memcpy(ngap_downlink_nas->nas_pdu.buffer, nas_pdu, nas_pdu_length); - ngap_downlink_nas->nas_pdu.length = nas_pdu_length; + ngap_downlink_nas->nas_pdu = create_byte_array(nas_pdu_length, nas_pdu); itti_send_msg_to_task(TASK_RRC_GNB, instance, message_p); } diff --git a/openair3/NGAP/ngap_gNB_management_procedures.c b/openair3/NGAP/ngap_gNB_management_procedures.c index 9615dc6b2a..e82fd1401b 100644 --- a/openair3/NGAP/ngap_gNB_management_procedures.c +++ b/openair3/NGAP/ngap_gNB_management_procedures.c @@ -38,6 +38,7 @@ #include "ngap_gNB_defs.h" #include "queue.h" #include "tree.h" +#include "ds/byte_array.h" static ngap_gNB_internal_data_t ngap_gNB_internal_data; diff --git a/openair3/NGAP/ngap_gNB_management_procedures.h b/openair3/NGAP/ngap_gNB_management_procedures.h index fa62f53382..d71480da30 100644 --- a/openair3/NGAP/ngap_gNB_management_procedures.h +++ b/openair3/NGAP/ngap_gNB_management_procedures.h @@ -28,6 +28,8 @@ * @ingroup _ngap */ +#include "ds/byte_array.h" + #ifndef NGAP_GNB_MANAGEMENT_PROCEDURES_H_ #define NGAP_GNB_MANAGEMENT_PROCEDURES_H_ diff --git a/openair3/NGAP/ngap_gNB_nas_procedures.c b/openair3/NGAP/ngap_gNB_nas_procedures.c index a86ba83442..7729ffa4f2 100644 --- a/openair3/NGAP/ngap_gNB_nas_procedures.c +++ b/openair3/NGAP/ngap_gNB_nas_procedures.c @@ -58,15 +58,6 @@ #include "s1ap_messages_types.h" #include "xer_encoder.h" -static void allocCopy(OCTET_STRING_t *out, ngap_pdu_t in) -{ - if (in.length) { - out->buf = malloc(in.length); - memcpy(out->buf, in.buffer, in.length); - } - out->size = in.length; -} - static void allocAddrCopy(BIT_STRING_t *out, transport_layer_addr_t in) { if (in.length) { @@ -77,20 +68,106 @@ static void allocAddrCopy(BIT_STRING_t *out, transport_layer_addr_t in) } } -//------------------------------------------------------------------------------ -int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEfirstReq) -//------------------------------------------------------------------------------ +/** @brief Selects the AMF instance for a given UE based on identity information. + * It attempts to select an AMF using the following prioritized criteria: + * 1. GUAMI, if provided and valid (via Region ID, Set ID, Pointer). + * 2. 5G-S-TMSI, using AMF Set ID if GUAMI is unavailable or unusable. + * 3. Selected PLMN identity and local PLMN configuration. + * 4. Fallback to AMF with highest relative capacity, considering load balancing. + * @ref AMF Discovery and Selection (3GPP TS 23.501 clause 6.3.5) */ +static ngap_gNB_amf_data_t *select_amf(ngap_gNB_instance_t *instance_p, const ngap_nas_first_req_t *msg) { - ngap_gNB_instance_t *instance_p = NULL; - struct ngap_gNB_amf_data_s *amf_desc_p = NULL; - NGAP_NGAP_PDU_t pdu; - uint8_t *buffer = NULL; - uint32_t length = 0; + ngap_gNB_amf_data_t *amf = NULL; + + // Select the AMF corresponding to the GUAMI from the RegisteredAMF IE + if (msg->ue_identity.presenceMask & NGAP_UE_IDENTITIES_guami) { + const nr_guami_t *guami = &msg->ue_identity.guami; + NGAP_DEBUG("GUAMI is present: MCC=%03d MNC=%03d RegionID=%d SetID=%d Pointer=%d\n", + guami->mcc, + guami->mnc, + guami->amf_region_id, + guami->amf_set_id, + guami->amf_pointer); + amf = ngap_gNB_nnsf_select_amf_by_guami(instance_p, msg->establishment_cause, *guami); + if (amf) { + NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through GUAMI MCC %d MNC %d AMFRI %d AMFSI %d AMFPT %d\n", + msg->gNB_ue_ngap_id, + amf->amf_name, + amf->assoc_id, + guami->mcc, + guami->mnc, + guami->amf_region_id, + guami->amf_set_id, + guami->amf_pointer); + return amf; + } + } + + // Select the AMF corresponding to the provided 5G-S-TMSI + if (amf == NULL) { + if (msg->ue_identity.presenceMask & NGAP_UE_IDENTITIES_FiveG_s_tmsi) { + const fiveg_s_tmsi_t *fgs_tmsi = &msg->ue_identity.s_tmsi; + amf = ngap_gNB_nnsf_select_amf_by_amf_setid(instance_p, msg->establishment_cause, msg->plmn, fgs_tmsi->amf_set_id); + if (amf) { + NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through S-TMSI AMFSI %d and selected PLMN MCC %d MNC %d\n", + msg->gNB_ue_ngap_id, + amf->amf_name, + amf->assoc_id, + fgs_tmsi->amf_set_id, + msg->plmn.mcc, + msg->plmn.mnc); + return amf; + } + } + } + + // No UE identity (5G-S-TMSI or GUAMI) is present + if (msg->ue_identity.presenceMask == 0) { + // Select the AMF based on the selected PLMN identity received through RRCSetupComplete + amf = ngap_gNB_nnsf_select_amf_by_plmn_id(instance_p, msg->establishment_cause, msg->plmn); + if (amf) { + NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through selected PLMN MCC %d MNC %d\n", + msg->gNB_ue_ngap_id, + amf->amf_name, + amf->assoc_id, + msg->plmn.mcc, + msg->plmn.mnc); + return amf; + } else { + // Select the AMF with the highest capacity + amf = ngap_gNB_nnsf_select_amf(instance_p, msg->establishment_cause); + if (amf) { + NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through highest relative capacity\n", msg->gNB_ue_ngap_id, amf->amf_name, amf->assoc_id); + return amf; + } + } + } + + return amf; +} + +/** @brief NAS Transport Messages: Initial UE Message + * forward the first received (layer 3) uplink NAS message + * from the radio interface to the AMF over N2 + * NG-RAN node -> AMF (9.2.5.1, 3GPP TS 38.413) */ +int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEfirstReq) +{ + NGAP_NGAP_PDU_t pdu = {0}; + uint8_t *buffer = NULL; + uint32_t length = 0; DevAssert(UEfirstReq != NULL); /* Retrieve the NGAP gNB instance associated with Mod_id */ - instance_p = ngap_gNB_get_instance(instance); + ngap_gNB_instance_t *instance_p = ngap_gNB_get_instance(instance); DevAssert(instance_p != NULL); - memset(&pdu, 0, sizeof(pdu)); + + // AMF selection from the Initial UE message contents + struct ngap_gNB_amf_data_s *amf = select_amf(instance_p, UEfirstReq); + if (amf == NULL) { + NGAP_WARN("No AMF is associated to the gNB\n"); + return -1; + } + + // Message Type (M) pdu.present = NGAP_NGAP_PDU_PR_initiatingMessage; asn1cCalloc(pdu.choice.initiatingMessage, head); head->procedureCode = NGAP_ProcedureCode_id_InitialUEMessage; @@ -98,98 +175,18 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf head->value.present = NGAP_InitiatingMessage__value_PR_InitialUEMessage; NGAP_InitialUEMessage_t *out = &head->value.choice.InitialUEMessage; - /* Select the AMF corresponding to the provided GUAMI. */ - //TODO have not be test. it's should be test - if (UEfirstReq->ue_identity.presenceMask & NGAP_UE_IDENTITIES_guami) { - amf_desc_p = ngap_gNB_nnsf_select_amf_by_guami(instance_p, UEfirstReq->establishment_cause, UEfirstReq->ue_identity.guami); - - if (amf_desc_p) { - NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through GUAMI MCC %d MNC %d AMFRI %d AMFSI %d AMFPT %d\n", - UEfirstReq->gNB_ue_ngap_id, - amf_desc_p->amf_name, - amf_desc_p->assoc_id, - UEfirstReq->ue_identity.guami.mcc, - UEfirstReq->ue_identity.guami.mnc, - UEfirstReq->ue_identity.guami.amf_region_id, - UEfirstReq->ue_identity.guami.amf_set_id, - UEfirstReq->ue_identity.guami.amf_pointer); - } - } - - if (amf_desc_p == NULL) { - /* Select the AMF corresponding to the provided s-TMSI. */ - //TODO have not be test. it's should be test - if (UEfirstReq->ue_identity.presenceMask & NGAP_UE_IDENTITIES_FiveG_s_tmsi) { - amf_desc_p = ngap_gNB_nnsf_select_amf_by_amf_setid(instance_p, UEfirstReq->establishment_cause, UEfirstReq->selected_plmn_identity, UEfirstReq->ue_identity.s_tmsi.amf_set_id); - - if (amf_desc_p) { - NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through S-TMSI AMFSI %d and selected PLMN Identity index %d MCC %d MNC %d\n", - UEfirstReq->gNB_ue_ngap_id, - amf_desc_p->amf_name, - amf_desc_p->assoc_id, - UEfirstReq->ue_identity.s_tmsi.amf_set_id, - UEfirstReq->selected_plmn_identity, - instance_p->plmn[UEfirstReq->selected_plmn_identity].plmn.mcc, - instance_p->plmn[UEfirstReq->selected_plmn_identity].plmn.mnc); - } - } - } - - if (amf_desc_p == NULL) { - /* Select AMF based on the selected PLMN identity, received through RRC - * Connection Setup Complete */ - //TODO have not be test. it's should be test - amf_desc_p = ngap_gNB_nnsf_select_amf_by_plmn_id(instance_p, UEfirstReq->establishment_cause, UEfirstReq->selected_plmn_identity); - - if (amf_desc_p) { - NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through selected PLMN Identity index %d MCC %d MNC %d\n", - UEfirstReq->gNB_ue_ngap_id, - amf_desc_p->amf_name, - amf_desc_p->assoc_id, - UEfirstReq->selected_plmn_identity, - instance_p->plmn[UEfirstReq->selected_plmn_identity].plmn.mcc, - instance_p->plmn[UEfirstReq->selected_plmn_identity].plmn.mnc); - } - } - - if (amf_desc_p == NULL) { - /* - * If no AMF corresponds to the GUAMI, the s-TMSI, or the selected PLMN - * identity, selects the AMF with the highest capacity. - */ - //TODO have not be test. it's should be test - amf_desc_p = ngap_gNB_nnsf_select_amf(instance_p, UEfirstReq->establishment_cause); - - if (amf_desc_p) { - NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through highest relative capacity\n", UEfirstReq->gNB_ue_ngap_id, amf_desc_p->amf_name, amf_desc_p->assoc_id); - } - } - - if (amf_desc_p == NULL) { - /* - * In case gNB has no AMF associated, the gNB should inform RRC and discard - * this request. - */ - NGAP_WARN("No AMF is associated to the gNB\n"); - // TODO: Inform RRC - return -1; - } - - /* The gNB should allocate a unique gNB UE NGAP ID for this UE. The value - * will be used for the duration of the connectivity. - */ - struct ngap_gNB_ue_context_s *ue_desc_p = calloc(1, sizeof(*ue_desc_p)); + /* Store the UE context in NGAP with: + * selected AMF, selected PLMN identity, gNB ID + * the unique gNB UE NGAP ID, used for the duration of the connectivity */ + struct ngap_gNB_ue_context_s *ue_desc_p = calloc_or_fail(1, sizeof(*ue_desc_p)); DevAssert(ue_desc_p != NULL); - /* Keep a reference to the selected AMF */ - ue_desc_p->amf_ref = amf_desc_p; + ue_desc_p->amf_ref = amf; ue_desc_p->gNB_ue_ngap_id = UEfirstReq->gNB_ue_ngap_id; ue_desc_p->gNB_instance = instance_p; - ue_desc_p->selected_plmn_identity = UEfirstReq->selected_plmn_identity; - - // insert in master table + ue_desc_p->selected_plmn_identity = UEfirstReq->plmn; ngap_store_ue_context(ue_desc_p); - /* mandatory */ + // RAN UE NGAP ID (M) { asn1cSequenceAdd(out->protocolIEs.list, NGAP_InitialUEMessage_IEs_t, ie); ie->id = NGAP_ProtocolIE_ID_id_RAN_UE_NGAP_ID; @@ -197,47 +194,43 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf ie->value.present = NGAP_InitialUEMessage_IEs__value_PR_RAN_UE_NGAP_ID; ie->value.choice.RAN_UE_NGAP_ID = ue_desc_p->gNB_ue_ngap_id; } - /* mandatory */ + + /* NAS-PDU (M): transferred transparently */ { asn1cSequenceAdd(out->protocolIEs.list, NGAP_InitialUEMessage_IEs_t, ie); ie->id = NGAP_ProtocolIE_ID_id_NAS_PDU; ie->criticality = NGAP_Criticality_reject; ie->value.present = NGAP_InitialUEMessage_IEs__value_PR_NAS_PDU; - allocCopy(&ie->value.choice.NAS_PDU, UEfirstReq->nas_pdu); + OCTET_STRING_fromBuf(&ie->value.choice.NAS_PDU, (const char *)UEfirstReq->nas_pdu.buf, UEfirstReq->nas_pdu.len); } - /* mandatory */ + // User Location Information (M) { asn1cSequenceAdd(out->protocolIEs.list, NGAP_InitialUEMessage_IEs_t, ie); ie->id = NGAP_ProtocolIE_ID_id_UserLocationInformation; ie->criticality = NGAP_Criticality_reject; ie->value.present = NGAP_InitialUEMessage_IEs__value_PR_UserLocationInformation; - ie->value.choice.UserLocationInformation.present = NGAP_UserLocationInformation_PR_userLocationInformationNR; - asn1cCalloc(ie->value.choice.UserLocationInformation.choice.userLocationInformationNR, userinfo_nr_p); /* Set nRCellIdentity. default userLocationInformationNR */ MACRO_GNB_ID_TO_CELL_IDENTITY(instance_p->gNB_id, 0, // Cell ID &userinfo_nr_p->nR_CGI.nRCellIdentity); - MCC_MNC_TO_TBCD(instance_p->plmn[ue_desc_p->selected_plmn_identity].plmn.mcc, - instance_p->plmn[ue_desc_p->selected_plmn_identity].plmn.mnc, - instance_p->plmn[ue_desc_p->selected_plmn_identity].plmn.mnc_digit_length, - &userinfo_nr_p->nR_CGI.pLMNIdentity); - /* Set TAI */ + plmn_id_t *plmn = &ue_desc_p->selected_plmn_identity; + MCC_MNC_TO_TBCD(plmn->mcc, plmn->mnc, plmn->mnc_digit_length, &userinfo_nr_p->nR_CGI.pLMNIdentity); + + /* In case of network sharing, + the selected PLMN is indicated by the PLMN Identity IE within the TAI IE */ INT24_TO_OCTET_STRING(instance_p->tac, &userinfo_nr_p->tAI.tAC); - MCC_MNC_TO_PLMNID(instance_p->plmn[ue_desc_p->selected_plmn_identity].plmn.mcc, - instance_p->plmn[ue_desc_p->selected_plmn_identity].plmn.mnc, - instance_p->plmn[ue_desc_p->selected_plmn_identity].plmn.mnc_digit_length, - &userinfo_nr_p->tAI.pLMNIdentity); + MCC_MNC_TO_PLMNID(plmn->mcc, plmn->mnc, plmn->mnc_digit_length, &userinfo_nr_p->tAI.pLMNIdentity); } /* Set the establishment cause according to those provided by RRC */ DevCheck(UEfirstReq->establishment_cause < NGAP_RRC_CAUSE_LAST, UEfirstReq->establishment_cause, NGAP_RRC_CAUSE_LAST, 0); - /* mandatory */ + // RRC Establishment Cause (M) { asn1cSequenceAdd(out->protocolIEs.list, NGAP_InitialUEMessage_IEs_t, ie); ie->id = NGAP_ProtocolIE_ID_id_RRCEstablishmentCause; @@ -246,7 +239,7 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf ie->value.choice.RRCEstablishmentCause = UEfirstReq->establishment_cause; } - /* optional */ + // 5G-S-TMSI (O) if (UEfirstReq->ue_identity.presenceMask & NGAP_UE_IDENTITIES_FiveG_s_tmsi) { NGAP_DEBUG("FIVEG_S_TMSI_PRESENT\n"); asn1cSequenceAdd(out->protocolIEs.list, NGAP_InitialUEMessage_IEs_t, ie); @@ -258,7 +251,8 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf M_TMSI_TO_OCTET_STRING(UEfirstReq->ue_identity.s_tmsi.m_tmsi, &ie->value.choice.FiveG_S_TMSI.fiveG_TMSI); } - /* optional */ + /* UE Context Request (O): instruct the AMF to trigger an + Initial Context Setup procedure towards the NG-RAN node. */ { asn1cSequenceAdd(out->protocolIEs.list, NGAP_InitialUEMessage_IEs_t, ie); ie->id = NGAP_ProtocolIE_ID_id_UEContextRequest; @@ -267,10 +261,8 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf ie->value.choice.UEContextRequest = NGAP_UEContextRequest_requested; } - if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) { - /* Failed to encode message */ - DevMessage("Failed to encode initial UE message\n"); - } + if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) + DevMessage("Failed to encode initial UE message\n"); /* Update the current NGAP UE state */ ue_desc_p->ue_state = NGAP_UE_WAITING_CSR; @@ -286,16 +278,13 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf * the stream should not be changed during the communication of the * UE-associated signalling. */ - amf_desc_p->nextstream = (amf_desc_p->nextstream + 1) % amf_desc_p->out_streams; - - if ((amf_desc_p->nextstream == 0) && (amf_desc_p->out_streams > 1)) { - amf_desc_p->nextstream += 1; + amf->nextstream = (amf->nextstream + 1) % amf->out_streams; + if ((amf->nextstream == 0) && (amf->out_streams > 1)) { + amf->nextstream += 1; } - - ue_desc_p->tx_stream = amf_desc_p->nextstream; + ue_desc_p->tx_stream = amf->nextstream; /* Send encoded message over sctp */ - ngap_gNB_itti_send_sctp_data_req(instance_p->instance, amf_desc_p->assoc_id, - buffer, length, ue_desc_p->tx_stream); + ngap_gNB_itti_send_sctp_data_req(instance_p->instance, amf->assoc_id, buffer, length, ue_desc_p->tx_stream); return 0; } @@ -436,8 +425,8 @@ int ngap_gNB_nas_uplink(instance_t instance, ngap_uplink_nas_t *ngap_uplink_nas_ ie->id = NGAP_ProtocolIE_ID_id_NAS_PDU; ie->criticality = NGAP_Criticality_reject; ie->value.present = NGAP_UplinkNASTransport_IEs__value_PR_NAS_PDU; - ie->value.choice.NAS_PDU.buf = ngap_uplink_nas_p->nas_pdu.buffer; - ie->value.choice.NAS_PDU.size = ngap_uplink_nas_p->nas_pdu.length; + ie->value.choice.NAS_PDU.buf = ngap_uplink_nas_p->nas_pdu.buf; + ie->value.choice.NAS_PDU.size = ngap_uplink_nas_p->nas_pdu.len; } /* mandatory */ { @@ -453,17 +442,12 @@ int ngap_gNB_nas_uplink(instance_t instance, ngap_uplink_nas_t *ngap_uplink_nas_ MACRO_GNB_ID_TO_CELL_IDENTITY(ngap_gNB_instance_p->gNB_id, 0, // Cell ID &userinfo_nr_p->nR_CGI.nRCellIdentity); - MCC_MNC_TO_TBCD(ngap_gNB_instance_p->plmn[ue_context_p->selected_plmn_identity].plmn.mcc, - ngap_gNB_instance_p->plmn[ue_context_p->selected_plmn_identity].plmn.mnc, - ngap_gNB_instance_p->plmn[ue_context_p->selected_plmn_identity].plmn.mnc_digit_length, - &userinfo_nr_p->nR_CGI.pLMNIdentity); + plmn_id_t *plmn = &ue_context_p->selected_plmn_identity; + MCC_MNC_TO_TBCD(plmn->mcc, plmn->mnc, plmn->mnc_digit_length, &userinfo_nr_p->nR_CGI.pLMNIdentity); /* Set TAI */ INT24_TO_OCTET_STRING(ngap_gNB_instance_p->tac, &userinfo_nr_p->tAI.tAC); - MCC_MNC_TO_PLMNID(ngap_gNB_instance_p->plmn[ue_context_p->selected_plmn_identity].plmn.mcc, - ngap_gNB_instance_p->plmn[ue_context_p->selected_plmn_identity].plmn.mnc, - ngap_gNB_instance_p->plmn[ue_context_p->selected_plmn_identity].plmn.mnc_digit_length, - &userinfo_nr_p->tAI.pLMNIdentity); + MCC_MNC_TO_PLMNID(plmn->mcc, plmn->mnc, plmn->mnc_digit_length, &userinfo_nr_p->tAI.pLMNIdentity); } if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) { NGAP_ERROR("Failed to encode uplink NAS transport\n"); @@ -532,8 +516,8 @@ int ngap_gNB_nas_non_delivery_ind(instance_t instance, ie->id = NGAP_ProtocolIE_ID_id_NAS_PDU; ie->criticality = NGAP_Criticality_ignore; ie->value.present = NGAP_NASNonDeliveryIndication_IEs__value_PR_NAS_PDU; - ie->value.choice.NAS_PDU.buf = ngap_nas_non_delivery_ind->nas_pdu.buffer; - ie->value.choice.NAS_PDU.size = ngap_nas_non_delivery_ind->nas_pdu.length; + ie->value.choice.NAS_PDU.buf = ngap_nas_non_delivery_ind->nas_pdu.buf; + ie->value.choice.NAS_PDU.size = ngap_nas_non_delivery_ind->nas_pdu.len; } /* mandatory */ { @@ -861,8 +845,8 @@ int ngap_gNB_ue_capabilities(instance_t instance, ngap_ue_cap_info_ind_t *ue_cap ie->id = NGAP_ProtocolIE_ID_id_UERadioCapability; ie->criticality = NGAP_Criticality_ignore; ie->value.present = NGAP_UERadioCapabilityInfoIndicationIEs__value_PR_UERadioCapability; - ie->value.choice.UERadioCapability.buf = ue_cap_info_ind_p->ue_radio_cap.buffer; - ie->value.choice.UERadioCapability.size = ue_cap_info_ind_p->ue_radio_cap.length; + ie->value.choice.UERadioCapability.buf = ue_cap_info_ind_p->ue_radio_cap.buf; + ie->value.choice.UERadioCapability.size = ue_cap_info_ind_p->ue_radio_cap.len; } /* optional */ //NGAP_UERadioCapabilityForPaging TBD @@ -1224,8 +1208,9 @@ int ngap_gNB_pdusession_release_resp(instance_t instance, ngap_pdusession_releas for (i = 0; i < pdusession_release_resp_p->nb_of_pdusessions_released; i++) { asn1cSequenceAdd(ie->value.choice.PDUSessionResourceReleasedListRelRes.list, NGAP_PDUSessionResourceReleasedItemRelRes_t, item); - item->pDUSessionID = pdusession_release_resp_p->pdusession_release[i].pdusession_id; - allocCopy(&item->pDUSessionResourceReleaseResponseTransfer, pdusession_release_resp_p->pdusession_release[i].data); + pdusession_release_t *r = &pdusession_release_resp_p->pdusession_release[i]; + item->pDUSessionID = r->pdusession_id; + OCTET_STRING_fromBuf(&item->pDUSessionResourceReleaseResponseTransfer, (const char *)r->data.buf, r->data.len); NGAP_DEBUG("pdusession_release_resp: pdusession ID %ld\n", item->pDUSessionID); } } diff --git a/openair3/NGAP/ngap_gNB_nnsf.c b/openair3/NGAP/ngap_gNB_nnsf.c index e9f23c6401..77cc7866e1 100644 --- a/openair3/NGAP/ngap_gNB_nnsf.c +++ b/openair3/NGAP/ngap_gNB_nnsf.c @@ -33,9 +33,7 @@ #include "queue.h" #include "tree.h" -struct ngap_gNB_amf_data_s * -ngap_gNB_nnsf_select_amf(ngap_gNB_instance_t *instance_p, - ngap_rrc_establishment_cause_t cause) +ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf(ngap_gNB_instance_t *instance_p, const ngap_rrc_establishment_cause_t cause) { struct ngap_gNB_amf_data_s *amf_data_p = NULL; struct ngap_gNB_amf_data_s *amf_highest_capacity_p = NULL; @@ -86,10 +84,9 @@ ngap_gNB_nnsf_select_amf(ngap_gNB_instance_t *instance_p, return amf_highest_capacity_p; } -struct ngap_gNB_amf_data_s * -ngap_gNB_nnsf_select_amf_by_plmn_id(ngap_gNB_instance_t *instance_p, - ngap_rrc_establishment_cause_t cause, - int selected_plmn_identity) +ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf_by_plmn_id(ngap_gNB_instance_t *instance_p, + const ngap_rrc_establishment_cause_t cause, + const plmn_id_t selected_plmn_identity) { struct ngap_gNB_amf_data_s *amf_data_p = NULL; struct ngap_gNB_amf_data_s *amf_highest_capacity_p = NULL; @@ -135,8 +132,7 @@ ngap_gNB_nnsf_select_amf_by_plmn_id(ngap_gNB_instance_t *instance_p, /* Looking for served GUAMI PLMN Identity selected matching the one provided by the UE */ STAILQ_FOREACH(guami_p, &amf_data_p->served_guami, next) { STAILQ_FOREACH(served_plmn_p, &guami_p->served_plmns, next) { - if ((served_plmn_p->mcc == instance_p->plmn[selected_plmn_identity].plmn.mcc) - && (served_plmn_p->mnc == instance_p->plmn[selected_plmn_identity].plmn.mnc)) { + if ((served_plmn_p->mcc == selected_plmn_identity.mcc) && (served_plmn_p->mnc == selected_plmn_identity.mnc)) { break; } } @@ -156,11 +152,10 @@ ngap_gNB_nnsf_select_amf_by_plmn_id(ngap_gNB_instance_t *instance_p, return amf_highest_capacity_p; } -struct ngap_gNB_amf_data_s * -ngap_gNB_nnsf_select_amf_by_amf_setid(ngap_gNB_instance_t *instance_p, - ngap_rrc_establishment_cause_t cause, - int selected_plmn_identity, - uint8_t amf_setid) +ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf_by_amf_setid(ngap_gNB_instance_t *instance_p, + const ngap_rrc_establishment_cause_t cause, + const plmn_id_t selected_plmn_identity, + uint8_t amf_setid) { struct ngap_gNB_amf_data_s *amf_data_p = NULL; @@ -207,8 +202,7 @@ ngap_gNB_nnsf_select_amf_by_amf_setid(ngap_gNB_instance_t *instance_p, struct plmn_identity_s *served_plmn_p = NULL; STAILQ_FOREACH(served_plmn_p, &guami_p->served_plmns, next) { - if ((served_plmn_p->mcc == instance_p->plmn[selected_plmn_identity].plmn.mcc) - && (served_plmn_p->mnc == instance_p->plmn[selected_plmn_identity].plmn.mnc)) { + if ((served_plmn_p->mcc == selected_plmn_identity.mcc) && (served_plmn_p->mnc == selected_plmn_identity.mnc)) { break; } } @@ -234,10 +228,9 @@ ngap_gNB_nnsf_select_amf_by_amf_setid(ngap_gNB_instance_t *instance_p, return NULL; } -struct ngap_gNB_amf_data_s * -ngap_gNB_nnsf_select_amf_by_guami(ngap_gNB_instance_t *instance_p, - ngap_rrc_establishment_cause_t cause, - ngap_guami_t guami) +ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf_by_guami(ngap_gNB_instance_t *instance_p, + const ngap_rrc_establishment_cause_t cause, + const nr_guami_t guami) { struct ngap_gNB_amf_data_s *amf_data_p = NULL; @@ -327,10 +320,7 @@ ngap_gNB_nnsf_select_amf_by_guami(ngap_gNB_instance_t *instance_p, return NULL; } - -struct ngap_gNB_amf_data_s * -ngap_gNB_nnsf_select_amf_by_guami_no_cause(ngap_gNB_instance_t *instance_p, - ngap_guami_t guami) +ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf_by_guami_no_cause(ngap_gNB_instance_t *instance_p, const nr_guami_t guami) { struct ngap_gNB_amf_data_s *amf_data_p = NULL; struct ngap_gNB_amf_data_s *amf_highest_capacity_p = NULL; diff --git a/openair3/NGAP/ngap_gNB_nnsf.h b/openair3/NGAP/ngap_gNB_nnsf.h index bf6c309af0..8a87ecfce2 100644 --- a/openair3/NGAP/ngap_gNB_nnsf.h +++ b/openair3/NGAP/ngap_gNB_nnsf.h @@ -34,28 +34,21 @@ #include "ngap_gNB_defs.h" #include "ngap_messages_types.h" -struct ngap_gNB_amf_data_s * -ngap_gNB_nnsf_select_amf(ngap_gNB_instance_t *instance_p, - ngap_rrc_establishment_cause_t cause); +ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf(ngap_gNB_instance_t *instance_p, const ngap_rrc_establishment_cause_t cause); -struct ngap_gNB_amf_data_s * -ngap_gNB_nnsf_select_amf_by_plmn_id(ngap_gNB_instance_t *instance_p, - ngap_rrc_establishment_cause_t cause, - int selected_plmn_identity); +ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf_by_plmn_id(ngap_gNB_instance_t *instance_p, + const ngap_rrc_establishment_cause_t cause, + const plmn_id_t selected_plmn_identity); -struct ngap_gNB_amf_data_s* -ngap_gNB_nnsf_select_amf_by_amf_setid(ngap_gNB_instance_t *instance_p, - ngap_rrc_establishment_cause_t cause, - int selected_plmn_identity, - uint8_t amf_setid); +ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf_by_amf_setid(ngap_gNB_instance_t *instance_p, + const ngap_rrc_establishment_cause_t cause, + const plmn_id_t selected_plmn_identity, + uint8_t amf_setid); -struct ngap_gNB_amf_data_s* -ngap_gNB_nnsf_select_amf_by_guami(ngap_gNB_instance_t *instance_p, - ngap_rrc_establishment_cause_t cause, - ngap_guami_t guami); +ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf_by_guami(ngap_gNB_instance_t *instance_p, + const ngap_rrc_establishment_cause_t cause, + const nr_guami_t guami); -struct ngap_gNB_amf_data_s* -ngap_gNB_nnsf_select_amf_by_guami_no_cause(ngap_gNB_instance_t *instance_p, - ngap_guami_t guami); +ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf_by_guami_no_cause(ngap_gNB_instance_t *instance_p, const nr_guami_t guami); #endif /* NGAP_GNB_NNSF_H_ */ diff --git a/openair3/NGAP/ngap_gNB_ue_context.h b/openair3/NGAP/ngap_gNB_ue_context.h index 2ca75141ef..4c0c63239f 100644 --- a/openair3/NGAP/ngap_gNB_ue_context.h +++ b/openair3/NGAP/ngap_gNB_ue_context.h @@ -72,7 +72,7 @@ typedef struct ngap_gNB_ue_context_s { /* Signaled by the UE in RRC Connection Setup Complete and used in NAS Uplink * to route NAS messages correctly. 0-based, not 1-based as in TS 36.331 * 6.2.2 RRC Connection Setup Complete! */ - int selected_plmn_identity; + plmn_id_t selected_plmn_identity; /* Reference to gNB data this UE is attached to */ ngap_gNB_instance_t *gNB_instance;