From f7a0186f4fd1827aa379a23097ed5a6eb093e26a Mon Sep 17 00:00:00 2001 From: Thomas Kolb Date: Sun, 23 Feb 2025 13:55:03 +0100 Subject: [PATCH] test_connection: test packet queue and (re)transmission --- impl/test/unittest/test_connection.c | 196 +++++++++++++++++++++++++++ 1 file changed, 196 insertions(+) diff --git a/impl/test/unittest/test_connection.c b/impl/test/unittest/test_connection.c index a119d5d..46688cf 100644 --- a/impl/test/unittest/test_connection.c +++ b/impl/test/unittest/test_connection.c @@ -3,6 +3,7 @@ #include "layer2/packet_queue.h" #include "layer2/packet_structs.h" +#include "results.h" #include "utils.h" #include "config.h" @@ -312,5 +313,200 @@ int main(void) expected_state.next_expected_seq = 3; ASSERT_STATE(expected_state, conn); + LOG(LVL_INFO, ">>> Checking packet transmission."); + + LOG(LVL_INFO, "Enqueueing 8 packets and checking that they are transmitted correctly."); + + // prepare 200 static bytes of payload data (starts at index 1). + // the first byte is used as a counter. + for(size_t i = 0; i < 200; i++) { + static_payload[i+1] = i; + } + + // enqueue 8 packets + for(size_t i = 0; i < 8; i++) { + payload_len = 201; + static_payload[0] = i; + + ASSERT_RESULT(OK, connection_enqueue_data_packet(&conn, L2_PAYLOAD_TYPE_IPV6, static_payload, payload_len)); + } + + // "transmit" these 8 packets + for(size_t i = 0; i < 8; i++) { + ASSERT_TRUE(connection_can_transmit(&conn)); + + packet_len = connection_encode_next_packet(&conn, packet_buf, sizeof(packet_buf), &end_burst); + ASSERT_EQUAL_UINT(214, packet_len); + + bool header_decoded_ok = layer2_decode_packet_header(packet_buf, packet_len, &header); + ASSERT_TRUE(header_decoded_ok); + + LOG(LVL_DUMP, "Header of supposed data packet:"); + layer2_dump_packet_header(LVL_DUMP, &header); + + // check the header + if(i == 7) { + ASSERT_TRUE(header.tx_request); + } else { + ASSERT_FALSE(header.tx_request); + } + + ASSERT_EQUAL_UINT(3, header.rx_seq_nr); + ASSERT_EQUAL_UINT(i, header.tx_seq_nr); + } + + ASSERT_FALSE(connection_can_transmit(&conn)); + + // no packet must be returned + packet_len = connection_encode_next_packet(&conn, packet_buf, sizeof(packet_buf), &end_burst); + ASSERT_EQUAL_UINT(0, packet_len); + + expected_state.next_seq_nr = 8; + expected_state.next_packet_index = 8; + + ASSERT_STATE(expected_state, conn); + + LOG(LVL_INFO, "Acknowledging up to packet #6 -> #7 must be retransmitted"); + + // build empty ACK packet + header.dst_addr = dut_address; + header.src_addr = peer_address; + header.msg_type = L2_MSG_TYPE_EMPTY; + header.rx_seq_nr = 7; + header.tx_seq_nr = 0; + header.tx_request = 1; + + packet_len = layer2_encode_packet(&header, NULL, 0, packet_buf, sizeof(packet_buf)); + ASSERT_EQUAL_UINT(12, packet_len); + + ASSERT_RESULT(OK, connection_handle_packet(&conn, packet_buf, packet_len, &data_packet, &tx_req_rcvd)); + + // next packet index must change because packets were removed from the queue + expected_state.next_packet_index = 1; + expected_state.last_acked_seq = 7; + + ASSERT_STATE(expected_state, conn); + + // reset the transmitter + connection_restart_tx(&conn); + expected_state.next_packet_index = 0; + + ASSERT_STATE(expected_state, conn); + + // verify that the next encoded packet is indeed the one with sequence number 7 + ASSERT_TRUE(connection_can_transmit(&conn)); + + packet_len = connection_encode_next_packet(&conn, packet_buf, sizeof(packet_buf), &end_burst); + ASSERT_EQUAL_UINT(214, packet_len); + + ASSERT_FALSE(connection_can_transmit(&conn)); + + header_decoded_ok = layer2_decode_packet_header(packet_buf, packet_len, &header); + ASSERT_TRUE(header_decoded_ok); + + LOG(LVL_DUMP, "Header of supposed data packet #7:"); + layer2_dump_packet_header(LVL_DUMP, &header); + + // check the header + ASSERT_TRUE(header.tx_request); + ASSERT_EQUAL_UINT(3, header.rx_seq_nr); + ASSERT_EQUAL_UINT(7, header.tx_seq_nr); + + // check the payload + header_size = layer2_get_encoded_header_size(&header); + payload_len = packet_len - header_size - crc_size; + payload = packet_buf + header_size; + + ASSERT_EQUAL_UINT(L2_PAYLOAD_TYPE_IPV6, payload[0]); + ASSERT_EQUAL_UINT(7, payload[1]); + + // enqueue 10 more packets to test the sequence number overflow. + for(size_t i = 0; i < 10; i++) { + payload_len = 201; + static_payload[0] = i; + + ASSERT_RESULT(OK, connection_enqueue_data_packet(&conn, L2_PAYLOAD_TYPE_IPV6, static_payload, payload_len)); + } + + ASSERT_TRUE(connection_can_transmit(&conn)); + + expected_state.next_seq_nr = 2; + expected_state.next_packet_index = 1; + + ASSERT_STATE(expected_state, conn); + + // transmitter was NOT reset, so #7 remains in the queue, but is not transmitted again. + // Only 10 packets should be "transmitted" before the burst ends. + for(size_t i = 0; i < 10; i++) { + ASSERT_TRUE(connection_can_transmit(&conn)); + + packet_len = connection_encode_next_packet(&conn, packet_buf, sizeof(packet_buf), &end_burst); + ASSERT_EQUAL_UINT(214, packet_len); + + bool header_decoded_ok = layer2_decode_packet_header(packet_buf, packet_len, &header); + ASSERT_TRUE(header_decoded_ok); + + // check the header + if(i == 9) { + ASSERT_TRUE(header.tx_request); + } else { + ASSERT_FALSE(header.tx_request); + } + + ASSERT_EQUAL_UINT(3, header.rx_seq_nr); + ASSERT_EQUAL_UINT((i+8)%16, header.tx_seq_nr); + } + + ASSERT_FALSE(connection_can_transmit(&conn)); + + expected_state.next_packet_index = 11; + + ASSERT_STATE(expected_state, conn); + + LOG(LVL_INFO, "Queue overflow test:"); + + // nothing has been acknowledged so far, so we have 11 packets in the queue. + // It must be possible to add 4 more packets, but the 5th must fail. + + // enqueue 5 more packets to test queue full checks. + for(size_t i = 0; i < 5; i++) { + payload_len = 201; + static_payload[0] = i; + + LOG(LVL_DEBUG, "Trying to add %dth entry (15 max) to queue:", i+12); + result_t result = connection_enqueue_data_packet(&conn, L2_PAYLOAD_TYPE_IPV6, static_payload, payload_len); + if(i < 4) { + ASSERT_RESULT(OK, result); + } else { + ASSERT_RESULT(ERR_NO_MEM, result); + } + } + + expected_state.next_seq_nr += 4; + + ASSERT_STATE(expected_state, conn); + + LOG(LVL_INFO, "Acknowledging all packets"); + + // build empty ACK packet + header.dst_addr = dut_address; + header.src_addr = peer_address; + header.msg_type = L2_MSG_TYPE_EMPTY; + header.rx_seq_nr = 6; + header.tx_seq_nr = 0; + header.tx_request = 1; + + packet_len = layer2_encode_packet(&header, NULL, 0, packet_buf, sizeof(packet_buf)); + ASSERT_EQUAL_UINT(12, packet_len); + + ASSERT_RESULT(OK, connection_handle_packet(&conn, packet_buf, packet_len, &data_packet, &tx_req_rcvd)); + + expected_state.next_packet_index = 0; + expected_state.last_acked_seq = 6; + + ASSERT_STATE(expected_state, conn); + + // TODO: test connection close sequence + LOG(LVL_INFO, ">>> All assertions successful."); }