From 3310f5c6b04f30720c783abe3b05e58113cfd170 Mon Sep 17 00:00:00 2001 From: Cedric Roux <cedric.roux@eurecom.fr> Date: Thu, 25 Apr 2019 10:54:58 +0200 Subject: [PATCH] alternative RLC implementation This commit introduces an alternative RLC implementation based on 36.322 version 8. AM and UM done, TM not done. See openair2/LAYER2/rlc_v2/TODO for missing parts. --- cmake_targets/CMakeLists.txt | 21 +- common/utils/T/tracer/hacks/pilot_timeplot.sh | 15 + common/utils/T/tracer/hacks/time_meas.c | 10 +- common/utils/T/tracer/hacks/timeplot.c | 18 +- openair2/COMMON/rrc_messages_def.h | 3 + openair2/COMMON/rrc_messages_types.h | 10 + openair2/LAYER2/rlc_v2/TODO | 18 + openair2/LAYER2/rlc_v2/asn1_utils.c | 129 ++ openair2/LAYER2/rlc_v2/asn1_utils.h | 33 + openair2/LAYER2/rlc_v2/rlc_entity.c | 144 ++ openair2/LAYER2/rlc_v2/rlc_entity.h | 97 + openair2/LAYER2/rlc_v2/rlc_entity_am.c | 1694 +++++++++++++++++ openair2/LAYER2/rlc_v2/rlc_entity_am.h | 285 +++ openair2/LAYER2/rlc_v2/rlc_entity_um.c | 703 +++++++ openair2/LAYER2/rlc_v2/rlc_entity_um.h | 90 + openair2/LAYER2/rlc_v2/rlc_oai_api.c | 821 ++++++++ openair2/LAYER2/rlc_v2/rlc_pdu.c | 266 +++ openair2/LAYER2/rlc_v2/rlc_pdu.h | 109 ++ openair2/LAYER2/rlc_v2/rlc_sdu.c | 68 + openair2/LAYER2/rlc_v2/rlc_sdu.h | 39 + openair2/LAYER2/rlc_v2/rlc_ue_manager.c | 182 ++ openair2/LAYER2/rlc_v2/rlc_ue_manager.h | 58 + openair2/LAYER2/rlc_v2/tests/LOG/log.h | 10 + openair2/LAYER2/rlc_v2/tests/Makefile | 32 + openair2/LAYER2/rlc_v2/tests/README | 38 + openair2/LAYER2/rlc_v2/tests/make_pdu.c | 29 + openair2/LAYER2/rlc_v2/tests/run_tests.sh | 12 + openair2/LAYER2/rlc_v2/tests/test.c | 433 +++++ openair2/LAYER2/rlc_v2/tests/test1.h | 14 + openair2/LAYER2/rlc_v2/tests/test1.txt.gz | Bin 0 -> 238 bytes openair2/LAYER2/rlc_v2/tests/test10.h | 23 + openair2/LAYER2/rlc_v2/tests/test10.txt.gz | Bin 0 -> 361 bytes openair2/LAYER2/rlc_v2/tests/test11.h | 37 + openair2/LAYER2/rlc_v2/tests/test11.txt.gz | Bin 0 -> 430 bytes openair2/LAYER2/rlc_v2/tests/test12.h | 34 + openair2/LAYER2/rlc_v2/tests/test12.txt.gz | Bin 0 -> 415 bytes openair2/LAYER2/rlc_v2/tests/test13.h | 30 + openair2/LAYER2/rlc_v2/tests/test13.txt.gz | Bin 0 -> 351 bytes openair2/LAYER2/rlc_v2/tests/test14.h | 12 + openair2/LAYER2/rlc_v2/tests/test14.txt.gz | Bin 0 -> 180 bytes openair2/LAYER2/rlc_v2/tests/test15.h | 42 + openair2/LAYER2/rlc_v2/tests/test15.txt.gz | Bin 0 -> 360 bytes openair2/LAYER2/rlc_v2/tests/test16.h | 48 + openair2/LAYER2/rlc_v2/tests/test16.txt.gz | Bin 0 -> 353 bytes openair2/LAYER2/rlc_v2/tests/test17.h | 30 + openair2/LAYER2/rlc_v2/tests/test17.txt.gz | Bin 0 -> 298 bytes openair2/LAYER2/rlc_v2/tests/test18.h | 10 + openair2/LAYER2/rlc_v2/tests/test18.txt.gz | Bin 0 -> 207 bytes openair2/LAYER2/rlc_v2/tests/test19.h | 54 + openair2/LAYER2/rlc_v2/tests/test19.txt.gz | Bin 0 -> 101 bytes openair2/LAYER2/rlc_v2/tests/test2.h | 10 + openair2/LAYER2/rlc_v2/tests/test2.txt.gz | Bin 0 -> 1616 bytes openair2/LAYER2/rlc_v2/tests/test20.h | 28 + openair2/LAYER2/rlc_v2/tests/test20.txt.gz | Bin 0 -> 3931 bytes openair2/LAYER2/rlc_v2/tests/test21.h | 18 + openair2/LAYER2/rlc_v2/tests/test21.txt.gz | Bin 0 -> 970 bytes openair2/LAYER2/rlc_v2/tests/test22.h | 25 + openair2/LAYER2/rlc_v2/tests/test22.txt.gz | Bin 0 -> 392 bytes openair2/LAYER2/rlc_v2/tests/test23.h | 9 + openair2/LAYER2/rlc_v2/tests/test23.txt.gz | Bin 0 -> 266 bytes openair2/LAYER2/rlc_v2/tests/test24.h | 9 + openair2/LAYER2/rlc_v2/tests/test24.txt.gz | Bin 0 -> 324 bytes openair2/LAYER2/rlc_v2/tests/test25.h | 8 + openair2/LAYER2/rlc_v2/tests/test25.txt.gz | Bin 0 -> 161 bytes openair2/LAYER2/rlc_v2/tests/test26.h | 25 + openair2/LAYER2/rlc_v2/tests/test26.txt.gz | Bin 0 -> 374 bytes openair2/LAYER2/rlc_v2/tests/test27.h | 17 + openair2/LAYER2/rlc_v2/tests/test27.txt.gz | Bin 0 -> 243 bytes openair2/LAYER2/rlc_v2/tests/test28.h | 18 + openair2/LAYER2/rlc_v2/tests/test28.txt.gz | Bin 0 -> 282 bytes openair2/LAYER2/rlc_v2/tests/test29.h | 21 + openair2/LAYER2/rlc_v2/tests/test29.txt.gz | Bin 0 -> 349 bytes openair2/LAYER2/rlc_v2/tests/test3.h | 11 + openair2/LAYER2/rlc_v2/tests/test3.txt.gz | Bin 0 -> 757 bytes openair2/LAYER2/rlc_v2/tests/test30.h | 16 + openair2/LAYER2/rlc_v2/tests/test30.txt.gz | Bin 0 -> 395 bytes openair2/LAYER2/rlc_v2/tests/test31.h | 10 + openair2/LAYER2/rlc_v2/tests/test31.txt.gz | Bin 0 -> 267 bytes openair2/LAYER2/rlc_v2/tests/test32.h | 10 + openair2/LAYER2/rlc_v2/tests/test32.txt.gz | Bin 0 -> 268 bytes openair2/LAYER2/rlc_v2/tests/test33.h | 18 + openair2/LAYER2/rlc_v2/tests/test33.txt.gz | Bin 0 -> 421 bytes openair2/LAYER2/rlc_v2/tests/test34.h | 15 + openair2/LAYER2/rlc_v2/tests/test34.txt.gz | Bin 0 -> 434 bytes openair2/LAYER2/rlc_v2/tests/test35.h | 9 + openair2/LAYER2/rlc_v2/tests/test35.txt.gz | Bin 0 -> 170 bytes openair2/LAYER2/rlc_v2/tests/test36.h | 14 + openair2/LAYER2/rlc_v2/tests/test36.txt.gz | Bin 0 -> 379 bytes openair2/LAYER2/rlc_v2/tests/test37.h | 37 + openair2/LAYER2/rlc_v2/tests/test37.txt.gz | Bin 0 -> 92 bytes openair2/LAYER2/rlc_v2/tests/test38.h | 22 + openair2/LAYER2/rlc_v2/tests/test38.txt.gz | Bin 0 -> 1048 bytes openair2/LAYER2/rlc_v2/tests/test39.h | 9 + openair2/LAYER2/rlc_v2/tests/test39.txt.gz | Bin 0 -> 758 bytes openair2/LAYER2/rlc_v2/tests/test4.h | 13 + openair2/LAYER2/rlc_v2/tests/test4.txt.gz | Bin 0 -> 166 bytes openair2/LAYER2/rlc_v2/tests/test40.h | 9 + openair2/LAYER2/rlc_v2/tests/test40.txt.gz | Bin 0 -> 148 bytes openair2/LAYER2/rlc_v2/tests/test41.h | 45 + openair2/LAYER2/rlc_v2/tests/test41.txt.gz | Bin 0 -> 875 bytes openair2/LAYER2/rlc_v2/tests/test42.h | 39 + openair2/LAYER2/rlc_v2/tests/test42.txt.gz | Bin 0 -> 496 bytes openair2/LAYER2/rlc_v2/tests/test43.h | 39 + openair2/LAYER2/rlc_v2/tests/test43.txt.gz | Bin 0 -> 416 bytes openair2/LAYER2/rlc_v2/tests/test44.h | 20 + openair2/LAYER2/rlc_v2/tests/test44.txt.gz | Bin 0 -> 278 bytes openair2/LAYER2/rlc_v2/tests/test45.h | 30 + openair2/LAYER2/rlc_v2/tests/test45.txt.gz | Bin 0 -> 358 bytes openair2/LAYER2/rlc_v2/tests/test5.h | 13 + openair2/LAYER2/rlc_v2/tests/test5.txt.gz | Bin 0 -> 167 bytes openair2/LAYER2/rlc_v2/tests/test6.h | 27 + openair2/LAYER2/rlc_v2/tests/test6.txt.gz | Bin 0 -> 777 bytes openair2/LAYER2/rlc_v2/tests/test7.h | 26 + openair2/LAYER2/rlc_v2/tests/test7.txt.gz | Bin 0 -> 796 bytes openair2/LAYER2/rlc_v2/tests/test8.h | 19 + openair2/LAYER2/rlc_v2/tests/test8.txt.gz | Bin 0 -> 461 bytes openair2/LAYER2/rlc_v2/tests/test9.h | 34 + openair2/LAYER2/rlc_v2/tests/test9.txt.gz | Bin 0 -> 327 bytes openair2/RRC/LTE/rrc_eNB.c | 228 ++- 119 files changed, 6579 insertions(+), 23 deletions(-) create mode 100755 common/utils/T/tracer/hacks/pilot_timeplot.sh create mode 100644 openair2/LAYER2/rlc_v2/TODO create mode 100644 openair2/LAYER2/rlc_v2/asn1_utils.c create mode 100644 openair2/LAYER2/rlc_v2/asn1_utils.h create mode 100644 openair2/LAYER2/rlc_v2/rlc_entity.c create mode 100644 openair2/LAYER2/rlc_v2/rlc_entity.h create mode 100644 openair2/LAYER2/rlc_v2/rlc_entity_am.c create mode 100644 openair2/LAYER2/rlc_v2/rlc_entity_am.h create mode 100644 openair2/LAYER2/rlc_v2/rlc_entity_um.c create mode 100644 openair2/LAYER2/rlc_v2/rlc_entity_um.h create mode 100644 openair2/LAYER2/rlc_v2/rlc_oai_api.c create mode 100644 openair2/LAYER2/rlc_v2/rlc_pdu.c create mode 100644 openair2/LAYER2/rlc_v2/rlc_pdu.h create mode 100644 openair2/LAYER2/rlc_v2/rlc_sdu.c create mode 100644 openair2/LAYER2/rlc_v2/rlc_sdu.h create mode 100644 openair2/LAYER2/rlc_v2/rlc_ue_manager.c create mode 100644 openair2/LAYER2/rlc_v2/rlc_ue_manager.h create mode 100644 openair2/LAYER2/rlc_v2/tests/LOG/log.h create mode 100644 openair2/LAYER2/rlc_v2/tests/Makefile create mode 100644 openair2/LAYER2/rlc_v2/tests/README create mode 100644 openair2/LAYER2/rlc_v2/tests/make_pdu.c create mode 100755 openair2/LAYER2/rlc_v2/tests/run_tests.sh create mode 100644 openair2/LAYER2/rlc_v2/tests/test.c create mode 100644 openair2/LAYER2/rlc_v2/tests/test1.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test1.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test10.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test10.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test11.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test11.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test12.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test12.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test13.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test13.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test14.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test14.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test15.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test15.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test16.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test16.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test17.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test17.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test18.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test18.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test19.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test19.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test2.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test2.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test20.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test20.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test21.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test21.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test22.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test22.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test23.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test23.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test24.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test24.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test25.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test25.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test26.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test26.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test27.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test27.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test28.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test28.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test29.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test29.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test3.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test3.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test30.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test30.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test31.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test31.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test32.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test32.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test33.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test33.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test34.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test34.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test35.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test35.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test36.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test36.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test37.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test37.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test38.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test38.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test39.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test39.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test4.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test4.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test40.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test40.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test41.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test41.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test42.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test42.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test43.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test43.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test44.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test44.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test45.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test45.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test5.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test5.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test6.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test6.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test7.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test7.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test8.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test8.txt.gz create mode 100644 openair2/LAYER2/rlc_v2/tests/test9.h create mode 100644 openair2/LAYER2/rlc_v2/tests/test9.txt.gz diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index f155d3061db..68849c01916 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -727,7 +727,6 @@ Message("CPU_Affinity flag is ${CPU_AFFINITY}") ############################################################## add_boolean_option(NO_RRM True "DO WE HAVE A RADIO RESSOURCE MANAGER: NO") -add_boolean_option(RRC_DEFAULT_RAB_IS_AM False "set the RLC mode to AM for the default bearer") add_boolean_option(OAI_NW_DRIVER_TYPE_ETHERNET False "????") add_boolean_option(DEADLINE_SCHEDULER True "Use the Linux scheduler SCHED_DEADLINE: kernel >= 3.14") @@ -828,7 +827,7 @@ add_boolean_option(TRACE_RLC_UM_TX_STATUS False "TRACE for RLC UM, TO BE CHANGE ########################## # RRC LAYER OPTIONS ########################## -add_boolean_option(RRC_DEFAULT_RAB_IS_AM False "Otherwise it is UM, configure params are actually set in rrc_eNB.c:rrc_eNB_generate_defaultRRCConnectionReconfiguration(...)") +add_boolean_option(RRC_DEFAULT_RAB_IS_AM True "set the RLC mode to AM for the default bearer, otherwise it is UM.") ########################## @@ -1640,7 +1639,7 @@ set(NR_RRC_DIR ${OPENAIR2_DIR}/RRC/NR) set(NR_UE_RRC_DIR ${OPENAIR2_DIR}/RRC/NR_UE) set(PDCP_DIR ${OPENAIR2_DIR}/LAYER2/PDCP_v10.1.0) -set(LTE_RLC_SRC +set(RLC_ENB_V1 ${RLC_AM_DIR}/rlc_am.c ${RLC_AM_DIR}/rlc_am_init.c ${RLC_AM_DIR}/rlc_am_timer_poll_retransmit.c @@ -1670,6 +1669,17 @@ set(LTE_RLC_SRC ${RLC_DIR}/rlc_mpls.c ) +set(RLC_ENB_V2 + ${OPENAIR2_DIR}/LAYER2/rlc_v2/rlc_oai_api.c + ${OPENAIR2_DIR}/LAYER2/rlc_v2/asn1_utils.c + ${OPENAIR2_DIR}/LAYER2/rlc_v2/rlc_ue_manager.c + ${OPENAIR2_DIR}/LAYER2/rlc_v2/rlc_entity.c + ${OPENAIR2_DIR}/LAYER2/rlc_v2/rlc_entity_am.c + ${OPENAIR2_DIR}/LAYER2/rlc_v2/rlc_entity_um.c + ${OPENAIR2_DIR}/LAYER2/rlc_v2/rlc_pdu.c + ${OPENAIR2_DIR}/LAYER2/rlc_v2/rlc_sdu.c + ) + set(NR_RLC_SRC ${OPENAIR2_DIR}/LAYER2/nr_rlc/asn1_utils.c ${OPENAIR2_DIR}/LAYER2/nr_rlc/nr_rlc_entity.c @@ -1691,6 +1701,7 @@ set(L2_SRC ${PDCP_DIR}/pdcp_util.c ${PDCP_DIR}/pdcp_security.c ${PDCP_DIR}/pdcp_netlink.c + ${RLC_ENB_V2} # ${RRC_DIR}/rrc_UE.c ${RRC_DIR}/rrc_eNB.c ${RRC_DIR}/rrc_eNB_endc.c @@ -1704,7 +1715,7 @@ set(L2_SRC ) set(L2_LTE_SRC - ${LTE_RLC_SRC} + ${RLC_ENB_V1} ) set(L2_NR_SRC @@ -1741,7 +1752,7 @@ set(LTE_NR_L2_SRC_UE ${PDCP_DIR}/pdcp_util.c ${PDCP_DIR}/pdcp_security.c ${PDCP_DIR}/pdcp_netlink.c - ${LTE_RLC_SRC} + ${RLC_ENB_V1} ) set(NR_L2_SRC_UE diff --git a/common/utils/T/tracer/hacks/pilot_timeplot.sh b/common/utils/T/tracer/hacks/pilot_timeplot.sh new file mode 100755 index 00000000000..0d9c4694a62 --- /dev/null +++ b/common/utils/T/tracer/hacks/pilot_timeplot.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +# use UP and DOWN arrow keys to scroll the view displayed by timeplot + +while read -n 1 key +do + case "$key" in + 'B' ) + kill -SIGUSR1 `ps aux|grep timeplot|grep -v grep|grep -v sh|tr -s ' ' :|cut -f 2 -d :` + ;; + 'A' ) + kill -SIGUSR2 `ps aux|grep timeplot|grep -v grep|grep -v sh|tr -s ' ' :|cut -f 2 -d :` + ;; + esac +done diff --git a/common/utils/T/tracer/hacks/time_meas.c b/common/utils/T/tracer/hacks/time_meas.c index 6bd29503011..408189cd80c 100644 --- a/common/utils/T/tracer/hacks/time_meas.c +++ b/common/utils/T/tracer/hacks/time_meas.c @@ -13,7 +13,8 @@ void usage(void) "options:\n" " -d <database file> this option is mandatory\n" " -ip <host> connect to given IP address (default %s)\n" -" -p <port> connect to given port (default %d)\n", +" -p <port> connect to given port (default %d)\n" +" -e <event> event to trace (default VCD_FUNCTION_ENB_DLSCH_ULSCH_SCHEDULER)\n", DEFAULT_REMOTE_IP, DEFAULT_REMOTE_PORT ); @@ -47,6 +48,7 @@ int main(int n, char **v) int ev_fun; int start_valid = 0; struct timespec start_time, stop_time, delta_time; + char *name = "VCD_FUNCTION_ENB_DLSCH_ULSCH_SCHEDULER"; for (i = 1; i < n; i++) { if (!strcmp(v[i], "-h") || !strcmp(v[i], "--help")) usage(); @@ -55,6 +57,7 @@ int main(int n, char **v) if (!strcmp(v[i], "-ip")) { if (i > n-2) usage(); ip = v[++i]; continue; } if (!strcmp(v[i], "-p")) { if (i > n-2) usage(); port = atoi(v[++i]); continue; } + if (!strcmp(v[i], "-e")) { if (i > n-2) usage(); name = v[++i]; continue; } usage(); } @@ -71,10 +74,9 @@ int main(int n, char **v) is_on = calloc(number_of_events, sizeof(int)); if (is_on == NULL) abort(); - on_off(database, "VCD_FUNCTION_ENB_DLSCH_ULSCH_SCHEDULER", is_on, 1); + on_off(database, name, is_on, 1); - ev_fun = event_id_from_name(database, - "VCD_FUNCTION_ENB_DLSCH_ULSCH_SCHEDULER"); + ev_fun = event_id_from_name(database, name); socket = connect_to(ip, port); diff --git a/common/utils/T/tracer/hacks/timeplot.c b/common/utils/T/tracer/hacks/timeplot.c index 79905d16f99..a1ddb2a1c92 100644 --- a/common/utils/T/tracer/hacks/timeplot.c +++ b/common/utils/T/tracer/hacks/timeplot.c @@ -28,6 +28,7 @@ int bins[50]; #define N 1000 int data[N]; +long start = 100; void plot(void) { @@ -45,7 +46,8 @@ void plot(void) if (data[i] < vmin) vmin = data[i]; if (data[i] > vmax) vmax = data[i]; vavg += data[i]; - int ms2 = data[i]/binsize_ns; + int ms2 = (data[i] - start * 1000)/binsize_ns; + if (ms2 < 0) ms2 = 0; if (ms2 > 49) ms2 = 49; bins[ms2]++; if (bins[ms2] > max) max = bins[ms2]; @@ -55,7 +57,7 @@ void plot(void) GOTO(1,1); for (i = 0; i < 50; i++) { - double binend = (i+1) * binsize_ns / 1000.; + double binend = (i+1) * binsize_ns / 1000. + start; int k; int width = bins[i] * 70 / max; /* force at least width of 1 if some point is there */ @@ -68,11 +70,23 @@ void plot(void) printf("min %d ns max %d ns avg %ld ns\n", vmin, vmax, vavg); } +void up(int x) +{ + start += 5; +} + +void down(int x) +{ + start -= 5; +} + int main(void) { int i; int pos = 0; signal(SIGINT, sig); + signal(SIGUSR1, up); + signal(SIGUSR2, down); RESET(); HIDE_CURSOR(); while (!feof(stdin)) { diff --git a/openair2/COMMON/rrc_messages_def.h b/openair2/COMMON/rrc_messages_def.h index 1d0c2dfdb85..cde24978808 100644 --- a/openair2/COMMON/rrc_messages_def.h +++ b/openair2/COMMON/rrc_messages_def.h @@ -76,3 +76,6 @@ MESSAGE_DEF(NAS_DOWNLINK_DATA_IND, MESSAGE_PRIORITY_MED, NasDlDataInd // eNB: realtime -> RRC messages MESSAGE_DEF(RRC_SUBFRAME_PROCESS, MESSAGE_PRIORITY_MED, RrcSubframeProcess, rrc_subframe_process) + +// eNB: RLC -> RRC messages +MESSAGE_DEF(RLC_SDU_INDICATION, MESSAGE_PRIORITY_MED, RlcSduIndication, rlc_sdu_indication) diff --git a/openair2/COMMON/rrc_messages_types.h b/openair2/COMMON/rrc_messages_types.h index 68e1753448b..7582de65ba4 100644 --- a/openair2/COMMON/rrc_messages_types.h +++ b/openair2/COMMON/rrc_messages_types.h @@ -87,6 +87,8 @@ #define RRC_SUBFRAME_PROCESS(mSGpTR) (mSGpTR)->ittiMsg.rrc_subframe_process +#define RLC_SDU_INDICATION(mSGpTR) (mSGpTR)->ittiMsg.rlc_sdu_indication + //-------------------------------------------------------------------------------------------// typedef struct RrcStateInd_s { Rrc_State_t state; @@ -429,4 +431,12 @@ typedef struct rrc_subframe_process_s { int CC_id; } RrcSubframeProcess; +// eNB: RLC -> RRC messages +typedef struct rlc_sdu_indication_s { + int rnti; + int is_successful; + int srb_id; + int message_id; +} RlcSduIndication; + #endif /* RRC_MESSAGES_TYPES_H_ */ diff --git a/openair2/LAYER2/rlc_v2/TODO b/openair2/LAYER2/rlc_v2/TODO new file mode 100644 index 00000000000..0778d4320b8 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/TODO @@ -0,0 +1,18 @@ +RLC AM +====== + +- 36.322 5.4 Re-establishment procedure + when possible, reassemble RLC SDUs from any byte segments of AMD PDUs + with SN < VR(MR) in the receiving side, remove RLC headers when doing + so and deliver all reassembled RLC SDUs to upper layer in ascending order + of the RLC SN, if not delivered before; + +- 36.322 5.2.3 Status reporting + delay triggering the STATUS report until x < VR(MS) or x >= VR(MR) + +- 36.322 5.1.3.2.3 Actions when a RLC data PDU is placed in the reception + buffer + [...] and in-sequence byte segments of the AMD PDU with SN = VR(R) [...] + +- use SOstart/SOend in NACK reporting, do not NACK full PDU if + parts of it have been received diff --git a/openair2/LAYER2/rlc_v2/asn1_utils.c b/openair2/LAYER2/rlc_v2/asn1_utils.c new file mode 100644 index 00000000000..46f7d90da57 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/asn1_utils.c @@ -0,0 +1,129 @@ +/* + * 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 "rlc.h" + +int decode_t_reordering(int v) +{ + static int tab[32] = { + 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, + 90, 95, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200, 1600 + }; + + if (v < 0 || v > 31) { + LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + return tab[v]; +} + +int decode_t_status_prohibit(int v) +{ + static int tab[62] = { + 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, + 95, 100, 105, 110, 115, 120, 125, 130, 135, 140, 145, 150, 155, 160, 165, + 170, 175, 180, 185, 190, 195, 200, 205, 210, 215, 220, 225, 230, 235, 240, + 245, 250, 300, 350, 400, 450, 500, 800, 1000, 1200, 1600, 2000, 2400 + }; + + if (v < 0 || v > 61) { + LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + return tab[v]; +} + +int decode_t_poll_retransmit(int v) +{ + static int tab[59] = { + 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, + 100, 105, 110, 115, 120, 125, 130, 135, 140, 145, 150, 155, 160, 165, 170, + 175, 180, 185, 190, 195, 200, 205, 210, 215, 220, 225, 230, 235, 240, 245, + 250, 300, 350, 400, 450, 500, 800, 1000, 2000, 4000 + }; + + if (v < 0 || v > 58) { + LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + return tab[v]; +} + +int decode_poll_pdu(int v) +{ + static int tab[8] = { + 4, 8, 16, 32, 64, 128, 256, -1 /* -1 means infinity */ + }; + + if (v < 0 || v > 7) { + LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + return tab[v]; +} + +int decode_poll_byte(int v) +{ + static int tab[15] = { + 25, 50, 75, 100, 125, 250, 375, 500, 750, 1000, 1250, 1500, 2000, 3000, + -1 /* -1 means infinity */ + }; + + if (v < 0 || v > 14) { + LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + if (tab[v] == -1) return -1; + return tab[v] * 1024; +} + +int decode_max_retx_threshold(int v) +{ + static int tab[8] = { + 1, 2, 3, 4, 6, 8, 16, 32 + }; + + if (v < 0 || v > 7) { + LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + return tab[v]; +} + +int decode_sn_field_length(int v) +{ + static int tab[2] = { + 5, 10 + }; + + if (v < 0 || v > 1) { + LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + return tab[v]; +} diff --git a/openair2/LAYER2/rlc_v2/asn1_utils.h b/openair2/LAYER2/rlc_v2/asn1_utils.h new file mode 100644 index 00000000000..61394c9c699 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/asn1_utils.h @@ -0,0 +1,33 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef _ASN1_UTILS_H_ +#define _ASN1_UTILS_H_ + +int decode_t_reordering(int v); +int decode_t_status_prohibit(int v); +int decode_t_poll_retransmit(int v); +int decode_poll_pdu(int v); +int decode_poll_byte(int v); +int decode_max_retx_threshold(int v); +int decode_sn_field_length(int v); + +#endif /* _ASN1_UTILS_H_ */ diff --git a/openair2/LAYER2/rlc_v2/rlc_entity.c b/openair2/LAYER2/rlc_v2/rlc_entity.c new file mode 100644 index 00000000000..d774e2b7e17 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/rlc_entity.c @@ -0,0 +1,144 @@ +/* + * 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 "rlc_entity.h" + +#include <stdlib.h> + +#include "rlc_entity_am.h" +#include "rlc_entity_um.h" + +#include "LOG/log.h" + +rlc_entity_t *new_rlc_entity_am( + int rx_maxsize, + int tx_maxsize, + void (*deliver_sdu)(void *deliver_sdu_data, struct rlc_entity_t *entity, + char *buf, int size), + void *deliver_sdu_data, + void (*sdu_successful_delivery)(void *sdu_successful_delivery_data, + struct rlc_entity_t *entity, + int sdu_id), + void *sdu_successful_delivery_data, + void (*max_retx_reached)(void *max_retx_reached_data, + struct rlc_entity_t *entity), + void *max_retx_reached_data, + int t_reordering, + int t_status_prohibit, + int t_poll_retransmit, + int poll_pdu, + int poll_byte, + int max_retx_threshold) +{ + rlc_entity_am_t *ret; + + ret = calloc(1, sizeof(rlc_entity_am_t)); + if (ret == NULL) { + LOG_E(RLC, "%s:%d:%s: out of memory\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + ret->common.recv_pdu = rlc_entity_am_recv_pdu; + ret->common.buffer_status = rlc_entity_am_buffer_status; + ret->common.generate_pdu = rlc_entity_am_generate_pdu; + + ret->common.recv_sdu = rlc_entity_am_recv_sdu; + + ret->common.set_time = rlc_entity_am_set_time; + + ret->common.discard_sdu = rlc_entity_am_discard_sdu; + + ret->common.reestablishment = rlc_entity_am_reestablishment; + + ret->common.delete = rlc_entity_am_delete; + + ret->common.deliver_sdu = deliver_sdu; + ret->common.deliver_sdu_data = deliver_sdu_data; + + ret->common.sdu_successful_delivery = sdu_successful_delivery; + ret->common.sdu_successful_delivery_data = sdu_successful_delivery_data; + + ret->common.max_retx_reached = max_retx_reached; + ret->common.max_retx_reached_data = max_retx_reached_data; + + ret->rx_maxsize = rx_maxsize; + ret->tx_maxsize = tx_maxsize; + ret->t_reordering = t_reordering; + ret->t_status_prohibit = t_status_prohibit; + ret->t_poll_retransmit = t_poll_retransmit; + ret->poll_pdu = poll_pdu; + ret->poll_byte = poll_byte; + ret->max_retx_threshold = max_retx_threshold; + + return (rlc_entity_t *)ret; +} + +rlc_entity_t *new_rlc_entity_um( + int rx_maxsize, + int tx_maxsize, + void (*deliver_sdu)(void *deliver_sdu_data, struct rlc_entity_t *entity, + char *buf, int size), + void *deliver_sdu_data, + int t_reordering, + int sn_field_length) +{ + rlc_entity_um_t *ret; + + ret = calloc(1, sizeof(rlc_entity_um_t)); + if (ret == NULL) { + LOG_E(RLC, "%s:%d:%s: out of memory\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + ret->common.recv_pdu = rlc_entity_um_recv_pdu; + ret->common.buffer_status = rlc_entity_um_buffer_status; + ret->common.generate_pdu = rlc_entity_um_generate_pdu; + + ret->common.recv_sdu = rlc_entity_um_recv_sdu; + + ret->common.set_time = rlc_entity_um_set_time; + + ret->common.discard_sdu = rlc_entity_um_discard_sdu; + + ret->common.reestablishment = rlc_entity_um_reestablishment; + + ret->common.delete = rlc_entity_um_delete; + + ret->common.deliver_sdu = deliver_sdu; + ret->common.deliver_sdu_data = deliver_sdu_data; + + ret->sn_field_length = sn_field_length; + ret->rx_maxsize = rx_maxsize; + ret->tx_maxsize = tx_maxsize; + ret->t_reordering = t_reordering; + + if (sn_field_length == 5) + ret->sn_modulus = 32; + else if (sn_field_length == 10) + ret->sn_modulus = 1024; + else { + LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + ret->window_size = ret->sn_modulus / 2; + + return (rlc_entity_t *)ret; +} diff --git a/openair2/LAYER2/rlc_v2/rlc_entity.h b/openair2/LAYER2/rlc_v2/rlc_entity.h new file mode 100644 index 00000000000..c9b35204f03 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/rlc_entity.h @@ -0,0 +1,97 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef _RLC_ENTITY_H_ +#define _RLC_ENTITY_H_ + +#include <stdint.h> + +#define SDU_MAX 16000 /* maximum PDCP SDU size is 8188, let's take more */ + +typedef struct { + int status_size; + int tx_size; + int retx_size; +} rlc_entity_buffer_status_t; + +typedef struct rlc_entity_t { + /* functions provided by the RLC module */ + void (*recv_pdu)(struct rlc_entity_t *entity, char *buffer, int size); + rlc_entity_buffer_status_t (*buffer_status)( + struct rlc_entity_t *entity, int maxsize); + int (*generate_pdu)(struct rlc_entity_t *entity, char *buffer, int size); + + void (*recv_sdu)(struct rlc_entity_t *entity, char *buffer, int size, + int sdu_id); + + void (*set_time)(struct rlc_entity_t *entity, uint64_t now); + + void (*discard_sdu)(struct rlc_entity_t *entity, int sdu_id); + + void (*reestablishment)(struct rlc_entity_t *entity); + + void (*delete)(struct rlc_entity_t *entity); + + /* callbacks provided to the RLC module */ + void (*deliver_sdu)(void *deliver_sdu_data, struct rlc_entity_t *entity, + char *buf, int size); + void *deliver_sdu_data; + + void (*sdu_successful_delivery)(void *sdu_successful_delivery_data, + struct rlc_entity_t *entity, + int sdu_id); + void *sdu_successful_delivery_data; + + void (*max_retx_reached)(void *max_retx_reached_data, + struct rlc_entity_t *entity); + void *max_retx_reached_data; +} rlc_entity_t; + +rlc_entity_t *new_rlc_entity_am( + int rx_maxsize, + int tx_maxsize, + void (*deliver_sdu)(void *deliver_sdu_data, struct rlc_entity_t *entity, + char *buf, int size), + void *deliver_sdu_data, + void (*sdu_successful_delivery)(void *sdu_successful_delivery_data, + struct rlc_entity_t *entity, + int sdu_id), + void *sdu_successful_delivery_data, + void (*max_retx_reached)(void *max_retx_reached_data, + struct rlc_entity_t *entity), + void *max_retx_reached_data, + int t_reordering, + int t_status_prohibit, + int t_poll_retransmit, + int poll_pdu, + int poll_byte, + int max_retx_threshold); + +rlc_entity_t *new_rlc_entity_um( + int rx_maxsize, + int tx_maxsize, + void (*deliver_sdu)(void *deliver_sdu_data, struct rlc_entity_t *entity, + char *buf, int size), + void *deliver_sdu_data, + int t_reordering, + int sn_field_length); + +#endif /* _RLC_ENTITY_H_ */ diff --git a/openair2/LAYER2/rlc_v2/rlc_entity_am.c b/openair2/LAYER2/rlc_v2/rlc_entity_am.c new file mode 100644 index 00000000000..5b3df3ec75e --- /dev/null +++ b/openair2/LAYER2/rlc_v2/rlc_entity_am.c @@ -0,0 +1,1694 @@ +/* + * 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 "rlc_entity_am.h" +#include "rlc_pdu.h" + +#include <stdlib.h> +#include <string.h> + +#include "LOG/log.h" + +/*************************************************************************/ +/* PDU RX functions */ +/*************************************************************************/ + +static int modulus_rx(rlc_entity_am_t *entity, int a) +{ + /* as per 36.322 7.1, modulus base is vr(r) and modulus is 1024 for rx */ + int r = a - entity->vr_r; + if (r < 0) r += 1024; + return r; +} + +/* used in both RX and TX processing */ +static int modulus_tx(rlc_entity_am_t *entity, int a) +{ + /* as per 36.322 7.1, modulus base is vt(a) and modulus is 1024 for tx */ + int r = a - entity->vt_a; + if (r < 0) r += 1024; + return r; +} + +static int sn_in_recv_window(void *_entity, int sn) +{ + rlc_entity_am_t *entity = _entity; + int mod_sn = modulus_rx(entity, sn); + /* we simplify vr(r)<=sn<vr(mr). base is vr(r) and vr(mr) = vr(r) + 512 */ + return mod_sn < 512; +} + +static int sn_compare_rx(void *_entity, int a, int b) +{ + rlc_entity_am_t *entity = _entity; + return modulus_rx(entity, a) - modulus_rx(entity, b); +} + +/* used in both RX and TX processing */ +static int sn_compare_tx(void *_entity, int a, int b) +{ + rlc_entity_am_t *entity = _entity; + return modulus_tx(entity, a) - modulus_tx(entity, b); +} + +static int segment_already_received(rlc_entity_am_t *entity, + int sn, int so, int data_size) +{ + /* TODO: optimize */ + rlc_rx_pdu_segment_t *l = entity->rx_list; + + while (l != NULL) { + if (l->sn == sn && l->so <= so && + l->so + l->size - l->data_offset >= so + data_size) + return 1; + l = l->next; + } + + return 0; +} + +static int rlc_am_segment_full(rlc_entity_am_t *entity, int sn) +{ + rlc_rx_pdu_segment_t *l = entity->rx_list; + int last_byte; + int new_last_byte; + + last_byte = -1; + while (l != NULL) { + if (l->sn == sn) + break; + l = l->next; + } + while (l != NULL && l->sn == sn) { + if (l->so > last_byte + 1) + return 0; + if (l->is_last) + return 1; + new_last_byte = l->so + l->size - l->data_offset - 1; + if (new_last_byte > last_byte) + last_byte = new_last_byte; + l = l->next; + } + return 0; +} + +/* return 1 if the new segment has some data to consume, 0 if not */ +static int rlc_am_reassemble_next_segment(rlc_am_reassemble_t *r) +{ + int rf; + int sn; + + r->sdu_offset = r->start->data_offset; + + rlc_pdu_decoder_init(&r->dec, r->start->data, r->start->size); + + rlc_pdu_decoder_get_bits(&r->dec, 1); /* dc */ + rf = rlc_pdu_decoder_get_bits(&r->dec, 1); + rlc_pdu_decoder_get_bits(&r->dec, 1); /* p */ + r->fi = rlc_pdu_decoder_get_bits(&r->dec, 2); + r->e = rlc_pdu_decoder_get_bits(&r->dec, 1); + sn = rlc_pdu_decoder_get_bits(&r->dec, 10); + if (rf) { + rlc_pdu_decoder_get_bits(&r->dec, 1); /* lsf */ + r->so = rlc_pdu_decoder_get_bits(&r->dec, 15); + } else { + r->so = 0; + } + + if (r->e) { + r->e = rlc_pdu_decoder_get_bits(&r->dec, 1); + r->sdu_len = rlc_pdu_decoder_get_bits(&r->dec, 11); + } else + r->sdu_len = r->start->size - r->sdu_offset; + + /* new sn: read starts from PDU byte 0 */ + if (sn != r->sn) { + r->pdu_byte = 0; + r->sn = sn; + } + + r->data_pos = r->start->data_offset + r->pdu_byte - r->so; + + /* TODO: remove this check, it is useless, data has been validated before */ + if (r->pdu_byte < r->so) { + LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + /* if pdu_byte is not in [so .. so+len-1] then all bytes from this segment + * have already been consumed + */ + if (r->pdu_byte >= r->so + r->start->size - r->start->data_offset) + return 0; + + /* go to correct SDU */ + while (r->pdu_byte >= r->so + (r->sdu_offset - r->start->data_offset) + r->sdu_len) { + r->sdu_offset += r->sdu_len; + if (r->e) { + r->e = rlc_pdu_decoder_get_bits(&r->dec, 1); + r->sdu_len = rlc_pdu_decoder_get_bits(&r->dec, 11); + } else { + r->sdu_len = r->start->size - r->sdu_offset; + } + } + + return 1; +} + +static void rlc_am_reassemble(rlc_entity_am_t *entity) +{ + rlc_am_reassemble_t *r = &entity->reassemble; + + while (r->start != NULL) { + if (r->sdu_pos >= SDU_MAX) { + /* TODO: proper error handling (discard PDUs with current sn from + * reassembly queue? something else?) + */ + LOG_E(RLC, "%s:%d:%s: bad RLC PDU\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + r->sdu[r->sdu_pos] = r->start->data[r->data_pos]; + r->sdu_pos++; + r->data_pos++; + r->pdu_byte++; + if (r->data_pos == r->sdu_offset + r->sdu_len) { + /* all bytes of SDU are consumed, check if SDU is fully there. + * It is if the data pointer is not at the end of the PDU segment + * or if 'fi' & 1 == 0 + */ + if (r->data_pos != r->start->size || + (r->fi & 1) == 0) { + /* SDU is full - deliver to higher layer */ + entity->common.deliver_sdu(entity->common.deliver_sdu_data, + (rlc_entity_t *)entity, + r->sdu, r->sdu_pos); + r->sdu_pos = 0; + } + if (r->data_pos != r->start->size) { + /* not at the end, process next SDU */ + r->sdu_offset += r->sdu_len; + if (r->e) { + r->e = rlc_pdu_decoder_get_bits(&r->dec, 1); + r->sdu_len = rlc_pdu_decoder_get_bits(&r->dec, 11); + } else + r->sdu_len = r->start->size - r->sdu_offset; + } else { + /* all bytes are consumend, go to next segment not already fully + * processed, if any + */ + do { + rlc_rx_pdu_segment_t *e = r->start; + entity->rx_size -= e->size; + r->start = r->start->next; + rlc_rx_free_pdu_segment(e); + } while (r->start != NULL && !rlc_am_reassemble_next_segment(r)); + } + } + } +} + +static void rlc_am_reception_actions(rlc_entity_am_t *entity, + rlc_rx_pdu_segment_t *pdu_segment) +{ + int x = pdu_segment->sn; + int vr_ms; + int vr_r; + + if (modulus_rx(entity, x) >= modulus_rx(entity, entity->vr_h)) + entity->vr_h = (x + 1) % 1024; + + vr_ms = entity->vr_ms; + while (rlc_am_segment_full(entity, vr_ms)) + vr_ms = (vr_ms + 1) % 1024; + entity->vr_ms = vr_ms; + + if (x == entity->vr_r) { + vr_r = entity->vr_r; + while (rlc_am_segment_full(entity, vr_r)) { + /* move segments with sn=vr(r) from rx list to end of reassembly list */ + while (entity->rx_list != NULL && entity->rx_list->sn == vr_r) { + rlc_rx_pdu_segment_t *e = entity->rx_list; + entity->rx_list = e->next; + e->next = NULL; + if (entity->reassemble.start == NULL) { + entity->reassemble.start = e; + /* the list was empty, we need to init decoder */ + entity->reassemble.sn = -1; + if (!rlc_am_reassemble_next_segment(&entity->reassemble)) { + /* TODO: proper error recovery (or remove the test, it should not happen) */ + LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + } else { + entity->reassemble.end->next = e; + } + entity->reassemble.end = e; + } + + /* update vr_r */ + vr_r = (vr_r + 1) % 1024; + } + entity->vr_r = vr_r; + } + + rlc_am_reassemble(entity); + + if (entity->t_reordering_start) { + int vr_x = entity->vr_x; + if (vr_x < entity->vr_r) vr_x += 1024; + if (vr_x == entity->vr_r || vr_x > entity->vr_r + 512) + entity->t_reordering_start = 0; + } + + if (entity->t_reordering_start == 0) { + if (sn_compare_rx(entity, entity->vr_h, entity->vr_r) > 0) { + entity->t_reordering_start = entity->t_current; + entity->vr_x = entity->vr_h; + } + } +} + +static void process_received_ack(rlc_entity_am_t *entity, int sn) +{ + rlc_tx_pdu_segment_t head; + rlc_tx_pdu_segment_t *cur; + rlc_tx_pdu_segment_t *prev; + + /* put all PDUs from wait and retransmit lists with SN < 'sn' to ack_list */ + + /* process wait list */ + head.next = entity->wait_list; + prev = &head; + cur = entity->wait_list; + while (cur != NULL) { + if (sn_compare_tx(entity, cur->sn, sn) < 0) { + /* remove from wait list */ + prev->next = cur->next; + /* put the PDU in the ack list */ + entity->ack_list = rlc_tx_pdu_list_add(sn_compare_tx, entity, + entity->ack_list, cur); + cur = prev->next; + } else { + prev = cur; + cur = cur->next; + } + } + entity->wait_list = head.next; + + /* process retransmit list */ + head.next = entity->retransmit_list; + prev = &head; + cur = entity->retransmit_list; + while (cur != NULL) { + if (sn_compare_tx(entity, cur->sn, sn) < 0) { + /* dec. retx_count in case we put this segment back in retransmit list + * in 'process_received_nack' + */ + cur->retx_count--; + /* remove from retransmit list */ + prev->next = cur->next; + /* put the PDU in the ack list */ + entity->ack_list = rlc_tx_pdu_list_add(sn_compare_tx, entity, + entity->ack_list, cur); + cur = prev->next; + } else { + prev = cur; + cur = cur->next; + } + } + entity->retransmit_list = head.next; + +} + +static void consider_retransmission(rlc_entity_am_t *entity, + rlc_tx_pdu_segment_t *cur) +{ + cur->retx_count++; + + /* let's report max RETX reached for all retx_count >= max_retx_threshold + * (specs say to report if retx_count == max_retx_threshold). + * Upper layers should react (radio link failure), so no big deal actually. + */ + if (cur->retx_count >= entity->max_retx_threshold) { + entity->common.max_retx_reached(entity->common.max_retx_reached_data, + (rlc_entity_t *)entity); + } + + /* let's put in retransmit list even if we are over max_retx_threshold. + * upper layers should deal with this condition, internally it's better + * for the RLC code to keep going with this segment (we only remove + * a segment that was ACKed) + */ + entity->retransmit_list = rlc_tx_pdu_list_add(sn_compare_tx, entity, + entity->retransmit_list, cur); +} + +static int so_overlap(int s1, int e1, int s2, int e2) +{ + if (s1 < s2) { + if (e1 == -1 || e1 >= s2) + return 1; + return 0; + } + if (e2 == -1 || s1 <= e2) + return 1; + return 0; +} + +static void process_received_nack(rlc_entity_am_t *entity, int sn, + int so_start, int so_end) +{ + /* put all PDU segments with SN == 'sn' and with an overlapping so start/end + * to the retransmit list + * source lists are ack list and wait list. + * Not sure if we should consider wait list, isn't the other end supposed + * to only NACK SNs lower than the ACK SN sent in the status PDU, in which + * case all potential PDU segments should all be in ack list when calling + * the current function? in doubt let's accept anything and thus process + * also wait list. + */ + rlc_tx_pdu_segment_t head; + rlc_tx_pdu_segment_t *cur; + rlc_tx_pdu_segment_t *prev; + + /* check that VT(A) <= sn < VT(S) */ + if (!(sn_compare_tx(entity, entity->vt_a, sn) <= 0 && + sn_compare_tx(entity, sn, entity->vt_s) < 0)) + return; + + /* process wait list */ + head.next = entity->wait_list; + prev = &head; + cur = entity->wait_list; + while (cur != NULL) { + if (cur->sn == sn && + so_overlap(so_start, so_end, cur->so, cur->so + cur->data_size - 1)) { + /* remove from wait list */ + prev->next = cur->next; + /* consider the PDU segment for retransmission */ + consider_retransmission(entity, cur); + cur = prev->next; + } else { + prev = cur; + cur = cur->next; + } + } + entity->wait_list = head.next; + + /* process ack list */ + head.next = entity->ack_list; + prev = &head; + cur = entity->ack_list; + while (cur != NULL) { + if (cur->sn == sn && + so_overlap(so_start, so_end, cur->so, cur->so + cur->data_size - 1)) { + /* remove from ack list */ + prev->next = cur->next; + /* consider the PDU segment for retransmission */ + consider_retransmission(entity, cur); + cur = prev->next; + } else { + prev = cur; + cur = cur->next; + } + } + entity->ack_list = head.next; +} + +int tx_pdu_in_ack_list_full(rlc_tx_pdu_segment_t *pdu) +{ + int sn = pdu->sn; + int last_byte = -1; + int new_last_byte; + int is_last_seen = 0; + + while (pdu != NULL && pdu->sn == sn) { + if (pdu->so > last_byte + 1) return 0; + if (pdu->is_last) + is_last_seen = 1; + new_last_byte = pdu->so + pdu->data_size - 1; + if (new_last_byte > last_byte) + last_byte = new_last_byte; + pdu = pdu->next; + } + + return is_last_seen == 1; +} + +int tx_pdu_in_ack_list_size(rlc_tx_pdu_segment_t *pdu) +{ + int sn = pdu->sn; + int ret = 0; + + while (pdu != NULL && pdu->sn == sn) { + ret += pdu->data_size; + pdu = pdu->next; + } + + return ret; +} + +void ack_sdu_bytes(rlc_sdu_t *start, int start_byte, int sdu_size) +{ + rlc_sdu_t *cur = start; + int remaining_size = sdu_size; + + while (remaining_size) { + int cursize = cur->size - start_byte; + if (cursize > remaining_size) + cursize = remaining_size; + cur->acked_bytes += cursize; + remaining_size -= cursize; + /* start_byte is only meaningful for the 1st SDU, then it is 0 */ + start_byte = 0; + cur = cur->next; + } +} + +rlc_tx_pdu_segment_t *tx_list_remove_sn(rlc_tx_pdu_segment_t *list, int sn) +{ + rlc_tx_pdu_segment_t head; + rlc_tx_pdu_segment_t *cur; + rlc_tx_pdu_segment_t *prev; + + head.next = list; + cur = list; + prev = &head; + + while (cur != NULL) { + if (cur->sn == sn) { + prev->next = cur->next; + rlc_tx_free_pdu(cur); + cur = prev->next; + } else { + prev = cur; + cur = cur->next; + } + } + + return head.next; +} + +void cleanup_sdu_list(rlc_entity_am_t *entity) +{ + rlc_sdu_t head; + rlc_sdu_t *cur; + rlc_sdu_t *prev; + + /* remove fully acked SDUs, indicate successful delivery to upper layer */ + head.next = entity->tx_list; + cur = entity->tx_list; + prev = &head; + + while (cur != NULL) { + if (cur->acked_bytes == cur->size) { + prev->next = cur->next; + entity->tx_size -= cur->size; + entity->common.sdu_successful_delivery( + entity->common.sdu_successful_delivery_data, + (rlc_entity_t *)entity, cur->upper_layer_id); + rlc_free_sdu(cur); + entity->tx_end = prev; + cur = prev->next; + } else { + entity->tx_end = cur; + cur = cur->next; + } + } + + entity->tx_list = head.next; + + /* if tx_end == head then it means that the list is now empty */ + if (entity->tx_end == &head) + entity->tx_end = NULL; +} + +static void finalize_ack_nack_processing(rlc_entity_am_t *entity) +{ + int sn; + rlc_tx_pdu_segment_t *cur = entity->ack_list; + int pdu_size; + + if (cur == NULL) + return; + + /* Remove full PDUs and ack the SDU bytes they cover. Start from SN == VT(A) + * and process increasing SNs until end of list or missing ACK or PDU not + * fully ACKed. + */ + while (cur != NULL && cur->sn == entity->vt_a && + tx_pdu_in_ack_list_full(cur)) { + sn = cur->sn; + entity->vt_a = (entity->vt_a + 1) % 1024; + pdu_size = tx_pdu_in_ack_list_size(cur); + ack_sdu_bytes(cur->start_sdu, cur->sdu_start_byte, pdu_size); + while (cur != NULL && cur->sn == sn) + cur = cur->next; + entity->ack_list = tx_list_remove_sn(entity->ack_list, sn); + } + + cleanup_sdu_list(entity); +} + +void rlc_entity_am_recv_pdu(rlc_entity_t *_entity, char *buffer, int size) +{ +#define R(d) do { if (rlc_pdu_decoder_in_error(&d)) goto err; } while (0) + rlc_entity_am_t *entity = (rlc_entity_am_t *)_entity; + rlc_pdu_decoder_t decoder; + rlc_pdu_decoder_t data_decoder; + rlc_pdu_decoder_t control_decoder; + + int dc; + int rf; + int p = 0; + int fi; + int e; + int sn; + int lsf; + int so; + + int cpt; + int e1; + int e2; + int ack_sn; + int nack_sn; + int so_start; + int so_end; + int control_e1; + int control_e2; + + int data_e; + int data_li; + + int packet_count; + int data_size; + int data_start; + int indicated_data_size; + + rlc_rx_pdu_segment_t *pdu_segment; + + rlc_pdu_decoder_init(&decoder, buffer, size); + dc = rlc_pdu_decoder_get_bits(&decoder, 1); R(decoder); + if (dc == 0) goto control; + + /* data PDU */ + rf = rlc_pdu_decoder_get_bits(&decoder, 1); R(decoder); + p = rlc_pdu_decoder_get_bits(&decoder, 1); R(decoder); + fi = rlc_pdu_decoder_get_bits(&decoder, 2); R(decoder); + e = rlc_pdu_decoder_get_bits(&decoder, 1); R(decoder); + sn = rlc_pdu_decoder_get_bits(&decoder, 10); R(decoder); + + /* dicard PDU if rx buffer is full */ + if (entity->rx_size + size > entity->rx_maxsize) { + LOG_D(RLC, "%s:%d:%s: warning: discard PDU, RX buffer full\n", + __FILE__, __LINE__, __FUNCTION__); + goto discard; + } + + if (!sn_in_recv_window(entity, sn)) { + LOG_D(RLC, "%s:%d:%s: warning: discard PDU, sn out of window (sn %d vr_r %d)\n", + __FILE__, __LINE__, __FUNCTION__, + sn, entity->vr_r); + goto discard; + } + + if (rf) { + lsf = rlc_pdu_decoder_get_bits(&decoder, 1); R(decoder); + so = rlc_pdu_decoder_get_bits(&decoder, 15); R(decoder); + } else { + lsf = 1; + so = 0; + } + + packet_count = 1; + + /* go to start of data */ + indicated_data_size = 0; + data_decoder = decoder; + data_e = e; + while (data_e) { + data_e = rlc_pdu_decoder_get_bits(&data_decoder, 1); R(data_decoder); + data_li = rlc_pdu_decoder_get_bits(&data_decoder, 11); R(data_decoder); + if (data_li == 0) { + LOG_D(RLC, "%s:%d:%s: warning: discard PDU, li == 0\n", + __FILE__, __LINE__, __FUNCTION__); + goto discard; + } + indicated_data_size += data_li; + packet_count++; + } + rlc_pdu_decoder_align(&data_decoder); + + data_start = data_decoder.byte; + data_size = size - data_start; + + if (data_size <= 0) { + LOG_D(RLC, "%s:%d:%s: warning: discard PDU, wrong data size (sum of LI %d data size %d)\n", + __FILE__, __LINE__, __FUNCTION__, + indicated_data_size, data_size); + goto discard; + } + if (indicated_data_size >= data_size) { + LOG_D(RLC, "%s:%d:%s: warning: discard PDU, bad LIs (sum of LI %d data size %d)\n", + __FILE__, __LINE__, __FUNCTION__, + indicated_data_size, data_size); + goto discard; + } + + /* discard segment if all the bytes of the segment are already there */ + if (segment_already_received(entity, sn, so, data_size)) { + LOG_D(RLC, "%s:%d:%s: warning: discard PDU, already received\n", + __FILE__, __LINE__, __FUNCTION__); + goto discard; + } + + char *fi_str[] = { + "first byte: YES last byte: YES", + "first byte: YES last byte: NO", + "first byte: NO last byte: YES", + "first byte: NO last byte: NO", + }; + + LOG_D(RLC, "found %d packets, data size %d data start %d [fi %d %s] (sn %d) (p %d)\n", + packet_count, data_size, data_decoder.byte, fi, fi_str[fi], sn, p); + + /* put in pdu reception list */ + entity->rx_size += size; + pdu_segment = rlc_rx_new_pdu_segment(sn, so, size, lsf, buffer, data_start); + entity->rx_list = rlc_rx_pdu_segment_list_add(sn_compare_rx, entity, + entity->rx_list, pdu_segment); + + /* do reception actions (36.322 5.1.3.2.3) */ + rlc_am_reception_actions(entity, pdu_segment); + + if (p) { + /* 36.322 5.2.3 says status triggering should be delayed + * until x < VR(MS) or x >= VR(MR). This is not clear (what + * is x then? we keep the same?). So let's trigger no matter what. + */ + int vr_mr = (entity->vr_r + 512) % 1024; + entity->status_triggered = 1; + if (!(sn_compare_rx(entity, sn, entity->vr_ms) < 0 || + sn_compare_rx(entity, sn, vr_mr) >= 0)) { + LOG_D(RLC, "%s:%d:%s: warning: STATUS trigger should be delayed, according to specs\n", + __FILE__, __LINE__, __FUNCTION__); + } + } + + return; + +control: + cpt = rlc_pdu_decoder_get_bits(&decoder, 3); R(decoder); + if (cpt != 0) { + LOG_D(RLC, "%s:%d:%s: warning: discard PDU, CPT not 0 (%d)\n", + __FILE__, __LINE__, __FUNCTION__, cpt); + goto discard; + } + ack_sn = rlc_pdu_decoder_get_bits(&decoder, 10); R(decoder); + e1 = rlc_pdu_decoder_get_bits(&decoder, 1); R(decoder); + + /* let's try to parse the control PDU once to check consistency */ + control_decoder = decoder; + control_e1 = e1; + while (control_e1) { + rlc_pdu_decoder_get_bits(&control_decoder, 10); R(control_decoder); /* NACK_SN */ + control_e1 = rlc_pdu_decoder_get_bits(&control_decoder, 1); R(control_decoder); + control_e2 = rlc_pdu_decoder_get_bits(&control_decoder, 1); R(control_decoder); + if (control_e2) { + rlc_pdu_decoder_get_bits(&control_decoder, 15); R(control_decoder); /* SOstart */ + rlc_pdu_decoder_get_bits(&control_decoder, 15); R(control_decoder); /* SOend */ + } + } + + /* 36.322 5.2.2.2 says to stop t_poll_retransmit if a ACK or NACK is + * received for the SN 'poll_sn' + */ + if (sn_compare_tx(entity, entity->poll_sn, ack_sn) < 0) + entity->t_poll_retransmit_start = 0; + + /* at this point, accept the PDU even if the actual values + * may be incorrect (eg. if so_start > so_end) + */ + process_received_ack(entity, ack_sn); + + while (e1) { + nack_sn = rlc_pdu_decoder_get_bits(&decoder, 10); R(decoder); + e1 = rlc_pdu_decoder_get_bits(&decoder, 1); R(decoder); + e2 = rlc_pdu_decoder_get_bits(&decoder, 1); R(decoder); + if (e2) { + so_start = rlc_pdu_decoder_get_bits(&decoder, 15); R(decoder); + so_end = rlc_pdu_decoder_get_bits(&decoder, 15); R(decoder); + if (so_end < so_start) { + LOG_W(RLC, "%s:%d:%s: warning, bad so start/end, NACK the whole PDU (sn %d)\n", + __FILE__, __LINE__, __FUNCTION__, nack_sn); + so_start = 0; + so_end = -1; + } + /* special value 0x7fff indicates 'all bytes to the end' */ + if (so_end == 0x7fff) + so_end = -1; + } else { + so_start = 0; + so_end = -1; + } + process_received_nack(entity, nack_sn, so_start, so_end); + + /* 36.322 5.2.2.2 says to stop t_poll_retransmit if a ACK or NACK is + * received for the SN 'poll_sn' + */ + if (entity->poll_sn == nack_sn) + entity->t_poll_retransmit_start = 0; + } + + finalize_ack_nack_processing(entity); + + return; + +err: + LOG_W(RLC, "%s:%d:%s: error decoding PDU, discarding\n", __FILE__, __LINE__, __FUNCTION__); + goto discard; + +discard: + if (p) + entity->status_triggered = 1; + +#undef R +} + +/*************************************************************************/ +/* TX functions */ +/*************************************************************************/ + +static int pdu_size(rlc_entity_am_t *entity, rlc_tx_pdu_segment_t *pdu) +{ + int header_size; + int sdu_count; + int data_size; + int li_bits; + rlc_sdu_t *sdu; + + header_size = 2; + if (pdu->is_segment) + header_size += 2; + + data_size = pdu->data_size; + + sdu = pdu->start_sdu; + + sdu_count = 1; + data_size -= sdu->size - pdu->sdu_start_byte; + sdu = sdu->next; + + while (data_size > 0) { + sdu_count++; + data_size -= sdu->size; + sdu = sdu->next; + } + + li_bits = 12 * (sdu_count - 1); + header_size += (li_bits + 7) / 8; + + return header_size + pdu->data_size; +} + +static int header_size(int sdu_count) +{ + int bits = 16 + 12 * (sdu_count - 1); + /* padding if we have to */ + return (bits + 7) / 8; +} + +typedef struct { + int sdu_count; + int data_size; + int header_size; +} tx_pdu_size_t; + +static tx_pdu_size_t compute_new_pdu_size(rlc_entity_am_t *entity, int maxsize) +{ + tx_pdu_size_t ret; + int sdu_count; + int sdu_size; + int pdu_data_size; + rlc_sdu_t *sdu; + + int vt_ms = (entity->vt_a + 512) % 1024; + + ret.sdu_count = 0; + ret.data_size = 0; + ret.header_size = 0; + + /* sn out of window? nothing to do */ + if (!(sn_compare_tx(entity, entity->vt_s, entity->vt_a) >= 0 && + sn_compare_tx(entity, entity->vt_s, vt_ms) < 0)) + return ret; + + /* TX PDU - let's make the biggest PDU we can with the SDUs we have */ + sdu_count = 0; + pdu_data_size = 0; + sdu = entity->tx_list; + while (sdu != NULL) { + /* include SDU only if it has not been fully included in PDUs already */ + if (sdu->next_byte != sdu->size) { + int new_header_size = header_size(sdu_count + 1); + /* if we cannot put new header + at least 1 byte of data then over */ + if (new_header_size + pdu_data_size + 1 > maxsize) + break; + sdu_count++; + /* only include the bytes of this SDU not included in PDUs already */ + sdu_size = sdu->size - sdu->next_byte; + /* don't feed more than 'maxsize' bytes */ + if (new_header_size + pdu_data_size + sdu_size > maxsize) + sdu_size = maxsize - new_header_size - pdu_data_size; + pdu_data_size += sdu_size; + /* if we put more than 2^11-1 bytes then the LI field cannot be used, + * so this is the last SDU we can put + */ + if (sdu_size > 2047) + break; + } + sdu = sdu->next; + } + + if (sdu_count) { + ret.sdu_count = sdu_count; + ret.data_size = pdu_data_size; + ret.header_size = header_size(sdu_count); + } + + return ret; +} + +static int status_size(rlc_entity_am_t *entity, int maxsize) +{ + /* let's count bits */ + int bits = 15; /* minimum size is 15 (header+ack_sn+e1) */ + int sn; + + maxsize *= 8; + + if (bits > maxsize) { + LOG_W(RLC, "%s:%d:%s: warning: cannot generate status PDU, not enough room\n", + __FILE__, __LINE__, __FUNCTION__); + return 0; + } + + /* each NACK adds 12 bits */ + sn = entity->vr_r; + while (bits + 12 <= maxsize && sn_compare_rx(entity, sn, entity->vr_ms) < 0) { + if (!(rlc_am_segment_full(entity, sn))) + bits += 12; + sn = (sn + 1) % 1024; + } + + return (bits + 7) / 8; +} + +static int generate_status(rlc_entity_am_t *entity, char *buffer, int size) +{ + /* let's count bits */ + int bits = 15; /* minimum size is 15 (header+ack_sn+e1) */ + int sn; + rlc_pdu_encoder_t encoder; + int has_nack = 0; + int ack; + + rlc_pdu_encoder_init(&encoder, buffer, size); + + size *= 8; + + if (bits > size) { + LOG_W(RLC, "%s:%d:%s: warning: cannot generate status PDU, not enough room\n", + __FILE__, __LINE__, __FUNCTION__); + return 0; + } + + /* header */ + rlc_pdu_encoder_put_bits(&encoder, 0, 1); /* D/C */ + rlc_pdu_encoder_put_bits(&encoder, 0, 3); /* CPT */ + + /* reserve room for ACK (it will be set after putting the NACKs) */ + rlc_pdu_encoder_put_bits(&encoder, 0, 10); + + /* at this point, ACK is VR(R) */ + ack = entity->vr_r; + + /* each NACK adds 12 bits */ + sn = entity->vr_r; + while (bits + 12 <= size && sn_compare_rx(entity, sn, entity->vr_ms) < 0) { + if (!(rlc_am_segment_full(entity, sn))) { + /* put previous e1 (is 1) */ + rlc_pdu_encoder_put_bits(&encoder, 1, 1); + /* if previous was NACK, put previous e2 (0, we don't do 'so' thing) */ + if (has_nack) + rlc_pdu_encoder_put_bits(&encoder, 0, 1); + /* put NACKed sn */ + rlc_pdu_encoder_put_bits(&encoder, sn, 10); + has_nack = 1; + bits += 12; + } else { + /* this sn is full and we put all NACKs before it, use it for ACK */ + ack = (sn + 1) % 1024; + } + sn = (sn + 1) % 1024; + } + + /* go to highest full sn+1 for ACK, VR(MS) is the limit */ + while (sn_compare_rx(entity, sn, entity->vr_ms) < 0 && + rlc_am_segment_full(entity, sn)) { + ack = (sn + 1) % 1024; + sn = (sn + 1) % 1024; + } + + /* at this point, if last put was NACK then put 2 bits else put 1 bit */ + if (has_nack) + rlc_pdu_encoder_put_bits(&encoder, 0, 2); + else + rlc_pdu_encoder_put_bits(&encoder, 0, 1); + + rlc_pdu_encoder_align(&encoder); + + /* let's put the ACK */ + buffer[0] |= ack >> 6; + buffer[1] |= (ack & 0x3f) << 2; + + /* reset the trigger */ + entity->status_triggered = 0; + + /* start t_status_prohibit */ + entity->t_status_prohibit_start = entity->t_current; + + return encoder.byte; +} + +int transmission_buffer_empty(rlc_entity_am_t *entity) +{ + rlc_sdu_t *sdu; + + /* is transmission buffer empty? */ + sdu = entity->tx_list; + while (sdu != NULL) { + if (sdu->next_byte != sdu->size) + return 0; + sdu = sdu->next; + } + return 1; +} + +int check_poll_after_pdu_assembly(rlc_entity_am_t *entity) +{ + int retransmission_buffer_empty; + int window_stalling; + int vt_ms; + + /* is retransmission buffer empty? */ + if (entity->retransmit_list == NULL) + retransmission_buffer_empty = 1; + else + retransmission_buffer_empty = 0; + + /* is window stalling? */ + vt_ms = (entity->vt_a + 512) % 1024; + if (!(sn_compare_tx(entity, entity->vt_s, entity->vt_a) >= 0 && + sn_compare_tx(entity, entity->vt_s, vt_ms) < 0)) + window_stalling = 1; + else + window_stalling = 0; + + return (transmission_buffer_empty(entity) && retransmission_buffer_empty) || + window_stalling; +} + +void include_poll(rlc_entity_am_t *entity, char *buffer) +{ + /* set the P bit to 1 */ + buffer[0] |= 0x20; + + entity->pdu_without_poll = 0; + entity->byte_without_poll = 0; + + /* set POLL_SN to VT(S) - 1 */ + entity->poll_sn = (entity->vt_s + 1023) % 1024; + + /* start t_poll_retransmit */ + entity->t_poll_retransmit_start = entity->t_current; +} + +static int serialize_pdu(rlc_entity_am_t *entity, char *buffer, int bufsize, + rlc_tx_pdu_segment_t *pdu, int p) +{ + int first_sdu_full; + int last_sdu_full; + int sdu_next_byte; + rlc_sdu_t *sdu; + int i; + int cursize; + rlc_pdu_encoder_t encoder; + int fi; + int e; + int li; + char *out; + int outpos; + int sdu_count; + int header_size; + int sdu_start_byte; + + first_sdu_full = pdu->sdu_start_byte == 0; + + /* is last SDU full? (and also compute sdu_count) */ + last_sdu_full = 1; + sdu = pdu->start_sdu; + sdu_next_byte = pdu->sdu_start_byte; + cursize = 0; + sdu_count = 0; + while (cursize != pdu->data_size) { + int sdu_size = sdu->size - sdu_next_byte; + sdu_count++; + if (cursize + sdu_size > pdu->data_size) { + last_sdu_full = 0; + break; + } + cursize += sdu_size; + sdu = sdu->next; + sdu_next_byte = 0; + } + + /* generate header */ + rlc_pdu_encoder_init(&encoder, buffer, bufsize); + + rlc_pdu_encoder_put_bits(&encoder, 1, 1); /* D/C: 1 = data */ + rlc_pdu_encoder_put_bits(&encoder, pdu->is_segment, 1); /* RF */ + rlc_pdu_encoder_put_bits(&encoder, 0, 1); /* P: reserve, set later */ + + fi = 0; + if (!first_sdu_full) + fi |= 0x02; + if (!last_sdu_full) + fi |= 0x01; + rlc_pdu_encoder_put_bits(&encoder, fi, 2); /* FI */ + + /* to understand the logic for Es and LIs: + * If we have: + * 1 SDU: E=0 + * + * 2 SDUs: E=1 + * then: E=0 LI(sdu[0]) + * + * 3 SDUs: E=1 + * then: E=1 LI(sdu[0]) + * then: E=0 LI(sdu[1]) + * + * 4 SDUs: E=1 + * then: E=1 LI(sdu[0]) + * then: E=1 LI(sdu[1]) + * then: E=0 LI(sdu[2]) + */ + if (sdu_count >= 2) + e = 1; + else + e = 0; + rlc_pdu_encoder_put_bits(&encoder, e, 1); /* E */ + + rlc_pdu_encoder_put_bits(&encoder, pdu->sn, 10); /* SN */ + + if (pdu->is_segment) { + rlc_pdu_encoder_put_bits(&encoder, pdu->is_last, 1); /* LSF */ + rlc_pdu_encoder_put_bits(&encoder, pdu->so, 15); /* SO */ + } + + /* put LIs */ + sdu = pdu->start_sdu; + /* first SDU */ + li = sdu->size - pdu->sdu_start_byte; + /* put E+LI only if at least 2 SDUs */ + if (sdu_count >= 2) { + /* E is 1 if at least 3 SDUs */ + if (sdu_count >= 3) + e = 1; + else + e = 0; + rlc_pdu_encoder_put_bits(&encoder, e, 1); /* E */ + rlc_pdu_encoder_put_bits(&encoder, li, 11); /* LI */ + } + /* next SDUs, but not the last (no LI for the last) */ + sdu = sdu->next; + for (i = 2; i < sdu_count; i++, sdu = sdu->next) { + if (i != sdu_count - 1) + e = 1; + else + e = 0; + li = sdu->size; + rlc_pdu_encoder_put_bits(&encoder, e, 1); /* E */ + rlc_pdu_encoder_put_bits(&encoder, li, 11); /* LI */ + } + + rlc_pdu_encoder_align(&encoder); + + header_size = encoder.byte; + + /* generate data */ + out = buffer + header_size; + sdu = pdu->start_sdu; + sdu_start_byte = pdu->sdu_start_byte; + outpos = 0; + for (i = 0; i < sdu_count; i++, sdu = sdu->next) { + li = sdu->size - sdu_start_byte; + if (outpos + li >= pdu->data_size) + li = pdu->data_size - outpos; + memcpy(out+outpos, sdu->data + sdu_start_byte, li); + outpos += li; + sdu_start_byte = 0; + } + + if (p) + include_poll(entity, buffer); + + return header_size + pdu->data_size; +} + +static int generate_tx_pdu(rlc_entity_am_t *entity, char *buffer, int bufsize) +{ + int vt_ms; + tx_pdu_size_t pdu_size; + rlc_sdu_t *sdu; + int i; + int cursize; + int p; + rlc_tx_pdu_segment_t *pdu; + + /* sn out of window? do nothing */ + vt_ms = (entity->vt_a + 512) % 1024; + if (!(sn_compare_tx(entity, entity->vt_s, entity->vt_a) >= 0 && + sn_compare_tx(entity, entity->vt_s, vt_ms) < 0)) + return 0; + + pdu_size = compute_new_pdu_size(entity, bufsize); + if (pdu_size.sdu_count == 0) + return 0; + + pdu = rlc_tx_new_pdu(); + + pdu->sn = entity->vt_s; + entity->vt_s = (entity->vt_s + 1) % 1024; + + /* go to first SDU (skip those already fully processed) */ + sdu = entity->tx_list; + while (sdu->next_byte == sdu->size) + sdu = sdu->next; + + pdu->start_sdu = sdu; + + pdu->sdu_start_byte = sdu->next_byte; + + pdu->so = 0; + pdu->is_segment = 0; + pdu->is_last = 1; + /* to conform to specs' logic, put -1 (specs say "for 1st retransmission + * put 0 otherwise increase", let's put -1 and always increase when the + * segment goes to retransmit list) + */ + pdu->retx_count = -1; + + /* reserve SDU bytes */ + cursize = 0; + for (i = 0; i < pdu_size.sdu_count; i++, sdu = sdu->next) { + int sdu_size = sdu->size - sdu->next_byte; + if (cursize + sdu_size > pdu_size.data_size) + sdu_size = pdu_size.data_size - cursize; + sdu->next_byte += sdu_size; + cursize += sdu_size; + } + + pdu->data_size = cursize; + + /* put PDU at the end of the wait list */ + entity->wait_list = rlc_tx_pdu_list_append(entity->wait_list, pdu); + + /* polling actions for a new PDU */ + entity->pdu_without_poll++; + entity->byte_without_poll += pdu_size.data_size; + if ((entity->poll_pdu != -1 && + entity->pdu_without_poll >= entity->poll_pdu) || + (entity->poll_byte != -1 && + entity->byte_without_poll >= entity->poll_byte)) + p = 1; + else + p = check_poll_after_pdu_assembly(entity); + + if (entity->force_poll) { + p = 1; + entity->force_poll = 0; + } + + return serialize_pdu(entity, buffer, bufsize, pdu, p); +} + +static void resegment(rlc_tx_pdu_segment_t *pdu, int size) +{ + rlc_tx_pdu_segment_t *new_pdu; + rlc_sdu_t *sdu; + int sdu_count; + int pdu_header_size; + int pdu_data_size; + int sdu_pos; + int sdu_bytes_to_take; + + /* PDU segment too big, cut in two parts so that first part fits into + * size bytes (including header) + */ + sdu = pdu->start_sdu; + pdu_data_size = 0; + sdu_pos = pdu->sdu_start_byte; + sdu_count = 0; + while (1) { + /* can we put a new header and at least one byte of data? */ + /* header has 2 more bytes for SO */ + pdu_header_size = 2 + header_size(sdu_count + 1); + if (pdu_header_size + pdu_data_size + 1 > size) { + /* no we can't, stop here */ + break; + } + /* yes we can, go ahead */ + sdu_count++; + sdu_bytes_to_take = sdu->size - sdu_pos; + if (pdu_header_size + pdu_data_size + sdu_bytes_to_take > size) { + sdu_bytes_to_take = size - (pdu_header_size + pdu_data_size); + } + sdu_pos += sdu_bytes_to_take; + if (sdu_pos == sdu->size) { + sdu = sdu->next; + sdu_pos = 0; + } + pdu_data_size += sdu_bytes_to_take; + } + + new_pdu = rlc_tx_new_pdu(); + pdu->is_segment = 1; + *new_pdu = *pdu; + + new_pdu->so = pdu->so + pdu_data_size; + new_pdu->data_size = pdu->data_size - pdu_data_size; + new_pdu->start_sdu = sdu; + new_pdu->sdu_start_byte = sdu_pos; + + pdu->is_last = 0; + pdu->data_size = pdu_data_size; + pdu->next = new_pdu; +} + +static int generate_retx_pdu(rlc_entity_am_t *entity, char *buffer, int size) +{ + rlc_tx_pdu_segment_t *pdu; + int orig_size; + int p; + + pdu = entity->retransmit_list; + orig_size = pdu_size(entity, pdu); + + if (orig_size > size) { + /* we can't resegment if size is less than 5 + * (4 bytes for header, 1 byte for data) + */ + if (size < 5) + return 0; + resegment(pdu, size); + } + + /* remove from retransmit list and put in wait list */ + entity->retransmit_list = pdu->next; + entity->wait_list = rlc_tx_pdu_list_add(sn_compare_tx, entity, + entity->wait_list, pdu); + + p = check_poll_after_pdu_assembly(entity); + + if (entity->force_poll) { + p = 1; + entity->force_poll = 0; + } + + return serialize_pdu(entity, buffer, orig_size, pdu, p); +} + +static int status_to_report(rlc_entity_am_t *entity) +{ + return entity->status_triggered && + (entity->t_status_prohibit_start == 0 || + entity->t_current - entity->t_status_prohibit_start > + entity->t_status_prohibit); +} + +static int retx_pdu_size(rlc_entity_am_t *entity, int maxsize) +{ + int size; + + if (entity->retransmit_list == NULL) + return 0; + + size = pdu_size(entity, entity->retransmit_list); + if (size <= maxsize) + return size; + + /* we can segment head of retransmist list if maxsize is large enough + * to hold a PDU segment with at least 1 data byte (so 5 bytes: 4 bytes + * header + 1 byte data) + */ + if (maxsize < 5) + return 0; + + /* a later segmentation of the head of retransmit list will generate a pdu + * of maximum size 'maxsize' (can be less) + */ + return maxsize; +} + +rlc_entity_buffer_status_t rlc_entity_am_buffer_status( + rlc_entity_t *_entity, int maxsize) +{ + rlc_entity_am_t *entity = (rlc_entity_am_t *)_entity; + rlc_entity_buffer_status_t ret; + tx_pdu_size_t tx_size; + + /* status PDU, if we have to */ + if (status_to_report(entity)) + ret.status_size = status_size(entity, maxsize); + else + ret.status_size = 0; + + /* TX PDU */ + tx_size = compute_new_pdu_size(entity, maxsize); + ret.tx_size = tx_size.data_size + tx_size.header_size; + + /* reTX PDU */ + ret.retx_size = retx_pdu_size(entity, maxsize); + + return ret; +} + +int rlc_entity_am_generate_pdu(rlc_entity_t *_entity, char *buffer, int size) +{ + rlc_entity_am_t *entity = (rlc_entity_am_t *)_entity; + int ret; + + if (status_to_report(entity)) { + ret = generate_status(entity, buffer, size); + if (ret != 0) + return ret; + } + + if (entity->retransmit_list != NULL) { + ret = generate_retx_pdu(entity, buffer, size); + if (ret != 0) + return ret; + } + + return generate_tx_pdu(entity, buffer, size); +} + +/*************************************************************************/ +/* SDU RX functions */ +/*************************************************************************/ + +void rlc_entity_am_recv_sdu(rlc_entity_t *_entity, char *buffer, int size, + int sdu_id) +{ + rlc_entity_am_t *entity = (rlc_entity_am_t *)_entity; + rlc_sdu_t *sdu; + + if (size > SDU_MAX) { + LOG_E(RLC, "%s:%d:%s: fatal: SDU size too big (%d bytes)\n", + __FILE__, __LINE__, __FUNCTION__, size); + exit(1); + } + + if (entity->tx_size + size > entity->tx_maxsize) { + LOG_D(RLC, "%s:%d:%s: warning: SDU rejected, SDU buffer full\n", + __FILE__, __LINE__, __FUNCTION__); + return; + } + + entity->tx_size += size; + + sdu = rlc_new_sdu(buffer, size, sdu_id); + rlc_sdu_list_add(&entity->tx_list, &entity->tx_end, sdu); +} + +/*************************************************************************/ +/* time/timers */ +/*************************************************************************/ + +static void check_t_poll_retransmit(rlc_entity_am_t *entity) +{ + rlc_tx_pdu_segment_t head; + rlc_tx_pdu_segment_t *cur; + rlc_tx_pdu_segment_t *prev; + int sn; + + /* 36.322 5.2.2.3 */ + /* did t_poll_retransmit expire? */ + if (entity->t_poll_retransmit_start == 0 || + entity->t_current <= entity->t_poll_retransmit_start + + entity->t_poll_retransmit) + return; + + /* stop timer */ + entity->t_poll_retransmit_start = 0; + + /* 36.322 5.2.2.3 says: + * + * - include a poll in a RLC data PDU as described in section 5.2.2.1 + * + * That does not seem to be conditional. So we forcefully will send + * a poll as soon as we generate a PDU. + * Hopefully this interpretation is correct. In the worst case we generate + * more polling than necessary, but it's not a big deal. When + * 't_poll_retransmit' expires it means we didn't receive a status report, + * meaning a bad radio link, so things are quite bad at this point and + * asking again for a poll won't hurt much more. + */ + entity->force_poll = 1; + + LOG_D(RLC, "%s:%d:%s: warning: t_poll_retransmit expired\n", + __FILE__, __LINE__, __FUNCTION__); + + /* do we meet conditions of 36.322 5.2.2.3? */ + if (!check_poll_after_pdu_assembly(entity)) + return; + + /* search wait list for PDU with SN = VT(S)-1 */ + sn = (entity->vt_s + 1023) % 1024; + + head.next = entity->wait_list; + cur = entity->wait_list; + prev = &head; + + while (cur != NULL) { + if (cur->sn == sn) + break; + prev = cur; + cur = cur->next; + } + + /* PDU with SN = VT(S)-1 not found?, take the head of wait list */ + if (cur == NULL) { + cur = entity->wait_list; + prev = &head; + sn = cur->sn; + } + + /* 36.322 says "PDU", not "PDU segment", so let's retransmit all + * PDU segments with this SN + */ + while (cur != NULL && cur->sn == sn) { + prev->next = cur->next; + entity->wait_list = head.next; + /* put in retransmit list */ + consider_retransmission(entity, cur); + cur = prev->next; + } +} + +static void check_t_reordering(rlc_entity_am_t *entity) +{ + int sn; + + /* is t_reordering running and if yes has it expired? */ + if (entity->t_reordering_start == 0 || + entity->t_current <= entity->t_reordering_start + entity->t_reordering) + return; + + /* stop timer */ + entity->t_reordering_start = 0; + + LOG_D(RLC, "%s:%d:%s: t_reordering expired\n", __FILE__, __LINE__, __FUNCTION__); + + /* update VR(MS) to first SN >= VR(X) for which not all PDU segments + * have been received + */ + sn = entity->vr_x; + while (rlc_am_segment_full(entity, sn)) + sn = (sn + 1) % 1024; + entity->vr_ms = sn; + + if (sn_compare_rx(entity, entity->vr_h, entity->vr_ms) > 0) { + entity->t_reordering_start = entity->t_current; + entity->vr_x = entity->vr_h; + } + + /* trigger STATUS report */ + entity->status_triggered = 1; +} + +void rlc_entity_am_set_time(rlc_entity_t *_entity, uint64_t now) +{ + rlc_entity_am_t *entity = (rlc_entity_am_t *)_entity; + + entity->t_current = now; + + check_t_poll_retransmit(entity); + + check_t_reordering(entity); + + /* t_status_prohibit is handled by generate_status */ +} + +/*************************************************************************/ +/* discard/re-establishment/delete */ +/*************************************************************************/ + +void rlc_entity_am_discard_sdu(rlc_entity_t *_entity, int sdu_id) +{ + /* implements 36.322 5.3 */ + rlc_entity_am_t *entity = (rlc_entity_am_t *)_entity; + rlc_sdu_t head; + rlc_sdu_t *cur; + rlc_sdu_t *prev; + + head.next = entity->tx_list; + cur = entity->tx_list; + prev = &head; + + while (cur != NULL && cur->upper_layer_id != sdu_id) { + prev = cur; + cur = cur->next; + } + + /* if sdu_id not found or some bytes have already been 'PDU-ized' + * then do nothing + */ + if (cur == NULL || cur->next_byte != 0) + return; + + /* remove SDU from tx_list */ + prev->next = cur->next; + entity->tx_list = head.next; + if (entity->tx_end == cur) { + if (prev != &head) + entity->tx_end = prev; + else + entity->tx_end = NULL; + } + + rlc_free_sdu(cur); +} + +static void free_pdu_segment_list(rlc_tx_pdu_segment_t *l) +{ + rlc_tx_pdu_segment_t *cur; + + while (l != NULL) { + cur = l; + l = l->next; + rlc_tx_free_pdu(cur); + } +} + +static void clear_entity(rlc_entity_am_t *entity) +{ + rlc_rx_pdu_segment_t *cur_rx; + rlc_sdu_t *cur_tx; + + entity->vr_r = 0; + entity->vr_x = 0; + entity->vr_ms = 0; + entity->vr_h = 0; + + entity->status_triggered = 0; + + entity->vt_a = 0; + entity->vt_s = 0; + entity->poll_sn = 0; + entity->pdu_without_poll = 0; + entity->byte_without_poll = 0; + entity->force_poll = 0; + + entity->t_current = 0; + + entity->t_reordering_start = 0; + entity->t_status_prohibit_start = 0; + entity->t_poll_retransmit_start = 0; + + cur_rx = entity->rx_list; + while (cur_rx != NULL) { + rlc_rx_pdu_segment_t *p = cur_rx; + cur_rx = cur_rx->next; + rlc_rx_free_pdu_segment(p); + } + entity->rx_list = NULL; + entity->rx_size = 0; + + memset(&entity->reassemble, 0, sizeof(rlc_am_reassemble_t)); + + cur_tx = entity->tx_list; + while (cur_tx != NULL) { + rlc_sdu_t *p = cur_tx; + cur_tx = cur_tx->next; + rlc_free_sdu(p); + } + entity->tx_list = NULL; + entity->tx_end = NULL; + entity->tx_size = 0; + + free_pdu_segment_list(entity->wait_list); + free_pdu_segment_list(entity->retransmit_list); + free_pdu_segment_list(entity->ack_list); + entity->wait_list = NULL; + entity->retransmit_list = NULL; + entity->ack_list = NULL; +} + +void rlc_entity_am_reestablishment(rlc_entity_t *_entity) +{ + rlc_entity_am_t *entity = (rlc_entity_am_t *)_entity; + + /* 36.322 5.4 says to deliver SDUs if possible. + * Let's not do that, it makes the code simpler. + * TODO: change this behavior if wanted/needed. + */ + + clear_entity(entity); +} + +void rlc_entity_am_delete(rlc_entity_t *_entity) +{ + rlc_entity_am_t *entity = (rlc_entity_am_t *)_entity; + clear_entity(entity); + free(entity); +} diff --git a/openair2/LAYER2/rlc_v2/rlc_entity_am.h b/openair2/LAYER2/rlc_v2/rlc_entity_am.h new file mode 100644 index 00000000000..0437f17ad8e --- /dev/null +++ b/openair2/LAYER2/rlc_v2/rlc_entity_am.h @@ -0,0 +1,285 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef _RLC_ENTITY_AM_H_ +#define _RLC_ENTITY_AM_H_ + +#include <stdint.h> + +#include "rlc_entity.h" +#include "rlc_pdu.h" +#include "rlc_sdu.h" + +/* + * Here comes some documentation to understand the reassembly + * logic in the code and the fields in the structure rlc_am_reassemble_t. + * + * Inside RLC, we deal with SDUs, PDUs and PDU segments. + * SDUs are packets coming from upper layer. + * A PDU is made of a header and a payload. + * In the payload there are SDUs. + * First SDU and last SDU in a PDU may be incomplete. + * PDU segments exist in case of retransmissions when the MAC + * layer asks for less data than previously, in which case + * only part of the previous PDU is sent. + * + * This is PDU data (just bytes): + * --------------------------------------------------------- + * | PDU data | + * --------------------------------------------------------- + * It contains SDUs, like: + * --------------------------------------------------------- + * | SDU 1 | SDU 2 | [...] | SDU n | + * --------------------------------------------------------- + * SDU 1 may be only the end of an SDU from which previous bytes were + * transmitted in previous PDUs. + * SDU n may be only the start of an SDU, that is more bytes from + * this SDU may be sent in successive PDUs. + * + * At front of the PDU data, we have a header: + * --------------- --------------------------------------------------------- + * | PDU header | | SDU 1 | SDU 2 | [...] | SDU n | + * --------------- --------------------------------------------------------- + * PDU header describes PDU data (most notably lengths). + * + * A PDU segment is a part of a PDU. For example, from this PDU data: + * --------------------------------------------------------- + * | SDU 1 | SDU 2 | [...] | SDU n | + * --------------------------------------------------------- + * We can extract the following PDU segment (data part only): + * ---------------------- + * | PDU segment data | + * ---------------------- + * This PDU segment would contain the end of SDU 2 above and some SDUs up to, + * let's say SDU x (x is 5 below). + * + * In front of a transmitted PDU segment, we have a header, + * containing the important variable 'so' (segment offset) that gives + * the index of the first byte of the segment in the original PDU. + * -------------- ---------------------- + * | seg. header| | PDU segment data | + * -------------- ---------------------- + * + * Let's now explain the data structure rlc_am_reassemble_t. + * + * In the structure rlc_am_reassemble_t, the fields fi, e, sn and so + * are coming from the PDU segment header and the semantics is the + * one of the RLC specs. + * + * The currently processed PDU segment is stored in 'start'. + * We have 'start->s->data_offset' and 'start->s->size'. + * start->s->data_offset is the index of the start of the data in the + * PDU segment. That is if the header is of length 3 bytes + * then start->s->data_offset is 3. + * start->s->size is the total length of the PDU segment, + * including header. + * The size of actual data bytes in the PDU segment is thus + * start->s->size - start->s->data_offset. + * + * The field sdu_len is the length of the current SDU being + * processed. + * + * The field sdu_offset is the starting point of the + * current SDU being processed (starting from beginning + * of PDU segment, including header). + * + * The field data_pos is the current read pointer. 0 points to + * the beginning of the PDU segment (including header). + * + * The field pdu_byte points to the current byte in the original + * PDU (not the PDU segment). It starts at 0 when we start + * processing a new PDU (when a new 'sn' is seen) and always + * increases after each byte processed. This is tha variable + * that is used to know if the next PDU segment will be used + * or not and if yes, starting from which data byte (see + * function rlc_am_reassemble_next_segment). + * + * 'so' is important and points to the byte in the original PDU + * that is the first byte of the PDU segment. + * + * For example, let's take this PDU segment data from above: + * ---------------------- + * | PDU segment data | + * ---------------------- + * Let's say it is decomposed as: + * ---------------------- + * |222|33|4444|55555555| + * ---------------------- + * It contains SDUs 2, 3, 4, and 5. + * SDU 2 is 3 bytes, SDU 3 is 2 bytes, SDU 4 is 4 bytes, SDU 5 is 8 bytes. + * + * Let's suppose that the original PDU starts with: + * ---------------- + * |1111111|222222| + * ---------------- + * + * (In this example, in the PDU segment, SDU 2 is not full, + * we only have its end.) + * + * Then 'so' is 13 (SDU 1 is 7 bytes, head of SDU 2 is 6 bytes). + * + * Let's continue with our PDU segment data. + * Let's say we are current processing SDU 4. + * Let's say the read pointer (variable 'data_pos') is there: + * ---------------------- + * |222|33|4444|55555555| + * ---------------------- + * ^ + * read pointer (data_pos) + * + * Then: + * - sdu_len is 4 + * - sdu_offset is 5 + [PDU segment header length] + * (it points to the beginning of SDU 4, starting + * from the head of the PDU segment, that is + * 3 bytes for SDU 2, 2 bytes for SDU 3, and the + * PDU segment header length) + * - start->s->data_offset is [PDU segment header length] + * - pdu_byte is 20 + * (13 bytes from beginning of original PDU, + * 3 bytes for SDU 2, 2 bytes for SDU 3, then 2 bytes for SDU 4) + * - data_pos = read pointer = 7 + [PDU segment header length] + * + * To finish this description, in the code, a PDU is simply + * seen as a PDU segment with 'so' = 0 (and is_last == 1 (lsf in the specs), + * but this variable is not used by the reassembly logic). + * + * And for [PDU segment header length] we use start->s->data_offset. + * + * To recap, here is an illustration of the various variables + * and what starting point they use. In the figures, the start + * of the variable name is aligned to the byte it refers to. + * + is used to show the starting point. + * + * Let's put the PDU segment back into the original PDU. + * And let's show the values for when the read pointer + * is on the second byte of SDU 4 (as above). + * + * +++++++++++++++ so + * +++++++++++++++++++++++ pdu_byte + * --------------------------------------------------------- + * | SDU 1| SDU 2..222|33|4444|55555555| [...] | SDU n | + * --------------------------------------------------------- + * + * And now the PDU segment with header. + * + * + * ++++ sdu_len + * ++++++++++++++++++++++ sdu_offset + * +++++++++++++++++++++++ data_pos + * +++++++++++++++ start->s->data_offset + * +++++++++++++++++++++++++++++++++++++ start->s->size + * -------------- ---------------------- + * | seg. header| |222|33|4444|55555555| + * -------------- ---------------------- + * + * We see three case for the starting point: + * - start of original PDU (without any header) + * - start of header of current PDU segment + * - start of current SDU (for sdu_len) + */ + +typedef struct { + rlc_rx_pdu_segment_t *start; /* start of list */ + rlc_rx_pdu_segment_t *end; /* end of list (last element) */ + int pos; /* byte to get from current buffer */ + char sdu[SDU_MAX]; /* sdu is reassembled here */ + int sdu_pos; /* next byte to put in sdu */ + + /* decoder of current PDU */ + rlc_pdu_decoder_t dec; + int fi; + int e; + int sn; + int so; + int sdu_len; + int sdu_offset; + int data_pos; + int pdu_byte; +} rlc_am_reassemble_t; + +typedef struct { + rlc_entity_t common; + + /* configuration */ + int t_reordering; + int t_status_prohibit; + int t_poll_retransmit; + int poll_pdu; /* -1 means infinity */ + int poll_byte; /* -1 means infinity */ + int max_retx_threshold; + + /* runtime rx */ + int vr_r; + int vr_x; + int vr_ms; + int vr_h; + + int status_triggered; + + /* runtime tx */ + int vt_a; + int vt_s; + int poll_sn; + int pdu_without_poll; + int byte_without_poll; + int force_poll; + + /* set to the latest know time by the user of the module. Unit: ms */ + uint64_t t_current; + + /* timers (stores the TTI of activation, 0 means not active) */ + uint64_t t_reordering_start; + uint64_t t_status_prohibit_start; + uint64_t t_poll_retransmit_start; + + /* rx management */ + rlc_rx_pdu_segment_t *rx_list; + int rx_size; + int rx_maxsize; + + /* reassembly management */ + rlc_am_reassemble_t reassemble; + + /* tx management */ + rlc_sdu_t *tx_list; + rlc_sdu_t *tx_end; + int tx_size; + int tx_maxsize; + + rlc_tx_pdu_segment_t *wait_list; + rlc_tx_pdu_segment_t *retransmit_list; + + rlc_tx_pdu_segment_t *ack_list; +} rlc_entity_am_t; + +void rlc_entity_am_recv_sdu(rlc_entity_t *entity, char *buffer, int size, + int sdu_id); +void rlc_entity_am_recv_pdu(rlc_entity_t *entity, char *buffer, int size); +rlc_entity_buffer_status_t rlc_entity_am_buffer_status( + rlc_entity_t *entity, int maxsize); +int rlc_entity_am_generate_pdu(rlc_entity_t *entity, char *buffer, int size); +void rlc_entity_am_set_time(rlc_entity_t *entity, uint64_t now); +void rlc_entity_am_discard_sdu(rlc_entity_t *entity, int sdu_id); +void rlc_entity_am_reestablishment(rlc_entity_t *entity); +void rlc_entity_am_delete(rlc_entity_t *entity); + +#endif /* _RLC_ENTITY_AM_H_ */ diff --git a/openair2/LAYER2/rlc_v2/rlc_entity_um.c b/openair2/LAYER2/rlc_v2/rlc_entity_um.c new file mode 100644 index 00000000000..75692851cd2 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/rlc_entity_um.c @@ -0,0 +1,703 @@ +/* + * 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 "rlc_entity_um.h" +#include "rlc_pdu.h" + +#include <stdlib.h> +#include <string.h> + +#include "LOG/log.h" + +/*************************************************************************/ +/* PDU RX functions */ +/*************************************************************************/ + +static int modulus_rx(rlc_entity_um_t *entity, int a) +{ + /* as per 36.322 7.1, modulus base is vr(uh)-window_size and modulus is + * 2^sn_field_length (which is 'sn_modulus' in rlc_entity_um_t) + */ + int r = a - (entity->vr_uh - entity->window_size); + if (r < 0) r += entity->sn_modulus; + return r % entity->sn_modulus; +} + +static int sn_compare_rx(void *_entity, int a, int b) +{ + rlc_entity_um_t *entity = _entity; + return modulus_rx(entity, a) - modulus_rx(entity, b); +} + +static int sn_in_recv_window(void *_entity, int sn) +{ + rlc_entity_um_t *entity = _entity; + int mod_sn = modulus_rx(entity, sn); + /* we simplify (VR(UH) - UM_Window_Size) <= SN < VR(UH), base is + * (VR(UH) - UM_Window_Size) and VR(UH) = base + window_size + */ + return mod_sn < entity->window_size; +} + +/* return 1 if a PDU with SN == 'sn' is in the rx list, 0 otherwise */ +static int rlc_um_pdu_received(rlc_entity_um_t *entity, int sn) +{ + rlc_rx_pdu_segment_t *cur = entity->rx_list; + while (cur != NULL) { + if (cur->sn == sn) + return 1; + cur = cur->next; + } + return 0; +} + +static int less_than_vr_ur(rlc_entity_um_t *entity, int sn) +{ + return sn_compare_rx(entity, sn, entity->vr_ur) < 0; +} + +static int outside_of_reordering_window(rlc_entity_um_t *entity, int sn) +{ + return !sn_in_recv_window(entity, sn); +} + +static int less_than_vr_uh(rlc_entity_um_t *entity, int sn) +{ + return sn_compare_rx(entity, sn, entity->vr_uh) < 0; +} + +static void rlc_um_reassemble_pdu(rlc_entity_um_t *entity, + rlc_rx_pdu_segment_t *pdu) +{ + rlc_um_reassemble_t *r = &entity->reassemble; + + int fi; + int e; + int sn; + int data_pos; + int sdu_len; + int sdu_offset; + + sdu_offset = pdu->data_offset; + + rlc_pdu_decoder_init(&r->dec, pdu->data, pdu->size); + + if (entity->sn_field_length == 10) + rlc_pdu_decoder_get_bits(&r->dec, 3); + + fi = rlc_pdu_decoder_get_bits(&r->dec, 2); + e = rlc_pdu_decoder_get_bits(&r->dec, 1); + sn = rlc_pdu_decoder_get_bits(&r->dec, entity->sn_field_length); + + if (e) { + e = rlc_pdu_decoder_get_bits(&r->dec, 1); + sdu_len = rlc_pdu_decoder_get_bits(&r->dec, 11); + } else + sdu_len = pdu->size - sdu_offset; + + /* discard current SDU being reassembled if bad SN or bad FI */ + if (sn != (r->sn + 1) % entity->sn_modulus || + !(fi & 0x02)) { + if (r->sdu_pos) + LOG_D(RLC, "%s:%d:%s: warning: discard partially reassembled SDU\n", + __FILE__, __LINE__, __FUNCTION__); + r->sdu_pos = 0; + } + + /* if the head of the SDU is missing, still process the PDU + * but remember to discard the reassembled SDU later on (the + * head has not been received). + * The head is missing if sdu_pos == 0 and fi says the PDU does not + * start an SDU. + */ + if (r->sdu_pos == 0 && (fi & 0x02)) + r->sdu_head_missing = 1; + + r->sn = sn; + data_pos = pdu->data_offset; + + while (1) { + if (r->sdu_pos >= SDU_MAX) { + /* TODO: proper error handling (discard PDUs with current sn from + * reassembly queue? something else?) + */ + LOG_E(RLC, "%s:%d:%s: bad RLC PDU\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + r->sdu[r->sdu_pos] = pdu->data[data_pos]; + r->sdu_pos++; + data_pos++; + if (data_pos == sdu_offset + sdu_len) { + /* all bytes of SDU are consumed, check if SDU is fully there. + * It is if the data pointer is not at the end of the PDU segment + * or if 'fi' & 1 == 0 + */ + if (data_pos != pdu->size || (fi & 1) == 0) { + /* time to discard the SDU if we didn't receive the head */ + if (r->sdu_head_missing) { + LOG_D(RLC, "%s:%d:%s: warning: discard SDU, head not received\n", + __FILE__, __LINE__, __FUNCTION__); + r->sdu_head_missing = 0; + } else { + /* SDU is full - deliver to higher layer */ + entity->common.deliver_sdu(entity->common.deliver_sdu_data, + (rlc_entity_t *)entity, + r->sdu, r->sdu_pos); + } + r->sdu_pos = 0; + } + /* done with PDU? */ + if (data_pos == pdu->size) + break; + /* not at the end of PDU, process next SDU */ + sdu_offset += sdu_len; + if (e) { + e = rlc_pdu_decoder_get_bits(&r->dec, 1); + sdu_len = rlc_pdu_decoder_get_bits(&r->dec, 11); + } else + sdu_len = pdu->size - sdu_offset; + } + } +} + +static void rlc_um_reassemble(rlc_entity_um_t *entity, + int (*check_sn)(rlc_entity_um_t *entity, int sn)) +{ + rlc_rx_pdu_segment_t *cur; + + /* process all PDUs from head of rx list until all is processed or + * the SN is not valid anymore with respect to 'check_sn' + */ + while (entity->rx_list != NULL && check_sn(entity, entity->rx_list->sn)) { + cur = entity->rx_list; + rlc_um_reassemble_pdu(entity, cur); + entity->rx_size -= cur->size; + entity->rx_list = cur->next; + rlc_rx_free_pdu_segment(cur); + } +} + +static void rlc_um_reception_actions(rlc_entity_um_t *entity, + rlc_rx_pdu_segment_t *pdu_segment) +{ + if (!sn_in_recv_window(entity, pdu_segment->sn)) { + entity->vr_uh = (pdu_segment->sn + 1) % entity->sn_modulus; + rlc_um_reassemble(entity, outside_of_reordering_window); + if (!sn_in_recv_window(entity, entity->vr_ur)) + entity->vr_ur = (entity->vr_uh - entity->window_size + + entity->sn_modulus) % entity->sn_modulus; + } + + if (rlc_um_pdu_received(entity, entity->vr_ur)) { + do { + entity->vr_ur = (entity->vr_ur + 1) % entity->sn_modulus; + } while (rlc_um_pdu_received(entity, entity->vr_ur)); + rlc_um_reassemble(entity, less_than_vr_ur); + } + + if (entity->t_reordering_start) { + if (sn_compare_rx(entity, entity->vr_ux, entity->vr_ur) <= 0 || + (!sn_in_recv_window(entity, entity->vr_ux) && + entity->vr_ux != entity->vr_uh)) + entity->t_reordering_start = 0; + } + + if (entity->t_reordering_start == 0) { + if (sn_compare_rx(entity, entity->vr_uh, entity->vr_ur) > 0) { + entity->t_reordering_start = entity->t_current; + entity->vr_ux = entity->vr_uh; + } + } +} + +void rlc_entity_um_recv_pdu(rlc_entity_t *_entity, char *buffer, int size) +{ +#define R(d) do { if (rlc_pdu_decoder_in_error(&d)) goto err; } while (0) + rlc_entity_um_t *entity = (rlc_entity_um_t *)_entity; + rlc_pdu_decoder_t decoder; + rlc_pdu_decoder_t data_decoder; + + int e; + int sn; + + int data_e; + int data_li; + + int packet_count; + int data_size; + int data_start; + int indicated_data_size; + + rlc_rx_pdu_segment_t *pdu_segment; + + rlc_pdu_decoder_init(&decoder, buffer, size); + + if (entity->sn_field_length == 10) { + rlc_pdu_decoder_get_bits(&decoder, 3); R(decoder); /* R1 */ + } + + rlc_pdu_decoder_get_bits(&decoder, 2); R(decoder); /* FI */ + e = rlc_pdu_decoder_get_bits(&decoder, 1); R(decoder); + sn = rlc_pdu_decoder_get_bits(&decoder, entity->sn_field_length); R(decoder); + + /* dicard PDU if rx buffer is full */ + if (entity->rx_size + size > entity->rx_maxsize) { + LOG_D(RLC, "%s:%d:%s: warning: discard PDU, RX buffer full\n", + __FILE__, __LINE__, __FUNCTION__); + return; + } + + /* discard according to 36.322 5.1.2.2.2 */ + if ((sn_compare_rx(entity, entity->vr_ur, sn) < 0 && + sn_compare_rx(entity, sn, entity->vr_uh) < 0 && + rlc_um_pdu_received(entity, sn)) || + (sn_compare_rx(entity, entity->vr_uh - entity->window_size, sn) <= 0 && + sn_compare_rx(entity, sn, entity->vr_ur) < 0)) { + LOG_D(RLC, "%s:%d:%s: warning: discard PDU (sn %d vr(ur) %d vr(uh) %d)\n", + __FILE__, __LINE__, __FUNCTION__, + sn, entity->vr_ur, entity->vr_uh); + return; + } + + packet_count = 1; + + /* go to start of data */ + indicated_data_size = 0; + data_decoder = decoder; + data_e = e; + while (data_e) { + data_e = rlc_pdu_decoder_get_bits(&data_decoder, 1); R(data_decoder); + data_li = rlc_pdu_decoder_get_bits(&data_decoder, 11); R(data_decoder); + if (data_li == 0) { + LOG_D(RLC, "%s:%d:%s: warning: discard PDU, li == 0\n", + __FILE__, __LINE__, __FUNCTION__); + return; + } + indicated_data_size += data_li; + packet_count++; + } + rlc_pdu_decoder_align(&data_decoder); + + data_start = data_decoder.byte; + data_size = size - data_start; + + if (data_size <= 0) { + LOG_D(RLC, "%s:%d:%s: warning: discard PDU, wrong data size (sum of LI %d data size %d)\n", + __FILE__, __LINE__, __FUNCTION__, + indicated_data_size, data_size); + return; + } + if (indicated_data_size >= data_size) { + LOG_D(RLC, "%s:%d:%s: warning: discard PDU, bad LIs (sum of LI %d data size %d)\n", + __FILE__, __LINE__, __FUNCTION__, + indicated_data_size, data_size); + return; + } + + /* put in pdu reception list */ + entity->rx_size += size; + pdu_segment = rlc_rx_new_pdu_segment(sn, 0, size, 1, buffer, data_start); + entity->rx_list = rlc_rx_pdu_segment_list_add(sn_compare_rx, entity, + entity->rx_list, pdu_segment); + + /* do reception actions (36.322 5.1.2.2.3) */ + rlc_um_reception_actions(entity, pdu_segment); + + return; + +err: + LOG_D(RLC, "%s:%d:%s: error decoding PDU, discarding\n", __FILE__, __LINE__, __FUNCTION__); + +#undef R +} + +/*************************************************************************/ +/* TX functions */ +/*************************************************************************/ + +typedef struct { + int sdu_count; + int data_size; + int header_size; + int last_sdu_is_full; + int first_sdu_length; +} tx_pdu_size_t; + +static int header_size(int sn_field_length, int sdu_count) +{ + int bits = 8 + 8 * (sn_field_length == 10) + 12 * (sdu_count - 1); + /* padding if we have to */ + return (bits + 7) / 8; +} + +static tx_pdu_size_t tx_pdu_size(rlc_entity_um_t *entity, int maxsize) +{ + tx_pdu_size_t ret; + int sdu_count; + int sdu_size; + int pdu_data_size; + rlc_sdu_t *sdu; + + ret.sdu_count = 0; + ret.data_size = 0; + ret.header_size = 0; + ret.last_sdu_is_full = 1; + + /* TX PDU - let's make the biggest PDU we can with the SDUs we have */ + sdu_count = 0; + pdu_data_size = 0; + sdu = entity->tx_list; + while (sdu != NULL) { + int new_header_size = header_size(entity->sn_field_length, sdu_count+1); + /* if we cannot put new header + at least 1 byte of data then over */ + if (new_header_size + pdu_data_size >= maxsize) + break; + sdu_count++; + /* only include the bytes of this SDU not included in PDUs already */ + sdu_size = sdu->size - sdu->next_byte; + /* don't feed more than 'maxsize' bytes */ + if (new_header_size + pdu_data_size + sdu_size > maxsize) { + sdu_size = maxsize - new_header_size - pdu_data_size; + ret.last_sdu_is_full = 0; + } + if (sdu_count == 1) + ret.first_sdu_length = sdu_size; + pdu_data_size += sdu_size; + /* if we put more than 2^11-1 bytes then the LI field cannot be used, + * so this is the last SDU we can put + */ + if (sdu_size > 2047) + break; + sdu = sdu->next; + } + + if (sdu_count) { + ret.sdu_count = sdu_count; + ret.data_size = pdu_data_size; + ret.header_size = header_size(entity->sn_field_length, sdu_count); + } + + return ret; +} + +rlc_entity_buffer_status_t rlc_entity_um_buffer_status( + rlc_entity_t *_entity, int maxsize) +{ + rlc_entity_um_t *entity = (rlc_entity_um_t *)_entity; + rlc_entity_buffer_status_t ret; + tx_pdu_size_t tx_size; + + ret.status_size = 0; + + tx_size = tx_pdu_size(entity, maxsize); + ret.tx_size = tx_size.data_size + tx_size.header_size; + + ret.retx_size = 0; + + return ret; +} + +int rlc_entity_um_generate_pdu(rlc_entity_t *_entity, char *buffer, int size) +{ + rlc_entity_um_t *entity = (rlc_entity_um_t *)_entity; + tx_pdu_size_t pdu_size; + rlc_sdu_t *sdu; + int i; + int cursize; + int first_sdu_full; + int last_sdu_full; + rlc_pdu_encoder_t encoder; + int fi; + int e; + int li; + char *out; + int outpos; + int first_sdu_start_byte; + int sdu_start_byte; + + pdu_size = tx_pdu_size(entity, size); + if (pdu_size.sdu_count == 0) + return 0; + + sdu = entity->tx_list; + + first_sdu_start_byte = sdu->next_byte; + + /* reserve SDU bytes */ + cursize = 0; + for (i = 0; i < pdu_size.sdu_count; i++, sdu = sdu->next) { + int sdu_size = sdu->size - sdu->next_byte; + if (cursize + sdu_size > pdu_size.data_size) + sdu_size = pdu_size.data_size - cursize; + sdu->next_byte += sdu_size; + cursize += sdu_size; + } + + first_sdu_full = first_sdu_start_byte == 0; + last_sdu_full = pdu_size.last_sdu_is_full; + + /* generate header */ + rlc_pdu_encoder_init(&encoder, buffer, size); + + if (entity->sn_field_length == 10) + rlc_pdu_encoder_put_bits(&encoder, 0, 3); /* R1 */ + + fi = 0; + if (!first_sdu_full) + fi |= 0x02; + if (!last_sdu_full) + fi |= 0x01; + rlc_pdu_encoder_put_bits(&encoder, fi, 2); /* FI */ + + /* see the AM code to understand the logic for Es and LIs */ + if (pdu_size.sdu_count >= 2) + e = 1; + else + e = 0; + rlc_pdu_encoder_put_bits(&encoder, e, 1); /* E */ + + if (entity->sn_field_length == 10) + rlc_pdu_encoder_put_bits(&encoder, entity->vt_us, 10); /* SN */ + else + rlc_pdu_encoder_put_bits(&encoder, entity->vt_us, 5); /* SN */ + + /* put LIs */ + sdu = entity->tx_list; + /* first SDU */ + li = pdu_size.first_sdu_length; + /* put E+LI only if at least 2 SDUs */ + if (pdu_size.sdu_count >= 2) { + /* E is 1 if at least 3 SDUs */ + if (pdu_size.sdu_count >= 3) + e = 1; + else + e = 0; + rlc_pdu_encoder_put_bits(&encoder, e, 1); /* E */ + rlc_pdu_encoder_put_bits(&encoder, li, 11); /* LI */ + } + /* next SDUs, but not the last (no LI for the last) */ + sdu = sdu->next; + for (i = 2; i < pdu_size.sdu_count; i++, sdu = sdu->next) { + if (i != pdu_size.sdu_count - 1) + e = 1; + else + e = 0; + li = sdu->size; + rlc_pdu_encoder_put_bits(&encoder, e, 1); /* E */ + rlc_pdu_encoder_put_bits(&encoder, li, 11); /* LI */ + } + + rlc_pdu_encoder_align(&encoder); + + /* generate data */ + out = buffer + pdu_size.header_size; + sdu = entity->tx_list; + sdu_start_byte = first_sdu_start_byte; + outpos = 0; + for (i = 0; i < pdu_size.sdu_count; i++, sdu = sdu->next) { + li = sdu->size - sdu_start_byte; + if (outpos + li >= pdu_size.data_size) + li = pdu_size.data_size - outpos; + memcpy(out+outpos, sdu->data + sdu_start_byte, li); + outpos += li; + sdu_start_byte = 0; + } + + /* cleanup sdu list */ + while (entity->tx_list != NULL && + entity->tx_list->size == entity->tx_list->next_byte) { + rlc_sdu_t *c = entity->tx_list; + /* release SDU bytes */ + entity->tx_size -= c->size; + entity->tx_list = c->next; + rlc_free_sdu(c); + } + if (entity->tx_list == NULL) + entity->tx_end = NULL; + + /* update VT(US) */ + entity->vt_us = (entity->vt_us + 1) % entity->sn_modulus; + + return pdu_size.header_size + pdu_size.data_size; +} + +/*************************************************************************/ +/* SDU RX functions */ +/*************************************************************************/ + +void rlc_entity_um_recv_sdu(rlc_entity_t *_entity, char *buffer, int size, + int sdu_id) +{ + rlc_entity_um_t *entity = (rlc_entity_um_t *)_entity; + rlc_sdu_t *sdu; + + if (size > SDU_MAX) { + LOG_E(RLC, "%s:%d:%s: fatal: SDU size too big (%d bytes)\n", + __FILE__, __LINE__, __FUNCTION__, size); + exit(1); + } + + if (entity->tx_size + size > entity->tx_maxsize) { + LOG_D(RLC, "%s:%d:%s: warning: SDU rejected, SDU buffer full\n", + __FILE__, __LINE__, __FUNCTION__); + return; + } + + entity->tx_size += size; + + sdu = rlc_new_sdu(buffer, size, sdu_id); + rlc_sdu_list_add(&entity->tx_list, &entity->tx_end, sdu); +} + +/*************************************************************************/ +/* time/timers */ +/*************************************************************************/ + +static void check_t_reordering(rlc_entity_um_t *entity) +{ + int sn; + + /* is t_reordering running and if yes has it expired? */ + if (entity->t_reordering_start == 0 || + entity->t_current <= entity->t_reordering_start + entity->t_reordering) + return; + + /* stop timer */ + entity->t_reordering_start = 0; + + LOG_D(RLC, "%s:%d:%s: t_reordering expired\n", __FILE__, __LINE__, __FUNCTION__); + + /* update VR(UR) to first SN >= VR(UX) of PDU not received + */ + sn = entity->vr_ux; + while (rlc_um_pdu_received(entity, sn)) + sn = (sn + 1) % entity->sn_modulus; + entity->vr_ur = sn; + + rlc_um_reassemble(entity, less_than_vr_ur); + + if (sn_compare_rx(entity, entity->vr_uh, entity->vr_ur) > 0) { + entity->t_reordering_start = entity->t_current; + entity->vr_ux = entity->vr_uh; + } +} + +void rlc_entity_um_set_time(rlc_entity_t *_entity, uint64_t now) +{ + rlc_entity_um_t *entity = (rlc_entity_um_t *)_entity; + + entity->t_current = now; + + check_t_reordering(entity); +} + +/*************************************************************************/ +/* discard/re-establishment/delete */ +/*************************************************************************/ + +void rlc_entity_um_discard_sdu(rlc_entity_t *_entity, int sdu_id) +{ + /* implements 36.322 5.3 */ + rlc_entity_um_t *entity = (rlc_entity_um_t *)_entity; + rlc_sdu_t head; + rlc_sdu_t *cur; + rlc_sdu_t *prev; + + head.next = entity->tx_list; + cur = entity->tx_list; + prev = &head; + + while (cur != NULL && cur->upper_layer_id != sdu_id) { + prev = cur; + cur = cur->next; + } + + /* if sdu_id not found or some bytes have already been 'PDU-ized' + * then do nothing + */ + if (cur == NULL || cur->next_byte != 0) + return; + + /* remove SDU from tx_list */ + prev->next = cur->next; + entity->tx_list = head.next; + if (entity->tx_end == cur) { + if (prev != &head) + entity->tx_end = prev; + else + entity->tx_end = NULL; + } + + rlc_free_sdu(cur); +} + +static void clear_entity(rlc_entity_um_t *entity) +{ + rlc_rx_pdu_segment_t *cur_rx; + rlc_sdu_t *cur_tx; + + entity->vr_ur = 0; + entity->vr_ux = 0; + entity->vr_uh = 0; + + entity->vt_us = 0; + + entity->t_current = 0; + + entity->t_reordering_start = 0; + + cur_rx = entity->rx_list; + while (cur_rx != NULL) { + rlc_rx_pdu_segment_t *p = cur_rx; + cur_rx = cur_rx->next; + rlc_rx_free_pdu_segment(p); + } + entity->rx_list = NULL; + entity->rx_size = 0; + + memset(&entity->reassemble, 0, sizeof(rlc_um_reassemble_t)); + + cur_tx = entity->tx_list; + while (cur_tx != NULL) { + rlc_sdu_t *p = cur_tx; + cur_tx = cur_tx->next; + rlc_free_sdu(p); + } + entity->tx_list = NULL; + entity->tx_end = NULL; + entity->tx_size = 0; +} + +void rlc_entity_um_reestablishment(rlc_entity_t *_entity) +{ + rlc_entity_um_t *entity = (rlc_entity_um_t *)_entity; + + rlc_um_reassemble(entity, less_than_vr_uh); + + clear_entity(entity); +} + +void rlc_entity_um_delete(rlc_entity_t *_entity) +{ + rlc_entity_um_t *entity = (rlc_entity_um_t *)_entity; + clear_entity(entity); + free(entity); +} diff --git a/openair2/LAYER2/rlc_v2/rlc_entity_um.h b/openair2/LAYER2/rlc_v2/rlc_entity_um.h new file mode 100644 index 00000000000..02c5141a7a6 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/rlc_entity_um.h @@ -0,0 +1,90 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef _RLC_ENTITY_UM_H_ +#define _RLC_ENTITY_UM_H_ + +#include "rlc_entity.h" +#include "rlc_pdu.h" +#include "rlc_sdu.h" + +typedef struct { + char sdu[SDU_MAX]; /* sdu is reassembled here */ + int sdu_pos; /* next byte to put in sdu */ + + /* decoder of current PDU */ + rlc_pdu_decoder_t dec; + int sn; + + int sdu_head_missing; +} rlc_um_reassemble_t; + +typedef struct { + rlc_entity_t common; + + /* configuration */ + int t_reordering; + int sn_field_length; + + int sn_modulus; /* 1024 for sn_field_length == 10, 32 for 5 */ + int window_size; /* 512 for sn_field_length == 10, 16 for 5 */ + + /* runtime rx */ + int vr_ur; + int vr_ux; + int vr_uh; + + /* runtime tx */ + int vt_us; + + /* set to the latest know time by the user of the module. Unit: ms */ + uint64_t t_current; + + /* timers (stores the TTI of activation, 0 means not active) */ + uint64_t t_reordering_start; + + /* rx management */ + rlc_rx_pdu_segment_t *rx_list; + int rx_size; + int rx_maxsize; + + /* reassembly management */ + rlc_um_reassemble_t reassemble; + + /* tx management */ + rlc_sdu_t *tx_list; + rlc_sdu_t *tx_end; + int tx_size; + int tx_maxsize; +} rlc_entity_um_t; + +void rlc_entity_um_recv_sdu(rlc_entity_t *_entity, char *buffer, int size, + int sdu_id); +void rlc_entity_um_recv_pdu(rlc_entity_t *entity, char *buffer, int size); +rlc_entity_buffer_status_t rlc_entity_um_buffer_status( + rlc_entity_t *entity, int maxsize); +int rlc_entity_um_generate_pdu(rlc_entity_t *_entity, char *buffer, int size); +void rlc_entity_um_set_time(rlc_entity_t *entity, uint64_t now); +void rlc_entity_um_discard_sdu(rlc_entity_t *entity, int sdu_id); +void rlc_entity_um_reestablishment(rlc_entity_t *entity); +void rlc_entity_um_delete(rlc_entity_t *entity); + +#endif /* _RLC_ENTITY_UM_H_ */ diff --git a/openair2/LAYER2/rlc_v2/rlc_oai_api.c b/openair2/LAYER2/rlc_v2/rlc_oai_api.c new file mode 100644 index 00000000000..1be9c90a31a --- /dev/null +++ b/openair2/LAYER2/rlc_v2/rlc_oai_api.c @@ -0,0 +1,821 @@ +/* + * 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 + */ + +/* from openair */ +#include "rlc.h" +#include "pdcp.h" + +/* from new rlc module */ +#include "asn1_utils.h" +#include "rlc_ue_manager.h" +#include "rlc_entity.h" + +#include <stdint.h> + +static rlc_ue_manager_t *rlc_ue_manager; + +/* TODO: handle time a bit more properly */ +static uint64_t rlc_current_time; +static int rlc_current_time_last_frame; +static int rlc_current_time_last_subframe; + +void mac_rlc_data_ind ( + const module_id_t module_idP, + const rnti_t rntiP, + const eNB_index_t eNB_index, + const frame_t frameP, + const eNB_flag_t enb_flagP, + const MBMS_flag_t MBMS_flagP, + const logical_chan_id_t channel_idP, + char *buffer_pP, + const tb_size_t tb_sizeP, + num_tb_t num_tbP, + crc_t *crcs_pP) +{ + rlc_ue_t *ue; + rlc_entity_t *rb; + + if (module_idP != 0 || eNB_index != 0 || enb_flagP != 1 || MBMS_flagP != 0) { + LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + if (enb_flagP) + T(T_ENB_RLC_MAC_UL, T_INT(module_idP), T_INT(rntiP), + T_INT(channel_idP), T_INT(tb_sizeP)); + + rlc_manager_lock(rlc_ue_manager); + ue = rlc_manager_get_ue(rlc_ue_manager, rntiP); + + switch (channel_idP) { + case 1 ... 2: rb = ue->srb[channel_idP - 1]; break; + case 3 ... 7: rb = ue->drb[channel_idP - 3]; break; + default: rb = NULL; break; + } + + if (rb != NULL) { + rb->set_time(rb, rlc_current_time); + rb->recv_pdu(rb, buffer_pP, tb_sizeP); + } else { + LOG_E(RLC, "%s:%d:%s: fatal: no RB found (channel ID %d)\n", + __FILE__, __LINE__, __FUNCTION__, channel_idP); + exit(1); + } + + rlc_manager_unlock(rlc_ue_manager); +} + +tbs_size_t mac_rlc_data_req( + const module_id_t module_idP, + const rnti_t rntiP, + const eNB_index_t eNB_index, + const frame_t frameP, + const eNB_flag_t enb_flagP, + const MBMS_flag_t MBMS_flagP, + const logical_chan_id_t channel_idP, + const tb_size_t tb_sizeP, + char *buffer_pP +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + ,const uint32_t sourceL2Id + ,const uint32_t destinationL2Id +#endif + ) +{ + int ret; + rlc_ue_t *ue; + rlc_entity_t *rb; + + rlc_manager_lock(rlc_ue_manager); + ue = rlc_manager_get_ue(rlc_ue_manager, rntiP); + + switch (channel_idP) { + case 1 ... 2: rb = ue->srb[channel_idP - 1]; break; + case 3 ... 7: rb = ue->drb[channel_idP - 3]; break; + default: rb = NULL; break; + } + + if (rb != NULL) { + rb->set_time(rb, rlc_current_time); + ret = rb->generate_pdu(rb, buffer_pP, ue->saved_status_ind_tb_size[channel_idP - 1]); + } else { + LOG_E(RLC, "%s:%d:%s: fatal: data req for unknown RB\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + ret = 0; + } + + rlc_manager_unlock(rlc_ue_manager); + + if (enb_flagP) + T(T_ENB_RLC_MAC_DL, T_INT(module_idP), T_INT(rntiP), + T_INT(channel_idP), T_INT(ret)); + + return ret; +} + +mac_rlc_status_resp_t mac_rlc_status_ind( + const module_id_t module_idP, + const rnti_t rntiP, + const eNB_index_t eNB_index, + const frame_t frameP, + const sub_frame_t subframeP, + const eNB_flag_t enb_flagP, + const MBMS_flag_t MBMS_flagP, + const logical_chan_id_t channel_idP, + const tb_size_t tb_sizeP +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + ,const uint32_t sourceL2Id + ,const uint32_t destinationL2Id +#endif + ) +{ + rlc_ue_t *ue; + mac_rlc_status_resp_t ret; + rlc_entity_t *rb; + + /* TODO: handle time a bit more properly */ + if (rlc_current_time_last_frame != frameP || + rlc_current_time_last_subframe != subframeP) { + rlc_current_time++; + rlc_current_time_last_frame = frameP; + rlc_current_time_last_subframe = subframeP; + } + + rlc_manager_lock(rlc_ue_manager); + ue = rlc_manager_get_ue(rlc_ue_manager, rntiP); + + switch (channel_idP) { + case 1 ... 2: rb = ue->srb[channel_idP - 1]; break; + case 3 ... 7: rb = ue->drb[channel_idP - 3]; break; + default: rb = NULL; break; + } + + if (rb != NULL) { + rlc_entity_buffer_status_t buf_stat; + rb->set_time(rb, rlc_current_time); + buf_stat = rb->buffer_status(rb, tb_sizeP ? tb_sizeP : 1000000); + if (buf_stat.status_size) + ret.bytes_in_buffer = buf_stat.status_size; + else if (buf_stat.retx_size) + ret.bytes_in_buffer = buf_stat.retx_size; + else + ret.bytes_in_buffer = buf_stat.tx_size; + ue->saved_status_ind_tb_size[channel_idP - 1] = tb_sizeP; + } else { + ret.bytes_in_buffer = 0; + } + + rlc_manager_unlock(rlc_ue_manager); + + ret.pdus_in_buffer = 0; + /* TODO: creation time may be important (unit: frame, as it seems) */ + ret.head_sdu_creation_time = 0; + ret.head_sdu_remaining_size_to_send = 0; + ret.head_sdu_is_segmented = 0; + return ret; +} + +int oai_emulation; + +rlc_op_status_t rlc_data_req (const protocol_ctxt_t *const ctxt_pP, + const srb_flag_t srb_flagP, + const MBMS_flag_t MBMS_flagP, + const rb_id_t rb_idP, + const mui_t muiP, + confirm_t confirmP, + sdu_size_t sdu_sizeP, + mem_block_t *sdu_pP +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + ,const uint32_t *const sourceL2Id + ,const uint32_t *const destinationL2Id +#endif + ) +{ + int rnti = ctxt_pP->rnti; + rlc_ue_t *ue; + rlc_entity_t *rb; + + LOG_D(RLC, "%s rnti %d srb_flag %d rb_id %d mui %d confirm %d sdu_size %d MBMS_flag %d\n", + __FUNCTION__, rnti, srb_flagP, rb_idP, muiP, confirmP, sdu_sizeP, + MBMS_flagP); + + if (ctxt_pP->enb_flag) + T(T_ENB_RLC_DL, T_INT(ctxt_pP->module_id), + T_INT(ctxt_pP->rnti), T_INT(rb_idP), T_INT(sdu_sizeP)); + + rlc_manager_lock(rlc_ue_manager); + ue = rlc_manager_get_ue(rlc_ue_manager, rnti); + + rb = NULL; + + if (srb_flagP) { + if (rb_idP >= 1 && rb_idP <= 2) + rb = ue->srb[rb_idP - 1]; + } else { + if (rb_idP >= 1 && rb_idP <= 5) + rb = ue->drb[rb_idP - 1]; + } + + if (rb != NULL) { + rb->set_time(rb, rlc_current_time); + rb->recv_sdu(rb, (char *)sdu_pP->data, sdu_sizeP, muiP); + } else { + LOG_E(RLC, "%s:%d:%s: fatal: SDU sent to unknown RB\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + rlc_manager_unlock(rlc_ue_manager); + + free_mem_block(sdu_pP, __func__); + + return RLC_OP_STATUS_OK; +} + +int rlc_module_init(void) +{ + static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; + static int inited = 0; + + if (pthread_mutex_lock(&lock)) abort(); + + if (inited) { + LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + inited = 1; + + rlc_ue_manager = new_rlc_ue_manager(); + + if (pthread_mutex_unlock(&lock)) abort(); + + return 0; +} + +void rlc_util_print_hex_octets(comp_name_t componentP, unsigned char *dataP, const signed long sizeP) +{ +} + +static void deliver_sdu(void *_ue, rlc_entity_t *entity, char *buf, int size) +{ + rlc_ue_t *ue = _ue; + int is_srb; + int rb_id; + protocol_ctxt_t ctx; + mem_block_t *memblock; + int i; + + /* is it SRB? */ + for (i = 0; i < 2; i++) { + if (entity == ue->srb[i]) { + is_srb = 1; + rb_id = i+1; + goto rb_found; + } + } + + /* maybe DRB? */ + for (i = 0; i < 5; i++) { + if (entity == ue->drb[i]) { + is_srb = 0; + rb_id = i+1; + goto rb_found; + } + } + + LOG_E(RLC, "%s:%d:%s: fatal, no RB found for ue %d\n", + __FILE__, __LINE__, __FUNCTION__, ue->rnti); + exit(1); + +rb_found: + LOG_D(RLC, "%s:%d:%s: delivering SDU (rnti %d is_srb %d rb_id %d) size %d", + __FILE__, __LINE__, __FUNCTION__, ue->rnti, is_srb, rb_id, size); + + memblock = get_free_mem_block(size, __func__); + if (memblock == NULL) { + LOG_E(RLC, "%s:%d:%s: ERROR: get_free_mem_block failed\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + memcpy(memblock->data, buf, size); + + /* unused fields? */ + ctx.instance = 0; + ctx.frame = 0; + ctx.subframe = 0; + ctx.eNB_index = 0; + ctx.configured = 1; + ctx.brOption = 0; + + /* used fields? */ + ctx.module_id = 0; + ctx.rnti = ue->rnti; + ctx.enb_flag = 1; + + T(T_ENB_RLC_UL, + T_INT(0 /*ctxt_pP->module_id*/), + T_INT(ue->rnti), T_INT(rb_id), T_INT(size)); + + if (!pdcp_data_ind(&ctx, is_srb, 0, rb_id, size, memblock)) { + LOG_E(RLC, "%s:%d:%s: ERROR: pdcp_data_ind failed\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } +} + +static void successful_delivery(void *_ue, rlc_entity_t *entity, int sdu_id) +{ + rlc_ue_t *ue = _ue; + int i; + int is_srb; + int rb_id; + MessageDef *msg; + + /* is it SRB? */ + for (i = 0; i < 2; i++) { + if (entity == ue->srb[i]) { + is_srb = 1; + rb_id = i+1; + goto rb_found; + } + } + + /* maybe DRB? */ + for (i = 0; i < 5; i++) { + if (entity == ue->drb[i]) { + is_srb = 0; + rb_id = i+1; + goto rb_found; + } + } + + LOG_E(RLC, "%s:%d:%s: fatal, no RB found for ue %d\n", + __FILE__, __LINE__, __FUNCTION__, ue->rnti); + exit(1); + +rb_found: + LOG_D(RLC, "sdu %d was successfully delivered on %s %d\n", + sdu_id, + is_srb ? "SRB" : "DRB", + rb_id); + + /* TODO: do something for DRBs? */ + if (is_srb == 0) + return; + + msg = itti_alloc_new_message(TASK_RLC_ENB, RLC_SDU_INDICATION); + RLC_SDU_INDICATION(msg).rnti = ue->rnti; + RLC_SDU_INDICATION(msg).is_successful = 1; + RLC_SDU_INDICATION(msg).srb_id = rb_id; + RLC_SDU_INDICATION(msg).message_id = sdu_id; + /* TODO: accept more than 1 instance? here we send to instance id 0 */ + itti_send_msg_to_task(TASK_RRC_ENB, 0, msg); +} + +static void max_retx_reached(void *_ue, rlc_entity_t *entity) +{ + rlc_ue_t *ue = _ue; + int i; + int is_srb; + int rb_id; + MessageDef *msg; + + /* is it SRB? */ + for (i = 0; i < 2; i++) { + if (entity == ue->srb[i]) { + is_srb = 1; + rb_id = i+1; + goto rb_found; + } + } + + /* maybe DRB? */ + for (i = 0; i < 5; i++) { + if (entity == ue->drb[i]) { + is_srb = 0; + rb_id = i+1; + goto rb_found; + } + } + + LOG_E(RLC, "%s:%d:%s: fatal, no RB found for ue %d\n", + __FILE__, __LINE__, __FUNCTION__, ue->rnti); + exit(1); + +rb_found: + LOG_D(RLC, "max RETX reached on %s %d\n", + is_srb ? "SRB" : "DRB", + rb_id); + + /* TODO: do something for DRBs? */ + if (is_srb == 0) + return; + + msg = itti_alloc_new_message(TASK_RLC_ENB, RLC_SDU_INDICATION); + RLC_SDU_INDICATION(msg).rnti = ue->rnti; + RLC_SDU_INDICATION(msg).is_successful = 0; + RLC_SDU_INDICATION(msg).srb_id = rb_id; + RLC_SDU_INDICATION(msg).message_id = -1; + /* TODO: accept more than 1 instance? here we send to instance id 0 */ + itti_send_msg_to_task(TASK_RRC_ENB, 0, msg); +} + +static void add_srb(int rnti, struct LTE_SRB_ToAddMod *s) +{ + rlc_entity_t *rlc_am; + rlc_ue_t *ue; + + struct LTE_SRB_ToAddMod__rlc_Config *r = s->rlc_Config; + struct LTE_SRB_ToAddMod__logicalChannelConfig *l = s->logicalChannelConfig; + int srb_id = s->srb_Identity; + int logical_channel_group; + + int t_reordering; + int t_status_prohibit; + int t_poll_retransmit; + int poll_pdu; + int poll_byte; + int max_retx_threshold; + + if (srb_id != 1 && srb_id != 2) { + LOG_E(RLC, "%s:%d:%s: fatal, bad srb id %d\n", + __FILE__, __LINE__, __FUNCTION__, srb_id); + exit(1); + } + + switch (l->present) { + case LTE_SRB_ToAddMod__logicalChannelConfig_PR_explicitValue: + logical_channel_group = *l->choice.explicitValue.ul_SpecificParameters->logicalChannelGroup; + break; + case LTE_SRB_ToAddMod__logicalChannelConfig_PR_defaultValue: + /* default value from 36.331 9.2.1 */ + logical_channel_group = 0; + break; + default: + LOG_E(RLC, "%s:%d:%s: fatal error\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + /* TODO: accept other values? */ + if (logical_channel_group != 0) { + LOG_E(RLC, "%s:%d:%s: fatal error\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + switch (r->present) { + case LTE_SRB_ToAddMod__rlc_Config_PR_explicitValue: { + struct LTE_RLC_Config__am *am; + if (r->choice.explicitValue.present != LTE_RLC_Config_PR_am) { + LOG_E(RLC, "%s:%d:%s: fatal error, must be RLC AM\n", + __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + am = &r->choice.explicitValue.choice.am; + t_reordering = decode_t_reordering(am->dl_AM_RLC.t_Reordering); + t_status_prohibit = decode_t_status_prohibit(am->dl_AM_RLC.t_StatusProhibit); + t_poll_retransmit = decode_t_poll_retransmit(am->ul_AM_RLC.t_PollRetransmit); + poll_pdu = decode_poll_pdu(am->ul_AM_RLC.pollPDU); + poll_byte = decode_poll_byte(am->ul_AM_RLC.pollByte); + max_retx_threshold = decode_max_retx_threshold(am->ul_AM_RLC.maxRetxThreshold); + break; + } + case LTE_SRB_ToAddMod__rlc_Config_PR_defaultValue: + /* default values from 36.331 9.2.1 */ + t_reordering = 35; + t_status_prohibit = 0; + t_poll_retransmit = 45; + poll_pdu = -1; + poll_byte = -1; + max_retx_threshold = 4; + break; + default: + LOG_E(RLC, "%s:%d:%s: fatal error\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + rlc_manager_lock(rlc_ue_manager); + ue = rlc_manager_get_ue(rlc_ue_manager, rnti); + if (ue->srb[srb_id-1] != NULL) { + LOG_D(RLC, "%s:%d:%s: warning SRB %d already exist for ue %d, do nothing\n", + __FILE__, __LINE__, __FUNCTION__, srb_id, rnti); + } else { + rlc_am = new_rlc_entity_am(100000, + 100000, + deliver_sdu, ue, + successful_delivery, ue, + max_retx_reached, ue, + t_reordering, t_status_prohibit, + t_poll_retransmit, + poll_pdu, poll_byte, max_retx_threshold); + rlc_ue_add_srb_rlc_entity(ue, srb_id, rlc_am); + + LOG_D(RLC, "%s:%d:%s: added srb %d to ue %d\n", + __FILE__, __LINE__, __FUNCTION__, srb_id, rnti); + } + rlc_manager_unlock(rlc_ue_manager); +} + +static void add_drb_am(int rnti, struct LTE_DRB_ToAddMod *s) +{ + rlc_entity_t *rlc_am; + rlc_ue_t *ue; + + struct LTE_RLC_Config *r = s->rlc_Config; + struct LTE_LogicalChannelConfig *l = s->logicalChannelConfig; + int drb_id = s->drb_Identity; + int channel_id = *s->logicalChannelIdentity; + int logical_channel_group; + + int t_reordering; + int t_status_prohibit; + int t_poll_retransmit; + int poll_pdu; + int poll_byte; + int max_retx_threshold; + + if (!(drb_id >= 1 && drb_id <= 5)) { + LOG_E(RLC, "%s:%d:%s: fatal, bad srb id %d\n", + __FILE__, __LINE__, __FUNCTION__, drb_id); + exit(1); + } + + if (channel_id != drb_id + 2) { + LOG_E(RLC, "%s:%d:%s: todo, remove this limitation\n", + __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + logical_channel_group = *l->ul_SpecificParameters->logicalChannelGroup; + + /* TODO: accept other values? */ + if (logical_channel_group != 1) { + LOG_E(RLC, "%s:%d:%s: fatal error\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + switch (r->present) { + case LTE_RLC_Config_PR_am: { + struct LTE_RLC_Config__am *am; + am = &r->choice.am; + t_reordering = decode_t_reordering(am->dl_AM_RLC.t_Reordering); + t_status_prohibit = decode_t_status_prohibit(am->dl_AM_RLC.t_StatusProhibit); + t_poll_retransmit = decode_t_poll_retransmit(am->ul_AM_RLC.t_PollRetransmit); + poll_pdu = decode_poll_pdu(am->ul_AM_RLC.pollPDU); + poll_byte = decode_poll_byte(am->ul_AM_RLC.pollByte); + max_retx_threshold = decode_max_retx_threshold(am->ul_AM_RLC.maxRetxThreshold); + break; + } + default: + LOG_E(RLC, "%s:%d:%s: fatal error\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + rlc_manager_lock(rlc_ue_manager); + ue = rlc_manager_get_ue(rlc_ue_manager, rnti); + if (ue->drb[drb_id-1] != NULL) { + LOG_D(RLC, "%s:%d:%s: warning DRB %d already exist for ue %d, do nothing\n", + __FILE__, __LINE__, __FUNCTION__, drb_id, rnti); + } else { + rlc_am = new_rlc_entity_am(1000000, + 1000000, + deliver_sdu, ue, + successful_delivery, ue, + max_retx_reached, ue, + t_reordering, t_status_prohibit, + t_poll_retransmit, + poll_pdu, poll_byte, max_retx_threshold); + rlc_ue_add_drb_rlc_entity(ue, drb_id, rlc_am); + + LOG_D(RLC, "%s:%d:%s: added drb %d to ue %d\n", + __FILE__, __LINE__, __FUNCTION__, drb_id, rnti); + } + rlc_manager_unlock(rlc_ue_manager); +} + +static void add_drb_um(int rnti, struct LTE_DRB_ToAddMod *s) +{ + rlc_entity_t *rlc_um; + rlc_ue_t *ue; + + struct LTE_RLC_Config *r = s->rlc_Config; + struct LTE_LogicalChannelConfig *l = s->logicalChannelConfig; + int drb_id = s->drb_Identity; + int channel_id = *s->logicalChannelIdentity; + int logical_channel_group; + + int t_reordering; + int sn_field_length; + + if (!(drb_id >= 1 && drb_id <= 5)) { + LOG_E(RLC, "%s:%d:%s: fatal, bad srb id %d\n", + __FILE__, __LINE__, __FUNCTION__, drb_id); + exit(1); + } + + if (channel_id != drb_id + 2) { + LOG_E(RLC, "%s:%d:%s: todo, remove this limitation\n", + __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + logical_channel_group = *l->ul_SpecificParameters->logicalChannelGroup; + + /* TODO: accept other values? */ + if (logical_channel_group != 1) { + LOG_E(RLC, "%s:%d:%s: fatal error\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + switch (r->present) { + case LTE_RLC_Config_PR_um_Bi_Directional: { + struct LTE_RLC_Config__um_Bi_Directional *um; + um = &r->choice.um_Bi_Directional; + t_reordering = decode_t_reordering(um->dl_UM_RLC.t_Reordering); + if (um->dl_UM_RLC.sn_FieldLength != um->ul_UM_RLC.sn_FieldLength) { + LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + sn_field_length = decode_sn_field_length(um->dl_UM_RLC.sn_FieldLength); + break; + } + default: + LOG_E(RLC, "%s:%d:%s: fatal error\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + rlc_manager_lock(rlc_ue_manager); + ue = rlc_manager_get_ue(rlc_ue_manager, rnti); + if (ue->drb[drb_id-1] != NULL) { + LOG_D(RLC, "%s:%d:%s: warning DRB %d already exist for ue %d, do nothing\n", + __FILE__, __LINE__, __FUNCTION__, drb_id, rnti); + } else { + rlc_um = new_rlc_entity_um(1000000, + 1000000, + deliver_sdu, ue, + t_reordering, + sn_field_length); + rlc_ue_add_drb_rlc_entity(ue, drb_id, rlc_um); + + LOG_D(RLC, "%s:%d:%s: added drb %d to ue %d\n", + __FILE__, __LINE__, __FUNCTION__, drb_id, rnti); + } + rlc_manager_unlock(rlc_ue_manager); +} + +static void add_drb(int rnti, struct LTE_DRB_ToAddMod *s) +{ + switch (s->rlc_Config->present) { + case LTE_RLC_Config_PR_am: + add_drb_am(rnti, s); + break; + case LTE_RLC_Config_PR_um_Bi_Directional: + add_drb_um(rnti, s); + break; + default: + LOG_E(RLC, "%s:%d:%s: fatal: unhandled DRB type\n", + __FILE__, __LINE__, __FUNCTION__); + exit(1); + } +} + +rlc_op_status_t rrc_rlc_config_asn1_req (const protocol_ctxt_t * const ctxt_pP, + const LTE_SRB_ToAddModList_t * const srb2add_listP, + const LTE_DRB_ToAddModList_t * const drb2add_listP, + const LTE_DRB_ToReleaseList_t * const drb2release_listP +#if (LTE_RRC_VERSION >= MAKE_VERSION(9, 0, 0)) + ,const LTE_PMCH_InfoList_r9_t * const pmch_InfoList_r9_pP + ,const uint32_t sourceL2Id + ,const uint32_t destinationL2Id +#endif + ) +{ + int rnti = ctxt_pP->rnti; + int i; + + if (ctxt_pP->enb_flag != 1 || ctxt_pP->module_id != 0 /*|| + ctxt_pP->instance != 0 || ctxt_pP->eNB_index != 0 || + ctxt_pP->configured != 1 || ctxt_pP->brOption != 0 */) { + LOG_E(RLC, "%s: ctxt_pP not handled (%d %d %d %d %d %d)\n", __FUNCTION__, + ctxt_pP->enb_flag , ctxt_pP->module_id, ctxt_pP->instance, + ctxt_pP->eNB_index, ctxt_pP->configured, ctxt_pP->brOption); + exit(1); + } + + if (pmch_InfoList_r9_pP != NULL) { + LOG_E(RLC, "%s: pmch_InfoList_r9_pP not handled\n", __FUNCTION__); + exit(1); + } + + if (drb2release_listP != NULL) { + LOG_E(RLC, "%s:%d:%s: TODO\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + if (srb2add_listP != NULL) { + for (i = 0; i < srb2add_listP->list.count; i++) { + add_srb(rnti, srb2add_listP->list.array[i]); + } + } + + if (drb2add_listP != NULL) { + for (i = 0; i < drb2add_listP->list.count; i++) { + add_drb(rnti, drb2add_listP->list.array[i]); + } + } + + return RLC_OP_STATUS_OK; +} + +rlc_op_status_t rrc_rlc_config_req ( + const protocol_ctxt_t* const ctxt_pP, + const srb_flag_t srb_flagP, + const MBMS_flag_t mbms_flagP, + const config_action_t actionP, + const rb_id_t rb_idP, + const rlc_info_t rlc_infoP) +{ + rlc_ue_t *ue; + int i; + + if (mbms_flagP) { + LOG_E(RLC, "%s:%d:%s: todo (mbms not supported)\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + if (!ctxt_pP->enb_flag) { + LOG_E(RLC, "%s:%d:%s: todo (only eNB supported, not UE)\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + if (actionP != CONFIG_ACTION_REMOVE) { + LOG_E(RLC, "%s:%d:%s: todo (only CONFIG_ACTION_REMOVE supported)\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + if (ctxt_pP->module_id) { + LOG_E(RLC, "%s:%d:%s: todo (only module_id 0 supported)\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + if ((srb_flagP && !(rb_idP >= 1 && rb_idP <= 2)) || + (!srb_flagP && !(rb_idP >= 1 && rb_idP <= 5))) { + LOG_E(RLC, "%s:%d:%s: bad rb_id (%d) (is_srb %d)\n", __FILE__, __LINE__, __FUNCTION__, rb_idP, srb_flagP); + exit(1); + } + rlc_manager_lock(rlc_ue_manager); + LOG_D(RLC, "%s:%d:%s: remove rb %d (is_srb %d) for UE %d\n", __FILE__, __LINE__, __FUNCTION__, rb_idP, srb_flagP, ctxt_pP->rnti); + ue = rlc_manager_get_ue(rlc_ue_manager, ctxt_pP->rnti); + if (srb_flagP) { + if (ue->srb[rb_idP-1] != NULL) { + ue->srb[rb_idP-1]->delete(ue->srb[rb_idP-1]); + ue->srb[rb_idP-1] = NULL; + } else + LOG_W(RLC, "removing non allocated SRB %d, do nothing\n", rb_idP); + } else { + if (ue->drb[rb_idP-1] != NULL) { + ue->drb[rb_idP-1]->delete(ue->drb[rb_idP-1]); + ue->drb[rb_idP-1] = NULL; + } else + LOG_W(RLC, "removing non allocated DRB %d, do nothing\n", rb_idP); + } + /* remove UE if it has no more RB configured */ + for (i = 0; i < 2; i++) + if (ue->srb[i] != NULL) + break; + if (i == 2) { + for (i = 0; i < 5; i++) + if (ue->drb[i] != NULL) + break; + if (i == 5) + rlc_manager_remove_ue(rlc_ue_manager, ctxt_pP->rnti); + } + rlc_manager_unlock(rlc_ue_manager); + return RLC_OP_STATUS_OK; +} + +void rrc_rlc_register_rrc (rrc_data_ind_cb_t rrc_data_indP, rrc_data_conf_cb_t rrc_data_confP) +{ + /* nothing to do */ +} + +rlc_op_status_t rrc_rlc_remove_ue (const protocol_ctxt_t* const x) +{ + LOG_D(RLC, "%s:%d:%s: remove UE %d\n", __FILE__, __LINE__, __FUNCTION__, x->rnti); + rlc_manager_lock(rlc_ue_manager); + rlc_manager_remove_ue(rlc_ue_manager, x->rnti); + rlc_manager_unlock(rlc_ue_manager); + + return RLC_OP_STATUS_OK; +} + diff --git a/openair2/LAYER2/rlc_v2/rlc_pdu.c b/openair2/LAYER2/rlc_v2/rlc_pdu.c new file mode 100644 index 00000000000..c55e2d9c3c5 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/rlc_pdu.c @@ -0,0 +1,266 @@ +/* + * 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 "rlc_pdu.h" + +#include <stdlib.h> +#include <string.h> + +#include "LOG/log.h" + +/**************************************************************************/ +/* RX PDU segment and segment list */ +/**************************************************************************/ + +rlc_rx_pdu_segment_t *rlc_rx_new_pdu_segment(int sn, int so, int size, + int is_last, char *data, int data_offset) +{ + rlc_rx_pdu_segment_t *ret = malloc(sizeof(rlc_rx_pdu_segment_t)); + if (ret == NULL) { + LOG_E(RLC, "%s:%d:%s: out of memory\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + ret->sn = sn; + ret->so = so; + ret->size = size; + ret->is_last = is_last; + ret->next = NULL; + + ret->data = malloc(size); + if (ret->data == NULL) { + LOG_E(RLC, "%s:%d:%s: out of memory\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + memcpy(ret->data, data, size); + + ret->data_offset = data_offset; + + return ret; +} + +void rlc_rx_free_pdu_segment(rlc_rx_pdu_segment_t *pdu_segment) +{ + free(pdu_segment->data); + free(pdu_segment); +} + +rlc_rx_pdu_segment_t *rlc_rx_pdu_segment_list_add( + int (*sn_compare)(void *, int, int), void *sn_compare_data, + rlc_rx_pdu_segment_t *list, rlc_rx_pdu_segment_t *pdu_segment) +{ + rlc_rx_pdu_segment_t head; + rlc_rx_pdu_segment_t *cur; + rlc_rx_pdu_segment_t *prev; + + head.next = list; + cur = list; + prev = &head; + + /* order is by 'sn', if 'sn' is the same then order is by 'so' */ + while (cur != NULL) { + /* check if 'pdu_segment' is before 'cur' in the list */ + if (sn_compare(sn_compare_data, cur->sn, pdu_segment->sn) > 0 || + (cur->sn == pdu_segment->sn && cur->so > pdu_segment->so)) { + break; + } + prev = cur; + cur = cur->next; + } + prev->next = pdu_segment; + pdu_segment->next = cur; + return head.next; +} + +/**************************************************************************/ +/* TX PDU management */ +/**************************************************************************/ + +rlc_tx_pdu_segment_t *rlc_tx_new_pdu(void) +{ + rlc_tx_pdu_segment_t *ret = calloc(1, sizeof(rlc_tx_pdu_segment_t)); + if (ret == NULL) { + LOG_E(RLC, "%s:%d:%s: out of memory\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + ret->retx_count = -1; + return ret; +} + +void rlc_tx_free_pdu(rlc_tx_pdu_segment_t *pdu) +{ + free(pdu); +} + +rlc_tx_pdu_segment_t *rlc_tx_pdu_list_append(rlc_tx_pdu_segment_t *list, + rlc_tx_pdu_segment_t *pdu) +{ + rlc_tx_pdu_segment_t head; + rlc_tx_pdu_segment_t *cur; + + head.next = list; + + cur = &head; + while (cur->next != NULL) { + cur = cur->next; + } + cur->next = pdu; + + return head.next; +} + +rlc_tx_pdu_segment_t *rlc_tx_pdu_list_add( + int (*sn_compare)(void *, int, int), void *sn_compare_data, + rlc_tx_pdu_segment_t *list, rlc_tx_pdu_segment_t *pdu_segment) +{ + rlc_tx_pdu_segment_t head; + rlc_tx_pdu_segment_t *cur; + rlc_tx_pdu_segment_t *prev; + + head.next = list; + cur = list; + prev = &head; + + /* order is by 'sn', if 'sn' is the same then order is by 'so' */ + while (cur != NULL) { + /* check if 'pdu_segment' is before 'cur' in the list */ + if (sn_compare(sn_compare_data, cur->sn, pdu_segment->sn) > 0 || + (cur->sn == pdu_segment->sn && cur->so > pdu_segment->so)) { + break; + } + prev = cur; + cur = cur->next; + } + prev->next = pdu_segment; + pdu_segment->next = cur; + return head.next; +} + +/**************************************************************************/ +/* PDU decoder */ +/**************************************************************************/ + +void rlc_pdu_decoder_init(rlc_pdu_decoder_t *decoder, char *buffer, int size) +{ + decoder->error = 0; + decoder->byte = 0; + decoder->bit = 0; + decoder->buffer = buffer; + decoder->size = size; +} + +static int get_bit(rlc_pdu_decoder_t *decoder) +{ + int ret; + + if (decoder->byte >= decoder->size) { + decoder->error = 1; + return 0; + } + + ret = (decoder->buffer[decoder->byte] >> (7 - decoder->bit)) & 1; + + decoder->bit++; + if (decoder->bit == 8) { + decoder->bit = 0; + decoder->byte++; + } + + return ret; +} + +int rlc_pdu_decoder_get_bits(rlc_pdu_decoder_t *decoder, int count) +{ + int ret = 0; + int i; + + if (count > 31) { + LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + for (i = 0; i < count; i++) { + ret <<= 1; + ret |= get_bit(decoder); + if (decoder->error) return -1; + } + + return ret; +} + +void rlc_pdu_decoder_align(rlc_pdu_decoder_t *decoder) +{ + if (decoder->bit) { + decoder->bit = 0; + decoder->byte++; + } +} + +/**************************************************************************/ +/* PDU encoder */ +/**************************************************************************/ + +void rlc_pdu_encoder_init(rlc_pdu_encoder_t *encoder, char *buffer, int size) +{ + encoder->byte = 0; + encoder->bit = 0; + encoder->buffer = buffer; + encoder->size = size; +} + +static void put_bit(rlc_pdu_encoder_t *encoder, int bit) +{ + if (encoder->byte == encoder->size) { + LOG_E(RLC, "%s:%d:%s: fatal, buffer full\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + encoder->buffer[encoder->byte] <<= 1; + if (bit) + encoder->buffer[encoder->byte] |= 1; + + encoder->bit++; + if (encoder->bit == 8) { + encoder->bit = 0; + encoder->byte++; + } +} + +void rlc_pdu_encoder_put_bits(rlc_pdu_encoder_t *encoder, int value, int count) +{ + int i; + int x; + + if (count > 31) { + LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + x = 1 << (count - 1); + for (i = 0; i < count; i++, x >>= 1) + put_bit(encoder, value & x); +} + +void rlc_pdu_encoder_align(rlc_pdu_encoder_t *encoder) +{ + while (encoder->bit) + put_bit(encoder, 0); +} diff --git a/openair2/LAYER2/rlc_v2/rlc_pdu.h b/openair2/LAYER2/rlc_v2/rlc_pdu.h new file mode 100644 index 00000000000..dbffe9f3cbf --- /dev/null +++ b/openair2/LAYER2/rlc_v2/rlc_pdu.h @@ -0,0 +1,109 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef _RLC_PDU_H_ +#define _RLC_PDU_H_ + +/**************************************************************************/ +/* RX PDU segment and segment list */ +/**************************************************************************/ + +typedef struct rlc_rx_pdu_segment_t { + int sn; + int so; + int size; + int is_last; + char *data; + int data_offset; + struct rlc_rx_pdu_segment_t *next; +} rlc_rx_pdu_segment_t; + +rlc_rx_pdu_segment_t *rlc_rx_new_pdu_segment(int sn, int so, int size, + int is_last, char *data, int data_offset); + +void rlc_rx_free_pdu_segment(rlc_rx_pdu_segment_t *pdu_segment); + +rlc_rx_pdu_segment_t *rlc_rx_pdu_segment_list_add( + int (*sn_compare)(void *, int, int), void *sn_compare_data, + rlc_rx_pdu_segment_t *list, rlc_rx_pdu_segment_t *pdu_segment); + +/**************************************************************************/ +/* TX PDU management */ +/**************************************************************************/ + +typedef struct rlc_tx_pdu_segment_t { + int sn; + void *start_sdu; /* real type is rlc_sdu_t * */ + int sdu_start_byte; /* starting byte in 'start_sdu' */ + int so; /* starting byte of the segment in full PDU */ + int data_size; /* number of data bytes (exclude header) */ + int is_segment; + int is_last; + int retx_count; + struct rlc_tx_pdu_segment_t *next; +} rlc_tx_pdu_segment_t; + +rlc_tx_pdu_segment_t *rlc_tx_new_pdu(void); +void rlc_tx_free_pdu(rlc_tx_pdu_segment_t *pdu); +rlc_tx_pdu_segment_t *rlc_tx_pdu_list_append(rlc_tx_pdu_segment_t *list, + rlc_tx_pdu_segment_t *pdu); +rlc_tx_pdu_segment_t *rlc_tx_pdu_list_add( + int (*sn_compare)(void *, int, int), void *sn_compare_data, + rlc_tx_pdu_segment_t *list, rlc_tx_pdu_segment_t *pdu_segment); + +/**************************************************************************/ +/* PDU decoder */ +/**************************************************************************/ + +typedef struct { + int error; + int byte; /* next byte to decode */ + int bit; /* next bit in next byte to decode */ + char *buffer; + int size; +} rlc_pdu_decoder_t; + +void rlc_pdu_decoder_init(rlc_pdu_decoder_t *decoder, char *buffer, int size); + +#define rlc_pdu_decoder_in_error(d) ((d)->error == 1) + +int rlc_pdu_decoder_get_bits(rlc_pdu_decoder_t *decoder, int count); + +void rlc_pdu_decoder_align(rlc_pdu_decoder_t *decoder); + +/**************************************************************************/ +/* PDU encoder */ +/**************************************************************************/ + +typedef struct { + int byte; /* next byte to encode */ + int bit; /* next bit in next byte to encode */ + char *buffer; + int size; +} rlc_pdu_encoder_t; + +void rlc_pdu_encoder_init(rlc_pdu_encoder_t *encoder, char *buffer, int size); + +void rlc_pdu_encoder_put_bits(rlc_pdu_encoder_t *encoder, int value, int count); + +void rlc_pdu_encoder_align(rlc_pdu_encoder_t *encoder); + +#endif /* _RLC_PDU_H_ */ diff --git a/openair2/LAYER2/rlc_v2/rlc_sdu.c b/openair2/LAYER2/rlc_v2/rlc_sdu.c new file mode 100644 index 00000000000..16465a9ff13 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/rlc_sdu.c @@ -0,0 +1,68 @@ +/* + * 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 "rlc_sdu.h" + +#include <stdlib.h> +#include <string.h> + +#include "LOG/log.h" + +rlc_sdu_t *rlc_new_sdu(char *buffer, int size, int upper_layer_id) +{ + rlc_sdu_t *ret = calloc(1, sizeof(rlc_sdu_t)); + if (ret == NULL) + goto oom; + + ret->upper_layer_id = upper_layer_id; + + ret->data = malloc(size); + if (ret->data == NULL) + goto oom; + + memcpy(ret->data, buffer, size); + + ret->size = size; + + return ret; + +oom: + LOG_E(RLC, "%s:%d:%s: out of memory\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); +} + +void rlc_free_sdu(rlc_sdu_t *sdu) +{ + free(sdu->data); + free(sdu); +} + +void rlc_sdu_list_add(rlc_sdu_t **list, rlc_sdu_t **end, rlc_sdu_t *sdu) +{ + if (*list == NULL) { + *list = sdu; + *end = sdu; + return; + } + + (*end)->next = sdu; + *end = sdu; +} diff --git a/openair2/LAYER2/rlc_v2/rlc_sdu.h b/openair2/LAYER2/rlc_v2/rlc_sdu.h new file mode 100644 index 00000000000..2c678956ee4 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/rlc_sdu.h @@ -0,0 +1,39 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef _RLC_SDU_H_ +#define _RLC_SDU_H_ + +typedef struct rlc_sdu_t { + int upper_layer_id; + char *data; + int size; + /* next_byte indicates the starting byte to use to construct a new PDU */ + int next_byte; + int acked_bytes; + struct rlc_sdu_t *next; +} rlc_sdu_t; + +rlc_sdu_t *rlc_new_sdu(char *buffer, int size, int upper_layer_id); +void rlc_free_sdu(rlc_sdu_t *sdu); +void rlc_sdu_list_add(rlc_sdu_t **list, rlc_sdu_t **end, rlc_sdu_t *sdu); + +#endif /* _RLC_SDU_H_ */ diff --git a/openair2/LAYER2/rlc_v2/rlc_ue_manager.c b/openair2/LAYER2/rlc_v2/rlc_ue_manager.c new file mode 100644 index 00000000000..1d0884bb9ce --- /dev/null +++ b/openair2/LAYER2/rlc_v2/rlc_ue_manager.c @@ -0,0 +1,182 @@ +/* + * 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 "rlc_ue_manager.h" + +#include <pthread.h> +#include <stdlib.h> +#include <string.h> + +#include "LOG/log.h" + +typedef struct { + pthread_mutex_t lock; + rlc_ue_t **ue_list; + int ue_count; +} rlc_ue_manager_internal_t; + +rlc_ue_manager_t *new_rlc_ue_manager(void) +{ + rlc_ue_manager_internal_t *ret; + + ret = calloc(1, sizeof(rlc_ue_manager_internal_t)); + if (ret == NULL) { + LOG_E(RLC, "%s:%d:%s: out of memory\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + if (pthread_mutex_init(&ret->lock, NULL)) abort(); + + return ret; +} + +void rlc_manager_lock(rlc_ue_manager_t *_m) +{ + rlc_ue_manager_internal_t *m = _m; + if (pthread_mutex_lock(&m->lock)) { + LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } +} + +void rlc_manager_unlock(rlc_ue_manager_t *_m) +{ + rlc_ue_manager_internal_t *m = _m; + if (pthread_mutex_unlock(&m->lock)) { + LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } +} + +/* must be called with lock acquired */ +rlc_ue_t *rlc_manager_get_ue(rlc_ue_manager_t *_m, int rnti) +{ + /* TODO: optimze */ + rlc_ue_manager_internal_t *m = _m; + int i; + + for (i = 0; i < m->ue_count; i++) + if (m->ue_list[i]->rnti == rnti) + return m->ue_list[i]; + + LOG_D(RLC, "%s:%d:%s: new UE %d\n", __FILE__, __LINE__, __FUNCTION__, rnti); + + m->ue_count++; + m->ue_list = realloc(m->ue_list, sizeof(rlc_ue_t *) * m->ue_count); + if (m->ue_list == NULL) { + LOG_E(RLC, "%s:%d:%s: out of memory\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + m->ue_list[m->ue_count-1] = calloc(1, sizeof(rlc_ue_t)); + if (m->ue_list[m->ue_count-1] == NULL) { + LOG_E(RLC, "%s:%d:%s: out of memory\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + m->ue_list[m->ue_count-1]->rnti = rnti; + + return m->ue_list[m->ue_count-1]; +} + +/* must be called with lock acquired */ +void rlc_manager_remove_ue(rlc_ue_manager_t *_m, int rnti) +{ + rlc_ue_manager_internal_t *m = _m; + rlc_ue_t *ue; + int i; + int j; + + for (i = 0; i < m->ue_count; i++) + if (m->ue_list[i]->rnti == rnti) + break; + + if (i == m->ue_count) { + LOG_D(RLC, "%s:%d:%s: warning: ue %d not found\n", + __FILE__, __LINE__, __FUNCTION__, + rnti); + return; + } + + ue = m->ue_list[i]; + + for (j = 0; j < 2; j++) + if (ue->srb[j] != NULL) + ue->srb[j]->delete(ue->srb[j]); + + for (j = 0; j < 5; j++) + if (ue->drb[j] != NULL) + ue->drb[j]->delete(ue->drb[j]); + + free(ue); + + m->ue_count--; + if (m->ue_count == 0) { + free(m->ue_list); + m->ue_list = NULL; + return; + } + + memmove(&m->ue_list[i], &m->ue_list[i+1], + (m->ue_count - i) * sizeof(rlc_ue_t *)); + m->ue_list = realloc(m->ue_list, m->ue_count * sizeof(rlc_ue_t *)); + if (m->ue_list == NULL) { + LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } +} + +/* must be called with lock acquired */ +void rlc_ue_add_srb_rlc_entity(rlc_ue_t *ue, int srb_id, rlc_entity_t *entity) +{ + if (srb_id < 1 || srb_id > 2) { + LOG_E(RLC, "%s:%d:%s: fatal, bad srb id\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + srb_id--; + + if (ue->srb[srb_id] != NULL) { + LOG_E(RLC, "%s:%d:%s: fatal, srb already present\n", + __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + ue->srb[srb_id] = entity; +} + +/* must be called with lock acquired */ +void rlc_ue_add_drb_rlc_entity(rlc_ue_t *ue, int drb_id, rlc_entity_t *entity) +{ + if (drb_id < 1 || drb_id > 5) { + LOG_E(RLC, "%s:%d:%s: fatal, bad drb id\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + drb_id--; + + if (ue->drb[drb_id] != NULL) { + LOG_E(RLC, "%s:%d:%s: fatal, drb already present\n", + __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + ue->drb[drb_id] = entity; +} diff --git a/openair2/LAYER2/rlc_v2/rlc_ue_manager.h b/openair2/LAYER2/rlc_v2/rlc_ue_manager.h new file mode 100644 index 00000000000..7d5ef18b1e7 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/rlc_ue_manager.h @@ -0,0 +1,58 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef _RLC_UE_MANAGER_H_ +#define _RLC_UE_MANAGER_H_ + +#include "rlc_entity.h" + +typedef void rlc_ue_manager_t; + +typedef struct rlc_ue_t { + int rnti; + /* due to openair calling status_ind/data_req, we need to keep this. + * To be considered 'hackish'. + */ + int saved_status_ind_tb_size[2+5]; + rlc_entity_t *srb[2]; + rlc_entity_t *drb[5]; +} rlc_ue_t; + +/***********************************************************************/ +/* manager functions */ +/***********************************************************************/ + +rlc_ue_manager_t *new_rlc_ue_manager(void); + +void rlc_manager_lock(rlc_ue_manager_t *m); +void rlc_manager_unlock(rlc_ue_manager_t *m); + +rlc_ue_t *rlc_manager_get_ue(rlc_ue_manager_t *m, int rnti); +void rlc_manager_remove_ue(rlc_ue_manager_t *m, int rnti); + +/***********************************************************************/ +/* ue functions */ +/***********************************************************************/ + +void rlc_ue_add_srb_rlc_entity(rlc_ue_t *ue, int srb_id, rlc_entity_t *entity); +void rlc_ue_add_drb_rlc_entity(rlc_ue_t *ue, int drb_id, rlc_entity_t *entity); + +#endif /* _RLC_UE_MANAGER_H_ */ diff --git a/openair2/LAYER2/rlc_v2/tests/LOG/log.h b/openair2/LAYER2/rlc_v2/tests/LOG/log.h new file mode 100644 index 00000000000..5c9fcd643cf --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/LOG/log.h @@ -0,0 +1,10 @@ +#ifndef _LOG_H_ +#define _LOG_H_ + +#include <stdio.h> + +#define LOG_E(x, ...) printf(__VA_ARGS__) +#define LOG_D(x, ...) printf(__VA_ARGS__) +#define LOG_W(x, ...) printf(__VA_ARGS__) + +#endif /* _LOG_H_ */ diff --git a/openair2/LAYER2/rlc_v2/tests/Makefile b/openair2/LAYER2/rlc_v2/tests/Makefile new file mode 100644 index 00000000000..14bb186d4c2 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/Makefile @@ -0,0 +1,32 @@ +CC=gcc +CFLAGS=-Wall -g --coverage -I. + +LIB=rlc_entity.o rlc_entity_am.o rlc_entity_um.o rlc_pdu.o rlc_sdu.o + +tests: + @./run_tests.sh + +all: clean_run $(TEST).run + +%.run: $(TEST).bin + #valgrind ./$(TEST).bin > $(TEST).run_pre 2> $(TEST).valgrind + ./$(TEST).bin > $(TEST).run_pre + grep ^TEST $(TEST).run_pre > $(TEST).run + gunzip -c $(TEST).txt.gz > $(TEST).txt + diff -q $(TEST).txt $(TEST).run + +$(TEST).bin: $(TEST).o $(LIB) + $(CC) $(CFLAGS) -o $@ $^ + +%.o: ../%.c + $(CC) $(CFLAGS) -I.. -c -o $@ $< + +$(TEST).o: test.c + $(CC) $(CFLAGS) -c -o $@ $< -DTEST='"$(TEST).h"' + +clean_run: + rm -f $(TEST).run $(TEST).bin $(TEST).o + +clean: + rm -f *.o *.bin *.run *.run_pre *.gcov *.gcda *.gcno test*.txt a.out \ + *.valgrind diff --git a/openair2/LAYER2/rlc_v2/tests/README b/openair2/LAYER2/rlc_v2/tests/README new file mode 100644 index 00000000000..db69cd4fa71 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/README @@ -0,0 +1,38 @@ +To run tests, simply type: make + +Each test is made of: + testXX.h definition of the test + testXX.txt.gz compressed expected output of the test + +At runtime, we generate: + testXX.run actual output of the test + +test.c is the test driving program. + +Only the output lines of the test program starting with "TEST" are +stored into testXX.txt and testXX.run. + +A test is considered a success if testXX.txt and testXX.run are equal. + +Only failed tests are reported. + +How to define a new test? + +1 - get the ID + + Look in the file run_tests.sh, the variable test_count gives you + the number of existing tests. The ID of your test has to be + test_count + 1. + +2 - create files + + Create the file test<ID>.h containing the test, then generate test<ID>.run + by running 'make all TEST=test<ID>' and copy test<ID>.run to test<ID>.txt. + Then compress this file (gzip -9 test<ID>.txt). Be sure that the output + is correct, of course. + + For the file names, replace <ID> by the actual number of the test. + For example, if your test ID is 47, then name the files test47.h and + test47.txt. And run 'make all TEST=test47' to generate test47.run. + +The available instructions for a test are described at the top of test.c. diff --git a/openair2/LAYER2/rlc_v2/tests/make_pdu.c b/openair2/LAYER2/rlc_v2/tests/make_pdu.c new file mode 100644 index 00000000000..057cc3e36db --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/make_pdu.c @@ -0,0 +1,29 @@ +/* gcc -Wall make_pdu.c -I.. ../rlc_pdu.c */ + +#include "rlc_pdu.h" +#include <stdio.h> + +int main(void) +{ + char out[100]; + rlc_pdu_encoder_t e; + int i; + + rlc_pdu_encoder_init(&e, out, 100); + + rlc_pdu_encoder_put_bits(&e, 0, 1); // D/C + rlc_pdu_encoder_put_bits(&e, 0, 3); // CPT + rlc_pdu_encoder_put_bits(&e, 0, 10); // ack_sn + rlc_pdu_encoder_put_bits(&e, 1, 1); // e1 + rlc_pdu_encoder_put_bits(&e, 10, 10); // nack_sn + rlc_pdu_encoder_put_bits(&e, 0, 1); // e1 + rlc_pdu_encoder_put_bits(&e, 0, 1); // e2 + + rlc_pdu_encoder_align(&e); + + for (i = 0; i < e.byte; i++) printf(" %2.2x", (unsigned char)e.buffer[i]); + + printf("\n"); + + return 0; +} diff --git a/openair2/LAYER2/rlc_v2/tests/run_tests.sh b/openair2/LAYER2/rlc_v2/tests/run_tests.sh new file mode 100755 index 00000000000..72feff00363 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/run_tests.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +test_count=45 + +for i in `seq $test_count` +do + make all TEST=test$i >/dev/null 2>/dev/null + if [ $? != 0 ] + then + echo TEST $i FAILURE + fi +done diff --git a/openair2/LAYER2/rlc_v2/tests/test.c b/openair2/LAYER2/rlc_v2/tests/test.c new file mode 100644 index 00000000000..734e85f1f56 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test.c @@ -0,0 +1,433 @@ +#include "../rlc_entity.h" +#include "../rlc_entity_am.h" +#include "../rlc_entity_um.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <inttypes.h> +#include <sys/wait.h> +#include <unistd.h> + +/* + * ENB_AM <rx_maxsize> <tx_maxsize> <t_reordering> <t_status_prohibit> + * <t_poll_retransmit> <poll_pdu> <poll_byte> <max_retx_threshold> + * create the eNB RLC AM entity with given parameters + * + * UE_AM <rx_maxsize> <tx_maxsize> <t_reordering> <t_status_prohibit> + * <t_poll_retransmit> <poll_pdu> <poll_byte> <max_retx_threshold> + * create the UE RLC AM entity with given parameters + * + * ENB_UM <rx_maxsize> <tx_maxsize> <t_reordering> <sn_field_length> + * create the eNB RLC UM entity with given parameters + * + * UE_UM <rx_maxsize> <tx_maxsize> <t_reordering> <sn_field_length> + * create the UE RLC UM entity with given parameters + * + * TIME <time> + * following actions to be performed at time <time> + * <time> starts at 1 + * You must end your test definition with a line 'TIME, -1'. + * + * ENB_SDU <id> <size> + * send an SDU to eNB with id <i> and size <size> + * the SDU is [00 01 ... ff 01 ...] + * (ie. start byte is 00 then we increment for each byte, loop if needed) + * + * UE_SDU <id> <size> + * same as ENB_SDU but the SDU is sent to the UE + * + * ENB_PDU <size> <'size' bytes> + * send a custom PDU from eNB to UE (eNB does not see this PDU at all) + * + * UE_PDU <size> <'size' bytes> + * send a custom PDU from UE to eNB (UE does not see this PDU at all) + * + * ENB_PDU_SIZE <size> + * set 'enb_pdu_size' + * + * UE_PDU_SIZE <size> + * set 'ue_pdu_size' + * + * ENB_RECV_FAILS <fails> + * set the 'enb_recv_fails' flag to <fails> + * (1: recv will fail, 0: recv will succeed) + * + * UE_RECV_FAILS <fails> + * same as ENB_RECV_FAILS but for 'ue_recv_fails' + * + * MUST_FAIL + * to be used as first command after the first TIME to indicate + * that the test must fail (ie. exit with non zero, crash not allowed) + * + * ENB_BUFFER_STATUS + * call buffer_status for eNB and print result + * + * UE_BUFFER_STATUS + * call buffer_status for UE and print result + * + * ENB_DISCARD_SDU <sdu ID> + * discards given SDU + * + * UE_DISCARD_SDU <sdu ID> + * discards given SDU + * + * RE_ESTABLISH + * re-establish both eNB and UE + */ + +enum action { + ENB_AM, UE_AM, + ENB_UM, UE_UM, + TIME, ENB_SDU, UE_SDU, ENB_PDU, UE_PDU, + ENB_PDU_SIZE, UE_PDU_SIZE, + ENB_RECV_FAILS, UE_RECV_FAILS, + MUST_FAIL, + ENB_BUFFER_STATUS, UE_BUFFER_STATUS, + ENB_DISCARD_SDU, UE_DISCARD_SDU, + RE_ESTABLISH +}; + +int test[] = { +/* TEST is defined at compilation time */ +#include TEST +}; + +void deliver_sdu_enb_am(void *deliver_sdu_data, struct rlc_entity_t *_entity, + char *buf, int size) +{ + rlc_entity_am_t *entity = (rlc_entity_am_t *)_entity; + printf("TEST: ENB: %"PRIu64": deliver SDU size %d [", + entity->t_current, size); + for (int i = 0; i < size; i++) printf(" %2.2x", (unsigned char)buf[i]); + printf("]\n"); +} + +void deliver_sdu_enb_um(void *deliver_sdu_data, struct rlc_entity_t *_entity, + char *buf, int size) +{ + rlc_entity_um_t *entity = (rlc_entity_um_t *)_entity; + printf("TEST: ENB: %"PRIu64": deliver SDU size %d [", + entity->t_current, size); + for (int i = 0; i < size; i++) printf(" %2.2x", (unsigned char)buf[i]); + printf("]\n"); +} + +void successful_delivery_enb(void *successful_delivery_data, + rlc_entity_t *_entity, int sdu_id) +{ + rlc_entity_am_t *entity = (rlc_entity_am_t *)_entity; + printf("TEST: ENB: %"PRIu64": SDU %d was successfully delivered.\n", + entity->t_current, sdu_id); +} + +void max_retx_reached_enb(void *max_retx_reached_data, rlc_entity_t *_entity) +{ + rlc_entity_am_t *entity = (rlc_entity_am_t *)_entity; + printf("TEST: ENB: %"PRIu64": max RETX reached! radio link failure!\n", + entity->t_current); + exit(1); +} + +void deliver_sdu_ue_am(void *deliver_sdu_data, struct rlc_entity_t *_entity, + char *buf, int size) +{ + rlc_entity_am_t *entity = (rlc_entity_am_t *)_entity; + printf("TEST: UE: %"PRIu64": deliver SDU size %d [", + entity->t_current, size); + for (int i = 0; i < size; i++) printf(" %2.2x", (unsigned char)buf[i]); + printf("]\n"); +} + +void deliver_sdu_ue_um(void *deliver_sdu_data, struct rlc_entity_t *_entity, + char *buf, int size) +{ + rlc_entity_um_t *entity = (rlc_entity_um_t *)_entity; + printf("TEST: UE: %"PRIu64": deliver SDU size %d [", + entity->t_current, size); + for (int i = 0; i < size; i++) printf(" %2.2x", (unsigned char)buf[i]); + printf("]\n"); +} + +void successful_delivery_ue(void *successful_delivery_data, + rlc_entity_t *_entity, int sdu_id) +{ + rlc_entity_am_t *entity = (rlc_entity_am_t *)_entity; + printf("TEST: UE: %"PRIu64": SDU %d was successfully delivered.\n", + entity->t_current, sdu_id); +} + +void max_retx_reached_ue(void *max_retx_reached_data, rlc_entity_t *_entity) +{ + rlc_entity_am_t *entity = (rlc_entity_am_t *)_entity; + printf("TEST: UE: %"PRIu64", max RETX reached! radio link failure!\n", + entity->t_current); + exit(1); +} + +int test_main(void) +{ + rlc_entity_t *enb = NULL; + rlc_entity_t *ue = NULL; + int i; + int k; + char *sdu; + char *pdu; + rlc_entity_buffer_status_t buffer_status; + int enb_do_buffer_status = 0; + int ue_do_buffer_status = 0; + int size; + int pos; + int next_byte_enb = 0; + int next_byte_ue = 0; + int enb_recv_fails = 0; + int ue_recv_fails = 0; + int enb_pdu_size = 1000; + int ue_pdu_size = 1000; + + sdu = malloc(16001); + pdu = malloc(3000); + if (sdu == NULL || pdu == NULL) { + printf("out of memory\n"); + exit(1); + } + + for (i = 0; i < 16001; i++) + sdu[i] = i & 255; + + pos = 0; + if (test[pos] != TIME) { + printf("%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + for (i = 1; i < 1000; i++) { + if (i == test[pos+1]) { + pos += 2; + while (test[pos] != TIME) + switch (test[pos]) { + default: printf("fatal: unknown action\n"); exit(1); + case ENB_AM: + enb = new_rlc_entity_am(test[pos+1], test[pos+2], + deliver_sdu_enb_am, NULL, + successful_delivery_enb, NULL, + max_retx_reached_enb, NULL, + test[pos+3], test[pos+4], test[pos+5], + test[pos+6], test[pos+7], test[pos+8]); + pos += 9; + break; + case UE_AM: + ue = new_rlc_entity_am(test[pos+1], test[pos+2], + deliver_sdu_ue_am, NULL, + successful_delivery_ue, NULL, + max_retx_reached_ue, NULL, + test[pos+3], test[pos+4], test[pos+5], + test[pos+6], test[pos+7], test[pos+8]); + pos += 9; + break; + case ENB_UM: + enb = new_rlc_entity_um(test[pos+1], test[pos+2], + deliver_sdu_enb_um, NULL, + test[pos+3], test[pos+4]); + pos += 5; + break; + case UE_UM: + ue = new_rlc_entity_um(test[pos+1], test[pos+2], + deliver_sdu_ue_um, NULL, + test[pos+3], test[pos+4]); + pos += 5; + break; + case ENB_SDU: + for (k = 0; k < test[pos+2]; k++, next_byte_enb++) + sdu[k] = next_byte_enb; + printf("TEST: ENB: %d: recv_sdu (id %d): size %d: [", + i, test[pos+1], test[pos+2]); + for (k = 0; k < test[pos+2]; k++) + printf(" %2.2x", (unsigned char)sdu[k]); + printf("]\n"); + enb->recv_sdu(enb, sdu, test[pos+2], test[pos+1]); + pos += 3; + break; + case UE_SDU: + for (k = 0; k < test[pos+2]; k++, next_byte_ue++) + sdu[k] = next_byte_ue; + printf("TEST: UE: %d: recv_sdu (id %d): size %d: [", + i, test[pos+1], test[pos+2]); + for (k = 0; k < test[pos+2]; k++) + printf(" %2.2x", (unsigned char)sdu[k]); + printf("]\n"); + ue->recv_sdu(ue, sdu, test[pos+2], test[pos+1]); + pos += 3; + break; + case ENB_PDU: + for (k = 0; k < test[pos+1]; k++) + pdu[k] = test[pos+2+k]; + printf("TEST: ENB: %d: custom PDU: size %d: [", i, test[pos+1]); + for (k = 0; k < test[pos+1]; k++) printf(" %2.2x", (unsigned char)pdu[k]); + printf("]\n"); + if (!ue_recv_fails) + ue->recv_pdu(ue, pdu, test[pos+1]); + pos += 2 + test[pos+1]; + break; + case UE_PDU: + for (k = 0; k < test[pos+1]; k++) + pdu[k] = test[pos+2+k]; + printf("TEST: UE: %d: custom PDU: size %d: [", i, test[pos+1]); + for (k = 0; k < test[pos+1]; k++) printf(" %2.2x", (unsigned char)pdu[k]); + printf("]\n"); + if (!enb_recv_fails) + enb->recv_pdu(enb, pdu, test[pos+1]); + pos += 2 + test[pos+1]; + break; + case ENB_PDU_SIZE: + enb_pdu_size = test[pos+1]; + pos += 2; + break; + case UE_PDU_SIZE: + ue_pdu_size = test[pos+1]; + pos += 2; + break; + case ENB_RECV_FAILS: + enb_recv_fails = test[pos+1]; + pos += 2; + break; + case UE_RECV_FAILS: + ue_recv_fails = test[pos+1]; + pos += 2; + break; + case MUST_FAIL: + /* do nothing, only used by caller */ + pos++; + break; + case ENB_BUFFER_STATUS: + enb_do_buffer_status = 1; + pos++; + break; + case UE_BUFFER_STATUS: + ue_do_buffer_status = 1; + pos++; + break; + case ENB_DISCARD_SDU: + printf("TEST: ENB: %d: discard SDU %d\n", i, test[pos+1]); + enb->discard_sdu(enb, test[pos+1]); + pos += 2; + break; + case UE_DISCARD_SDU: + printf("TEST: UE: %d: discard SDU %d\n", i, test[pos+1]); + ue->discard_sdu(ue, test[pos+1]); + pos += 2; + break; + case RE_ESTABLISH: + printf("TEST: %d: re-establish eNB and UE\n", i); + enb->reestablishment(enb); + ue->reestablishment(ue); + pos++; + break; + } + } + + enb->set_time(enb, i); + ue->set_time(ue, i); + + if (enb_do_buffer_status) { + enb_do_buffer_status = 0; + buffer_status = enb->buffer_status(enb, enb_pdu_size); + printf("TEST: ENB: %d: buffer_status: status_size %d tx_size %d retx_size %d\n", + i, + buffer_status.status_size, + buffer_status.tx_size, + buffer_status.retx_size); + } + + size = enb->generate_pdu(enb, pdu, enb_pdu_size); + if (size) { + printf("TEST: ENB: %d: generate_pdu: size %d: [", i, size); + for (k = 0; k < size; k++) printf(" %2.2x", (unsigned char)pdu[k]); + printf("]\n"); + if (!ue_recv_fails) + ue->recv_pdu(ue, pdu, size); + } + + if (ue_do_buffer_status) { + ue_do_buffer_status = 0; + buffer_status = ue->buffer_status(ue, ue_pdu_size); + printf("TEST: UE: %d: buffer_status: status_size %d tx_size %d retx_size %d\n", + i, + buffer_status.status_size, + buffer_status.tx_size, + buffer_status.retx_size); + } + + size = ue->generate_pdu(ue, pdu, ue_pdu_size); + if (size) { + printf("TEST: UE: %d: generate_pdu: size %d: [", i, size); + for (k = 0; k < size; k++) printf(" %2.2x", (unsigned char)pdu[k]); + printf("]\n"); + if (!enb_recv_fails) + enb->recv_pdu(enb, pdu, size); + } + } + + enb->delete(enb); + ue->delete(ue); + + free(sdu); + free(pdu); + + return 0; +} + +void usage(void) +{ + printf("options:\n"); + printf(" -no-fork\n"); + printf(" don't fork (to ease debugging with gdb)\n"); + exit(0); +} + +int main(int n, char **v) +{ + int must_fail = 0; + int son; + int status; + int i; + int no_fork = 0; + + for (i = 1; i < n; i++) { + if (!strcmp(v[i], "-no-fork")) { no_fork = 1; continue; } + usage(); + } + + if (test[2] == MUST_FAIL) + must_fail = 1; + + if (no_fork) return test_main(); + + son = fork(); + if (son == -1) { + perror("fork"); + return 1; + } + + if (son == 0) + return test_main(); + + if (wait(&status) == -1) { + perror("wait"); + return 1; + } + + /* child must quit properly */ + if (!WIFEXITED(status)) + return 1; + + /* child must fail if expected to */ + if (must_fail && WEXITSTATUS(status) == 0) + return 1; + + /* child must not fail if not expected to */ + if (!must_fail && WEXITSTATUS(status)) + return 1; + + return 0; +} diff --git a/openair2/LAYER2/rlc_v2/tests/test1.h b/openair2/LAYER2/rlc_v2/tests/test1.h new file mode 100644 index 00000000000..c7744da55c2 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test1.h @@ -0,0 +1,14 @@ +/* + * basic am test: + * at time 1, eNB receives an SDU of 10 bytes + * at time 10, UE receives an SDU of 5 bytes + */ + +TIME, 1, + ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + ENB_SDU, 0, 10, + UE_BUFFER_STATUS, +TIME, 10, + UE_SDU, 0, 5, +TIME, -1 diff --git a/openair2/LAYER2/rlc_v2/tests/test1.txt.gz b/openair2/LAYER2/rlc_v2/tests/test1.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..1c6661e9ea1c43c854ecf24cdac718215bbd1f22 GIT binary patch literal 238 zcmV<K01^KmiwFpQwB}p_19W9`bTKY;cys`bkUfurKp2Gk`xR53jTunRyDg2hHezKA zLH5Ov5Mx-@uV1gOhY^K@YTss_oq3{g5h;Z8se-3aN_vQmw)oC9I8ZS8Mc`3k1rqc? z9~^;WFaUqR3HS^Ct-qoMXe&D@lS<;fwl&4SQxZB*AJ#H-C@n>PkP?g8vaZv&%|Bsd zvrNj^R7qvct&MwQ$MR8~9v5%ppLa9gGRCisjNg~vYZAxAz}PeuV=`M5=X!<c;VYY6 o%7ahi>$hM_t4WvPW=Xb44LbjOWcq4w?Rsgr0<ZBKV0r=o0I)l7YXATM literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test10.h b/openair2/LAYER2/rlc_v2/tests/test10.h new file mode 100644 index 00000000000..c7aca15eb05 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test10.h @@ -0,0 +1,23 @@ +/* + * rlc am test resegmentation of PDU segment with several SDUs + * eNB sends 3 SDUs [1..10] [11.20] [21..30], not received + * eNB retx with smaller PDUs, not received + * eNB retx with still smaller PDUs, not received + * then reception on, all passes + */ +TIME, 1, + ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + UE_RECV_FAILS, 1, + ENB_RECV_FAILS, 1, + ENB_SDU, 0, 10, + ENB_SDU, 1, 10, + ENB_SDU, 2, 10, +TIME, 2, + ENB_PDU_SIZE, 25, +TIME, 48, + ENB_PDU_SIZE, 15, +TIME, 100, + UE_RECV_FAILS, 0, + ENB_RECV_FAILS, 0, +TIME, -1 diff --git a/openair2/LAYER2/rlc_v2/tests/test10.txt.gz b/openair2/LAYER2/rlc_v2/tests/test10.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..68fd3fa0ba7ec7fad990101439087dcdf55693b4 GIT binary patch literal 361 zcmV-v0hazBiwFoNuHsw*19W9`bTKe4ba-?CwUkY3gFq05@BJ0;vAvWTT|d@iX|BB_ zIh7JNyPF_LDY2%szrL=G1&wY@NI*OY^UOQXy0e(g7a3+RPZ>DF&g%WDG!^c11A53% z=06rp8D2pIVo(4IK>`$kVo(A~LGtZxF%IG$NP*TM4XS%s(5C(lW^e!wy`Z2AVgZi8 zF*pIIU<p>>HCTg9AGEdacBek=>cdnAN*Fnc5^l7Vps0!F8`Gctj6fn8OcXSUtZq`Y zkD`l1b$h0RJ-O*=+Me|o?oFO~x>PwxjU9AD2enSXkpmeG=Mjwq>NuGA=gD{&89Jm+ zTbP=vOeVKbCeurmu@KjEww#S4gZ9o-FF|x&#Vq1mIOdTX=9l~@q^>l!$oF=K`SY^f zI8#^PDaMrTcY-l#&-^odhbxYyxmJWPRido4wq?1gisHLXV$I`V1)p6Jcq@JZ@8D&O Hm<9j<hSsH3 literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test11.h b/openair2/LAYER2/rlc_v2/tests/test11.h new file mode 100644 index 00000000000..5801689aea4 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test11.h @@ -0,0 +1,37 @@ +/* + * rlc am test function rlc_am_reassemble_next_segment + * in r->pdu_byte >= r->so + (r->sdu_offset - r->start->data_offset) + * + r->sdu_len + * when case 'if (r->e)' is false + * eNB sends 3 SDUs [1..10] [11.20] [21..30], not received + * eNB retx with smaller PDUs, not received + * eNB retx with still smaller PDUs, not received + * then UE reception on + * then custom PDUs, first a small part of head of original PDU + * then a bigger part, covering the first part + * so that the beginning of this part triggers the 'while' + * then eNB reception on, all passes + */ +TIME, 1, + ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + UE_RECV_FAILS, 1, + ENB_RECV_FAILS, 1, + ENB_SDU, 0, 10, + ENB_SDU, 1, 10, + ENB_SDU, 2, 10, +TIME, 2, + ENB_PDU_SIZE, 25, +TIME, 48, + ENB_PDU_SIZE, 15, +TIME, 95, + ENB_BUFFER_STATUS, +TIME, 99, + UE_RECV_FAILS, 0, + ENB_PDU, 14, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + ENB_PDU, 25, 0xec, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, +TIME, 100, + ENB_RECV_FAILS, 0, +TIME, 134, + UE_BUFFER_STATUS, +TIME, -1 diff --git a/openair2/LAYER2/rlc_v2/tests/test11.txt.gz b/openair2/LAYER2/rlc_v2/tests/test11.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..ea435a666025ab5d90ca2992b91dd94e1551a654 GIT binary patch literal 430 zcmV;f0a5-RiwFp&wB}p_19W9`bTKh5ba-?CwUtY6f<P37_x%-T*>0M9nL&YNquZv5 zx@sCT4nt#NA7Q{getiL*rsx#WXhMJx?sx7z9A>8D$uz<E{w@J0$c<jlZCc`bnSyQ- z*yXnYQ-Vhjffy8k1W1BH&;T?9MWFcUYWhEjcR&iX0BKOAVL(~+9L(SVEIL6!8^jVE zf(PIsI0DCD1zvzPINb$3n^%*o!pz^(a!V0mO;NHQEg~ptTI(9KyZ0j+l0$DtLDP}Z zO&9J^baGQ|&B&|Cjb`dJt1;>`b<ESI#$M{6hGw+2wl-kTgSZl2lv!r-xh+&t+N!j< z&Km-u_;h!<arYeVB77ss#ztz{*fYHGz>gF)Qb!J^`nnzuFX4I|o$Pw`y>w}dw--E& zX6G=>2fS2}XXA~a@85BY6#adfh3rh3^rnn<2_8M^^n$kPX2B6%$<!wq&Em|_WO0#f zvN$E28>_3z)U1|klVdWPxy8Qk?sJIIXX81*=(WWEGP+_a_f4y%2p`JAmRcKYvvRfi Ya-Ep;)?2|xR|K6EKh2#HPZJ0L05dMoSpWb4 literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test12.h b/openair2/LAYER2/rlc_v2/tests/test12.h new file mode 100644 index 00000000000..0387f0aa7f3 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test12.h @@ -0,0 +1,34 @@ +/* + * rlc am test function rlc_am_reassemble_next_segment + * in r->pdu_byte >= r->so + (r->sdu_offset - r->start->data_offset) + * + r->sdu_len + * when case 'if (r->e)' is true + * eNB sends 4 SDUs [1..5] [6..10] [11.20] [21..30], not received + * eNB retx with smaller PDUs, not received + * eNB retx with still smaller PDUs, not received + * then UE reception on + * then custom PDUs, first a small part of head of original PDU + * then a bigger part, covering the first part + * so that the beginning of this part triggers the 'while' + * then eNB reception on, all passes + */ +TIME, 1, + ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + UE_RECV_FAILS, 1, + ENB_RECV_FAILS, 1, + ENB_SDU, 0, 5, + ENB_SDU, 1, 5, + ENB_SDU, 2, 10, + ENB_SDU, 3, 10, +TIME, 2, + ENB_PDU_SIZE, 25, +TIME, 48, + ENB_PDU_SIZE, 15, +TIME, 99, + UE_RECV_FAILS, 0, + ENB_PDU, 15, 0xec, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + ENB_PDU, 25, 0xec, 0x00, 0x00, 0x00, 0x80, 0x50, 0x05, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, +TIME, 100, + ENB_RECV_FAILS, 0, +TIME, -1 diff --git a/openair2/LAYER2/rlc_v2/tests/test12.txt.gz b/openair2/LAYER2/rlc_v2/tests/test12.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..988d7ae644c008cef2f34adce448d00a3a7ce4e1 GIT binary patch literal 415 zcmV;Q0bu?giwFpK`Quyy19W9`bTKk6ba-?CwUtXx!!Qtp@BE56!UgTxN%J_O_KJ|& zo)D^1$3>OOLv>RGzn(lA)D*`}3c2JEd1hxnt-Z6!bQWWBe;0#eY_-}iOq$_(oq}#+ znDv*2AL9{3AO;DL1bI(avvwgjg+6Em3P2$!atcK)WGa;jXbDoFJd6gd^8a843$Sz= z$)*u|U>`gJ2jCDKffMi&tib81(X)Ql+hnH~?`d{$kwM{-cm;%z;D=>XgoIA8oHXn1 zphqk(u;vmaV6Dm&RHvguy8gMEHA8DnE^DTB&AgNRE6CAO(>1cXmVj4v3k3rkhRAnB zI>ta1hE@hm*HM>73u;tg>WD82hQJqvf5DftSDD$pz2IRy|0j4h&!OgWKB)@Yu0s7r z(eYuHp7pd>pB7C`^#(}Sn5j!iu^eR1SPn91EH9k23VSY2^=7@-TTI9E!!~H$B4;$# z1=6m`8FkzpXFNK+&p#fnq4a*UElLqS5(ASdrHxr-o6TpPM5nh_1@~5n-U{hdd;_Eq JWzaDQ003|)yl4Ob literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test13.h b/openair2/LAYER2/rlc_v2/tests/test13.h new file mode 100644 index 00000000000..a57bd43a946 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test13.h @@ -0,0 +1,30 @@ +/* + * rlc am test function process_received_ack with something in + * the retransmit_list to put in the ack_list + * eNB sends 4 PDUs, not received + * eNB retransmits 4th PDU, received, ACKed with NACKs for PDU 1, 2, 3 + * UE receives custom PDU for 1, 2, 3, 4 (they are not sent by eNB) + * (4 resent to have the P bit set) + * UE sends ACK for all, eNB puts from retransmit_list to ack_list + * + * Maybe not very realistic (custom PDUs). + */ +TIME, 1, + ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + UE_RECV_FAILS, 1, + ENB_RECV_FAILS, 1, + ENB_PDU_SIZE, 12, + ENB_SDU, 0, 10, + ENB_SDU, 1, 10, + ENB_SDU, 2, 10, + ENB_SDU, 3, 10, +TIME, 10, + UE_RECV_FAILS, 0, + ENB_RECV_FAILS, 0, +TIME, 87, + ENB_PDU, 12, 0x80, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + ENB_PDU, 12, 0x80, 0x01, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, + ENB_PDU, 12, 0x80, 0x02, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, + ENB_PDU, 12, 0xa0, 0x03, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, +TIME, -1 diff --git a/openair2/LAYER2/rlc_v2/tests/test13.txt.gz b/openair2/LAYER2/rlc_v2/tests/test13.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..55a26712db1f9d1efb68b8a66a275d20b4867beb GIT binary patch literal 351 zcmV-l0igaLiwFob2IO1<19W9`bTKn7ba-?Ct&~e^gHRBK_x%-T*>1|r_>9XEx1|tW zl@g3zi(nskV@mt$t5P9NldHG55s^8cXU;vE#G52Se18{#BQz>MY<1D%x+*|75p?yX zz!c#TL?8wU$N{+^59EUaPzYK*T_u-6d;-cqJ5Ubl-l0Hc_Z-Y%0Xs&J{06ZL_P{<k z0EgfeI0Ns%Ik+%_oD)!YQ$h&B5P>)l7ve#DNN@^zR<Ekb_G<fHv?E1&N=QRSvtyD8 z7F#6cOt8cvEZ4xwsNZXTULGw2OXG_y8Ouq>!=Zn6IQSXv66~%n4dL>Uc5oebV|lCh zZ!dUQr~f_V(MF-_>Yy5I*6CO}tIuh|&CHrixS8Fw2{$u~W_Gg#Vs=Fh3)!~4M=kMt x7*-36ZRfv@?E@fuWE#57bES3J*7fI@k1B4@3D{O3wgSf}_y#e8SSNr60016qoZbKc literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test14.h b/openair2/LAYER2/rlc_v2/tests/test14.h new file mode 100644 index 00000000000..0a3a5017961 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test14.h @@ -0,0 +1,12 @@ +/* + * rlc am test max_retx_reached + * eNB sends PDU, never received + */ +TIME, 1, + MUST_FAIL, + ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + UE_RECV_FAILS, 1, + ENB_RECV_FAILS, 1, + ENB_SDU, 0, 10, +TIME, -1 diff --git a/openair2/LAYER2/rlc_v2/tests/test14.txt.gz b/openair2/LAYER2/rlc_v2/tests/test14.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..93aa5de81ea42ae69511552066c75ccf11febbea GIT binary patch literal 180 zcmV;l089TLiwFn<2;^J>19W9`bTKq8ba-?Ct<kX#f-n>X(4DWiY`VQt5a?*a>YyD= zj3EtuVk4p{VvJuenmD*Q^asvzbhXh6)oQ6A6g)TgdaxsA&VuF&gL^UrDeOQ55}*Vm zK`AH$EkHS_0G0bl|3EGG?9Gkqs~x{e@>UFepuep&4~UgAASPrPQY*56S|X=|vw2`$ i>Fu;?nj_m7-dJ}*=lT;4#&x6TIC=s9>P3110ssK(flLqp literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test15.h b/openair2/LAYER2/rlc_v2/tests/test15.h new file mode 100644 index 00000000000..4adf93f81c0 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test15.h @@ -0,0 +1,42 @@ +/* + * rlc am test so_overlap + * eNB sends PDU, not received + * then PDU is segmented in 3 parts, part 1 & 3 not received, + * then we generate a fake control PDU from UE to eNB that + * contains NACK with so_start/so_end being inside part 2. + * + * code to generate fake control PDU: + * rlc_pdu_encoder_init(&e, out, 100); + * rlc_pdu_encoder_put_bits(&e, 0, 1); // D/C + * rlc_pdu_encoder_put_bits(&e, 0, 3); // CPT + * rlc_pdu_encoder_put_bits(&e, 2, 10); // ack_sn + * rlc_pdu_encoder_put_bits(&e, 1, 1); // e1 + * rlc_pdu_encoder_put_bits(&e, 1, 10); // nack_sn + * rlc_pdu_encoder_put_bits(&e, 0, 1); // e1 + * rlc_pdu_encoder_put_bits(&e, 1, 1); // e2 + * rlc_pdu_encoder_put_bits(&e, 14, 15); // so_start + * rlc_pdu_encoder_put_bits(&e, 16, 15); // so_end + * rlc_pdu_encoder_align(&e); + */ +TIME, 1, + ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + ENB_SDU, 0, 8, + ENB_RECV_FAILS, 1, +TIME, 2, + UE_RECV_FAILS, 1, + ENB_SDU, 1, 30, +TIME, 20, + ENB_PDU_SIZE, 14, +TIME, 48, + UE_RECV_FAILS, 0, +TIME, 49, + UE_RECV_FAILS, 1, +TIME, 50, + UE_RECV_FAILS, 0, +TIME, 60, + ENB_RECV_FAILS, 0, + UE_PDU, 8, 0x00, 0x0a, 0x00, 0xa0, 0x03, 0x80, 0x08, 0x00, +TIME, 70, + UE_RECV_FAILS, 0, +TIME, -1 diff --git a/openair2/LAYER2/rlc_v2/tests/test15.txt.gz b/openair2/LAYER2/rlc_v2/tests/test15.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..f6f25dac9857198c69c7a5c05bd468b9458d65f9 GIT binary patch literal 360 zcmV-u0hj(CiwFo5Vdh){19W9`bTKt9ba-?Cy_3yu!Y~ko?|q6nwwG$xc7n;Vf@@U? zI8_K4$EhNvKf;8nefq{JsYn2~y>Q9NJNwN{c0QfWGfeOAGH`~Cv%8hgYh0H(=q7_N zKOJ<2M-YJ+BtR0RKnW-Xjh0vQp2CxRaT~LBtGB$~k28gNL#;$yWif3<a#xi*x4~?( z*c1E?upd3KUv&7Y2P+14xw9)<Uecg3$bi-$3u^LkprUaDX0QNDumUIG6g&cJ@EB~s zYp?}3f{pb8f*=?|Ku8D$kqjYD5KGY|#uwsH`gC<FfH>WPe76_FIqc$$;+ZnkII=(g z*>B>8dy)x7B#Sm%O|8;jQVN#NC>~o1kJIL{t^M}(84r`i@RCgUhJs~)2%%CRzR4r} z{e*Yp;cIK1_eEV*AKh`d{Pu7ljk^7BfSrM(LzHxh)9BX6!q&^7{Q$|)yuJXCTK)d* G1ONcdtgHP1 literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test16.h b/openair2/LAYER2/rlc_v2/tests/test16.h new file mode 100644 index 00000000000..862cecf344b --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test16.h @@ -0,0 +1,48 @@ +/* + * rlc am test process_received_nack + * Same events as for test15 except the fake control PDU + * does not ACK anything (ack_sn = 0) so that PDU in the + * wait_list are not transfered into the ack_list and + * we cover the case: + * } else { + * prev = cur; + * cur = cur->next; + * } + * for the wait_list case. + * + * code to generate fake control PDU: + * rlc_pdu_encoder_init(&e, out, 100); + * rlc_pdu_encoder_put_bits(&e, 0, 1); // D/C + * rlc_pdu_encoder_put_bits(&e, 0, 3); // CPT + * rlc_pdu_encoder_put_bits(&e, 0, 10); // ack_sn + * rlc_pdu_encoder_put_bits(&e, 1, 1); // e1 + * rlc_pdu_encoder_put_bits(&e, 1, 10); // nack_sn + * rlc_pdu_encoder_put_bits(&e, 0, 1); // e1 + * rlc_pdu_encoder_put_bits(&e, 1, 1); // e2 + * rlc_pdu_encoder_put_bits(&e, 14, 15); // so_start + * rlc_pdu_encoder_put_bits(&e, 16, 15); // so_end + * rlc_pdu_encoder_align(&e); + */ + +TIME, 1, + ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + ENB_SDU, 0, 8, + ENB_RECV_FAILS, 1, +TIME, 2, + UE_RECV_FAILS, 1, + ENB_SDU, 1, 30, +TIME, 20, + ENB_PDU_SIZE, 14, +TIME, 48, + UE_RECV_FAILS, 0, +TIME, 49, + UE_RECV_FAILS, 1, +TIME, 50, + UE_RECV_FAILS, 0, +TIME, 60, + ENB_RECV_FAILS, 0, + UE_PDU, 8, 0x00, 0x02, 0x00, 0xa0, 0x03, 0x80, 0x08, 0x00, +TIME, 70, + UE_RECV_FAILS, 0, +TIME, -1 diff --git a/openair2/LAYER2/rlc_v2/tests/test16.txt.gz b/openair2/LAYER2/rlc_v2/tests/test16.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..61f36c292ec8ec46edaa3de7d77b235d78322a06 GIT binary patch literal 353 zcmV-n0iOOJiwFplVdh){19W9`bTKwAba-?Cy_3yO!!Qtp?>xmE;evM8PU_}}+ABh8 zdP1m569+{qKZ=_oczWW{AkwA=F1`5Vo&9FUPUnj>!Tk0n0Vk+!zFWDX!DUr|t`fNF z!@?xE2N8%t0#YCiia;@F@^Fz36dvuft+TCNy%x=WoXO8;)JcR@mh(=eu$yXUYb<8V zJ;Cn)`_Ym8(&Os^tQ^?o-mdC+$$+My473L2pf(Q+DqA;T1`Ak$H8=vt;0f4(r{D~{ z2It^bu(e)72*MD7D2RqchY%ygO8Uh3OdQ&bSEoIQH66%Tdm)^kU7S!nQHGud_7~s# zv#{ZTWJCeUvdh*`r}USUyrmP0$Cmu%xV@Y=Zu|0tyV>&aCy76O!OBDUP-y@k2jTyl zN6&NguN0l*rT6PY*_k8z9+L2uIk+azt#f6w*}V52Y;ip{z`=n}&Sm$H?F0Y-V5+iw literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test17.h b/openair2/LAYER2/rlc_v2/tests/test17.h new file mode 100644 index 00000000000..a2e6c237de9 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test17.h @@ -0,0 +1,30 @@ +/* + * rlc am test function process_received_nack + * case 'check that VT(A) <= sn < VT(S)' + * eNB sends PDU, not received, resends segmented + * we generate a fake control PDU containing nack_sn == 10, + * to fail the 'check ...' and cover the return. + * + * code to generate fake control PDU: + * rlc_pdu_encoder_init(&e, out, 100); + * rlc_pdu_encoder_put_bits(&e, 0, 1); // D/C + * rlc_pdu_encoder_put_bits(&e, 0, 3); // CPT + * rlc_pdu_encoder_put_bits(&e, 0, 10); // ack_sn + * rlc_pdu_encoder_put_bits(&e, 1, 1); // e1 + * rlc_pdu_encoder_put_bits(&e, 10, 10); // nack_sn + * rlc_pdu_encoder_put_bits(&e, 0, 1); // e1 + * rlc_pdu_encoder_put_bits(&e, 0, 1); // e2 + * rlc_pdu_encoder_align(&e); + */ + +TIME, 1, + ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + ENB_SDU, 0, 30, + ENB_RECV_FAILS, 1, +TIME, 20, + ENB_PDU_SIZE, 14, +TIME, 60, + ENB_RECV_FAILS, 0, + UE_PDU, 4, 0x00, 0x02, 0x05, 0x00, +TIME, -1 diff --git a/openair2/LAYER2/rlc_v2/tests/test17.txt.gz b/openair2/LAYER2/rlc_v2/tests/test17.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..a35b5cecd18759c7c683afd4e83df2fc7ba38293 GIT binary patch literal 298 zcmV+_0oDE=iwFp&V&+@|19W9`bTKzBba-?Cy^=dm!$1&(`}~S2p+UR$`B|d4MM$wL zgrdvc8d)+A`Qjk>^~6>VVG#!kLO(Y%_sy2Ys?1T`T<72%otWL)*&Y{-1zqNF&AT9^ z9CsiBF(?3qAO(s*F(?70pbVrz8;}9*9}1`j6PUpPI0P$j1dhQ8I0a{54c>qa*xoP7 zNr?w}l1^`B{bGCHAQ&2G8cUqJM^%h9thCKeI;@tJ$M7E%4(UfA1bziIA*Pa}YF2|> zQjhEha9`tR9Ov@W6Z!TtU!R6EwaiXf)}voaBhKFvopJpBr9m9;@7?rn`}~O8Wp$7$ wFAYX=G%1`#f4#ws<IDzwdbm@<t9Ed`G2&d^x9yuhW3g9@51CcfUF-t@0Qo(KUjP6A literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test18.h b/openair2/LAYER2/rlc_v2/tests/test18.h new file mode 100644 index 00000000000..0ac25d5c915 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test18.h @@ -0,0 +1,10 @@ +/* + * test rlc am simulate rx pdu buffer full + * eNB sends too big PDU to UE, rejected because buffer full + */ +TIME, 1, + MUST_FAIL, + ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + UE_AM, 10, 10, 35, 0, 45, -1, -1, 4, + ENB_SDU, 0, 10, +TIME, -1 diff --git a/openair2/LAYER2/rlc_v2/tests/test18.txt.gz b/openair2/LAYER2/rlc_v2/tests/test18.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..e119c2b018fcece7c4504135b4bf09c23d902590 GIT binary patch literal 207 zcmV;=05Ja_iwFoxX69T119W9`bTK$Cba-?Ct<u2?f<P37;k{3B+|};tXzDBjw=K#b zh>*dVYRD`!BYOHQaN*)Yi+O?Xzg$j{ZwiTgwUh`XT2npCPWPBu4Vp`I_H7W5#2!ST z02G1*C<4Wx1t<ZfpzPok6X;|b)2fFl@46qA@T(~LLH}6WoTI|=9-4Hc#9f%Nm~tlE zl^KgE2O@L$Z3g4oY3#7gU`#s{!!)kyg>_!+hTW>_Y_yM7X?sI$n+uN0)_rSy?*nWL J?pNai004#9VgmpG literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test19.h b/openair2/LAYER2/rlc_v2/tests/test19.h new file mode 100644 index 00000000000..f28e7609f45 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test19.h @@ -0,0 +1,54 @@ +/* + * test rlc am bad PDU + * eNB sends custom PDUs to UE, all of them are wrong for a reason or another + */ +TIME, 1, + ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + /* data PDU, LI == 0 + * rlc_pdu_encoder_put_bits(&e, 1, 1); // D/C + * rlc_pdu_encoder_put_bits(&e, 0, 1); // RF + * rlc_pdu_encoder_put_bits(&e, 0, 1); // P + * rlc_pdu_encoder_put_bits(&e, 0, 2); // FI + * rlc_pdu_encoder_put_bits(&e, 1, 1); // E + * rlc_pdu_encoder_put_bits(&e, 0, 10); // SN + * rlc_pdu_encoder_put_bits(&e, 0, 1); // E + * rlc_pdu_encoder_put_bits(&e, 0, 11); // LI + */ + ENB_PDU, 4, 0x84, 0x00, 0x00, 0x00, + /* data PDU, no data + * rlc_pdu_encoder_put_bits(&e, 1, 1); // D/C + * rlc_pdu_encoder_put_bits(&e, 0, 1); // RF + * rlc_pdu_encoder_put_bits(&e, 0, 1); // P + * rlc_pdu_encoder_put_bits(&e, 0, 2); // FI + * rlc_pdu_encoder_put_bits(&e, 0, 1); // E + * rlc_pdu_encoder_put_bits(&e, 0, 10); // SN + */ + ENB_PDU, 2, 0x80, 0x00, + /* data PDU, LI == 2 > data size == 1 + * rlc_pdu_encoder_put_bits(&e, 1, 1); // D/C + * rlc_pdu_encoder_put_bits(&e, 0, 1); // RF + * rlc_pdu_encoder_put_bits(&e, 0, 1); // P + * rlc_pdu_encoder_put_bits(&e, 0, 2); // FI + * rlc_pdu_encoder_put_bits(&e, 1, 1); // E + * rlc_pdu_encoder_put_bits(&e, 0, 10); // SN + * rlc_pdu_encoder_put_bits(&e, 0, 1); // E + * rlc_pdu_encoder_put_bits(&e, 2, 11); // LI + * rlc_pdu_encoder_align(&e); + * rlc_pdu_encoder_put_bits(&e, 0, 8); // 1 byte of data + */ + ENB_PDU, 5, 0x84, 0x00, 0x00, 0x20, 0x00, + /* control PDU, CPT != 0 + * rlc_pdu_encoder_put_bits(&e, 0, 1); // D/C + * rlc_pdu_encoder_put_bits(&e, 2, 3); // CPT + */ + ENB_PDU, 1, 0x20, + /* data PDU, but only 1 byte + * rlc_pdu_encoder_put_bits(&e, 1, 1); // D/C + * rlc_pdu_encoder_put_bits(&e, 0, 1); // RF + * rlc_pdu_encoder_put_bits(&e, 0, 1); // P + * rlc_pdu_encoder_put_bits(&e, 0, 2); // FI + * rlc_pdu_encoder_put_bits(&e, 1, 1); // E + */ + ENB_PDU, 1, 0x84, +TIME, -1 diff --git a/openair2/LAYER2/rlc_v2/tests/test19.txt.gz b/openair2/LAYER2/rlc_v2/tests/test19.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..a3c034e7298d5298cd54493622afdfca7c51b9be GIT binary patch literal 101 zcmV-r0Gj_FiwFqaZ01}719W9`bTK(Dba-?C3vmq&u~KmLbFxw}v{FbeEiTE=RS0ki zwNfa~tV&fdu~LXuurN_DFo2*~t`PhhjKCU*Qfi7~wh>W!3_*H~h*W1`63YbuD=HNT H-~a#scwQuT literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test2.h b/openair2/LAYER2/rlc_v2/tests/test2.h new file mode 100644 index 00000000000..ba00920778b --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test2.h @@ -0,0 +1,10 @@ +/* + * basic am test: + * at time 1, eNB receives an SDU of 16000 bytes + */ + +TIME, 1, + ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + ENB_SDU, 0, 16000, +TIME, -1 diff --git a/openair2/LAYER2/rlc_v2/tests/test2.txt.gz b/openair2/LAYER2/rlc_v2/tests/test2.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..9961ff3a1020fe5ecf83b49b11ede590b229de6d GIT binary patch literal 1616 zcmb2|=HOtixD~_1T#{N`Vx(76QNr-{?%pmLcL}$LG2w+y)`nMOuU@??%$2_?C48d5 zqFr@Ingr6WYbVF<b-%&HZ#M6Q!NHTym#?h4_v>EYtB3FYJv?%E_I34T!v1^fetx(U z_v7J4!8)6de|~H=ekyRNv%JM&28XetkWivx$|0{C9M%g3_?%Sd?7z*~tZCruV;r2~ z<#YPy@)=>vdNb3teAt6ivwWV{OP*=0Oqw@Sxi~3qhVkc9dko*7Y5ke7?o97aWBw!s zzaujxIy-j=7#FJM9hn=^!M;&QdZRGA<^;7%K3z*(qC949nPhg!PiskYh-dE=&t}yP zK03zUDV{pq-f5AMX4B>_-5{egb?L^EX^wnPI&CH^TTT=&Qd|F|ch6+*p9<kc%H^LD zc-IKOJ|h(={QA(W$na~urRlnB*t1h}*UT;5z`Ct7H?2FTGdJ;cj`r<i+ct}CYhJs_ zblW+z8_d6t*ll+Ic4Xg%^lwvZlkeZ;{(Ug+rgU|>{1k_o8pf(YLa7T=PI=wbuwEL# z=e5+tYdKHf0mH&GG82^xb!28HKfPg5)_16|Af)fuMN2l*0QFZsy;odfSIpcMWd6!e z_eyir%HCTmo5eDObC<bBEz;fM6P+oYyIk~^<LWJLueUhzf9bTltZaKxylUC{FTMLN zbN^isUbVRVR|3niBQqo?PL$wQHV!*>?1p4(p@G(7L#yN$@&A8a-~aFH`ue}GM;P;e z{jd7}$O%~f_w#=tb#LYCGWFHx$?u;hZrD=r=<arxn%g?xPk%o3*$WX=|I7ZyoBa7{ zFa595_uRI#-IaxLNFjND!~gC!`SoUhZtj^O{=5|ty8m^5@6Y)0GV5^vv!i<~^uHiN zJ^$u^*TeDa%>Jaro$3DUgk;k+kWDpPAL?V*0<<LutCqJ}hvP9Ewh8F4{qea!W>*^O zpW{YE`Tyu|^_7o9cSL<GXHHI#kw8il+u!`(^vFM4yUx&n?O5YNL^`QI{ZC)}-`DJ1 zeym#J_g~*8CBgjozy(C|+MoJ=y6FF3N4K#ZJ78ge?EPE+Q;+Vi+nj5T-ICS0?Tv;8 zd_1Twj{NxlZ{F=0`$Yd3&-r}o&-uci|19#~|ErmG&EB@|rT?A(f4;51-dj_5-@?B4 z_N$H0HZDWB9uf2-B<=ry_W$qd_T9hRh4bJ0JrA|{xUv47|I_RL9!~#O^yufu*Oh^O zdwy^8)vW#h0a%{b*ZunUd^<~>_IaEAS8mOpfBf`v|NZly)>QquG{5Ti%d7IA?uTy7 IGGk%@0R6Za0RR91 literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test20.h b/openair2/LAYER2/rlc_v2/tests/test20.h new file mode 100644 index 00000000000..54f4bec720a --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test20.h @@ -0,0 +1,28 @@ +/* + * rlc am test full tx window + * for that eNB sends a lot of small PDUs + */ +TIME, 1, + ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + ENB_SDU, 0, 513, + ENB_PDU_SIZE, 3, + ENB_RECV_FAILS, 1, + ENB_BUFFER_STATUS, +TIME, 511, + UE_BUFFER_STATUS, +TIME, 512, + UE_BUFFER_STATUS, +TIME, 513, + UE_BUFFER_STATUS, +TIME, 557, + ENB_BUFFER_STATUS, +TIME, 558, + ENB_BUFFER_STATUS, +TIME, 559, + ENB_BUFFER_STATUS, +TIME, 600, + ENB_BUFFER_STATUS, + ENB_RECV_FAILS, 0, +TIME, -1 + diff --git a/openair2/LAYER2/rlc_v2/tests/test20.txt.gz b/openair2/LAYER2/rlc_v2/tests/test20.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..5fedad91a452500def6a850e2da72d99f68346d0 GIT binary patch literal 3931 zcmeH`dsvcb7Qma@!p01na;#9%)kY_qE}Do*8fhuj1dUT!*_dHy<%QBPa*#<)n-WDN z4K>WLvT{_)QZps9yc9}aCdEtU1=ImAc_Tq&-|ut(+x=tz-F^0XzUO(*Ilpt>b9v8) zzOJWtN}%vrxG4NoSh(Hhjo}x=7YyIpTVUm};)-ha+LKs=hi|XuJ<MG9>KNwPVZ9?$ z?x`DMDLDCOMcrywbIVJ;CtmpHaFx3Pe7l@f;RhLOveeflF1lU=7fsdZ#}iR8#j2UE z!=w4CFH^0?_qtzHmKEsef`;)W%-37}(zh7xizaM2xKIC{QFGh_zxFMrH}~&j46ueO zaen+Q#^UHBTMmo$<wg^6rG6i`pl=ez#&Xm|j9s?aX7Mi4s=IeK*x0^}Ya-FOi)8Ml zq!2E`4o~sCtmkfF^mxai+9jvirssF;uU%Yffeepsc)!pncc*Rm<^1;s?YEsLf8)Q` zzvPB)d7zW$E<Q*ydU|JLuI*oO?WBm7MN{tOB#o#s=F}@Y^7r0<yMFS4_qQ8tQw{c3 zJtjL9W_oYj;FyX~#9pXATKM&$H%EmVy$|Q1KEz$9xpZQ?@E7mUJmj;b9SMJ&SQ&Kf zkCVp=|7gPm8FVBLzoeZkE9`1BD_R=7+cq%zUZ7Dh{#YZXDDIiSG|;;J3Qe%R&01+c z9eupecKRBlvf^ZSp`+4ydXeUL?W-s<le!N}F<Bh{iDY6_6HR_2><PruOc04HYp(QF zfBuw7ZNTd9uY7>DZCE^TEv!mP9l;_qtsC?QSQC{FJ?ZC+e4_WBJLsdIZ`2z1sHgp$ zX~}*c<9t+WOysNWeH%*_7x(6u7<bx^7(`T+_qkBBN;Y*mjvyql0o7h(dS-9DK5w{q z2#4aw1=NIna{BCZF$5>MFVYd2I^6(M$5j7mTqWzhsKco`3O+K*n3}ocBJW?nj2=ek zuUT24)u?pV+K1zPI^u}I+^;%WR2egpIn}DrB8@YUY3XJUo(9iemh}~kCLeVe=$Yb( zDpV!Q3R-8U$|vn!RLBcPvkbSrh^q7LcHRHinA(BK&?%3^wT8|pG>AX9y{M2C6gw<& zk)hN9Cs2;!nYg*%OOsHZueB3Xs~y=1n){!fLd-2xl998WJAN8rHmgc5zwV5jOhAoi z4zKUMmWBv!%@pc|@r#aUSAWOFoi5|E4%*P0Xj7;%(s<7BQK!`GenQ8M3qfvmDbEyR z-tipk;KRd0<T_$|{%11!Yr^yH6$uO*tDz{}=ILy9j;5=+4Pil0MWzUmJ2@i}c4Ty{ zRo7@rwTmaesB0aI!3H_*pEr&J$0C%*9HbIqrtu)vNQg29q$>Z^h5)IYYlO&j>tGd+ zjNVFYAK6pm5(wg}5*Z{;xTw!ma~ou2;->M0CT++iWeg`rQ?6=5tRtwLr-aBooDs=a za3FtSwMz@`bR=c9hBT2gyp*hTt5110up;6S*E*QEiHttOFWRn1VC2%9rv0~0XUhp4 zVJ&U(AT#m!JQT1PxmH7S?vB%bpsfLs5UEdi?)pO_!`rh-D?P8Q0$u8y=V7N1xfk3g z0}wRCyQr)J(;~hnqf<c%AI&s{pugssws;3(J73mS<pz9bk{I3-Ijofl@UedWz=MO( z6zSWygfrRLT5{QnG3^jyPVi;0P@YW@zI|RM1ohC_PPTRMssLqGs&%k<{)i2PHQZ_V zn4CZI&cK@gyX`*?5Kst|rcg#eIiNJ}$8%Uh79-GVsJ!6ZB7%AlYzW6iv(}NFQ&3TD zU^P?*o9FXz&nw;DrC{zkO=pAXuYO3(>_33oY*cJ1Y5(%@xhcIZj{K-2`F`*u?VR&? ziNSP!hzGw|=tty@zcg6qEZ&;@T2;}x{F|A^v<|$TtLFUJb^oX-8I3I-1!m4nb6Q7o zK*+w2jo(F!m-RSzy5HojV74L`)+>K|ITb^)cP3J`=569cw2!Nv<CEsE0cucEtEOVu z_Rjj}wC022#Qgv{KS}vk;zy8s_=X_rW|i-T&3V3zQd6smvQ5P?{&SNuT0gI24OfA{ z2h#jyYW(W-Th!7h!>bg;$$WI|9q9~Dfv60mb;{LvZ2GMRfY_9HIzTy6X%>h&P5XIJ zjrUH!wc&Y`;Y|u68K8U8(z~t?{#_#8BM@?i=B`lVZ>HZG1R=Q;#7hwJP)ZkqL}zF( zlxloQ`mNn%QHF(-_*Q`O7~WuVrKT)kdPcDx%18e#Us_qFKxCh#?H^U+$I?v|8Uc<o z)0O7@&XVT}x}(c6<WFk6VFt^pB+9UwvT_*+dMtez1A>Au=pHqGa|X)`pax2_F+fGq z!Z-!OA{f&F5GjKd4bTTliX}kLq_=+uQNftBUNxSY!4d-Wk>a%ppps#tFH~853$XQ5 zEU}>2Qt9hN1>$lD=2M><pPNy?2n<X~>2m|9Oj?wzKztR7$?R9-YcuNY0Ggx-hyayK zbHEE+4#jwb7Z}W__XB8_LOuqNNXktEQPi6GeX#cji7TbGJT#)tzIdqvc=ev3+x1`} zuo=uSt@-MPY8iO-_$Nc#99QndW*YRBW*ffh38G1UykfXKKoAwOA(o2GSQZ{;5nClS z&qgh?Flmr4CxTu0*X6TM2|2^2Vo}1(u0&i|Ms4`SPatT)ee}(@_QiCf<Cb06Oji8! z<nKX(^p>d@;OcTgYi`m&Id~kZq47{F5}<EBz$g<&@*o%qePDF06`&Hu(7WMU`{Ffz zuq~$za?jX7gKk=q3cJrxU}Vysv`WtFm@HBtdZ?J7VX%{#^%SrdptDXetSV`LF^p_R zU~~gU<Uts<Jcp3#pL6^S+w{s|_j6#4z^n#g_la2;eGx&3qW^{0feTB~hlXlzTnUxt zWeh9Lu(Hw;R+3&pq<JH(>;-=zwPXP5$}Y4ZFM(V2)cBX(1Sg+JKMEI8LgtkKSc#ff z0%0X_UO5db>AR13$}5{~^y_d}*PgQAA-n{6Rui|+aBujV`LG^y#4&jXKHw$-&vG3k zxWCq(s<&tMoXw-lH^s6XB(qn9LOD-F!T=BBhU(OSxt;B8<6>WL)G_{yelXdRCmO?e z$`5q5fgGJSs5)FO>Xao95g`b&nlKOL{vg4%qwdOh9t=SdZelQ$n;KxYII(G5ET}wi zlu!Q|yXT#K(sGZ}boqf^8{mA@1af8xwsPoWSpUEC5Xo-eap;?!An^tyQelzjb`Mk> zR?7`AyRe)GZj)Ge@#(9!`M<SK+8r+jw+*qKB)Dy+b^|<*2X1oUe4#co!0hRA9zkBI zVDtRVUc;gi5?f$#n7z{uc|M*Cd?P&T?2|4*;vg(W!`6$C^%`u2MGkDGU+w34)Vsy{ zo8gcvICR79?qCv=hG5QrLPj6R$lmS_Y8<xUfO3(^;MT~ia-K(z+g1r~E&2|qcE+&Y zKB*x-kWc5jxKD@$Qx@r<SmXgP1s8XM96xKgj)$0VTMx#I{t0xTW$&>=j>orvTA7|8 zR1JxPus9cQxZGHav@qGIM(@P>OuEKWO9q*GJ=8`W_=WH2z#qFy=cX5b{lC(Y3pHZ{ zHA8}$$%dO*3N`Z$)b%>3>pf7{|9AYK9FG8c<|O!q*F#&73oXEZYBZRuNz2j}_K4Jp zi9_V>#sl`8R`k@8n0`&xktXPyX?A|`C0SM#K?>IOWc{i;GxJ6y=<3ro6}QdB7qiE{ zbyfJPEm6IqX5?sh)KF+?TTRO*hQ5|AlGR{-?JxFuEJ+b0%r&V-yB&R0j=szY(VGF0 zZv1{IPBVEWAgf|*sM(m$P-}FPD&3I2WR7vSHs5`1fjbS)8!OhDek^yDXu8S<w2s}g XeKm@DhIaa}ZeeJG8vk3^f(8Eou;B(b literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test21.h b/openair2/LAYER2/rlc_v2/tests/test21.h new file mode 100644 index 00000000000..ba2a2088e68 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test21.h @@ -0,0 +1,18 @@ +/* + * rlc am test big SDU (size > 2047) + * first generate SDU with exactly 2047 bytes + * later on generate SDU with exactly 2048 bytes + */ +TIME, 1, + ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + ENB_SDU, 0, 20, + ENB_SDU, 1, 2047, + ENB_SDU, 2, 20, + ENB_PDU_SIZE, 2200, +TIME, 10, + ENB_SDU, 3, 20, + ENB_SDU, 4, 2048, + ENB_SDU, 5, 20, +TIME, -1 + diff --git a/openair2/LAYER2/rlc_v2/tests/test21.txt.gz b/openair2/LAYER2/rlc_v2/tests/test21.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..7fc8cbacdef75cc7a77684509989bc7d414e37d6 GIT binary patch literal 970 zcmaKlYfKXd0D#FRo0*Z^O=s4qFnghmz216{(3`!x@<Ukmh;WUML~UFQD`*NBY|jY{ zNL&aT8+tb)$s(I$#Hp*`U65x3Z7HxZg5KFQfR@s;!#zM5IDtfLm-ru(@9+108DDSQ z80dItf8|xT!{x@Ycim^*DUYVTrJv?*tyP<^uI~MSoi?R`c^{5!X;H4V|MqPy-|%`M z6e>Yu8gCYKY3NA#!39^JkING~J*L|;_U5ug@Ux;xqJ3iZ-$Y?_>FMmy=dO|Q*^Es^ zw^zXebXy!v--3dTsAfO<RtVimpmhzKI;7W}Qrg^16}RZtJUjIrf1$S6|9<gcVR7J4 zaq!H%KfTE`Z@n>mxH(vE_vhLN9rnOMdytFx_eIn%$Y>0Ss*E)TSyf^n1`nuIbxdEa zk^#UN0O?(Tb{B}Z0EQOOavabd2h9qAC?JCY5C#$w081cM2I$K`a+EiY3iNJXyIa7o z^M>n!<s`2=DVV2tWJ+N6@X#KC=;h&Ffhy<q<pMd(8i#FkCacY~;a6D06`RGu>Krz6 zm_@=iCX0o#Y(ysuciJe9)pIs-TsDp?G$Lye1#goLZHlEt)|DvcX&IST7)FK|h3J>z zeub)%^;HTPM2$g=hEOep;jO5l6|)qex&q7`LXi;05GX`oL<b6YV3Z5hyD)N0G>%C$ zENWp1_lO3MWO0f*r)0h_BKIYR5+O<=ydvzCs7g^^DXq8$waF#Z`Xmj{FVAo7soVTj zQO;}}&u+Us!9C;pla6R&e`{aC#o$fnV|3?#@Z=j^=aBU?FAk<Zk^@H<m)F`4V-w-o zI&S>Z!c4T=aIBDy|9vNWLyk*RfAazS(n#{ipLkx^JIC6G7boeF=b8g*Ty2QwzFqAk zBa!n`Y3cH#aCl*5qUT}vg&W<U^hB$cE1oEFea(BfmcA(pcpJIFn)8a`*N-Yr|25h| zUR@jWtxwYPq^9pEkZ~sS2jOD=KXgUYp#kU2j!3$1Z>90a6Y#zIuJz>?-R!&fdbV%F z^7pl_`BKxS?tWQ&`q~QrQYq=lkj_4s{Kc2ZiR?Hvm-@5uvE|MDbpO+Hsd?Y~v#h;~ eamVT%t9EW-v-&YP)VMvd;ir+(6Tdg5r2G#?mkcNX literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test22.h b/openair2/LAYER2/rlc_v2/tests/test22.h new file mode 100644 index 00000000000..6e2e8cd410a --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test22.h @@ -0,0 +1,25 @@ +/* + * am test: ask for retx with TX buffer too small + * then ask for status with buffer too small + */ + +TIME, 1, + ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + ENB_SDU, 0, 100, + UE_RECV_FAILS, 1, +TIME, 47, + ENB_PDU_SIZE, 4, + ENB_BUFFER_STATUS, + UE_BUFFER_STATUS, +TIME, 48, + ENB_PDU_SIZE, 1000, + UE_PDU_SIZE, 1, + UE_BUFFER_STATUS, + UE_RECV_FAILS, 0, +TIME, 49, + UE_BUFFER_STATUS, +TIME, 50, + UE_PDU_SIZE, 1000, + UE_BUFFER_STATUS, +TIME, -1 diff --git a/openair2/LAYER2/rlc_v2/tests/test22.txt.gz b/openair2/LAYER2/rlc_v2/tests/test22.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..cdc7f51a162aae7cff631abeb0324a088ab48907 GIT binary patch literal 392 zcmV;30eAi%iwFn-wB}p_19W9`bTTq7ba-?C?UhT5Q$Y|$_wy^xQa4i1`^Zwv*3D#A zBH=#z4uK$&n~aZNZxT&lKtv4gX4SRm`l>l!RrP9lzgn<-|8{{c*p=aFJ&y-oZARqv zf_d}3pdt%CAc81jh$Dd{QXw_cAT81%Ju)E2%z{kEG*nST9St<m3a!xwZP5<x(E%ON zV~q(DOfkb83oNk;tFZ=au@3980UNP`O}OBS8}4}EiC1`yH+YM8c#jYGh!=b!giyi= zCxS?#B5I-`TB0L*VjxDM5ECh+l14fiWRewGlMUID9odruIg*8(sDw(XjLJXWt)6jx zET77*+n4p{@o<G|C#apAxxS$NC$v#7=nvCWcI$cH?GN)2?)hAw84LTbmuOe6@h^pk z<&6SApU}M6`ycE*n{z}vmhI-L?6`mTa9u_(yXY38x6Mm?qd>|Z1?;Z`elu@&`Jv+3 mf;iniwT|$mo0$*8Q093$Y`5PoomIv+cRv8%;83Im2LJ$w(78(h literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test23.h b/openair2/LAYER2/rlc_v2/tests/test23.h new file mode 100644 index 00000000000..5ad2d25b7de --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test23.h @@ -0,0 +1,9 @@ +/* + * am test: basic test with poll_byte == 1 + */ +TIME, 1, + ENB_AM, 100000, 100000, 35, 0, 45, -1, 1, 4, + UE_AM, 100000, 100000, 35, 0, 45, -1, 1, 4, + ENB_SDU, 0, 30, + ENB_PDU_SIZE, 10, +TIME, -1 diff --git a/openair2/LAYER2/rlc_v2/tests/test23.txt.gz b/openair2/LAYER2/rlc_v2/tests/test23.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..3d66e6afa45fde0e6ebc6f9907c15b970f3a13d7 GIT binary patch literal 266 zcmV+l0rmbLiwFqRrR!V*19W9`bTTt8ba-?Cz0xsj!!Q&C;61<M#&#+9BqvckmU`_H zXDTJgk`fH26st~Ye|=*ULmX^p>n^?T?n!yJ%~NEr&nYBD9o%UjeS?S6gO4d<`5T~_ z;teDypaM0RfJ<-%u0aECKnoV21J4%&cz_Th5CzeY1hRyzAZv($Y#<g=Kpe!sFY-Z% zWB3TQ{R;a}-&_(%m%y4X#CVQ=$}XE4qWTueKvXkgVLEHP;kBsdMKcif9Z^l~?poCI zq8o_G=wZ`=Y!^BCC@poq?L$?bLXGXquKyGN@g*+$Oi|%&(KaISZ6jjiT!`_|RMk)4 QAo!=nALbdJ=JWyp06su@IsgCw literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test24.h b/openair2/LAYER2/rlc_v2/tests/test24.h new file mode 100644 index 00000000000..2393f7a95a8 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test24.h @@ -0,0 +1,9 @@ +/* + * am test: basic test with poll_pdu == 2 + */ +TIME, 1, + ENB_AM, 100000, 100000, 35, 0, 45, 2, -1, 4, + UE_AM, 100000, 100000, 35, 0, 45, 2, -1, 4, + ENB_SDU, 0, 50, + ENB_PDU_SIZE, 10, +TIME, -1 diff --git a/openair2/LAYER2/rlc_v2/tests/test24.txt.gz b/openair2/LAYER2/rlc_v2/tests/test24.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..6c457987dcf297d3beb6a93f27aeddbac5fd58af GIT binary patch literal 324 zcmV-K0lWSmiwFqcrR!V*19W9`bTTw9ba-?C&6B%M!$1&4`+UVIp+Pg_w@XA?nj{rM zksoUmDMBd5LGbm&RxD*v?6mYd_nv!qX1!dkbC%DKIhu2D)p6U_9e2ALxzA~LKaNOp zUJyYPF(g1jBtl{&K~f|`3Zz6T<TU7z1{G9MLjyEKBQ!=6G(|JCKufejYt*3)CYWM| z1z3nhSd1lDie*@Vl~{$<n8O+ZA<);w+6(aJ-rb@2blZ=*JJahxpQb~A>lr*1n^7s# zVg7pJQDw8760xzz)N>4G9J92?o#@h232$%*Q_Wv;hqK%&o?~=_JDmDcPbI#=9ZhY( zC3if}?f0EreH;#k(r<*fTD|;fqIUb;(H&SlZN{tk??-VapDU*NTTCBM_$pf3uBu$y WHr;;zJ*Ic{!{QgZ-}cQi1ONc=iI@2R literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test25.h b/openair2/LAYER2/rlc_v2/tests/test25.h new file mode 100644 index 00000000000..ddb584cdf64 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test25.h @@ -0,0 +1,8 @@ +/* + * am test: reject SDU because not enough room in rx buffer + */ +TIME, 1, + ENB_AM, 10, 10, 35, 0, 45, -1, -1, 4, + UE_AM, 10, 10, 35, 0, 45, -1, -1, 4, + ENB_SDU, 0, 50, +TIME, -1 diff --git a/openair2/LAYER2/rlc_v2/tests/test25.txt.gz b/openair2/LAYER2/rlc_v2/tests/test25.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..7ad895aaccc095103430cffdf324d3976077f0f2 GIT binary patch literal 161 zcmV;S0ABweiwFqurR!V*19W9`bTTzAba-?C4a+%B13>^p(cGu_A!Jq6vvz37DGAOH zLbLQpPO)&{)8m)F>*e!WxqO@}uKc#`@pIq*c)RWBy>h=j8@(!DNXRItpbqtDKqH#a zj25(_4ZUJR2NpICF1W)z9`J}KJmUqgc*8qx_#h%CA%%3LCj%MDL}s#(m26}ujT{tF P{C)ZdjiZP;!2kdN|3gX~ literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test26.h b/openair2/LAYER2/rlc_v2/tests/test26.h new file mode 100644 index 00000000000..95d8367247a --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test26.h @@ -0,0 +1,25 @@ +/* + * am test: test function check_t_poll_retransmit + * case 'PDU with SN = VT(S)-1 not found?' + * eNB sends some PDUs, UE receives none + * then UE receives the first retransmitted PDU and nothing more + * until poll retransmit occurs again in the eNB to trigger the case + */ +TIME, 1, + ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + ENB_SDU, 0, 10, + UE_RECV_FAILS, 1, +TIME, 2, + ENB_SDU, 1, 10, +TIME, 3, + ENB_SDU, 2, 10, +TIME, 4, + ENB_SDU, 3, 10, +TIME, 50, + UE_RECV_FAILS, 0, +TIME, 51, + UE_RECV_FAILS, 1, +TIME, 100, + UE_RECV_FAILS, 0, +TIME, -1 diff --git a/openair2/LAYER2/rlc_v2/tests/test26.txt.gz b/openair2/LAYER2/rlc_v2/tests/test26.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..85f1af55f691179defd6ab24bf8d4c0960d986dc GIT binary patch literal 374 zcmV-+0g3(}iwFowv+G;}19W9`bTT$Bba-?Ct(38DgD?<=_ddlxwo7$)2JA3aW$h9& zRaHd5i6TW+6-ui1>FbbC1t(CDSdfK$pTFZjlP2>tM)L9$gJbM%epr@8h5Ky*dWcbO ze=L|{yn+bCAOR^*01817NP`S$_I8)HKpXpR_t~dieiT(hks~Fe8Z?+Co)mjh8E6H{ zLC)8L*6ux+-C<zmgL<WS1WS2R(w5=?9D*aT1{?4UoPk&199;OIUMU&D3Op(0Nx8)u zLJ)=sL_q>b2#Fxt2lYy+5v-7=fi03wmNdgjmzzy=bF)5gcA2_oKy}=FQCnLZ-D7P= zPOvfmz{X6TnN2t`tiow->hXiuu)^-P2fN4odC|<?&_Bl?<AzY!N-cK_x^ConCgCe9 zQC4|w%W_@qcHfPXEgsty(KM-?w4=_}2Pex)PZRCQNOu`c!WepGyP9h5>{X8Xlp_z% U@mwLJD^zdAFFzEg0T>4W05LJB^#A|> literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test27.h b/openair2/LAYER2/rlc_v2/tests/test27.h new file mode 100644 index 00000000000..224fd121859 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test27.h @@ -0,0 +1,17 @@ +/* + * am test: test function check_t_poll_retransmit + * case 'do we meet conditions of 36.322 5.2.2.3?' + * eNB sends one PDU, UE does not receive + * just before calling check_t_poll_retransmit, eNB receives a new SDU + * for the function 'check_poll_after_pdu_assembly' to fail + * then UE receives all what eNB sends + */ +TIME, 1, + ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + ENB_SDU, 0, 10, + UE_RECV_FAILS, 1, +TIME, 47, + ENB_SDU, 1, 10, + UE_RECV_FAILS, 0, +TIME, -1 diff --git a/openair2/LAYER2/rlc_v2/tests/test27.txt.gz b/openair2/LAYER2/rlc_v2/tests/test27.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..15fc41defe11b0d13f2b044a3e3b02eab4c133ad GIT binary patch literal 243 zcmV<P01W>hiwFo?x9eO219W9`bTT(Cba-?Ct&zQM!axv&d!AxS(nPbi1Ln#oZqs0@ z2%*EbAWK#h`C=k?`WQ=x_{Rn9Y37^RxjdWZ2HEGkff&?UY!==%7?uuvG4SP1AvE{` z2?`j2F_?gF;0PRpDL9!A@)OWnzqPi%y7+NTphSC$We4ibO2%ic<gAqimtX<5g%w=2 z?+|IzAn^t1ZY}8tn`JjyQP_#c;xxW0PJ-B;TDr1n@|+F3{FddkDmPkV`Y{XZ_5IQZ th`y8ExacrhdU5|gi1@P}z9|aze$`afHuO;Udd(nr4gZF=vGVQ$001u<cZ&c3 literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test28.h b/openair2/LAYER2/rlc_v2/tests/test28.h new file mode 100644 index 00000000000..ac768f36523 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test28.h @@ -0,0 +1,18 @@ +/* + * am test: test function check_t_reordering, + * case 'update VR(MS) to first SN >= VR(X) for which not + * all PDU segments have been received' + * eNB sends 3 PDUs, first not received, two others received + * later on, everything is received + */ +TIME, 1, + ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + ENB_SDU, 0, 10, + UE_RECV_FAILS, 1, +TIME, 2, + UE_RECV_FAILS, 0, + ENB_SDU, 1, 10, +TIME, 3, + ENB_SDU, 2, 10, +TIME, -1 diff --git a/openair2/LAYER2/rlc_v2/tests/test28.txt.gz b/openair2/LAYER2/rlc_v2/tests/test28.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..760d1f2b84f0aa4849d987f157f258ab7d22b90b GIT binary patch literal 282 zcmV+#0p<Q5iwFpN;p<!i19W9`bTT+Dba-?Ct&%-Y!!QtrcYeh?!h-Icv`svsW@TwQ zAylRIwTcv>Dkeqn>q#Pch)IKySgpI~{qU8=uGA==pEOvb6>~i}+u^>ppa%_Ce+ig0 zUO)t5kOC#36tn`ZK^ss8%3trw3Fs_u(pK+sxY*89)Ih0d1Vyt{V2T4%73c^upx&>5 zPW?NWdogelf)-729BW_PLMdMoO>~nWfSLy26ubhj!5eS}&cPM<2sU6Ff))d)IMxs# zi3~8#X0yYoAC|ey`TtzNsNb`!H1$<l?6!N~UF<>rf{6X{+lctm^X1mfj|vAN!bj!c gI%CASQ`a<~-iO%7xdr~~f?8bo2I4$7_8<fR07(IbtpET3 literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test29.h b/openair2/LAYER2/rlc_v2/tests/test29.h new file mode 100644 index 00000000000..61bb183641d --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test29.h @@ -0,0 +1,21 @@ +/* + * am test: test function check_t_reordering, + * case 'VR(H) > VR(MS)' + * eNB sends 4 PDUs, only 1st and 3rd are received + * later on, everything is received + */ +TIME, 1, + ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + ENB_SDU, 0, 10, + UE_RECV_FAILS, 1, +TIME, 2, + UE_RECV_FAILS, 0, + ENB_SDU, 1, 10, +TIME, 3, + UE_RECV_FAILS, 1, + ENB_SDU, 2, 10, +TIME, 4, + UE_RECV_FAILS, 0, + ENB_SDU, 3, 10, +TIME, -1 diff --git a/openair2/LAYER2/rlc_v2/tests/test29.txt.gz b/openair2/LAYER2/rlc_v2/tests/test29.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..265735edbceb54e2a54c0f2d7c171080262c95de GIT binary patch literal 349 zcmV-j0iymNiwFo>;p<!i19W9`bTT<Eba-?Ct&>kn!$1(l?|zDR)Qil_Zkj(wF;_2b zPa-8vHWCOTiK*zPH(OXC+a|7%TUcg(^WK}uF5m7l<WCP7I74U3)1j{h+%^^HE<@jZ z8!%;f1`&us0#YCiia;As3`#)h%gt^AdNpsRD?ZHOy&4=vETy0`D3~RlDE34Zpd+XR zjd~5J9^b({4g)J6v?z+hSo?eqB`zeI%vGKNnHpdXj=&pm3{Jo)xBwr)CAjiIiw5K$ zEbWO>o~ZGoh7g1y0#OhRi69$D?1L6XsW6sJRR^YOYgKZ!Si9ol+9J|*&hk8eWL2hZ zPNu{5aqqGV{Y(Bpgx=wdqu<Dq3;%Wy;j`$`4`pfkz8>24%jq!H{j~-TXs~i(y||Q7 vzD;JjlsH=Fs?YPIxkT4Mgr4z?BexX3^lt}A=u%vRT5R|MpR8oc)&&3nC<mTU literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test3.h b/openair2/LAYER2/rlc_v2/tests/test3.h new file mode 100644 index 00000000000..5a469d82e24 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test3.h @@ -0,0 +1,11 @@ +/* + * basic am test: + * at time 1, eNB receives an SDU of 16001 bytes + */ + +TIME, 1, + MUST_FAIL, + ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + ENB_SDU, 0, 16001, +TIME, -1 diff --git a/openair2/LAYER2/rlc_v2/tests/test3.txt.gz b/openair2/LAYER2/rlc_v2/tests/test3.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..30a96e22781c5f1d3b4711f48fc337cef23a574e GIT binary patch literal 757 zcmb2|=HQstd@F{Dxg@o?#8|JSqJ-h?C2hVHo{TPu=e7D+uK)f1+iTKBiDQCJzh?HN z8gYc3k7e+-*cBA|?DyB{`~UxHj{o=Vy8IFOKfmAo|MU9$XZHGkZw3B+YQA6p`@QNl zfx5Q;3M@`4H7zbDTAWt2xV>m`oYCTXqh<bG?}{T1JxBUybj*yX^AnWbD9m0cBwi@Y z|MB_h$J{j&-#_-QnYsQ$=)Pmuf3n?w5?wR<{fF3n?p#YeetC3G@oWw8?7iaIY~tCy z#k0M{vtQ=K#6J^-EhlsDoFu(-GJEAD@yf~kKPSnn1}HsUtm3sy#A~UE*K(dyOLR^x zlR352CToG)D|g>3KDt-Da<BNwUh#~*;%j@wyLO91_m=)?88gE&re4dKYnCy2TgL3N zjOpKAG|Ih{x4me*_k#A`i`KOl)N3!A|Gl99*N{os$j&V(#Vs+!ExF`ag3qy}oMVYG z$CBC7QtHkeIdkUFnls1VoH;n>%+Wh%4(~a0oNLXAUlE;CBU?iwd#^?|n?`nTjchNC z?3cYU@$W`q>&@J|H%af_%wD}oym~YL?@jXR1xn8!tN1+=@q23G_nhb46P<I<WX?Uc z$$Q}T?zr!rGrD(9<=#0bd*@{AowK%gPS@@^(7mUBdd1A}imBHt=9*Vb-d-`gykh$I lFYD|7zK;L@>-zqGUq=}8|NpQ5&)fgyuX#J+?Z({<3;?NG)C>Rs literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test30.h b/openair2/LAYER2/rlc_v2/tests/test30.h new file mode 100644 index 00000000000..feeee977fd3 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test30.h @@ -0,0 +1,16 @@ +/* + * am test: test function generate_status + * enter the while loop 'go to highest full sn+1 for ACK' + * eNB sends several PDUs, only the last is received + * UE sends status PDU of a chosen size that let the code enter the while + */ +TIME, 1, + ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + ENB_SDU, 0, 70, + ENB_PDU_SIZE, 12, + UE_RECV_FAILS, 1, +TIME, 7, + UE_RECV_FAILS, 0, + UE_PDU_SIZE, 12, +TIME, -1 diff --git a/openair2/LAYER2/rlc_v2/tests/test30.txt.gz b/openair2/LAYER2/rlc_v2/tests/test30.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..eeb856c3414ce973ac95ab4e3258f6e9aacd3ff1 GIT binary patch literal 395 zcmV;60d)Q!iwFoX@#|ay19W9`bTcq6ba-?C-IP0v+%ObI`~4NCOqy^XvMsv|nKsSN zRv|2Y$jiVG!Z@=b`Sr1f9f%35*}_#CaSQ2)?;-7X_xpz3=Z_8Aa7z92<20OkcNmcO z4b$OwqLPL$h#-m>;z&RWq(mwtA~n(?9nvH7!Gw&cpo$vmXg~|JL@P9+HQJ&b+M@%S z&=C_%F~b}SSb>#Tg+;8!TCBr*Y`_vW;({w~xZ?pY@Di`^h}U?FcX*Evc)~}55R_m9 zCj>(A^=`is|CGL^Q~M)5ejm;+%GDO-F<!*y^siW!Vb$?M$+@*+`3;uky<M@w4VLGV zSh0#5tdP%b#VT*GihRl|R+V9OvPAZ#PCV>hL)rB$$lrUzD>>=Q?%CLRov&Lm*JYUF znZuh0i|dfWhD{8`hE)vZmR+niEMtfpwlUPX3cbCKms-rMAsr9T>BRk~hwFFxKmVpz p*_o%K{Xd2;<_JIAiRs+;X`06K@%ZcNT^c^z{Q*#u4>PF-006vp$jJZz literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test31.h b/openair2/LAYER2/rlc_v2/tests/test31.h new file mode 100644 index 00000000000..a978c69b39a --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test31.h @@ -0,0 +1,10 @@ +/* + * um test: several SDUs in a PDU (field length 5 bits) + */ +TIME, 1, + ENB_UM, 100000, 100000, 35, 5, + UE_UM, 100000, 100000, 35, 5, + ENB_SDU, 0, 10, + ENB_SDU, 1, 20, + ENB_SDU, 2, 30, +TIME, -1 diff --git a/openair2/LAYER2/rlc_v2/tests/test31.txt.gz b/openair2/LAYER2/rlc_v2/tests/test31.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..2c5e6fcc3415544b1ca81a258e81eef6d190311b GIT binary patch literal 267 zcmV+m0rdVKiwFpX?Ce|u19W9`bTct7ba-?CwUWC^15p%3d%t3p+MUO|OL1D8Oe&Eu zkDD+cA`_FsulFW8jW9vbe8Aaj?Za;BRZ~$v-dAYF6#C<4KODFn2js3|KYj#MDxMHQ z6fwk+1WAz$$&msnpKqGwAf1EkE2u>}q(>qnAlnE)6*bh+1WnNl&Cvoa(H8B{9vv=X zY{vK*qfvYtk(gqJIhJ54mSH(oU?tXK9oA#<Jo;_pEv~rXjwg7EXLybmc!{@o_fujQ zUc=PBht1n?_%_IrlR;z`LMx|E7r*zHmt4Q+x<1z&!pnFJ6RU^yJd5A1VkyDof99~1 R?{eK8d;$t?7b86b000>Ucwhhk literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test32.h b/openair2/LAYER2/rlc_v2/tests/test32.h new file mode 100644 index 00000000000..69d068cc836 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test32.h @@ -0,0 +1,10 @@ +/* + * um test: several SDUs in a PDU (field length 10 bits) + */ +TIME, 1, + ENB_UM, 100000, 100000, 35, 10, + UE_UM, 100000, 100000, 35, 10, + ENB_SDU, 0, 10, + ENB_SDU, 1, 20, + ENB_SDU, 2, 30, +TIME, -1 diff --git a/openair2/LAYER2/rlc_v2/tests/test32.txt.gz b/openair2/LAYER2/rlc_v2/tests/test32.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..0b4633045337017eb15e520e995f9754478fa423 GIT binary patch literal 268 zcmV+n0rUPJiwFpf?Ce|u19W9`bTcw8ba-?CwUWC^17R3Md!OQz+I^S3m*TcI*;FE7 zFaL&sh-^#>pWZ*KX@m`e<^g8T%rH&8YAWi-`wFd?LVw)shXc2}0lBN#?>+)56;FsD ziWuTZf}}`><Vb;(&o|Aok)Dn0%cw;<q(>qnAY%leiW=%@f~IJO=4gSIXp44ej}8|x zcE<RO(HMM;NK7%q980hi%di|Puo7#r4(qWfkNL)^#T7T)@dQut4A1cbFYy-deumhF z*D$s3Ve>W|z7u5WTr@e2RtT+}YF!-gFRNU?>bjnr4&h~Y3=^w|_4ygUJ;suQ$^SfJ S$=~I=SNH^^t3|~?0{{S19)VB* literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test33.h b/openair2/LAYER2/rlc_v2/tests/test33.h new file mode 100644 index 00000000000..6e907db577f --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test33.h @@ -0,0 +1,18 @@ +/* + * um test: test function rlc_um_reassemble_pdu, discard SDU + * case '!(fi & 0x02' + * eNB sends 33 PDUs covering 1 SDU, only PDU 0 received (with SN=0 and FI=1) + * then eNB sends 1 PDU covering 1 SDU (so SN=1 and FI=0 for this one) + * received by UE + */ +TIME, 1, + ENB_UM, 100000, 100000, 35, 5, + UE_UM, 100000, 100000, 35, 5, + ENB_SDU, 0, 33, + ENB_PDU_SIZE, 2, +TIME, 2, + UE_RECV_FAILS, 1, +TIME, 34, + UE_RECV_FAILS, 0, + ENB_SDU, 1, 1, +TIME, -1 diff --git a/openair2/LAYER2/rlc_v2/tests/test33.txt.gz b/openair2/LAYER2/rlc_v2/tests/test33.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..08cb366be415251d3c552da7b4f22615fa8f6138 GIT binary patch literal 421 zcmV;W0b2eaiwFob^Xyy#19W9`bTcz9ba-?CeU&j!0znXkdw<0%wVRne?v5*sv^GFx z41t@)kQie?DE#$4BE}5H>A%~|?f2&GVm4n4m_6PP&;k28o>m7x;&$hdy8(yYXGJLk zo*)8Ih(QXZflMGRq=WR3DP#@VKt>2ZtdK2Kpb9l;fi}<yw1sxi9y*1tp&RH3b!dfd zVe)*l2-CdOx4K_{)YZEmFQeFbl7^E+*#3t{&a4403CzE<05=KDdnf^(BrtER32>Xh zyxU2Dy9B0%Ho$!X(^nVZX#&%1AEih_GX&E}Ck{vEWgY2EBBQm5bY_t$93!1+WMDng znMY>3MmiI@<t9WrG3nfxt0hQOI+rU3TN9VgJ&eh=#HDj(W3(-C>D=y^ZA)A_iy(&E z5|_@-i0QV(rL$gQye)C*Y@(QNOI$ijE9ToWm+ZHgZ_8Y=3S+)4bII0>`7W7D7HrIS z$y~CFW4=q~k~JUmT@shQT$g-luHGE|d2{sqf$1Omzq9!?{nE?XH|+IwcdC2LAC{L> PFNb~s%~pQF_67g|j_=2T literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test34.h b/openair2/LAYER2/rlc_v2/tests/test34.h new file mode 100644 index 00000000000..da119a6047f --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test34.h @@ -0,0 +1,15 @@ +/* + * um test: trigger some cases in rlc_um_reception_actions + * eNB sends several PDUs, only the beginning PDUs and ending PDUs are + * received. Middle PDUs are not. + */ +TIME, 1, + ENB_UM, 100000, 100000, 35, 5, + UE_UM, 100000, 100000, 35, 5, + ENB_SDU, 0, 40, + ENB_PDU_SIZE, 2, +TIME, 2, + UE_RECV_FAILS, 1, +TIME, 8, + UE_RECV_FAILS, 0, +TIME, -1 diff --git a/openair2/LAYER2/rlc_v2/tests/test34.txt.gz b/openair2/LAYER2/rlc_v2/tests/test34.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..aabbe570e56ea236be3853ee4f8f445dbde899fd GIT binary patch literal 434 zcmV;j0ZslNiwFpnHSJsi19W9`bTc$Aba-?CeU-b86hROKeZC@1@T#hNo+i?{IIM@z zX?J=SorBOFhr!pAAe=-Z{aC4|BRco;@bR+a;lukKx#RgfemuU6SG;{1h<7_)o_?O_ zvEvgW5Q!*6Lv+N1m=OzNMQn&G;)Xa7{NahXBLkVpLN;VaPRJR#AXnsuydrPN138c< z@{S5rq6*be9W|k5)bjbwMUMF8{CYlLzn_oa#_Qkn)$ikV9xnv0|HB7ABn55;<|miH z-N3w@Ch%lnUSk({HZU)I5_mB%)yx8~2Bt*4=gq*>y{eQjG|SkOHVzL)bXD3(WN$a6 zokga3DD5<|;-R$j$ly<<oya?%htkI6;4{*$)2JMLaT<0SmxGT}%P!+`@EvQ~Wn2zE zd2PFl%fWTfxXZX491^X&jLX5z(Y(vJ9GoZZyNt`hCDXpkx#Z|+-{o9#AGPmtE;*&z zcXKYey4rVhE;-QJcXKYe{n~eP?~=2xeYb9hyZ#yO$u4(k-)*+jUD|hB>~@#--Bvr^ crG2-}u6JqQ-MCzrKYx?I0RPDYmC6SI0JcTpe*gdg literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test35.h b/openair2/LAYER2/rlc_v2/tests/test35.h new file mode 100644 index 00000000000..35ccec1a42a --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test35.h @@ -0,0 +1,9 @@ +/* + * um: discard PDU because rx buffer full + * eNB sends a PDU too big + */ +TIME, 1, + ENB_UM, 100000, 100000, 35, 5, + UE_UM, 10, 10, 35, 5, + ENB_SDU, 0, 40, +TIME, -1 diff --git a/openair2/LAYER2/rlc_v2/tests/test35.txt.gz b/openair2/LAYER2/rlc_v2/tests/test35.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..6581c390c73f05a34696e1effc3a7194e5f97f3c GIT binary patch literal 170 zcmV;b09F4ViwFoeHtk#j19W9`bTc(Bba-?C#m+qr0bv-0(cUValJ4Gj{`g9XR%1F5 z88aWzh!_-BPouB`3pmMXSDQAmS}zk$+;acikHdrMc|fzocz$I{CALV&C{Te)RG}I* zXpR=BLkHBO56tL@g^dFjxWpB%af9c0fjfM_JsxnzM?!>&APS-+DxxNu-K6~~p7JH% Yx_jPVhsXEl@9$s5HzI0ErbYn(0NS-nU;qFB literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test36.h b/openair2/LAYER2/rlc_v2/tests/test36.h new file mode 100644 index 00000000000..0a49527a923 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test36.h @@ -0,0 +1,14 @@ +/* + * um: discard according to 36.322 5.1.2.2.2 + * eNB sends many PDUs. 1st is received, then not, then again. + */ +TIME, 1, + ENB_UM, 100000, 100000, 35, 5, + UE_UM, 100000, 100000, 35, 5, + ENB_SDU, 0, 33, + ENB_PDU_SIZE, 2, +TIME, 2, + UE_RECV_FAILS, 1, +TIME, 22, + UE_RECV_FAILS, 0, +TIME, -1 diff --git a/openair2/LAYER2/rlc_v2/tests/test36.txt.gz b/openair2/LAYER2/rlc_v2/tests/test36.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..6ad38454f9ba8cbe02dbb137842d91cab52bbcca GIT binary patch literal 379 zcmV->0fhb^iwFp0K<!)t19W9`bTc+Cba-?CeU!US13?f3bH1WO$Yy5m<qMIVlHd#> z>wLRLP7ty&0bfspNE(UB%hLL)rgz)N-Hh$S{S2RRZtKVXQm?o@RoLB(%jvVBlo?Mj zgE=f<1=hiO*Z>=06Kn%pU<cR=;}09`2sgOH176@AyoV3)5kA2;@CAN=ukZ?Q@FT*W zZ+7yUm-gDu%X{0u)$8w5;`=2XU!rjQ53hW)3tSSI|1JdX5}4ni2;3(yzgQ>mkih)5 zy})Av)50L|l)&^g3cN{Rnw?aNB{U=0D4jT5*~_AICXs0!l+G-&!d2-^BZI9<XCB#h zQ#uoQ<RvJbn5?{*KSz+LtUN9a+Y^_Scc^7Y;<EB&HSI`TR$jNZ9f`}zA<(!Zaap+; zT6ZKaE9XV?j>Ki<5^3L&xU3v4?K?7;+&AqzGMAh}?K?7;Tutq}WG*?d+IPuZa*MU^ ZlDXu}Yu_btIoZ$1e*w>$Dg<)|002UQxV``Y literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test37.h b/openair2/LAYER2/rlc_v2/tests/test37.h new file mode 100644 index 00000000000..b418e2c7151 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test37.h @@ -0,0 +1,37 @@ +/* + * um: some wrong PDUs + */ +TIME, 1, + ENB_UM, 100000, 100000, 35, 5, + UE_UM, 100000, 100000, 35, 5, + /* LI == 0 + * rlc_pdu_encoder_put_bits(&e, 0, 2); // FI + * rlc_pdu_encoder_put_bits(&e, 1, 1); // E + * rlc_pdu_encoder_put_bits(&e, 0, 5); // SN + * rlc_pdu_encoder_put_bits(&e, 0, 1); // E + * rlc_pdu_encoder_put_bits(&e, 0, 11); // LI + */ + ENB_PDU, 3, 0x20, 0x00, 0x00, + /* no data + * rlc_pdu_encoder_put_bits(&e, 0, 2); // FI + * rlc_pdu_encoder_put_bits(&e, 0, 1); // E + * rlc_pdu_encoder_put_bits(&e, 0, 5); // SN + */ + ENB_PDU, 1, 0x00, + /* LI == 2 >= data_size == 1 + * rlc_pdu_encoder_put_bits(&e, 0, 2); // FI + * rlc_pdu_encoder_put_bits(&e, 1, 1); // E + * rlc_pdu_encoder_put_bits(&e, 0, 5); // SN + * rlc_pdu_encoder_put_bits(&e, 0, 1); // E + * rlc_pdu_encoder_put_bits(&e, 2, 11); // LI + * rlc_pdu_encoder_align(&e); + * rlc_pdu_encoder_put_bits(&e, 0, 8); // 1 byte of data + */ + ENB_PDU, 4, 0x20, 0x00, 0x20, 0x00, + /* PDU with E == 1 but has size 1 byte only (truncated PDU) + * rlc_pdu_encoder_put_bits(&e, 0, 2); // FI + * rlc_pdu_encoder_put_bits(&e, 1, 1); // E + * rlc_pdu_encoder_put_bits(&e, 0, 5); // SN + */ + ENB_PDU, 1, 0x20, +TIME, -1 diff --git a/openair2/LAYER2/rlc_v2/tests/test37.txt.gz b/openair2/LAYER2/rlc_v2/tests/test37.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..2a1a837bf0329b2859fa9e71ac9a4bc460c55075 GIT binary patch literal 92 zcmV-i0HgmOiwFpCM(tbz19W9`bTc<Dba-?C3vmq&u~KmLbFxw}v{FbeEiTE=RS0ki ywNfa~tV&fdwo-^zFfvdu0HIi}5d5kQL8^&RXM!-*h<JmIfa(B9s;Nh>00030-6F{V literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test38.h b/openair2/LAYER2/rlc_v2/tests/test38.h new file mode 100644 index 00000000000..66a37207e02 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test38.h @@ -0,0 +1,22 @@ +/* + * um: test some cases of functions tx_pdu_size and rlc_entity_um_generate_pdu + * eNB has too much data to fit in one PDU + * then later eNB wants to send an SDU of size > 2047 + * then later eNB sends several SDUs in one PDU + */ +TIME, 1, + ENB_UM, 100000, 100000, 35, 5, + UE_UM, 100000, 100000, 35, 5, + ENB_PDU_SIZE, 2050, + ENB_SDU, 0, 1500, + ENB_SDU, 1, 1500, + ENB_SDU, 2, 10, +TIME, 10, + ENB_SDU, 3, 2048, + ENB_SDU, 4, 10, +TIME, 20, + ENB_SDU, 5, 10, + ENB_SDU, 6, 10, + ENB_SDU, 7, 10, + ENB_SDU, 8, 10, +TIME, -1 diff --git a/openair2/LAYER2/rlc_v2/tests/test38.txt.gz b/openair2/LAYER2/rlc_v2/tests/test38.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..57e4ed270acc00bd861eeb824e24cc0a154c3a60 GIT binary patch literal 1048 zcmaKoeM}Pv7{-Yv<`QEjD}`gyGF^bn+?Zo9KnhFd7Md`LmI){0Ys-LBYq`xTh;z*1 z>?tAaJnp>nyfbG1lo3SOkQEU8TD-x8`9%+*tQK2aD0o;SFq_`o9~zS`OMZFt<jwo! zdGf|K0KlkrwrJUMWBDHAdufTr8e`b3J!4mKcEpi;Sp&|urwnsZ<XXcm@$4rX_N16r zn^e6*`$*Qhuhwn9i?hI0n_8SfpJ;ZisHkZ3|LtnE74!wX=Jh^h?C4@(ZYpqf!KUy# zk2Trq-qI(#k9C9f9iVxh{_ZG!_;=dWLLc$chtk!>bYlwKuorGxl@01ISLiS0>#ywd zUCi~($E~SEBOjpZC^Y;88eM=YZKx_0Rdl0ks-(z=k~&rjKP^R<O3J?^)d!MdKw`@P z$^r1J0sIGm*#eM%0^A0GI0vu@MtLwE#Bds8V2l(oE)64o#n>;k)O{@<p~aiE%%@uN zww6oQ62E9!y+HW{K1RS#2~3edP6(VvAo>LM3y5+;{HqXt9Ab13c@yH2AfgjucUq`v z3;&u0KWSkKE#zGbx6wlMSl9}LawB{sf>Q{SkC3AX_dY_LM_7Z0n)C2#56*j-5)V1) z;j%nLzlZ%Cr0#)yIEdpQvlS$7fZV$v(E+kMXv$0T(KOD`%yya_qq%gNu+nTfOu1lQ z3F9QpY=g-=FqZ-oT`;>_q-I54CE}dO6pN%?<T6F#g7{g`RT_fa5|9J-8FMP?v#*MY zYdHRK!}o!qfe>VQPBt#Tc5v*Xb*w*qGueA+vc1%1e)6<-VLb4-AfnQ_`P9^%*ej?e z?#HB`(hEa^UXGUcFUe2)9M^}~DU<bEYp^d%n!c7QPegCK-md#7=Ws~+vpzCm3-lbQ zsvT`kjLK{(-G`=?9DRLdXZ+VoC+eOfS1rg7H{~rzXIhGey4-u8?_V4|6LP}L&wj^n z<I?#R8SdOxwd~9xxGjm5?SoKxbAH5sSzg%X$^&_igSSj*Z->0&>^Dm9<Z$pz$ubo} zRu5*hWjuOE{vSqqHvQ&0=V<-VoO94LsA!HajKBZ#Q$qCVy8WgL-4@5A`SFI%Y%*aY zCQUSNT%Xy0`I5bj#Hx434eR_GU60C}+&J=vYaGwb3u<&$g;!s@_~y;b`ba}?@qsX2 v?_KLoQqe105>DPQblH<$nXdVR=FK&?%l;iuFdOq%&nJ{YZT{WeVPXFORwiKG literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test39.h b/openair2/LAYER2/rlc_v2/tests/test39.h new file mode 100644 index 00000000000..8c926b3745f --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test39.h @@ -0,0 +1,9 @@ +/* + * um: SDU too big + */ +TIME, 1, + MUST_FAIL, + ENB_UM, 10, 10, 35, 5, + UE_UM, 100, 100, 35, 5, + ENB_SDU, 0, 16001, +TIME, -1 diff --git a/openair2/LAYER2/rlc_v2/tests/test39.txt.gz b/openair2/LAYER2/rlc_v2/tests/test39.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..c4f6501d596f474dd77abbce265bd7ab4e7c9cd4 GIT binary patch literal 758 zcmb2|=HQs&`8I}$xg@o?#Mn}=q@sl3?Imr#6`qVPiRZQYSg!y5{@ZKPMu}sBPQPaM zq#ALAosVVkw%8RE`t0}D>HGixYL5T+?YjIC`9Htk{r~g&`)Bt0e{Ti;eQLg6|NFh_ zHG#Ue{|YQlDm5)GCt93Vw79)!ah%cOdZT6jUGIt`4n0TuXLQVrsPhw)-YCpoC?sAe z%>VKE>BrnP6W>4fu9><1L+HL^*MG9ze-d3Y`~8R5eePUKJbrm}PVsCF@$9|g*=*w3 zy~VS=#Is-K#Kb=ng)Jv@@0=vPb25A7B=O40{68njs|F}NU994@OvG!ciPv(TQ%iJC zEt5I5)Fx|z+beh9D?YkcymGJj$zJh{z2a+o#k+QkL-&^cX&E!aGNxY3m}{0Xd0WQp zvW)59UNp+Rl()TTy!V3k-iy|?7u0Jnn*Y6^|JRU7*~rc<Da9=@#4WkxSc1>7q?}`k zF~^eG(o*Wq96595(3&&H-kdo&=giSNXAbW<bDV3<iC+<&QzKhLBYUq#Hk(FvZ;fm( zjqI1bG4bz4Ve8G@yEjSi-ppRTNxXV9|L;xm>IF*AAFKF16Y+a$;`f~A+!LL1&t%R$ zwaI(n_U^dvoin<3PUYS?Cwu2)?47f=cTU&tInceQe|p8t@QSI|E9RP4Ox|8GyS!rh m_b=<~|Gtj@|Lgkxe_ux!^Z);^|Ige1<*#`=;qAuV3=9C~<<uYm literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test4.h b/openair2/LAYER2/rlc_v2/tests/test4.h new file mode 100644 index 00000000000..8801096de11 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test4.h @@ -0,0 +1,13 @@ +/* + * basic um test: UE field length 5 bits + * at time 1, eNB receives an SDU of 10 bytes + * at time 10, UE receives an SDU of 5 bytes + */ + +TIME, 1, + ENB_UM, 100000, 100000, 35, 5, + UE_UM, 100000, 100000, 35, 5, + ENB_SDU, 0, 10, +TIME, 10, + UE_SDU, 0, 5, +TIME, -1 diff --git a/openair2/LAYER2/rlc_v2/tests/test4.txt.gz b/openair2/LAYER2/rlc_v2/tests/test4.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..4339005cd60ae367d0f4bd3bf919253bcad82241 GIT binary patch literal 166 zcmV;X09pSZiwFqvW8GW=19W9`bTlq>cys`b&#?-^FcgL1-KRLCZYS1M%_z<4(sU9j zVlEO8k<@nZ>4iduYJ@(({qFglt(}2A9t@O0l<UxTzQ;0naAnYiw?NV01QJx>8Z5vK zsKFB4f;(`3UbqQ#lZV91OWLRJlcJI`2Wsr-c)5o`BI>G1Tjov~1^#Q&ze(SRnT9f( UFpXzswaz^I0B5r;VR``o0JC6E!2kdN literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test40.h b/openair2/LAYER2/rlc_v2/tests/test40.h new file mode 100644 index 00000000000..478fe1af065 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test40.h @@ -0,0 +1,9 @@ +/* + * um: not enough room in SDU list + */ +TIME, 1, + ENB_UM, 10, 10, 35, 5, + UE_UM, 100, 100, 35, 5, + ENB_SDU, 0, 20, + ENB_BUFFER_STATUS, +TIME, -1 diff --git a/openair2/LAYER2/rlc_v2/tests/test40.txt.gz b/openair2/LAYER2/rlc_v2/tests/test40.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..38d4b31cdaa43d1bac222a9d92ea9a615201cae6 GIT binary patch literal 148 zcmV;F0BipriwFn?PwiX+19W9`bTlw7ba-?CRn5B!!ax{A;XY4sO6}%PylyF^wK1K@ zlFKfn&1OY>dP6|LYECnJO?_(|_4VQ~#}xXfPeW!i4ruF0<2z8waYsUiN>rg8+M@$H zq7yo!7Immc%Q2vc2{Ww3sz=fMF<p)^Og_!+oYR7=>sL$6uWwD^*Tn}yCviEb0000{ C7eQbE literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test41.h b/openair2/LAYER2/rlc_v2/tests/test41.h new file mode 100644 index 00000000000..076d3e0d8c0 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test41.h @@ -0,0 +1,45 @@ +/* + * um: test function check_t_reordering + * eNB sends PDUs, UE receives some and some not + */ +TIME, 1, + ENB_UM, 10000, 10000, 35, 5, + UE_UM, 10000, 10000, 35, 5, + ENB_SDU, 0, 10, + ENB_SDU, 1, 10, + ENB_SDU, 2, 10, + ENB_SDU, 3, 10, + ENB_SDU, 4, 10, + ENB_SDU, 5, 10, + ENB_SDU, 6, 10, + ENB_SDU, 7, 10, + ENB_SDU, 8, 10, + ENB_SDU, 9, 10, + ENB_SDU, 10, 10, + ENB_SDU, 11, 10, + ENB_SDU, 12, 10, + ENB_SDU, 13, 10, + ENB_SDU, 14, 10, + ENB_SDU, 15, 10, + ENB_SDU, 16, 10, + ENB_SDU, 17, 10, + ENB_SDU, 18, 10, + ENB_SDU, 19, 10, + ENB_SDU, 20, 10, + ENB_SDU, 21, 10, + ENB_SDU, 22, 10, + ENB_SDU, 23, 10, + ENB_SDU, 24, 10, + ENB_SDU, 25, 10, + ENB_PDU_SIZE, 40, +TIME, 2, + UE_RECV_FAILS, 1, +TIME, 3, + UE_RECV_FAILS, 0, +TIME, 6, + UE_RECV_FAILS, 1, +TIME, 7, + UE_RECV_FAILS, 0, +TIME, 8, + UE_RECV_FAILS, 1, +TIME, -1 diff --git a/openair2/LAYER2/rlc_v2/tests/test41.txt.gz b/openair2/LAYER2/rlc_v2/tests/test41.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..8b799ac084ca15f8c1914c93d71d2c25d6271e7d GIT binary patch literal 875 zcmV-x1C;z9iwFomU+!E219W9`bTlz8ba-?Cjh4BN8&?oTbAQDN?d<IfL&K9g(I_$u z;jO{|h9QiWz+dlfjs>uv%wlH*0UlmfAJ(nsr+3d6o__!Jg1+!N+P4p%`&WK`>8M{W ze17?7pw)#xPzt3{24ztW<xv3@Q3;j*{OS2VNH3s*s;GwAzGI-~_C8vp4cdwza|CIJ z_UM3)=!DMbg0AR>?jp!8pzX!PD2&D!jKw&N#{^6iLGB1L36n7eQ!x#*MIM-mRah;8 z{1Idg)?yvjV*@r~6E<TDwu+#zfEsrDy#qUO3a4=fXK@baMNm9~T);(K!ev~+Rb0bu z6BxKDg3=M>6<*^F-r^nJ;{!h86JGWxFQ9_2_=excH}I372%2CBvPXJRJ2-+T1VSVv zLM9YKB{YI8l3v^ngD{DTsELMXiH_)rfhe1#7rA31W?~^$Vk2%3WDqAwkz|$hVs|nm zOL8Pn3ZzI%q)aL#*(JT`of>I-o`W>Wimb_oY{`x+%cK{-b09}@B4=_TS8^k7k9d$} zoAe@hQ4~!v6iaawPYIMrNt6d`X)(MMN~JVPrwq!ZDypU$>I0t^#jB%wYM@4HqGoEL zR%)X@@M&?p4(g;Snx+|=r8%0X1)A)WSsZVPmT84nX^qxtgEr}kF8gE_$Gf3hx}$q~ zphtS5XL_N_KAFYw-sqh^=#!xsnqe50;TW<{W^sH3Mr0&LW)wzcG)89(hU}AB9G{A* znTBbZj_H|!8JUSG`(zf!XJJ-mV|M0X&f5xINgv1G<F$MlA3pW3|54oAMp64;ezSS6 zO||PT7O~u}a%JB3;P-s*pRV!x`0M4{c;(%1@4x@VvnPQ}ICBe#g!4y$5vIJUw@o?R zO!<d9KrVN=vG3LJA)l4<nLVGm=1XrDl(!C-i&<`4xk9&EJmhmyKD)=tH}kt+sB%fl z#kZ8%A)lA>x&8D0Cf~6J<!Y1bN~oYiz98lEdp>=9z9q|@B=?Nm9dCVb$QPx2;X41D z`Q2#}xgF$<|Kk=v<V*jX&!lU2$336Bj_qdi%iH|ihTgZ2&G**Nsk2x{oH~dfAkLh^ zGUC(?`~Y$0_>~c-u3i~&>fC*RICJO9h*Jmdj)?vq;?$k>03jb({{sK_ua*4|000}V BuF3!a literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test42.h b/openair2/LAYER2/rlc_v2/tests/test42.h new file mode 100644 index 00000000000..66f27b9dac4 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test42.h @@ -0,0 +1,39 @@ +/* + * am test: test rlc_entity_am_discard_sdu + * eNB and UE get some SDU, later on some are discarded + */ + +TIME, 1, + ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + ENB_SDU, 0, 10, + ENB_SDU, 1, 10, + ENB_SDU, 2, 10, + ENB_SDU, 3, 10, + ENB_PDU_SIZE, 23, +TIME, 2, + ENB_DISCARD_SDU, 0, + ENB_DISCARD_SDU, 2, + ENB_DISCARD_SDU, 3, + ENB_DISCARD_SDU, 1, +TIME, 10, + UE_SDU, 0, 5, + UE_SDU, 1, 5, + UE_SDU, 2, 5, + UE_SDU, 3, 5, + UE_SDU, 4, 5, + UE_SDU, 5, 5, + UE_PDU_SIZE, 13, +TIME, 12, + UE_DISCARD_SDU, 3, + UE_DISCARD_SDU, 1, + UE_DISCARD_SDU, 0, + UE_DISCARD_SDU, 5, + UE_DISCARD_SDU, 4, + UE_DISCARD_SDU, 2, +TIME, 30, + UE_SDU, 6, 5, + UE_DISCARD_SDU, 6, +TIME, 31, + UE_SDU, 7, 8, +TIME, -1 diff --git a/openair2/LAYER2/rlc_v2/tests/test42.txt.gz b/openair2/LAYER2/rlc_v2/tests/test42.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..cf9f45c88268e0a986a41c335480dded4f33abbd GIT binary patch literal 496 zcmV<M0T2EkiwFp5e(qcX19W9`bTl$9ba-?Cl~qA*+b|Hk_Z4$&FU9Uslw=))`r1pJ zQ(*)$MF$3qps?x`$?I#e7Gg5w#=aSzo#ASh!(A=!R~?o=?>caYgLf~F<8Z{+-2nR5 zVcflWFm?C^A`pWFWIz?jf@)9$YC((jmsMGa6QLfo0Xfj=3=i6#{s%Kyz(y64ScogI z1=rvP+=3V29=riN@SqBrMCkNm3n2(Y1Y#f+#6oIFlL|fgXMgDb_{ZPF@vI_dQfXcA zh|rU6mg2yC*uyfMHTeDR#UF70<6-Xirb)<2VmG?}Fa!xwFi|k0V4PqXdxATg(DeI& zr!SP^7hZEk&I-AC%=fiT-3Tt=Z$Dx@I_Jl6d))6|=Pvy4JyXwD)Q5RdDM0pPe%2b1 zV`6r`S)#<m$VHWCVq($n55y`W#)(vkHYR4XI}<Y_<~VXzi(H&w%3M0D&xe&37H*=o zG&we%nNN4z0+(7)-qa$eJmf-(a~LZaDVSBTO2H(-GWOc})sVt+kdh<HLNWS#;UfRc z_3y=HJ>OU_H`bdg>rEQDI*wel^wtUSa#-~xmafuf7Hucdcy&Tr$O6)@6NOxw!X}<p mr}<1JjMC%+(SF{-f3m(e-t!t7KJS4>_5C04)?bTB2><{d5%JOh literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test43.h b/openair2/LAYER2/rlc_v2/tests/test43.h new file mode 100644 index 00000000000..e594437ae88 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test43.h @@ -0,0 +1,39 @@ +/* + * um test: test rlc_entity_um_discard_sdu + * eNB and UE get some SDU, later on some are discarded + */ + +TIME, 1, + ENB_UM, 100000, 100000, 35, 10, + UE_UM, 100000, 100000, 35, 10, + ENB_SDU, 0, 10, + ENB_SDU, 1, 10, + ENB_SDU, 2, 10, + ENB_SDU, 3, 10, + ENB_PDU_SIZE, 23, +TIME, 2, + ENB_DISCARD_SDU, 0, + ENB_DISCARD_SDU, 2, + ENB_DISCARD_SDU, 3, + ENB_DISCARD_SDU, 1, +TIME, 10, + UE_SDU, 0, 5, + UE_SDU, 1, 5, + UE_SDU, 2, 5, + UE_SDU, 3, 5, + UE_SDU, 4, 5, + UE_SDU, 5, 5, + UE_PDU_SIZE, 13, +TIME, 12, + UE_DISCARD_SDU, 3, + UE_DISCARD_SDU, 1, + UE_DISCARD_SDU, 0, + UE_DISCARD_SDU, 5, + UE_DISCARD_SDU, 4, + UE_DISCARD_SDU, 2, +TIME, 30, + UE_SDU, 6, 5, + UE_DISCARD_SDU, 6, +TIME, 31, + UE_SDU, 7, 8, +TIME, -1 diff --git a/openair2/LAYER2/rlc_v2/tests/test43.txt.gz b/openair2/LAYER2/rlc_v2/tests/test43.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..3387b6530e11728fbd180554a216f20c2b4ef2f8 GIT binary patch literal 416 zcmV;R0bl+fiwFpIe(qcX19W9`bTl(Aba-?Cl~u7$!!Qut`HDBfc6W}`G$W!bOWO%m zRhqac5<)1Y9r$`ui$HDcqij{4-t*nNch}WoxvH^vysyDE2G^dphwg~mz60IWIP@P5 zOf{ZB1Y(eY45$EEPzjoWD$sm$v&su`B-DU*pcXW~;XwQGJD9-&HmZ<>LR^3?xCGC@ z6?hJAz&mgY?o=TY35`GY5P~p7AO=!EETn|YVxedE>W1dsZQr`%mx>tQSL;0@G^CrQ zI50i7Uih~<_tKx-faSw_s`p=$kWr#Pw9U|Y2~sdoFr#1`VF`P@JM4@88SuG7$#!^6 zM7&3o3$6W~S(V5kG3jZNC?PSZTqT;2czusWKn%A)CEAdf+?R=%m?MWVw_41@t)axA ztv(-CN*D_sX%+cU+1y5jC2+0;<&I@J`5|XECxx+sk%CzTD-=v3EMc#mHdQhQS#pkK z(`(`omSG5k(;E{n%P%jn_@K`w(dsN39&ktnnM0aQq>#$j_g|g)OT`;vQW2@N5<US~ KxEK0y2LJ#BFu#%j literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test44.h b/openair2/LAYER2/rlc_v2/tests/test44.h new file mode 100644 index 00000000000..cc9873ac34b --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test44.h @@ -0,0 +1,20 @@ +/* + * am: test function rlc_entity_am_reestablishment + */ +TIME, 1, + ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + RE_ESTABLISH, +TIME, 2, + ENB_SDU, 0, 10, + RE_ESTABLISH, +TIME, 3, + ENB_SDU, 0, 40, + ENB_PDU_SIZE, 14, + UE_RECV_FAILS, 1, +TIME, 4, + UE_RECV_FAILS, 0, +TIME, 10, + RE_ESTABLISH, +TIME, -1 + diff --git a/openair2/LAYER2/rlc_v2/tests/test44.txt.gz b/openair2/LAYER2/rlc_v2/tests/test44.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..bdad9e3fbc5ce1eb162b82c6ea82b0c8cf6fef86 GIT binary patch literal 278 zcmV+x0qOo9iwFppitbzj19W9`bTl+Bba-?Cjgq@g!$1^7d%oh7P$1oVy?&OF+@`^) zP!##G36@ZV;)H^)#}2qKiizu;Ju^EyMgCG`XvWDu`|ey;?``*nU#}>S4V(O-xC-+1 zD#Hd<{kiL!3y*DsJY{t4mq#Vz6%j-cLjuGhArc`mk|62!7i5c^f;lJm<5VIQQX~D5 zNA`UJR8d0%)S)37p)s1EDO#cxTB8lx$K7LsDP~xJIV{8?EXEQn#Y(KgYOKLLwkHq* z-TsMq@JD|t&wlsOT*fBckS|HDW!z6WA-aEvX)<)X;7t=^c!y|98ki8Ho5W}URx*72 cjk-4Z+&vp-Bcpa$(%e420pAY8iK_wt00jttvH$=8 literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test45.h b/openair2/LAYER2/rlc_v2/tests/test45.h new file mode 100644 index 00000000000..c27fd8e2f06 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test45.h @@ -0,0 +1,30 @@ +/* + * um: test function rlc_entity_am_reestablishment + * and also the function clear_entity, case 'while (cur_rx != NULL)' + */ +TIME, 1, + ENB_UM, 100000, 100000, 35, 5, + UE_UM, 100000, 100000, 35, 5, + RE_ESTABLISH, +TIME, 2, + ENB_SDU, 0, 10, + RE_ESTABLISH, +TIME, 3, + ENB_SDU, 0, 10, + ENB_SDU, 0, 10, + ENB_SDU, 0, 10, + ENB_SDU, 0, 10, + ENB_PDU_SIZE, 14, +TIME, 5, + UE_RECV_FAILS, 1, +TIME, 6, + UE_RECV_FAILS, 0, +TIME, 10, + RE_ESTABLISH, +TIME, 998, + ENB_SDU, 0, 10, + ENB_SDU, 0, 10, + UE_RECV_FAILS, 1, +TIME, 999, + UE_RECV_FAILS, 0, +TIME, -1 diff --git a/openair2/LAYER2/rlc_v2/tests/test45.txt.gz b/openair2/LAYER2/rlc_v2/tests/test45.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..c5e3e71d46e7f4a547b59fd5403557ac623e7d4f GIT binary patch literal 358 zcmV-s0h#_EiwFozknUUp19W9`bTl<Cba-?Cm6E$o!$1&4d%oh7P$11??W|oQ(xxG) zP=x&0KqQ1vLMZrp>_8At6L;2nbmr*ZnNP3gC0epc=V|*?)%WY|9cgw!_0Y1Ip3L_H z)7eFd^;6CB&9>cfx^9uPlI{8>p;B^<2%?A~jszq_a%6%;q*%U#?5Iut&!!5gkp}60 zC1lmTqly~p%Ml<AXolwK1dV8cR%nejXgdnjeXKCS6f?}RfMr;YO~!yMVg*)VHP&D) zmar8rxPAxSriZktp3==@yE{-qPsyckqmtpIy5R$HG2H{(biaO18?G)F2dPnUhXJRg zy;C6riND48*(v<xbbNE!kdyUJQT}S~qmD1c{8wV^fzbzx>pMQ;{EH$EUx^#;c)&9} z$0vBi3%tVX<v3J>w|K%=1R*HF2u=uu>?i8~lN)sF)_r3Zzccr4Q3u^#0XS}>7rX=j E0MFa7@&Et; literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test5.h b/openair2/LAYER2/rlc_v2/tests/test5.h new file mode 100644 index 00000000000..3224817c264 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test5.h @@ -0,0 +1,13 @@ +/* + * basic um test: UE field length 10 bits + * at time 1, eNB receives an SDU of 10 bytes + * at time 10, UE receives an SDU of 5 bytes + */ + +TIME, 1, + ENB_UM, 100000, 100000, 35, 10, + UE_UM, 100000, 100000, 35, 10, + ENB_SDU, 0, 10, +TIME, 10, + UE_SDU, 0, 5, +TIME, -1 diff --git a/openair2/LAYER2/rlc_v2/tests/test5.txt.gz b/openair2/LAYER2/rlc_v2/tests/test5.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..5a27d5260641878ac7e26cda1d77b8eeb7442154 GIT binary patch literal 167 zcmV;Y09gMYiwFq)W8GW=19W9`bTuw?cys`bkg*EFFcd|1zv7O%-Be>WqnOpD=_FFb zJR~3@sqNs`3xy2T6#4=0+;g6@l{2uXgMl)La_gJccUT4wt_<4n5hxm*L4pb_z%{r5 zHMj*!a0l)$3pWDY<tg#{mgeQVL@5%5^H{YVP+lIPmx$_EC!M)A1A$Xn`oHS;Fq2VE VRg7Q2jJVG1eE|v@)?a`D006dCOVR)U literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test6.h b/openair2/LAYER2/rlc_v2/tests/test6.h new file mode 100644 index 00000000000..2115c8a328a --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test6.h @@ -0,0 +1,27 @@ +/* + * rlc am test function segment_already_received + * eNB sends SDU [1..900], not received + * eNB retx with smaller PDUs [1..600] [601..900] + * [1..600] is received but ACK/NACK not + * eNB retx with still smaller PDUs [1..400] [401..600] [601..900] + * all is received, ACKs/NACKs go through + * + * this test will fail if NACK mechanism uses SOstart/SOend + * (not implemented for the moment) + */ +TIME, 1, + ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + UE_RECV_FAILS, 1, + ENB_RECV_FAILS, 1, + ENB_SDU, 0, 900, +TIME, 2, + ENB_PDU_SIZE, 600, + UE_RECV_FAILS, 0, +TIME, 48, + UE_RECV_FAILS, 1, + ENB_PDU_SIZE, 400, +TIME, 90, + UE_RECV_FAILS, 0, + ENB_RECV_FAILS, 0, +TIME, -1 diff --git a/openair2/LAYER2/rlc_v2/tests/test6.txt.gz b/openair2/LAYER2/rlc_v2/tests/test6.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..54870821a619725938e1ea529ff533d748d9c7db GIT binary patch literal 777 zcmV+k1NQtMiwFo(!roj019W9`bT%$@cys{mo4altM-WAGeZ>i_#HfCEZ)k|A6H$?2 z2>qxw2oQ$BHD%ae?_JRpBzVQlFbNef;Y?KLp1RY6xxRXPec<ZH9}c(!cRD}3KdyVe zyIIKV1IL@clqPcECqxj3cqAYZNk~QtQjvyqWFQkcJ*mjX3C`g>F5n_A;WDn^Dz4!= zZr~<v;S{&=f_He25BP{r_>3?3if{OiANYx1c*Spm5FEi10wEF-ArlIr5*ncs24NBw zK?$2EL`U?*K#ash%)~;h#76AIL7c=zRN^KH$&oxMkRmCOGO3U%sgXKqkS1x7l(fl0 zc4SWu<Va5BOfKX~ZsblL<Vjv+C2xvQ9K}-tB~lV4QwpV08l_VPWl|PJDVr)(NA=V| zjnqWV)IzP)M(xx=ozz8D>OPH)=4hT4Xpxp^nO10()@YqJXp^>Rrx|a$&>h{=13l6c zJ<|)l(i^?g2Yu2PUFn-449D<{z=({*$c)0MjK=7U!I+H2P{w8o(=k0WFe5WDGqW%& zvoSk!Feh^{mAP5MaxBjZtjJ2N%qpzPYOKy0tjSs|Wo=YYhk7)i5lv`D3tG{Jc66W< zU8tg)Eo{g3?7)uf#Ln!(uI$F{?7^Pw#a8w<{*8a*-}pEFjeq0+|K<PZSJz+k)?f5j zz3ad0``_06r_$=rrS$~0h>gzFW$H5ijeq0c_&5HIf8+mIRM%K8cGvuH;Ch<A$Y+;L z&<th<GyaW#<Nq7t|8Zl!yZY+F^pD>s<;(S2FWw!bp6}lux9SP$bG|HM7BO2f&#fe% zBVWVC5XZ;J`wPKu@$xg)tF2d<^h|m$ivQ1L_%*RTDZ})X45!J^WN0!p8NMtTKA0_E zejAjJK3w&mfu18{sj<}jcSjQsG!{E;u+&&;Ui4|hImAnEZ$9W9Z{NK8^aF(b|6s;4 zV;TR(zwvMU8~?_?@&9}p>r<b^<G)@~&%IXoqaQim&#A}bzQ4Ww^Rf2o`u^45*|Zby H7CZm|ELM+i literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test7.h b/openair2/LAYER2/rlc_v2/tests/test7.h new file mode 100644 index 00000000000..081227a400d --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test7.h @@ -0,0 +1,26 @@ +/* + * rlc am test function rlc_am_segment_full + * eNB sends SDU [1..900], not received + * eNB retx with smaller PDUs [1..600] [601..900] + * nothing received + * eNB retx with still smaller PDUs [1..400] [401..600] [601..900] + * [401..600] received, ACK goes through + * link clean, all goes through + * + * this test will fail if NACK mechanism uses SOstart/SOend + * (not implemented for the moment) + */ +TIME, 1, + ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + UE_RECV_FAILS, 1, + ENB_RECV_FAILS, 1, + ENB_SDU, 0, 900, +TIME, 2, + ENB_PDU_SIZE, 600, +TIME, 48, + ENB_PDU_SIZE, 400, +TIME, 95, + UE_RECV_FAILS, 0, + ENB_RECV_FAILS, 0, +TIME, -1 diff --git a/openair2/LAYER2/rlc_v2/tests/test7.txt.gz b/openair2/LAYER2/rlc_v2/tests/test7.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..9976a6050779805882bbefb2dab98fa27fd789bc GIT binary patch literal 796 zcmV+%1LOQ3iwFp0#NJ#219W9`bT=+^cys{mn>}ltM-YX3|B9!Kn=t#md&^+8X)ISE znEjXy0uh34<dFRO+#5y0BG>6cBs}nz`&RRuGl#?O_0{|916SXFcfcLE)A{M+aozLH z%|hNDINtoBG?4>8Ac8o=BLRs>LNZd2iZrAn1DVL_PenFPa1Q5j0T*!zmvIGGaShjT z12=ICr?`z5yu*8Zz(;(-XMDj|e8YGAz)$?bD}ED%;0T@&2$7HonNSFo&<LF{2$Qe~ zO4vjpI-(~AVk9PFCKh5PHex3Z;v_Dj5;sXmj^s&!6iJDcNrhBNjnqklG)ar3q)isG zBYScnM{*)(av@i8BX{y3Px2xwc~gYqD4r51k&-BxQYe+uD4jAWld>pE*;JuAs;35O zq$X;n7HXw7YNrnBq%Nvb_i1c2NAt8mi?l?`v_h-2M(eaeo3uqc&3My=?&zK#=#if2 znO^9X-sqh^=##$aO5Y4&IEH5gMr0&LW)wzcG)89(#$+spGB#6~j_H|!8JUThnT1)I zjoF!lIhl*8%*_&(V|i9!MOI>ER$*0EV|CVGP1a&5YomfX)T057XhJhu(26#+qXV7j zLKWR?VLP^G2X<s9c4ilLWjA(b5B6j)wz9YJZ~Pno#=r4z{2TxOFaJNjxqg;gf6|}z zuK%hZe_8iWq1B&5>j`QR8=YB~S(ou|{2TwqzwvMU8~-mNy2f%byXJ?&^)!8v&pw-= zIhZ+^@o)Sa|6dXR&o^ehxG{s&^TynNEy@$6XUUjqOf|MOUS#fV@uG^O<zCzS=3wSv zuZsWY&Xz7Zo0oWYwpITg=vgwR8dJ@GoR(X*v}~#|)x6rY{Nd`0BKD7Wa^>^GE?mA2 z5g$+c=l?w1pa}lo^7ynoZh721(me8Y<?#nQJUQFa+nY~%$NP65o*p#Vdj_*Ivohn~ z_&5HIf8*cyH~wGBdxj9KLpFK5ln&X2XeF}A#$@xVOXM%9_^CyX{}lbXFA;w0M~?S% a>hZYmZ*PBptW$J-`{qygK1W|ZLI40jfsNb% literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test8.h b/openair2/LAYER2/rlc_v2/tests/test8.h new file mode 100644 index 00000000000..aa7f5bed5be --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test8.h @@ -0,0 +1,19 @@ +/* + * basic am test: + * at time 1, eNB receives 10 SDUs of 10 bytes + */ + +TIME, 1, + ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + ENB_SDU, 0, 10, + ENB_SDU, 1, 10, + ENB_SDU, 2, 10, + ENB_SDU, 3, 10, + ENB_SDU, 4, 10, + ENB_SDU, 5, 10, + ENB_SDU, 6, 10, + ENB_SDU, 7, 10, + ENB_SDU, 8, 10, + ENB_SDU, 9, 10, +TIME, -1 diff --git a/openair2/LAYER2/rlc_v2/tests/test8.txt.gz b/openair2/LAYER2/rlc_v2/tests/test8.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..c8016878635a3f971d3c63298ac49ddefe6835b7 GIT binary patch literal 461 zcmV;;0W$s{iwFqvtm0e(19W9`bT}?_cys`jl`)UgKoCZIe#I-HK{K<nYda+(EzR9k z2%Q{fjUq(|#pDqDdK{z_3CGCpR@T$o_0H$dkK2dG4ckv2Ht2>^9bTTN{h7CiJ@RhD zbogCS+3*<=L=i(0;z&jc(jYC;eR=cvf05padSr(T$h=2I#`!s_sG%to*{w(&&1gXz zv_(6#M|bFe?n6<!6U~be6HGC~66RRO3f6=ozZF@Fby$z>umPKoT(OZPBn?IRR+NmC zNKVS6LTX4YsU!8IT_`GdqJcEOZzYYm;EEfbaL02fYHmed@CI-34)5_DKH&2WRD29Y z?X4&aS;<CDWG82GAvfff9OtOJ6ZPaBc_7c%SIHwqC`vKPKRNnZztvO!qdtG%pRX1z z7ftV%XtzS&UZNQ+W~`U^JBY&_CpL~@oUJ%8aSGzm#`9V>gs1J_8SLxv@KR4ae0;jj zacQr_h9!j(8WuH4Y*<nup<z*XgoZ_>5gV4YMQB)56QN;IKg5O=nS7-e?E1I!`x3cq zBmC?qrt>h=X&TSR<FD%}>i+#JysqSJC7)LEzLL)?`LdF4R`Tsiz6<$3rw(`O{|Ep8 Dd_vy8 literal 0 HcmV?d00001 diff --git a/openair2/LAYER2/rlc_v2/tests/test9.h b/openair2/LAYER2/rlc_v2/tests/test9.h new file mode 100644 index 00000000000..88e23d94e95 --- /dev/null +++ b/openair2/LAYER2/rlc_v2/tests/test9.h @@ -0,0 +1,34 @@ +/* + * rlc am test function rlc_am_reassemble_next_segment + * case 'if pdu_byte is not in [so .. so+len-1]' + * eNB sends SDU [1..30], not received + * eNB retx with smaller PDUs [1..21] [22..30], not received + * eNB retx with still smaller PDUs [1..11] [12..21] [22..30], not received + * custom PDU [12..21] sent to UE, received + * custom PDU [1..21] sent to UE, received + * + * Not sure if in a real setup [12..21] is sent and then [1..21] is sent. + * In the current RLC implementation, this is impossible. If we send [12..21] + * it means [1..21] has been split and so we won't sent it later on. + * Maybe with HARQ retransmissions in PHY/MAC in bad radio conditions? + * + * this test will fail if NACK mechanism uses SOstart/SOend + * (not implemented for the moment) + */ +TIME, 1, + ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4, + UE_RECV_FAILS, 1, + ENB_RECV_FAILS, 1, + ENB_SDU, 0, 30, +TIME, 2, + ENB_PDU_SIZE, 25, +TIME, 48, + ENB_PDU_SIZE, 15, +TIME, 100, + UE_RECV_FAILS, 0, + ENB_RECV_FAILS, 0, + ENB_PDU, 14, 0xd8, 0x00, 0x00, 0x0b, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, +TIME, 101, + ENB_PDU, 25, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, +TIME, -1 diff --git a/openair2/LAYER2/rlc_v2/tests/test9.txt.gz b/openair2/LAYER2/rlc_v2/tests/test9.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..cc6d934e708e1ddad7286e7c3eec33cd23c91f94 GIT binary patch literal 327 zcmV-N0l5AjiwFpB!rxp119W9`bU7|`cys{0lub*+Kp2GY{S|Z6i_DwN_fgub2u)8S zCE49dp?;8UD*EefQd0;l#cJ$*-<fB2XWwErFLKQ8ZgWVE+UniXnFd#D177EF>rV^C z91kEt0RvEhAsB%%n1CsmfhAah8r%<Ba0MYmAOS={LP!LOAqgafWRMb4K{UiXPKp7< zlYOyuxwXqT)AR&EOHi_dxClp>ctL`w1+i%l@>iUpXX^D7)q1WvtCU@UpJm8Gzuwsy zhN_WYHEdPQQMEcFcovTvT)1znZrt|u8TZr02!ulMDE?O)7PD_hUjzHU$iZplf0eL5 z9Smm<p;UaLAo{lj5tWSI5K-g(jl+HI^^D!DceciSy66|(CHCCW|J3Vx;<uQ@d+FdB Zt*vvbX0!R|Q&@8|`2vfGRlm&z0062KoVWl0 literal 0 HcmV?d00001 diff --git a/openair2/RRC/LTE/rrc_eNB.c b/openair2/RRC/LTE/rrc_eNB.c index dc9183a87d5..b9bf68282f4 100644 --- a/openair2/RRC/LTE/rrc_eNB.c +++ b/openair2/RRC/LTE/rrc_eNB.c @@ -1,3 +1,4 @@ +#define RRC_DEFAULT_RAB_IS_AM 1 /* * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more * contributor license agreements. See the NOTICE file distributed with @@ -2134,6 +2135,8 @@ rrc_eNB_generate_RRCConnectionRelease( { uint8_t buffer[RRC_BUF_SIZE]; uint16_t size = 0; + int release_num; + memset(buffer, 0, RRC_BUF_SIZE); T(T_ENB_RRC_CONNECTION_RELEASE, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); @@ -2161,12 +2164,9 @@ rrc_eNB_generate_RRCConnectionRelease( ue_context_pP->ue_context.rnti, rrc_eNB_mui, size); + pthread_mutex_lock(&rrc_release_freelist); - while (pthread_mutex_trylock(&rrc_release_freelist)) { - /* spin... */ - } - - for (uint16_t release_num = 0; release_num < NUMBER_OF_UE_MAX; release_num++) { + for (release_num = 0; release_num < NUMBER_OF_UE_MAX; release_num++) { if (rrc_release_info.RRC_release_ctrl[release_num].flag == 0) { if (ue_context_pP->ue_context.ue_release_timer_s1 > 0) { rrc_release_info.RRC_release_ctrl[release_num].flag = 1; @@ -2186,6 +2186,12 @@ rrc_eNB_generate_RRCConnectionRelease( } } + /* TODO: what to do if RRC_release_ctrl is full? For now, exit. */ + if (release_num == NUMBER_OF_UE_MAX) { + LOG_E(RRC, "fatal: rrc_release_info.RRC_release_ctrl is full\n"); + exit(1); + } + pthread_mutex_unlock(&rrc_release_freelist); if (NODE_IS_CU(RC.rrc[ctxt_pP->module_id]->node_type)) { @@ -3512,6 +3518,33 @@ void rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt_t size, buffer, PDCP_TRANSMISSION_MODE_CONTROL); + + /* Refresh SRBs/DRBs */ + rrc_pdcp_config_asn1_req(ctxt_pP, + *SRB_configList2, // NULL, + *DRB_configList, + NULL, + 0xff, // already configured during the securitymodecommand + NULL, + NULL, + NULL +#if (LTE_RRC_VERSION >= MAKE_VERSION(9, 0, 0)) + , (LTE_PMCH_InfoList_r9_t *) NULL +#endif + , NULL); + + /* Refresh SRBs/DRBs */ + rrc_rlc_config_asn1_req(ctxt_pP, + *SRB_configList2, // NULL, + *DRB_configList, + NULL +#if (LTE_RRC_VERSION >= MAKE_VERSION(9, 0, 0)) + , (LTE_PMCH_InfoList_r9_t *) NULL, + 0, + 0 +#endif + ); + free(Sparams); Sparams = NULL; free(quantityConfig->quantityConfigEUTRA->filterCoefficientRSRP); @@ -5192,13 +5225,13 @@ rrc_eNB_generate_HO_RRCConnectionReconfiguration(const protocol_ctxt_t *const ct DRB_rlc_config = CALLOC(1, sizeof(*DRB_rlc_config)); DRB_config->rlc_Config = DRB_rlc_config; #ifdef RRC_DEFAULT_RAB_IS_AM - DRB_rlc_config->present = RLC_Config_PR_am; - DRB_rlc_config->choice.am.ul_AM_RLC.t_PollRetransmit = T_PollRetransmit_ms50; - DRB_rlc_config->choice.am.ul_AM_RLC.pollPDU = PollPDU_p16; - DRB_rlc_config->choice.am.ul_AM_RLC.pollByte = PollByte_kBinfinity; - DRB_rlc_config->choice.am.ul_AM_RLC.maxRetxThreshold = UL_AM_RLC__maxRetxThreshold_t8; - DRB_rlc_config->choice.am.dl_AM_RLC.t_Reordering = T_Reordering_ms35; - DRB_rlc_config->choice.am.dl_AM_RLC.t_StatusProhibit = T_StatusProhibit_ms25; + DRB_rlc_config->present = LTE_RLC_Config_PR_am; + DRB_rlc_config->choice.am.ul_AM_RLC.t_PollRetransmit = LTE_T_PollRetransmit_ms50; + DRB_rlc_config->choice.am.ul_AM_RLC.pollPDU = LTE_PollPDU_p16; + DRB_rlc_config->choice.am.ul_AM_RLC.pollByte = LTE_PollByte_kBinfinity; + DRB_rlc_config->choice.am.ul_AM_RLC.maxRetxThreshold = LTE_UL_AM_RLC__maxRetxThreshold_t8; + DRB_rlc_config->choice.am.dl_AM_RLC.t_Reordering = LTE_T_Reordering_ms35; + DRB_rlc_config->choice.am.dl_AM_RLC.t_StatusProhibit = LTE_T_StatusProhibit_ms25; #else DRB_rlc_config->present = LTE_RLC_Config_PR_um_Bi_Directional; DRB_rlc_config->choice.um_Bi_Directional.ul_UM_RLC.sn_FieldLength = LTE_SN_FieldLength_size10; @@ -6029,6 +6062,33 @@ rrc_eNB_generate_HO_RRCConnectionReconfiguration(const protocol_ctxt_t *const ct ue_context_pP->ue_context.rnti, rrc_eNB_mui, size); + + /* Refresh SRBs/DRBs */ + rrc_pdcp_config_asn1_req(ctxt_pP, + *SRB_configList2, // NULL, + *DRB_configList, + NULL, + 0xff, // already configured during the securitymodecommand + NULL, + NULL, + NULL +#if (LTE_RRC_VERSION >= MAKE_VERSION(9, 0, 0)) + , (LTE_PMCH_InfoList_r9_t *) NULL +#endif + , NULL); + + /* Refresh SRBs/DRBs */ + rrc_rlc_config_asn1_req(ctxt_pP, + *SRB_configList2, // NULL, + *DRB_configList, + NULL +#if (LTE_RRC_VERSION >= MAKE_VERSION(9, 0, 0)) + , (LTE_PMCH_InfoList_r9_t *) NULL, + 0, + 0 +#endif + ); + free(quantityConfig->quantityConfigEUTRA->filterCoefficientRSRQ); quantityConfig->quantityConfigEUTRA->filterCoefficientRSRQ = NULL; free(quantityConfig->quantityConfigEUTRA->filterCoefficientRSRP); @@ -8166,6 +8226,143 @@ void rrc_enb_init(void) { memset(&rrc_release_info,0,sizeof(RRC_release_list_t)); } +//----------------------------------------------------------------------------- +void process_successful_rlc_sdu_indication(int instance, + int rnti, + int message_id) +{ + int release_num; + int release_total; + RRC_release_ctrl_t *release_ctrl; + + /* Check if the message sent was RRC Connection Release. + * If yes then continue the release process. + */ + + pthread_mutex_lock(&rrc_release_freelist); + + if (rrc_release_info.num_UEs > 0) { + release_total = 0; + + for (release_num = 0, release_ctrl = &rrc_release_info.RRC_release_ctrl[0]; + release_num < NUMBER_OF_UE_MAX; + release_num++, release_ctrl++) { + if(release_ctrl->flag > 0) { + release_total++; + } else { + continue; + } + + if (release_ctrl->flag == 1 && release_ctrl->rnti == rnti && release_ctrl->rrc_eNB_mui == message_id) { + release_ctrl->flag = 3; + LOG_D(MAC,"DLSCH Release send:index %d rnti %x mui %d flag 1->3\n", + release_num, + rnti, + message_id); + break; + } + + if (release_ctrl->flag == 2 && release_ctrl->rnti == rnti && release_ctrl->rrc_eNB_mui == message_id) { + release_ctrl->flag = 4; + LOG_D(MAC, "DLSCH Release send:index %d rnti %x mui %d flag 2->4\n", + release_num, + rnti, + message_id); + break; + } + + if(release_total >= rrc_release_info.num_UEs) + break; + } + } + + pthread_mutex_unlock(&rrc_release_freelist); +} + +//----------------------------------------------------------------------------- +void process_unsuccessful_rlc_sdu_indication(int instance, int rnti) +{ + int release_num; + int release_total; + RRC_release_ctrl_t *release_ctrl; + + /* radio link failure detected by RLC layer, remove UE properly */ + + pthread_mutex_lock(&rrc_release_freelist); + + /* first, check if the rnti is in the list rrc_release_info.RRC_release_ctrl */ + + if (rrc_release_info.num_UEs > 0) { + release_total = 0; + + for (release_num = 0, release_ctrl = &rrc_release_info.RRC_release_ctrl[0]; + release_num < NUMBER_OF_UE_MAX; + release_num++, release_ctrl++) { + if(release_ctrl->flag > 0) { + release_total++; + } else { + continue; + } + + if (release_ctrl->flag == 1 && release_ctrl->rnti == rnti) { + release_ctrl->flag = 3; + LOG_D(MAC,"DLSCH Release send:index %d rnti %x flag 1->3\n", + release_num, + rnti); + goto done; + } + + if (release_ctrl->flag == 2 && release_ctrl->rnti == rnti) { + release_ctrl->flag = 4; + LOG_D(MAC, "DLSCH Release send:index %d rnti %x flag 2->4\n", + release_num, + rnti); + goto done; + } + + if(release_total >= rrc_release_info.num_UEs) + break; + } + } + + /* it's not in the list, put it with flag = 4 */ + for (release_num = 0; release_num < NUMBER_OF_UE_MAX; release_num++) { + if (rrc_release_info.RRC_release_ctrl[release_num].flag == 0) { + rrc_release_info.RRC_release_ctrl[release_num].flag = 4; + rrc_release_info.RRC_release_ctrl[release_num].rnti = rnti; + rrc_release_info.RRC_release_ctrl[release_num].rrc_eNB_mui = -1; /* not defined */ + rrc_release_info.num_UEs++; + LOG_D(RRC, "radio link failure detected: index %d rnti %x flag %d \n", + release_num, + rnti, + rrc_release_info.RRC_release_ctrl[release_num].flag); + break; + } + } + + /* TODO: what to do if rrc_release_info.RRC_release_ctrl is full? */ + if (release_num == NUMBER_OF_UE_MAX) { + LOG_E(RRC, "fatal: radio link failure: rrc_release_info.RRC_release_ctrl is full\n"); + exit(1); + } + +done: + pthread_mutex_unlock(&rrc_release_freelist); +} + +//----------------------------------------------------------------------------- +void process_rlc_sdu_indication(int instance, + int rnti, + int is_successful, + int srb_id, + int message_id) +{ + if (is_successful) + process_successful_rlc_sdu_indication(instance, rnti, message_id); + else + process_unsuccessful_rlc_sdu_indication(instance, rnti); +} + //----------------------------------------------------------------------------- int add_ue_to_remove(struct rrc_eNB_ue_context_s **ue_to_be_removed, int removed_ue_count, @@ -8868,6 +9065,13 @@ void *rrc_enb_process_itti_msg(void *notUsed) { rrc_eNB_process_M2AP_MCE_CONFIGURATION_UPDATE(&ctxt,&M2AP_MCE_CONFIGURATION_UPDATE(msg_p)); break; + case RLC_SDU_INDICATION: + process_rlc_sdu_indication(instance, + RLC_SDU_INDICATION(msg_p).rnti, + RLC_SDU_INDICATION(msg_p).is_successful, + RLC_SDU_INDICATION(msg_p).srb_id, + RLC_SDU_INDICATION(msg_p).message_id); + break; default: LOG_E(RRC, "[eNB %d] Received unexpected message %s\n", instance, msg_name_p); -- GitLab