aboutsummaryrefslogtreecommitdiff
path: root/src/protocol/icmp/rx.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/protocol/icmp/rx.c')
-rw-r--r--src/protocol/icmp/rx.c200
1 files changed, 200 insertions, 0 deletions
diff --git a/src/protocol/icmp/rx.c b/src/protocol/icmp/rx.c
new file mode 100644
index 0000000..8e543f9
--- /dev/null
+++ b/src/protocol/icmp/rx.c
@@ -0,0 +1,200 @@
+/*
+ * wip, a small TCP/IP stack.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+#include <wip/wip.h>
+#include <wip/prv/io.h>
+#include <wip/prv/log.h>
+#include <wip/prv/icmp.h>
+#include <wip/prv/icmp/types.h>
+#include <stddef.h>
+#include <string.h>
+
+enum
+{
+ TYPE,
+ CHECKSUM = 2,
+ ID = 4,
+ SEQ_NUM = 6,
+ DATA = 8
+};
+
+#if 0
+
+static int get_type(struct wip_icmp *const icmp,
+ const unsigned char *const p, const size_t n)
+{
+ unsigned char type;
+
+ if (icmp->read)
+ return 0;
+
+ type = p[0];
+
+ if (type != ECHO_REQUEST)
+ return -1;
+
+ wip_log("%s: got echo request\n");
+ icmp->type = type;
+ return 0;
+}
+
+static void get_checksum(struct wip_icmp *const icmp,
+ const unsigned char *const p, const size_t n)
+{
+ size_t off;
+ struct wip_be16 v;
+ enum {END = CHECKSUM + sizeof v};
+
+ if (icmp->read >= END || n < END - icmp->read)
+ return;
+
+ off = CHECKSUM - icmp->read;
+ v.v[0] = p[off];
+ v.v[1] = p[off + 1];
+ icmp->exp_checksum = wip_be16(&v);
+}
+
+static void get_id(struct wip_icmp *const icmp, const unsigned char *const p,
+ const size_t n)
+{
+ size_t off;
+ struct wip_be16 v;
+ enum {END = ID + sizeof v};
+
+ if (icmp->read >= END || n < END - icmp->read)
+ return;
+
+ off = ID - icmp->read;
+ v.v[0] = p[off];
+ v.v[1] = p[off + 1];
+ icmp->id = wip_be16(&v);
+}
+
+static void get_seqnum(struct wip_icmp *const icmp, const unsigned char *const p,
+ const size_t n)
+{
+ size_t off;
+ struct wip_be16 v;
+ enum {END = SEQ_NUM + sizeof v};
+
+ if (icmp->read >= END || n < END - icmp->read)
+ return;
+
+ off = SEQ_NUM - icmp->read;
+ v.v[0] = p[off];
+ v.v[1] = p[off + 1];
+ icmp->seqnum = wip_be16(&v);
+ wip_log("chksum=%#x, id=%#x, seq_num=%#x\n", icmp->exp_checksum,
+ icmp->id, icmp->seqnum);
+}
+
+static enum wip_state get_data(struct wip *const w,
+ struct wip_icmp *const icmp, const unsigned char *const p, const size_t n)
+{
+ const struct wip_cfg *const cfg = &w->cfg;
+ const size_t offset = icmp->read + n;
+ const void *src = p;
+ size_t sz = n;
+
+ if (offset < DATA)
+ return WIP_OK;
+ else if (!icmp->buf)
+ {
+ sz = n - DATA - icmp->read;
+ src = p + DATA - icmp->read;
+
+ if (!(icmp->buf = cfg->alloc(sz, cfg->user)))
+ return WIP_FATAL;
+ }
+ else
+ {
+ const size_t nsz = icmp->n + n;
+ enum {MAXSZ = 40};
+ void *buf;
+
+ if (nsz > MAXSZ)
+ return WIP_INVALID;
+ else if (!(buf = cfg->realloc(icmp->buf, nsz, cfg->user)))
+ return WIP_FATAL;
+
+ icmp->buf = buf;
+ }
+
+ memcpy((char *)icmp->buf + icmp->read, src, sz);
+ icmp->n += sz;
+
+ wip_log("data (%lu bytes): {", (unsigned long)icmp->n);
+
+ {
+ size_t i;
+
+ for (i = 0; i < icmp->n; i++)
+ {
+ wip_log("%#hhx", *((const char *)icmp->buf + i));
+
+ if (i + 1 < icmp->n)
+ wip_log(", ");
+ }
+ }
+
+ wip_log("}\n");
+ return WIP_OK;
+}
+#endif
+
+enum wip_state wip_icmp_rx(struct wip *const w, const void *buf,
+ size_t n, void *const args)
+{
+ struct wip_icmp *const icmp = args;
+ enum wip_state ret;
+ size_t r;
+
+ while ((ret = icmp->next(w, buf, n, icmp, &r)) == WIP_AGAIN)
+ {
+ buf = (const char *)buf + r;
+ n -= r;
+ }
+
+ return ret;
+
+#if 0
+ enum wip_state (*next)(struct wip *, const void *, size_t,
+ struct wip_icmp *)
+
+ const struct wip_rx_sm_h *const h = &w->rx.sm.h;
+ const unsigned char *const p = buf;
+ const unsigned short dlen = wip_be16(&h->len) - h->header_sz;
+
+ enum wip_state ret;
+ size_t i;
+
+ if (get_type(icmp, buf, n))
+ return 0;
+
+ get_checksum(icmp, buf, n);
+ get_id(icmp, buf, n);
+ get_seqnum(icmp, buf, n);
+
+ if ((ret = get_data(w, icmp, buf, n)))
+ return ret;
+
+ for (i = 0; i < n; i++)
+ /* Avoid suming checksum */
+ if (icmp->read >= CHECKSUM || ((i != 2) && (i != 3)))
+ icmp->checksum += p[i];
+
+ if (icmp->read += n >= dlen)
+ {
+ wip_log("expected checksum=%#x, got=%#x\n",
+ icmp->exp_checksum, icmp->checksum);
+ }
+
+ return WIP_OK;
+#endif
+}