#include "test_handlers.h" #include #include #include "pico/stdlib.h" #include "pico/time.h" #include "net.h" #include "icmp.h" static ResponseTest test_discovery(const responder&) { ResponseTest resp; resp.pass = true; resp.messages.push_back("TODO: rewrite as deferred test"); return resp; } static void test_ping(const responder& resp, ipv4::ip4_addr dst_ip) { auto& ns = net_get_state(); uint16_t ping_id = 0x1234; uint8_t tx_buf[128]; size_t len = icmp::build_echo_request( std::span{tx_buf}, ns.mac, ns.ip, eth::MAC_BROADCAST, dst_ip, ping_id, 1); if (len == 0) { resp.respond(ResponseTest{false, {"build_echo_request failed"}}); return; } net_send_raw(std::span{tx_buf, len}); ipv4::ip4_addr our_ip = ns.ip; auto done = std::make_shared(false); auto cb = std::make_shared)>>(); *cb = [resp, ping_id, our_ip, done, cb](std::span frame) { if (*done) return; ipv4::ip4_addr src_ip; if (!icmp::parse_echo_reply(frame, src_ip, ping_id)) { net_add_frame_callback(*cb); return; } if (src_ip == our_ip) { net_add_frame_callback(*cb); return; } *done = true; std::string ip_str = std::to_string(src_ip[0]) + "." + std::to_string(src_ip[1]) + "." + std::to_string(src_ip[2]) + "." + std::to_string(src_ip[3]); resp.respond(ResponseTest{true, {"reply from " + ip_str}}); }; net_add_frame_callback(*cb); dispatch_schedule_ms(5000, [resp, done]() { if (*done) return; *done = true; resp.respond(ResponseTest{false, {"no reply from non-self host within 5s"}}); }); } static void test_ping_subnet(const responder& resp) { test_ping(resp, {169, 254, 255, 255}); } static void test_ping_global(const responder& resp) { test_ping(resp, {255, 255, 255, 255}); } using sync_test_fn = ResponseTest (*)(const responder&); using async_test_fn = void (*)(const responder&); struct test_entry { sync_test_fn sync; async_test_fn async; }; static const std::unordered_map tests = { {"discovery", {test_discovery, nullptr}}, {"ping_subnet", {nullptr, test_ping_subnet}}, {"ping_global", {nullptr, test_ping_global}}, }; std::optional handle_list_tests(const responder&, const RequestListTests&) { ResponseListTests resp; for (const auto& [name, _] : tests) resp.names.emplace_back(name); return resp; } std::optional handle_test(const responder& resp, const RequestTest& req) { auto it = tests.find(req.name); if (it == tests.end()) return ResponseTest{false, {"unknown test: " + req.name}}; if (it->second.sync) return it->second.sync(resp); it->second.async(resp); return std::nullopt; }