Multiple fixes in packet handling
- add and handle layer 2 packet type correctly in data packets - don't produce garbage packets if a packet could not be decoded or was not a data packet - handle beacon/connection request/connection parameters handshake - digipeater cycle timeout does not reset beacon timer anymore. This prevented any beacon transmission. - Reset the connection timeout when empty packets are received
This commit is contained in:
parent
f85bb7f83e
commit
d77f4d4498
|
@ -100,6 +100,9 @@ result_t connection_handle_packet(connection_ctx_t *ctx, const uint8_t *buf, siz
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data_packet->payload_type = L2_PAYLOAD_TYPE_INVALID;
|
||||||
|
data_packet->payload_len = 0;
|
||||||
|
|
||||||
// check the CRC
|
// check the CRC
|
||||||
size_t packet_size = buf_len - crc_sizeof_key(PAYLOAD_CRC_SCHEME);
|
size_t packet_size = buf_len - crc_sizeof_key(PAYLOAD_CRC_SCHEME);
|
||||||
|
|
||||||
|
@ -122,7 +125,8 @@ result_t connection_handle_packet(connection_ctx_t *ctx, const uint8_t *buf, siz
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!ham64_is_equal(&header.dst_addr, &ctx->my_addr)) {
|
if(ham64_get_addr_type(&header.dst_addr) != HAM64_ADDR_TYPE_BROADCAST
|
||||||
|
&& !ham64_is_equal(&header.dst_addr, &ctx->my_addr)) {
|
||||||
char fmt_dst_addr[HAM64_FMT_MAX_LEN];
|
char fmt_dst_addr[HAM64_FMT_MAX_LEN];
|
||||||
char fmt_my_addr[HAM64_FMT_MAX_LEN];
|
char fmt_my_addr[HAM64_FMT_MAX_LEN];
|
||||||
|
|
||||||
|
@ -157,7 +161,8 @@ static result_t handle_conn_mgmt(
|
||||||
|
|
||||||
uint8_t packet_type = payload[0];
|
uint8_t packet_type = payload[0];
|
||||||
|
|
||||||
if(packet_type == CONN_MGMT_TYPE_BEACON) {
|
switch(packet_type) {
|
||||||
|
case CONN_MGMT_TYPE_BEACON:
|
||||||
if(ctx->conn_state == CONN_STATE_CONNECTING) {
|
if(ctx->conn_state == CONN_STATE_CONNECTING) {
|
||||||
LOG(LVL_INFO, "Received beacon; queueing connection request.");
|
LOG(LVL_INFO, "Received beacon; queueing connection request.");
|
||||||
|
|
||||||
|
@ -180,6 +185,17 @@ static result_t handle_conn_mgmt(
|
||||||
LOG(LVL_WARN, "Beacons are ignored in states other than CONNECTING.");
|
LOG(LVL_WARN, "Beacons are ignored in states other than CONNECTING.");
|
||||||
return ERR_INVALID_STATE;
|
return ERR_INVALID_STATE;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CONN_MGMT_TYPE_CONNECTION_PARAMETERS:
|
||||||
|
LOG(LVL_INFO, "Connection parameters received! -> connection established");
|
||||||
|
ctx->next_expected_seq = 1; // connection parameters are packet 0
|
||||||
|
ctx->conn_state = CONN_STATE_ESTABLISHED;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
LOG(LVL_WARN, "Ignored connection management type %d", packet_type);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
|
@ -231,6 +247,10 @@ result_t connection_handle_packet_prechecked(
|
||||||
switch(header->msg_type) {
|
switch(header->msg_type) {
|
||||||
case L2_MSG_TYPE_EMPTY:
|
case L2_MSG_TYPE_EMPTY:
|
||||||
LOG(LVL_DEBUG, "Empty packet: accepted ACK for %u.", ctx->last_acked_seq);
|
LOG(LVL_DEBUG, "Empty packet: accepted ACK for %u.", ctx->last_acked_seq);
|
||||||
|
|
||||||
|
// empty packets also reset the timeout timer
|
||||||
|
ctx->last_rx_time = get_hires_time();
|
||||||
|
|
||||||
// handle the acknowledgement internally
|
// handle the acknowledgement internally
|
||||||
connection_handle_ack(ctx, header->rx_seq_nr, false);
|
connection_handle_ack(ctx, header->rx_seq_nr, false);
|
||||||
return OK; // do not ACK
|
return OK; // do not ACK
|
||||||
|
@ -318,7 +338,11 @@ result_t connection_enqueue_packet(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
result_t connection_enqueue_data_packet(connection_ctx_t *ctx, uint8_t *buf, size_t buf_len)
|
result_t connection_enqueue_data_packet(
|
||||||
|
connection_ctx_t *ctx,
|
||||||
|
layer2_payload_type_t payload_type,
|
||||||
|
uint8_t *buf,
|
||||||
|
size_t buf_len)
|
||||||
{
|
{
|
||||||
// check the connection state
|
// check the connection state
|
||||||
switch(ctx->conn_state) {
|
switch(ctx->conn_state) {
|
||||||
|
@ -343,7 +367,12 @@ result_t connection_enqueue_data_packet(connection_ctx_t *ctx, uint8_t *buf, siz
|
||||||
header.tx_request = 0;
|
header.tx_request = 0;
|
||||||
header.tx_seq_nr = ctx->next_seq_nr;
|
header.tx_seq_nr = ctx->next_seq_nr;
|
||||||
|
|
||||||
ERR_CHECK(connection_enqueue_packet(ctx, &header, buf, buf_len));
|
uint8_t packet_with_type[buf_len + 1];
|
||||||
|
|
||||||
|
packet_with_type[0] = (uint8_t)payload_type;
|
||||||
|
memcpy(packet_with_type+1, buf, buf_len);
|
||||||
|
|
||||||
|
ERR_CHECK(connection_enqueue_packet(ctx, &header, packet_with_type, sizeof(packet_with_type)));
|
||||||
|
|
||||||
ctx->next_seq_nr++;
|
ctx->next_seq_nr++;
|
||||||
ctx->next_seq_nr &= SEQ_NR_MASK;
|
ctx->next_seq_nr &= SEQ_NR_MASK;
|
||||||
|
@ -531,8 +560,11 @@ void connection_handle_ack(connection_ctx_t *ctx, uint8_t acked_seq, bool do_ack
|
||||||
packet_queue_delete(&ctx->packet_queue, packets_to_remove);
|
packet_queue_delete(&ctx->packet_queue, packets_to_remove);
|
||||||
|
|
||||||
// send the next requested packet (all previous ones were deleted above).
|
// send the next requested packet (all previous ones were deleted above).
|
||||||
assert(ctx->next_packet_index >= packets_to_remove);
|
if(ctx->next_packet_index >= packets_to_remove) {
|
||||||
ctx->next_packet_index -= packets_to_remove;
|
ctx->next_packet_index -= packets_to_remove;
|
||||||
|
} else {
|
||||||
|
ctx->next_packet_index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
packets_available = packet_queue_get_used_space(&ctx->packet_queue);
|
packets_available = packet_queue_get_used_space(&ctx->packet_queue);
|
||||||
|
|
||||||
|
|
|
@ -138,10 +138,15 @@ result_t connection_enqueue_packet(
|
||||||
|
|
||||||
/*!\brief Enqueue a data packet for transmission.
|
/*!\brief Enqueue a data packet for transmission.
|
||||||
* \param ctx The connection context.
|
* \param ctx The connection context.
|
||||||
|
* \param payload_type Type of the payload.
|
||||||
* \param buf Pointer to the data buffer.
|
* \param buf Pointer to the data buffer.
|
||||||
* \param buf_len Length of the data.
|
* \param buf_len Length of the data.
|
||||||
*/
|
*/
|
||||||
result_t connection_enqueue_data_packet(connection_ctx_t *ctx, uint8_t *buf, size_t buf_len);
|
result_t connection_enqueue_data_packet(
|
||||||
|
connection_ctx_t *ctx,
|
||||||
|
layer2_payload_type_t payload_type,
|
||||||
|
uint8_t *buf,
|
||||||
|
size_t buf_len);
|
||||||
|
|
||||||
/*!\brief Check if there is free space in the TX packet queue.
|
/*!\brief Check if there is free space in the TX packet queue.
|
||||||
* \param ctx The connection context.
|
* \param ctx The connection context.
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
#define LOGGER_MODULE_NAME "clist"
|
||||||
|
#include "logger.h"
|
||||||
|
|
||||||
#include "connection_list.h"
|
#include "connection_list.h"
|
||||||
|
|
||||||
#include "layer2/connection.h"
|
#include "layer2/connection.h"
|
||||||
#include "results.h"
|
#include "results.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
#define SEQ_NR_MASK 0xF
|
#define SEQ_NR_MASK 0xF
|
||||||
|
|
||||||
|
@ -213,7 +217,7 @@ result_t connection_list_enqueue_packet(connection_list_t *list, uint8_t *data,
|
||||||
return ERR_INVALID_ADDRESS;
|
return ERR_INVALID_ADDRESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
return connection_enqueue_data_packet(&ptr->connection, data, data_len);
|
return connection_enqueue_data_packet(&ptr->connection, L2_PAYLOAD_TYPE_IPV6, data, data_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -186,7 +186,7 @@ result_t digipeater_fill_packet_queues_from_tundev(digipeater_ctx_t *ctx, int tu
|
||||||
// first check if any queue is already full, so we don't have to drop packets
|
// first check if any queue is already full, so we don't have to drop packets
|
||||||
// from the TUN device queue.
|
// from the TUN device queue.
|
||||||
if(!connection_list_can_enqueue_packet(&ctx->conn_list)) {
|
if(!connection_list_can_enqueue_packet(&ctx->conn_list)) {
|
||||||
LOG(LVL_DEBUG, "No free space in queues.");
|
LOG(LVL_DEBUG, "No connection or no free space in queues.");
|
||||||
return OK; // do nothing
|
return OK; // do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,6 +215,9 @@ result_t digipeater_fill_packet_queues_from_tundev(digipeater_ctx_t *ctx, int tu
|
||||||
} else if(ret == 0) {
|
} else if(ret == 0) {
|
||||||
// no more data, should not happen
|
// no more data, should not happen
|
||||||
break;
|
break;
|
||||||
|
} else if(ret < 4) {
|
||||||
|
LOG(LVL_ERR, "Not enough data from TUN read() to check packet type!");
|
||||||
|
return ERR_SYSCALL;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t flags = *(uint16_t*)packetbuf;
|
uint16_t flags = *(uint16_t*)packetbuf;
|
||||||
|
@ -222,9 +225,13 @@ result_t digipeater_fill_packet_queues_from_tundev(digipeater_ctx_t *ctx, int tu
|
||||||
LOG(LVL_DUMP, "TUN Flags: 0x%04x", flags);
|
LOG(LVL_DUMP, "TUN Flags: 0x%04x", flags);
|
||||||
LOG(LVL_DUMP, "TUN Proto: 0x%04x", proto);
|
LOG(LVL_DUMP, "TUN Proto: 0x%04x", proto);
|
||||||
|
|
||||||
|
uint8_t *packet_data = packetbuf + 4;
|
||||||
|
size_t packet_length = ret - 4;
|
||||||
|
|
||||||
|
// note: octets are swapped in case statements
|
||||||
switch(proto) {
|
switch(proto) {
|
||||||
case 0x86dd: // IPv6
|
case 0xdd86: // IPv6
|
||||||
ERR_CHECK(connection_list_enqueue_packet(&ctx->conn_list, packetbuf, ret));
|
WARN_ON_ERR(connection_list_enqueue_packet(&ctx->conn_list, packet_data, packet_length));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -258,6 +265,7 @@ size_t digipeater_encode_next_packet(digipeater_ctx_t *ctx, uint8_t *buf, size_t
|
||||||
switch(ctx->state) {
|
switch(ctx->state) {
|
||||||
case DIGIPEATER_STATE_BEACON:
|
case DIGIPEATER_STATE_BEACON:
|
||||||
packet_size = encode_beacon_packet(ctx, buf, buf_len);
|
packet_size = encode_beacon_packet(ctx, buf, buf_len);
|
||||||
|
ctx->next_beacon_time += HRTIME_MS(BEACON_INTERVAL_MS);
|
||||||
*end_burst = true;
|
*end_burst = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -318,7 +326,6 @@ result_t digipeater_end_cycle(digipeater_ctx_t *ctx)
|
||||||
uint64_t now = get_hires_time();
|
uint64_t now = get_hires_time();
|
||||||
|
|
||||||
if(now >= ctx->next_beacon_time) {
|
if(now >= ctx->next_beacon_time) {
|
||||||
ctx->next_beacon_time += HRTIME_MS(BEACON_INTERVAL_MS);
|
|
||||||
ctx->state = DIGIPEATER_STATE_BEACON;
|
ctx->state = DIGIPEATER_STATE_BEACON;
|
||||||
} else {
|
} else {
|
||||||
// TODO: adjust the time based on connection activity; right now this results
|
// TODO: adjust the time based on connection activity; right now this results
|
||||||
|
|
|
@ -49,4 +49,12 @@ typedef enum {
|
||||||
} \
|
} \
|
||||||
} while(0);
|
} while(0);
|
||||||
|
|
||||||
|
#define WARN_ON_ERR(call) \
|
||||||
|
do { \
|
||||||
|
result_t err_check_result = call; \
|
||||||
|
if(err_check_result != OK) { \
|
||||||
|
LOG(LVL_WARN, "Error ignored at %s:%d: %d", __FILE__, __LINE__, err_check_result); \
|
||||||
|
} \
|
||||||
|
} while(0);
|
||||||
|
|
||||||
#endif // RESULTS_H
|
#endif // RESULTS_H
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
#include "layer2/ham64.h"
|
#include "layer2/ham64.h"
|
||||||
|
#include "results.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
#define LOGGER_MODULE_NAME "main"
|
#define LOGGER_MODULE_NAME "main"
|
||||||
|
@ -314,12 +315,25 @@ int main(void)
|
||||||
} else if(ret == 0) {
|
} else if(ret == 0) {
|
||||||
// no more data, should not happen
|
// no more data, should not happen
|
||||||
break;
|
break;
|
||||||
|
} else if(ret < 4) {
|
||||||
|
LOG(LVL_ERR, "Not enough data from TUN read() to check packet type!");
|
||||||
|
return ERR_SYSCALL;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG(LVL_DUMP, "TUN Flags: 0x%04x", *(uint16_t*)packetbuf);
|
uint16_t flags = *(uint16_t*)packetbuf;
|
||||||
LOG(LVL_DUMP, "TUN Proto: 0x%04x", *((uint16_t*)packetbuf + 1));
|
uint16_t proto = *((uint16_t*)packetbuf + 1);
|
||||||
|
LOG(LVL_DUMP, "TUN Flags: 0x%04x", flags);
|
||||||
|
LOG(LVL_DUMP, "TUN Proto: 0x%04x", proto);
|
||||||
|
|
||||||
RESULT_CHECK(connection_enqueue_data_packet(&l2conn, packetbuf, ret));
|
uint8_t *packet_data = packetbuf + 4;
|
||||||
|
size_t packet_length = ret - 4;
|
||||||
|
|
||||||
|
if(proto != 0xdd86) {
|
||||||
|
LOG(LVL_WARN, "Non-IPv6 packet ignored. Proto: 0x%04x", proto);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
RESULT_CHECK(connection_enqueue_data_packet(&l2conn, L2_PAYLOAD_TYPE_IPV6, packet_data, packet_length));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -411,6 +425,10 @@ int main(void)
|
||||||
LOG(LVL_ERR, "Packet not in the expected sequence.");
|
LOG(LVL_ERR, "Packet not in the expected sequence.");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ERR_INVALID_STATE:
|
||||||
|
LOG(LVL_WARN, "Packet ignored due to invalid state.");
|
||||||
|
break;
|
||||||
|
|
||||||
default: // all other errors
|
default: // all other errors
|
||||||
LOG(LVL_ERR, "layer2_rx_handle_packet() returned error code %u.", result);
|
LOG(LVL_ERR, "layer2_rx_handle_packet() returned error code %u.", result);
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in a new issue