diff --git a/impl/src/layer2/layer2_rx.c b/impl/src/layer2/layer2_rx.c index b96e7e7..2b67379 100644 --- a/impl/src/layer2/layer2_rx.c +++ b/impl/src/layer2/layer2_rx.c @@ -47,10 +47,25 @@ result_t layer2_rx_handle_packet(layer2_rx_t *ctx, const uint8_t *buf, size_t bu 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; + 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) { LOG(LVL_ERR, "Expected sequence number %u, received %u.", ctx->next_expected_seq, header.tx_seq_nr); return ERR_SEQUENCE; diff --git a/impl/src/layer2/layer2_tx.c b/impl/src/layer2/layer2_tx.c index e4d795e..cdcfce3 100644 --- a/impl/src/layer2/layer2_tx.c +++ b/impl/src/layer2/layer2_tx.c @@ -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) { 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); // add the payload data - memcpy(buf + packet_size, entry->data, entry->data_len); + if(entry->data) { + memcpy(buf + packet_size, entry->data, entry->data_len); + } + packet_size += entry->data_len; // 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); - 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); + } } diff --git a/impl/src/layer2/layer2_tx.h b/impl/src/layer2/layer2_tx.h index 58c21f5..e30ddd0 100644 --- a/impl/src/layer2/layer2_tx.h +++ b/impl/src/layer2/layer2_tx.h @@ -32,6 +32,12 @@ void layer2_tx_destroy(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. * * \note diff --git a/impl/src/layer2/packet_queue.c b/impl/src/layer2/packet_queue.c index 27bb021..3e3eb72 100644 --- a/impl/src/layer2/packet_queue.c +++ b/impl/src/layer2/packet_queue.c @@ -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]; - free(entry->data); + if(entry->data) { + free(entry->data); + entry->data = NULL; + } + entry->data_len = 0; q->read_idx++; diff --git a/impl/src/layer2/packet_structs.c b/impl/src/layer2/packet_structs.c index 164f201..ffad7e2 100644 --- a/impl/src/layer2/packet_structs.c +++ b/impl/src/layer2/packet_structs.c @@ -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) { case L2_MSG_TYPE_CONNECTIONLESS: return "Connectionless"; case L2_MSG_TYPE_DATA: return "Data"; 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) { 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, " RX Seq. Nr: %2u", header->rx_seq_nr); LOG(level, " TX Seq. Nr: %2u", header->tx_seq_nr); diff --git a/impl/src/layer2/packet_structs.h b/impl/src/layer2/packet_structs.h index 8a83f2f..1042d4a 100644 --- a/impl/src/layer2/packet_structs.h +++ b/impl/src/layer2/packet_structs.h @@ -12,6 +12,7 @@ typedef enum { L2_MSG_TYPE_DATA = 0x0, L2_MSG_TYPE_CONN_MGMT = 0x1, + L2_MSG_TYPE_EMPTY = 0x2, L2_MSG_TYPE_CONNECTIONLESS = 0x4 } 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); +/*!\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 */ typedef enum {