connection: use one-shot packet „queueing“ to send connection request
The connection module now has a separate queueing mechanism for packets that are only transmitted once and not acknowledged through the regular Go-back-N mechanism. An example is the Connection Request that is a one-time response to a received beacon. When such a packet shall be sent, a simple flag is set and the packet is transmitted first in the next burst. Data packets may follow depending on the one-shot packet type (Connection Request ends the burst immediately).
This commit is contained in:
parent
d4f101793b
commit
56742ef811
2 changed files with 55 additions and 18 deletions
|
|
@ -30,6 +30,8 @@ result_t connection_init(
|
|||
ctx->my_addr = *my_addr;
|
||||
ctx->peer_addr = *peer_addr;
|
||||
|
||||
ctx->pending_packet = CONN_PENDING_NONE;
|
||||
|
||||
uint64_t now = get_hires_time();
|
||||
ctx->last_rx_time = now;
|
||||
|
||||
|
|
@ -165,21 +167,10 @@ static result_t handle_conn_mgmt(
|
|||
if(ctx->conn_state == CONN_STATE_CONNECTING) {
|
||||
LOG(LVL_INFO, "Received beacon; queueing connection request.");
|
||||
|
||||
// enqueue a connection request packet
|
||||
layer2_packet_header_t conn_request_header;
|
||||
// do not enqueue the connection request as it does not need a regular
|
||||
// ACK, but set it up as a pending one-shot packet.
|
||||
ctx->pending_packet = CONN_PENDING_CONNECTION_REQUEST;
|
||||
|
||||
conn_request_header.tx_request = true;
|
||||
conn_request_header.dst_addr = ctx->peer_addr;
|
||||
conn_request_header.src_addr = ctx->my_addr;
|
||||
conn_request_header.msg_type = L2_MSG_TYPE_CONN_MGMT;
|
||||
conn_request_header.rx_seq_nr = 0;
|
||||
conn_request_header.tx_seq_nr = 0;
|
||||
|
||||
// create a persistent copy of the packet data.
|
||||
uint8_t packetbuf[1];
|
||||
packetbuf[0] = CONN_MGMT_TYPE_CONNECTION_REQUEST;
|
||||
|
||||
connection_enqueue_packet(ctx, &conn_request_header, packetbuf, 1);
|
||||
} else {
|
||||
LOG(LVL_WARN, "Beacons are ignored in states other than CONNECTING.");
|
||||
return ERR_INVALID_STATE;
|
||||
|
|
@ -485,6 +476,44 @@ size_t connection_encode_next_packet(connection_ctx_t *ctx, uint8_t *buf, size_t
|
|||
break;
|
||||
}
|
||||
|
||||
layer2_packet_header_t header;
|
||||
|
||||
// first check one-shot packets; ensure they are only processed once
|
||||
connection_pending_packet_t pending = ctx->pending_packet;
|
||||
ctx->pending_packet = CONN_PENDING_NONE;
|
||||
|
||||
if(pending != CONN_PENDING_NONE) {
|
||||
// prepare the header (same for all packets transmitted outside Go-back-N)
|
||||
header.tx_request = true;
|
||||
header.dst_addr = ctx->peer_addr;
|
||||
header.src_addr = ctx->my_addr;
|
||||
header.rx_seq_nr = 0;
|
||||
header.tx_seq_nr = 0;
|
||||
|
||||
*end_burst = true;
|
||||
}
|
||||
|
||||
switch(pending) {
|
||||
case CONN_PENDING_NONE:
|
||||
// continue to check the regular packet queue
|
||||
break;
|
||||
|
||||
case CONN_PENDING_CONNECTION_REQUEST:
|
||||
{
|
||||
// enqueue a connection request packet
|
||||
header.msg_type = L2_MSG_TYPE_CONN_MGMT;
|
||||
|
||||
uint8_t payload[1];
|
||||
payload[0] = CONN_MGMT_TYPE_CONNECTION_REQUEST;
|
||||
|
||||
return layer2_encode_packet(&header, payload, sizeof(payload), buf, buf_len);
|
||||
}
|
||||
|
||||
default:
|
||||
LOG(LVL_ERR, "Invalid pending packet type encountered: 0x%08x", ctx->pending_packet);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const packet_queue_entry_t *entry = packet_queue_get(&ctx->packet_queue, ctx->next_packet_index);
|
||||
|
||||
if(!entry) {
|
||||
|
|
@ -492,7 +521,7 @@ size_t connection_encode_next_packet(connection_ctx_t *ctx, uint8_t *buf, size_t
|
|||
return 0;
|
||||
}
|
||||
|
||||
layer2_packet_header_t header = entry->header;
|
||||
header = entry->header;
|
||||
header.rx_seq_nr = ctx->next_expected_seq;
|
||||
|
||||
header.tx_request = (ctx->next_packet_index == (packet_queue_get_used_space(&ctx->packet_queue) - 1));
|
||||
|
|
@ -575,8 +604,9 @@ bool connection_can_transmit(const connection_ctx_t *ctx)
|
|||
{
|
||||
assert(ctx->conn_state != CONN_STATE_UNINITIALIZED);
|
||||
|
||||
return (packet_queue_get_used_space(&ctx->packet_queue) != 0)
|
||||
&& (packet_queue_get(&ctx->packet_queue, ctx->next_packet_index) != NULL);
|
||||
return (ctx->pending_packet != CONN_PENDING_NONE) ||
|
||||
((packet_queue_get_used_space(&ctx->packet_queue) != 0)
|
||||
&& (packet_queue_get(&ctx->packet_queue, ctx->next_packet_index) != NULL));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ struct connection_ctx_s;
|
|||
typedef enum {
|
||||
CONN_STATE_UNINITIALIZED, //!< Uninitialized. Cannot be used in any way
|
||||
CONN_STATE_INITIALIZED, //!< Initialized, no packets processed yet
|
||||
CONN_STATE_CONNECTING, //!< Connection request sent, no two-way communication yet
|
||||
CONN_STATE_CONNECTING, //!< Outgoing connection set up, waiting and responding to beacons
|
||||
CONN_STATE_ESTABLISHED, //!< Connection is established
|
||||
CONN_STATE_CLOSED //!< Connection has been closed (gracefully or by timeout)
|
||||
} connection_state_t;
|
||||
|
|
@ -32,6 +32,11 @@ typedef enum {
|
|||
CONN_EVT_RETRANSMIT, //!< Packet queue transmission is restarted
|
||||
} connection_evt_t;
|
||||
|
||||
typedef enum {
|
||||
CONN_PENDING_NONE,
|
||||
CONN_PENDING_CONNECTION_REQUEST,
|
||||
} connection_pending_packet_t;
|
||||
|
||||
typedef struct connection_ctx_s {
|
||||
connection_state_t conn_state; //!< State of the connection.
|
||||
|
||||
|
|
@ -45,6 +50,8 @@ typedef struct connection_ctx_s {
|
|||
|
||||
packet_queue_t packet_queue; //!< Transmission packet queue.
|
||||
|
||||
connection_pending_packet_t pending_packet; //!< Identifies a single one-shot packet that must be transmitted
|
||||
|
||||
size_t next_packet_index; //!< Index in the packet queue of the next packet to transmit.
|
||||
uint8_t next_seq_nr; //!< Sequence number to tag the next transmitted packet with.
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue