Added functions for basic layer 2 transmission handling
This commit is contained in:
parent
2348cd0c88
commit
5adbbca786
144
impl/src/layer2/layer2_tx.c
Normal file
144
impl/src/layer2/layer2_tx.c
Normal file
|
@ -0,0 +1,144 @@
|
|||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <poll.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "layer2_tx.h"
|
||||
|
||||
#include "packet_structs.h"
|
||||
#include "packet_queue.h"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#define SEQ_NR_MASK 0xF
|
||||
|
||||
result_t layer2_tx_init(layer2_tx_t *ctx)
|
||||
{
|
||||
packet_queue_init(&ctx->packet_queue);
|
||||
ctx->next_packet_index = 0;
|
||||
ctx->next_seq_nr = 0;
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
void layer2_tx_destroy(layer2_tx_t *ctx)
|
||||
{
|
||||
packet_queue_destroy(&ctx->packet_queue);
|
||||
}
|
||||
|
||||
|
||||
result_t layer2_tx_fill_packet_queue(layer2_tx_t *ctx, int tun_fd)
|
||||
{
|
||||
struct pollfd pfd = {0};
|
||||
|
||||
pfd.fd = tun_fd;
|
||||
pfd.events = POLLIN;
|
||||
|
||||
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_DATA;
|
||||
header.rx_seq_nr = 0; // will be filled in layer2_tx_encode_next_packet()
|
||||
header.tx_request = 0;
|
||||
|
||||
int ret = 0;
|
||||
|
||||
do {
|
||||
int ret = poll(&pfd, 1, 0);
|
||||
if(ret < 0) {
|
||||
LOG(LVL_ERR, "poll: %s", strerror(errno));
|
||||
return ERR_SYSCALL;
|
||||
} else if(ret > 0) {
|
||||
header.tx_seq_nr = ctx->next_seq_nr;
|
||||
|
||||
uint8_t packetbuf[2048];
|
||||
ret = read(tun_fd, packetbuf, sizeof(packetbuf));
|
||||
if(ret < 0) {
|
||||
LOG(LVL_ERR, "read: %s", strerror(errno));
|
||||
return ERR_SYSCALL;
|
||||
} else if(ret == 0) {
|
||||
// no more data
|
||||
break;
|
||||
}
|
||||
|
||||
packet_queue_add(&ctx->packet_queue, &header, packetbuf, ret);
|
||||
|
||||
ctx->next_seq_nr++;
|
||||
ctx->next_seq_nr &= SEQ_NR_MASK;
|
||||
}
|
||||
} while((ret > 0) && (packet_queue_get_free_space(&ctx->packet_queue) > 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);
|
||||
|
||||
if(!entry) {
|
||||
// no more entries
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int crc_size = crc_sizeof_key(PAYLOAD_CRC_SCHEME);
|
||||
|
||||
assert(buf_len >= 18 + crc_size + entry->data_len);
|
||||
|
||||
layer2_packet_header_t header = entry->header;
|
||||
header.rx_seq_nr = ack_seq_nr;
|
||||
|
||||
// encode the header
|
||||
size_t packet_size = layer2_encode_packet_header(&header, buf);
|
||||
|
||||
// add the payload 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
|
||||
crc_append_key(PAYLOAD_CRC_SCHEME, buf, packet_size);
|
||||
|
||||
packet_size += crc_size;
|
||||
|
||||
ctx->next_packet_index++;
|
||||
|
||||
return packet_size;
|
||||
}
|
||||
|
||||
|
||||
void layer2_tx_restart(layer2_tx_t *ctx)
|
||||
{
|
||||
ctx->next_packet_index = 0;
|
||||
}
|
||||
|
||||
|
||||
void layer2_tx_handle_ack(layer2_tx_t *ctx, uint8_t acked_seq)
|
||||
{
|
||||
ctx->next_packet_index = 0;
|
||||
|
||||
size_t packets_to_remove = 0;
|
||||
size_t packets_available = packet_queue_get_used_space(&ctx->packet_queue);
|
||||
|
||||
for(size_t i = 0; i < packets_available; i++) {
|
||||
const packet_queue_entry_t *entry = packet_queue_get(&ctx->packet_queue, i);
|
||||
|
||||
if(entry->header.tx_seq_nr == acked_seq) {
|
||||
break;
|
||||
}
|
||||
|
||||
packets_to_remove++;
|
||||
}
|
||||
|
||||
packet_queue_delete(&ctx->packet_queue, packets_to_remove);
|
||||
}
|
||||
|
||||
|
||||
bool layer2_tx_can_transmit(const layer2_tx_t *ctx)
|
||||
{
|
||||
return packet_queue_get_used_space(&ctx->packet_queue) != 0;
|
||||
}
|
61
impl/src/layer2/layer2_tx.h
Normal file
61
impl/src/layer2/layer2_tx.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
#ifndef LAYER2_TX_H
|
||||
#define LAYER2_TX_H
|
||||
|
||||
#include <results.h>
|
||||
|
||||
#include "packet_queue.h"
|
||||
|
||||
typedef struct {
|
||||
packet_queue_t packet_queue;
|
||||
size_t next_packet_index;
|
||||
uint8_t next_seq_nr;
|
||||
} layer2_tx_t;
|
||||
|
||||
|
||||
/*!\brief Initialize the layer 2 transmitter context.
|
||||
*/
|
||||
result_t layer2_tx_init(layer2_tx_t *ctx);
|
||||
|
||||
/*!\brief Destroy the given layer 2 transmitter context.
|
||||
*/
|
||||
void layer2_tx_destroy(layer2_tx_t *ctx);
|
||||
|
||||
/*!\brief Fill the packet queue from the given TUN device.
|
||||
* \param ctx The transmitter context.
|
||||
* \param tun_fd File descriptor of the TUN device to read packets from.
|
||||
*/
|
||||
result_t layer2_tx_fill_packet_queue(layer2_tx_t *ctx, int tun_fd);
|
||||
|
||||
/*!\brief Encode the next packet for transmission.
|
||||
*
|
||||
* \note
|
||||
* If no more packets are available, this function returns zero. In that case,
|
||||
* either \ref layer2_tx_restart() or \ref layer2_tx_handle_ack() must be
|
||||
* called to handle retransmits correctly.
|
||||
*
|
||||
* \param ctx The transmitter context.
|
||||
* \param ack_seq_nr The received sequence number to send as an acknowledgement.
|
||||
* \param buf Where to write the encoded packet data.
|
||||
* \param buf_len Space available in the buffer.
|
||||
* \returns The number of bytes written to buf or zero if no packet was available.
|
||||
*/
|
||||
size_t layer2_tx_encode_next_packet(layer2_tx_t *ctx, uint8_t ack_seq_nr, uint8_t *buf, size_t buf_len);
|
||||
|
||||
/*!\brief Restart the transmission from the beginning of the packet queue.
|
||||
*/
|
||||
void layer2_tx_restart(layer2_tx_t *ctx);
|
||||
|
||||
/*!\brief Handle acknowledgements.
|
||||
* \details
|
||||
* Removes all packets before the given sequence number from the queue.
|
||||
*
|
||||
* \param ctx The transmitter context.
|
||||
* \param acked_seq The acknowledged (= next expected) sequence number.
|
||||
*/
|
||||
void layer2_tx_handle_ack(layer2_tx_t *ctx, uint8_t acked_seq);
|
||||
|
||||
/*!\brief Check if there are packets queued for transmission.
|
||||
*/
|
||||
bool layer2_tx_can_transmit(const layer2_tx_t *ctx);
|
||||
|
||||
#endif // LAYER2_TX_H
|
|
@ -36,11 +36,7 @@ size_t layer2_encode_packet_header(const layer2_packet_header_t *header, uint8_t
|
|||
bool layer2_decode_packet_header(const uint8_t *encoded, size_t encoded_len, layer2_packet_header_t *header)
|
||||
{
|
||||
// check if there are enough bytes for the minimum header size:
|
||||
// - 1 byte packet info
|
||||
// - 1 byte sequence numbers
|
||||
// - 2 bytes source address
|
||||
// - 2 bytes destination address
|
||||
if(encoded_len < 6) {
|
||||
if(encoded_len < LAYER2_PACKET_HEADER_ENCODED_SIZE_MIN) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,20 @@ typedef struct layer2_packet_header_s {
|
|||
ham64_t dst_addr; //!< destination HAM-64 address
|
||||
} layer2_packet_header_t;
|
||||
|
||||
// maximum header size
|
||||
// - 1 byte packet info
|
||||
// - 1 byte sequence numbers
|
||||
// - 8 bytes source address
|
||||
// - 8 bytes destination address
|
||||
#define LAYER2_PACKET_HEADER_ENCODED_SIZE_MAX 18
|
||||
|
||||
// minimum header size:
|
||||
// - 1 byte packet info
|
||||
// - 1 byte sequence numbers
|
||||
// - 2 bytes source address
|
||||
// - 2 bytes destination address
|
||||
#define LAYER2_PACKET_HEADER_ENCODED_SIZE_MIN 6
|
||||
|
||||
/*!\brief Encode a layer2 packet header to the transmitted form.
|
||||
* \param header The header structure to encode.
|
||||
* \param encoded A byte array where the encoded header will be stored. Must have space for 18 bytes.
|
||||
|
|
Loading…
Reference in a new issue