- make it work for SRB or DRB
- adapt callers of this function
- cleanup key derivation: the User Plane keys are generated at some places
but are not used, remove the generation
Compiling the nrUE with -fsanitize=undefined leads to a crash
because the function nas_stream_encrypt_eia1() accesses the data
as uint32_t but the data is not aligned.
Actually this function wants 64 bits (big-endian) of data, so let's
introduce a simple function to read a big-endian 64 bits value.
It may seem bad (unoptimized), but looking at the output of gcc
without -fsanitize=undefined this will be translated as just one
movbeq instruction (on the machine where I did the test), which is
actually less instructions than the previous version which was doing
too movbel plus orq.
Moreover, after the main loop we need to process the last remaining
bytes (so less than 8). The code was wrong, reading past the input
data (and also not caring about alignment). It may work, it may fail,
it depends on many things. But it's plain wrong. So this was replaced
for something better, simpler. No need for mask32bit() anymore, only
one call to U64() is needed.
And now -fsanitize=undefined is happy, so all is good.
We also restrict the input length to be multiple of 8 bits. I don't
think it's a problem. To be refined if I'm wrong. (I think RRC and
NAS messages are 8-bits aligned, so it shouldn't be a problem.)
It should not be > 0xffffff.
Normally the core network would prevent this case from happening.
Plus to reach this value means to send a lot of NAS messages, which
is very doubtful in practice.
Anyway, it's better to deal with the case.
We exit if that happens. To be refined if needed (very doubtful).
This function was very wrong, now it's just wrong.
(It does not sanitize the input properly. Some bad input may have
unexpected effects on the nrUE.)
It needs a serious rewrite.
I just wanted to "fix" it so that it processes correctly some
correct input data.
OAI core network is sending Deregistation Accept in clear, even
after security context activation.
The standards is not clear to me, so let's accept it.
To be removed if incorrect with respect to the standards.
(The core network will need to be fixed then.)
The version before this commit is wrong, taking wrong byte for msg_type
in some cases.
I don't have much time to implement a proper NAS PDU parser, so let's go
with hardcoded values.
Some later work will be done to have a cleaner solution. As of now, it's
too much work.
Get the security algorithms from SecurityModeCommand.
Restructure the code a bit: add the function handle_security_mode_command()
and adapt the code to use it.
Derive also knas_enc (not used yet).
Do the derivation for knas_enc and knas_int only after reception
of SecurityModeCommand. We need the algorithms configured by core
network to derive those keys.
The starting point was the function do_NR_DLInformationTransfer() which
may deal with more than 256 bytes.
Then why not cleanup all the functions in the same file.
(And do a bit of formattting fixing while we're here.)
Then cleanup the callers of those functions.
Then, because of do_SIB23_NR() let's also cleanup in some
structures.
Not all the codebase was cleaned up, there surely remain some uint8_t
(and char/short/uint16_t) which are wrong.
By using a struct we may have warnings at compilation time in some
cases if the type is not used properly.
The type definition becomes a bit weird, so we need to properly
comment.
If too strange, we can revert to the classical "void" definition.
- rename "lib_ctx" to "mac_implementation" which is what is stored because
of previous commit
- rename "mac" to "mac_context" to be clearer with what is stored in this
variable too
The main work of this commit is to rewrite cipher_aes_128_cbc_cmac()
which was too slow and created issues when running the 4G eNB on some
machines (LLL when using a b210).
Instead of creating the security context, use it, and delete it, all in
cipher_aes_128_cbc_cmac(), we introduce the function init_aes_128_cbc_cmac()
to create it, and we change cipher_aes_128_cbc_cmac() to just use it,
and we also adapt free_aes_128_cbc_cmac(). The function aes_128_cbc_cmac()
is removed, it does not follow the new init/use/free API.
Doing so, on the primary test machine used to do this work (a powerful
and fast machine where it is possible to set the CPUs' frequencies)
it was possible to limit the CPUs' frequencies to 500 MHz (it was not
possible to go lower) without any LLL (using a b210, quectel UE in
idle, no data traffic, only periodic measurement reports). Before this
commit, it was necessary to set a frequency of at least 1.8 GHz
otherwise some LLL would appear.
Then we need to adapt the rest of the code to take into account those
changes.
A notion of security container (stream_security_container_t) containing
ciphering and integrity contexts is introduced.
And the code is harmonized for, hopefully, better readability.
The (opaque) type stream_security_context_t is introduced, used by
both integrity and ciphering contexts. The idea is to use a
init()/use()/free() API for all the security procedures, identical for
all the ciphering and integrity procedures.
Introduce the structure nr_pdcp_integrity_data_t and adapt code to use it.
Note: in nr_pdcp_sdu_t we keep the 'count' variable (which is also present
in nr_pdcp_integrity_data_t). They represent the same value, but 'count'
in nr_pdcp_integrity_data_t is to be specifically used for integrity while
the other one has other uses, so it's better to keep it.
The case securityModeFailure didn't seem to be implemented
properly, so I just removed it entirely.
The variable 'securityMode' did not make much sense, removed as well.
Plus for integrity, there was: securityMode |= 1 << 5 for nea1
and << 6 for nea2, which does not seem correct (I would expect << 4
and << 5 respectively), so it was properly incorrect.
'securityModeCommand->criticalExtensions.choice.securityModeCommand'
was accessed before checking that
'securityModeCommand->criticalExtensions.present'
is 'NR_SecurityModeCommand__criticalExtensions_PR_securityModeCommand',
which is wrong.
The tests 'securityMode >= NO_SECURITY_MODE' and 'securityMode != 0xff'
don't make sense/are unclear, so removed too.
So let's simplify this function, wrong in several places. And put
some AssertFatal() so that the code won't do weird things. The
AssertFatal() can be removed later and the function improved later
if needed. The case securityModeFailure can also be handled later,
but I think there is more work to do than just encoding the message
and send it to the gNB, so it's not bad to remove it for the moment.
The use of security_mode_completed in the PDCP entity was a hack.
Plus it was not working at all with the deregistration request
when nea2 is used, sent when doing ctrl+c in the nrUE.
So let's remove it.
And let's handle activation of integrity and ciphering more in
accordance with what 38.331 says. SecurityModeComplete has to
be sent integrity protected, but not ciphered. Only after should
the ciphering be activated. (See 38.331 5.3.4.3.)
A COTS UE is sending UE capabilities with accessStratumRelease "rel16"
which is not decoded by our RRC. Switching to RRC 16.13.0 lets our RRC
accept these capabilities (and as a positive side effect lets this
particular UE work nicely in NSA fr1).
cleanup means:
- typo: susbend -> suspend
- call nr_pdcp_manager_unlock() where needed
- simplify LOG_XX (remove __FILE__, __LINE__, __FUNCTION__)
note:
nr_pdcp_release_srb() and nr_pdcp_release_drb() don't use
nr_pdcp_release_drb() because they modify the arrays, so
it does not make sense to "abstract" the accesses to
->srb and ->drb.
Security part needs to be checked, may fail to work.
But if it fails, it was probably not working before either.
This commit also contains adding 'static' to nr_pdcp_entity_release()
and nr_pdcp_entity_delete() (it was too complicated to do a separate
commit for this).
We also update stats in free_rx_list() (again, too complicated for
a separate commit).
openair2/RRC/NR/rrc_gNB.c probably needs some more work, it is a
bit ugly to reestablish all the drbs without checking if they
exit. It will generate warnings at runtime. I didn't do it because
I don't know the proper way.
The function generateDRB() sets the value to 100ms but the function
rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ() sets it to 0ms.
So what happens is that the UE gets the value 100ms in the
RRC Reconfiguration but the gNB creates the PDCP entity with 0ms.
Let's create it with 100ms instead, to be aligned with how we configure
the UE.
And also avoid some PDCP warnings at runtime when some packets
are retransmitted but rejected because of the 0ms timer. This is
the warning:
[PDCP] discard NR PDU rcvd_count=68469, entity->rx_deliv 68481,sdu_in_list 0
This is just a hotfix. A real solution is to have the RB creation in
only one place. And we should also have those parameters configurable.
Work for later.
This commit follows the previous one and adds a dependancy for the
generated .h files so that when we change T_messages.txt to add a
T trace, the compilation succeeds when using ninja in
cmake_targets/ran_build/build.
When using the make system to generate T files, if you change
T_messages.txt you may have problems compiling the gnb with ninja.
If you want to see the problem:
First run: cd cmake_targets; ./build_oai --ninja --gNB
Then: cd common/utils/T
edit T_messages.txt, add a trace, for example:
---
ID = ENB_PHY_UL_TOCK
DESC = eNodeB uplink tick - one tick per ms at start of uplink processing
GROUP = ALL:PHY:GRAPHIC:ENB
FORMAT = int,eNB_ID : int,frame : int,subframe
---
then run: make
then: cd cmake_targets/ran_build/build; ninja nr-softmodem
You should have an error looking like this:
---
[3/81] Checking validity of VCD files
FAILED: common/utils/T/CMakeFiles/check_vcd /tmp/develop/cmake_targets/ran_build/build/common/utils/T/CMakeFiles/check_vcd
cd /tmp/develop/cmake_targets/ran_build/build/common/utils/T && /tmp/develop/cmake_targets/ran_build/build/common/utils/T/_check_vcd /tmp/develop/common/utils/T/T_messages.txt /tmp/develop/common/utils/T/../LOG/vcd_signal_dumper.h
error: VCD_FIRST_VARIABLE is not correct in T_defs.h
You probably added a VCD trace (variable or function) but you did not
update T_messages.txt and/or T_defs.h in common/utils/T/
[...]
---
Let's first isolate the generated T .h files when using make because
we have two versions of T_IDs.h and T_messages.txt.h when mixing
make/cmake.
A next commit will regenerate T_IDs.h and T_messages.txt.h when
T_messages.txt chages for the cmake system, because this commit
does not solve the problem.
tx_next was increased only when all segments of an SDU were sent to
lower layers. This may lead to a situation where the receive entity
transmits a control PDU that is rejected because it sets its ACK to
tx_next+1 (if all segments were not transmitted when the control PDU
is sent).
What is done now is to increase tx_next as soon as we send the first
segment of an SDU to lower layers. A control PDU received from the
receive entity is now accepted and processed.
Specifications (38.322 5.2.3.1.1) say to increase tx_next when the
RLC entity receives an SDU from upper layers. But for us, since the
buffering of SDUs is done in the RLC layer and since the buffer size
may be big, we may increase tx_next too much. The choice has been
made to increase it only when we transmit an SDU to lower layers.
We may change this logic if needed. (But it won't be simple.)
When t_poll_retransmit expires we need to consider an SDU for
retransmission.
We used to take the first SDU (which could be a segment, not a full SDU)
of the wait list and put it in the retransmit list.
When testing with some UE (Amarisoft UE) a bad behavior was detected.
This is what happens for the SDU with SN 6 (for illustration purpose).
The gNB is sending an SDU in several pieces (it is segmented).
slot n: rlc sn 6 [1 .. 119[ p=0 RECEIVED
slot n+x: rlc sn 6 ]120 .. 180[ p=0 RECEIVED
slot n+x+y: rlc sn 6 ]181 .. 210] p=1 not RECEIVED
Then when t_poll_retransmit expires rlc retransmits only the PDU of
slot n (with p=1 this time) and the UE replies with ack 6. So nothing
happens on the gnb side.
(We would have expected ack 7 + nack 6 181..end.)
Then after t_poll_retransmit expires again rlc retransmits only PDU
of slot n and the UE still replies with ack 6.
This goes on forever (or some other timeout occurs.)
The logic is now changed.
When t_poll_retransmit expires we transfer all the SDUs in the wait list
having the same SN as the head of the wait list into the retransmit list.
Testing with Amarisoft UE, it seems to work properly.
The RLC tests were not compiling because of the include of
openair2/RRC/NR/rrc_gNB_radio_bearers.h
by
openair2/LAYER2/nr_rlc/nr_rlc_entity.h
which does not seem correct/necessary to start with.
The only thing needed by nr_rlc_entity.h from rrc_gNB_radio_bearers.h
is MAX_DRBS_PER_UE which can be defined in common/platform_constants.h
like NGAP_MAX_PDU_SESSION.
At Eurecom now we only have Nuand bladeRF 2.0 (bladerf2) and those
calibration calls fail, so let's remove them. Maybe they are needed
for other boards, but we can't test at Eurecom. In case of problems
with other boards, contact us.
We don't work much on asn1c. The version we use has several bugs.
There is an active community out there that fixes bugs and improves
asn1c. Let's use their version.
We need to test security and integrity protection in the CI.
This commit activates ciphering+integrity protection for SRBs
and DRBs using nea2/nia2 for the amarisoft-ue + aw2s CI pipeline.
It may happen that the drb to configure is not 1, so we may need
this array in rrc_gNB_generate_dedicatedRRCReconfiguration().
Not tested, this commit is mostly to harmonize with other places in
openair2/RRC/NR/rrc_gNB.c
This commit fixes a bug caused by global variables in the gNB_MAC_INST
structure used to transfer MAC scheduler's results to the PHY layer.
When using several threads in the PHY layer, it may happen that the
MAC scheduler is called a second time by the second PHY thread for the
next slot before the content of the global variables in the gNB_MAC_INST
structure used to store the result of the MAC scheduler for the current
slot have been consumed by the first thread, leading to unpredictable
results (all of them certainly wrong).
The solution is to introduce a small memory management module for the
interface between the PHY threads and the MAC scheduler. The MAC
scheduler now fills the data structures passed to it, and not a
global variable anymore. The PHY layer manages the structures and
ensures that no data is overwritten before being fully consumed by
the various threads of the PHY layer.
Some care has to be taken because several PHY threads will access the
same structures at the same time for a given slot (in read mode, so
it's okay). A mechanism of reference counting has thus been introduced.
Only one CC is supported. This restriction should not be too hard
to remove if/when needed. (The code before this commit does not seem
to work for more than one CC anyway.)
For some (unclear) reason, nr-softmodem with aw2s device does not print
"Bye." when stopping it with control+c, which is problematic in the CI.
This little hack solves the problem.
(Maybe not the right solution, to be changed if needed.)
The d array has to be cleared at the first usage, which may not necessarily
be when new_rx is true. For example, in case of DTX detected for a first
transmission, the next transmission won't have new_rx true, so d won't be
cleared, containing data from a previous transmission. Or when a LDPC
decoding is cancelled for a segment when new_rx is true, a decoding for
a retransmission will not clear d because then new_rx will not be true.
(Yes, the logic of cancellation will be changed in the future, but the
changes will be orthogonal to the ones of this commit.)
new_rx is removed.
The LOG_x() and T() logic was wrong.
LOG_x() goes to the terminal when T_stdout == 1 or T_stdout == 2.
It goes to T() when T_stdout == 0 or T_stdout == 2.
The call T() does the check for T_stdout == 0 or T_stdout == 2.
So we have to call it out of the check "if (T_stdout)".
So, well, let's fix that.
Some spacing was fixed as well. clang-format may complain.
On a setup, length of cellGroupConfig was > 255.
Using uint8_t to store the length is thus wrong
and gives a bad encoding of the cellGroupConfig.
So let's use uint32_t to store length instead of uint8_t.
Some problems when we release the device:
- Calling the destructors is wrong, we should set the pointers to NULL.
These are shared pointers, this is C++.
- We have to stop rx by doing a STREAM_MODE_STOP_CONTINUOUS.
- The end-of-burst for tx has been simplified.
This problem when we acquire the device:
- Calling get_rx_stream() many times seems to be problematic.
We now should have a better behavior with UHD 4.2 and N310. (Hopefully with
others too.) No crash seen so far.
There was a problem testing accelleran cu + oai du + oai ue + rfsim
because accelleran cu configures sdap header for UL but not for DL
and our sdap implementation deals with either "no sdap header at all"
or "sdap headers for both UL and DL".
The code has been modified to deal with the other cases
("sdap header for UL but not DL" and "sdap header for DL but not UL").
has_sdapDLheader and has_sdapULheader have been removed, has_sdap
too, replaced by has_sdap_rx and has_sdap_tx, which makes the code
independant of ue or gnb and is, I think, clearer.
With this work, accelleran cu + oai du + oai ue + rfsim works. We
also have oai gnb + oai ue + rfsim functional for all cases of sdap
header configuration (this won't happen for users, the code of gnb has to
be modified to have sdap header for only ul or only dl). It also works
with a COTS UE for all cases of sdap configuration (again, this won't
happen for users, only "no sdap header" and "sdap headers for both
UL and DL" exist in oai gnb with the current code).
To have other cases, you can edit openair2/RRC/NR/rrc_gNB_radio_bearers.c
and search for NR_SDAP_Config__sdap_HeaderDL_present in there.
To enable sdap, run the gnb with the command line argument
--gNBs.[0].enable_sdap 1
There was a problem in rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND()
where we PROTOCOL_CTXT_SET_BY_INSTANCE() that does not initialize
eNB_index leading to a crash later on in pdcp. So let's initialize
everything.
Plus, while we're here, use do { } while(0) in the macros, just to avoid
problems like:
if (condition)
macro;
Without do { } while(0) only the first statement of the macro is done
in the if. (Not sure if the code has the problem somewhere, but doesn't
hurt to fix.)
There was a crash when we exit the nr softmodem with AW2S device.
The array rxbase[] was surely freed() by some other thread, so
let's not access it after detecting oai_exit != 0.
We also need to unblock a possible reader thread. The chosen way to
do may be not the best. To be checked.
Not only the teid is received from the DU but also the IP address. We
have to use it too.
Also, don't connect the UDP socket. The parameter remote_s_address in the
configuration file must not be used, at least not for gtp-u because the
IP address is received from the DU (plus for later, for multiple DUs, it
won't work at all).
- AssertFatal() in nr_rlc_srb0_recv_sdu() if the srb0 is not found
- do_RRCSetup() may return -1, handle it properly
- do_RRCReject() may return -1, handle it properly
- remove one switch in rrc_gNB_generate_RRCReject()