mac: implement MAC RAR PDU unpacking for NR

* add class for mac_rar_pdu_nr
* extend test case
This commit is contained in:
Andre Puschmann 2021-01-27 20:45:03 +01:00
parent da9e3363f1
commit f88943653b
5 changed files with 414 additions and 10 deletions

View File

@ -0,0 +1,104 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2020 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
#ifndef SRSLTE_MAC_RAR_PDU_NR_H
#define SRSLTE_MAC_RAR_PDU_NR_H
#include "srslte/common/common.h"
#include "srslte/config.h"
#include "srslte/srslog/srslog.h"
#include <memory>
#include <stdint.h>
#include <vector>
namespace srslte {
class mac_rar_pdu_nr;
// 3GPP 38.321 v15.3.0 Sec 6.1.5
class mac_rar_subpdu_nr
{
public:
// Possible types of RAR subpdus (same like EUTRA)
typedef enum { BACKOFF = 0, RAPID } rar_subh_type_t;
mac_rar_subpdu_nr(mac_rar_pdu_nr* parent_);
// RAR content length in bits (38.321 Sec 6.2.3)
static const uint32_t UL_GRANT_NBITS = 27;
static const uint32_t TA_COMMAND_NBITS = 12;
// getter
bool read_subpdu(const uint8_t* ptr);
bool has_more_subpdus();
uint32_t get_total_length();
bool has_rapid();
uint8_t get_rapid();
uint16_t get_temp_crnti();
uint32_t get_ta();
void get_ul_grant(std::array<uint8_t, UL_GRANT_NBITS>& grant);
bool has_backoff();
uint8_t get_backoff();
// setter
uint32_t write_subpdu(const uint8_t* start_);
void set_backoff(const uint8_t backoff_indicator_);
std::string to_string();
private:
int header_length = 1; // RAR PDU subheader is always 1 B
int payload_length = 0; // only used if MAC RAR is included
std::array<uint8_t, UL_GRANT_NBITS> ul_grant = {};
uint16_t ta = 0; // 12bit TA
uint16_t temp_crnti = 0;
uint16_t rapid = 0;
uint8_t backoff_indicator = 0;
rar_subh_type_t type = BACKOFF;
bool E_bit = 0;
srslog::basic_logger& logger;
mac_rar_pdu_nr* parent = nullptr;
};
class mac_rar_pdu_nr
{
public:
mac_rar_pdu_nr();
~mac_rar_pdu_nr() = default;
bool pack();
bool unpack(const uint8_t* payload, const uint32_t& len);
uint32_t get_num_subpdus();
const mac_rar_subpdu_nr& get_subpdu(const uint32_t& index);
uint32_t get_remaining_len();
void set_si_rapid(uint16_t si_rapid_); // configured through SIB1 for on-demand SI request (See 38.331 Sec 5.2.1)
bool has_si_rapid();
std::string to_string();
private:
std::vector<mac_rar_subpdu_nr> subpdus;
uint32_t remaining_len = 0;
uint16_t si_rapid = 0;
bool si_rapid_set = false;
srslog::basic_logger& logger;
};
} // namespace srslte
#endif // SRSLTE_MAC_RAR_PDU_NR_H

View File

@ -9,7 +9,7 @@
SET(SOURCES pdu.cc pdu_queue.cc)
if (ENABLE_5GNR)
set(SOURCES ${SOURCES} mac_sch_pdu_nr.cc)
set(SOURCES ${SOURCES} mac_sch_pdu_nr.cc mac_rar_pdu_nr.cc)
endif(ENABLE_5GNR)
add_library(srslte_mac STATIC ${SOURCES})

View File

