mirror of https://github.com/PentHertz/srsLTE.git
nas: add support ot UE test loop mode B
extend GW-NAS interface to signal test mode activation. The method is a noop in the normal GW but is implemented in the TTCN3 DUT according to TS 36.509 for Mode B
This commit is contained in:
parent
66a799661e
commit
d35c9e2b89
|
@ -4007,6 +4007,17 @@ liblte_mme_unpack_pdn_disconnect_request_msg(LIBLTE_BYTE_MSG_STRUCT*
|
|||
LIBLTE_ERROR_ENUM
|
||||
liblte_mme_pack_activate_test_mode_complete_msg(LIBLTE_BYTE_MSG_STRUCT* msg, uint8 sec_hdr_type, uint32 count);
|
||||
|
||||
// UE test mode type
|
||||
typedef enum {
|
||||
LIBLTE_MME_UE_TEST_LOOP_MODE_A = 0,
|
||||
LIBLTE_MME_UE_TEST_LOOP_MODE_B,
|
||||
LIBLTE_MME_UE_TEST_LOOP_MODE_C,
|
||||
LIBLTE_MME_UE_TEST_LOOP_MODE_N_ITEMS,
|
||||
} LIBLTE_MME_UE_TEST_LOOP_MODE_ENUM;
|
||||
static const char liblte_ue_test_loop_mode_text[LIBLTE_MME_UE_TEST_LOOP_MODE_N_ITEMS][20] = {"UE test loop mode A",
|
||||
"UE test loop mode B",
|
||||
"UE test loop mode C"};
|
||||
|
||||
/*********************************************************************
|
||||
Message Name: CLOSE UE TEST LOOP COMPLETE
|
||||
|
||||
|
|
|
@ -89,6 +89,20 @@ public:
|
|||
virtual int apply_traffic_flow_template(const uint8_t& eps_bearer_id,
|
||||
const uint8_t& lcid,
|
||||
const LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_STRUCT* tft) = 0;
|
||||
|
||||
typedef enum {
|
||||
TEST_LOOP_INACTIVE = 0,
|
||||
TEST_LOOP_MODE_A_ACTIVE,
|
||||
TEST_LOOP_MODE_B_ACTIVE,
|
||||
TEST_LOOP_MODE_C_ACTIVE
|
||||
} test_loop_mode_state_t;
|
||||
|
||||
/**
|
||||
* Updates the test loop mode. The IP delay parameter is only valid for Mode B.
|
||||
* @param mode
|
||||
* @param ip_pdu_delay_ms The PDU delay in ms
|
||||
*/
|
||||
virtual void set_test_loop_mode(const test_loop_mode_state_t mode, const uint32_t ip_pdu_delay_ms = 0) = 0;
|
||||
};
|
||||
|
||||
// GW interface for RRC
|
||||
|
|
|
@ -63,6 +63,7 @@ public:
|
|||
int apply_traffic_flow_template(const uint8_t& eps_bearer_id,
|
||||
const uint8_t& lcid,
|
||||
const LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_STRUCT* tft);
|
||||
void set_test_loop_mode(const test_loop_mode_state_t mode, const uint32_t ip_pdu_delay_ms);
|
||||
|
||||
// RRC interface
|
||||
void add_mch_port(uint32_t lcid, uint32_t port);
|
||||
|
|
|
@ -192,6 +192,11 @@ int gw::apply_traffic_flow_template(const uint8_t&
|
|||
return tft_matcher.apply_traffic_flow_template(erab_id, lcid, tft);
|
||||
}
|
||||
|
||||
void gw::set_test_loop_mode(const test_loop_mode_state_t mode, const uint32_t ip_pdu_delay_ms)
|
||||
{
|
||||
log.error("UE test loop mode not supported\n");
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
RRC interface
|
||||
*******************************************************************************/
|
||||
|
|
|
@ -700,6 +700,8 @@ void nas::write_pdu(uint32_t lcid, unique_byte_buffer_t pdu)
|
|||
// TODO: Handle deactivate test mode and ue open test loop
|
||||
case LIBLTE_MME_MSG_TYPE_OPEN_UE_TEST_LOOP:
|
||||
case LIBLTE_MME_MSG_TYPE_DEACTIVATE_TEST_MODE:
|
||||
gw->set_test_loop_mode(gw_interface_nas::TEST_LOOP_INACTIVE);
|
||||
break;
|
||||
default:
|
||||
nas_log->error("Not handling NAS message with MSG_TYPE=%02X\n", msg_type);
|
||||
return;
|
||||
|
@ -1678,12 +1680,24 @@ void nas::parse_activate_test_mode(uint32_t lcid, unique_byte_buffer_t pdu)
|
|||
|
||||
void nas::parse_close_ue_test_loop(uint32_t lcid, unique_byte_buffer_t pdu)
|
||||
{
|
||||
nas_log->info("Received Close UE test loop\n");
|
||||
LIBLTE_MME_UE_TEST_LOOP_MODE_ENUM mode = static_cast<LIBLTE_MME_UE_TEST_LOOP_MODE_ENUM>(pdu->msg[8]);
|
||||
nas_log->info("Received Close UE test loop for %s\n", liblte_ue_test_loop_mode_text[mode]);
|
||||
switch (mode) {
|
||||
case LIBLTE_MME_UE_TEST_LOOP_MODE_A:
|
||||
gw->set_test_loop_mode(gw_interface_nas::TEST_LOOP_MODE_A_ACTIVE);
|
||||
break;
|
||||
case LIBLTE_MME_UE_TEST_LOOP_MODE_B:
|
||||
gw->set_test_loop_mode(gw_interface_nas::TEST_LOOP_MODE_B_ACTIVE, pdu->msg[9] * 1000);
|
||||
break;
|
||||
case LIBLTE_MME_UE_TEST_LOOP_MODE_C:
|
||||
gw->set_test_loop_mode(gw_interface_nas::TEST_LOOP_MODE_C_ACTIVE);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ctxt.rx_count++;
|
||||
|
||||
// TODO: Save the test loop mode
|
||||
|
||||
send_close_ue_test_loop_complete();
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
class ttcn3_ue : public phy_interface_syssim, public gw_interface_stack
|
||||
{
|
||||
public:
|
||||
ttcn3_ue() {}
|
||||
ttcn3_ue() : tft_matcher(&log) {}
|
||||
|
||||
virtual ~ttcn3_ue() {}
|
||||
|
||||
|
@ -133,14 +133,95 @@ public:
|
|||
|
||||
// GW interface
|
||||
void add_mch_port(uint32_t lcid, uint32_t port) {}
|
||||
void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu) {}
|
||||
void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu)
|
||||
{
|
||||
log.debug_hex(pdu->msg, pdu->N_bytes, "Rx PDU (%d B) on lcid=%d\n", pdu->N_bytes, lcid);
|
||||
switch (test_loop_mode) {
|
||||
case TEST_LOOP_INACTIVE:
|
||||
log.warning("Test loop inactive. Dropping PDU.\n");
|
||||
break;
|
||||
case TEST_LOOP_MODE_A_ACTIVE:
|
||||
log.error("Test loop mode A not implemented. Dropping PDU.\n");
|
||||
break;
|
||||
case TEST_LOOP_MODE_B_ACTIVE:
|
||||
// Section 5.4.4 in TS 36.509
|
||||
if (pdu_delay_timer.is_running()) {
|
||||
pdu_queue[lcid].push(std::move(pdu));
|
||||
} else {
|
||||
if (pdu_delay_timer.is_valid()) {
|
||||
pdu_queue[lcid].push(std::move(pdu));
|
||||
pdu_delay_timer.run(); // timer is already set
|
||||
} else {
|
||||
loop_back_pdu_with_tft(lcid, std::move(pdu));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TEST_LOOP_MODE_C_ACTIVE:
|
||||
log.error("Test loop mode C not implemented. Dropping PDU.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
void write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t pdu) {}
|
||||
int setup_if_addr(uint32_t lcid, uint8_t pdn_type, uint32_t ip_addr, uint8_t* ipv6_if_id, char* err_str) { return 0; }
|
||||
|
||||
int apply_traffic_flow_template(const uint8_t& eps_bearer_id,
|
||||
const uint8_t& lcid,
|
||||
const LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_STRUCT* tft)
|
||||
{
|
||||
return 0;
|
||||
return tft_matcher.apply_traffic_flow_template(eps_bearer_id, lcid, tft);
|
||||
}
|
||||
|
||||
void set_test_loop_mode(const test_loop_mode_state_t mode, const uint32_t ip_pdu_delay_ms_ = 0)
|
||||
{
|
||||
test_loop_mode = mode;
|
||||
switch (test_loop_mode) {
|
||||
case TEST_LOOP_INACTIVE:
|
||||
// deactivate timer
|
||||
log.info("Deactivating Test Loop Mode\n");
|
||||
pdu_delay_timer.release();
|
||||
break;
|
||||
case TEST_LOOP_MODE_A_ACTIVE:
|
||||
log.error("Test loop mode A not implemented\n");
|
||||
break;
|
||||
case TEST_LOOP_MODE_B_ACTIVE:
|
||||
log.info("Activating Test loop mode B with %d ms PDU delay\n", ip_pdu_delay_ms_);
|
||||
// only create timer if needed
|
||||
if (ip_pdu_delay_ms_ > 0) {
|
||||
pdu_delay_timer = stack->get_unique_timer();
|
||||
pdu_delay_timer.set(ip_pdu_delay_ms_, [this](uint32_t tid) { timer_expired(tid); });
|
||||
}
|
||||
break;
|
||||
case TEST_LOOP_MODE_C_ACTIVE:
|
||||
log.error("Test loop mode A not implemented\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void timer_expired(uint32_t timeout_id)
|
||||
{
|
||||
if (timeout_id == pdu_delay_timer.id()) {
|
||||
log.info("Testmode B PDU delay timer expired\n");
|
||||
for (auto& bearer_pdu_queue : pdu_queue) {
|
||||
log.info("Delivering %zd buffered PDUs for LCID=%d\n", bearer_pdu_queue.second.size(), bearer_pdu_queue.first);
|
||||
while (not pdu_queue.empty()) {
|
||||
srslte::unique_byte_buffer_t pdu;
|
||||
bearer_pdu_queue.second.try_pop(&pdu);
|
||||
loop_back_pdu_with_tft(bearer_pdu_queue.first, std::move(pdu));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loop_back_pdu_with_tft(uint32_t input_lcid, srslte::unique_byte_buffer_t pdu)
|
||||
{
|
||||
uint8_t output_lcid = tft_matcher.check_tft_filter_match(pdu);
|
||||
log.info_hex(pdu->msg,
|
||||
pdu->N_bytes,
|
||||
"Rx PDU (%d B) on lcid=%d, looping back to lcid=%d\n",
|
||||
pdu->N_bytes,
|
||||
input_lcid,
|
||||
output_lcid);
|
||||
stack->write_sdu(input_lcid, std::move(pdu), false);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -151,6 +232,11 @@ private:
|
|||
srslte::logger* logger = nullptr;
|
||||
srslte::log_filter log; // Own logger for UE
|
||||
|
||||
test_loop_mode_state_t test_loop_mode = TEST_LOOP_INACTIVE;
|
||||
srslte::timer_handler::unique_timer pdu_delay_timer;
|
||||
std::map<uint32_t, block_queue<srslte::unique_byte_buffer_t> > pdu_queue; // A PDU queue for each DRB
|
||||
tft_pdu_matcher tft_matcher;
|
||||
|
||||
all_args_t args = {};
|
||||
};
|
||||
|
||||
|
|
|
@ -196,6 +196,7 @@ class gw_dummy : public gw_interface_nas, public gw_interface_pdcp
|
|||
}
|
||||
void write_pdu(uint32_t lcid, unique_byte_buffer_t pdu) {}
|
||||
void write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t sdu) {}
|
||||
void set_test_loop_mode(const test_loop_mode_state_t mode, const uint32_t ip_pdu_delay_ms = 0) {}
|
||||
};
|
||||
|
||||
} // namespace srslte
|
||||
|
|
Loading…
Reference in New Issue