Merge remote-tracking branch 'origin/telnet-o1' into integration_2024_w50 (!3125)
Add support for O1 in O-DU via telnet This change set adds a simple telnet interface to nr-softmodem. Together with oai/o1-adapter>, this implements a part of the O1 interface, for the DU only. Currently supported uses cases: - some stats are send to an SMO (such as bandwidth, PLMN, frequency, ...) - re-configuration of bandwidth, frequency - stop/start of the softmodem, while keeping the CU and L2 running - the o1-adapter implements two alarms, load overload and base station offline, using this interface. It is possible to use the telnet interface by itself (i.e., "o1" without the o1-adapter). To do this, compile with telnet support (./build_oai --build-lib telnetsrv) and start the nr-softmodem with O1 module (./nr-softmodem --telnetsrv --telnetsrv.shrmod o1). You can then do the following: - see some statistics as exposed to o1-adapter, in JSON: echo o1 stats | nc 127.0.0.1 9090 && echo - stop the L1: echo o1 stop_modem | nc 127.0.0.1 9090 && echo - reconfigure bandwidth: e.g., echo o1 bwconfig 20 | nc 127.0.0.1 9090 && echo (also supported: 40, 60, 100) - start the L1: echo o1 start_modem | nc 127.0.0.1 9090 && echo Note that the reconfiguration works with split-8 radios. Notably, it does not work yet out-of-the-box with 7.2 radios, because they have to be manually reconfigured on bandwith/frequency switch. The planned M-plane should allow such use case, though. To help with the above, this branch also includes fixes (for more information, refer to the corresponding commits): - fixes for stopping the L1, notably stop threads in right order, stop thread pool of RU - collect some general MAC metrics, fix some bugs in MAC - fix problems in F1AP gNB-DU configuration update message, update test - fix some problems in RRC
This commit is contained in:
@@ -108,6 +108,7 @@ void *config_allocate_new(configmodule_interface_t *cfg, int sz, bool autoFree)
|
||||
// add the memory piece in the managed memory pieces list
|
||||
pthread_mutex_lock(&cfg->memBlocks_mutex);
|
||||
int newBlockIdx=cfg->numptrs++;
|
||||
AssertFatal(newBlockIdx < sizeofArray(cfg->oneBlock), "reached maximum number of dynamically allocatable blocks\n");
|
||||
oneBlock_t* tmp=&cfg->oneBlock[newBlockIdx];
|
||||
tmp->ptrs = (char *)ptr;
|
||||
tmp->ptrsAllocated = true;
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
#include "common/config/config_paramdesc.h"
|
||||
#include "common/utils/T/T.h"
|
||||
#define CONFIG_MAX_OOPT_PARAMS 10 // maximum number of parameters in the -O option (-O <cfgmode>:P1:P2...
|
||||
#define CONFIG_MAX_ALLOCATEDPTRS 2048 // maximum number of parameters that can be dynamicaly allocated in the config module
|
||||
#define CONFIG_MAX_ALLOCATEDPTRS 32768 // maximum number of parameters that can be dynamicaly allocated in the config module
|
||||
|
||||
/* default values for configuration module parameters */
|
||||
#define CONFIG_LIBCONFIGFILE "libconfig" // use libconfig file
|
||||
|
||||
@@ -75,7 +75,13 @@ add_library(telnetsrv_rrc MODULE telnetsrv_rrc.c)
|
||||
target_link_libraries(telnetsrv_rrc PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs)
|
||||
add_dependencies(telnetsrv telnetsrv_rrc)
|
||||
|
||||
message(STATUS "Add CI specific telnet functions in libtelnetsrv_o1.so")
|
||||
add_library(telnetsrv_o1 MODULE telnetsrv_o1.c)
|
||||
target_link_libraries(telnetsrv_o1 PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs)
|
||||
add_dependencies(telnetsrv telnetsrv_o1)
|
||||
|
||||
# all libraries should be written to root build dir
|
||||
set_target_properties(telnetsrv telnetsrv_enb telnetsrv_5Gue telnetsrv_ci telnetsrv_ciUE telnetsrv_bearer telnetsrv_rrc
|
||||
set_target_properties(telnetsrv telnetsrv_enb telnetsrv_5Gue telnetsrv_ci telnetsrv_ciUE
|
||||
telnetsrv_bearer telnetsrv_rrc telnetsrv_o1
|
||||
PROPERTIES LIBRARY_OUTPUT_DIRECTORY ../../..
|
||||
)
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
[[_TOC_]]
|
||||
|
||||
The telnet O1 module (`telnetsrv_o1.c`) can be used to perform some O1-related
|
||||
actions (reading data, starting and stopping the nr-softmodem, reconfigurating
|
||||
frequency and bandwidth).
|
||||
|
||||
# General usage
|
||||
|
||||
The usage is similar to the general telnet usage, but in short:
|
||||
```
|
||||
./build_oai --ninja -c --gNB --nrUE --build-lib telnetsrv
|
||||
```
|
||||
to build everything including the telnet library. Then, run the nr-softmodem
|
||||
by activating telnet and loading the `o1` module:
|
||||
```
|
||||
./nr-softmodem -O <config> --telnetsrv --telnetsrv.shrmod o1
|
||||
```
|
||||
|
||||
Afterwards, it should be possible to connect via telnet on localhost, port
|
||||
9090. Use `help` to get help on the different command sections, and type e.g.
|
||||
`o1 stats` to get statistics (more information further below):
|
||||
|
||||
```
|
||||
$ telnet 127.0.0.1 9090
|
||||
Trying 127.0.0.1...
|
||||
Connected to 127.0.0.1.
|
||||
Escape character is '^]'.
|
||||
|
||||
softmodem_gnb> help
|
||||
[...]
|
||||
module 4 = o1:
|
||||
o1 stats
|
||||
o1 config ?
|
||||
o1 stop_modem
|
||||
o1 start_modem
|
||||
[...]
|
||||
softmodem_gnb> o1 stats
|
||||
[...]
|
||||
softmodem_gnb> exit
|
||||
Connection closed by foreign host.
|
||||
```
|
||||
|
||||
It also possible to send a command "directly from the command line", by piping
|
||||
the command into netcat:
|
||||
```
|
||||
echo o1 stats | nc -N 127.0.0.1 9090
|
||||
```
|
||||
|
||||
Note that only one telnet client can be connected at a time.
|
||||
|
||||
# Get statistics
|
||||
|
||||
Use the `o1 stats` command. The output is in JSON format:
|
||||
```json
|
||||
{
|
||||
"o1-config": {
|
||||
"BWP": {
|
||||
"dl": [
|
||||
{
|
||||
"bwp3gpp:isInitialBwp": true,
|
||||
"bwp3gpp:numberOfRBs": 106,
|
||||
"bwp3gpp:startRB": 0,
|
||||
"bwp3gpp:subCarrierSpacing": 30
|
||||
}
|
||||
],
|
||||
"ul": [
|
||||
{
|
||||
"bwp3gpp:isInitialBwp": true,
|
||||
"bwp3gpp:numberOfRBs": 106,
|
||||
"bwp3gpp:startRB": 0,
|
||||
"bwp3gpp:subCarrierSpacing": 30
|
||||
}
|
||||
]
|
||||
},
|
||||
"NRCELLDU": {
|
||||
"nrcelldu3gpp:ssbFrequency": 641280,
|
||||
"nrcelldu3gpp:arfcnDL": 640008,
|
||||
"nrcelldu3gpp:bSChannelBwDL": 40,
|
||||
"nrcelldu3gpp:arfcnUL": 640008,
|
||||
"nrcelldu3gpp:bSChannelBwUL": 40,
|
||||
"nrcelldu3gpp:nRPCI": 0,
|
||||
"nrcelldu3gpp:nRTAC": 1,
|
||||
"nrcelldu3gpp:mcc": "208",
|
||||
"nrcelldu3gpp:mnc": "95",
|
||||
"nrcelldu3gpp:sd": 16777215,
|
||||
"nrcelldu3gpp:sst": 1
|
||||
},
|
||||
"device": {
|
||||
"gnbId": 1,
|
||||
"gnbName": "gNB-Eurecom-5GNRBox",
|
||||
"vendor": "OpenAirInterface"
|
||||
}
|
||||
},
|
||||
"O1-Operational": {
|
||||
"frame-type": "tdd",
|
||||
"band-number": 78,
|
||||
"num-ues": 1,
|
||||
"ues": [
|
||||
6876
|
||||
],
|
||||
"load": 9,
|
||||
"ues-thp": [
|
||||
{
|
||||
"rnti": 6876,
|
||||
"dl": 3279,
|
||||
"ul": 2725
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Note that no actual JSON engine is used, so no actual verification is done; it
|
||||
is for convenience of the consumer. To verify, you can employ `jq`:
|
||||
```
|
||||
echo o1 stats | nc -N 127.0.0.1 9090 | awk '/^{$/, /^}$/' | jq .
|
||||
```
|
||||
(`awk`'s pattern matching makes that only everything between the first `{` and
|
||||
its corresponding `}` is printed).
|
||||
|
||||
There are two sections:
|
||||
1. `.o1-config` show some stats that map directly to the O1 Netconf model. Note
|
||||
that only one MCC/MNC/SD/SST (each) are supported right now. Also, note that
|
||||
as per 3GPP specifications, SD of value `0xffffff` (16777215 in decimal)
|
||||
means "no SD". `bSChannelBwDL/UL` is reported in MHz.
|
||||
2. `.O1-operational` output some statistics that do not map yet to any netconf
|
||||
parameters, but that might be useful nevertheless for a consumer.
|
||||
|
||||
# Write a new configuration
|
||||
|
||||
Use `o1 config` to write a configuration:
|
||||
```
|
||||
echo o1 config nrcelldu3gpp:ssbFrequency 620736 nrcelldu3gpp:arfcnDL 620020 nrcelldu3gpp:bSChannelBwDL 51 bwp3gpp:numberOfRBs 51 bwp3gpp:startRB 0 | nc -N 127.0.0.1 9090
|
||||
```
|
||||
You have to pass the above parameters in exactly this order. The softmodem
|
||||
needs to be stopped; it will pick up the new configuration when starting the
|
||||
softmodem again.
|
||||
|
||||
Note that you cannot switch three-quarter sampling for this as of now.
|
||||
|
||||
For values of the configuration, refer to the next section.
|
||||
|
||||
# Use hardcoded configuration
|
||||
|
||||
Use `o1 bwconfig` to write a hard-coded configuration for 20 or 40 MHz cells:
|
||||
```
|
||||
echo o1 bwconfig 20 | nc -N 127.0.0.1 9090
|
||||
echo o1 bwconfig 40 | nc -N 127.0.0.1 9090
|
||||
```
|
||||
|
||||
The softmodem needs to be stopped; it will pick up the new configuration when
|
||||
starting the softmodem again.
|
||||
|
||||
Use `o1 stats` to see which configurations are set by these commands for the
|
||||
parameters `nrcelldu3gpp:ssbFrequency`, `nrcelldu3gpp:arfcnDL`,
|
||||
`nrcelldu3gpp:arfcnUL`, `nrcelldu3gpp:bSChannelBwDL`,
|
||||
`nrcelldu3gpp:bSChannelBwUL`, and `bwp3gpp:numberOfRBsbwp3gpp:startRB`.
|
||||
Furthermore, for 20MHz, it *disables* three-quarter sampling, whereas it
|
||||
*enables* three-quarter sampling for 40MHz.
|
||||
|
||||
# Restart the softmodem
|
||||
|
||||
Use `o1 stop_modem` to stop the `nr-softmodem`. To restart the softmodem, use
|
||||
`o1 start_modem`:
|
||||
```
|
||||
echo o1 stop_modem | nc -N 127.0.0.1 9090
|
||||
echo o1 start_modem | nc -N 127.0.0.1 9090
|
||||
```
|
||||
|
||||
In fact, stopping terminates all L1 threads. It will be as if the softmodem
|
||||
"freezes", and no periodical output of statistics will occur (the O1 telnet
|
||||
interface will still work, though). Starting again will "defreeze" the
|
||||
softmodem.
|
||||
|
||||
Upon restart, the DU sends a gNB-DU configuration update to the CU to inform it
|
||||
about the updated configuration. Therefore, this also works in F1.
|
||||
@@ -3,5 +3,6 @@ The oai embedded telnet server is an optional monitoring and debugging tool. It
|
||||
* [Using the telnet server](telnetusage.md)
|
||||
* [Adding commands to the oai telnet server](telnetaddcmd.md)
|
||||
* [telnet server architecture ](telnetarch.md)
|
||||
* [on the telnet O1 module](telneto1.md)
|
||||
|
||||
[oai Wikis home](https://gitlab.eurecom.fr/oai/openairinterface5g/wikis/home)
|
||||
|
||||
@@ -0,0 +1,418 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#define TELNETSERVERCODE
|
||||
#include "telnetsrv.h"
|
||||
|
||||
#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/mac_proto.h"
|
||||
#include "openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c"
|
||||
#include "common/utils/nr/nr_common.h"
|
||||
|
||||
#define ERROR_MSG_RET(mSG, aRGS...) do { prnt("FAILURE: " mSG, ##aRGS); return 1; } while (0)
|
||||
|
||||
#define ISINITBWP "bwp3gpp:isInitialBwp"
|
||||
//#define CYCLPREF "bwp3gpp:cyclicPrefix"
|
||||
#define NUMRBS "bwp3gpp:numberOfRBs"
|
||||
#define STARTRB "bwp3gpp:startRB"
|
||||
#define BWPSCS "bwp3gpp:subCarrierSpacing"
|
||||
|
||||
#define SSBFREQ "nrcelldu3gpp:ssbFrequency"
|
||||
#define ARFCNDL "nrcelldu3gpp:arfcnDL"
|
||||
#define BWDL "nrcelldu3gpp:bSChannelBwDL"
|
||||
#define ARFCNUL "nrcelldu3gpp:arfcnUL"
|
||||
#define BWUL "nrcelldu3gpp:bSChannelBwUL"
|
||||
#define PCI "nrcelldu3gpp:nRPCI"
|
||||
#define TAC "nrcelldu3gpp:nRTAC"
|
||||
#define MCC "nrcelldu3gpp:mcc"
|
||||
#define MNC "nrcelldu3gpp:mnc"
|
||||
#define SD "nrcelldu3gpp:sd"
|
||||
#define SST "nrcelldu3gpp:sst"
|
||||
|
||||
typedef struct b {
|
||||
long int dl;
|
||||
long int ul;
|
||||
} b_t;
|
||||
|
||||
typedef struct ue_stat {
|
||||
rnti_t rnti;
|
||||
b_t thr;
|
||||
} ue_stat_t;
|
||||
|
||||
#define PRINTLIST_i(len, fmt, ...) \
|
||||
{ \
|
||||
for (int i = 0; i < len; ++i) { \
|
||||
if (i != 0) prnt(", "); \
|
||||
prnt(fmt, __VA_ARGS__); \
|
||||
} \
|
||||
} \
|
||||
|
||||
static int get_stats(char *buf, int debug, telnet_printfunc_t prnt)
|
||||
{
|
||||
if (buf)
|
||||
ERROR_MSG_RET("no parameter allowed\n");
|
||||
|
||||
gNB_MAC_INST *mac = RC.nrmac[0];
|
||||
AssertFatal(mac != NULL, "need MAC\n");
|
||||
NR_SCHED_LOCK(&mac->sched_lock);
|
||||
|
||||
const f1ap_setup_req_t *sr = mac->f1_config.setup_req;
|
||||
const f1ap_served_cell_info_t *cell_info = &sr->cell[0].info;
|
||||
|
||||
const NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon;
|
||||
const NR_FrequencyInfoDL_t *frequencyInfoDL = scc->downlinkConfigCommon->frequencyInfoDL;
|
||||
const NR_FrequencyInfoUL_t *frequencyInfoUL = scc->uplinkConfigCommon->frequencyInfoUL;
|
||||
frame_type_t frame_type = get_frame_type(*frequencyInfoDL->frequencyBandList.list.array[0], *scc->ssbSubcarrierSpacing);
|
||||
const NR_BWP_t *initialDL = &scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters;
|
||||
const NR_BWP_t *initialUL = &scc->uplinkConfigCommon->initialUplinkBWP->genericParameters;
|
||||
|
||||
int scs = initialDL->subcarrierSpacing;
|
||||
AssertFatal(scs == initialUL->subcarrierSpacing, "different SCS for UL/DL not supported!\n");
|
||||
int band = *frequencyInfoDL->frequencyBandList.list.array[0];
|
||||
int nrb = frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth;
|
||||
AssertFatal(nrb == frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth, "different BW for UL/DL not supported!\n");
|
||||
frequency_range_t fr = band > 256 ? FR2 : FR1;
|
||||
int bw_index = get_supported_band_index(scs, fr, nrb);
|
||||
int bw_mhz = get_supported_bw_mhz(fr, bw_index);
|
||||
|
||||
const mac_stats_t *stat = &mac->mac_stats;
|
||||
static mac_stats_t last = {0};
|
||||
int diff_used = stat->used_prb_aggregate - last.used_prb_aggregate;
|
||||
int diff_total = stat->total_prb_aggregate - last.total_prb_aggregate;
|
||||
int load = diff_total > 0 ? 100 * diff_used / diff_total : 0;
|
||||
last = *stat;
|
||||
|
||||
static struct timespec tp_last = {0};
|
||||
struct timespec tp_now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &tp_now);
|
||||
size_t diff_msec = (tp_now.tv_sec - tp_last.tv_sec) * 1000 + (tp_now.tv_nsec - tp_last.tv_nsec) / 1000000;
|
||||
tp_last = tp_now;
|
||||
|
||||
const int srb_flag = 0;
|
||||
const int rb_id = 1;
|
||||
static b_t last_total[MAX_MOBILES_PER_GNB] = {0}; // TODO: hash table?
|
||||
ue_stat_t ue_stat[MAX_MOBILES_PER_GNB] = {0};
|
||||
int num_ues = 0;
|
||||
UE_iterator((NR_UE_info_t **)mac->UE_info.list, it) {
|
||||
nr_rlc_statistics_t rlc = {0};
|
||||
nr_rlc_get_statistics(it->rnti, srb_flag, rb_id, &rlc);
|
||||
b_t *lt = &last_total[num_ues];
|
||||
ue_stat_t *ue_s = &ue_stat[num_ues];
|
||||
ue_s->rnti = it->rnti;
|
||||
// static var last_total: we might have old data, larger than what
|
||||
// reports RLC, leading to a huge number -> cut off to zero
|
||||
if (lt->dl > rlc.txpdu_bytes)
|
||||
lt->dl = rlc.txpdu_bytes;
|
||||
if (lt->ul > rlc.rxpdu_bytes)
|
||||
lt->ul = rlc.rxpdu_bytes;
|
||||
ue_s->thr.dl = (rlc.txpdu_bytes - lt->dl) * 8 / diff_msec;
|
||||
ue_s->thr.ul = (rlc.rxpdu_bytes - lt->ul) * 8 / diff_msec;
|
||||
lt->dl = rlc.txpdu_bytes;
|
||||
lt->ul = rlc.rxpdu_bytes;
|
||||
num_ues++;
|
||||
}
|
||||
|
||||
prnt("{\n");
|
||||
prnt(" \"o1-config\": {\n");
|
||||
|
||||
prnt(" \"BWP\": {\n");
|
||||
prnt(" \"dl\": [{\n");
|
||||
prnt(" \"" ISINITBWP "\": true,\n");
|
||||
//prnt(" \"" CYCLPREF "\": %ld,\n", *initialDL->cyclicPrefix);
|
||||
prnt(" \"" NUMRBS "\": %ld,\n", NRRIV2BW(initialDL->locationAndBandwidth, MAX_BWP_SIZE));
|
||||
prnt(" \"" STARTRB "\": %ld,\n", NRRIV2PRBOFFSET(initialDL->locationAndBandwidth, MAX_BWP_SIZE));
|
||||
prnt(" \"" BWPSCS "\": %ld\n", 15 * (1U << scs));
|
||||
prnt(" }],\n");
|
||||
prnt(" \"ul\": [{\n");
|
||||
prnt(" \"" ISINITBWP "\": true,\n");
|
||||
//prnt(" \"" CYCLPREF "\": %ld,\n", *initialUL->cyclicPrefix);
|
||||
prnt(" \"" NUMRBS "\": %ld,\n", NRRIV2BW(initialUL->locationAndBandwidth, MAX_BWP_SIZE));
|
||||
prnt(" \"" STARTRB "\": %ld,\n", NRRIV2PRBOFFSET(initialUL->locationAndBandwidth, MAX_BWP_SIZE));
|
||||
prnt(" \"" BWPSCS "\": %ld\n", 15 * (1U << scs));
|
||||
prnt(" }]\n");
|
||||
prnt(" },\n");
|
||||
|
||||
prnt(" \"NRCELLDU\": {\n");
|
||||
prnt(" \"" SSBFREQ "\": %ld,\n", *scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB);
|
||||
prnt(" \"" ARFCNDL "\": %ld,\n", frequencyInfoDL->absoluteFrequencyPointA);
|
||||
prnt(" \"" BWDL "\": %ld,\n", bw_mhz);
|
||||
prnt(" \"" ARFCNUL "\": %ld,\n", frequencyInfoUL->absoluteFrequencyPointA ? *frequencyInfoUL->absoluteFrequencyPointA : frequencyInfoDL->absoluteFrequencyPointA);
|
||||
prnt(" \"" BWUL "\": %ld,\n", bw_mhz);
|
||||
prnt(" \"" PCI "\": %ld,\n", *scc->physCellId);
|
||||
prnt(" \"" TAC "\": %ld,\n", *cell_info->tac);
|
||||
prnt(" \"" MCC "\": \"%03d\",\n", cell_info->plmn.mcc);
|
||||
prnt(" \"" MNC "\": \"%0*d\",\n", cell_info->plmn.mnc_digit_length, cell_info->plmn.mnc);
|
||||
prnt(" \"" SD "\": %d,\n", cell_info->nssai[0].sd);
|
||||
prnt(" \"" SST "\": %d\n", cell_info->nssai[0].sst);
|
||||
prnt(" },\n");
|
||||
prnt(" \"device\": {\n");
|
||||
prnt(" \"gnbId\": %d,\n", sr->gNB_DU_id);
|
||||
prnt(" \"gnbName\": \"%s\",\n", sr->gNB_DU_name);
|
||||
prnt(" \"vendor\": \"OpenAirInterface\"\n");
|
||||
prnt(" }\n");
|
||||
prnt(" },\n");
|
||||
|
||||
prnt(" \"O1-Operational\": {\n");
|
||||
prnt(" \"frame-type\": \"%s\",\n", frame_type == TDD ? "tdd" : "fdd");
|
||||
prnt(" \"band-number\": %ld,\n", band);
|
||||
prnt(" \"num-ues\": %d,\n", num_ues);
|
||||
prnt(" \"ues\": ["); PRINTLIST_i(num_ues, "%d", ue_stat[i].rnti); prnt("],\n");
|
||||
prnt(" \"load\": %d,\n", load);
|
||||
prnt(" \"ues-thp\": [");
|
||||
PRINTLIST_i(num_ues, "\n {\"rnti\": %d, \"dl\": %ld, \"ul\": %ld}", ue_stat[i].rnti, ue_stat[i].thr.dl, ue_stat[i].thr.ul);
|
||||
prnt("\n ]\n");
|
||||
prnt(" }\n");
|
||||
prnt("}\n");
|
||||
prnt("OK\n");
|
||||
NR_SCHED_UNLOCK(&mac->sched_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_long(const char *buf, const char *end, const char *id, long *val)
|
||||
{
|
||||
const char *curr = buf;
|
||||
while (isspace(*curr) && curr < end) // skip leading spaces
|
||||
curr++;
|
||||
int len = strlen(id);
|
||||
if (curr + len >= end)
|
||||
return -1;
|
||||
if (strncmp(curr, id, len) != 0) // check buf has id
|
||||
return -1;
|
||||
curr += len;
|
||||
while (isspace(*curr) && curr < end) // skip middle spaces
|
||||
curr++;
|
||||
if (curr >= end)
|
||||
return -1;
|
||||
int nread = sscanf(curr, "%ld", val);
|
||||
if (nread != 1)
|
||||
return -1;
|
||||
while (isdigit(*curr) && curr < end) // skip all digits read above
|
||||
curr++;
|
||||
if (curr > end)
|
||||
return -1;
|
||||
return curr - buf;
|
||||
}
|
||||
|
||||
bool running = true; // in the beginning, the softmodem is started automatically
|
||||
static int set_config(char *buf, int debug, telnet_printfunc_t prnt)
|
||||
{
|
||||
if (!buf)
|
||||
ERROR_MSG_RET("need param: o1 config param1 val1 [param2 val2 ...]\n");
|
||||
if (running)
|
||||
ERROR_MSG_RET("cannot set parameters while L1 is running\n");
|
||||
const char *end = buf + strlen(buf);
|
||||
|
||||
/* we need to update the following fields to change frequency and/or
|
||||
* bandwidth:
|
||||
* --gNBs.[0].servingCellConfigCommon.[0].absoluteFrequencySSB 620736 -> SSBFREQ
|
||||
* --gNBs.[0].servingCellConfigCommon.[0].dl_absoluteFrequencyPointA 620020 -> ARFCNDL
|
||||
* --gNBs.[0].servingCellConfigCommon.[0].dl_carrierBandwidth 51 -> BWDL
|
||||
* --gNBs.[0].servingCellConfigCommon.[0].initialDLBWPlocationAndBandwidth 13750 -> NUMRBS + STARTRB
|
||||
* --gNBs.[0].servingCellConfigCommon.[0].ul_carrierBandwidth 51 -> BWUL?
|
||||
* --gNBs.[0].servingCellConfigCommon.[0].initialULBWPlocationAndBandwidth 13750 -> ?
|
||||
*/
|
||||
|
||||
int processed = 0;
|
||||
int pos = 0;
|
||||
|
||||
long ssbfreq;
|
||||
processed = read_long(buf + pos, end, SSBFREQ, &ssbfreq);
|
||||
if (processed < 0)
|
||||
ERROR_MSG_RET("could not read " SSBFREQ " at index %d\n", pos + processed);
|
||||
pos += processed;
|
||||
prnt("setting " SSBFREQ ": %ld [len %d]\n", ssbfreq, pos);
|
||||
|
||||
long arfcn;
|
||||
processed = read_long(buf + pos, end, ARFCNDL, &arfcn);
|
||||
if (processed < 0)
|
||||
ERROR_MSG_RET("could not read " ARFCNDL " at index %d\n", pos + processed);
|
||||
pos += processed;
|
||||
prnt("setting " ARFCNDL ": %ld [len %d]\n", arfcn, pos);
|
||||
|
||||
long bwdl;
|
||||
processed = read_long(buf + pos, end, BWDL, &bwdl);
|
||||
if (processed < 0)
|
||||
ERROR_MSG_RET("could not read " BWDL " at index %d\n", pos + processed);
|
||||
pos += processed;
|
||||
prnt("setting " BWDL ": %ld [len %d]\n", bwdl, pos);
|
||||
|
||||
long numrbs;
|
||||
processed = read_long(buf + pos, end, NUMRBS, &numrbs);
|
||||
if (processed < 0)
|
||||
ERROR_MSG_RET("could not read " NUMRBS " at index %d\n", pos + processed);
|
||||
pos += processed;
|
||||
prnt("setting " NUMRBS ": %ld [len %d]\n", numrbs, pos);
|
||||
|
||||
long startrb;
|
||||
processed = read_long(buf + pos, end, STARTRB, &startrb);
|
||||
if (processed < 0)
|
||||
ERROR_MSG_RET("could not read " STARTRB " at index %d\n", pos + processed);
|
||||
pos += processed;
|
||||
prnt("setting " STARTRB ": %ld [len %d]\n", startrb, pos);
|
||||
|
||||
int locationAndBandwidth = PRBalloc_to_locationandbandwidth0(numrbs, startrb, MAX_BWP_SIZE);
|
||||
prnt("inferred locationAndBandwidth: %d\n", locationAndBandwidth);
|
||||
prnt("OK\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_bwconfig(char *buf, int debug, telnet_printfunc_t prnt)
|
||||
{
|
||||
if (running)
|
||||
ERROR_MSG_RET("cannot set parameters while L1 is running\n");
|
||||
if (!buf)
|
||||
ERROR_MSG_RET("need param: o1 bwconfig <BW>\n");
|
||||
|
||||
char *end = NULL;
|
||||
if (NULL != (end = strchr(buf, '\n')))
|
||||
*end = 0;
|
||||
if (NULL != (end = strchr(buf, '\r')))
|
||||
*end = 0;
|
||||
|
||||
gNB_MAC_INST *mac = RC.nrmac[0];
|
||||
NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon;
|
||||
NR_FrequencyInfoDL_t *frequencyInfoDL = scc->downlinkConfigCommon->frequencyInfoDL;
|
||||
NR_BWP_t *initialDL = &scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters;
|
||||
NR_FrequencyInfoUL_t *frequencyInfoUL = scc->uplinkConfigCommon->frequencyInfoUL;
|
||||
NR_BWP_t *initialUL = &scc->uplinkConfigCommon->initialUplinkBWP->genericParameters;
|
||||
if (strcmp(buf, "40") == 0) {
|
||||
*scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB = 641280;
|
||||
frequencyInfoDL->absoluteFrequencyPointA = 640008;
|
||||
AssertFatal(frequencyInfoUL->absoluteFrequencyPointA == NULL, "only handle TDD\n");
|
||||
frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth = 106;
|
||||
initialDL->locationAndBandwidth = 28875;
|
||||
frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth = 106;
|
||||
initialUL->locationAndBandwidth = 28875;
|
||||
get_softmodem_params()->threequarter_fs = 1;
|
||||
} else if (strcmp(buf, "20") == 0) {
|
||||
*scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB = 641280;
|
||||
frequencyInfoDL->absoluteFrequencyPointA = 640596;
|
||||
AssertFatal(frequencyInfoUL->absoluteFrequencyPointA == NULL, "only handle TDD\n");
|
||||
frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth = 51;
|
||||
initialDL->locationAndBandwidth = 13750;
|
||||
frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth = 51;
|
||||
initialUL->locationAndBandwidth = 13750;
|
||||
get_softmodem_params()->threequarter_fs = 0;
|
||||
} else if (strcmp(buf, "100") == 0) {
|
||||
*scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB = 646668;
|
||||
frequencyInfoDL->absoluteFrequencyPointA = 643392;
|
||||
AssertFatal(frequencyInfoUL->absoluteFrequencyPointA == NULL, "only handle TDD\n");
|
||||
frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth = 273;
|
||||
initialDL->locationAndBandwidth = 1099;
|
||||
frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth = 273;
|
||||
initialUL->locationAndBandwidth = 1099;
|
||||
get_softmodem_params()->threequarter_fs = 0;
|
||||
} else if (strcmp(buf, "60") == 0) {
|
||||
*scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB = 621984;
|
||||
frequencyInfoDL->absoluteFrequencyPointA = 620040;
|
||||
AssertFatal(frequencyInfoUL->absoluteFrequencyPointA == NULL, "only handle TDD\n");
|
||||
frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth = 162;
|
||||
initialDL->locationAndBandwidth = 31624;
|
||||
frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth = 162;
|
||||
initialUL->locationAndBandwidth = 31624;
|
||||
get_softmodem_params()->threequarter_fs = 0;
|
||||
} else {
|
||||
ERROR_MSG_RET("unhandled option %s\n", buf);
|
||||
}
|
||||
|
||||
free(RC.nrmac[0]->sched_ctrlCommon);
|
||||
RC.nrmac[0]->sched_ctrlCommon = NULL;
|
||||
|
||||
free_MIB_NR(mac->common_channels[0].mib);
|
||||
mac->common_channels[0].mib = get_new_MIB_NR(scc);
|
||||
|
||||
const f1ap_served_cell_info_t *info = &mac->f1_config.setup_req->cell[0].info;
|
||||
nr_mac_configure_sib1(mac, &info->plmn, info->nr_cellid, *info->tac);
|
||||
|
||||
prnt("OK\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern int stop_L1(module_id_t gnb_id);
|
||||
static int stop_modem(char *buf, int debug, telnet_printfunc_t prnt)
|
||||
{
|
||||
if (!running)
|
||||
ERROR_MSG_RET("cannot stop, nr-softmodem not running\n");
|
||||
|
||||
/* make UEs out of sync and wait 50ms to ensure no PUCCH is scheduled. After
|
||||
* a restart, the frame/slot numbers will be different, which "confuses" the
|
||||
* scheduler, which has many PUCCH structures filled with expected frame/slot
|
||||
* combinations that won't happen. */
|
||||
const gNB_MAC_INST *mac = RC.nrmac[0];
|
||||
UE_iterator((NR_UE_info_t **)mac->UE_info.list, it) {
|
||||
nr_mac_trigger_ul_failure(&it->UE_sched_ctrl, 1);
|
||||
}
|
||||
usleep(50000);
|
||||
|
||||
stop_L1(0);
|
||||
running = false;
|
||||
prnt("OK\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern int start_L1L2(module_id_t gnb_id);
|
||||
static int start_modem(char *buf, int debug, telnet_printfunc_t prnt)
|
||||
{
|
||||
if (running)
|
||||
ERROR_MSG_RET("cannot start, nr-softmodem already running\n");
|
||||
start_L1L2(0);
|
||||
running = true;
|
||||
prnt("OK\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern void du_clear_all_ue_states();
|
||||
static int remove_mac_ues(char *buf, int debug, telnet_printfunc_t prnt)
|
||||
{
|
||||
du_clear_all_ue_states();
|
||||
prnt("OK\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static telnetshell_cmddef_t o1cmds[] = {
|
||||
{"stats", "", get_stats},
|
||||
{"config", "[]", set_config},
|
||||
{"bwconfig", "", set_bwconfig},
|
||||
{"stop_modem", "", stop_modem},
|
||||
{"start_modem", "", start_modem},
|
||||
{"remove_mac_ues", "", remove_mac_ues},
|
||||
{"", "", NULL},
|
||||
};
|
||||
|
||||
static telnetshell_vardef_t o1vars[] = {
|
||||
{"", 0, 0, NULL}
|
||||
};
|
||||
|
||||
void add_o1_cmds(void) {
|
||||
add_telnetcmd("o1", o1vars, o1cmds);
|
||||
}
|
||||
@@ -95,6 +95,10 @@ COPY --from=gnb-build \
|
||||
/oai-ran/cmake_targets/ran_build/build/libtelnetsrv.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/libtelnetsrv_ci.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/libparams_yaml.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/libtelnetsrv_bearer.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/libtelnetsrv_5Gue.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/libtelnetsrv_rrc.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/libtelnetsrv_o1.so \
|
||||
/usr/local/lib/
|
||||
|
||||
# Now we are copying from builder-image the UHD files.
|
||||
|
||||
@@ -145,6 +145,9 @@ f1ap_cudu_inst_t *getCxt(instance_t instanceP)
|
||||
return &fake;
|
||||
}
|
||||
configmodule_interface_t *uniqCfg = NULL;
|
||||
|
||||
void rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_COMPLETE(instance_t instance, uint32_t gNB_ue_ngap_id) { };
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
/// static configuration for NR at the moment
|
||||
|
||||
@@ -383,12 +383,16 @@ void init_gNB_Tpool(int inst) {
|
||||
|
||||
void term_gNB_Tpool(int inst) {
|
||||
PHY_VARS_gNB *gNB = RC.gNB[inst];
|
||||
abortTpool(&gNB->threadPool);
|
||||
abortNotifiedFIFO(&gNB->respDecode);
|
||||
abortNotifiedFIFO(&gNB->resp_L1);
|
||||
pthread_join(gNB->L1_rx_thread, NULL);
|
||||
abortNotifiedFIFO(&gNB->L1_tx_out);
|
||||
pthread_join(gNB->L1_tx_thread, NULL);
|
||||
|
||||
abortTpool(&gNB->threadPool);
|
||||
abortNotifiedFIFO(&gNB->respPuschSymb);
|
||||
abortNotifiedFIFO(&gNB->respDecode);
|
||||
abortNotifiedFIFO(&gNB->L1_tx_free);
|
||||
abortNotifiedFIFO(&gNB->L1_tx_filled);
|
||||
abortNotifiedFIFO(&gNB->L1_tx_out);
|
||||
abortNotifiedFIFO(&gNB->L1_rx_out);
|
||||
|
||||
gNB_L1_proc_t *proc = &gNB->proc;
|
||||
|
||||
@@ -1443,6 +1443,12 @@ void kill_NR_RU_proc(int inst) {
|
||||
RU_t *ru = RC.ru[inst];
|
||||
RU_proc_t *proc = &ru->proc;
|
||||
|
||||
if (ru->if_south != REMOTE_IF4p5) {
|
||||
abortTpool(ru->threadPool);
|
||||
abortNotifiedFIFO(ru->respfeprx);
|
||||
abortNotifiedFIFO(ru->respfeptx);
|
||||
}
|
||||
|
||||
/* Note: it seems pthread_FH and and FEP thread below both use
|
||||
* mutex_fep/cond_fep. Thus, we unlocked above for pthread_FH above and do
|
||||
* the same for FEP thread below again (using broadcast() to ensure both
|
||||
|
||||
+101
-24
@@ -401,6 +401,105 @@ void terminate_task(task_id_t task_id, module_id_t mod_id) {
|
||||
//extern void free_transport(PHY_VARS_gNB *);
|
||||
extern void nr_phy_free_RU(RU_t *);
|
||||
|
||||
int stop_L1(module_id_t gnb_id)
|
||||
{
|
||||
RU_t *ru = RC.ru[gnb_id];
|
||||
if (!ru) {
|
||||
LOG_W(GNB_APP, "no RU configured\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!RC.gNB[gnb_id]->configured) {
|
||||
LOG_W(GNB_APP, "L1 already stopped\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOG_I(GNB_APP, "stopping nr-softmodem\n");
|
||||
oai_exit = 1;
|
||||
|
||||
/* these tasks/layers need to pick up new configuration */
|
||||
if (RC.nb_nr_L1_inst > 0)
|
||||
stop_gNB(RC.nb_nr_L1_inst);
|
||||
|
||||
if (RC.nb_RU > 0)
|
||||
stop_RU(RC.nb_RU);
|
||||
|
||||
/* stop trx devices, multiple carrier currently not supported by RU */
|
||||
if (ru->rfdevice.trx_stop_func) {
|
||||
ru->rfdevice.trx_stop_func(&ru->rfdevice);
|
||||
LOG_I(GNB_APP, "turned off RU rfdevice\n");
|
||||
}
|
||||
|
||||
if (ru->ifdevice.trx_stop_func) {
|
||||
ru->ifdevice.trx_stop_func(&ru->ifdevice);
|
||||
LOG_I(GNB_APP, "turned off RU ifdevice\n");
|
||||
}
|
||||
|
||||
/* release memory used by the RU/gNB threads (incomplete), after all
|
||||
* threads have been stopped (they partially use the same memory) */
|
||||
for (int inst = 0; inst < RC.nb_RU; inst++) {
|
||||
nr_phy_free_RU(RC.ru[inst]);
|
||||
}
|
||||
|
||||
for (int inst = 0; inst < RC.nb_nr_L1_inst; inst++) {
|
||||
phy_free_nr_gNB(RC.gNB[inst]);
|
||||
}
|
||||
|
||||
RC.gNB[gnb_id]->configured = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Restart the nr-softmodem after it has been soft-stopped with stop_L1L2()
|
||||
*/
|
||||
#include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h"
|
||||
int start_L1L2(module_id_t gnb_id)
|
||||
{
|
||||
LOG_I(GNB_APP, "starting nr-softmodem\n");
|
||||
/* block threads */
|
||||
oai_exit = 0;
|
||||
sync_var = -1;
|
||||
extern void init_sched_response(void);
|
||||
init_sched_response();
|
||||
|
||||
/* update config */
|
||||
gNB_MAC_INST *mac = RC.nrmac[0];
|
||||
NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon;
|
||||
nr_mac_config_scc(mac, scc, &mac->radio_config);
|
||||
|
||||
NR_BCCH_BCH_Message_t *mib = mac->common_channels[0].mib;
|
||||
const NR_BCCH_DL_SCH_Message_t *sib1 = mac->common_channels[0].sib1;
|
||||
|
||||
/* update existing config in F1 Setup request structures */
|
||||
f1ap_setup_req_t *sr = mac->f1_config.setup_req;
|
||||
DevAssert(sr->num_cells_available == 1);
|
||||
f1ap_served_cell_info_t *info = &sr->cell[0].info;
|
||||
DevAssert(info->mode == F1AP_MODE_TDD);
|
||||
DevAssert(scc->tdd_UL_DL_ConfigurationCommon != NULL);
|
||||
info->tdd = read_tdd_config(scc); /* updates radio config */
|
||||
/* send gNB-DU configuration update to RRC */
|
||||
f1ap_gnb_du_configuration_update_t update = {
|
||||
.transaction_id = 1,
|
||||
.num_cells_to_modify = 1,
|
||||
};
|
||||
update.cell_to_modify[0].old_nr_cellid = info->nr_cellid;
|
||||
update.cell_to_modify[0].info = *info;
|
||||
update.cell_to_modify[0].sys_info = get_sys_info(mib, sib1);
|
||||
mac->mac_rrc.gnb_du_configuration_update(&update);
|
||||
|
||||
init_NR_RU(config_get_if(), NULL);
|
||||
|
||||
start_NR_RU();
|
||||
wait_RUs();
|
||||
init_eNB_afterRU();
|
||||
LOG_I(GNB_APP, "Sending sync to all threads\n");
|
||||
pthread_mutex_lock(&sync_mutex);
|
||||
sync_var=0;
|
||||
pthread_cond_broadcast(&sync_cond);
|
||||
pthread_mutex_unlock(&sync_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wait_nfapi_init(char *thread_name)
|
||||
{
|
||||
pthread_mutex_lock( &nfapi_sync_mutex );
|
||||
@@ -629,37 +728,15 @@ int main( int argc, char **argv ) {
|
||||
printf("TYPE <CTRL-C> TO TERMINATE\n");
|
||||
itti_wait_tasks_end(NULL);
|
||||
printf("Returned from ITTI signal handler\n");
|
||||
oai_exit=1;
|
||||
|
||||
// cleanup
|
||||
if (RC.nb_nr_L1_inst > 0)
|
||||
stop_gNB(RC.nb_nr_L1_inst);
|
||||
|
||||
if (RC.nb_RU > 0)
|
||||
stop_RU(RC.nb_RU);
|
||||
|
||||
/* release memory used by the RU/gNB threads (incomplete), after all
|
||||
* threads have been stopped (they partially use the same memory) */
|
||||
for (int inst = 0; inst < RC.nb_RU; inst++) {
|
||||
nr_phy_free_RU(RC.ru[inst]);
|
||||
}
|
||||
|
||||
for (int inst = 0; inst < RC.nb_nr_L1_inst; inst++) {
|
||||
phy_free_nr_gNB(RC.gNB[inst]);
|
||||
}
|
||||
if (RC.nb_nr_L1_inst > 0 || RC.nb_RU > 0)
|
||||
stop_L1(0);
|
||||
|
||||
pthread_cond_destroy(&sync_cond);
|
||||
pthread_mutex_destroy(&sync_mutex);
|
||||
pthread_cond_destroy(&nfapi_sync_cond);
|
||||
pthread_mutex_destroy(&nfapi_sync_mutex);
|
||||
|
||||
// *** Handle per CC_id openair0
|
||||
|
||||
for(ru_id = 0; ru_id < RC.nb_RU; ru_id++) {
|
||||
if (RC.ru[ru_id]->ifdevice.trx_end_func)
|
||||
RC.ru[ru_id]->ifdevice.trx_end_func(&RC.ru[ru_id]->ifdevice);
|
||||
}
|
||||
|
||||
free(pckg);
|
||||
logClean();
|
||||
printf("Bye.\n");
|
||||
|
||||
@@ -52,7 +52,7 @@ extern void stop_RU(int nb_ru);
|
||||
extern void kill_NR_RU_proc(int inst);
|
||||
extern void set_function_spec_param(RU_t *ru);
|
||||
|
||||
void init_gNB_afterRU(void);
|
||||
void init_eNB_afterRU(void);
|
||||
|
||||
void init_pdcp(void);
|
||||
|
||||
|
||||
@@ -180,4 +180,8 @@ void nr_phy_free_RU(RU_t *ru)
|
||||
free_and_zero(ru->common.beam_id[i]);
|
||||
free_and_zero(ru->common.beam_id);
|
||||
}
|
||||
|
||||
PHY_VARS_gNB *gNB0 = ru->gNB_list[0];
|
||||
gNB0->num_RU--;
|
||||
DevAssert(gNB0->num_RU >= 0);
|
||||
}
|
||||
|
||||
@@ -177,10 +177,9 @@ c16_t *gNB_dmrs_lowpaprtype1_sequence[U_GROUP_NUMBER][V_BASE_SEQUENCE_NUMBER][MA
|
||||
void generate_lowpapr_typ1_refsig_sequences(unsigned int scaling)
|
||||
{
|
||||
/* prevent multiple calls, relevant when both UE & gNB initialize this */
|
||||
static bool already_called = false;
|
||||
bool already_called = gNB_dmrs_lowpaprtype1_sequence[0][0][0] != NULL;
|
||||
if (already_called)
|
||||
return;
|
||||
already_called = true;
|
||||
unsigned int v = 0; // sequence hopping and group hopping are not supported yet
|
||||
|
||||
for (unsigned int Msc_RS = 0; Msc_RS <= INDEX_SB_LESS_32; Msc_RS++) {
|
||||
@@ -200,9 +199,8 @@ c16_t *dmrs_lowpaprtype1_ul_ref_sig[U_GROUP_NUMBER][V_BASE_SEQUENCE_NUMBER][MAX_
|
||||
void generate_ul_reference_signal_sequences(unsigned int scaling)
|
||||
{
|
||||
/* prevent multiple calls, relevant when both UE & gNB initialize this */
|
||||
static bool already_called = false;
|
||||
bool already_called = rv_ul_ref_sig[0][0][0] != NULL;
|
||||
if (already_called) return;
|
||||
already_called = true;
|
||||
|
||||
unsigned int u,v,Msc_RS;
|
||||
|
||||
|
||||
@@ -467,6 +467,7 @@ int main(int argc, char **argv){
|
||||
ru->nb_rx = n_rx;
|
||||
ru->num_gNB = 1;
|
||||
ru->gNB_list[0] = gNB;
|
||||
gNB->num_RU = 1;
|
||||
gNB->gNB_config.carrier_config.num_tx_ant.value = 1;
|
||||
gNB->gNB_config.carrier_config.num_rx_ant.value = 1;
|
||||
if (mu == 0)
|
||||
|
||||
@@ -143,7 +143,6 @@ int CU_handle_gNB_DU_CONFIGURATION_UPDATE(instance_t instance, sctp_assoc_t asso
|
||||
message_p->ittiMsgHeader.originInstance = assoc_id;
|
||||
f1ap_gnb_du_configuration_update_t *req = &F1AP_GNB_DU_CONFIGURATION_UPDATE(message_p); // RRC thread will free it
|
||||
*req = msg; // copy F1 message to ITTI
|
||||
free_f1ap_du_configuration_update(&msg);
|
||||
LOG_D(F1AP, "Sending F1AP_GNB_DU_CONFIGURATION_UPDATE ITTI message \n");
|
||||
itti_send_msg_to_task(TASK_RRC_GNB, GNB_MODULE_ID_TO_INSTANCE(instance), message_p);
|
||||
return 0;
|
||||
|
||||
@@ -262,12 +262,9 @@ int DU_handle_gNB_DU_CONFIGURATION_UPDATE_ACKNOWLEDGE(instance_t instance,
|
||||
free_f1ap_du_configuration_update_acknowledge(&in);
|
||||
return -1;
|
||||
}
|
||||
// Allocate and send an ITTI message
|
||||
MessageDef *msg_p = itti_alloc_new_message(TASK_DU_F1, 0, F1AP_GNB_DU_CONFIGURATION_UPDATE_ACKNOWLEDGE);
|
||||
f1ap_gnb_du_configuration_update_acknowledge_t *msg = &F1AP_GNB_DU_CONFIGURATION_UPDATE_ACKNOWLEDGE(msg_p);
|
||||
// Copy the decoded message to the ITTI message (RRC thread will free it)
|
||||
*msg = in; // Copy the decoded message to the ITTI message (RRC thread will free it)
|
||||
itti_send_msg_to_task(TASK_GNB_APP, GNB_MODULE_ID_TO_INSTANCE(assoc_id), msg_p);
|
||||
|
||||
gnb_du_configuration_update_acknowledge(&in);
|
||||
free_f1ap_du_configuration_update_acknowledge(&in);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,9 +34,10 @@
|
||||
#ifndef F1AP_DU_RRC_MESSAGE_TRANSFER_H_
|
||||
#define F1AP_DU_RRC_MESSAGE_TRANSFER_H_
|
||||
|
||||
#include "f1ap_common.h"
|
||||
#include <openair2/RRC/NR/MESSAGES/asn1_msg.h>
|
||||
|
||||
int DU_handle_DL_RRC_MESSAGE_TRANSFER(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu);
|
||||
struct F1AP_F1AP_PDU;
|
||||
int DU_handle_DL_RRC_MESSAGE_TRANSFER(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, struct F1AP_F1AP_PDU *pdu);
|
||||
|
||||
int DU_send_UL_NR_RRC_MESSAGE_TRANSFER(sctp_assoc_t assoc_id, const f1ap_ul_rrc_message_t *msg);
|
||||
|
||||
|
||||
@@ -173,7 +173,7 @@ static bool decode_served_cell_info(const F1AP_Served_Cell_Information_t *in, f1
|
||||
OCTET_STRING_TO_INT24(in->fiveGS_TAC, *info->tac);
|
||||
}
|
||||
// NR CGI (M)
|
||||
TBCD_TO_MCC_MNC(&(in->nRCGI.pLMN_Identity), info->plmn.mcc, info->plmn.mnc, info->plmn.mnc_digit_length);
|
||||
PLMNID_TO_MCC_MNC(&(in->nRCGI.pLMN_Identity), info->plmn.mcc, info->plmn.mnc, info->plmn.mnc_digit_length);
|
||||
// NR Cell Identity (M)
|
||||
BIT_STRING_TO_NR_CELL_IDENTITY(&in->nRCGI.nRCellIdentity, info->nr_cellid);
|
||||
// NR PCI (M)
|
||||
@@ -310,7 +310,7 @@ static bool decode_cells_to_activate(served_cells_to_activate_t *out, const F1AP
|
||||
"in->value.present != F1AP_Cells_to_be_Activated_List_ItemIEs__value_PR_Cells_to_be_Activated_List_Item\n");
|
||||
const F1AP_Cells_to_be_Activated_List_Item_t *cell = &in->value.choice.Cells_to_be_Activated_List_Item;
|
||||
// NR CGI (M)
|
||||
TBCD_TO_MCC_MNC(&cell->nRCGI.pLMN_Identity, out->plmn.mcc, out->plmn.mnc, out->plmn.mnc_digit_length);
|
||||
PLMNID_TO_MCC_MNC(&cell->nRCGI.pLMN_Identity, out->plmn.mcc, out->plmn.mnc, out->plmn.mnc_digit_length);
|
||||
BIT_STRING_TO_NR_CELL_IDENTITY(&cell->nRCGI.nRCellIdentity, out->nr_cellid);
|
||||
// NR PCI (O)
|
||||
if (cell->nRPCI != NULL)
|
||||
@@ -534,20 +534,56 @@ bool decode_f1ap_setup_request(const F1AP_F1AP_PDU_t *pdu, f1ap_setup_req_t *out
|
||||
return true;
|
||||
}
|
||||
|
||||
void copy_f1ap_served_cell_info(f1ap_served_cell_info_t *dest, const f1ap_served_cell_info_t *src)
|
||||
f1ap_served_cell_info_t copy_f1ap_served_cell_info(const f1ap_served_cell_info_t *src)
|
||||
{
|
||||
// shallow copy
|
||||
*dest = *src;
|
||||
// tac
|
||||
f1ap_served_cell_info_t dst = {
|
||||
.plmn = src->plmn,
|
||||
.nr_cellid = src->nr_cellid,
|
||||
.nr_pci = src->nr_pci,
|
||||
.num_ssi = src->num_ssi,
|
||||
.mode = src->mode,
|
||||
};
|
||||
|
||||
for (int i = 0; i < src->num_ssi; ++i)
|
||||
dst.nssai[i] = src->nssai[i];
|
||||
|
||||
if (src->mode == F1AP_MODE_TDD)
|
||||
dst.tdd = src->tdd;
|
||||
else
|
||||
dst.fdd = src->fdd;
|
||||
|
||||
if (src->tac) {
|
||||
dest->tac = malloc_or_fail(sizeof(*dest->tac));
|
||||
*dest->tac = *src->tac;
|
||||
dst.tac = malloc_or_fail(sizeof(*dst.tac));
|
||||
*dst.tac = *src->tac;
|
||||
}
|
||||
// measurement timing config
|
||||
if (src->measurement_timing_config_len) {
|
||||
dest->measurement_timing_config = calloc_or_fail(src->measurement_timing_config_len, sizeof(*dest->measurement_timing_config));
|
||||
memcpy(dest->measurement_timing_config, src->measurement_timing_config, src->measurement_timing_config_len);
|
||||
|
||||
if (src->measurement_timing_config_len > 0) {
|
||||
dst.measurement_timing_config_len = src->measurement_timing_config_len;
|
||||
dst.measurement_timing_config = calloc_or_fail(src->measurement_timing_config_len, sizeof(*dst.measurement_timing_config));
|
||||
memcpy(dst.measurement_timing_config, src->measurement_timing_config, src->measurement_timing_config_len);
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
static f1ap_gnb_du_system_info_t *copy_f1ap_gnb_du_system_info(const f1ap_gnb_du_system_info_t *src)
|
||||
{
|
||||
if (!src)
|
||||
return NULL;
|
||||
|
||||
f1ap_gnb_du_system_info_t *dst = calloc_or_fail(1, sizeof(*dst));
|
||||
if (src->mib_length > 0) {
|
||||
dst->mib_length = src->mib_length;
|
||||
dst->mib = calloc_or_fail(src->mib_length, sizeof(*src->mib));
|
||||
memcpy(dst->mib, src->mib, dst->mib_length);
|
||||
}
|
||||
|
||||
if (src->sib1_length > 0) {
|
||||
dst->sib1_length = src->sib1_length;
|
||||
dst->sib1 = calloc_or_fail(src->sib1_length, sizeof(*dst->sib1));
|
||||
memcpy(dst->sib1, src->sib1, dst->sib1_length);
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -567,25 +603,9 @@ f1ap_setup_req_t cp_f1ap_setup_request(const f1ap_setup_req_t *msg)
|
||||
cp.num_cells_available = msg->num_cells_available;
|
||||
for (int n = 0; n < msg->num_cells_available; n++) {
|
||||
/* cell.info */
|
||||
f1ap_served_cell_info_t *sci = &cp.cell[n].info;
|
||||
const f1ap_served_cell_info_t *msg_sci = &msg->cell[n].info;
|
||||
copy_f1ap_served_cell_info(sci, msg_sci);
|
||||
cp.cell[n].info = copy_f1ap_served_cell_info(&msg->cell[n].info);
|
||||
/* cell.sys_info */
|
||||
if (msg->cell[n].sys_info) {
|
||||
f1ap_gnb_du_system_info_t *orig_sys_info = msg->cell[n].sys_info;
|
||||
f1ap_gnb_du_system_info_t *copy_sys_info = calloc_or_fail(1, sizeof(*copy_sys_info));
|
||||
cp.cell[n].sys_info = copy_sys_info;
|
||||
if (orig_sys_info->mib_length > 0) {
|
||||
copy_sys_info->mib = calloc_or_fail(orig_sys_info->mib_length, sizeof(*copy_sys_info->mib));
|
||||
copy_sys_info->mib_length = orig_sys_info->mib_length;
|
||||
memcpy(copy_sys_info->mib, orig_sys_info->mib, copy_sys_info->mib_length);
|
||||
}
|
||||
if (orig_sys_info->sib1_length > 0) {
|
||||
copy_sys_info->sib1 = calloc_or_fail(orig_sys_info->sib1_length, sizeof(*copy_sys_info->sib1));
|
||||
copy_sys_info->sib1_length = orig_sys_info->sib1_length;
|
||||
memcpy(copy_sys_info->sib1, orig_sys_info->sib1, copy_sys_info->sib1_length);
|
||||
}
|
||||
}
|
||||
cp.cell[n].sys_info = copy_f1ap_gnb_du_system_info(msg->cell[n].sys_info);
|
||||
}
|
||||
for (int i = 0; i < sizeofArray(msg->rrc_ver); i++)
|
||||
cp.rrc_ver[i] = msg->rrc_ver[i];
|
||||
@@ -1002,7 +1022,6 @@ F1AP_F1AP_PDU_t *encode_f1ap_du_configuration_update(const f1ap_gnb_du_configura
|
||||
/* mandatory */
|
||||
/* c2. Served_Cells_To_Add */
|
||||
if (msg->num_cells_to_add > 0) {
|
||||
AssertFatal(false, "code for adding cells not tested\n");
|
||||
asn1cSequenceAdd(out->protocolIEs.list, F1AP_GNBDUConfigurationUpdateIEs_t, ie2);
|
||||
ie2->id = F1AP_ProtocolIE_ID_id_Served_Cells_To_Add_List;
|
||||
ie2->criticality = F1AP_Criticality_reject;
|
||||
@@ -1060,7 +1079,6 @@ F1AP_F1AP_PDU_t *encode_f1ap_du_configuration_update(const f1ap_gnb_du_configura
|
||||
ie4->id = F1AP_ProtocolIE_ID_id_Served_Cells_To_Delete_List;
|
||||
ie4->criticality = F1AP_Criticality_reject;
|
||||
ie4->value.present = F1AP_GNBDUConfigurationUpdateIEs__value_PR_Served_Cells_To_Delete_List;
|
||||
AssertFatal(msg->num_cells_to_delete == 0, "code for deleting cells not tested\n");
|
||||
for (int i = 0; i < msg->num_cells_to_delete; i++) {
|
||||
asn1cSequenceAdd(ie4->value.choice.Served_Cells_To_Delete_List.list,
|
||||
F1AP_Served_Cells_To_Delete_ItemIEs_t,
|
||||
@@ -1114,8 +1132,8 @@ bool decode_f1ap_du_configuration_update(const F1AP_F1AP_PDU_t *pdu, f1ap_gnb_du
|
||||
} break;
|
||||
case F1AP_ProtocolIE_ID_id_Served_Cells_To_Add_List: {
|
||||
/* Served Cells To Add List */
|
||||
AssertError(out->num_cells_to_add > 0, return false, "at least 1 cell to add shall to be present");
|
||||
out->num_cells_to_add = ie->value.choice.Served_Cells_To_Add_List.list.count;
|
||||
AssertError(out->num_cells_to_add > 0, return false, "at least 1 cell to add shall to be present");
|
||||
for (int i = 0; i < out->num_cells_to_add; i++) {
|
||||
F1AP_Served_Cells_To_Add_Item_t *served_cells_item =
|
||||
&((F1AP_Served_Cells_To_Add_ItemIEs_t *)ie->value.choice.Served_Cells_To_Add_List.list.array[i])
|
||||
@@ -1142,7 +1160,7 @@ bool decode_f1ap_du_configuration_update(const F1AP_F1AP_PDU_t *pdu, f1ap_gnb_du
|
||||
/* Old NR CGI (M) */
|
||||
F1AP_NRCGI_t *oldNRCGI = &served_cells_item->oldNRCGI;
|
||||
f1ap_plmn_t *old_plmn = &out->cell_to_modify[i].old_plmn;
|
||||
TBCD_TO_MCC_MNC(&(oldNRCGI->pLMN_Identity), old_plmn->mcc, old_plmn->mnc, old_plmn->mnc_digit_length);
|
||||
PLMNID_TO_MCC_MNC(&oldNRCGI->pLMN_Identity, old_plmn->mcc, old_plmn->mnc, old_plmn->mnc_digit_length);
|
||||
/* Old NR CGI Cell ID */
|
||||
BIT_STRING_TO_NR_CELL_IDENTITY(&oldNRCGI->nRCellIdentity, out->cell_to_modify[i].old_nr_cellid);
|
||||
/* Served Cell Information (M) */
|
||||
@@ -1166,7 +1184,7 @@ bool decode_f1ap_du_configuration_update(const F1AP_F1AP_PDU_t *pdu, f1ap_gnb_du
|
||||
F1AP_NRCGI_t *oldNRCGI = &served_cells_item->oldNRCGI;
|
||||
f1ap_plmn_t *plmn = &out->cell_to_delete[i].plmn;
|
||||
/* Old NR CGI (M) */
|
||||
TBCD_TO_MCC_MNC(&(oldNRCGI->pLMN_Identity), plmn->mcc, plmn->mnc, plmn->mnc_digit_length);
|
||||
PLMNID_TO_MCC_MNC(&(oldNRCGI->pLMN_Identity), plmn->mcc, plmn->mnc, plmn->mnc_digit_length);
|
||||
// NR cellID
|
||||
BIT_STRING_TO_NR_CELL_IDENTITY(&oldNRCGI->nRCellIdentity, out->cell_to_delete[i].nr_cellid);
|
||||
}
|
||||
@@ -1216,10 +1234,8 @@ bool eq_f1ap_du_configuration_update(const f1ap_gnb_du_configuration_update_t *a
|
||||
for (int i = 0; i < a->num_cells_to_add; i++) {
|
||||
if (!eq_f1ap_cell_info(&a->cell_to_add[i].info, &b->cell_to_add[i].info))
|
||||
return false;
|
||||
if (a->cell_to_add[i].sys_info && b->cell_to_add[i].sys_info) {
|
||||
if (!eq_f1ap_sys_info(a->cell_to_add[i].sys_info, b->cell_to_add[i].sys_info))
|
||||
return false;
|
||||
}
|
||||
if (!eq_f1ap_sys_info(a->cell_to_add[i].sys_info, b->cell_to_add[i].sys_info))
|
||||
return false;
|
||||
}
|
||||
/* to delete */
|
||||
_F1_EQ_CHECK_INT(a->num_cells_to_delete, b->num_cells_to_delete);
|
||||
@@ -1231,12 +1247,13 @@ bool eq_f1ap_du_configuration_update(const f1ap_gnb_du_configuration_update_t *a
|
||||
/* to modify */
|
||||
_F1_EQ_CHECK_INT(a->num_cells_to_modify, b->num_cells_to_modify);
|
||||
for (int i = 0; i < a->num_cells_to_modify; i++) {
|
||||
if (!eq_f1ap_plmn(&a->cell_to_modify[i].old_plmn, &b->cell_to_modify[i].old_plmn))
|
||||
return false;
|
||||
_F1_EQ_CHECK_LONG(a->cell_to_modify[i].old_nr_cellid, b->cell_to_modify[i].old_nr_cellid);
|
||||
if (!eq_f1ap_cell_info(&a->cell_to_modify[i].info, &b->cell_to_modify[i].info))
|
||||
return false;
|
||||
if (a->cell_to_modify[i].sys_info && b->cell_to_modify[i].sys_info) {
|
||||
if (!eq_f1ap_sys_info(a->cell_to_modify[i].sys_info, b->cell_to_modify[i].sys_info))
|
||||
return false;
|
||||
}
|
||||
if (!eq_f1ap_sys_info(a->cell_to_modify[i].sys_info, b->cell_to_modify[i].sys_info))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -1256,6 +1273,10 @@ f1ap_gnb_du_configuration_update_t cp_f1ap_du_configuration_update(const f1ap_gn
|
||||
cp.transaction_id = msg->transaction_id;
|
||||
/* to add */
|
||||
cp.num_cells_to_add = msg->num_cells_to_add;
|
||||
for (int i = 0; i < cp.num_cells_to_add; ++i) {
|
||||
cp.cell_to_add[i].info = copy_f1ap_served_cell_info(&msg->cell_to_add[i].info);
|
||||
cp.cell_to_add[i].sys_info = copy_f1ap_gnb_du_system_info(msg->cell_to_add[i].sys_info);
|
||||
}
|
||||
/* to delete */
|
||||
cp.num_cells_to_delete = msg->num_cells_to_delete;
|
||||
for (int i = 0; i < cp.num_cells_to_delete; i++) {
|
||||
@@ -1265,31 +1286,10 @@ f1ap_gnb_du_configuration_update_t cp_f1ap_du_configuration_update(const f1ap_gn
|
||||
/* to modify */
|
||||
cp.num_cells_to_modify = msg->num_cells_to_modify;
|
||||
for (int i = 0; i < cp.num_cells_to_modify; i++) {
|
||||
cp.cell_to_modify[i].info = msg->cell_to_modify[i].info;
|
||||
f1ap_served_cell_info_t *info = &cp.cell_to_modify[i].info;
|
||||
if (info->measurement_timing_config_len > 0) {
|
||||
info->measurement_timing_config = malloc_or_fail(info->measurement_timing_config_len * sizeof(*info->measurement_timing_config));
|
||||
for (int j = 0; j < info->measurement_timing_config_len; j++)
|
||||
info->measurement_timing_config[j] = msg->cell_to_modify[i].info.measurement_timing_config[j];
|
||||
}
|
||||
/* TAC */
|
||||
info->tac = calloc_or_fail(1, sizeof(*info->tac));
|
||||
*info->tac = *msg->cell_to_modify[i].info.tac;
|
||||
/* System information */
|
||||
cp.cell_to_modify[i].sys_info = malloc_or_fail(sizeof(*cp.cell_to_modify[i].sys_info));
|
||||
f1ap_gnb_du_system_info_t *sys_info = cp.cell_to_modify[i].sys_info;
|
||||
if (msg->cell_to_modify[i].sys_info->mib_length > 0) {
|
||||
sys_info->mib_length = msg->cell_to_modify[i].sys_info->mib_length;
|
||||
sys_info->mib = calloc_or_fail(msg->cell_to_modify[i].sys_info->mib_length, sizeof(*sys_info->mib));
|
||||
for (int j = 0; j < sys_info->mib_length; j++)
|
||||
sys_info->mib[j] = msg->cell_to_modify[i].sys_info->mib[j];
|
||||
}
|
||||
if (msg->cell_to_modify[i].sys_info->sib1_length > 0) {
|
||||
sys_info->sib1_length = msg->cell_to_modify[i].sys_info->sib1_length;
|
||||
sys_info->sib1 = calloc_or_fail(msg->cell_to_modify[i].sys_info->sib1_length, sizeof(*sys_info->sib1));
|
||||
for (int j = 0; j < sys_info->sib1_length; j++)
|
||||
sys_info->sib1[j] = msg->cell_to_modify[i].sys_info->sib1[j];
|
||||
}
|
||||
cp.cell_to_modify[i].old_plmn = msg->cell_to_modify[i].old_plmn;
|
||||
cp.cell_to_modify[i].old_nr_cellid = msg->cell_to_modify[i].old_nr_cellid;
|
||||
cp.cell_to_modify[i].info = copy_f1ap_served_cell_info(&msg->cell_to_modify[i].info);
|
||||
cp.cell_to_modify[i].sys_info = copy_f1ap_gnb_du_system_info(msg->cell_to_modify[i].sys_info);
|
||||
}
|
||||
return cp;
|
||||
}
|
||||
@@ -1521,7 +1521,7 @@ bool decode_f1ap_cu_configuration_update_acknowledge(const F1AP_F1AP_PDU_t *pdu,
|
||||
const F1AP_Cells_Failed_to_be_Activated_List_Item_t *item = &itemIE->value.choice.Cells_Failed_to_be_Activated_List_Item;
|
||||
// NR CGI (M)
|
||||
f1ap_plmn_t *plmn = &out->cells_failed_to_be_activated[j].plmn;
|
||||
TBCD_TO_MCC_MNC(&(item->nRCGI.pLMN_Identity), plmn->mcc, plmn->mnc, plmn->mnc_digit_length);
|
||||
PLMNID_TO_MCC_MNC(&(item->nRCGI.pLMN_Identity), plmn->mcc, plmn->mnc, plmn->mnc_digit_length);
|
||||
BIT_STRING_TO_NR_CELL_IDENTITY(&item->nRCGI.nRCellIdentity, out->cells_failed_to_be_activated[j].nr_cellid);
|
||||
// Cause (M)
|
||||
switch (item->cause.present) {
|
||||
|
||||
@@ -32,7 +32,7 @@ bool decode_f1ap_setup_request(const struct F1AP_F1AP_PDU *pdu, f1ap_setup_req_t
|
||||
f1ap_setup_req_t cp_f1ap_setup_request(const f1ap_setup_req_t *msg);
|
||||
bool eq_f1ap_setup_request(const f1ap_setup_req_t *a, const f1ap_setup_req_t *b);
|
||||
void free_f1ap_setup_request(const f1ap_setup_req_t *msg);
|
||||
void copy_f1ap_served_cell_info(f1ap_served_cell_info_t *a, const f1ap_served_cell_info_t *b);
|
||||
f1ap_served_cell_info_t copy_f1ap_served_cell_info(const f1ap_served_cell_info_t *src);
|
||||
void free_f1ap_cell(const f1ap_served_cell_info_t *info, const f1ap_gnb_du_system_info_t *sys_info);
|
||||
|
||||
/* F1 Setup Response */
|
||||
|
||||
@@ -53,7 +53,10 @@ bool eq_f1ap_cell_info(const f1ap_served_cell_info_t *a, const f1ap_served_cell_
|
||||
{
|
||||
_F1_EQ_CHECK_LONG(a->nr_cellid, b->nr_cellid);
|
||||
_F1_EQ_CHECK_INT(a->nr_pci, b->nr_pci);
|
||||
_F1_EQ_CHECK_INT(*a->tac, *b->tac);
|
||||
if ((!a->tac) ^ (!b->tac))
|
||||
return false;
|
||||
if (a->tac)
|
||||
_F1_EQ_CHECK_INT(*a->tac, *b->tac);
|
||||
_F1_EQ_CHECK_INT(a->mode, b->mode);
|
||||
if (a->mode == F1AP_MODE_TDD) {
|
||||
/* TDD */
|
||||
@@ -81,6 +84,13 @@ bool eq_f1ap_cell_info(const f1ap_served_cell_info_t *a, const f1ap_served_cell_
|
||||
|
||||
bool eq_f1ap_sys_info(const f1ap_gnb_du_system_info_t *a, const f1ap_gnb_du_system_info_t *b)
|
||||
{
|
||||
if (!a && !b)
|
||||
return true;
|
||||
|
||||
/* will fail if not both a/b NULL or set */
|
||||
if ((!a) ^ (!b))
|
||||
return false;
|
||||
|
||||
/* MIB */
|
||||
_F1_EQ_CHECK_INT(a->mib_length, b->mib_length);
|
||||
for (int i = 0; i < a->mib_length; i++)
|
||||
|
||||
@@ -420,12 +420,38 @@ static void test_f1ap_du_configuration_update(void)
|
||||
.plmn.mnc_digit_length = 3,
|
||||
.tac = tac,
|
||||
};
|
||||
char *mtc2_data = "mtc2";
|
||||
uint8_t *mtc2 = (void*)strdup(mtc2_data);
|
||||
int mtc2_len = strlen(mtc2_data);
|
||||
f1ap_served_cell_info_t info2 = {
|
||||
.mode = F1AP_MODE_FDD,
|
||||
.fdd.ul_freqinfo.arfcn = 640000,
|
||||
.fdd.ul_freqinfo.band = 78,
|
||||
.fdd.dl_freqinfo.arfcn = 600000,
|
||||
.fdd.dl_freqinfo.band = 78,
|
||||
.fdd.ul_tbw.nrb = 66,
|
||||
.fdd.ul_tbw.scs = 1,
|
||||
.fdd.dl_tbw.nrb = 66,
|
||||
.fdd.dl_tbw.scs = 1,
|
||||
.measurement_timing_config_len = mtc2_len,
|
||||
.measurement_timing_config = mtc2,
|
||||
.nr_cellid = 123456,
|
||||
.plmn.mcc = 2,
|
||||
.plmn.mnc = 2,
|
||||
.plmn.mnc_digit_length = 2,
|
||||
};
|
||||
/* create message */
|
||||
f1ap_gnb_du_configuration_update_t orig = {
|
||||
.transaction_id = 2,
|
||||
.num_cells_to_add = 1,
|
||||
.cell_to_add[0].info = info2,
|
||||
.num_cells_to_modify = 1,
|
||||
.cell_to_modify[0].info = info,
|
||||
.num_cells_to_delete = 0,
|
||||
.cell_to_modify[0].old_nr_cellid = 1235UL,
|
||||
.cell_to_modify[0].old_plmn.mcc = 208,
|
||||
.cell_to_modify[0].old_plmn.mnc = 88,
|
||||
.cell_to_modify[0].old_plmn.mnc_digit_length = 2,
|
||||
.num_cells_to_delete = 1,
|
||||
.cell_to_delete[0].nr_cellid = 1234UL,
|
||||
.cell_to_delete[0].plmn.mcc = 1,
|
||||
.cell_to_delete[0].plmn.mnc = 1,
|
||||
|
||||
@@ -238,10 +238,6 @@ void *gNB_app_task(void *args_p)
|
||||
|
||||
break;
|
||||
|
||||
case F1AP_GNB_DU_CONFIGURATION_UPDATE_ACKNOWLEDGE:
|
||||
LOG_E(GNB_APP, "[gNB %ld] Handling of %s message not implemented yet\n", instance, msg_name);
|
||||
break;
|
||||
|
||||
case NGAP_DEREGISTERED_GNB_IND:
|
||||
LOG_W(GNB_APP, "[gNB %ld] Received %s: associated AMF %d\n", instance, msg_name,
|
||||
NGAP_DEREGISTERED_GNB_IND(msg_p).nb_amf);
|
||||
|
||||
@@ -1166,7 +1166,7 @@ static int read_du_cell_info(configmodule_interface_t *cfg,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static f1ap_tdd_info_t read_tdd_config(const NR_ServingCellConfigCommon_t *scc)
|
||||
f1ap_tdd_info_t read_tdd_config(const NR_ServingCellConfigCommon_t *scc)
|
||||
{
|
||||
const NR_FrequencyInfoDL_t *dl = scc->downlinkConfigCommon->frequencyInfoDL;
|
||||
f1ap_tdd_info_t tdd = {
|
||||
@@ -1195,7 +1195,27 @@ static f1ap_fdd_info_t read_fdd_config(const NR_ServingCellConfigCommon_t *scc)
|
||||
return fdd;
|
||||
}
|
||||
|
||||
static f1ap_setup_req_t *RC_read_F1Setup(uint64_t id,
|
||||
f1ap_gnb_du_system_info_t *get_sys_info(NR_BCCH_BCH_Message_t *mib, const NR_BCCH_DL_SCH_Message_t *sib1)
|
||||
{
|
||||
int buf_len = 3;
|
||||
f1ap_gnb_du_system_info_t *sys_info = calloc_or_fail(1, sizeof(*sys_info));
|
||||
|
||||
sys_info->mib = calloc_or_fail(buf_len, sizeof(*sys_info->mib));
|
||||
DevAssert(mib != NULL);
|
||||
sys_info->mib_length = encode_MIB_NR(mib, 0, sys_info->mib, buf_len);
|
||||
DevAssert(sys_info->mib_length == buf_len);
|
||||
|
||||
DevAssert(sib1 != NULL);
|
||||
NR_SIB1_t *bcch_SIB1 = sib1->message.choice.c1->choice.systemInformationBlockType1;
|
||||
sys_info->sib1 = calloc_or_fail(NR_MAX_SIB_LENGTH / 8, sizeof(*sys_info->sib1));
|
||||
asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_SIB1, NULL, (void *)bcch_SIB1, sys_info->sib1, NR_MAX_SIB_LENGTH / 8);
|
||||
AssertFatal(enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n", enc_rval.failed_type->name, enc_rval.encoded);
|
||||
sys_info->sib1_length = (enc_rval.encoded + 7) / 8;
|
||||
|
||||
return sys_info;
|
||||
}
|
||||
|
||||
f1ap_setup_req_t *RC_read_F1Setup(uint64_t id,
|
||||
const char *name,
|
||||
const f1ap_served_cell_info_t *info,
|
||||
const NR_ServingCellConfigCommon_t *scc,
|
||||
@@ -1244,24 +1264,7 @@ static f1ap_setup_req_t *RC_read_F1Setup(uint64_t id,
|
||||
if (IS_SA_MODE(get_softmodem_params())) {
|
||||
// in NSA we don't transmit SIB1, so cannot fill DU system information
|
||||
// so cannot send MIB either
|
||||
|
||||
int buf_len = 3; // this is what we assume in monolithic
|
||||
req->cell[0].sys_info = calloc(1, sizeof(*req->cell[0].sys_info));
|
||||
AssertFatal(req->cell[0].sys_info != NULL, "out of memory\n");
|
||||
f1ap_gnb_du_system_info_t *sys_info = req->cell[0].sys_info;
|
||||
sys_info->mib = calloc(buf_len, sizeof(*sys_info->mib));
|
||||
DevAssert(sys_info->mib != NULL);
|
||||
DevAssert(mib != NULL);
|
||||
// encode only the mib message itself
|
||||
sys_info->mib_length = encode_MIB_NR_setup(mib->message.choice.mib, 0, sys_info->mib, buf_len);
|
||||
DevAssert(sys_info->mib_length == buf_len);
|
||||
|
||||
DevAssert(sib1 != NULL);
|
||||
NR_SIB1_t *bcch_SIB1 = sib1->message.choice.c1->choice.systemInformationBlockType1;
|
||||
sys_info->sib1 = calloc(NR_MAX_SIB_LENGTH / 8, sizeof(*sys_info->sib1));
|
||||
asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_SIB1, NULL, (void *)bcch_SIB1, sys_info->sib1, NR_MAX_SIB_LENGTH / 8);
|
||||
AssertFatal(enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n", enc_rval.failed_type->name, enc_rval.encoded);
|
||||
sys_info->sib1_length = (enc_rval.encoded + 7) / 8;
|
||||
req->cell[0].sys_info = get_sys_info(mib, sib1);
|
||||
}
|
||||
|
||||
int num = read_version(TO_STRING(NR_RRC_VERSION), &req->rrc_ver[0], &req->rrc_ver[1], &req->rrc_ver[2]);
|
||||
|
||||
@@ -95,6 +95,14 @@ gNB_RRC_INST *RCconfig_NRRRC();
|
||||
int RCconfig_NR_NG(MessageDef *msg_p, uint32_t i);
|
||||
int RCconfig_NR_X2(MessageDef *msg_p, uint32_t i);
|
||||
void wait_f1_setup_response(void);
|
||||
f1ap_setup_req_t *RC_read_F1Setup(uint64_t id,
|
||||
const char *name,
|
||||
const f1ap_served_cell_info_t *info,
|
||||
const NR_ServingCellConfigCommon_t *scc,
|
||||
NR_BCCH_BCH_Message_t *mib,
|
||||
const NR_BCCH_DL_SCH_Message_t *sib1);
|
||||
f1ap_tdd_info_t read_tdd_config(const NR_ServingCellConfigCommon_t *scc);
|
||||
f1ap_gnb_du_system_info_t *get_sys_info(NR_BCCH_BCH_Message_t *mib, const NR_BCCH_DL_SCH_Message_t *sib1);
|
||||
int gNB_app_handle_f1ap_gnb_cu_configuration_update(f1ap_gnb_cu_configuration_update_t *gnb_cu_cfg_update);
|
||||
MessageDef *RCconfig_NR_CU_E1(const E1_t *entity);
|
||||
ngran_node_t get_node_type(void);
|
||||
|
||||
@@ -1941,7 +1941,8 @@ static void nr_generate_Msg4_MsgB(module_id_t module_idP,
|
||||
|
||||
NR_UE_info_t *UE = find_nr_UE(&nr_mac->UE_info, ra->rnti);
|
||||
if (!UE) {
|
||||
LOG_E(NR_MAC, "want to generate %s, but rnti %04x not in the table\n", ra_type_str, ra->rnti);
|
||||
LOG_E(NR_MAC, "want to generate %s, but rnti %04x not in the table. Abort RA\n", ra_type_str, ra->rnti);
|
||||
nr_clear_ra_proc(ra);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -938,6 +938,9 @@ void nr_schedule_ue_spec(module_id_t module_id,
|
||||
NR_UEs_t *UE_info = &gNB_mac->UE_info;
|
||||
nfapi_nr_dl_tti_request_body_t *dl_req = &DL_req->dl_tti_request_body;
|
||||
|
||||
const NR_BWP_t *initialDL = &scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters;
|
||||
gNB_mac->mac_stats.total_prb_aggregate += NRRIV2BW(initialDL->locationAndBandwidth, MAX_BWP_SIZE);
|
||||
|
||||
UE_iterator(UE_info->list, UE) {
|
||||
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
|
||||
NR_UE_DL_BWP_t *current_BWP = &UE->current_DL_BWP;
|
||||
@@ -1252,6 +1255,7 @@ void nr_schedule_ue_spec(module_id_t module_id,
|
||||
T(T_GNB_MAC_RETRANSMISSION_DL_PDU_WITH_DATA, T_INT(module_id), T_INT(CC_id), T_INT(rnti),
|
||||
T_INT(frame), T_INT(slot), T_INT(current_harq_pid), T_INT(harq->round), T_BUFFER(harq->transportBlock, TBS));
|
||||
UE->mac_stats.dl.total_rbs_retx += sched_pdsch->rbSize;
|
||||
gNB_mac->mac_stats.used_prb_aggregate += sched_pdsch->rbSize;
|
||||
} else { /* initial transmission */
|
||||
LOG_D(NR_MAC, "Initial HARQ transmission in %d.%d\n", frame, slot);
|
||||
uint8_t *buf = (uint8_t *) harq->transportBlock;
|
||||
@@ -1369,6 +1373,7 @@ void nr_schedule_ue_spec(module_id_t module_id,
|
||||
UE->mac_stats.dl.num_mac_sdu += sdus;
|
||||
UE->mac_stats.dl.current_rbs = sched_pdsch->rbSize;
|
||||
UE->mac_stats.dl.total_sdu_bytes += dlsch_total_bytes;
|
||||
gNB_mac->mac_stats.used_prb_aggregate += sched_pdsch->rbSize;
|
||||
|
||||
/* save retransmission information */
|
||||
harq->sched_pdsch = *sched_pdsch;
|
||||
|
||||
@@ -3319,7 +3319,7 @@ bool nr_mac_request_release_ue(const gNB_MAC_INST *nrmac, int rnti)
|
||||
.gNB_CU_ue_id = ue_data.secondary_ue,
|
||||
.gNB_DU_ue_id = rnti,
|
||||
.cause = F1AP_CAUSE_RADIO_NETWORK,
|
||||
.cause_value = F1AP_CauseRadioNetwork_rl_failure_others,
|
||||
.cause_value = F1AP_CauseRadioNetwork_rl_failure_rlc,
|
||||
};
|
||||
nrmac->mac_rrc.ue_context_release_request(&request);
|
||||
return true;
|
||||
|
||||
@@ -99,7 +99,8 @@ static bool check_plmn_identity(const f1ap_plmn_t *check_plmn, const f1ap_plmn_t
|
||||
return plmn->mcc == check_plmn->mcc && plmn->mnc_digit_length == check_plmn->mnc_digit_length && plmn->mnc == check_plmn->mnc;
|
||||
}
|
||||
|
||||
static void du_clear_all_ue_states()
|
||||
/* not static, so we can call it from the outside (in telnet) */
|
||||
void du_clear_all_ue_states()
|
||||
{
|
||||
gNB_MAC_INST *mac = RC.nrmac[0];
|
||||
NR_SCHED_LOCK(&mac->sched_lock);
|
||||
|
||||
@@ -82,10 +82,8 @@ static void gnb_du_configuration_update_f1ap(const f1ap_gnb_du_configuration_upd
|
||||
f1ap_gnb_du_configuration_update_t cp = cp_f1ap_du_configuration_update(upd);
|
||||
/* transfer to ITTI message */
|
||||
F1AP_GNB_DU_CONFIGURATION_UPDATE(msg) = cp;
|
||||
/* free after copy */
|
||||
free_f1ap_du_configuration_update(upd);
|
||||
/* send to RRC task */
|
||||
itti_send_msg_to_task(TASK_RRC_GNB, 0, msg);
|
||||
itti_send_msg_to_task(TASK_DU_F1, 0, msg);
|
||||
}
|
||||
|
||||
static void ue_context_setup_response_f1ap(const f1ap_ue_context_setup_t *req, const f1ap_ue_context_setup_t *resp)
|
||||
|
||||
@@ -807,6 +807,11 @@ typedef struct {
|
||||
int8_t nvipc_poll_core;
|
||||
} nvipc_params_t;
|
||||
|
||||
typedef struct {
|
||||
uint64_t total_prb_aggregate;
|
||||
uint64_t used_prb_aggregate;
|
||||
} mac_stats_t;
|
||||
|
||||
/*! \brief top level eNB MAC structure */
|
||||
typedef struct gNB_MAC_INST_s {
|
||||
/// Ethernet parameters for northbound midhaul interface
|
||||
@@ -930,6 +935,8 @@ typedef struct gNB_MAC_INST_s {
|
||||
|
||||
pthread_mutex_t sched_lock;
|
||||
|
||||
mac_stats_t mac_stats;
|
||||
|
||||
} gNB_MAC_INST;
|
||||
|
||||
#endif /*__LAYER2_NR_MAC_GNB_H__ */
|
||||
|
||||
@@ -920,10 +920,14 @@ void nr_rrc_config_dl_tda(struct NR_PDSCH_TimeDomainResourceAllocationList *pdsc
|
||||
}
|
||||
|
||||
|
||||
void nr_rrc_config_ul_tda(NR_ServingCellConfigCommon_t *scc, int min_fb_delay){
|
||||
|
||||
void nr_rrc_config_ul_tda(NR_ServingCellConfigCommon_t *scc, int min_fb_delay)
|
||||
{
|
||||
//TODO change to accomodate for SRS
|
||||
|
||||
const NR_PUSCH_TimeDomainResourceAllocationList_t *tda =
|
||||
scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList;
|
||||
AssertFatal(tda->list.count == 0, "already have pusch_TimeDomainAllocationList members\n");
|
||||
|
||||
frame_type_t frame_type = get_frame_type(*scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0], *scc->ssbSubcarrierSpacing);
|
||||
const int k2 = min_fb_delay;
|
||||
|
||||
|
||||
+28
-16
@@ -106,6 +106,21 @@ extern RAN_CONTEXT_t RC;
|
||||
|
||||
mui_t rrc_gNB_mui = 0;
|
||||
|
||||
typedef struct deliver_ue_ctxt_release_data_t {
|
||||
gNB_RRC_INST *rrc;
|
||||
f1ap_ue_context_release_cmd_t *release_cmd;
|
||||
sctp_assoc_t assoc_id;
|
||||
} deliver_ue_ctxt_release_data_t;
|
||||
|
||||
static void rrc_deliver_ue_ctxt_release_cmd(void *deliver_pdu_data, ue_id_t ue_id, int srb_id, char *buf, int size, int sdu_id)
|
||||
{
|
||||
DevAssert(deliver_pdu_data != NULL);
|
||||
deliver_ue_ctxt_release_data_t *data = deliver_pdu_data;
|
||||
data->release_cmd->rrc_container = (uint8_t*) buf;
|
||||
data->release_cmd->rrc_container_length = size;
|
||||
data->rrc->mac_rrc.ue_context_release_command(data->assoc_id, data->release_cmd);
|
||||
}
|
||||
|
||||
///---------------------------------------------------------------------------------------------------------------///
|
||||
///---------------------------------------------------------------------------------------------------------------///
|
||||
|
||||
@@ -1974,8 +1989,18 @@ static void rrc_CU_process_ue_context_release_request(MessageDef *msg_p, sctp_as
|
||||
rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(rrc, req->gNB_CU_ue_id);
|
||||
// TODO what happens if no AMF connected? should also handle, set an_release true
|
||||
if (!ue_context_p) {
|
||||
LOG_E(RRC, "could not find UE context for CU UE ID %u, aborting transaction\n", req->gNB_CU_ue_id);
|
||||
// TODO just request the DU to release to make it happy
|
||||
LOG_W(RRC, "could not find UE context for CU UE ID %u: auto-generate release command\n", req->gNB_CU_ue_id);
|
||||
uint8_t buffer[RRC_BUF_SIZE] = {0};
|
||||
int size = do_NR_RRCRelease(buffer, RRC_BUF_SIZE, rrc_gNB_get_next_transaction_identifier(0));
|
||||
f1ap_ue_context_release_cmd_t ue_context_release_cmd = {
|
||||
.gNB_CU_ue_id = req->gNB_CU_ue_id,
|
||||
.gNB_DU_ue_id = req->gNB_DU_ue_id,
|
||||
.cause = F1AP_CAUSE_RADIO_NETWORK,
|
||||
.cause_value = 10, // 10 = F1AP_CauseRadioNetwork_normal_release
|
||||
.srb_id = DCCH,
|
||||
};
|
||||
deliver_ue_ctxt_release_data_t data = {.rrc = rrc, .release_cmd = &ue_context_release_cmd};
|
||||
nr_pdcp_data_req_srb(req->gNB_CU_ue_id, DCCH, rrc_gNB_mui++, size, buffer, rrc_deliver_ue_ctxt_release_cmd, &data);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2473,6 +2498,7 @@ void *rrc_gnb_task(void *args_p) {
|
||||
switch (ITTI_MSG_ID(msg_p)) {
|
||||
case TERMINATE_MESSAGE:
|
||||
LOG_W(NR_RRC, " *** Exiting NR_RRC thread\n");
|
||||
timer_remove(stats_timer_id);
|
||||
itti_exit_task();
|
||||
break;
|
||||
|
||||
@@ -2645,20 +2671,6 @@ void rrc_gNB_generate_SecurityModeCommand(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p)
|
||||
nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, buffer, size);
|
||||
}
|
||||
|
||||
typedef struct deliver_ue_ctxt_release_data_t {
|
||||
gNB_RRC_INST *rrc;
|
||||
f1ap_ue_context_release_cmd_t *release_cmd;
|
||||
sctp_assoc_t assoc_id;
|
||||
} deliver_ue_ctxt_release_data_t;
|
||||
static void rrc_deliver_ue_ctxt_release_cmd(void *deliver_pdu_data, ue_id_t ue_id, int srb_id, char *buf, int size, int sdu_id)
|
||||
{
|
||||
DevAssert(deliver_pdu_data != NULL);
|
||||
deliver_ue_ctxt_release_data_t *data = deliver_pdu_data;
|
||||
data->release_cmd->rrc_container = (uint8_t*) buf;
|
||||
data->release_cmd->rrc_container_length = size;
|
||||
data->rrc->mac_rrc.ue_context_release_command(data->assoc_id, data->release_cmd);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/*
|
||||
* Generate the RRC Connection Release to UE.
|
||||
|
||||
@@ -448,7 +448,7 @@ static void update_cell_info(nr_rrc_du_container_t *du, const f1ap_served_cell_i
|
||||
f1ap_served_cell_info_t *ci = &du->setup_req->cell[0].info;
|
||||
// make sure no memory is allocated
|
||||
free_f1ap_cell(ci, NULL);
|
||||
copy_f1ap_served_cell_info(ci, new_ci);
|
||||
*ci = copy_f1ap_served_cell_info(new_ci);
|
||||
|
||||
NR_MeasurementTimingConfiguration_t *new_mtc =
|
||||
extract_mtc(new_ci->measurement_timing_config, new_ci->measurement_timing_config_len);
|
||||
@@ -505,8 +505,10 @@ void rrc_gNB_process_f1_du_configuration_update(f1ap_gnb_du_configuration_update
|
||||
// MIB is mandatory, so will be overwritten. SIB1 is optional, so will
|
||||
// only be overwritten if present in sys_info
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_MIB, du->mib);
|
||||
if (sys_info->sib1 != NULL)
|
||||
if (sys_info->sib1 != NULL) {
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_SIB1, du->sib1);
|
||||
du->sib1 = NULL;
|
||||
}
|
||||
|
||||
NR_MIB_t *mib = NULL;
|
||||
if (!extract_sys_info(sys_info, &mib, &du->sib1)) {
|
||||
@@ -531,8 +533,6 @@ void rrc_gNB_process_f1_du_configuration_update(f1ap_gnb_du_configuration_update
|
||||
/* Send DU Configuration Acknowledgement */
|
||||
f1ap_gnb_du_configuration_update_acknowledge_t ack = {.transaction_id = conf_up->transaction_id};
|
||||
rrc->mac_rrc.gnb_du_configuration_update_acknowledge(assoc_id, &ack);
|
||||
/* free F1AP message after use */
|
||||
free_f1ap_du_configuration_update(conf_up);
|
||||
}
|
||||
|
||||
void rrc_CU_process_f1_lost_connection(gNB_RRC_INST *rrc, f1ap_lost_connection_t *lc, sctp_assoc_t assoc_id)
|
||||
|
||||
@@ -1085,7 +1085,16 @@ static void rfsimulator_end(openair0_device *device) {
|
||||
}
|
||||
close(s->epollfd);
|
||||
hashtable_destroy(&s->fd_to_buf_map);
|
||||
free(s);
|
||||
}
|
||||
static void stopServer(openair0_device *device)
|
||||
{
|
||||
rfsimulator_state_t *t = (rfsimulator_state_t *) device->priv;
|
||||
DevAssert(t != NULL);
|
||||
close(t->listen_sock);
|
||||
rfsimulator_end(device);
|
||||
}
|
||||
|
||||
static int rfsimulator_stop(openair0_device *device) {
|
||||
return 0;
|
||||
}
|
||||
@@ -1136,7 +1145,7 @@ int device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
|
||||
device->trx_start_func = rfsimulator->role == SIMU_ROLE_SERVER ? startServer : startClient;
|
||||
device->trx_get_stats_func = rfsimulator_get_stats;
|
||||
device->trx_reset_stats_func = rfsimulator_reset_stats;
|
||||
device->trx_end_func = rfsimulator_end;
|
||||
device->trx_end_func = rfsimulator->role == SIMU_ROLE_SERVER ? stopServer : rfsimulator_end;
|
||||
device->trx_stop_func = rfsimulator_stop;
|
||||
device->trx_set_freq_func = rfsimulator_set_freq;
|
||||
device->trx_set_gains_func = rfsimulator_set_gains;
|
||||
|
||||
Reference in New Issue
Block a user