WIP: digipeater module managing multiple connections
Backup commit. This is a basic setup with lots of TODOs and errors. Will not compile yet.
This commit is contained in:
parent
8572018c4e
commit
6e303e8aed
122
impl/src/layer2/digipeater.c
Normal file
122
impl/src/layer2/digipeater.c
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "digipeater.h"
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "layer2/connection.h"
|
||||||
|
#include "layer2/ham64.h"
|
||||||
|
#include "results.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
result_t digipeater_init(digipeater_ctx_t *ctx, const ham64_t *my_addr, digipeater_data_callback_t data_cb)
|
||||||
|
{
|
||||||
|
ctx->my_addr = *my_addr;
|
||||||
|
ctx->data_cb = data_cb;
|
||||||
|
|
||||||
|
ctx->state = DIGIPEATER_STATE_CONN;
|
||||||
|
|
||||||
|
uint64_t now = get_hires_time();
|
||||||
|
ctx->next_beacon_time = now + HRTIME_MS(BEACON_INTERVAL_MS);
|
||||||
|
|
||||||
|
return connection_list_init(&ctx->conn_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void digipeater_destroy(digipeater_ctx_t *ctx)
|
||||||
|
{
|
||||||
|
connection_list_destroy(&ctx->conn_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
result_t digipeater_handle_packet(digipeater_ctx_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, "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;
|
||||||
|
}
|
||||||
|
|
||||||
|
layer2_dump_packet_header(LVL_DUMP, &header);
|
||||||
|
|
||||||
|
// check if the packet really should be handled by us
|
||||||
|
if(ham64_is_equal(&ctx->my_addr, &header.src_addr)) {
|
||||||
|
LOG(LVL_DEBUG, "Packet is from ourselves. Ignored.");
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!ham64_is_equal(&header.dst_addr, &ctx->my_addr)) {
|
||||||
|
char fmt_dst_addr[HAM64_FMT_MAX_LEN];
|
||||||
|
char fmt_my_addr[HAM64_FMT_MAX_LEN];
|
||||||
|
|
||||||
|
ham64_format(&header.dst_addr, fmt_dst_addr);
|
||||||
|
ham64_format(&ctx->my_addr, fmt_my_addr);
|
||||||
|
|
||||||
|
LOG(LVL_ERR, "Packet has the wrong destination address: got %s, expected %s",
|
||||||
|
fmt_dst_addr, fmt_my_addr);
|
||||||
|
|
||||||
|
return ERR_INVALID_ADDRESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: handle connection management packets here
|
||||||
|
// FIXME: handle data and empty packets in the current connection
|
||||||
|
|
||||||
|
size_t header_size = layer2_get_encoded_header_size(&header);
|
||||||
|
|
||||||
|
const uint8_t *payload = buf + header_size;
|
||||||
|
size_t payload_len = packet_size - header_size;
|
||||||
|
|
||||||
|
connection_handle_packet_prechecked(current_conn, &header, payload, payload_len);
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t digipeater_encode_next_packet(digipeater_ctx_t *ctx, uint8_t *buf, size_t buf_len, bool *end_burst)
|
||||||
|
{
|
||||||
|
uint64_t now = get_hires_time();
|
||||||
|
|
||||||
|
*end_burst = false;
|
||||||
|
|
||||||
|
if(now > ctx->next_beacon_time) {
|
||||||
|
// TODO: build a beacon packet
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: pull packets from the current connection
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool digipeater_can_transmit(const digipeater_ctx_t *ctx)
|
||||||
|
{
|
||||||
|
uint64_t now = get_hires_time();
|
||||||
|
|
||||||
|
if(now > ctx->next_beacon_time) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: also true if next TX time has expired and there are packets waiting for this connection.
|
||||||
|
|
||||||
|
/*return (packet_queue_get_used_space(&ctx->packet_queue) != 0)
|
||||||
|
&& (packet_queue_get(&ctx->packet_queue, ctx->next_packet_index) != NULL); */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
result_t digipeater_maintain(digipeater_ctx_t *ctx)
|
||||||
|
{
|
||||||
|
(void)ctx;
|
||||||
|
return OK;
|
||||||
|
}
|
94
impl/src/layer2/digipeater.h
Normal file
94
impl/src/layer2/digipeater.h
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
* This file contains functions to handle a single layer 2 digipeater.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* Copyright (C) 2024 Thomas Kolb
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DIGIPEATER_H
|
||||||
|
#define DIGIPEATER_H
|
||||||
|
|
||||||
|
#include <results.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "connection_list.h"
|
||||||
|
|
||||||
|
struct digipeater_ctx_s;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
DIGIPEATER_STATE_BEACON, //!< Beacon sent, waiting for connection requests
|
||||||
|
DIGIPEATER_STATE_CONN, //!< Handling client connections
|
||||||
|
} digipeater_state_t;
|
||||||
|
|
||||||
|
/*!\brief Type for a callback function that is called when a data packet was received. */
|
||||||
|
typedef void (*digipeater_data_callback_t)(struct digipeater_ctx_s *conn, const uint8_t *data, size_t len);
|
||||||
|
|
||||||
|
typedef struct digipeater_ctx_s {
|
||||||
|
digipeater_state_t state; //!< Current operating state
|
||||||
|
|
||||||
|
digipeater_data_callback_t data_cb; //!< Callback function for received data packets.
|
||||||
|
|
||||||
|
ham64_t my_addr; //!< The local link layer address.
|
||||||
|
|
||||||
|
uint64_t next_beacon_time; //!< Absolute timestamp of the next beacon transmission.
|
||||||
|
|
||||||
|
connection_list_t conn_list; //!< List of connections.
|
||||||
|
} digipeater_ctx_t;
|
||||||
|
|
||||||
|
|
||||||
|
/*!\brief Initialize the digipeater context.
|
||||||
|
*
|
||||||
|
* \param ctx The digipeater context to initialize.
|
||||||
|
* \param my_addr The local link layer address.
|
||||||
|
* \param data_cb Callback function that handles received (decoded) data packets.
|
||||||
|
* \returns OK if everything worked or a fitting error code.
|
||||||
|
*/
|
||||||
|
result_t digipeater_init(
|
||||||
|
digipeater_ctx_t *ctx,
|
||||||
|
const ham64_t *my_addr,
|
||||||
|
digipeater_data_callback_t data_cb);
|
||||||
|
|
||||||
|
/*!\brief Destroy the given digipeater context.
|
||||||
|
*/
|
||||||
|
void digipeater_destroy(digipeater_ctx_t *ctx);
|
||||||
|
|
||||||
|
/*!\brief Handle a received packet.
|
||||||
|
*
|
||||||
|
* \param ctx The digipeater context.
|
||||||
|
* \param buf Pointer to the packet data.
|
||||||
|
* \param buf_len Length of the packet.
|
||||||
|
* \returns A result code from the packet handling procedure.
|
||||||
|
*/
|
||||||
|
result_t digipeater_handle_packet(digipeater_ctx_t *ctx, const uint8_t *buf, size_t buf_len);
|
||||||
|
|
||||||
|
/*!\brief Enqueue a packet for transmission.
|
||||||
|
* \param ctx The digipeater context.
|
||||||
|
* \param tun_fd File descriptor for an open TUN device.
|
||||||
|
*/
|
||||||
|
result_t digipeater_fill_packet_queues_from_tundev(digipeater_ctx_t *ctx, int tun_fd);
|
||||||
|
|
||||||
|
/*!\brief Encode the next packet for transmission.
|
||||||
|
*
|
||||||
|
* \note
|
||||||
|
* If no packets are currently available for transmission, this function returns zero.
|
||||||
|
*
|
||||||
|
* \param ctx The digipeater context.
|
||||||
|
* \param buf Where to write the encoded packet data.
|
||||||
|
* \param buf_len Space available in the buffer.
|
||||||
|
* \param end_burst Set to true if this packet should end the current burst and start the transmission.
|
||||||
|
* \returns The number of bytes written to buf or zero if no packet was available.
|
||||||
|
*/
|
||||||
|
size_t digipeater_encode_next_packet(digipeater_ctx_t *ctx, uint8_t *buf, size_t buf_len, bool *end_burst);
|
||||||
|
|
||||||
|
/*!\brief Check if there are packets queued for transmission.
|
||||||
|
*/
|
||||||
|
bool digipeater_can_transmit(const digipeater_ctx_t *ctx);
|
||||||
|
|
||||||
|
/*!\brief Handle internal maintenance tasks.
|
||||||
|
*
|
||||||
|
* This should be called periodically to handle timeouts and retransmissions.
|
||||||
|
*/
|
||||||
|
result_t digipeater_maintain(digipeater_ctx_t *ctx);
|
||||||
|
|
||||||
|
#endif // DIGIPEATER_H
|
Loading…
Reference in a new issue