Layer 2 received packet handling
This commit is contained in:
parent
7381c7e808
commit
a6464a28b8
66
impl/src/layer2/layer2_rx.c
Normal file
66
impl/src/layer2/layer2_rx.c
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "layer2_rx.h"
|
||||||
|
|
||||||
|
#include "packet_structs.h"
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
result_t layer2_rx_init(layer2_rx_t *ctx, int tun_fd)
|
||||||
|
{
|
||||||
|
ctx->last_acked_seq = 0;
|
||||||
|
ctx->tun_fd = tun_fd;
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void layer2_rx_destroy(layer2_rx_t *ctx)
|
||||||
|
{
|
||||||
|
(void)ctx;
|
||||||
|
// nothing to do here so far
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
result_t layer2_rx_handle_packet(layer2_rx_t *ctx, const uint8_t *buf, size_t buf_len)
|
||||||
|
{
|
||||||
|
// check the CRC
|
||||||
|
size_t packet_size = buf_len - crc_sizeof_key(PAYLOAD_CRC_SCHEME);
|
||||||
|
|
||||||
|
if(!crc_check_key(PAYLOAD_CRC_SCHEME, (unsigned char*)buf, packet_size)) {
|
||||||
|
LOG(LVL_ERR, "payload CRC check failed!");
|
||||||
|
return ERR_INTEGRITY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// decode the header
|
||||||
|
layer2_packet_header_t header;
|
||||||
|
|
||||||
|
if(!layer2_decode_packet_header(buf, buf_len, &header)) {
|
||||||
|
LOG(LVL_ERR, "Header could not be decoded!");
|
||||||
|
return ERR_INTEGRITY;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->last_acked_seq = header.rx_seq_nr;
|
||||||
|
|
||||||
|
size_t header_size = layer2_get_encoded_header_size(&header);
|
||||||
|
|
||||||
|
// extract the payload and forward it to the tun device
|
||||||
|
const uint8_t *payload = buf + header_size;
|
||||||
|
size_t payload_len = packet_size - header_size;
|
||||||
|
|
||||||
|
int ret = write(ctx->tun_fd, payload, payload_len);
|
||||||
|
if(ret < 0) {
|
||||||
|
LOG(LVL_ERR, "write: %s", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t layer2_rx_get_last_acked_seq(const layer2_rx_t *ctx)
|
||||||
|
{
|
||||||
|
return ctx->last_acked_seq;
|
||||||
|
}
|
38
impl/src/layer2/layer2_rx.h
Normal file
38
impl/src/layer2/layer2_rx.h
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
#ifndef LAYER2_RX_H
|
||||||
|
#define LAYER2_RX_H
|
||||||
|
|
||||||
|
#include <results.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t last_acked_seq;
|
||||||
|
|
||||||
|
int tun_fd;
|
||||||
|
} layer2_rx_t;
|
||||||
|
|
||||||
|
|
||||||
|
/*!\brief Initialize the layer 2 receiver context.
|
||||||
|
*
|
||||||
|
* \param ctx The receiver context to initialize.
|
||||||
|
* \param tun_fd The TUN device to read packets from.
|
||||||
|
* \returns OK if everything worked or a fitting error code.
|
||||||
|
*/
|
||||||
|
result_t layer2_rx_init(layer2_rx_t *ctx, int tun_fd);
|
||||||
|
|
||||||
|
/*!\brief Destroy the given layer 2 receiver context.
|
||||||
|
*/
|
||||||
|
void layer2_rx_destroy(layer2_rx_t *ctx);
|
||||||
|
|
||||||
|
/*!\brief Handle a received packet.
|
||||||
|
*
|
||||||
|
* \param ctx The receiver context.
|
||||||
|
* \param buf Where to write the encoded packet data.
|
||||||
|
* \param buf_len Space available in the buffer.
|
||||||
|
* \returns A result code from the packet handling procedure.
|
||||||
|
*/
|
||||||
|
result_t layer2_rx_handle_packet(layer2_rx_t *ctx, const uint8_t *buf, size_t buf_len);
|
||||||
|
|
||||||
|
/*!\brief Return the sequence number expected next by the other side.
|
||||||
|
*/
|
||||||
|
uint8_t layer2_rx_get_last_acked_seq(const layer2_rx_t *ctx);
|
||||||
|
|
||||||
|
#endif // LAYER2_RX_H
|
|
@ -14,11 +14,12 @@
|
||||||
|
|
||||||
#define SEQ_NR_MASK 0xF
|
#define SEQ_NR_MASK 0xF
|
||||||
|
|
||||||
result_t layer2_tx_init(layer2_tx_t *ctx)
|
result_t layer2_tx_init(layer2_tx_t *ctx, int tun_fd)
|
||||||
{
|
{
|
||||||
packet_queue_init(&ctx->packet_queue);
|
packet_queue_init(&ctx->packet_queue);
|
||||||
ctx->next_packet_index = 0;
|
ctx->next_packet_index = 0;
|
||||||
ctx->next_seq_nr = 0;
|
ctx->next_seq_nr = 0;
|
||||||
|
ctx->tun_fd = tun_fd;
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,11 +30,11 @@ void layer2_tx_destroy(layer2_tx_t *ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
result_t layer2_tx_fill_packet_queue(layer2_tx_t *ctx, int tun_fd)
|
result_t layer2_tx_fill_packet_queue(layer2_tx_t *ctx)
|
||||||
{
|
{
|
||||||
struct pollfd pfd = {0};
|
struct pollfd pfd = {0};
|
||||||
|
|
||||||
pfd.fd = tun_fd;
|
pfd.fd = ctx->tun_fd;
|
||||||
pfd.events = POLLIN;
|
pfd.events = POLLIN;
|
||||||
|
|
||||||
layer2_packet_header_t header;
|
layer2_packet_header_t header;
|
||||||
|
@ -59,7 +60,7 @@ result_t layer2_tx_fill_packet_queue(layer2_tx_t *ctx, int tun_fd)
|
||||||
header.tx_seq_nr = ctx->next_seq_nr;
|
header.tx_seq_nr = ctx->next_seq_nr;
|
||||||
|
|
||||||
uint8_t packetbuf[2048];
|
uint8_t packetbuf[2048];
|
||||||
ret = read(tun_fd, packetbuf, sizeof(packetbuf));
|
ret = read(ctx->tun_fd, packetbuf, sizeof(packetbuf));
|
||||||
if(ret < 0) {
|
if(ret < 0) {
|
||||||
LOG(LVL_ERR, "read: %s", strerror(errno));
|
LOG(LVL_ERR, "read: %s", strerror(errno));
|
||||||
return ERR_SYSCALL;
|
return ERR_SYSCALL;
|
||||||
|
|
|
@ -7,14 +7,21 @@
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
packet_queue_t packet_queue;
|
packet_queue_t packet_queue;
|
||||||
|
|
||||||
size_t next_packet_index;
|
size_t next_packet_index;
|
||||||
uint8_t next_seq_nr;
|
uint8_t next_seq_nr;
|
||||||
|
|
||||||
|
int tun_fd;
|
||||||
} layer2_tx_t;
|
} layer2_tx_t;
|
||||||
|
|
||||||
|
|
||||||
/*!\brief Initialize the layer 2 transmitter context.
|
/*!\brief Initialize the layer 2 transmitter context.
|
||||||
|
*
|
||||||
|
* \param ctx The transmitter context to initialize.
|
||||||
|
* \param tun_fd The TUN device to read packets from.
|
||||||
|
* \returns OK if everything worked or a fitting error code.
|
||||||
*/
|
*/
|
||||||
result_t layer2_tx_init(layer2_tx_t *ctx);
|
result_t layer2_tx_init(layer2_tx_t *ctx, int tun_fd);
|
||||||
|
|
||||||
/*!\brief Destroy the given layer 2 transmitter context.
|
/*!\brief Destroy the given layer 2 transmitter context.
|
||||||
*/
|
*/
|
||||||
|
@ -22,9 +29,8 @@ void layer2_tx_destroy(layer2_tx_t *ctx);
|
||||||
|
|
||||||
/*!\brief Fill the packet queue from the given TUN device.
|
/*!\brief Fill the packet queue from the given TUN device.
|
||||||
* \param ctx The transmitter context.
|
* \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);
|
result_t layer2_tx_fill_packet_queue(layer2_tx_t *ctx);
|
||||||
|
|
||||||
/*!\brief Encode the next packet for transmission.
|
/*!\brief Encode the next packet for transmission.
|
||||||
*
|
*
|
||||||
|
|
|
@ -33,6 +33,15 @@ size_t layer2_encode_packet_header(const layer2_packet_header_t *header, uint8_t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t layer2_get_encoded_header_size(const layer2_packet_header_t *header)
|
||||||
|
{
|
||||||
|
assert(header->src_addr.length <= 4 && header->src_addr.length != 0);
|
||||||
|
assert(header->dst_addr.length <= 4 && header->dst_addr.length != 0);
|
||||||
|
|
||||||
|
return 2 + 2 * header->src_addr.length + 2 * header->dst_addr.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool layer2_decode_packet_header(const uint8_t *encoded, size_t encoded_len, layer2_packet_header_t *header)
|
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:
|
// check if there are enough bytes for the minimum header size:
|
||||||
|
@ -42,11 +51,11 @@ bool layer2_decode_packet_header(const uint8_t *encoded, size_t encoded_len, lay
|
||||||
|
|
||||||
header->msg_type = (encoded[0] >> 5) & 0x7;
|
header->msg_type = (encoded[0] >> 5) & 0x7;
|
||||||
header->tx_request = (encoded[0] & 0x10) != 0;
|
header->tx_request = (encoded[0] & 0x10) != 0;
|
||||||
header->src_addr.length = (encoded[0] >> 2) & 0x3 + 1;
|
header->src_addr.length = ((encoded[0] >> 2) & 0x3) + 1;
|
||||||
header->dst_addr.length = (encoded[0] >> 0) & 0x3 + 1;
|
header->dst_addr.length = ((encoded[0] >> 0) & 0x3) + 1;
|
||||||
|
|
||||||
// check for the actually needed size
|
// check for the actually needed size
|
||||||
if(encoded_len < (2 + 2*header->src_addr.length + 2*header->dst_addr.length)) {
|
if(encoded_len < (2U + 2*header->src_addr.length + 2*header->dst_addr.length)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,12 @@ typedef struct layer2_packet_header_s {
|
||||||
*/
|
*/
|
||||||
size_t layer2_encode_packet_header(const layer2_packet_header_t *header, uint8_t *encoded);
|
size_t layer2_encode_packet_header(const layer2_packet_header_t *header, uint8_t *encoded);
|
||||||
|
|
||||||
|
/*!\brief Get the size of a layer2 packet header in encoded form.
|
||||||
|
* \param header The header structure.
|
||||||
|
* \returns The number of encoded bytes.
|
||||||
|
*/
|
||||||
|
size_t layer2_get_encoded_header_size(const layer2_packet_header_t *header);
|
||||||
|
|
||||||
/*!\brief Decode a layer2 packet header from the received form.
|
/*!\brief Decode a layer2 packet header from the received form.
|
||||||
* \param encoded A byte array containing the received header.
|
* \param encoded A byte array containing the received header.
|
||||||
* \param encoded_len Length (in bytes) of the given encoded data.
|
* \param encoded_len Length (in bytes) of the given encoded data.
|
||||||
|
|
|
@ -21,8 +21,10 @@
|
||||||
#include "layer1/tx.h"
|
#include "layer1/tx.h"
|
||||||
#include "layer1/rx.h"
|
#include "layer1/rx.h"
|
||||||
|
|
||||||
#include "layer2/tundev.h"
|
|
||||||
#include "layer2/layer2_tx.h"
|
#include "layer2/layer2_tx.h"
|
||||||
|
#include "layer2/layer2_rx.h"
|
||||||
|
|
||||||
|
#include "layer2/tundev.h"
|
||||||
|
|
||||||
#include "sdr/sdr.h"
|
#include "sdr/sdr.h"
|
||||||
|
|
||||||
|
@ -43,6 +45,8 @@ static double next_tx_switch_time = 0.0;
|
||||||
|
|
||||||
static rx_stats_t m_rx_stats;
|
static rx_stats_t m_rx_stats;
|
||||||
|
|
||||||
|
static layer2_rx_t l2rx;
|
||||||
|
|
||||||
static void signal_handler(int signal, siginfo_t *info, void *ctx)
|
static void signal_handler(int signal, siginfo_t *info, void *ctx)
|
||||||
{
|
{
|
||||||
(void)signal;
|
(void)signal;
|
||||||
|
@ -93,22 +97,24 @@ void cb_rx(rx_evt_t evt, const struct layer1_rx_s *rx, uint8_t *packet_data, siz
|
||||||
//hexdump(packet_data, packet_len < 64 ? packet_len : 64);
|
//hexdump(packet_data, packet_len < 64 ? packet_len : 64);
|
||||||
//LOG(LVL_INFO, "====================================");
|
//LOG(LVL_INFO, "====================================");
|
||||||
|
|
||||||
m_rx_stats.successful_decodes++;
|
|
||||||
|
|
||||||
block_tx_for(TX_SWITCH_BACKOFF_END_OF_PACKET_MS);
|
block_tx_for(TX_SWITCH_BACKOFF_END_OF_PACKET_MS);
|
||||||
|
|
||||||
unsigned int data_size = packet_len - crc_sizeof_key(PAYLOAD_CRC_SCHEME);
|
result_t result = layer2_rx_handle_packet(&l2rx, packet_data, packet_len);
|
||||||
|
switch(result) {
|
||||||
|
case OK:
|
||||||
|
m_rx_stats.successful_decodes++;
|
||||||
|
break;
|
||||||
|
|
||||||
// FIXME: move to layer 2
|
case ERR_INTEGRITY:
|
||||||
if(!crc_check_key(PAYLOAD_CRC_SCHEME, packet_data, data_size)) {
|
LOG(LVL_ERR, "Packet could not be decoded by Layer 2.");
|
||||||
LOG(LVL_WARN, "payload CRC check failed!");
|
m_rx_stats.failed_decodes++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: // all other errors
|
||||||
|
LOG(LVL_ERR, "layer2_rx_handle_packet() returned error code %u.", result);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = write(m_tunfd, packet_data, data_size);
|
|
||||||
if(ret < 0) {
|
|
||||||
LOG(LVL_ERR, "write: %s", strerror(errno));
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RX_EVT_PREAMBLE_FOUND:
|
case RX_EVT_PREAMBLE_FOUND:
|
||||||
|
@ -179,7 +185,8 @@ int main(int argc, char **argv)
|
||||||
RESULT_CHECK(layer1_tx_init(&tx));
|
RESULT_CHECK(layer1_tx_init(&tx));
|
||||||
RESULT_CHECK(layer1_rx_init(&rx, cb_rx));
|
RESULT_CHECK(layer1_rx_init(&rx, cb_rx));
|
||||||
|
|
||||||
RESULT_CHECK(layer2_tx_init(&l2tx));
|
RESULT_CHECK(layer2_tx_init(&l2tx, m_tunfd));
|
||||||
|
RESULT_CHECK(layer2_rx_init(&l2rx, m_tunfd));
|
||||||
|
|
||||||
// ** Set up signal handling
|
// ** Set up signal handling
|
||||||
|
|
||||||
|
@ -217,7 +224,7 @@ int main(int argc, char **argv)
|
||||||
double now = get_hires_time();
|
double now = get_hires_time();
|
||||||
|
|
||||||
// fill the TX queue from the TUN device
|
// fill the TX queue from the TUN device
|
||||||
layer2_tx_fill_packet_queue(&l2tx, m_tunfd);
|
layer2_tx_fill_packet_queue(&l2tx);
|
||||||
|
|
||||||
if((now > next_tx_switch_time) && (on_air || !layer1_rx_is_busy(&rx))) {
|
if((now > next_tx_switch_time) && (on_air || !layer1_rx_is_busy(&rx))) {
|
||||||
if(layer2_tx_can_transmit(&l2tx)) {
|
if(layer2_tx_can_transmit(&l2tx)) {
|
||||||
|
@ -355,6 +362,7 @@ int main(int argc, char **argv)
|
||||||
// ** Cleanup **
|
// ** Cleanup **
|
||||||
|
|
||||||
layer2_tx_destroy(&l2tx);
|
layer2_tx_destroy(&l2tx);
|
||||||
|
layer2_rx_destroy(&l2rx);
|
||||||
|
|
||||||
layer1_tx_shutdown(&tx);
|
layer1_tx_shutdown(&tx);
|
||||||
layer1_rx_shutdown(&rx);
|
layer1_rx_shutdown(&rx);
|
||||||
|
|
|
@ -13,6 +13,7 @@ typedef enum {
|
||||||
ERR_SYSCALL, // a syscall failed. Use errno to determine the cause.
|
ERR_SYSCALL, // a syscall failed. Use errno to determine the cause.
|
||||||
ERR_SOAPY, // an error occurred in the SoapySDR library.
|
ERR_SOAPY, // an error occurred in the SoapySDR library.
|
||||||
ERR_SDR, // an error occurred in the SDR interface.
|
ERR_SDR, // an error occurred in the SDR interface.
|
||||||
|
ERR_INTEGRITY, // an integrity check failed (e.g. CRC of received packet is wrong)
|
||||||
} result_t;
|
} result_t;
|
||||||
|
|
||||||
#ifdef DEBUG_LIQUID
|
#ifdef DEBUG_LIQUID
|
||||||
|
|
Loading…
Reference in a new issue