/* * 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 #include #include #include #include #include #include #include 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; }