Layer 2: send Empty Packet acknowledgements if there’s nothing else to transmit
This commit is contained in:
parent
87eeb045b0
commit
10a869d1a2
|
@ -47,10 +47,25 @@ result_t layer2_rx_handle_packet(layer2_rx_t *ctx, const uint8_t *buf, size_t bu
|
||||||
return ERR_INTEGRITY;
|
return ERR_INTEGRITY;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG(LVL_DEBUG, "Handling packet with rx_seq_nr %u, tx_seq_nr %u.", header.rx_seq_nr, header.tx_seq_nr);
|
LOG(LVL_DEBUG, "Handling %s packet with rx_seq_nr %u, tx_seq_nr %u.",
|
||||||
|
layer2_msg_type_to_string(header.msg_type), header.rx_seq_nr, header.tx_seq_nr);
|
||||||
|
|
||||||
ctx->last_acked_seq = header.rx_seq_nr;
|
ctx->last_acked_seq = header.rx_seq_nr;
|
||||||
|
|
||||||
|
switch(header.msg_type) {
|
||||||
|
case L2_MSG_TYPE_EMPTY:
|
||||||
|
LOG(LVL_DEBUG, "Empty packet: accepted ACK for %u.", ctx->last_acked_seq);
|
||||||
|
return OK; // do not write anything to the TUN device
|
||||||
|
|
||||||
|
case L2_MSG_TYPE_CONN_MGMT:
|
||||||
|
case L2_MSG_TYPE_CONNECTIONLESS:
|
||||||
|
LOG(LVL_WARN, "Message type %s is not implemented yet.", layer2_msg_type_to_string(header.msg_type));
|
||||||
|
return OK;
|
||||||
|
|
||||||
|
case L2_MSG_TYPE_DATA:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if(ctx->next_expected_seq != header.tx_seq_nr) {
|
if(ctx->next_expected_seq != header.tx_seq_nr) {
|
||||||
LOG(LVL_ERR, "Expected sequence number %u, received %u.", ctx->next_expected_seq, header.tx_seq_nr);
|
LOG(LVL_ERR, "Expected sequence number %u, received %u.", ctx->next_expected_seq, header.tx_seq_nr);
|
||||||
return ERR_SEQUENCE;
|
return ERR_SEQUENCE;
|
||||||
|
|
|
@ -94,6 +94,29 @@ result_t layer2_tx_fill_packet_queue(layer2_tx_t *ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
result_t layer2_tx_add_empty_packet(layer2_tx_t *ctx, bool tx_request)
|
||||||
|
{
|
||||||
|
if(packet_queue_get_free_space(&ctx->packet_queue) == 0) {
|
||||||
|
return ERR_NO_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
layer2_packet_header_t header;
|
||||||
|
|
||||||
|
header.dst_addr.addr[0] = 0xFFFF;
|
||||||
|
header.dst_addr.length = 1;
|
||||||
|
header.src_addr.addr[0] = 0x0001;
|
||||||
|
header.src_addr.length = 1;
|
||||||
|
header.msg_type = L2_MSG_TYPE_EMPTY;
|
||||||
|
header.rx_seq_nr = 0; // will be filled in layer2_tx_encode_next_packet()
|
||||||
|
header.tx_seq_nr = 0; // not used in empty packets
|
||||||
|
header.tx_request = tx_request;
|
||||||
|
|
||||||
|
packet_queue_add(&ctx->packet_queue, &header, NULL, 0);
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
size_t layer2_tx_encode_next_packet(layer2_tx_t *ctx, uint8_t ack_seq_nr, uint8_t *buf, size_t buf_len)
|
size_t layer2_tx_encode_next_packet(layer2_tx_t *ctx, uint8_t ack_seq_nr, uint8_t *buf, size_t buf_len)
|
||||||
{
|
{
|
||||||
const packet_queue_entry_t *entry = packet_queue_get(&ctx->packet_queue, ctx->next_packet_index);
|
const packet_queue_entry_t *entry = packet_queue_get(&ctx->packet_queue, ctx->next_packet_index);
|
||||||
|
@ -116,7 +139,10 @@ size_t layer2_tx_encode_next_packet(layer2_tx_t *ctx, uint8_t ack_seq_nr, uint8_
|
||||||
size_t packet_size = layer2_encode_packet_header(&header, buf);
|
size_t packet_size = layer2_encode_packet_header(&header, buf);
|
||||||
|
|
||||||
// add the payload data
|
// add the payload data
|
||||||
|
if(entry->data) {
|
||||||
memcpy(buf + packet_size, entry->data, entry->data_len);
|
memcpy(buf + packet_size, entry->data, entry->data_len);
|
||||||
|
}
|
||||||
|
|
||||||
packet_size += entry->data_len;
|
packet_size += entry->data_len;
|
||||||
|
|
||||||
// calculate CRC of everything and append it to the packet
|
// calculate CRC of everything and append it to the packet
|
||||||
|
@ -155,8 +181,15 @@ void layer2_tx_handle_ack(layer2_tx_t *ctx, uint8_t acked_seq)
|
||||||
|
|
||||||
packet_queue_delete(&ctx->packet_queue, packets_to_remove);
|
packet_queue_delete(&ctx->packet_queue, packets_to_remove);
|
||||||
|
|
||||||
LOG(LVL_DEBUG, "handling ack for seq_nr %u, removing %zu packets, %zu packets remaining.", acked_seq, packets_to_remove, packet_queue_get_used_space(&ctx->packet_queue));
|
packets_available = packet_queue_get_used_space(&ctx->packet_queue);
|
||||||
|
|
||||||
|
LOG(LVL_DEBUG, "handling ack for seq_nr %u, removing %zu packets, %zu packets remaining.", acked_seq, packets_to_remove, packets_available);
|
||||||
|
|
||||||
|
if(packets_available == 0) {
|
||||||
|
// no packets left in queue, but an acknowledgement must be
|
||||||
|
// transmitted. Add an empty packet to do that.
|
||||||
|
layer2_tx_add_empty_packet(ctx, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,12 @@ void layer2_tx_destroy(layer2_tx_t *ctx);
|
||||||
*/
|
*/
|
||||||
result_t layer2_tx_fill_packet_queue(layer2_tx_t *ctx);
|
result_t layer2_tx_fill_packet_queue(layer2_tx_t *ctx);
|
||||||
|
|
||||||
|
/*!\brief Add an empty packet to ensure an acknowledgement is sent.
|
||||||
|
* \param ctx The transmitter context.
|
||||||
|
* \param tx_request Value of the TX Request field in the packet.
|
||||||
|
*/
|
||||||
|
result_t layer2_tx_add_empty_packet(layer2_tx_t *ctx, bool tx_request);
|
||||||
|
|
||||||
/*!\brief Encode the next packet for transmission.
|
/*!\brief Encode the next packet for transmission.
|
||||||
*
|
*
|
||||||
* \note
|
* \note
|
||||||
|
|
|
@ -61,7 +61,11 @@ void packet_queue_delete(packet_queue_t *q, size_t count)
|
||||||
|
|
||||||
packet_queue_entry_t *entry = &q->entries[q->read_idx];
|
packet_queue_entry_t *entry = &q->entries[q->read_idx];
|
||||||
|
|
||||||
|
if(entry->data) {
|
||||||
free(entry->data);
|
free(entry->data);
|
||||||
|
entry->data = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
entry->data_len = 0;
|
entry->data_len = 0;
|
||||||
|
|
||||||
q->read_idx++;
|
q->read_idx++;
|
||||||
|
|
|
@ -72,20 +72,23 @@ bool layer2_decode_packet_header(const uint8_t *encoded, size_t encoded_len, lay
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const char* msg_type_to_string(layer2_message_type_t type)
|
const char* layer2_msg_type_to_string(layer2_message_type_t type)
|
||||||
{
|
{
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case L2_MSG_TYPE_CONNECTIONLESS: return "Connectionless";
|
case L2_MSG_TYPE_CONNECTIONLESS: return "Connectionless";
|
||||||
case L2_MSG_TYPE_DATA: return "Data";
|
case L2_MSG_TYPE_DATA: return "Data";
|
||||||
case L2_MSG_TYPE_CONN_MGMT: return "Connection Management";
|
case L2_MSG_TYPE_CONN_MGMT: return "Connection Management";
|
||||||
|
case L2_MSG_TYPE_EMPTY: return "Empty";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return "!UNHANDLED TYPE!";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void layer2_dump_packet_header(int level, const layer2_packet_header_t *header)
|
void layer2_dump_packet_header(int level, const layer2_packet_header_t *header)
|
||||||
{
|
{
|
||||||
LOG(level, "Packet header dump:");
|
LOG(level, "Packet header dump:");
|
||||||
LOG(level, " Packet type: %s", msg_type_to_string(header->msg_type));
|
LOG(level, " Packet type: %s", layer2_msg_type_to_string(header->msg_type));
|
||||||
LOG(level, " TX Request: %s", header->tx_request ? "true" : "false");
|
LOG(level, " TX Request: %s", header->tx_request ? "true" : "false");
|
||||||
LOG(level, " RX Seq. Nr: %2u", header->rx_seq_nr);
|
LOG(level, " RX Seq. Nr: %2u", header->rx_seq_nr);
|
||||||
LOG(level, " TX Seq. Nr: %2u", header->tx_seq_nr);
|
LOG(level, " TX Seq. Nr: %2u", header->tx_seq_nr);
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
typedef enum {
|
typedef enum {
|
||||||
L2_MSG_TYPE_DATA = 0x0,
|
L2_MSG_TYPE_DATA = 0x0,
|
||||||
L2_MSG_TYPE_CONN_MGMT = 0x1,
|
L2_MSG_TYPE_CONN_MGMT = 0x1,
|
||||||
|
L2_MSG_TYPE_EMPTY = 0x2,
|
||||||
L2_MSG_TYPE_CONNECTIONLESS = 0x4
|
L2_MSG_TYPE_CONNECTIONLESS = 0x4
|
||||||
} layer2_message_type_t;
|
} layer2_message_type_t;
|
||||||
|
|
||||||
|
@ -67,6 +68,10 @@ bool layer2_decode_packet_header(const uint8_t *encoded, size_t encoded_len, lay
|
||||||
*/
|
*/
|
||||||
void layer2_dump_packet_header(int level, const layer2_packet_header_t *header);
|
void layer2_dump_packet_header(int level, const layer2_packet_header_t *header);
|
||||||
|
|
||||||
|
/*!\brief Get a string representation of the given message type.
|
||||||
|
*/
|
||||||
|
const char* layer2_msg_type_to_string(layer2_message_type_t type);
|
||||||
|
|
||||||
/* Data Packet Structs */
|
/* Data Packet Structs */
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|
Loading…
Reference in a new issue