// The MIT License (MIT)
//
// Copyright (C) 2026 Scott Duensing
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.

// Secure serial link  -- convenience wrapper tying rs232 + packet + security
//
// This is the top-level API for the serial/networking stack. It composes
// three layers into one:
//   rs232     -- ISR-driven UART I/O with ring buffers
//   packet    -- HDLC framing + CRC-16 + Go-Back-N ARQ (reliable delivery)
//   security  -- DH key exchange + XTEA-CTR encryption
//
// Usage:
//   1. secLinkOpen()       -- opens COM port, sets up packet framing
//   2. secLinkHandshake()  -- DH key exchange (blocks until both sides complete)
//   3. secLinkSend()       -- send data (optionally encrypted) on a channel
//   4. secLinkPoll()       -- receive, decrypt if needed, deliver to callback
//   5. secLinkClose()      -- tear everything down
//
// Channel multiplexing:
//   Each packet carries a one-byte header: bit 7 = encrypted flag,
//   bits 6..0 = channel number (0-127). This allows multiple logical streams
//   (e.g., terminal data, file transfer, control messages) over a single
//   serial link without needing separate framing or sequencing per stream.
//   The callback receives plaintext regardless of whether encryption was used.
//
// Mixed clear/encrypted traffic:
//   Unencrypted packets can be sent before or after the handshake. This
//   allows a startup protocol (e.g., version negotiation) before keys are
//   exchanged. Encrypted packets require a completed handshake.

#ifndef SECLINK_H
#define SECLINK_H

#include <stdint.h>
#include <stdbool.h>
#include "../packet/packet.h"

// Error codes
#define SECLINK_SUCCESS           0
#define SECLINK_ERR_PARAM        -1
#define SECLINK_ERR_SERIAL       -2
#define SECLINK_ERR_ALLOC        -3
#define SECLINK_ERR_HANDSHAKE    -4
#define SECLINK_ERR_NOT_READY    -5
#define SECLINK_ERR_SEND         -6
#define SECLINK_ERR_TIMEOUT      -7

// Channel header is one byte: bit 7 = encrypted flag, bits 6..0 = channel
#define SECLINK_CHAN_HDR_SIZE    1

// Max plaintext payload per send (packet max minus the channel header)
#define SECLINK_MAX_PAYLOAD      (PKT_MAX_PAYLOAD - SECLINK_CHAN_HDR_SIZE)

// Channel limits.  MAX_CHANNEL is the highest valid channel index;
// NUM_CHANNELS is the array size needed to hold one slot per channel.
#define SECLINK_MAX_CHANNEL      127
#define SECLINK_NUM_CHANNELS     (SECLINK_MAX_CHANNEL + 1)

// Recommended per-channel receive buffer size for callers that buffer
// inbound data between the SecLinkRecvT callback and application read.
// 4096 bytes holds many full secLink payloads (SECLINK_MAX_PAYLOAD=254).
#define SECLINK_CHAN_BUF_SIZE    4096

// Receive callback  -- delivers plaintext with channel number
typedef void (*SecLinkRecvT)(void *ctx, const uint8_t *data, int len, uint8_t channel);

// Opaque handle
typedef struct SecLinkS SecLinkT;


// Open a secure serial link. Opens the COM port and packet layer.
// Handshake must be called separately before sending encrypted data.
SecLinkT *secLinkOpen(int com, int32_t bps, int dataBits, char parity, int stopBits, int handshake, SecLinkRecvT callback, void *ctx);

// Close the link. Frees all resources and closes the COM port.
void secLinkClose(SecLinkT *link);

// Perform DH key exchange. Blocks until both sides have exchanged keys
// and derived cipher keys, or until an internal timeout expires (returns
// SECLINK_ERR_TIMEOUT if the peer never responds). RNG must be seeded
// before calling this.
int secLinkHandshake(SecLinkT *link);

// Get number of unacknowledged packets in the transmit window.
int secLinkGetPending(SecLinkT *link);

// Returns true if handshake is complete and link is ready for data.
bool secLinkIsReady(SecLinkT *link);

// Poll for incoming data. Decrypts if needed and delivers to callback.
// Returns number of packets delivered, or negative on error.
int secLinkPoll(SecLinkT *link);

// Send data on a channel. If encrypt is true, data is encrypted before
// sending (requires completed handshake). Clear packets can be sent
// without a handshake. len must be 1..SECLINK_MAX_PAYLOAD.
// If block is true, waits for transmit window space.
// A blocking send pumps the receive callback; an encrypted send re-entered
// from that callback while an encrypted send is in progress is refused with
// SECLINK_ERR_SEND to keep the cipher streams in sync.
int secLinkSend(SecLinkT *link, const uint8_t *data, int len, uint8_t channel, bool encrypt, bool block);

// Send an arbitrarily large buffer by splitting it into SECLINK_MAX_PAYLOAD
// chunks. Always blocks until all data is sent. Returns SECLINK_SUCCESS
// or the first error encountered.
int secLinkSendBuf(SecLinkT *link, const uint8_t *data, int len, uint8_t channel, bool encrypt);

#endif
