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:
Thomas Kolb 2024-11-03 14:39:22 +01:00
parent 8572018c4e
commit 6e303e8aed
2 changed files with 216 additions and 0 deletions

View 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;
}

View 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