aboutsummaryrefslogtreecommitdiff
path: root/src/protocol
diff options
context:
space:
mode:
authorXavier Del Campo Romero <xavi92@disroot.org>2025-09-09 03:14:50 +0200
committerXavier Del Campo Romero <xavi92@disroot.org>2025-09-18 01:08:14 +0200
commitc11cb04929f28853142b14339b66f561ca028f36 (patch)
treea77a3ddcc1d01028e4077cb295b9b41f594c5d52 /src/protocol
First commitHEADmaster
Diffstat (limited to 'src/protocol')
-rw-r--r--src/protocol/CMakeLists.txt10
-rw-r--r--src/protocol/icmp/CMakeLists.txt14
-rw-r--r--src/protocol/icmp/alloc.c29
-rw-r--r--src/protocol/icmp/free.c25
-rw-r--r--src/protocol/icmp/rx.c200
-rw-r--r--src/protocol/icmp/start.c205
-rw-r--r--src/protocol/icmp/tx.c21
-rw-r--r--src/protocol/tcp/CMakeLists.txt13
-rw-r--r--src/protocol/tcp/alloc.c20
-rw-r--r--src/protocol/tcp/free.c19
-rw-r--r--src/protocol/tcp/rx.c21
-rw-r--r--src/protocol/tcp/tx.c21
-rw-r--r--src/protocol/udp/CMakeLists.txt13
-rw-r--r--src/protocol/udp/alloc.c20
-rw-r--r--src/protocol/udp/free.c19
-rw-r--r--src/protocol/udp/rx.c21
-rw-r--r--src/protocol/udp/tx.c21
17 files changed, 692 insertions, 0 deletions
diff --git a/src/protocol/CMakeLists.txt b/src/protocol/CMakeLists.txt
new file mode 100644
index 0000000..194274d
--- /dev/null
+++ b/src/protocol/CMakeLists.txt
@@ -0,0 +1,10 @@
+# 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/.
+
+add_subdirectory(icmp)
+add_subdirectory(tcp)
+add_subdirectory(udp)
diff --git a/src/protocol/icmp/CMakeLists.txt b/src/protocol/icmp/CMakeLists.txt
new file mode 100644
index 0000000..4fd374d
--- /dev/null
+++ b/src/protocol/icmp/CMakeLists.txt
@@ -0,0 +1,14 @@
+# 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/.
+
+target_sources(${PROJECT_NAME} PRIVATE
+ alloc.c
+ free.c
+ rx.c
+ start.c
+ tx.c
+)
diff --git a/src/protocol/icmp/alloc.c b/src/protocol/icmp/alloc.c
new file mode 100644
index 0000000..23d7329
--- /dev/null
+++ b/src/protocol/icmp/alloc.c
@@ -0,0 +1,29 @@
+/*
+ * 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/log.h>
+#include <wip/prv/icmp.h>
+#include <wip/prv/icmp/routines.h>
+#include <wip/prv/icmp/types.h>
+#include <stddef.h>
+
+void *wip_icmp_alloc(struct wip *const w)
+{
+ const struct wip_cfg *const cfg = &w->cfg;
+ const struct wip_icmp z = {0};
+ struct wip_icmp *const ret = cfg->alloc(sizeof *ret, cfg->user);
+
+ if (!ret)
+ return ret;
+
+ *ret = z;
+ ret->next = wip_icmp_rx_start;
+ return ret;
+}
diff --git a/src/protocol/icmp/free.c b/src/protocol/icmp/free.c
new file mode 100644
index 0000000..452e1d4
--- /dev/null
+++ b/src/protocol/icmp/free.c
@@ -0,0 +1,25 @@
+/*
+ * 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/log.h>
+#include <wip/prv/icmp.h>
+#include <wip/prv/icmp/types.h>
+#include <stddef.h>
+
+void wip_icmp_free(struct wip *const w, void *const args)
+{
+ const struct wip_cfg *const cfg = &w->cfg;
+ struct wip_icmp *const icmp = args;
+
+ if (icmp)
+ cfg->free(icmp->buf, cfg->user);
+
+ cfg->free(icmp, cfg->user);
+}
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
+}
diff --git a/src/protocol/icmp/start.c b/src/protocol/icmp/start.c
new file mode 100644
index 0000000..f50052e
--- /dev/null
+++ b/src/protocol/icmp/start.c
@@ -0,0 +1,205 @@
+/*
+ * 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/routines.h>
+#include <wip/prv/icmp/types.h>
+#include <stddef.h>
+#include <string.h>
+
+struct read
+{
+ const void *buf;
+ size_t n;
+ struct wip_icmp *icmp;
+};
+
+static int io_read(void *const buf, const size_t n, void *const user)
+{
+ const struct read *const r = user;
+ const size_t ret = n > r->n ? r->n : n;
+
+ memcpy(buf, r->buf, ret);
+ return ret;
+}
+
+static enum wip_state readbuf(struct wip_sm_io *const io, const void *const buf,
+ const size_t n, struct wip_icmp *const icmp)
+{
+ struct wip_cfg cfg = {0};
+ struct read r;
+
+ r.buf = buf;
+ r.n = n;
+ r.icmp = icmp;
+
+ cfg.read = io_read;
+ cfg.user = &r;
+ return wip_io_read_c(&cfg, io);
+}
+
+enum wip_state get_payload(struct wip *const w, const void *const buf,
+ const size_t n, struct wip_icmp *const icmp, size_t *const r)
+{
+ const struct wip_cfg *const cfg = &w->cfg;
+ const size_t nsz = icmp->read + n;
+ char *const nbuf = cfg->realloc(icmp->buf, nsz, cfg->user);
+ size_t i;
+
+ if (!nbuf)
+ return WIP_FATAL;
+
+ memcpy(nbuf + icmp->read, buf, n);
+ icmp->buf = nbuf;
+ icmp->read += n;
+ *r = n;
+
+ for (i = icmp->read; i < nsz; i++)
+ icmp->checksum += *(const char *)icmp->buf;
+
+ wip_log("ICMP data={");
+
+ for (i = 0; i < icmp->read; i++)
+ {
+ wip_log("%#hhx", *((const char *)icmp->buf + i));
+
+ if (i + 1 < icmp->read)
+ wip_log(", ");
+ }
+
+ wip_log("}\n");
+
+ wip_log("calculated checksum: %#hx, expected checksum: %#hx\n",
+ icmp->checksum, wip_be16(&icmp->exp_checksum));
+ return WIP_OK;
+}
+
+enum wip_state get_seqnum(struct wip *const w, const void *const buf,
+ const size_t n, struct wip_icmp *const icmp, size_t *const r)
+{
+ const enum wip_state state = readbuf(&icmp->io, buf, n, icmp);
+
+ if (state)
+ return state;
+ else
+ {
+ struct wip_sm_io io = {0};
+
+ io.buf = &icmp->seqnum;
+ io.n = sizeof icmp->seqnum;
+ icmp->io = io;
+ }
+
+ wip_log("got seqnum: %#x\n", wip_be16(&icmp->seqnum));
+ icmp->checksum += wip_be16(&icmp->seqnum);
+ icmp->next = get_payload;
+ *r = sizeof icmp->seqnum;
+ return WIP_AGAIN;
+}
+
+enum wip_state get_id(struct wip *const w, const void *const buf,
+ const size_t n, struct wip_icmp *const icmp, size_t *const r)
+{
+ const enum wip_state state = readbuf(&icmp->io, buf, n, icmp);
+
+ if (state)
+ return state;
+ else
+ {
+ struct wip_sm_io io = {0};
+
+ io.buf = &icmp->seqnum;
+ io.n = sizeof icmp->seqnum;
+ icmp->io = io;
+ }
+
+ wip_log("got id: %#x\n", wip_be16(&icmp->id));
+ icmp->checksum += wip_be16(&icmp->id);
+ icmp->next = get_seqnum;
+ *r = sizeof icmp->id;
+ return WIP_AGAIN;
+}
+
+enum wip_state get_checksum(struct wip *const w, const void *const buf,
+ const size_t n, struct wip_icmp *const icmp, size_t *const r)
+{
+ const enum wip_state state = readbuf(&icmp->io, buf, n, icmp);
+
+ if (state)
+ return state;
+ else
+ {
+ struct wip_sm_io io = {0};
+
+ io.buf = &icmp->id;
+ io.n = sizeof icmp->id;
+ icmp->io = io;
+ }
+
+ wip_log("got expected checksum: %#x\n", wip_be16(&icmp->exp_checksum));
+ icmp->next = get_id;
+ *r = sizeof icmp->exp_checksum;
+ return WIP_AGAIN;
+}
+
+enum wip_state get_code(struct wip *const w, const void *const buf,
+ const size_t n, struct wip_icmp *const icmp, size_t *const r)
+{
+ unsigned char code;
+ struct wip_sm_io io = {0};
+ enum wip_state state;
+
+ io.buf = &code;
+ io.n = sizeof code;
+
+ if ((state = readbuf(&io, buf, n, icmp)))
+ return state;
+ else if (code)
+ return WIP_INVALID;
+ else
+ {
+ struct wip_sm_io nio = {0};
+
+ nio.buf = &icmp->exp_checksum;
+ nio.n = sizeof icmp->exp_checksum;
+ icmp->io = nio;
+ }
+
+ wip_log("got code\n");
+ icmp->checksum += code;
+ icmp->next = get_checksum;
+ *r = sizeof code;
+ return WIP_AGAIN;
+}
+
+enum wip_state wip_icmp_rx_start(struct wip *const w, const void *const buf,
+ const size_t n, struct wip_icmp *const icmp, size_t *const r)
+{
+ unsigned char type;
+ struct wip_sm_io io = {0};
+ enum wip_state state;
+
+ io.buf = &type;
+ io.n = sizeof type;
+
+ if ((state = readbuf(&io, buf, n, icmp)))
+ return state;
+ else if (type != ICMP_ECHO_REQUEST)
+ return WIP_INVALID;
+
+ wip_log("got echo request\n");
+ icmp->checksum += type;
+ icmp->type = type;
+ icmp->next = get_code;
+ *r = sizeof type;
+ return WIP_AGAIN;
+}
diff --git a/src/protocol/icmp/tx.c b/src/protocol/icmp/tx.c
new file mode 100644
index 0000000..27fe876
--- /dev/null
+++ b/src/protocol/icmp/tx.c
@@ -0,0 +1,21 @@
+/*
+ * 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/log.h>
+#include <wip/prv/icmp.h>
+#include <wip/prv/icmp/types.h>
+#include <stddef.h>
+
+int wip_icmp_tx(struct wip *const wip, void *const buf, const size_t n,
+ void *const args)
+{
+ wip_log("%s: TODO\n");
+ return 0;
+}
diff --git a/src/protocol/tcp/CMakeLists.txt b/src/protocol/tcp/CMakeLists.txt
new file mode 100644
index 0000000..0caec18
--- /dev/null
+++ b/src/protocol/tcp/CMakeLists.txt
@@ -0,0 +1,13 @@
+# 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/.
+
+target_sources(${PROJECT_NAME} PRIVATE
+ alloc.c
+ free.c
+ rx.c
+ tx.c
+)
diff --git a/src/protocol/tcp/alloc.c b/src/protocol/tcp/alloc.c
new file mode 100644
index 0000000..c90f1c9
--- /dev/null
+++ b/src/protocol/tcp/alloc.c
@@ -0,0 +1,20 @@
+/*
+ * 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/log.h>
+#include <wip/prv/tcp.h>
+#include <wip/prv/tcp/types.h>
+#include <stddef.h>
+
+void *wip_tcp_alloc(struct wip *const w)
+{
+ wip_log("%s: TODO\n", __func__);
+ return NULL;
+}
diff --git a/src/protocol/tcp/free.c b/src/protocol/tcp/free.c
new file mode 100644
index 0000000..ddde038
--- /dev/null
+++ b/src/protocol/tcp/free.c
@@ -0,0 +1,19 @@
+/*
+ * 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/log.h>
+#include <wip/prv/tcp.h>
+#include <wip/prv/tcp/types.h>
+#include <stddef.h>
+
+void wip_tcp_free(struct wip *const w, void *const args)
+{
+ wip_log("%s: TODO\n", __func__);
+}
diff --git a/src/protocol/tcp/rx.c b/src/protocol/tcp/rx.c
new file mode 100644
index 0000000..6b23546
--- /dev/null
+++ b/src/protocol/tcp/rx.c
@@ -0,0 +1,21 @@
+/*
+ * 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/log.h>
+#include <wip/prv/tcp.h>
+#include <wip/prv/tcp/types.h>
+#include <stddef.h>
+
+enum wip_state wip_tcp_rx(struct wip *const wip, const void *const buf,
+ const size_t n, void *const args)
+{
+ wip_log("%s: TODO\n");
+ return WIP_OK;
+}
diff --git a/src/protocol/tcp/tx.c b/src/protocol/tcp/tx.c
new file mode 100644
index 0000000..55524e3
--- /dev/null
+++ b/src/protocol/tcp/tx.c
@@ -0,0 +1,21 @@
+/*
+ * 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/log.h>
+#include <wip/prv/tcp.h>
+#include <wip/prv/tcp/types.h>
+#include <stddef.h>
+
+int wip_tcp_tx(struct wip *const wip, void *const buf, const size_t n,
+ void *const args)
+{
+ wip_log("%s: TODO\n");
+ return 0;
+}
diff --git a/src/protocol/udp/CMakeLists.txt b/src/protocol/udp/CMakeLists.txt
new file mode 100644
index 0000000..0caec18
--- /dev/null
+++ b/src/protocol/udp/CMakeLists.txt
@@ -0,0 +1,13 @@
+# 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/.
+
+target_sources(${PROJECT_NAME} PRIVATE
+ alloc.c
+ free.c
+ rx.c
+ tx.c
+)
diff --git a/src/protocol/udp/alloc.c b/src/protocol/udp/alloc.c
new file mode 100644
index 0000000..d812ea5
--- /dev/null
+++ b/src/protocol/udp/alloc.c
@@ -0,0 +1,20 @@
+/*
+ * 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/log.h>
+#include <wip/prv/udp.h>
+#include <wip/prv/udp/types.h>
+#include <stddef.h>
+
+void *wip_udp_alloc(struct wip *const w)
+{
+ wip_log("%s: TODO\n", __func__);
+ return NULL;
+}
diff --git a/src/protocol/udp/free.c b/src/protocol/udp/free.c
new file mode 100644
index 0000000..c6354fb
--- /dev/null
+++ b/src/protocol/udp/free.c
@@ -0,0 +1,19 @@
+/*
+ * 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/log.h>
+#include <wip/prv/udp.h>
+#include <wip/prv/udp/types.h>
+#include <stddef.h>
+
+void wip_udp_free(struct wip *const w, void *const args)
+{
+ wip_log("%s: TODO\n", __func__);
+}
diff --git a/src/protocol/udp/rx.c b/src/protocol/udp/rx.c
new file mode 100644
index 0000000..29aa4cc
--- /dev/null
+++ b/src/protocol/udp/rx.c
@@ -0,0 +1,21 @@
+/*
+ * 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/log.h>
+#include <wip/prv/udp.h>
+#include <wip/prv/udp/types.h>
+#include <stddef.h>
+
+enum wip_state wip_udp_rx(struct wip *const wip, const void *const buf,
+ const size_t n, void *const args)
+{
+ wip_log("%s: TODO\n");
+ return WIP_OK;
+}
diff --git a/src/protocol/udp/tx.c b/src/protocol/udp/tx.c
new file mode 100644
index 0000000..a29ec0f
--- /dev/null
+++ b/src/protocol/udp/tx.c
@@ -0,0 +1,21 @@
+/*
+ * 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/log.h>
+#include <wip/prv/udp.h>
+#include <wip/prv/udp/types.h>
+#include <stddef.h>
+
+int wip_udp_tx(struct wip *const wip, void *const buf, const size_t n,
+ void *const args)
+{
+ wip_log("%s: TODO\n");
+ return 0;
+}