@ -0,0 +1,214 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2020 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
#include "srslte/mac/mac_rar_pdu_nr.h"
#include <sstream>
#ifdef __cplusplus
extern "C" {
#include "srslte/phy/utils/bit.h"
#include "srslte/phy/utils/vector.h"
}
#endif
namespace srslte {
mac_rar_subpdu_nr::mac_rar_subpdu_nr(mac_rar_pdu_nr* parent_) :
parent(parent_), logger(srslog::fetch_basic_logger("MAC"))
{}
// Return true if subPDU could be parsed correctly, false otherwise
bool mac_rar_subpdu_nr::read_subpdu(const uint8_t* ptr)
{
E_bit = (bool)(*ptr & 0x80) ? true : false;
type = (*ptr & 0x40) ? RAPID : BACKOFF;
if (type == RAPID) {
rapid = *ptr & 0x3f;
// if PDU is not configured with SI request, extract MAC RAR
if (parent->has_si_rapid() == false) {
const uint32_t MAC_RAR_NBYTES = 7;
if (parent->get_remaining_len() >= MAC_RAR_NBYTES) {
uint8_t* rar = const_cast<uint8_t*>(ptr + 1);
// check reserved bits
if (*rar & 0x80) {
logger.error("Error parsing RAR PDU, reserved bit is set.");
return false;
}
// TA is first 7 bits of 1st + 5 bits of 2nd octet
ta = (uint16_t)(((*(rar + 0) & 0x7f) << 5 | ((*(rar + 1) & 0xf8) >> 3)));
// Extract the first 3 bits of the UL grant from the 2nd octet
ul_grant.at(0) = *(rar + 1) & 0x4 ? 1 : 0;
ul_grant.at(1) = *(rar + 1) & 0x2 ? 1 : 0;
ul_grant.at(2) = *(rar + 1) & 0x1 ? 1 : 0;
// And now the remaining 3 full octets
uint8_t* x = &ul_grant.at(3);
srslte_bit_unpack(*(rar + 2), &x, 8);
srslte_bit_unpack(*(rar + 3), &x, 8);
srslte_bit_unpack(*(rar + 4), &x, 8);
// Temp CRNTI is octet 6 + 7
temp_crnti = ((uint16_t) * (rar + 5)) << 8 | *(rar + 6);
payload_length = MAC_RAR_NBYTES;
} else {
logger.error("Error parsing RAR PDU, remaining bytes not sufficant (%d < %d)",
parent->get_remaining_len(),
MAC_RAR_NBYTES);
return false;
}
}
} else {
// check reserved bits
if (*ptr & 0x10 || *ptr & 0x20) {
logger.error("Error parsing RAR PDU, reserved bit is set.");
return false;
}
backoff_indicator = *ptr & 0xf;
}
return true;
}
// Return true if another subPDU follows after that
bool mac_rar_subpdu_nr::has_more_subpdus()
{
return E_bit;
}
// Section 6.1.2
uint32_t mac_rar_subpdu_nr::write_subpdu(const uint8_t* start_)
{
return 0;
}
uint32_t mac_rar_subpdu_nr::get_total_length()
{
return (header_length + payload_length);
}
bool mac_rar_subpdu_nr::has_rapid()
{
return (type == rar_subh_type_t::RAPID);
}
uint8_t mac_rar_subpdu_nr::get_rapid()
{
return rapid;
}
uint32_t mac_rar_subpdu_nr::get_ta()
{
return ta;
}
uint16_t mac_rar_subpdu_nr::get_temp_crnti()
{
return temp_crnti;
}
bool mac_rar_subpdu_nr::has_backoff()
{
return (type == rar_subh_type_t::BACKOFF);
}
void mac_rar_subpdu_nr::set_backoff(const uint8_t backoff_indicator_)
{
backoff_indicator = backoff_indicator_;
}
void mac_rar_subpdu_nr::get_ul_grant(std::array<uint8_t, UL_GRANT_NBITS>& grant_)
{
grant_ = ul_grant;
}
std::string mac_rar_subpdu_nr::to_string()
{
std::stringstream ss;
if (has_rapid()) {
ss << "RAPID: " << rapid << ", Temp C-RNTI: " << temp_crnti << ", TA: " << ta << ", UL Grant: ";
} else {
ss << "Backoff Indicator: " << backoff_indicator << " ";
}
char tmp[16] = {};
srslte_vec_sprint_hex(tmp, sizeof(tmp), ul_grant.data(), UL_GRANT_NBITS);
ss << tmp;
return ss.str();
}
mac_rar_pdu_nr::mac_rar_pdu_nr() : logger(srslog::fetch_basic_logger("MAC")) {}
bool mac_rar_pdu_nr::pack()
{
// not implemented yet
return false;
}
bool mac_rar_pdu_nr::has_si_rapid()
{
return si_rapid_set;
}
void mac_rar_pdu_nr::set_si_rapid(uint16_t si_rapid_)
{
si_rapid = si_rapid_;
si_rapid_set = true;
}
// Return true if PDU could be parsed successfully
bool mac_rar_pdu_nr::unpack(const uint8_t* payload, const uint32_t& len)
{
bool ret = false;
bool have_more_subpdus = false;
uint32_t offset = 0;
remaining_len = len;
do {
mac_rar_subpdu_nr rar_subpdu(this);
ret = rar_subpdu.read_subpdu(payload + offset);
have_more_subpdus = rar_subpdu.has_more_subpdus();
offset += rar_subpdu.get_total_length();
remaining_len -= rar_subpdu.get_total_length();
// only append if subPDU could be read successfully
if (ret == true) {
subpdus.push_back(rar_subpdu);
}
// continue reading as long as subPDUs can be extracted ok and we are not overrunning the PDU length
} while (ret && have_more_subpdus && offset <= len);
return ret;
}
uint32_t mac_rar_pdu_nr::get_num_subpdus()
{
return subpdus.size();
}
const mac_rar_subpdu_nr& mac_rar_pdu_nr::get_subpdu(const uint32_t& index)
{
return subpdus.at(index);
}
uint32_t mac_rar_pdu_nr::get_remaining_len()
{
return remaining_len;
}
std::string mac_rar_pdu_nr::to_string()
{
std::stringstream ss;
for (auto& subpdu : subpdus) {
ss << subpdu.to_string() << " ";
}
return ss.str();
}
} // namespace srslte

