summaryrefslogtreecommitdiff
path: root/src/core/circuit.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/circuit.c')
-rw-r--r--src/core/circuit.c337
1 files changed, 337 insertions, 0 deletions
diff --git a/src/core/circuit.c b/src/core/circuit.c
new file mode 100644
index 0000000..04ac264
--- /dev/null
+++ b/src/core/circuit.c
@@ -0,0 +1,337 @@
+#include "hybbx/circuit.h"
+
+#include <string.h>
+
+static uint32_t read_be32(const uint8_t *p)
+{
+ return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) |
+ ((uint32_t)p[2] << 8) | (uint32_t)p[3];
+}
+
+static uint16_t read_be16(const uint8_t *p)
+{
+ return (uint16_t)(((uint16_t)p[0] << 8) | (uint16_t)p[1]);
+}
+
+static void write_be32(uint8_t *p, uint32_t v)
+{
+ p[0] = (uint8_t)((v >> 24) & 0xFFu);
+ p[1] = (uint8_t)((v >> 16) & 0xFFu);
+ p[2] = (uint8_t)((v >> 8) & 0xFFu);
+ p[3] = (uint8_t)(v & 0xFFu);
+}
+
+static void write_be16(uint8_t *p, uint16_t v)
+{
+ p[0] = (uint8_t)((v >> 8) & 0xFFu);
+ p[1] = (uint8_t)(v & 0xFFu);
+}
+
+const char *hybbx_circuit_proto_name(hybbx_circuit_proto_t proto)
+{
+ switch (proto) {
+ case HYBBX_CIRCUIT_PROTO_AX25:
+ return "ax25";
+ case HYBBX_CIRCUIT_PROTO_AX25_UI:
+ return "ax25_ui";
+ case HYBBX_CIRCUIT_PROTO_LINK_AUTH:
+ return "link_auth";
+ case HYBBX_CIRCUIT_PROTO_LINK_AUTH_ACK:
+ return "link_auth_ack";
+ case HYBBX_CIRCUIT_PROTO_FLOW_CTRL:
+ return "flow_ctrl";
+ case HYBBX_CIRCUIT_PROTO_TERMINAL:
+ return "terminal";
+ case HYBBX_CIRCUIT_PROTO_PROXY_MAIL:
+ return "proxy_mail";
+ case HYBBX_CIRCUIT_PROTO_PROXY_CHAT:
+ return "proxy_chat";
+ case HYBBX_CIRCUIT_PROTO_RESERVED_APRS:
+ return "aprs";
+ case HYBBX_CIRCUIT_PROTO_RESERVED_NETROM:
+ return "netrom";
+ default:
+ return "unknown";
+ }
+}
+
+void hybbx_circuit_decoder_init(hybbx_circuit_decoder_t *dec)
+{
+ if (dec == NULL) {
+ return;
+ }
+
+ memset(dec, 0, sizeof(*dec));
+}
+
+static void circuit_deliver(hybbx_circuit_decoder_t *dec,
+ hybbx_circuit_frame_cb cb, void *userdata)
+{
+ const uint8_t *payload;
+ size_t payload_len;
+
+ if (dec->len < HYBBX_CIRCUIT_HEADER_SIZE) {
+ dec->len = 0;
+ dec->need = 0;
+ dec->have_header = 0;
+ return;
+ }
+
+ payload = dec->buf + HYBBX_CIRCUIT_HEADER_SIZE;
+ payload_len = dec->len - HYBBX_CIRCUIT_HEADER_SIZE;
+
+ if (cb != NULL) {
+ cb(dec->proto, dec->flags, payload, payload_len, userdata);
+ }
+
+ dec->len = 0;
+ dec->need = 0;
+ dec->have_header = 0;
+}
+
+static int circuit_parse_header(hybbx_circuit_decoder_t *dec)
+{
+ const uint8_t *h = dec->buf;
+
+ if (h[0] != HYBBX_CIRCUIT_MAGIC_0 || h[1] != HYBBX_CIRCUIT_MAGIC_1 ||
+ h[2] != HYBBX_CIRCUIT_MAGIC_2 || h[3] != HYBBX_CIRCUIT_VERSION) {
+ return 0;
+ }
+
+ dec->proto = (hybbx_circuit_proto_t)h[4];
+ dec->flags = read_be16(h + 5);
+ dec->need = (size_t)read_be32(h + 7);
+ if (dec->need > HYBBX_CIRCUIT_MAX_PAYLOAD) {
+ return 0;
+ }
+
+ return 1;
+}
+
+void hybbx_circuit_decoder_feed(hybbx_circuit_decoder_t *dec,
+ const uint8_t *data, size_t len,
+ hybbx_circuit_frame_cb cb, void *userdata)
+{
+ size_t i;
+
+ if (dec == NULL || data == NULL) {
+ return;
+ }
+
+ for (i = 0; i < len; i++) {
+ if (dec->len >= sizeof(dec->buf)) {
+ hybbx_circuit_decoder_init(dec);
+ }
+
+ dec->buf[dec->len++] = data[i];
+
+ if (!dec->have_header) {
+ if (dec->len < HYBBX_CIRCUIT_HEADER_SIZE) {
+ continue;
+ }
+ if (!circuit_parse_header(dec)) {
+ memmove(dec->buf, dec->buf + 1, dec->len - 1);
+ dec->len--;
+ continue;
+ }
+ dec->have_header = 1;
+ }
+
+ if (dec->len < HYBBX_CIRCUIT_HEADER_SIZE + dec->need) {
+ continue;
+ }
+
+ circuit_deliver(dec, cb, userdata);
+ }
+}
+
+size_t hybbx_circuit_encode(hybbx_circuit_proto_t proto, uint16_t flags,
+ const uint8_t *payload, size_t payload_len,
+ uint8_t *out, size_t out_cap)
+{
+ if (out == NULL || out_cap < HYBBX_CIRCUIT_HEADER_SIZE) {
+ return 0;
+ }
+
+ if (payload_len > HYBBX_CIRCUIT_MAX_PAYLOAD) {
+ return 0;
+ }
+
+ if (payload_len > 0 && payload == NULL) {
+ return 0;
+ }
+
+ if (HYBBX_CIRCUIT_HEADER_SIZE + payload_len > out_cap) {
+ return 0;
+ }
+
+ out[0] = HYBBX_CIRCUIT_MAGIC_0;
+ out[1] = HYBBX_CIRCUIT_MAGIC_1;
+ out[2] = HYBBX_CIRCUIT_MAGIC_2;
+ out[3] = HYBBX_CIRCUIT_VERSION;
+ out[4] = (uint8_t)proto;
+ write_be16(out + 5, flags);
+
+ write_be32(out + 7, (uint32_t)payload_len);
+ if (payload_len > 0) {
+ memcpy(out + HYBBX_CIRCUIT_HEADER_SIZE, payload, payload_len);
+ }
+
+ return HYBBX_CIRCUIT_HEADER_SIZE + payload_len;
+}
+
+size_t hybbx_circuit_encode_ax25(const uint8_t *frame, size_t frame_len,
+ uint16_t flags,
+ uint8_t *out, size_t out_cap)
+{
+ return hybbx_circuit_encode(HYBBX_CIRCUIT_PROTO_AX25,
+ (uint16_t)(flags | HYBBX_CIRCUIT_FLAG_RX),
+ frame, frame_len, out, out_cap);
+}
+
+static size_t pack_path_payload(const hybbx_ax25_path_t *path,
+ const uint8_t *payload, size_t payload_len,
+ uint8_t *out, size_t out_cap)
+{
+ size_t pos = 0;
+ unsigned i;
+
+ if (path == NULL || out == NULL) {
+ return 0;
+ }
+
+ if (1 + payload_len > out_cap) {
+ return 0;
+ }
+
+ out[pos++] = (uint8_t)path->digi_count;
+ if (pos + HYBBX_AX25_ADDR_ENCODED * (2 + path->digi_count) > out_cap) {
+ return 0;
+ }
+
+ hybbx_ax25_encode_address(out + pos, &path->dest, 0);
+ pos += HYBBX_AX25_ADDR_ENCODED;
+ for (i = 0; i < path->digi_count; i++) {
+ hybbx_ax25_encode_address(out + pos, &path->digi[i], 0);
+ pos += HYBBX_AX25_ADDR_ENCODED;
+ }
+ hybbx_ax25_encode_address(out + pos, &path->source, 1);
+ pos += HYBBX_AX25_ADDR_ENCODED;
+
+ if (payload_len > 0) {
+ if (pos + payload_len > out_cap) {
+ return 0;
+ }
+ memcpy(out + pos, payload, payload_len);
+ pos += payload_len;
+ }
+
+ return pos;
+}
+
+size_t hybbx_circuit_encode_ax25_ui(const hybbx_ax25_path_t *path,
+ const uint8_t *payload, size_t payload_len,
+ uint16_t flags,
+ uint8_t *out, size_t out_cap)
+{
+ uint8_t body[HYBBX_CIRCUIT_MAX_PAYLOAD];
+ size_t body_len;
+
+ body_len = pack_path_payload(path, payload, payload_len, body, sizeof(body));
+ if (body_len == 0 && payload_len > 0) {
+ return 0;
+ }
+
+ return hybbx_circuit_encode(HYBBX_CIRCUIT_PROTO_AX25_UI,
+ (uint16_t)(flags | HYBBX_CIRCUIT_FLAG_PATH),
+ body, body_len, out, out_cap);
+}
+
+size_t hybbx_circuit_encode_terminal(const char *data, size_t len,
+ uint8_t *out, size_t out_cap)
+{
+ return hybbx_circuit_encode(HYBBX_CIRCUIT_PROTO_TERMINAL,
+ HYBBX_CIRCUIT_FLAG_TX,
+ (const uint8_t *)data, len, out, out_cap);
+}
+
+size_t hybbx_circuit_encode_link_msg(hybbx_circuit_proto_t proto,
+ const char *payload, size_t payload_len,
+ uint8_t *out, size_t out_cap)
+{
+ if (proto != HYBBX_CIRCUIT_PROTO_LINK_AUTH &&
+ proto != HYBBX_CIRCUIT_PROTO_LINK_AUTH_ACK) {
+ return 0;
+ }
+
+ return hybbx_circuit_encode(proto, HYBBX_CIRCUIT_FLAG_NONE,
+ (const uint8_t *)payload, payload_len,
+ out, out_cap);
+}
+
+static void decode_address_field(const uint8_t *in, hybbx_ax25_address_t *out)
+{
+ size_t i;
+
+ for (i = 0; i < HYBBX_AX25_CALL_MAX; i++) {
+ char ch = (char)((in[i] >> 1) & 0x7Fu);
+ out->call[i] = ch == ' ' ? '\0' : ch;
+ }
+ out->call[HYBBX_AX25_CALL_MAX] = '\0';
+ out->ssid = (unsigned)((in[6] >> 1) & 0x0Fu);
+}
+
+size_t hybbx_circuit_unpack_ax25_ui(const uint8_t *payload, size_t payload_len,
+ hybbx_ax25_path_t *path,
+ uint8_t *ui, size_t ui_cap)
+{
+ size_t pos = 0;
+ unsigned digi_count;
+ unsigned i;
+
+ if (payload == NULL || payload_len < 1) {
+ return 0;
+ }
+
+ if (path != NULL) {
+ memset(path, 0, sizeof(*path));
+ }
+
+ digi_count = payload[0];
+ if (digi_count > HYBBX_AX25_MAX_DIGI) {
+ return 0;
+ }
+
+ pos = 1;
+ if (pos + HYBBX_AX25_ADDR_ENCODED * (size_t)(2 + digi_count) > payload_len) {
+ return 0;
+ }
+
+ if (path != NULL) {
+ decode_address_field(payload + pos, &path->dest);
+ pos += HYBBX_AX25_ADDR_ENCODED;
+ for (i = 0; i < digi_count; i++) {
+ decode_address_field(payload + pos, &path->digi[i]);
+ pos += HYBBX_AX25_ADDR_ENCODED;
+ }
+ path->digi_count = digi_count;
+ decode_address_field(payload + pos, &path->source);
+ } else {
+ pos += HYBBX_AX25_ADDR_ENCODED * (size_t)(2 + digi_count);
+ }
+ pos += HYBBX_AX25_ADDR_ENCODED;
+
+ {
+ size_t ui_len = payload_len - pos;
+
+ if (ui_len > ui_cap) {
+ return 0;
+ }
+
+ if (ui_len > 0 && ui != NULL) {
+ memcpy(ui, payload + pos, ui_len);
+ }
+
+ return ui_len;
+ }
+}
git clone -b <branch> https://cgit.mode42.com/<repo>.git
git clone -b <branch> git://cgit.mode42.com/<repo>.git

info@mode42.com