ProtoCore v0.0.2
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
iface_bridge.cpp
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
5
6#if PC_ENABLE_IFACE_BRIDGE
7
8#include <string.h>
9
10namespace
11{
12/// The one owned mutable: the address:port -> bus rule table.
13struct BridgeCtx
14{
15 BridgeRule rules[PC_BRIDGE_MAX_RULES];
16 uint8_t count;
17};
18BridgeCtx s_bridge;
19} // namespace
20
21void pc_iface_bridge_clear()
22{
23 for (uint8_t i = 0; i < PC_BRIDGE_MAX_RULES; i++)
24 {
25 s_bridge.rules[i].used = false;
26 }
27 s_bridge.count = 0;
28}
29
30bool pc_iface_bridge_add(const BridgeRule *rule)
31{
32 if (!rule)
33 {
34 return false;
35 }
36 if (pc_iface_bridge_find(rule->listen_port, rule->proto))
37 {
38 return false; // a rule already binds this port+proto
39 }
40 for (uint8_t i = 0; i < PC_BRIDGE_MAX_RULES; i++)
41 {
42 if (!s_bridge.rules[i].used)
43 {
44 s_bridge.rules[i] = *rule;
45 s_bridge.rules[i].used = true;
46 s_bridge.count++;
47 return true;
48 }
49 }
50 return false; // table full
51}
52
53bool pc_iface_bridge_map(const char *ip, uint16_t port, BridgeProto proto, const BridgeTarget *target)
54{
55 if (!target)
56 {
57 return false;
58 }
59 BridgeRule r;
60 memset(&r, 0, sizeof(r));
61 r.listen_ip.family = pc_ip_family::PC_IP_NONE; // "any interface" unless a valid address is given
62 if (ip && ip[0] && !pc_ip_parse(ip, &r.listen_ip))
63 {
64 return false; // malformed bind address
65 }
66 r.listen_port = port;
67 r.proto = proto;
68 r.target = *target;
69 return pc_iface_bridge_add(&r);
70}
71
72const BridgeRule *pc_iface_bridge_find(uint16_t port, BridgeProto proto)
73{
74 for (uint8_t i = 0; i < PC_BRIDGE_MAX_RULES; i++)
75 {
76 if (s_bridge.rules[i].used && s_bridge.rules[i].listen_port == port && s_bridge.rules[i].proto == proto)
77 {
78 return &s_bridge.rules[i];
79 }
80 }
81 return nullptr;
82}
83
84uint8_t pc_iface_bridge_count()
85{
86 return s_bridge.count;
87}
88
89size_t pc_iface_bridge_txn_parse(const uint8_t *buf, size_t len, uint16_t *write_len, uint16_t *read_len,
90 const uint8_t **write_data)
91{
92 if (!buf || len < (size_t)PC_BRIDGE_TXN_HDR)
93 {
94 return 0;
95 }
96 uint16_t wl = (uint16_t)(((uint16_t)buf[0] << 8) | buf[1]);
97 uint16_t rl = (uint16_t)(((uint16_t)buf[2] << 8) | buf[3]);
98 if (len < (size_t)PC_BRIDGE_TXN_HDR + wl)
99 {
100 return 0; // the write payload has not fully arrived yet
101 }
102 if (write_len)
103 {
104 *write_len = wl;
105 }
106 if (read_len)
107 {
108 *read_len = rl;
109 }
110 if (write_data)
111 {
112 *write_data = buf + PC_BRIDGE_TXN_HDR;
113 }
114 return (size_t)PC_BRIDGE_TXN_HDR + wl;
115}
116
117size_t pc_iface_bridge_txn_build(uint8_t *out, size_t cap, const uint8_t *write_data, uint16_t write_len,
118 uint16_t read_len)
119{
120 size_t need = (size_t)PC_BRIDGE_TXN_HDR + write_len;
121 if (!out || cap < need)
122 {
123 return 0;
124 }
125 out[0] = (uint8_t)(write_len >> 8);
126 out[1] = (uint8_t)write_len;
127 out[2] = (uint8_t)(read_len >> 8);
128 out[3] = (uint8_t)read_len;
129 if (write_len && write_data)
130 {
131 memcpy(out + PC_BRIDGE_TXN_HDR, write_data, write_len);
132 }
133 return need;
134}
135
136#endif // PC_ENABLE_IFACE_BRIDGE
User-defined address:port -> hardware-bus translation (PC_ENABLE_IFACE_BRIDGE).
bool pc_ip_parse(const char *s, pc_ip *out)
Parse an IPv4 or IPv6 textual address (RFC 4291 ยง2.2) into out.
Definition ip.cpp:436
@ PC_IP_NONE
empty / unparsed
#define PC_BRIDGE_MAX_RULES
Max concurrent address:port -> bus rules (services/net/iface_bridge).