ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
lower.h
Go to the documentation of this file.
1// ProtoCore v1.0.16 - Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file lower.h
6 * @brief Layer 4 (Transport) - the TCP/lower-level interface (RFC 9293 sec 3.9.2).
7 *
8 * "The TCP endpoint calls on a lower-level protocol module to actually send and receive
9 * information over a network." Every such call this library makes goes through here: the write,
10 * the push, the close, the reset, the window update, and the DS field (sec 3.9.2 names the
11 * Diffserv value as one the user supplies to the lower layer).
12 *
13 * The byte stream is the floor. Nothing below the platform's own TCP is modelled here; this module
14 * is the one place that names it, so no other file in the layer holds a raw stack call.
15 *
16 * **Why the ops are marshaled**
17 * The raw stack API is not thread-safe: its callbacks run in the stack's own task, while this
18 * library issues writes and closes from a worker. Issuing one concurrently with the stack
19 * processing an inbound segment corrupts the connection state. The portable fix is the stack's own
20 * marshaling call, which runs a function inside the stack's context and blocks the caller until it
21 * completes. A raw callback already runs in that context and must NOT marshal again - it performs
22 * its op inline instead, or it would block on the very mailbox its own thread services.
23 *
24 * @author Douglas Quigg (dstroy0)
25 * @date 2026
26 */
27
28#ifndef PROTOCORE_TCP_LOWER_H
29#define PROTOCORE_TCP_LOWER_H
30
32
33#include "protocore_config.h"
34
36
37/**
38 * @brief The TTL outbound TCP segments carry.
39 *
40 * RFC 9293 sec 3.9.2 MUST-49: "The TTL value used to send TCP segments MUST be configurable." RFC
41 * 793 fixed it at one minute; RFC 1122 replaced that with this requirement. Overridable at build
42 * time; the running value is set through ::TcpLowerNs::set_ttl, which takes the candidate in
43 * @c len, and stamped onto a control block by ::TcpLowerNs::apply_ttl.
44 */
45#ifndef PROTOCORE_TCP_TTL
46#define PROTOCORE_TCP_TTL 64
47#endif
48
49/** @brief Which call into the lower-level module a marshaled op performs. */
51{
57 PROTOCORE_OP_RAWSEND, // raw write of already-encrypted bytes (TLS BIO), no TLS re-entry
58 PROTOCORE_OP_CLOSE_CHECK, // in stack context: finalize a CONN_CLOSING slot if its TX has drained
59 PROTOCORE_OP_RECVED, // in stack context: reopen the receive window (ack-on-consume)
60 PROTOCORE_OP_SET_TTL, // in stack context: stamp the TTL on a control block; len carries the value
62static_assert(sizeof(protocore_tcp_op) == 1, "protocore_tcp_op must stay one byte (PROTO_ENUM_PACKED)");
63
64/**
65 * @brief The lower-level interface: what this endpoint can ask the module below it to do.
66 *
67 * A caller sets the op it wants and what it acts on, invokes it through ::TcpLower, and reads the
68 * outcome off the same handle. The seam's own state - the stack thread it captured, the TTL it
69 * stamps, and the call records - is behind @ref internal and is not describable here.
70 *
71 * @var TcpLowerNs::op which call into the lower module to make
72 * @var TcpLowerNs::slot the connection the op acts on
73 * @var TcpLowerNs::pcb the control block the op acts on
74 * @var TcpLowerNs::data bytes for a write
75 * @var TcpLowerNs::len how many, or the byte a stamping op carries
76 * @var TcpLowerNs::flush SEND: push after a successful write
77 * @var TcpLowerNs::result what the op reported
78 * @var TcpLowerNs::ok a call's true/false outcome
79 */
80typedef struct
81{
83 uint8_t slot;
84 protocore_pcb *pcb;
85 const void *data;
88 protocore_net_err result;
90 /// Run the op set above, in the one context where it is safe. The outcome lands in @c result.
91 /// Drop the control block's back-reference, so a late callback finds a null arg.
92 /// Reset the control block (RFC 9293 sec 3.10.5): a hard close, no FIN.
93 /// Install the TTL outbound segments carry; the candidate arrives in len, the verdict in @c ok.
94 /// Stamp the control block above with the configured TTL.
96
97/** @brief The operands and the outcome. */
99
100/** @brief The entries. */
101typedef struct
102{
103 void (*const marshal)(uint8_t *work);
104 void (*const detach)(uint8_t *work);
105 void (*const abort)(uint8_t *work);
106 void (*const set_ttl)(uint8_t *work);
107 void (*const apply_ttl)(uint8_t *work);
108} TcpLowerNs;
109
110// What the table binds, defined once in the .c and taking one parameter each: everything
111// else an entry needs is an operand in TcpLowerV or a region of the borrow at a fixed offset.
112void protocore_tcp_lower_marshal(uint8_t *work);
113void protocore_tcp_lower_detach(uint8_t *work);
114void protocore_tcp_lower_abort(uint8_t *work);
115void protocore_tcp_lower_set_ttl(uint8_t *work);
117
118// `static const`, initialised HERE rather than `extern` against a definition in the .c: a
119// const object whose initializer every translation unit can see is a COMPILE-TIME FACT, so
120// `TcpLower.marshal(work)` resolves to a named function and becomes a DIRECT call. An extern table
121// leaves the call indirect and the symbol live at every level, -O2 -flto included.
122static const TcpLowerNs TcpLower __attribute__((unused)) = {
128};
129
130/**
131 * @brief The PROTOCORE_TCP_LOWER_BORROW bytes this module's state lives in.
132 *
133 * Stated beside the namespace rather than on it: an entry takes a borrow, and this is where
134 * that borrow comes from. Taken once from the end of the pool, which no mark and no release
135 * walks, so the state lasts the life of the program.
136 *
137 * @return the span.
138 */
140
142
143#endif // PROTOCORE_TCP_LOWER_H
PROTO_ENUM_PACKED
Application protocol spoken on a listener port or connection slot.
void protocore_tcp_lower_abort(uint8_t *work)
enum PROTO_ENUM_PACKED protocore_tcp_op
Which call into the lower-level module a marshaled op performs.
uint8_t * protocore_tcp_lower_span(void)
The PROTOCORE_TCP_LOWER_BORROW bytes this module's state lives in.
TcpLowerVars TcpLowerV
The operands and the outcome.
void protocore_tcp_lower_detach(uint8_t *work)
void protocore_tcp_lower_marshal(uint8_t *work)
@ PROTOCORE_OP_RAWSEND
Definition lower.h:57
@ PROTOCORE_OP_CLOSE_CHECK
Definition lower.h:58
@ PROTOCORE_OP_ABORT
Definition lower.h:55
@ PROTOCORE_OP_CLOSE
Definition lower.h:54
@ PROTOCORE_OP_SEND
Definition lower.h:52
@ PROTOCORE_OP_DETACH
Definition lower.h:56
@ PROTOCORE_OP_SET_TTL
Definition lower.h:60
@ PROTOCORE_OP_OUTPUT
Definition lower.h:53
@ PROTOCORE_OP_RECVED
Definition lower.h:59
void protocore_tcp_lower_set_ttl(uint8_t *work)
void protocore_tcp_lower_apply_ttl(uint8_t *work)
The entries.
Definition lower.h:102
void(*const marshal)(uint8_t *work)
Definition lower.h:103
proto_u16 len
Definition lower.h:86
const void * data
Definition lower.h:85
proto_bool flush
Definition lower.h:87
protocore_tcp_op op
Definition lower.h:82
proto_bool ok
Definition lower.h:89
uint8_t slot
Definition lower.h:83
protocore_pcb * pcb
Definition lower.h:84
protocore_net_err result
Definition lower.h:88
Layer 4 (Transport) - the connection state every half of TCP reads.
#define PROTOCORE_BEGIN_DECLS
Give a header's declarations C linkage, so their symbol names carry no parameter types.
Definition types.h:96
_Bool proto_bool
The truth value.
Definition types.h:64
uint16_t proto_u16
Definition types.h:41
#define PROTOCORE_END_DECLS
Definition types.h:97