View File

@ -16,6 +16,6 @@ add_test(mac_pcap_test mac_pcap_test)
if (ENABLE_5GNR)
add_executable(mac_pdu_nr_test mac_pdu_nr_test.cc)
target_link_libraries(mac_pdu_nr_test srslte_phy srslte_mac srslte_common ${CMAKE_THREAD_LIBS_INIT})
target_link_libraries(mac_pdu_nr_test srslte_mac srslte_common ${CMAKE_THREAD_LIBS_INIT})
add_test(mac_pdu_nr_test mac_pdu_nr_test)
endif (ENABLE_5GNR)

View File

@ -12,7 +12,9 @@
#include "srslte/common/log_filter.h"
#include "srslte/common/mac_nr_pcap.h"
#include "srslte/common/test_common.h"
#include "srslte/config.h"
#include "srslte/mac/mac_rar_pdu_nr.h"
#include "srslte/mac/mac_sch_pdu_nr.h"
#include <array>
@ -20,14 +22,6 @@
#include <memory>
#include <vector>
#define TESTASSERT(cond) \
{ \
if (!(cond)) { \
std::cout << "[" << __FUNCTION__ << "][Line " << __LINE__ << "]: FAIL at " << (#cond) << std::endl; \
return -1; \
} \
}
#define PCAP 0
#define PCAP_CRNTI (0x1001)
#define PCAP_TTI (666)
@ -260,6 +254,88 @@ int mac_dl_sch_pdu_unpack_test6()
return SRSLTE_SUCCESS;
}
int mac_rar_pdu_unpack_test7()
{
// MAC PDU with RAR PDU with single RAPID=0
// rapid=0
// ta=180
// ul_grant:
// hopping_flag=0
// riv=0x1
// time_domain_rsc=1
// mcs=4
// tpc_command=3
// csi_request=0
// tc-rnti=0x4616
// Bit 1-8
// | | | | | | | | |
// | R |T=1| RAPID=0 | Octet 1
// | RAR | Octet 2-8
const uint32_t tv_rapid = 0;
const uint32_t tv_ta = 180;
const uint16_t tv_tcrnti = 0x4616;
const uint8_t tv_msg3_grant[mac_rar_subpdu_nr::UL_GRANT_NBITS] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00}; // unpacked UL grant
uint8_t mac_dl_rar_pdu[] = {0x40, 0x05, 0xa0, 0x00, 0x11, 0x46, 0x46, 0x16, 0x00, 0x00, 0x00};
if (pcap_handle) {
pcap_handle->write_dl_ra_rnti(mac_dl_rar_pdu, sizeof(mac_dl_rar_pdu), 0x0016, true, PCAP_TTI);
}
srslte::mac_rar_pdu_nr pdu;
TESTASSERT(pdu.unpack(mac_dl_rar_pdu, sizeof(mac_dl_rar_pdu)) == true);
std::cout << pdu.to_string() << std::endl;
TESTASSERT(pdu.get_num_subpdus() == 1);
mac_rar_subpdu_nr subpdu = pdu.get_subpdu(0);
TESTASSERT(subpdu.has_rapid() == true);
TESTASSERT(subpdu.has_backoff() == false);
TESTASSERT(subpdu.get_temp_crnti() == tv_tcrnti);
TESTASSERT(subpdu.get_ta() == tv_ta);
TESTASSERT(subpdu.get_rapid() == tv_rapid);
std::array<uint8_t, mac_rar_subpdu_nr::UL_GRANT_NBITS> msg3_grant;
subpdu.get_ul_grant(msg3_grant);
TESTASSERT(memcmp(msg3_grant.data(), tv_msg3_grant, msg3_grant.size()) == 0);
return SRSLTE_SUCCESS;
}
int mac_rar_pdu_unpack_test8()
{
// Malformed MAC PDU, says it has RAR PDU but is too short to include MAC RAR
// Bit 1-8
// | | | | | | | | |
// | E |T=1| RAPID=0 | Octet 1
// | RAR_fragment | Octet 2
uint8_t mac_dl_rar_pdu[] = {0x40, 0x05};
if (pcap_handle) {
pcap_handle->write_dl_ra_rnti(mac_dl_rar_pdu, sizeof(mac_dl_rar_pdu), 0x0016, true, PCAP_TTI);
}
// unpacking should fail
srslte::mac_rar_pdu_nr pdu;
TESTASSERT(pdu.unpack(mac_dl_rar_pdu, sizeof(mac_dl_rar_pdu)) == false);
TESTASSERT(pdu.get_num_subpdus() == 0);
// Malformed PDU with reserved bits set
// Bit 1-8
// | | | | | | | | |
// | E |T=0| R | R | BI | Octet 1
uint8_t mac_dl_rar_pdu2[] = {0x10};
TESTASSERT(pdu.unpack(mac_dl_rar_pdu2, sizeof(mac_dl_rar_pdu2)) == false);
TESTASSERT(pdu.get_num_subpdus() == 0);
return SRSLTE_SUCCESS;
}
int mac_ul_sch_pdu_unpack_test1()
{
// UL-SCH MAC PDU with fixed-size CE and DL-SCH subheader with 16-bit length field
@ -498,6 +574,16 @@ int main(int argc, char** argv)
return SRSLTE_ERROR;
}
if (mac_rar_pdu_unpack_test7()) {
fprintf(stderr, "mac_rar_pdu_unpack_test7() failed.\n");
return SRSLTE_ERROR;
}
if (mac_rar_pdu_unpack_test8()) {
fprintf(stderr, "mac_rar_pdu_unpack_test8() failed.\n");
return SRSLTE_ERROR;
}
if (mac_ul_sch_pdu_unpack_test1()) {
fprintf(stderr, "mac_ul_sch_pdu_unpack_test1() failed.\n");
return SRSLTE_ERROR;